ssh: reject certificate signature keys before recursing

parseCert parsed a certificate's SignatureKey by calling ParsePublicKey
again, and only afterwards rejected a certificate used as a signing key.
For a chain of nested certificates this recursed once per level, so a key
with enough nesting exhausted the goroutine stack and crashed with a fatal
stack overflow that recover cannot catch.

Reject the signature key by its declared algorithm before parsing it, which
bounds parsing.

Fixes golang/go#80414

Change-Id: Id51401aae15bfbec006c03ab97635a3b68bd6058
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/802145
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
This commit is contained in:
Nicola Murino
2026-07-22 10:37:06 -07:00
committed by Gopher Robot
parent b53964a1ca
commit 90f76b8ffe
2 changed files with 39 additions and 5 deletions
+10 -5
View File
@@ -229,15 +229,20 @@ func parseCert(in []byte, privAlgo string) (*Certificate, error) {
return nil, err
}
c.Reserved = g.Reserved
// Reject a certificate whose signature key is itself a certificate before
// parsing it. Certificates signed by certificates are not supported (see
// PROTOCOL.certkeys), and rejecting after ParsePublicKey returns would allow
// a chain of nested certificates to recurse once per level, exhausting the
// goroutine stack.
if sigAlgo, _, ok := parseString(g.SignatureKey); !ok {
return nil, errShortRead
} else if _, ok := certKeyAlgoNames[string(sigAlgo)]; ok {
return nil, fmt.Errorf("ssh: the signature key type %q is invalid for certificates", sigAlgo)
}
k, err := ParsePublicKey(g.SignatureKey)
if err != nil {
return nil, err
}
// The Type() function is intended to return only certificate key types, but
// we use certKeyAlgoNames anyway for safety, to match [Certificate.Type].
if _, ok := certKeyAlgoNames[k.Type()]; ok {
return nil, fmt.Errorf("ssh: the signature key type %q is invalid for certificates", k.Type())
}
c.SignatureKey = k
c.Signature, rest, ok = parseSignatureBody(g.Signature)
if !ok || len(rest) > 0 {