From 1a2c46781cebbb1ff71a1a05c33d5db79a10a301 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Fri, 30 May 2025 09:47:34 +0200 Subject: [PATCH] auth: Process outstanding packets before selecting signature algorithm Originally reported by Till on mailing list here: https://archive.libssh.org/libssh/2025-05/0000000.html After some debugging, it turns out the client code does not guarantee the extensions are processed before making decisions on the signature algorithm that is being used for authentication, causing false-positive failures. This does not happen in the tests, where we initially call ssh_userauth_none, which enumerates authentications methods and as a side effect processes outstanding packets such as SSH_EXT_INFO message with the server-sig-algs extension. When the first function called after `ssh_connect()` is `ssh_userauth_publickey()`, the `ssh_userauth_request_service()` was wrongly called only after the signature algorithm compatibility was checked. Signed-off-by: Jakub Jelen Reviewed-by: Norbert Pocs (cherry picked from commit 12baa5200a3c6d6d0a5779aae3454fcb06483a61) --- src/auth.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/auth.c b/src/auth.c index 36ad2ed5..0c0412a4 100644 --- a/src/auth.c +++ b/src/auth.c @@ -521,6 +521,17 @@ int ssh_userauth_try_publickey(ssh_session session, return SSH_AUTH_ERROR; } + /* Note, that this is intentionally before checking the signature type + * compatibility to make sure the possible EXT_INFO packet is processed, + * extensions recorded and the right signature type is used below + */ + rc = ssh_userauth_request_service(session); + if (rc == SSH_AGAIN) { + return SSH_AUTH_AGAIN; + } else if (rc == SSH_ERROR) { + return SSH_AUTH_ERROR; + } + /* Check if the given public key algorithm is allowed */ sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type); if (sig_type_c == NULL) { @@ -544,13 +555,6 @@ int ssh_userauth_try_publickey(ssh_session session, return SSH_AUTH_DENIED; } - rc = ssh_userauth_request_service(session); - if (rc == SSH_AGAIN) { - return SSH_AUTH_AGAIN; - } else if (rc == SSH_ERROR) { - return SSH_AUTH_ERROR; - } - /* public key */ rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_s); if (rc < 0) { @@ -652,6 +656,17 @@ int ssh_userauth_publickey(ssh_session session, return SSH_AUTH_ERROR; } + /* Note, that this is intentionally before checking the signature type + * compatibility to make sure the possible EXT_INFO packet is processed, + * extensions recorded and the right signature type is used below + */ + rc = ssh_userauth_request_service(session); + if (rc == SSH_AGAIN) { + return SSH_AUTH_AGAIN; + } else if (rc == SSH_ERROR) { + return SSH_AUTH_ERROR; + } + /* Cert auth requires presenting the cert type name (*-cert@openssh.com) */ key_type = privkey->cert != NULL ? privkey->cert_type : privkey->type; @@ -678,13 +693,6 @@ int ssh_userauth_publickey(ssh_session session, return SSH_AUTH_DENIED; } - rc = ssh_userauth_request_service(session); - if (rc == SSH_AGAIN) { - return SSH_AUTH_AGAIN; - } else if (rc == SSH_ERROR) { - return SSH_AUTH_ERROR; - } - /* get public key or cert */ rc = ssh_pki_export_pubkey_blob(privkey, &str); if (rc < 0) { @@ -769,6 +777,10 @@ static int ssh_userauth_agent_publickey(ssh_session session, return SSH_ERROR; } + /* Note, that this is intentionally before checking the signature type + * compatibility to make sure the possible EXT_INFO packet is processed, + * extensions recorded and the right signature type is used below + */ rc = ssh_userauth_request_service(session); if (rc == SSH_AGAIN) { return SSH_AUTH_AGAIN;