From 1c17e20020f974158d1b45be166660c999d6269b Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sun, 16 Jul 2023 14:25:08 +0200 Subject: [PATCH] ssh: fix certificate authentication with OpenSSH 7.2-7.7 OpenSSH 7.2-7.7 advertises support for rsa-sha2-256 and rsa-sha2-512 in the "server-sig-algs" extension but doesn't support these algorithms for certificate authentication, so if the server rejects the key try to use the obtained algorithm as if "server-sig-algs" had not been implemented. Fixes golang/go#58371 Change-Id: Id49960d3dedd32a21e2c6c2689b1696e05398286 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/510155 Reviewed-by: Filippo Valsorda Run-TryBot: Nicola Murino Reviewed-by: Dmitri Shuralyov Reviewed-by: Michael Knyszek TryBot-Result: Gopher Robot LUCI-TryBot-Result: Go LUCI Auto-Submit: Nicola Murino --- ssh/client_auth.go | 20 +++++++++++++++++++- ssh/common.go | 8 ++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/ssh/client_auth.go b/ssh/client_auth.go index 5c3bc25723..34bf089d0b 100644 --- a/ssh/client_auth.go +++ b/ssh/client_auth.go @@ -307,7 +307,10 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand } var methods []string var errSigAlgo error - for _, signer := range signers { + + origSignersLen := len(signers) + for idx := 0; idx < len(signers); idx++ { + signer := signers[idx] pub := signer.PublicKey() as, algo, err := pickSignatureAlgorithm(signer, extensions) if err != nil && errSigAlgo == nil { @@ -321,6 +324,21 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand if err != nil { return authFailure, nil, err } + // OpenSSH 7.2-7.7 advertises support for rsa-sha2-256 and rsa-sha2-512 + // in the "server-sig-algs" extension but doesn't support these + // algorithms for certificate authentication, so if the server rejects + // the key try to use the obtained algorithm as if "server-sig-algs" had + // not been implemented if supported from the algorithm signer. + if !ok && idx < origSignersLen && isRSACert(algo) && algo != CertAlgoRSAv01 { + if contains(as.Algorithms(), KeyAlgoRSA) { + // We retry using the compat algorithm after all signers have + // been tried normally. + signers = append(signers, &multiAlgorithmSigner{ + AlgorithmSigner: as, + supportedAlgorithms: []string{KeyAlgoRSA}, + }) + } + } if !ok { continue } diff --git a/ssh/common.go b/ssh/common.go index dd2ab0d69a..7e9c2cbc64 100644 --- a/ssh/common.go +++ b/ssh/common.go @@ -127,6 +127,14 @@ func isRSA(algo string) bool { return contains(algos, underlyingAlgo(algo)) } +func isRSACert(algo string) bool { + _, ok := certKeyAlgoNames[algo] + if !ok { + return false + } + return isRSA(algo) +} + // supportedPubKeyAuthAlgos specifies the supported client public key // authentication algorithms. Note that this doesn't include certificate types // since those use the underlying algorithm. This list is sent to the client if