OpenSSH 2.0 shipped earlier this month with full support for the SSH-2 protocol. I have spent the last fortnight migrating my own infrastructure from SSH-1 to SSH-2. The transition is overdue and the new protocol is meaningfully better.
I wrote about replacing Telnet with SSH-1 last year. The same arguments now apply to replacing SSH-1 with SSH-2.
What is wrong with SSH-1
The SSH-1 protocol, which has been the de facto standard since 1995, has accumulated several known weaknesses since its design.
The integrity check is weak. SSH-1 uses CRC-32 to verify packet integrity. CRC-32 is not a cryptographic hash. An attacker who can modify ciphertext can produce predictable changes to the corresponding plaintext, and adjust the CRC to match. The Ariel Futoransky and Emiliano Kargieman insertion attack exploits this in practice; SSH-1 connections are vulnerable to a man-in-the-middle who can inject packets undetectably.
The cipher choice is limited. SSH-1 supports DES, 3DES, IDEA, Blowfish, and RC4. DES is now considered too weak for serious use; IDEA has patent encumbrance; the others are usable but the protocol has no graceful path to add new ciphers as cryptanalysis improves.
The key exchange is fragile. SSH-1 uses an RSA-based key exchange with the server's host key. If the server's host key is compromised, every past session that used that key is decryptable by anyone who captured the encrypted traffic. There is no forward secrecy.
The authentication-method extensibility is weak. SSH-1 hard-codes a small set of authentication methods. Adding new ones requires protocol changes that break compatibility.
These are not theoretical concerns. The CRC-32 attack has been demonstrated. The forward-secrecy issue is exploitable by anyone who has been recording encrypted SSH traffic — the volume of such recording is not trivial in adversarial environments. SSH-1 is not, on any reasonable analysis, a protocol I would deploy in a new system.
What SSH-2 does differently
SSH-2 is a redesign rather than an evolution. The key changes:
HMAC for integrity. Cryptographic message authentication, not CRC. The integrity check is now resistant to active modification.
Diffie-Hellman key exchange. The session key is established by Diffie-Hellman, which provides forward secrecy. Compromise of the host key does not retroactively decrypt past sessions.
Cipher and MAC negotiation. Each side advertises the algorithms it supports; they negotiate the strongest mutually supported pair. New ciphers can be added without breaking the protocol.
Separate key for each direction. The client-to-server and server-to-client directions use independent keys, which simplifies the cryptographic analysis and improves resistance to certain attack classes.
Modular authentication. Authentication methods are negotiated separately from the protocol itself. New methods can be added without protocol changes.
Clean separation of layers. The protocol is structured as transport layer, user authentication layer, and connection layer. Each is documented separately. The structure makes implementation and analysis cleaner.
The net effect is a protocol that is meaningfully more secure, more extensible, and more analytically tractable than SSH-1.
The migration
The OpenSSH migration is straightforward in principle and has a few sharp edges in practice.
Building OpenSSH 2.0. The build now requires OpenSSL 0.9.5 or later, which is a step up from earlier versions. On Slackware 4.0 the system OpenSSL is older and needs upgrading first. The new OpenSSL builds cleanly; the OpenSSH build then proceeds.
Configuration changes. The sshd_config file has new directives. The most important:
Protocol 2,1
This says "prefer SSH-2; fall back to SSH-1 if the client cannot do SSH-2". For a transitional period this is the right setting. Once your clients are all SSH-2 capable, change to:
Protocol 2
Which disables SSH-1 entirely.
Host keys. SSH-2 introduces a new key format and supports multiple algorithms. You need to generate new host keys:
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ''
ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N ''
The old ssh_host_key (which is the SSH-1 RSA host key) can stay in place during transition. After full migration, it can be removed.
User keys. The same applies to user authentication keys. Keys generated for SSH-1 will not work for SSH-2 — the format is different. New keys are needed:
ssh-keygen -t rsa
ssh-keygen -t dsa
Older OpenSSH versions place SSH-2 RSA keys in ~/.ssh/id_rsa (private) and ~/.ssh/id_rsa.pub (public), and SSH-2 DSA keys in ~/.ssh/id_dsa and ~/.ssh/id_dsa.pub. The corresponding authorized_keys file uses a slightly different format, with ssh-rsa or ssh-dss as the key-type prefix.
The known_hosts file gets bigger. Each server you connect to now has multiple host keys (one per algorithm). Your known_hosts will have multiple entries per server during transition. This is fine; it is also a source of confusion if you have not encountered it before.
The gotchas I hit
Three things that took me time to work out.
Some clients I use are SSH-1 only. A handful of older systems I connect to do not yet have SSH-2 support. The Protocol 2,1 setting handles this, but it means SSH-1 is still in use somewhere in my flow. The right discipline is to track which systems are SSH-1 and prioritise upgrading them; my list has eight items at the moment.
OpenSSH and the commercial SSH have subtle compatibility differences in SSH-2. The protocol is supposed to be standardised. In practice, the commercial SSH from SSH Communications Security and OpenSSH have minor differences in default cipher and MAC choices, in how authorized_keys files are formatted, and in some less commonly used features. For most use cases this does not matter; for specific cases it can be an interoperability issue. The fix is usually to add explicit cipher and MAC preferences in the config.
Forward-secrecy is great, except for archived sessions. This took me a moment to internalise. Past sessions that used SSH-1 — captured by an attacker, sat on disk somewhere — are still vulnerable to the SSH-1 weaknesses. Migrating to SSH-2 protects future sessions; it does not protect past ones. The right discipline is to assume any data communicated over SSH-1 in the past several years is potentially exposed if any host key was compromised.
Where this leaves me
My own infrastructure is now SSH-2. SSH-1 is disabled on every server I administer. The Protocol 2,1 fallback was used briefly during transition; it is gone now.
For friends and small organisations I support, the migration is a similar one-evening exercise. The barrier is mostly remembering to do it; the technical complexity is low.
The larger question — whose data was exposed during the SSH-1 era? — is unanswerable in any rigorous sense. Anyone who recorded my SSH-1 traffic over the past few years could, in principle, decrypt some of it given enough effort. I do not think anyone did. I cannot prove it. The discipline going forward is to use protocols that do not have this property.
More on the year as it develops. The next post is going to be on a wireless attack tool I have been experimenting with.