The Secure Shell (SSH) Transport Layer Protocol
updated by
- rfc-6668 — SHA-2 Data Integrity Verification for the Secure Shell (SSH) Transport Layer Protocol
- rfc-8268 — More Modular Exponentiation (MODP) Diffie-Hellman (DH) Key Exchange (KEX) Groups for Secure Shell (SSH)
- rfc-8308 — Extension Negotiation in the Secure Shell (SSH) Protocol
- rfc-8332 — Use of RSA Keys with SHA-256 and SHA-512 in the Secure Shell (SSH) Protocol
- rfc-8709 — Ed25519 and Ed448 Public Key Algorithms for the Secure Shell (SSH) Protocol
- rfc-8758 — Deprecating RC4 in Secure Shell (SSH)
- rfc-9142 — Key Exchange (KEX) Method Updates and Recommendations for Secure Shell (SSH)
Extracted elements (30)
3des-cbc is REQUIRED despite having only a 112-bit effective key length (below the 128-bit threshold) because all known implementations support it and it is the fundamental interoperable algorithm. It is expected to be deprecated by STANDARDS ACTION once a stronger algorithm becomes ubiquitous.
SSH maintains its own group identifier space logically distinct from Oakley and IKE. The name 'diffie-hellman-group1-sha1' uses 'group1' despite specifying Oakley Group 2. Implementations should treat these names as opaque identifiers and not assume any relationship to IKE groups.
For backward compatibility with SSH 1.x, a server MAY use protoversion '1.99' to signal dual support; SSH 2.0 clients MUST treat '1.99' as identical to '2.0'. In compatibility mode, the server MUST NOT send additional data before the identification string.
Algorithm selection for key exchange iterates over the client's kex_algorithms and picks the first that the server also supports (with compatible host key capabilities). If no matching algorithm is found, both sides MUST disconnect.
All ciphers SHOULD use keys with an effective key length of 128 bits or more. The ciphers in each direction MUST run independently. Initially, the MAC algorithm MUST be 'none'.
All implementations MUST be able to process packets with an uncompressed payload length of 32768 bytes or less and a total packet size of 35000 bytes or less. Implementations SHOULD check packet length to avoid denial of service and buffer overflow attacks.
All implementations MUST be able to process SSH_MSG_DISCONNECT. After sending or receiving this message, no further data may be sent or accepted. The sender MUST NOT send any data after this message.
All implementations MUST understand and ignore SSH_MSG_IGNORE at any time after receiving the identification string. This message can be used as an additional protection measure against advanced traffic analysis techniques.
An implementation MUST respond to all unrecognized messages with SSH_MSG_UNIMPLEMENTED in the order received. SSH_MSG_UNIMPLEMENTED carries the uint32 packet sequence number of the rejected message.
Compression MUST be independent for each direction, and implementations MUST allow independent selection of the algorithm for each direction. Initially, compression MUST be 'none'.
During DH key exchange, the client MUST verify that K_S is really the host key for the server (e.g., via certificates or local database). Accepting without verification renders the protocol insecure against active attacks.
Key re-exchange is RECOMMENDED after each gigabyte of transmitted data or each hour of connection time, whichever comes sooner. Either party MAY initiate re-exchange, but roles MUST NOT change.
Once a party sends SSH_MSG_KEXINIT, it MUST NOT send any messages other than transport layer generic messages (1-19, excluding SERVICE_REQUEST/SERVICE_ACCEPT), algorithm negotiation messages (20-29, excluding further KEXINIT), and key exchange method messages (30-49), until it has sent SSH_MSG_NEWKEYS.
Two key exchange methods are REQUIRED: diffie-hellman-group1-sha1 (Oakley Group 2, 1024-bit MODP) and diffie-hellman-group14-sha1 (Oakley Group 14, 2048-bit MODP). Both MUST be supported for interoperability.
When the connection is established, both sides MUST send an identification string. The null character MUST NOT be sent. The identification MUST be terminated by a single CR and LF.
Defined encryption algorithms include 3des-cbc (REQUIRED), aes128-cbc (RECOMMENDED), and numerous OPTIONAL ciphers including aes256-cbc, twofish256-cbc, arcfour, and none (NOT RECOMMENDED). The 'none' algorithm provides no confidentiality protection.
Defined public key algorithms: ssh-dss (REQUIRED, sign, raw DSS key), ssh-rsa (RECOMMENDED, sign, raw RSA key), pgp-sign-rsa (OPTIONAL), pgp-sign-dss (OPTIONAL). The key type MUST always be explicitly known from algorithm negotiation.
Diffie-Hellman key exchange: client sends SSH_MSG_KEXDH_INIT with mpint e; server responds with SSH_MSG_KEXDH_REPLY containing string K_S (host key/certificates), mpint f, and string signature of H. Values of e or f not in range [1, p-1] MUST NOT be sent or accepted.
Key exchange produces shared secret K and exchange hash H. Six derived keys are computed as HASH(K || H || letter || session_id) for letters A-F, covering IVs and encryption/integrity keys for both directions. The session identifier is H from the first key exchange and never changes.
MAC is computed as MAC(key, sequence_number || unencrypted_packet). The sequence_number is an implicit uint32 initialized to zero, incremented after every packet, never reset even during re-exchange, and wraps at 2^32. Defined MAC algorithms: hmac-sha1 (REQUIRED), hmac-sha1-96 (RECOMMENDED), hmac-md5 (OPTIONAL), hmac-md5-96 (OPTIONAL), none (OPTIONAL, NOT RECOMMENDED).
The defined compression methods are 'none' (REQUIRED, no compression) and 'zlib' (OPTIONAL, ZLIB/LZ77 compression per RFC 1950/1951). The zlib compression context is initialized after each key exchange and passed between packets with a partial flush at each packet boundary.
The SSH identification string sent by both sides upon connection has the format 'SSH-protoversion-softwareversion SP comments CR LF'. For SSH version 2.0, the protoversion MUST be '2.0'. The string is limited to 255 characters including CR LF.
IANA registry for SSH transport layer message numbers is managed through [SSH-NUMBERS] (RFC 4250). Core transport messages: SSH_MSG_DISCONNECT (1), SSH_MSG_IGNORE (2), SSH_MSG_UNIMPLEMENTED (3), SSH_MSG_DEBUG (4), SSH_MSG_SERVICE_REQUEST (5), SSH_MSG_SERVICE_ACCEPT (6), SSH_MSG_KEXINIT (20), SSH_MSG_NEWKEYS (21). Numbers 30-49 reserved for kex packets.
The protocol provides server host authentication, key exchange, encryption, and integrity protection, deriving a unique session ID for use by higher-level protocols. Full security considerations are in [SSH-ARCH] (RFC 4251). The exchange hash H SHOULD be kept secret.
Key exchange ends when each side sends SSH_MSG_NEWKEYS. This message is sent with old keys; all subsequent sent messages MUST use new keys. Upon receipt, new keys MUST immediately be used for receiving. States: exchanging keys → sending SSH_MSG_NEWKEYS (old keys) → new keys active.
SSH_MSG_DISCONNECT carries: byte SSH_MSG_DISCONNECT, uint32 reason code, string description in ISO-10646 UTF-8, string language tag. Fifteen reason codes are defined (1-15), codes 0x10 to 0xFDFFFFFF require IETF CONSENSUS, and 0xFE000000-0xFFFFFFFF are PRIVATE USE.
The SSH binary packet format consists of: uint32 packet_length, byte padding_length, byte[n1] payload, byte[n2] random padding, and byte[m] MAC. The total length of packet_length + padding_length + payload + random padding MUST be a multiple of the cipher block size or 8, whichever is larger.
The ssh-dss key blob encodes as: string 'ssh-dss', mpint p, mpint q, mpint g, mpint y. DSS signatures encode as: string 'ssh-dss', string dss_signature_blob containing r || s (each 160-bit integer, unsigned, network byte order, no padding).
The SSH_MSG_KEXINIT packet contains: byte SSH_MSG_KEXINIT, byte[16] cookie (random), followed by ten name-lists for algorithm negotiation (kex, host key, encryption C2S/S2C, MAC C2S/S2C, compression C2S/S2C, languages C2S/S2C), boolean first_kex_packet_follows, uint32 0 reserved.
The ssh-rsa key blob encodes as: string 'ssh-rsa', mpint e, mpint n. RSA signatures are computed using RSASSA-PKCS1-v1_5 with SHA-1 and encoded as: string 'ssh-rsa', string rsa_signature_blob (unsigned integer s, network byte order, no padding).