145 lines
4.7 KiB
Diff
145 lines
4.7 KiB
Diff
From 041fa43ad6669ac10ccdcdd8f47653897c592dfb Mon Sep 17 00:00:00 2001
|
|
From: Filippo Valsorda <filippo@golang.org>
|
|
Date: Wed, 2 Feb 2022 09:14:57 -0800
|
|
Subject: [PATCH] [release-branch.go1.17] crypto/elliptic: make IsOnCurve
|
|
return false for invalid field elements
|
|
|
|
Updates #50974
|
|
Fixes #50978
|
|
Fixes CVE-2022-23806
|
|
|
|
Change-Id: I0201c2c88f13dd82910985a495973f1683af9259
|
|
Reviewed-on: https://go-review.googlesource.com/c/go/+/382854
|
|
Trust: Filippo Valsorda <filippo@golang.org>
|
|
Run-TryBot: Filippo Valsorda <filippo@golang.org>
|
|
Reviewed-by: Katie Hockman <katie@golang.org>
|
|
Trust: Katie Hockman <katie@golang.org>
|
|
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
|
|
Conflict: NA
|
|
Reference: https://go-review.googlesource.com/c/go/+/382854
|
|
---
|
|
src/crypto/elliptic/elliptic.go | 5 +++
|
|
src/crypto/elliptic/elliptic_test.go | 55 ++++++++++++++++++++++++++++
|
|
src/crypto/elliptic/p224.go | 5 +++
|
|
src/crypto/elliptic/p521.go | 5 +++
|
|
4 files changed, 70 insertions(+)
|
|
|
|
diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go
|
|
index f072960bfed..b84339ec1c2 100644
|
|
--- a/src/crypto/elliptic/elliptic.go
|
|
+++ b/src/crypto/elliptic/elliptic.go
|
|
@@ -86,6 +86,11 @@ func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
|
|
return specific.IsOnCurve(x, y)
|
|
}
|
|
|
|
+ if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
|
|
+ y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
|
|
+ return false
|
|
+ }
|
|
+
|
|
// y² = x³ - 3x + b
|
|
y2 := new(big.Int).Mul(y, y)
|
|
y2.Mod(y2, curve.P)
|
|
diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go
|
|
index 183861a54b5..3fe53c5f332 100644
|
|
--- a/src/crypto/elliptic/elliptic_test.go
|
|
+++ b/src/crypto/elliptic/elliptic_test.go
|
|
@@ -174,6 +174,61 @@ func testUnmarshalToLargeCoordinates(t *testing.T, curve Curve) {
|
|
}
|
|
}
|
|
|
|
+// TestInvalidCoordinates tests big.Int values that are not valid field elements
|
|
+// (negative or bigger than P). They are expected to return false from
|
|
+// IsOnCurve, all other behavior is undefined.
|
|
+func TestInvalidCoordinates(t *testing.T) {
|
|
+ testAllCurves(t, testInvalidCoordinates)
|
|
+}
|
|
+
|
|
+func testInvalidCoordinates(t *testing.T, curve Curve) {
|
|
+ checkIsOnCurveFalse := func(name string, x, y *big.Int) {
|
|
+ if curve.IsOnCurve(x, y) {
|
|
+ t.Errorf("IsOnCurve(%s) unexpectedly returned true", name)
|
|
+ }
|
|
+ }
|
|
+
|
|
+ p := curve.Params().P
|
|
+ _, x, y, _ := GenerateKey(curve, rand.Reader)
|
|
+ xx, yy := new(big.Int), new(big.Int)
|
|
+
|
|
+ // Check if the sign is getting dropped.
|
|
+ xx.Neg(x)
|
|
+ checkIsOnCurveFalse("-x, y", xx, y)
|
|
+ yy.Neg(y)
|
|
+ checkIsOnCurveFalse("x, -y", x, yy)
|
|
+
|
|
+ // Check if negative values are reduced modulo P.
|
|
+ xx.Sub(x, p)
|
|
+ checkIsOnCurveFalse("x-P, y", xx, y)
|
|
+ yy.Sub(y, p)
|
|
+ checkIsOnCurveFalse("x, y-P", x, yy)
|
|
+
|
|
+ // Check if positive values are reduced modulo P.
|
|
+ xx.Add(x, p)
|
|
+ checkIsOnCurveFalse("x+P, y", xx, y)
|
|
+ yy.Add(y, p)
|
|
+ checkIsOnCurveFalse("x, y+P", x, yy)
|
|
+
|
|
+ // Check if the overflow is dropped.
|
|
+ xx.Add(x, new(big.Int).Lsh(big.NewInt(1), 535))
|
|
+ checkIsOnCurveFalse("x+2⁵³⁵, y", xx, y)
|
|
+ yy.Add(y, new(big.Int).Lsh(big.NewInt(1), 535))
|
|
+ checkIsOnCurveFalse("x, y+2⁵³⁵", x, yy)
|
|
+
|
|
+ // Check if P is treated like zero (if possible).
|
|
+ // y^2 = x^3 - 3x + B
|
|
+ // y = mod_sqrt(x^3 - 3x + B)
|
|
+ // y = mod_sqrt(B) if x = 0
|
|
+ // If there is no modsqrt, there is no point with x = 0, can't test x = P.
|
|
+ if yy := new(big.Int).ModSqrt(curve.Params().B, p); yy != nil {
|
|
+ if !curve.IsOnCurve(big.NewInt(0), yy) {
|
|
+ t.Fatal("(0, mod_sqrt(B)) is not on the curve?")
|
|
+ }
|
|
+ checkIsOnCurveFalse("P, y", p, yy)
|
|
+ }
|
|
+}
|
|
+
|
|
func TestMarshalCompressed(t *testing.T) {
|
|
t.Run("P-256/03", func(t *testing.T) {
|
|
data, _ := hex.DecodeString("031e3987d9f9ea9d7dd7155a56a86b2009e1e0ab332f962d10d8beb6406ab1ad79")
|
|
diff --git a/src/crypto/elliptic/p224.go b/src/crypto/elliptic/p224.go
|
|
index 8c760214642..ff5c8344522 100644
|
|
--- a/src/crypto/elliptic/p224.go
|
|
+++ b/src/crypto/elliptic/p224.go
|
|
@@ -48,6 +48,11 @@ func (curve p224Curve) Params() *CurveParams {
|
|
}
|
|
|
|
func (curve p224Curve) IsOnCurve(bigX, bigY *big.Int) bool {
|
|
+ if bigX.Sign() < 0 || bigX.Cmp(curve.P) >= 0 ||
|
|
+ bigY.Sign() < 0 || bigY.Cmp(curve.P) >= 0 {
|
|
+ return false
|
|
+ }
|
|
+
|
|
var x, y p224FieldElement
|
|
p224FromBig(&x, bigX)
|
|
p224FromBig(&y, bigY)
|
|
diff --git a/src/crypto/elliptic/p521.go b/src/crypto/elliptic/p521.go
|
|
index 3d355943ec7..587991e31bf 100644
|
|
--- a/src/crypto/elliptic/p521.go
|
|
+++ b/src/crypto/elliptic/p521.go
|
|
@@ -32,6 +32,11 @@ func (curve p521Curve) Params() *CurveParams {
|
|
}
|
|
|
|
func (curve p521Curve) IsOnCurve(x, y *big.Int) bool {
|
|
+ if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
|
|
+ y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
|
|
+ return false
|
|
+ }
|
|
+
|
|
x1 := bigIntToFiatP521(x)
|
|
y1 := bigIntToFiatP521(y)
|
|
b := bigIntToFiatP521(curve.B) // TODO: precompute this value.
|
|
--
|
|
2.30.0
|
|
|