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.