ssh/knownhosts: respect @revoked CA keys Fixes CVE-2026-42508 Fixes golang/go#79568 Change-Id: I20f33cba20756b048726ff3464b83871859d3b5c Reviewed-on: https://go-review.googlesource.com/c/crypto/+/781220 Reviewed-by: Nicholas Husin <husin@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Nicholas Husin <nsh@golang.org> Reviewed-by: Nicola Murino <nicola.murino@gmail.com> Reviewed-by: Roland Shoemaker <roland@golang.org>
diff --git a/ssh/knownhosts/knownhosts.go b/ssh/knownhosts/knownhosts.go index 1ebd7e6..e57cf5b 100644 --- a/ssh/knownhosts/knownhosts.go +++ b/ssh/knownhosts/knownhosts.go
@@ -160,8 +160,13 @@ // IsRevoked can be used as a callback in ssh.CertChecker func (db *hostKeyDB) IsRevoked(key *ssh.Certificate) bool { - _, ok := db.revoked[string(key.Marshal())] - return ok + if _, ok := db.revoked[string(key.Marshal())]; ok { + return true + } + if _, ok := db.revoked[string(key.SignatureKey.Marshal())]; ok { + return true + } + return false } const markerCert = "@cert-authority"
diff --git a/ssh/knownhosts/knownhosts_test.go b/ssh/knownhosts/knownhosts_test.go index 552a556..4d3ca59 100644 --- a/ssh/knownhosts/knownhosts_test.go +++ b/ssh/knownhosts/knownhosts_test.go
@@ -6,6 +6,8 @@ import ( "bytes" + "crypto/ed25519" + "crypto/rand" "fmt" "net" "reflect" @@ -272,7 +274,45 @@ } } -// TODO(hanwen): test coverage for certificates. +func TestRevokedCA(t *testing.T) { + _, caPriv, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + caSigner, err := ssh.NewSignerFromKey(caPriv) + if err != nil { + t.Fatal(err) + } + caKey := caSigner.PublicKey() + + _, hostPriv, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + hostKey, err := ssh.NewPublicKey(hostPriv.Public()) + if err != nil { + t.Fatal(err) + } + + cert := &ssh.Certificate{ + CertType: ssh.HostCert, + Key: hostKey, + ValidBefore: ssh.CertTimeInfinity, + ValidPrincipals: []string{"server.org"}, + } + if err := cert.SignCert(rand.Reader, caSigner); err != nil { + t.Fatal(err) + } + + caLine := "ssh-ed25519 " + serialize(caKey)[len("ssh-ed25519 "):] + knownHostsData := "@revoked server.org " + caLine + "\n" + + "@cert-authority server.org " + caLine + "\n" + db := testDB(t, knownHostsData) + + if !db.IsRevoked(cert) { + t.Error("IsRevoked returned false for certificate signed by revoked CA") + } +} const testHostname = "hostname"