Skip to content

Commit 01abca8

Browse files
thatnealpatelrickystewart
authored andcommitted
[release-branch.go1.24] crypto/x509: mitigate DoS vector when intermediate certificate contains DSA public key
An attacker could craft an intermediate X.509 certificate containing a DSA public key and can crash a remote host with an unauthenticated call to any endpoint that verifies the certificate chain. Thank you to Jakub Ciolek for reporting this issue. Fixes CVE-2025-58188 For golang#75675 Fixes golang#75702 Change-Id: I2ecbb87b9b8268dbc55c8795891e596ab60f0088 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2780 Reviewed-by: Damien Neil <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2964 Reviewed-on: https://go-review.googlesource.com/c/go/+/709836 TryBot-Bypass: Michael Pratt <[email protected]> Reviewed-by: Carlos Amedee <[email protected]> Auto-Submit: Michael Pratt <[email protected]>
1 parent bd9a6e0 commit 01abca8

File tree

2 files changed

+131
-1
lines changed

2 files changed

+131
-1
lines changed

src/crypto/x509/verify.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,10 @@ func alreadyInChain(candidate *Certificate, chain []*Certificate) bool {
873873
if !bytes.Equal(candidate.RawSubject, cert.RawSubject) {
874874
continue
875875
}
876-
if !candidate.PublicKey.(pubKeyEqual).Equal(cert.PublicKey) {
876+
// We enforce the canonical encoding of SPKI (by only allowing the
877+
// correct AI paremeter encodings in parseCertificate), so it's safe to
878+
// directly compare the raw bytes.
879+
if !bytes.Equal(candidate.RawSubjectPublicKeyInfo, cert.RawSubjectPublicKeyInfo) {
877880
continue
878881
}
879882
var certSAN *pkix.Extension

src/crypto/x509/verify_test.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package x509
66

77
import (
88
"crypto"
9+
"crypto/dsa"
910
"crypto/ecdsa"
1011
"crypto/elliptic"
1112
"crypto/rand"
@@ -2837,3 +2838,129 @@ func TestVerifyBareWildcard(t *testing.T) {
28372838
t.Fatalf("VerifyHostname unexpected success with bare wildcard SAN")
28382839
}
28392840
}
2841+
2842+
func TestCertificateChainSignedByECDSA(t *testing.T) {
2843+
caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2844+
if err != nil {
2845+
t.Fatal(err)
2846+
}
2847+
root := &Certificate{
2848+
SerialNumber: big.NewInt(1),
2849+
Subject: pkix.Name{CommonName: "X"},
2850+
NotBefore: time.Now().Add(-time.Hour),
2851+
NotAfter: time.Now().Add(365 * 24 * time.Hour),
2852+
IsCA: true,
2853+
KeyUsage: KeyUsageCertSign | KeyUsageCRLSign,
2854+
BasicConstraintsValid: true,
2855+
}
2856+
caDER, err := CreateCertificate(rand.Reader, root, root, &caKey.PublicKey, caKey)
2857+
if err != nil {
2858+
t.Fatal(err)
2859+
}
2860+
root, err = ParseCertificate(caDER)
2861+
if err != nil {
2862+
t.Fatal(err)
2863+
}
2864+
2865+
leafKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2866+
leaf := &Certificate{
2867+
SerialNumber: big.NewInt(42),
2868+
Subject: pkix.Name{CommonName: "leaf"},
2869+
NotBefore: time.Now().Add(-10 * time.Minute),
2870+
NotAfter: time.Now().Add(24 * time.Hour),
2871+
KeyUsage: KeyUsageDigitalSignature,
2872+
ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
2873+
BasicConstraintsValid: true,
2874+
}
2875+
leafDER, err := CreateCertificate(rand.Reader, leaf, root, &leafKey.PublicKey, caKey)
2876+
if err != nil {
2877+
t.Fatal(err)
2878+
}
2879+
leaf, err = ParseCertificate(leafDER)
2880+
if err != nil {
2881+
t.Fatal(err)
2882+
}
2883+
2884+
inter, err := ParseCertificate(dsaSelfSignedCNX(t))
2885+
if err != nil {
2886+
t.Fatal(err)
2887+
}
2888+
2889+
inters := NewCertPool()
2890+
inters.AddCert(root)
2891+
inters.AddCert(inter)
2892+
2893+
wantErr := "certificate signed by unknown authority"
2894+
_, err = leaf.Verify(VerifyOptions{Intermediates: inters, Roots: NewCertPool()})
2895+
if !strings.Contains(err.Error(), wantErr) {
2896+
t.Errorf("got %v, want %q", err, wantErr)
2897+
}
2898+
}
2899+
2900+
// dsaSelfSignedCNX produces DER-encoded
2901+
// certificate with the properties:
2902+
//
2903+
// Subject=Issuer=CN=X
2904+
// DSA SPKI
2905+
// Matching inner/outer signature OIDs
2906+
// Dummy ECDSA signature
2907+
func dsaSelfSignedCNX(t *testing.T) []byte {
2908+
t.Helper()
2909+
var params dsa.Parameters
2910+
if err := dsa.GenerateParameters(&params, rand.Reader, dsa.L1024N160); err != nil {
2911+
t.Fatal(err)
2912+
}
2913+
2914+
var dsaPriv dsa.PrivateKey
2915+
dsaPriv.Parameters = params
2916+
if err := dsa.GenerateKey(&dsaPriv, rand.Reader); err != nil {
2917+
t.Fatal(err)
2918+
}
2919+
dsaPub := &dsaPriv.PublicKey
2920+
2921+
type dsaParams struct{ P, Q, G *big.Int }
2922+
paramDER, err := asn1.Marshal(dsaParams{dsaPub.P, dsaPub.Q, dsaPub.G})
2923+
if err != nil {
2924+
t.Fatal(err)
2925+
}
2926+
yDER, err := asn1.Marshal(dsaPub.Y)
2927+
if err != nil {
2928+
t.Fatal(err)
2929+
}
2930+
2931+
spki := publicKeyInfo{
2932+
Algorithm: pkix.AlgorithmIdentifier{
2933+
Algorithm: oidPublicKeyDSA,
2934+
Parameters: asn1.RawValue{FullBytes: paramDER},
2935+
},
2936+
PublicKey: asn1.BitString{Bytes: yDER, BitLength: 8 * len(yDER)},
2937+
}
2938+
2939+
rdn := pkix.Name{CommonName: "X"}.ToRDNSequence()
2940+
b, err := asn1.Marshal(rdn)
2941+
if err != nil {
2942+
t.Fatal(err)
2943+
}
2944+
rawName := asn1.RawValue{FullBytes: b}
2945+
2946+
algoIdent := pkix.AlgorithmIdentifier{Algorithm: oidSignatureDSAWithSHA256}
2947+
tbs := tbsCertificate{
2948+
Version: 0,
2949+
SerialNumber: big.NewInt(1002),
2950+
SignatureAlgorithm: algoIdent,
2951+
Issuer: rawName,
2952+
Validity: validity{NotBefore: time.Now().Add(-time.Hour), NotAfter: time.Now().Add(24 * time.Hour)},
2953+
Subject: rawName,
2954+
PublicKey: spki,
2955+
}
2956+
c := certificate{
2957+
TBSCertificate: tbs,
2958+
SignatureAlgorithm: algoIdent,
2959+
SignatureValue: asn1.BitString{Bytes: []byte{0}, BitLength: 8},
2960+
}
2961+
dsaDER, err := asn1.Marshal(c)
2962+
if err != nil {
2963+
t.Fatal(err)
2964+
}
2965+
return dsaDER
2966+
}

0 commit comments

Comments
 (0)