3

When an SSH client connects to an SSH server using public key authentication, the server encrypts a message using a public key from authorized_keys, and the client must prove it can decrypt the message.

How does the SSH server know which public key to use for a given client?

The client cannot be sending the public key to the server, as according to this answer the client doesn't need the public key to login: https://security.stackexchange.com/a/42847/174597

Note I am not asking about how public key authentication works. I am asking which public key does a typical SSH server (e.g. OpenSSH) use to encrypt the challenge sent to the client, from a list of keys stored for example in authorized_keys?

17
  • 1
    The client does indeed send the public key to the server, if public key authentication is enabled.
    – forest
    Apr 2, 2018 at 23:48
  • @forest do you have any references to back that up? Did you read the linked answer?
    – aaa90210
    Apr 3, 2018 at 0:00
  • 1
    Is this what you are asking: How are unique SSH users linked to authorized_keys file?
    – forest
    Apr 3, 2018 at 0:21
  • 2
    I'll add one minor detail, that key selection is negotiated. The client tells the server what keys it has, the server picks one, and the client proves it has the private key by sending a signed string. You can see this happen with ssh -vvv user@example.com.
    – nbering
    Apr 3, 2018 at 1:21
  • 1
    Well take SSH being the SSH server/client command on Linux for a start. I am not interested in RFCs.
    – aaa90210
    Apr 3, 2018 at 1:32

1 Answer 1

9

RFC 4252 provides guidelines on how public key authentication should work, but it is not entirely specific on the exact order of the exchange. That said, it was stated in the comments that OP is not interested in RFCs but rather the implementation details for "SSH on Linux", which refers to OpenSSH in most cases.

Connecting to a remote host over SSH with the verbose -v flag, you will typically see the following for each key:

debug1: Offering RSA public key: .ssh/id_rsa.pub

Further, we can look at the source code. After a quick skim, the following is relevant:

if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) &&
        PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
        sshbuf_len(b), NULL, ssh->compat)) == 0) {
        authenticated = 1;
}

The user_key_allowed function checks for the key in an authorized keys file, while the sshkey_verify appears to verify the signature of some buffer.

Combining this information, it appears that the client will use all of its keys until the server accepts one. This is also evident by the fact that having multiple keys present during a single connection attempt may appear on the server as multiple authentication attempts since all of the keys are tried.

Additionally, see @nbering's comments for the details on the challenges/signatures.

Edit: Here's an example where I have several keys, and only the third one tried is accepted by the server. Using -vvv:

debug1: Next authentication method: publickey
debug1: Offering public key: RSA SHA256:QfriqWH2S2uD6wHbxTFSudppOcJ51bB5ABr8ICrUhL8 .ssh/id_rsa2
debug3: send_pubkey_test
debug3: send packet: type 50 # SSH_MSG_USERAUTH_REQUEST
debug2: we sent a publickey packet, wait for reply
debug3: receive packet: type 51 # SSH_MSG_USERAUTH_FAILURE
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password
debug1: Offering public key: RSA SHA256:3M8bnhs+jGJm8X2cgnWzzMrfoeT3WmDkSp8AEr751Sk user@laptop
debug3: send_pubkey_test
debug3: send packet: type 50
debug2: we sent a publickey packet, wait for reply
debug3: receive packet: type 51
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password
debug1: Offering public key: RSA SHA256:CQeP9lcYBVqV11Rn8Ca4Sv+W8l8uU63WQ4TpyG5ZMmI user@laptop
debug3: send_pubkey_test
debug3: send packet: type 50
debug2: we sent a publickey packet, wait for reply
debug3: receive packet: type 60 #  SSH_MSG_USERAUTH_PK_OK
debug1: Server accepts key: pkalg ssh-rsa blen 279
debug2: input_userauth_pk_ok: fp SHA256:CQeP9lcYBVqV11Rn8Ca4Sv+W8l8uU63WQ4TpyG5ZMmI
debug3: sign_and_send_pubkey: RSA SHA256:CQeP9lcYBVqV11Rn8Ca4Sv+W8l8uU63WQ4TpyG5ZMmI
debug3: send packet: type 50
debug3: receive packet: type 52 # SSH_MSG_USERAUTH_SUCCESS 
debug1: Authentication succeeded (publickey).

This again closely follows RFC 4252, pages 8-9.

7
  • 2
    Nice. Clear and concise and with source code to boot. Hope this explains things well enough for @aaa90210's purposes.
    – nbering
    Apr 3, 2018 at 2:00
  • Wrong answer, the client doesn't need a public key to connect using public key authentication.
    – aaa90210
    Apr 4, 2018 at 0:02
  • 6
    @aaa90210 You don't need the public key file on your system, but as long as you have the private key, you can derive the public key if needed. Also, with that attitude, it is unlikely you will get much more help. Apr 4, 2018 at 0:08
  • @multithr3at3d if being surprised all these experts can't answer a basic question is an attitude, then I guess I have one. I am not interested in deriving a public key, I want to know how e.g. OpenSSH knows which key from authorized_keys to encrypt the challenge sent to the client. Such a simple question.
    – aaa90210
    Apr 4, 2018 at 0:10
  • 4
    @aaa90210 OpenSSH does not encrypt any challenge. That's not how the protocol works.
    – forest
    Apr 4, 2018 at 0:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.