Skip to content

No way to configure KEX/ciphers/MACs/host-key algorithms, so legacy servers are unreachable #151

Description

@eiserv

What

hop.clientConfig in internal/uploader/connection.go builds an ssh.ClientConfig with User, Auth, HostKeyCallback and Timeout. The embedded ssh.Config (KeyExchanges, Ciphers, MACs) and HostKeyAlgorithms are left at golang.org/x/crypto/ssh's defaults, and there is no input or config-file field to change them.

Why it matters

x/crypto/ssh's defaults are deliberately modern and get tightened over time. Notably, SHA-1 based host key algorithms (ssh-rsa) and older key exchanges are not in the default client set. That is the right default. The problem is that there is no escape hatch when the server cannot meet it.

The population that hits this is exactly easySFTP's audience:

  • old shared hosting running an unmaintained sshd
  • network appliances, storage boxes and managed-file-transfer products with an SFTP front end
  • corporate bastions frozen on a validated configuration

The user experience is bad in a specific way: the handshake fails inside ssh.Dial, connect() wraps it as connecting to %s: %w, and the message the user sees is something like no common algorithm for key exchange or ssh: handshake failed. There is nothing in the message and nothing in docs/troubleshooting.md that tells them what to change, and there is nothing they can change, because the knob does not exist. The workaround is to stop using easySFTP.

Note this also interacts with host key pinning: a server that only presents an ssh-rsa host key cannot be verified at all today, so the user is pushed toward allow-any-host-key: true, which is strictly worse for security than pinning an old-algorithm key would be.

Suggested direction

Add config-file-only fields (this is advanced tuning, so it belongs in category 2 per CLAUDE.md, not as an inline input):

connection:
  algorithms:
    key_exchanges: [...]
    ciphers: [...]
    macs: [...]
    host_key_algorithms: [...]

Design points worth settling before implementing:

  • Additive or replacing. Replacing the whole list is a footgun (a user pastes one legacy KEX and loses every modern one). Additive ("also allow these on top of the defaults") is safer and matches the intent, which is almost always "I need one more old algorithm", not "I want a different policy".
  • Warn loudly. Enabling a SHA-1 algorithm should produce a warning naming what was enabled, in the same spirit as the allow-any-host-key warning, and should show up in the job summary's security row.
  • Whether to expose this at all, versus documenting "your server is too old, upgrade it". Given the project's stated preference for user choice over enforced opinions, exposing it with a warning looks right, but a decision either way should be written down, because the alternative is that this keeps coming back as bug reports.

Even if the knob is rejected, docs/troubleshooting.md should gain a section that names the symptom (no common algorithm, handshake failed) and explains that the server's algorithms are too old, so users stop guessing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions