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 {