Skip to content

Commit 3de5aca

Browse files
FiloSottilegopherbot
authored andcommitted
[release-branch.go1.24] crypto/x509: avoid panic when parsing partial PKCS#1 private keys
These keys are off-spec, but have historically been accepted by ParsePKCS1PrivateKey. Thanks to Philippe Antoine (Catena cyber) for reporting this issue. Fixes #71216 Fixes CVE-2025-22865 Change-Id: I6a6a46564156fa32e29e8d6acbec3fbac47c7352 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1820 Reviewed-by: Tatiana Bradley <[email protected]> Reviewed-by: Damien Neil <[email protected]> Commit-Queue: Roland Shoemaker <[email protected]> (cherry picked from commit 36c6c8b6957e155770461fd710aea9477ef3bc88) Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1841 Reviewed-on: https://go-review.googlesource.com/c/go/+/643102 Auto-Submit: Michael Knyszek <[email protected]> Reviewed-by: Michael Pratt <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 8336dfd commit 3de5aca

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

src/crypto/x509/pkcs1.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) {
7272
}
7373

7474
if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 ||
75-
priv.Dp.Sign() <= 0 || priv.Dq.Sign() <= 0 || priv.Qinv.Sign() <= 0 {
75+
priv.Dp != nil && priv.Dp.Sign() <= 0 ||
76+
priv.Dq != nil && priv.Dq.Sign() <= 0 ||
77+
priv.Qinv != nil && priv.Qinv.Sign() <= 0 {
7678
return nil, errors.New("x509: private key contains zero or negative value")
7779
}
7880

src/crypto/x509/x509_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,32 @@ func TestParsePKCS1PrivateKey(t *testing.T) {
5959
if _, err := ParsePKCS1PrivateKey(data); err == nil {
6060
t.Errorf("parsing invalid private key did not result in an error")
6161
}
62+
63+
// A partial key without CRT values should still parse.
64+
b, _ := asn1.Marshal(struct {
65+
Version int
66+
N *big.Int
67+
E int
68+
D *big.Int
69+
P *big.Int
70+
Q *big.Int
71+
}{
72+
N: priv.N,
73+
E: priv.PublicKey.E,
74+
D: priv.D,
75+
P: priv.Primes[0],
76+
Q: priv.Primes[1],
77+
})
78+
p2, err := ParsePKCS1PrivateKey(b)
79+
if err != nil {
80+
t.Fatalf("parsing partial private key resulted in an error: %v", err)
81+
}
82+
if !p2.Equal(priv) {
83+
t.Errorf("partial private key did not match original key")
84+
}
85+
if p2.Precomputed.Dp == nil || p2.Precomputed.Dq == nil || p2.Precomputed.Qinv == nil {
86+
t.Errorf("precomputed values not recomputed")
87+
}
6288
}
6389

6490
func TestPKCS1MismatchPublicKeyFormat(t *testing.T) {

0 commit comments

Comments
 (0)