ssh/agent: fix non-RSA certificates
The type of ssh.PublicKey.Type can be a certificate type, while the
algorithm passed to SignWithAlgorithm is going to be an underlying
algorithm.
Fixes golang/go#52185
Change-Id: I0f7c46defa83d1fd64a3c1e861734650b20cca21
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/404614
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
diff --git a/ssh/agent/client.go b/ssh/agent/client.go
index dbc79d5..3c4d18a 100644
--- a/ssh/agent/client.go
+++ b/ssh/agent/client.go
@@ -772,7 +772,7 @@
}
func (s *agentKeyringSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*ssh.Signature, error) {
- if algorithm == "" || algorithm == s.pub.Type() {
+ if algorithm == "" || algorithm == underlyingAlgo(s.pub.Type()) {
return s.Sign(rand, data)
}
@@ -791,6 +791,33 @@
var _ ssh.AlgorithmSigner = &agentKeyringSigner{}
+// certKeyAlgoNames is a mapping from known certificate algorithm names to the
+// corresponding public key signature algorithm.
+//
+// This map must be kept in sync with the one in certs.go.
+var certKeyAlgoNames = map[string]string{
+ ssh.CertAlgoRSAv01: ssh.KeyAlgoRSA,
+ ssh.CertAlgoRSASHA256v01: ssh.KeyAlgoRSASHA256,
+ ssh.CertAlgoRSASHA512v01: ssh.KeyAlgoRSASHA512,
+ ssh.CertAlgoDSAv01: ssh.KeyAlgoDSA,
+ ssh.CertAlgoECDSA256v01: ssh.KeyAlgoECDSA256,
+ ssh.CertAlgoECDSA384v01: ssh.KeyAlgoECDSA384,
+ ssh.CertAlgoECDSA521v01: ssh.KeyAlgoECDSA521,
+ ssh.CertAlgoSKECDSA256v01: ssh.KeyAlgoSKECDSA256,
+ ssh.CertAlgoED25519v01: ssh.KeyAlgoED25519,
+ ssh.CertAlgoSKED25519v01: ssh.KeyAlgoSKED25519,
+}
+
+// underlyingAlgo returns the signature algorithm associated with algo (which is
+// an advertised or negotiated public key or host key algorithm). These are
+// usually the same, except for certificate algorithms.
+func underlyingAlgo(algo string) string {
+ if a, ok := certKeyAlgoNames[algo]; ok {
+ return a
+ }
+ return algo
+}
+
// Calls an extension method. It is up to the agent implementation as to whether or not
// any particular extension is supported and may always return an error. Because the
// type of the response is up to the implementation, this returns the bytes of the
diff --git a/ssh/certs.go b/ssh/certs.go
index a69e224..4600c20 100644
--- a/ssh/certs.go
+++ b/ssh/certs.go
@@ -460,6 +460,8 @@
// certKeyAlgoNames is a mapping from known certificate algorithm names to the
// corresponding public key signature algorithm.
+//
+// This map must be kept in sync with the one in agent/client.go.
var certKeyAlgoNames = map[string]string{
CertAlgoRSAv01: KeyAlgoRSA,
CertAlgoRSASHA256v01: KeyAlgoRSASHA256,