Post

SSH

I use SSH almost every work day, but never thought about how it works exactly until one day I got an error message Permission denied (publickey) when trying to git clone a repo. This post documents what I learned about SSH.

There are two versions of SSH: 1.0 and 2.0. Almost all cloud vendors only support SSH 2.0 these days. You can check the remote server ssh version as follows,

1
2
3
$ ssh -v user@server
...
debug1: Remote protocol version 2.0, remote software version 71aa2b1d4

(TODO: write the difference between SSH1.0 and SSH2.0).

The SSH protocol is mainly covered by rfc-4252 and rfc-4253. There are multiple authentication methods: publickey, password and hostbased. Usually, hostbased is disabled in /etc/ssh/ssh_config, and password is seldomly used in any serious workflow, so we only talk about publickey authentication. I will use golang’s implementation to illustrate the SSH connection process.

Connection Steps

We need some preparation steps. First, on the client side, use ssh-keygen to generate a private key and public key: id_rsa and rd_rsa.pub. Then we add the public key to server’s ~/.ssh/authorized_keys.

The connection steps are as follows:

  1. Establish a TCP connection.
  2. SSH Version Exchange.
  3. Negotiate algorithms. It seems that golang does not implements this step. But you can consult rfc-4253 section 7. Or just run ssh -vT git@github.com and the output shows a few SSH2_MSG_KEXINIT messages.
  4. Client sends a service request, and server sends a service response. See code.
  5. Client sends a request which contains its public key, and the signature of the message. The signature is signed by the private key. After server receives this request, it first verifies that the provided public key is one of those inside ~/.ssh/authorized_keys. See code. Here PublicKeyCallback is initialized from file authorized_keys. See this example. Then the server verifies the signature using this public key. If verification is successful, then it means the client indeed holds the private key.

Try ssh -vT git@gitub.com to see the whole authentication chain logs.

Binary Protocol

Where are those message number defined in golang? See code.

This post is licensed under CC BY 4.0 by the author.