Last Updated: February 23, 2006
Michael Ligh (michael.ligh@mnin.org)
This is an overview of the SSH2 protocol, with a focus on how it uses cryptography to
accomplish many of its goals: authentication, integrity, and confidentiality. The
information is derived from client-side debug output; a network packet capture; protocol
decoding by Ethereal; RFC drafts for SSH-ARCH, SSH-TRANS, SSH-AUTH, SSH-CONN; O’Reilly’s
Secure Shell Definitive Guide, VPNs Illustrated, and Practical Cryptography. The expected
product of the guide is an ability to detect insecure client and/or server settings and
recognize anomalies during session establishment. The sections are organized by order of
which they occur during an SSH2 login.
|
Note: This diagram is modeled after the conventions used in Richard Steven’s |
In this example, host .14 (the client) establishes a TCP connection to port 22
of host .11 (the server), the two sides announce SSH versions, and the key
exchange initialization takes place. For brevity, the 3-way handshake
is the only sub-section in which either side’s acknowledgment (ACK)
packets affect the packet count. Following section 1, the two peers
will have derived the following information:
- SSH version (for compatibility mode)
- Supported and preferred key exchange methods
- Supported and preferred host key types
- Supported and preferred bulk data encryption algorithms
- Supported and preferred integrity algorithms
- Supported and preferred compression algorithms
- A unique random number generated by each side, known as a cookie
TCP 3-way handshake (packets 1, 2 3)
If you’re reading this, then likely you already know the significance of the 3-way handshake.
It is provided here to be complete. Using the -v option when calling the SSH client on .14, these
three packets produce the output:
debug1: Connecting to 192.168.1.11 [192.168.1.11] port 22. debug1: Connection established.
The network packet captures in this document are recorded with Ethereal. Here are the first three:
/* Packets 1, 2, and 3 */ 192.168.1.14.55821 > 192.168.1.11.22: S 381470515:381470515(0) win 5840 192.168.1.11.22 > 192.168.1.14.55821: S 1684940992:1684940992(0) ack 381470516 win 5792 192.168.1.14.55821 > 192.168.1.11.22: . ack 1 win 1460
Version string announcement (packets 4, 5)
There are two main, incompatible, versions of the SSH protocol: SSH1 (1.5) and SSH2. Most recent
implementations still support both protocols, though support for the older, less secure SSH1 version
should not be used. One major reason is because SSH1 only applies a CRC32 (cyclancy redundancy check)
to the message for integrity, rather than a MAC (message authentication code). CRCs are not
collision-resistant functions and are normally just used to detect accidental errors in
transmissions (IP, TCP, and UDP, for example, use a checksum in their headers). MACs, on the other
hand, are strengthened by using a cryotographic hash such as MD5 or SHA1.
Note: by definition, hashes produce a fixed length output. Due to MD5’s 128-bit |
In this sub-section, two packets are exchanged. The server sends it’s protocol version first and
the client replies with it’s own version. A special code “1.99” specifies that the sender supports
both SSH1 and SSH2. In our example, the client and server both suport SSH2 only.
debug1: Remote protocol version 2.0, remote software version OpenSSH_4.1 debug1: match: OpenSSH_4.1 pat OpenSSH* debug1: Enabling compatibility mode for protocol 2.0 debug1: Local version string SSH-2.0-OpenSSH_4.2
If the protocol versions are compatible, the connection progresses to the next step. If they are not,
then either peer can force a termination. View the packet capture for a closer look at the traffic
that produces the above output.
/* Packet 4 */ Internet Protocol, Src: 192.168.1.11 (192.168.1.11), Dst: 192.168.1.14 (192.168.1.14) Transmission Control Protocol, Src Port: 22 (22), Dst Port: 55821 (55821), Seq: 1, Ack: 1, Len: 20 SSH Protocol Protocol: SSH-2.0-OpenSSH_4.1n 0000 00 0c 29 6d 5c 01 00 50 2c 05 6b a9 08 00 45 00 ..)m..P,.k...E. 0010 00 48 55 20 40 00 40 06 62 26 c0 a8 01 0b c0 a8 .HU @.@.b&...... 0020 01 0e 00 16 da 0d 64 6e 28 c1 16 bc c7 34 80 18 ......dn(....4.. 0030 05 a8 67 ce 00 00 01 01 08 0a 0b 79 7d e4 04 99 ..g........y}... 0040 fe e0 53 53 48 2d 32 2e 30 2d 4f 70 65 6e 53 53 ..SSH-2.0-OpenSS 0050 48 5f 34 2e 31 0a H_4.1. /* Packet 5 */ Internet Protocol, Src: 192.168.1.14 (192.168.1.14), Dst: 192.168.1.11 (192.168.1.11) Transmission Control Protocol, Src Port: 55821 (55821), Dst Port: 22 (22), Seq: 1, Ack: 21, Len: 20 SSH Protocol Protocol: SSH-2.0-OpenSSH_4.2n 0000 00 50 2c 05 6b a9 00 0c 29 6d 5c 01 08 00 45 00 .P,.k...)m...E. 0010 00 48 39 d6 40 00 40 06 7d 70 c0 a8 01 0e c0 a8 .H9.@.@.}p...... 0020 01 0b da 0d 00 16 16 bc c7 34 64 6e 28 d5 80 18 .........4dn(... 0030 05 b4 66 ae 00 00 01 01 08 0a 04 99 fe e0 0b 79 ..f............y 0040 7d e4 53 53 48 2d 32 2e 30 2d 4f 70 65 6e 53 53 }.SSH-2.0-OpenSS 0050 48 5f 34 2e 32 0a H_4.2.
SSH2_MSG_KEXINIT exchange (packets 6, 7)
The primary objective of this round-trip exchange is to negotiate the algorithms for key exchange,
bulk data encryption, message integrity, and compression. The peers will also let each other know the
accepted host key types. In this stage they present their supported and preferred methods for the aforementioned
functions in comma seperated list form. Preferred values are distinguished by placing them first in the
list.
debug1: SSH2_MSG_KEXINIT sent debug1: SSH2_MSG_KEXINIT received debug1: kex: server->client aes128-cbc hmac-md5 none debug1: kex: client->server aes128-cbc hmac-md5 none
Two of the common key exchange methods are represented as diffie-hellman-group-exchange-sha1 and
diffie-hellman-group1-sha1. The later method is less secure, because it uses a fixed group with which
to make it’s calculations. If diffie-hellman-group-exchange-sha1 (otherwise known as DHGEX) is selected,
the group to use is negotiated based on the client’s minimum, maximum, and preferred size prime modulus;
from which the server chooses an appropriate value (see the SSH2_MSG_KEXDH_GEX_GROUP message in packet 9).
For bulk data encryption, SSH uses a symetric algorithm to scramble the message.
Asymetric algorithms are simply not efficient when applied to bulk data, because they are too slow.
The key used for this function is then encrypted with the peer’s public host key to ensure that only a host
with the corresponding private key can reproduce it. Without knowing the symetric algorithm key, the
original message itself cannot be decrypted. So, upon receipt of the packet, a peer would use it’s
private key to decrypt the symetric algorithm key; and then use that resulting value to derive the plaintext message.
For data integrity, the two peers agree to use a common MAC algorithm.
Encryption alone does not prove to the recipient that the remote peer truly generated and
sent a message, and further more it does not prevent against alteration of the data. In fact,
encryption does not even attempt to do this – it assumes the data will be available
to anyone, and just makes it’s best attempt to prevent it from being readable. MACs fill in this void by
computing a hash of the unencrypted message body, a shared secret, and a session sequence number; which is
then sent to the recipient. The shared secret is a product of the Diffie Hellman key exchange (section 2) and is
computed individually by each peer, without needing to transmit over the network.
Without the MAC, an eavesdropper (man in the middle) could capture parts of the encrypted conversation (though not necessarily
be able to read it) and conduct a replay attack, where s/he duplicates and resends that part of the
converstation at a later point in time. The packet would still contain a payload signed with the recipient’s
public key, and the message would be encrypted with the expected symetric algorithm key; thus it would seem
quite reasonable to the recipient. The session sequence number here is critical. It begins at 0 and increments
by 1 for each message. Since this is a factor in the computation of the MAC value, only the sender can produce
a legitimate code; and the recipient will only accept each code once – in the proper order. The MAC is not
included in packets until after the SSH2_MSG_NEWKEYS is sent (packet 12).
SSH optionally will compress transmissions for more efficient delivery. Zlib is the only supported
scheme according to the RFCs, but they are only drafts so this is subject to change. In the case that compression
is negotiated, it is applied only to the message body and occurs before any MAC or encryption routines. Notice above that the
client->server and server->client algorithms match; they both have chosen the same
bulk data, integrity, and compression methods. This may be the case here, but it is not required. Data flow
in both directions is independent of each other. The server could encrypt it’s messages with AES128 and compress
it with zlib, and the client could encrypt it’s replies with 3DES with no compression.
Additionally, in this sub-section, the client and server both generate a sequence of 16 random bytes known as a cookie.
This value is used in the key generation process, to ensure that neither side can completely determine the keys
on it’s own.
/* Packet 6 */ Internet Protocol, Src: 192.168.1.11 (192.168.1.11), Dst: 192.168.1.14 (192.168.1.14) Transmission Control Protocol, Src Port: 22 (22), Dst Port: 55821 (55821), Seq: 21, Ack: 21, Len: 640 SSH Protocol SSH Version 2 Packet Length: 636 Padding Length: 11 Key Exchange Msg code: Key Exchange Init (20) Algorithms Cookie: E943B8EAD89BC6BD6861A54CFD333DB0 kex_algorithms length: 89 kex_algorithms string: diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1, diffie-hellman-group1-sha1 server_host_key_algorithms length: 15 server_host_key_algorithms string: ssh-rsa,ssh-dss encryption_algorithms_client_to_server length: 135 encryption_algorithms_client_to_server string: aes128-cbc,3des-cbc,blowfish-cbc, cast128-cbc,arcfour,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,aes128-ctr, aes192-ctr,aes256-ctr encryption_algorithms_server_to_client length: 135 encryption_algorithms_server_to_client string: aes128-cbc,3des-cbc,blowfish-cbc, cast128-cbc,arcfour,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,aes128-ctr, aes192-ctr,aes256-ctr mac_algorithms_client_to_server length: 85 mac_algorithms_client_to_server string: hmac-md5,hmac-sha1,hmac-ripemd160, hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96 mac_algorithms_server_to_client length: 85 mac_algorithms_server_to_client string: hmac-md5,hmac-sha1,hmac-ripemd160, hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96 compression_algorithms_client_to_server length: 9 compression_algorithms_client_to_server string: none,zlib compression_algorithms_server_to_client length: 9 compression_algorithms_server_to_client string: none,zlib languages_client_to_server length: 0 languages_server_to_client length: 0 Payload: 0000000000 Padding String: 0000 00 0c 29 6d 5c 01 00 50 2c 05 6b a9 08 00 45 00 ..)m..P,.k...E. 0010 02 b4 55 24 40 00 40 06 5f b6 c0 a8 01 0b c0 a8 ..U$@.@._....... 0020 01 0e 00 16 da 0d 64 6e 28 d5 16 bc c7 48 80 18 ......dn(....H.. 0030 05 a8 79 e0 00 00 01 01 08 0a 0b 79 7d e5 04 99 ..y........y}... 0040 fe e0 00 00 02 7c 0b 14 e9 43 b8 ea d8 9b c6 bd .....|...C...... 0050 68 61 a5 4c fd 33 3d b0 00 00 00 59 64 69 66 66 ha.L.3=....Ydiff 0060 69 65 2d 68 65 6c 6c 6d 61 6e 2d 67 72 6f 75 70 ie-hellman-group 0070 2d 65 78 63 68 61 6e 67 65 2d 73 68 61 31 2c 64 -exchange-sha1,d 0080 69 66 66 69 65 2d 68 65 6c 6c 6d 61 6e 2d 67 72 iffie-hellman-gr 0090 6f 75 70 31 34 2d 73 68 61 31 2c 64 69 66 66 69 oup14-sha1,diffi 00a0 65 2d 68 65 6c 6c 6d 61 6e 2d 67 72 6f 75 70 31 e-hellman-group1 00b0 2d 73 68 61 31 00 00 00 0f 73 73 68 2d 72 73 61 -sha1....ssh-rsa 00c0 2c 73 73 68 2d 64 73 73 00 00 00 87 61 65 73 31 ,ssh-dss....aes1 00d0 32 38 2d 63 62 63 2c 33 64 65 73 2d 63 62 63 2c 28-cbc,3des-cbc, 00e0 62 6c 6f 77 66 69 73 68 2d 63 62 63 2c 63 61 73 blowfish-cbc,cas 00f0 74 31 32 38 2d 63 62 63 2c 61 72 63 66 6f 75 72 t128-cbc,arcfour 0100 2c 61 65 73 31 39 32 2d 63 62 63 2c 61 65 73 32 ,aes192-cbc,aes2 0110 35 36 2d 63 62 63 2c 72 69 6a 6e 64 61 65 6c 2d 56-cbc,rijndael- 0120 63 62 63 40 6c 79 73 61 74 6f 72 2e 6c 69 75 2e cbc@lysator.liu. 0130 73 65 2c 61 65 73 31 32 38 2d 63 74 72 2c 61 65 se,aes128-ctr,ae 0140 73 31 39 32 2d 63 74 72 2c 61 65 73 32 35 36 2d s192-ctr,aes256- 0150 63 74 72 00 00 00 87 61 65 73 31 32 38 2d 63 62 ctr....aes128-cb 0160 63 2c 33 64 65 73 2d 63 62 63 2c 62 6c 6f 77 66 c,3des-cbc,blowf 0170 69 73 68 2d 63 62 63 2c 63 61 73 74 31 32 38 2d ish-cbc,cast128- 0180 63 62 63 2c 61 72 63 66 6f 75 72 2c 61 65 73 31 cbc,arcfour,aes1 0190 39 32 2d 63 62 63 2c 61 65 73 32 35 36 2d 63 62 92-cbc,aes256-cb 01a0 63 2c 72 69 6a 6e 64 61 65 6c 2d 63 62 63 40 6c c,rijndael-cbc@l 01b0 79 73 61 74 6f 72 2e 6c 69 75 2e 73 65 2c 61 65 ysator.liu.se,ae 01c0 73 31 32 38 2d 63 74 72 2c 61 65 73 31 39 32 2d s128-ctr,aes192- 01d0 63 74 72 2c 61 65 73 32 35 36 2d 63 74 72 00 00 ctr,aes256-ctr.. 01e0 00 55 68 6d 61 63 2d 6d 64 35 2c 68 6d 61 63 2d .Uhmac-md5,hmac- 01f0 73 68 61 31 2c 68 6d 61 63 2d 72 69 70 65 6d 64 sha1,hmac-ripemd 0200 31 36 30 2c 68 6d 61 63 2d 72 69 70 65 6d 64 31 160,hmac-ripemd1 0210 36 30 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 60@openssh.com,h 0220 6d 61 63 2d 73 68 61 31 2d 39 36 2c 68 6d 61 63 mac-sha1-96,hmac 0230 2d 6d 64 35 2d 39 36 00 00 00 55 68 6d 61 63 2d -md5-96...Uhmac- 0240 6d 64 35 2c 68 6d 61 63 2d 73 68 61 31 2c 68 6d md5,hmac-sha1,hm 0250 61 63 2d 72 69 70 65 6d 64 31 36 30 2c 68 6d 61 ac-ripemd160,hma 0260 63 2d 72 69 70 65 6d 64 31 36 30 40 6f 70 65 6e c-ripemd160@open 0270 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 2d 73 68 61 ssh.com,hmac-sha 0280 31 2d 39 36 2c 68 6d 61 63 2d 6d 64 35 2d 39 36 1-96,hmac-md5-96 0290 00 00 00 09 6e 6f 6e 65 2c 7a 6c 69 62 00 00 00 ....none,zlib... 02a0 09 6e 6f 6e 65 2c 7a 6c 69 62 00 00 00 00 00 00 .none,zlib...... 02b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 02c0 00 00 .. /* Packet 7 */ Internet Protocol, Src: 192.168.1.14 (192.168.1.14), Dst: 192.168.1.11 (192.168.1.11) Transmission Control Protocol, Src Port: 55821 (55821), Dst Port: 22 (22), Seq: 21, Ack: 661, Len: 712 SSH Protocol SSH Version 2 Packet Length: 708 Padding Length: 5 Key Exchange Msg code: Key Exchange Init (20) Algorithms Cookie: 4C07661B0E42B52E6081306F2714EDC3 kex_algorithms length: 89 kex_algorithms string: diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1, diffie-hellman-group1-sha1 server_host_key_algorithms length: 15 server_host_key_algorithms string: ssh-rsa,ssh-dss encryption_algorithms_client_to_server length: 157 encryption_algorithms_client_to_server string: aes128-cbc,3des-cbc,blowfish-cbc, cast128-cbc,arcfour128,arcfour256,arcfour,aes192-cbc,aes256-cbc, rijndael-cbc@lysator.liu.se,aes128-ctr,aes192-ctr,aes256-ctr encryption_algorithms_server_to_client length: 157 encryption_algorithms_server_to_client string: aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc, arcfour128,arcfour256,arcfour,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,aes128-ctr, aes192-ctr,aes256-ctr mac_algorithms_client_to_server length: 85 mac_algorithms_client_to_server string: hmac-md5,hmac-sha1,hmac-ripemd160, hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96 mac_algorithms_server_to_client length: 85 mac_algorithms_server_to_client string: hmac-md5,hmac-sha1,hmac-ripemd160, hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96 compression_algorithms_client_to_server length: 26 compression_algorithms_client_to_server string: none,zlib@openssh.com,zlib compression_algorithms_server_to_client length: 26 compression_algorithms_server_to_client string: none,zlib@openssh.com,zlib languages_client_to_server length: 0 languages_server_to_client length: 0 Payload: 0000000000 Padding String: 0000 00 50 2c 05 6b a9 00 0c 29 6d 5c 01 08 00 45 00 .P,.k...)m...E. 0010 02 fc 39 d7 40 00 40 06 7a bb c0 a8 01 0e c0 a8 ..9.@.@.z....... 0020 01 0b da 0d 00 16 16 bc c7 48 64 6e 2b 55 80 18 .........Hdn+U.. 0030 06 f4 78 4e 00 00 01 01 08 0a 04 99 fe e0 0b 79 ..xN...........y 0040 7d e5 00 00 02 c4 05 14 4c 07 66 1b 0e 42 b5 2e }.......L.f..B.. 0050 60 81 30 6f 27 14 ed c3 00 00 00 59 64 69 66 66 `.0o'......Ydiff 0060 69 65 2d 68 65 6c 6c 6d 61 6e 2d 67 72 6f 75 70 ie-hellman-group 0070 2d 65 78 63 68 61 6e 67 65 2d 73 68 61 31 2c 64 -exchange-sha1,d 0080 69 66 66 69 65 2d 68 65 6c 6c 6d 61 6e 2d 67 72 iffie-hellman-gr 0090 6f 75 70 31 34 2d 73 68 61 31 2c 64 69 66 66 69 oup14-sha1,diffi 00a0 65 2d 68 65 6c 6c 6d 61 6e 2d 67 72 6f 75 70 31 e-hellman-group1 00b0 2d 73 68 61 31 00 00 00 0f 73 73 68 2d 72 73 61 -sha1....ssh-rsa 00c0 2c 73 73 68 2d 64 73 73 00 00 00 9d 61 65 73 31 ,ssh-dss....aes1 00d0 32 38 2d 63 62 63 2c 33 64 65 73 2d 63 62 63 2c 28-cbc,3des-cbc, 00e0 62 6c 6f 77 66 69 73 68 2d 63 62 63 2c 63 61 73 blowfish-cbc,cas 00f0 74 31 32 38 2d 63 62 63 2c 61 72 63 66 6f 75 72 t128-cbc,arcfour 0100 31 32 38 2c 61 72 63 66 6f 75 72 32 35 36 2c 61 128,arcfour256,a 0110 72 63 66 6f 75 72 2c 61 65 73 31 39 32 2d 63 62 rcfour,aes192-cb 0120 63 2c 61 65 73 32 35 36 2d 63 62 63 2c 72 69 6a c,aes256-cbc,rij 0130 6e 64 61 65 6c 2d 63 62 63 40 6c 79 73 61 74 6f ndael-cbc@lysato 0140 72 2e 6c 69 75 2e 73 65 2c 61 65 73 31 32 38 2d r.liu.se,aes128- 0150 63 74 72 2c 61 65 73 31 39 32 2d 63 74 72 2c 61 ctr,aes192-ctr,a 0160 65 73 32 35 36 2d 63 74 72 00 00 00 9d 61 65 73 es256-ctr....aes 0170 31 32 38 2d 63 62 63 2c 33 64 65 73 2d 63 62 63 128-cbc,3des-cbc 0180 2c 62 6c 6f 77 66 69 73 68 2d 63 62 63 2c 63 61 ,blowfish-cbc,ca 0190 73 74 31 32 38 2d 63 62 63 2c 61 72 63 66 6f 75 st128-cbc,arcfou 01a0 72 31 32 38 2c 61 72 63 66 6f 75 72 32 35 36 2c r128,arcfour256, 01b0 61 72 63 66 6f 75 72 2c 61 65 73 31 39 32 2d 63 arcfour,aes192-c 01c0 62 63 2c 61 65 73 32 35 36 2d 63 62 63 2c 72 69 bc,aes256-cbc,ri 01d0 6a 6e 64 61 65 6c 2d 63 62 63 40 6c 79 73 61 74 jndael-cbc@lysat 01e0 6f 72 2e 6c 69 75 2e 73 65 2c 61 65 73 31 32 38 or.liu.se,aes128 01f0 2d 63 74 72 2c 61 65 73 31 39 32 2d 63 74 72 2c -ctr,aes192-ctr, 0200 61 65 73 32 35 36 2d 63 74 72 00 00 00 55 68 6d aes256-ctr...Uhm 0210 61 63 2d 6d 64 35 2c 68 6d 61 63 2d 73 68 61 31 ac-md5,hmac-sha1 0220 2c 68 6d 61 63 2d 72 69 70 65 6d 64 31 36 30 2c ,hmac-ripemd160, 0230 68 6d 61 63 2d 72 69 70 65 6d 64 31 36 30 40 6f hmac-ripemd160@o 0240 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 2d penssh.com,hmac- 0250 73 68 61 31 2d 39 36 2c 68 6d 61 63 2d 6d 64 35 sha1-96,hmac-md5 0260 2d 39 36 00 00 00 55 68 6d 61 63 2d 6d 64 35 2c -96...Uhmac-md5, 0270 68 6d 61 63 2d 73 68 61 31 2c 68 6d 61 63 2d 72 hmac-sha1,hmac-r 0280 69 70 65 6d 64 31 36 30 2c 68 6d 61 63 2d 72 69 ipemd160,hmac-ri 0290 70 65 6d 64 31 36 30 40 6f 70 65 6e 73 73 68 2e pemd160@openssh. 02a0 63 6f 6d 2c 68 6d 61 63 2d 73 68 61 31 2d 39 36 com,hmac-sha1-96 02b0 2c 68 6d 61 63 2d 6d 64 35 2d 39 36 00 00 00 1a ,hmac-md5-96.... 02c0 6e 6f 6e 65 2c 7a 6c 69 62 40 6f 70 65 6e 73 73 none,zlib@openss 02d0 68 2e 63 6f 6d 2c 7a 6c 69 62 00 00 00 1a 6e 6f h.com,zlib....no 02e0 6e 65 2c 7a 6c 69 62 40 6f 70 65 6e 73 73 68 2e ne,zlib@openssh. 02f0 63 6f 6d 2c 7a 6c 69 62 00 00 00 00 00 00 00 00 com,zlib........ 0300 00 00 00 00 00 00 00 00 00 00 ..........
This section involves key exchange, using the selected Diffie Hellman protocol. By using this
method properly, the two peers can derive the same secret key through plain text communications, without
the possibility of eavesdroppers being able to calculate the same value. DH is not a total package solution,
because it does not prevent man-in-the-middle data alteration. This attack will be described shortly.
Following section 2, the peers will have derived the following information:
- The Diffie Hellman group to use (and thus the size of the prime)
- The prime number itself and the corresponding generator
- The exchange hash (initial = session ID) and shared secret (k)
- The server’s identity is authenticated via public key cryptography
- The encryption, integrity, and initial IV keys
SSH2_MSG_KEXDH_GEX_REQUEST (packet 8)
As mentioned earlier, if diffie-hellman-group-exchange-sha1 is selected as the key exchange method, the
client notifies the server of it’s minimum, preferred, and maximum prime size for the group. As the debug
output shows, the numers are 1024, 1024, and 8192, respectively. The 32-bit unsigned integers have been
highlighted below.
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024Internet Protocol, Src: 192.168.1.14 (192.168.1.14), Dst: 192.168.1.11 (192.168.1.11) Transmission Control Protocol, Src Port: 55821 (55821), Dst Port: 22 (22), Seq: 733, Ack: 661, Len: 24 SSH Protocol SSH Version 2 Packet Length: 20 Padding Length: 6 Key Exchange Msg code: Diffie-Hellman GEX Request (34) Payload: 000004000000040000002000 Padding String: 0000 00 50 2c 05 6b a9 00 0c 29 6d 5c 01 08 00 45 00 .P,.k...)m...E. 0010 00 4c 39 d8 40 00 40 06 7d 6a c0 a8 01 0e c0 a8 .L9.@.@.}j...... 0020 01 0b da 0d 00 16 16 bc ca 10 64 6e 2b 55 80 18 ..........dn+U.. 0030 06 f4 e6 6e 00 00 01 01 08 0a 04 99 fe e3 0b 79 ...n...........y 0040 7d f0 00 00 00 14 06 22 00 00 04 00 00 00 04 00 }......"........ 0050 00 00 20 00 00 00 00 00 00 00 .. .......
SSH2_MSG_KEXDH_GEX_GROUP (packet 9)
This is the server's response to the SSH2_MSG_KEXDH_GEX_REQUEST. From the available options, the server
selects an appropriate size for the group's prime and informs the client. This packet also contains two
multiprecision integers containing the prime to be used (p) and the corresponding generator (g). After
receiving this message, both peers know the DH group to use. There are only two remaining packets in
the key exchange (packets 10 and 11) before enough parameters are negotiated to start encrypting data..Internet Protocol, Src: 192.168.1.11 (192.168.1.11), Dst: 192.168.1.14 (192.168.1.14) Transmission Control Protocol, Src Port: 22 (22), Dst Port: 55821 (55821), Seq: 661, Ack: 757, Len: 152 SSH Protocol SSH Version 2 Packet Length: 148 Padding Length: 8 Key Exchange Msg code: Diffie-Hellman Key Exchange Reply (31) Payload: 0000008100CAADDDEC1667FC68B5FA15D53C4E1532DD2456... Padding String: 0000 00 0c 29 6d 5c 01 00 50 2c 05 6b a9 08 00 45 00 ..)m..P,.k...E. 0010 00 cc 55 2a 40 00 40 06 61 98 c0 a8 01 0b c0 a8 ..U*@.@.a....... 0020 01 0e 00 16 da 0d 64 6e 2b 55 16 bc ca 28 80 18 ......dn+U...(.. 0030 07 0c 19 0a 00 00 01 01 08 0a 0b 79 7d f1 04 99 ...........y}... 0040 fe e3 00 00 00 94 08 1f 00 00 00 81 00 ca ad dd ................ 0050 ec 16 67 fc 68 b5 fa 15 d5 3c 4e 15 32 dd 24 56 ..g.h....jN.2.$V 0060 1a 1a 2d 47 a1 2c 01 ab ea 1e 00 73 1f 69 21 aa ..-G.,.....s.i!. 0070 c4 07 42 31 1f df 9e 63 4b b7 13 1b ee 1a f2 40 ..B1...cK......@ 0080 26 15 54 38 9a 91 04 25 e0 44 e8 8c 83 59 b0 10 &.T8...%.D...Y.. 0090 f5 ad 2b 80 e2 9c b1 a5 b0 27 b1 9d 9e 01 a6 f6 ..+......'...... 00a0 3a 6f 45 e5 d7 ed 2f f6 a2 a0 08 50 50 a7 d0 cf :oE.../....PP... 00b0 30 7c 3d b5 1d 24 90 35 59 07 b4 42 7c 23 a9 8d 0|=..$.5Y..B|#.. 00c0 f1 eb 8a be f2 ba 20 9b b7 b0 df d8 bb 00 00 00 ...... ......... 00d0 01 02 00 00 00 00 00 00 00 00 ..........SSH2_MSG_KEXDH_GEX_INIT (packet 10)
In this sub-section, the client computes a value based on p and g and sends it to the server. In
particular, the client generates a random number x, such that 1debug1: SSH2_MSG_KEX_DH_GEX_INIT sent debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLYInternet Protocol, Src: 192.168.1.14 (192.168.1.14), Dst: 192.168.1.11 (192.168.1.11) Transmission Control Protocol, Src Port: 55821 (55821), Dst Port: 22 (22), Seq: 757, Ack: 813, Len: 144 SSH Protocol SSH Version 2 Packet Length: 140 Padding Length: 6 Key Exchange Msg code: Diffie-Hellman GEX Init (32) Payload: 000000803DEEBF549A8BBA70F9B4E3DFB149ED844D67C1AD... Padding String: 0000 00 50 2c 05 6b a9 00 0c 29 6d 5c 01 08 00 45 00 .P,.k...)m...E. 0010 00 c4 39 d9 40 00 40 06 7c f1 c0 a8 01 0e c0 a8 ..9.@.@.|....... 0020 01 0b da 0d 00 16 16 bc ca 28 64 6e 2b ed 80 18 .........(dn+... 0030 08 34 2d 8a 00 00 01 01 08 0a 04 99 fe e5 0b 79 .4-............y 0040 7d f1 00 00 00 8c 06 20 00 00 00 80 3d ee bf 54 }...... ....=..T 0050 9a 8b ba 70 f9 b4 e3 df b1 49 ed 84 4d 67 c1 ad ...p.....I..Mg.. 0060 6a 3c 6d b6 4a e2 99 65 37 a6 d6 b5 66 f0 39 d3 jkm.J..e7...f.9. 0070 15 ff d2 26 ca ac 96 c5 8b bb f2 5d 0d 39 36 69 ...&.......].96i 0080 1d 4b 2e 41 80 44 e2 50 dd 52 50 06 a3 1c bc 0e .K.A.D.P.RP..... 0090 dd 20 90 44 69 1a 4a f6 bf a0 6d 9d 4d 8a d2 a2 . .Di.J...m.M... 00a0 0f c0 1e e4 15 2a 8d c2 ee 6b cd 33 bb da 74 c1 .....*...k.3..t. 00b0 54 45 ad b6 9b 48 db 7b 6a 53 b7 b3 f4 45 21 96 TE...H.{jS...E!. 00c0 50 ee 22 95 21 97 7b 9d ff 9d 60 cf 00 00 00 00 P.".!.{...`..... 00d0 00 00 ..
SSH2_MSG_KEXDH_GEX_REPLY (packet 11)
Upon receipt of the client's SSH2_MSG_KEXDH_GEX_INIT message, the server generates it's own random
number y, calculates f = g^y mod p, and sends "f" to the client. It also calculates k = e^y mod p,
which is the value of the shared secret. The client does the same, using formula k = f^x mod p. If
everything goes right, the client and server should compute identical values for k. This is very
important, because k is one of the elements used to create the exchange hash signature, which is the
primary factor in server authentication.The exchange hash is created by contatenating several pieces of the puzzle, one of which is the value of
k. It is also built with e, f, and data such as the client and server's version strings. Once collected,
the combined data is run through the negotiated hashing algorithm, which is then signed with the server's private key.
Included in this same packet is the server's public key.
Note: p, g, e, and f are all transmitted in plain text Note: based on the above information, an eavesdropper cannot determine x or y. |
The first time .14 connects to .11, this public key is recorded in the client’s known_hosts database
(~/.ssh/known_hosts), which is then used in comparison against the key sent by the server on future
connections. If the key does not match, then the client assumes he has never connected to this server
before and prompts for permission to add it. If the public key does match, it is used to decrypt the
exchange hash signature. In turn, the result is then compared to the client’s own hash value for the same
group of concatenated puzzle pieces. In the event that there is a match, the client concludes with
strong certainty that a) the server possesses the private key that is paired with a pre-authorized
public key and b) the server must know the value of shared secret k. At this point, the server has been
authenticated.
It would be mighty dangerous if the client failed to check for an existing public key in it’s
known_hosts file. Consider the repercussions over an example. Assume an attacker compromises .12, and then
sabotages DNS so that .11’s DNS name now points to .12. He can now cause .14 to try logging into the wrong machine.
Upon connecting, if the host key provided by .12 is not already in known_hosts, the client should produce
a banner that warns of potential attack (mitm or redirection). However, if this check was not conducted and
password authentication was enabled, the user at .14 would then unknowingly enter his credentials into the
compromised .12 system, where the attacker could capture it. Since the server is the first one with
an opportunity to exploit a trust relationship, the protocol was designed with these checks so that the
client can properly authenticate the server first.
Here is the client side debug that relates to these few actions:
debug1: Host '192.168.1.11' is known and matches the RSA host key. debug1: Found key in /home/michali/.ssh/known_hosts:1 debug1: ssh_rsa_verify: signature correct
If the server’s public key was not in known_hosts upon connection, a user would see the following error
(or something similar – it can be personalized):
The authenticity of host '192.168.1.11 (192.168.1.11)' can't be established. RSA key fingerprint is 94:ed:a5:9f:80:ac:7c:25:02:d1:a6:5a:1d:84:02:bc. Are you sure you want to continue connecting (yes/no)? no Host key verification failed.
So back to the real example at this point all the required information for key generation has been negotiated.
Using the shared secret, exchange hash, and session ID (which is the initial exchange hash), the peers calculate
keys for the following purposes:
- client to server initial IV
- server to client initial IV
- client to server encryption
- client to server encryption
- client to server integrity key
- server to client integrity key
Note: the initial IV (initialization vector) is not required if the bulk data |
Internet Protocol, Src: 192.168.1.11 (192.168.1.11), Dst: 192.168.1.14 (192.168.1.14) Transmission Control Protocol, Src Port: 22 (22), Dst Port: 55821 (55821), Seq: 813, Ack: 901, Len: 464 SSH Protocol SSH Version 2 Packet Length: 444 Padding Length: 10 Key Exchange Msg code: Diffie-Hellman GEX Reply (33) Payload: 00000095000000077373682D727361000000012300000081... Padding String: MAC String: 0000 00 0c 29 6d 5c 01 00 50 2c 05 6b a9 08 00 45 00 ..)m..P,.k...E. 0010 02 04 55 2c 40 00 40 06 60 5e c0 a8 01 0b c0 a8 ..U,@.@.`^...... 0020 01 0e 00 16 da 0d 64 6e 2b ed 16 bc ca b8 80 18 ......dn+....... 0030 07 0c b2 99 00 00 01 01 08 0a 0b 79 7d f5 04 99 ...........y}... 0040 fe e5 00 00 01 bc 0a 21 00 00 00 95 00 00 00 07 .......!........ 0050 73 73 68 2d 72 73 61 00 00 00 01 23 00 00 00 81 ssh-rsa....#.... 0060 00 de 38 1b a2 9a 31 65 d5 2e f2 62 a7 64 6b 98 ..8...1e...b.dk. 0070 15 6a 44 29 90 97 f2 db 61 f0 c7 46 26 f6 e7 b5 .jD)....a..F&... 0080 a5 cc 5f 92 e0 f2 b9 40 27 3f e7 46 d3 23 dd f0 .._....@'?.F.#.. 0090 d9 1f f0 89 bc 14 a2 75 de 87 9b 2c fd c3 9d 90 .......u...,.... 00a0 66 3a 2c 68 2a 0a 39 0e 64 cc 9b 04 d9 00 67 bf f:,h*.9.d.....g. 00b0 f5 93 34 19 70 92 86 cb a6 00 dc b8 eb 85 e0 ba ..4.p........... 00c0 d8 ea ce 4d 95 c0 4f f5 ea f5 2a e1 06 d1 1c e1 ...M..O...*..... 00d0 f0 be e9 2c d1 65 22 1f c9 0a 57 2f 57 bf 12 b3 ...,.e"...W/W... 00e0 8b 00 00 00 80 04 79 1d a8 49 7c e9 f2 d7 3e e9 ......y..I|...>. 00f0 af cc 03 31 26 ee 88 ed a2 e5 5c 08 f8 54 83 ae ...1&.......T.. 0100 4c eb 7e 02 d4 43 44 4e 1e 19 55 32 c4 9d 45 e1 L.~..CDN..U2..E. 0110 87 42 d8 92 1b 96 41 d9 d7 43 e2 f0 46 69 b4 4e .B....A..C..Fi.N 0120 3a 2d 63 7f 40 24 a9 ec a1 71 13 37 eb 11 cd 21 :-c.@$...q.7...! 0130 a6 0c b5 ab 0d 3b f6 a9 1c c0 2a 1f 0d 06 5c d5 .....;....*.... 0140 f5 79 4c 44 c3 0c 70 d6 c2 e2 dd b2 c0 5c 86 84 .yLD..p........ 0150 d0 e8 57 58 fd 09 89 bb b6 dd 58 41 81 ef 70 ca ..WX......XA..p. 0160 75 39 f5 c5 78 00 00 00 8f 00 00 00 07 73 73 68 u9..x........ssh 0170 2d 72 73 61 00 00 00 80 6f c0 7e 21 bb 62 22 8e -rsa....o.~!.b". 0180 86 62 b1 89 08 02 ee 7c 24 c0 a7 ec 93 40 54 71 .b.....|$....@Tq 0190 76 23 26 47 f1 20 35 cd d8 4f d9 d7 ae 99 96 42 v#&G. 5..O.....B 01a0 b5 67 aa c9 7b b8 fb ce d9 b5 d2 1d 4c 4b e2 d2 .g..{.......LK.. 01b0 03 37 1c d3 61 e6 fc 0c e5 f7 fa a3 da 1c 74 8f .7..a.........t. 01c0 03 82 ed 27 40 ca a4 e8 57 3f c3 d8 30 77 f3 69 ...'@...W?..0w.i 01d0 ad 74 06 72 85 60 c2 82 7d 52 9d 14 2f cc 43 06 .t.r.`..}R../.C. 01e0 a3 a9 e4 52 fb 00 55 a4 13 64 e2 00 66 7b db 15 ...R..U..d..f{.. 01f0 02 a4 6f d1 f1 f2 31 23 00 00 00 00 00 00 00 00 ..o...1#........ 0200 00 00 00 00 00 0c 0a 15 00 00 00 00 00 00 00 00 ................ 0210 00 00 ..
SSH2_MSG_NEWKEYS (packet 12)
Once the above operations are complete, the client sends it’s SSH2_MSG_NEWKEYS message to the server. This is
a notice that keying materials and algorithms should go into effect from this point on. Here is the client-side
debug output:
debug1: SSH2_MSG_NEWKEYS sent debug1: expecting SSH2_MSG_NEWKEYS debug1: SSH2_MSG_NEWKEYS received
During the SSH session, either side can invoke a rekeying procedure. The RFC draft recommends this be done
once per GB of data transferred or hour of activity, whichever comes first. This would make it more difficult
for an attacker to obtain enough ciphertext to attempt cryptanalysis. It also prevents the 32-bit sequence
number (a value used in MAC generation) from wrapping around back to zero, which would cause replay-attack
vulnerabilities. The sequence number itself is never sent across the network, it is simply known by both
peers based on how many messages have been exchanged.
Internet Protocol, Src: 192.168.1.14 (192.168.1.14), Dst: 192.168.1.11 (192.168.1.11) Transmission Control Protocol, Src Port: 55821 (55821), Dst Port: 22 (22), Seq: 901, Ack: 1277, Len: 16 SSH Protocol SSH Version 2 Packet Length: 12 Padding Length: 10 Key Exchange Msg code: New Keys (21) Padding String: 0000 00 50 2c 05 6b a9 00 0c 29 6d 5c 01 08 00 45 00 .P,.k...)m...E. 0010 00 44 39 da 40 00 40 06 7d 70 c0 a8 01 0e c0 a8 .D9.@.@.}p...... 0020 01 0b da 0d 00 16 16 bc ca b8 64 6e 2d bd 80 18 ..........dn-... 0030 09 74 04 f1 00 00 01 01 08 0a 04 99 fe e9 0b 79 .t.............y 0040 7d f5 00 00 00 0c 0a 15 00 00 00 00 00 00 00 00 }............... 0050 00 00 ..
Once an encrypted transport layer is established and identity of the server is verified, the client
must authenticate. If you had doubts on why the server must be authenticated first, now it makes sense.
If the client authenticates first then it would either do so in plain text or it would send credentials
to a server it isn’t familiar with (and thus shouldn’t trust).
Requesting SSH_AUTH
To accomplish user (and sometimes client host)
authentication, the client invokes SSH-AUTH by first sending an SSH2_MSG_USERAUTH_REQUEST message
specifying “none” as the method. A server will reply with it’s list of supported methods, which normally
include password, keyboard-interactive, public key, and host based. Public key and “none” are the only
required methods according to the SSH-AUTH RFC draft.
Note: SSH-AUTH itself does not do any encrypting or protecting of credentials. |
Public Key Authentication
Since this document is focused on the cryptography of SSH2, only public key will be discussed in this
section. The process is similar to how the server is authenticated using (public) host keys in section 2.
A signature is created by concatenating several pieces of information known by both peers
(strings, byte, and Boolean types in this case). The client then signs this data with the user’s RSA
or DSS private key. This resulting value is sent to the server along with the user’s public key so the
signature can be verified. If this checks out, then the client is believed to posess the private key
of the corresponding public key sent in the packet; however this is only part of the login
process. The more important aspect is confirming that the user who posesses this key pair is actually
authorized to log in.
The SSH-AUTH module does not dictate how the later aspect should be conducted, rather it leaves
this up to the particular implementation. The most common technique is to locate the users’s advertised
public key in the local users’ authorized_keys file (~/.ssh/authorized_keys). This means each user who
intends to authenticate via public key must have prior access to the server in order to plant the public
key, which can be a considerable amount of work if many servers need to be accessed. This is why the
solution is left up to the implementation – a centralized source such as an LDAP database or PKI key
server can be queried for this information.
Aside from the cryptography, there are many other ways to satisfy a server’s authentication
requirements (assuming the server offers more than just the public key method) and even more
ways to authorize a user’s actions. Authentication is not the same as authorization. For example, a
user might pass authentication (ie s/he is who s/he claims to be), but fail authorization (ie s/he is
only allowed to run certain commands remotely). SSH2 can enforce rules such as where a user logs in
from, commands s/he can execute; if X11 forwarding, port forwarding, or psuedo-terminals are allowed;
and it can even chroot users to specific directories. At this point, SSH-CONN is normally invoked to
handle the pty, multiplexing, and launch subsystems (sftp).
From the given information, it’s evident that the security of SSH2 is based just as heavily on the
security of underlying cryptosystems as it is on user interaction. If a user exposes his password and/or
private key, the use of strong cryptography is wasted. Likewise, if a server supports weak algorithms
and allows SSH1, a user can be as careful as possible, but the total system is still relatively insecure.
In this section, some best practices will be discussed so administrators can choose what is right for
their environment.
Passwords vs Public Keys
If password authentication is chosen as a standard, then the only credentials used to authenticate a
user are sent (encrypted, of course) across the network from client to server. If public key authentication
is chosen, neither the private key nor the associated passphrase leave the client. So, on one hand,
the only piece an attacker needs is transmitted; and on the other hand neither piece is transmitted.
At first glance, it might seem like a simple decision, but there is much more.
Password aging can easily be enforced on the server where SSH runs, while key pairs are less likely to
be changed at regular intervals. If an attacker obtained a private key, he would be able to access the
server for a much longer period before a switch locked him out. If a central source such as LDAP or PKI
was available, key pairs could change more frequently without much work; but this isn’t always possible.
Attackers wishing to circumvent security by sniffing a password would have to stage a mitm or similar
type of attack. One option discussed earlier involves DNS redirection to a server capable of logging
keystrokes. Even then, an adversary would need to wait until the user attempted to login and hope that
the server authentication warning is ignored. Remote brute force is also an option, but extremely noisy
and requires a presense online, which in easier to detect. This makes password sniffing and
guessing difficult.
Furthermore, a private key can be brute forced off-line if it is encrypted with a passphrase,
and no one would know it was being conducted. This is assuming the private key is actually encrypted
like it should be, which might be hard to manage and enforce. This type of attack of course would not
be possible without somehow gaining access to a user’s private key file. Likewise, if an attacker first
gains access to a shadow or SAM database, passwords can be brute forced off-line just as easily.
The immediate solution is to apply complexity requirements for the password or passphrase. Users are always
resistant to choosing complex passwords, because they’re difficult to remember, but at least an
operating system can enforce a policy (ie via PAM) for passwords, whereas this is not so easy with
key pairs.
Password authentication and public key authentication both utilize cryptography, but in different
ways. Using public key, a server dictates the supported algorithms for creating the keys. SSH2 requires
DSS and recommends RSA. It will not accept use of any less secure algorithms without custom configuration,
however DSS and RSA happen to be quite strong. In other words, it’s relatively safe by default.
Passwords on the other hand rely on mechanisms offered by the server operating system. Some modern
installations still allow password hashing with algorithms based on DES, a completely intolerable
system these days. A small number even select DES by default.
While this is certainly not an exhaustive list of pros and cons, it should get some ideas flowing.
SSH2 is very flexible and does it’s job well, but as previously warned – a small configuration error
or weak cryptosystem could spoil all of it’s goals.
[1]. OpenSSH client and server.
http://www.openssh.org
[2]. RFC Drafts for SSH-ARCH, SSH-TRANS, SSH-AUTH, and SSH-CONN.
http://www.openssh.org/txt/draft-ietf-secsh-architecture-12.txt
http://www.openssh.org/txt/draft-ietf-secsh-transport-14.txt
http://www.openssh.org/txt/draft-ietf-secsh-userauth-15.txt
http://www.openssh.org/txt/draft-ietf-secsh-connect-15.txt
[3]. Ethereal Protocol Analyzer.
http://www.ethereal.com
[4]. Barrett, Daniel J. and Richard E. Silverman. SSH, The Secure Shell: The Definitive Guide.
USA: O’Reilly Media, Inc. 2005.
http://www.oreilly.com/catalog/sshtdg/
[5]. Snader, Jon C. VPNs Illustrated – Tunnels, VPNs, and IPsec.
USA: Person Education / Addison Wesley. 2006.
http://www.awprofessional.com/bookstore/product.asp?isbn=032124544X&rl=1
[6]. Ferguson, Niels and Bruce Schneier. Practical Cryptography.
Indianaplois, Indiana: Niels Ferguson and Bruce Scheier / Wiley Publishing, Inc.
http://www.schneier.com/book-practical.html