From: David Leon Gil Date: Wed, 7 Jan 2015 05:07:24 +0000 (-0800) Subject: crypto/elliptic: don't unmarshal points that are off the curve X-Git-Tag: go1.5beta1~906 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=d86b8d34d069c3895721ba47cac664f8bbf2b8ad;p=gostls13.git crypto/elliptic: don't unmarshal points that are off the curve At present, Unmarshal does not check that the point it unmarshals is actually *on* the curve. (It may be on the curve's twist.) This can, as Daniel Bernstein has pointed out at great length, lead to quite devastating attacks. And 3 out of the 4 curves supported by crypto/elliptic have twists with cofactor != 1; P-224, in particular, has a sufficiently large cofactor that it is likely that conventional dlog attacks might be useful. This closes #2445, filed by Watson Ladd. To explain why this was (partially) rejected before being accepted: In the general case, for curves with cofactor != 1, verifying subgroup membership is required. (This is expensive and hard-to-implement.) But, as recent discussion during the CFRG standardization process has brought out, small-subgroup attacks are much less damaging than a twist attack. Change-Id: I284042eb9954ff9b7cde80b8b693b1d468c7e1e8 Reviewed-on: https://go-review.googlesource.com/2421 Reviewed-by: Adam Langley --- diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go index 396bb5caf5..f3b84e1eac 100644 --- a/src/crypto/elliptic/elliptic.go +++ b/src/crypto/elliptic/elliptic.go @@ -308,7 +308,8 @@ func Marshal(curve Curve, x, y *big.Int) []byte { return ret } -// Unmarshal converts a point, serialized by Marshal, into an x, y pair. On error, x = nil. +// Unmarshal converts a point, serialized by Marshal, into an x, y pair. +// It is an error if the point is not on the curve. On error, x = nil. func Unmarshal(curve Curve, data []byte) (x, y *big.Int) { byteLen := (curve.Params().BitSize + 7) >> 3 if len(data) != 1+2*byteLen { @@ -319,6 +320,9 @@ func Unmarshal(curve Curve, data []byte) (x, y *big.Int) { } x = new(big.Int).SetBytes(data[1 : 1+byteLen]) y = new(big.Int).SetBytes(data[1+byteLen:]) + if !curve.Params().IsOnCurve(x, y) { + x, y = nil, nil + } return } diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go index 4dc27c92bf..7e27913dcd 100644 --- a/src/crypto/elliptic/elliptic_test.go +++ b/src/crypto/elliptic/elliptic_test.go @@ -19,6 +19,19 @@ func TestOnCurve(t *testing.T) { } } +func TestOffCurve(t *testing.T) { + p224 := P224() + x, y := new(big.Int).SetInt64(1), new(big.Int).SetInt64(1) + if p224.IsOnCurve(x, y) { + t.Errorf("FAIL: point off curve is claimed to be on the curve") + } + b := Marshal(p224, x, y) + x1, y1 := Unmarshal(p224, b) + if x1 != nil || y1 != nil { + t.Errorf("FAIL: unmarshalling a point not on the curve succeeded") + } +} + type baseMultTest struct { k string x, y string