]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/x509: avoid panic when parsing partial PKCS#1 private keys
authorFilippo Valsorda <filippo@golang.org>
Thu, 9 Jan 2025 15:03:08 +0000 (16:03 +0100)
committerGopher Robot <gobot@golang.org>
Thu, 16 Jan 2025 19:01:33 +0000 (11:01 -0800)
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 <tatianabradley@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Commit-Queue: Roland Shoemaker <bracewell@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/643098
Auto-Submit: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
src/crypto/x509/pkcs1.go
src/crypto/x509/x509_test.go

index ca23358c8c4610c88d787d95e7cfde92c05492fc..68aa8dd980c10e95d1d1388784a0932a1e14f5da 100644 (file)
@@ -72,7 +72,9 @@ func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) {
        }
 
        if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 ||
-               priv.Dp.Sign() <= 0 || priv.Dq.Sign() <= 0 || priv.Qinv.Sign() <= 0 {
+               priv.Dp != nil && priv.Dp.Sign() <= 0 ||
+               priv.Dq != nil && priv.Dq.Sign() <= 0 ||
+               priv.Qinv != nil && priv.Qinv.Sign() <= 0 {
                return nil, errors.New("x509: private key contains zero or negative value")
        }
 
index 941ea572e69f26e2eea745045b53128ea85c6425..f67f40778b930bb8b863957a2e486a2747c7c851 100644 (file)
@@ -59,6 +59,32 @@ func TestParsePKCS1PrivateKey(t *testing.T) {
        if _, err := ParsePKCS1PrivateKey(data); err == nil {
                t.Errorf("parsing invalid private key did not result in an error")
        }
+
+       // A partial key without CRT values should still parse.
+       b, _ := asn1.Marshal(struct {
+               Version int
+               N       *big.Int
+               E       int
+               D       *big.Int
+               P       *big.Int
+               Q       *big.Int
+       }{
+               N: priv.N,
+               E: priv.PublicKey.E,
+               D: priv.D,
+               P: priv.Primes[0],
+               Q: priv.Primes[1],
+       })
+       p2, err := ParsePKCS1PrivateKey(b)
+       if err != nil {
+               t.Fatalf("parsing partial private key resulted in an error: %v", err)
+       }
+       if !p2.Equal(priv) {
+               t.Errorf("partial private key did not match original key")
+       }
+       if p2.Precomputed.Dp == nil || p2.Precomputed.Dq == nil || p2.Precomputed.Qinv == nil {
+               t.Errorf("precomputed values not recomputed")
+       }
 }
 
 func TestPKCS1MismatchPublicKeyFormat(t *testing.T) {