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:
- Establish a TCP connection.
- SSH Version Exchange.
- 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 fewSSH2_MSG_KEXINIT
messages. - Client sends a service request, and server sends a service response. See code.
- 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. HerePublicKeyCallback
is initialized from fileauthorized_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.