Version sharing
The handshake begins with the fact that both sides send each other a string with the version number. Nothing extremely exciting happens in this part of the handshake, but it should be noted that most relatively modern clients and servers only support SSH 2.0 due to design flaws in version 1.0.
Key exchange
During the key exchange process (sometimes called KEX), the parties exchange publicly available information and derive a secret shared by the client and server. This secret cannot be discovered or obtained from publicly available information.
Key Exchange Initialization
Key exchange begins with the fact that both parties send each other a message
SSH_MSG_KEX_INIT
with a list of supported cryptographic primitives and their preferred order.
Cryptographic primitives must establish the building blocks that will be used for key exchange, and then complete data encryption. The table below lists the cryptographic primitives that Teleport supports.
Key Exchange (KEX) | Symmetric cipher | Message Authentication Code (MAC) | Server Host Key Algorithm |
---|---|---|---|
curve25519-sha256@libssh.org | chacha20-poly1305@openssh.com | hmac-sha2-256-etm@openssh.com | ssh-rsa-cert-v01@openssh.com |
ecdh-sha2-nistp256 | aes128-gcm@openssh.com | hmac-sha2-256 | ssh-rsa |
ecdh-sha2-nistp384 | aes256-ctr | ||
ecdh-sha2-nistp521 | aes192-ctr | ||
aes128-ctr |
Initialization of the Diffie-Hellman Protocol on Elliptic Curves
Since both sides use the same algorithm to select cryptographic primitives from the list of supported ones, after initialization, you can immediately begin exchanging keys. Teleport only supports the Elliptic Curve Diffie-Hellman (ECDH) protocol, so key exchange begins with the client generating an ephemeral key pair (private and associated public key) and sending the server its public key in the message
SSH_MSG_KEX_ECDH_INIT
.
It is worth emphasizing that this key pair is ephemeral: it is used only for key exchange, and then it will be deleted. This makes it extremely difficult to conduct a class of attacks where an attacker passively records encrypted traffic with the hope of stealing the private key sometime in the future (as stipulated by Yarovaya’s law - approx. Trans.). It is very difficult to steal something that no longer exists. This property is called forward secrecy.
![](https://habrastorage.org/webt/5c/og/b0/5cogb0xbwdlj_k-88ljfpet1olw.png)
Fig. 1. Generating a key exchange initialization message
Diffie-Hellman response on elliptic curves
The server waits for the
SSH_MSG_KEX_ECDH_INIT
message, and upon receipt, generates its own ephemeral key pair. Using the client’s public key and its own key pair, the server can generate a shared secret K.
Then the server generates something called the exchange hash H and signs it, generating a signed HS hash (more on Fig. 3). The exchange hash and its signature serve several purposes:
- Since the exchange hash includes a shared secret, it proves that the other party was able to create a shared secret.
- The hash / verification cycle of the hash and exchange signature allows the client to verify that the server owns the private key of the host, and therefore the client is connected to the correct server (if the client can trust the corresponding public key, more on this later).
- Due to the signature of the hash instead of signing the input data, the size of the signed data is significantly reduced and leads to a faster handshake.
The exchange hash is generated by taking the hash (SHA256, SHA384 or SHA512, depending on the key exchange algorithm) of the following fields:
- Magic
M
Client version, server version, client messageSSH_MSG_KEXINIT
, server messageSSH_MSG_KEXINIT
.
- The public key (or certificate) of the
HPub
serverHPub
. This value (and its corresponding HPriv private key) is usually generated during the initialization of the process, and not for each handshake.
- Client Public Key
- Server Public Key
B
- Shared Secret
K
With this information, the server can construct the
SSH_MSG_KEX_ECDH_REPLY
message using the ephemeral public key of server
B
, the public key of the
HPub
server host, and the signature on the
HS
exchange hash. See fig. 4 for more details.
![](https://habrastorage.org/webt/v1/df/pr/v1dfprnrhjw01tlsqn4u148cgqc.png)
Fig. 2. Generation of the exchange hash H
As soon as the client received
SSH_MSG_KEX_ECDH_REPLY
from the server, it has everything necessary to calculate the secret
K
and the exchange hash
H
In the last part of the key exchange, the client retrieves the host public key (or certificate) from
SSH_MSG_KEX_ECDH_REPLY
and verifies the signature of the
HS
exchange hash confirming ownership of the private key of the host. To prevent attacks of the “man in the middle” type (MitM), after checking the signature, the host’s public key (or certificate) is checked against the local database of known hosts; if this key (or certificate) is not trusted, the connection is disconnected.
The SSH client offers to add the host key to the local database of known hosts. For OpenSSH, this is usuallyThe authenticity of host 10.10.10.10 (10.10.10.10) 'can't be established. ECDSA key fingerprint is SHA256: pnPn3SxExHtVGNdzbV0cRzUrtNhqZv + Pwdq / qGQPZO3. Are you sure you want to continue connecting (yes / no)?
~/.ssh/known_hosts
Such a message means that the key presented is not in your local database of known hosts. A good way to avoid such messages is to use SSH certificates (which Teleport does by default) instead of keys, which allows you to simply store the certificate of the certification authority in a local database of known hosts, and then check all the hosts signed by this CA.
![](https://habrastorage.org/webt/xh/jg/zo/xhjgzo174zrxjc-grwuerapldsc.png)
Fig. 3. Generating an ECDH key exchange response
New keys
Before starting mass data encryption, the last nuance remained. Both parties must create six keys: two for encryption, two initialization vectors (IV) and two for integrity. You may ask, why are there so many extra keys? Isn't K secret enough? No, not enough.
First, why do we need separate keys for encryption, integrity and IV. One of the reasons is related to the historical development of protocols such as TLS and SSH, namely, the negotiation of cryptographic primitives. In some selected cryptographic primitives, key reuse is not a problem. But, as Henryk Hellstrom correctly explains , if the primitives are incorrectly selected (for example, AES-256-CBC for encryption and AES-256-CBC-MAC for authentication), the consequences can be disastrous. It should be noted that protocol developers are gradually abandoning such flexibility to make protocols simpler and more secure.
Next, why are keys of each type used.
Encryption keys ensure data confidentiality and are used with a symmetric cipher to encrypt and decrypt a message.
Integrity keys are commonly used with Message Authentication Code (MAC) to ensure the authenticity of the ciphertext. In the absence of integrity checks, an attacker can modify the ciphertext that is transmitted over open channels and you will decrypt a fake message. This scheme is usually called Encrypt-then-MAC .
It should be noted that modern AEAD ciphers (authenticated encryption with attached data, when part of the message is encrypted, part remains open and the whole message is authenticated) like
aes128-gcm@openssh.com
and
chacha20-poly1305@openssh.com
do not actually use the derived key integrity for the MAC, and perform authentication within their structure.
Initialization vectors (IV) are usually random numbers used as input for a symmetric cipher. Their goal is to ensure that the same message, encrypted twice, does not lead to the same ciphertext. The need for such a procedure is perfectly demonstrated by the famous Tux penguin image, encrypted in electronic code book (ECB) mode.
![](https://habrastorage.org/webt/fw/f6/fo/fwf6folqfhnw1mh48lkxc7lh8uq.png)
From left to right. (1) Clear text as an image. (2) A cryptogram obtained by encryption in ECB mode. (3) A cryptogram obtained by encryption in a mode other than ECB. The image is a pseudo-random pixel sequence
Using (and hacking) IV vectors is an interesting topic in itself, which Filippo Walsord wrote about .
Finally, why do keys come in pairs? As Thomas Pornin noted, if only one integrity key is used, the attacker can reproduce the record sent to him to the client, and he will consider it valid. With paired integrity keys (on the server and the client), the client will check the integrity of the ciphertext and this trick will not work.
Now with an understanding of why these keys are needed, let's see how they are generated according to the RFC :
- Starting vector IV from client to server:
HASH(K || H || «A» || session_id)
- Starting vector IV from server to client:
HASH(K || H || «B» || session_id)
- Encryption key from client to server:
HASH(K || H || «C» || session_id)
- Encryption key from server to client:
HASH(K || H || «D» || session_id)
- Integrity control key from client to server:
HASH(K || H || «E» || session_id)
- Integrity control key from server to client:
HASH(K || H || «F» || session_id)
Here the SHA hash algorithm is used {256, 384 or 512} depending on the key exchange algorithm, and the symbol || implies concatenation, i.e. traction.
As soon as these values are calculated, both sides send
SSH_MSG_NEWKEYS
to inform the other side that the key exchange is complete and all future communications should be carried out using the new keys created above.
![](https://habrastorage.org/webt/lx/gn/71/lxgn71y33ihsymnavtekvnhw2l4.png)
Fig. 4:. Initial vector generation IV. Generation for other keys occurs according to the same scheme, if we replace A and B with C, D, E and F, respectively
Conclusion
At this stage, both parties agreed on cryptographic primitives, exchanged secrets and generated key material for the selected primitives. Now, a secure channel can be established between the client and the server, which will ensure confidentiality and integrity.
This is how SSH handshakes establish a secure connection between clients and servers.