From ff03dafdb03eafe35dd29a219550a907489a7a69 Mon Sep 17 00:00:00 2001 From: Akira <50253469+Daquisu@users.noreply.github.com> Date: Wed, 15 Jul 2026 00:46:40 +0000 Subject: [PATCH] ssh: report verified signature format to callback VerifiedPublicKeyCallback currently receives the public-key algorithm declared in the outer authentication request. For RSA authentication, that value can differ from the format of the signature that was successfully verified because compatible RSA algorithm combinations are accepted. This can cause post-verification policy or audit decisions to use the request algorithm instead of the signature format actually verified. Pass sig.Format to VerifiedPublicKeyCallback so signatureAlgorithm identifies the successfully verified signature format. Clarify the callback documentation and add a regression test covering compatible but different RSA request algorithms and signature formats. Fixes golang/go#80411 Change-Id: Ib405378d75367a90536e0814c9d26d4dec9aaa25 GitHub-Last-Rev: 1a4acd4e639361be1f2948a4aef1013436a75ecf GitHub-Pull-Request: golang/crypto#364 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/800740 Reviewed-by: Michael Pratt Reviewed-by: Nicola Murino Reviewed-by: David Chase Auto-Submit: Michael Pratt LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- ssh/server.go | 6 +++-- ssh/server_test.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/ssh/server.go b/ssh/server.go index 07d2405..e090262 100644 --- a/ssh/server.go +++ b/ssh/server.go @@ -229,7 +229,9 @@ type ServerConfig struct { // Permissions object can be the same object, optionally modified, or a // completely new object. If VerifiedPublicKeyCallback is non-nil, // PublicKeyCallback is not allowed to return a PartialSuccessError, which - // can instead be returned by VerifiedPublicKeyCallback. + // can instead be returned by VerifiedPublicKeyCallback. The + // signatureAlgorithm argument is the format of the signature that was + // successfully verified. // // VerifiedPublicKeyCallback does not affect which authentication methods // are included in the list of methods that can be attempted by the client. @@ -891,7 +893,7 @@ userAuthLoop: // Only call VerifiedPublicKeyCallback after the key has been accepted // and successfully verified. If authErr is non-nil, the key is not // considered verified and the callback must not run. - perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, algo) + perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, sig.Format) } } case "gssapi-with-mic": diff --git a/ssh/server_test.go b/ssh/server_test.go index 0f84616..7116ad4 100644 --- a/ssh/server_test.go +++ b/ssh/server_test.go @@ -544,6 +544,62 @@ func TestVerifiedPublicKeyCallback(t *testing.T) { <-done } +func TestVerifiedPublicKeyCallbackSignatureFormat(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + var gotSignatureAlgorithm string + serverConf := &ServerConfig{ + PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { + return nil, nil + }, + VerifiedPublicKeyCallback: func(conn ConnMetadata, key PublicKey, permissions *Permissions, signatureAlgorithm string) (*Permissions, error) { + gotSignatureAlgorithm = signatureAlgorithm + return permissions, nil + }, + } + serverConf.AddHostKey(testSigners["rsa"]) + + serverDone := make(chan error, 1) + go func() { + conn, _, _, err := NewServerConn(c1, serverConf) + if err == nil { + conn.Close() + } + serverDone <- err + }() + + clientConf := &ClientConfig{ + User: "user", + Auth: []AuthMethod{ + // The selected algorithm and signature format differ for + // compatibility with old RSA clients. + configurablePublicKeyCallback{ + signer: testSigners["rsa"].(AlgorithmSigner), + signatureAlgo: KeyAlgoRSASHA256, + signatureFormat: KeyAlgoRSA, + }, + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + clientConn, _, _, clientErr := NewClientConn(c2, "", clientConf) + if clientErr == nil { + clientConn.Close() + } + serverErr := <-serverDone + if clientErr != nil || serverErr != nil { + t.Fatalf("connection failed: client error: %v; server error: %v", clientErr, serverErr) + } + if gotSignatureAlgorithm != KeyAlgoRSA { + t.Errorf("signature algorithm = %q; want verified signature format %q", gotSignatureAlgorithm, KeyAlgoRSA) + } +} + func TestVerifiedPublicCallbackPartialSuccess(t *testing.T) { c1, c2, err := netPipe() if err != nil {