Source file src/crypto/ecdsa/ecdsa_test.go

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ecdsa
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"compress/bzip2"
    11  	"crypto/elliptic"
    12  	"crypto/rand"
    13  	"crypto/sha1"
    14  	"crypto/sha256"
    15  	"crypto/sha512"
    16  	"encoding/hex"
    17  	"hash"
    18  	"io"
    19  	"math/big"
    20  	"os"
    21  	"strings"
    22  	"testing"
    23  )
    24  
    25  func testAllCurves(t *testing.T, f func(*testing.T, elliptic.Curve)) {
    26  	tests := []struct {
    27  		name  string
    28  		curve elliptic.Curve
    29  	}{
    30  		{"P256", elliptic.P256()},
    31  		{"P224", elliptic.P224()},
    32  		{"P384", elliptic.P384()},
    33  		{"P521", elliptic.P521()},
    34  		{"P256/Generic", genericParamsForCurve(elliptic.P256())},
    35  	}
    36  	if testing.Short() {
    37  		tests = tests[:1]
    38  	}
    39  	for _, test := range tests {
    40  		curve := test.curve
    41  		t.Run(test.name, func(t *testing.T) {
    42  			t.Parallel()
    43  			f(t, curve)
    44  		})
    45  	}
    46  }
    47  
    48  // genericParamsForCurve returns the dereferenced CurveParams for
    49  // the specified curve. This is used to avoid the logic for
    50  // upgrading a curve to its specific implementation, forcing
    51  // usage of the generic implementation.
    52  func genericParamsForCurve(c elliptic.Curve) *elliptic.CurveParams {
    53  	d := *(c.Params())
    54  	return &d
    55  }
    56  
    57  func TestKeyGeneration(t *testing.T) {
    58  	testAllCurves(t, testKeyGeneration)
    59  }
    60  
    61  func testKeyGeneration(t *testing.T, c elliptic.Curve) {
    62  	priv, err := GenerateKey(c, rand.Reader)
    63  	if err != nil {
    64  		t.Fatal(err)
    65  	}
    66  	if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) {
    67  		t.Errorf("public key invalid: %s", err)
    68  	}
    69  }
    70  
    71  func TestSignAndVerify(t *testing.T) {
    72  	testAllCurves(t, testSignAndVerify)
    73  }
    74  
    75  func testSignAndVerify(t *testing.T, c elliptic.Curve) {
    76  	priv, _ := GenerateKey(c, rand.Reader)
    77  
    78  	hashed := []byte("testing")
    79  	r, s, err := Sign(rand.Reader, priv, hashed)
    80  	if err != nil {
    81  		t.Errorf("error signing: %s", err)
    82  		return
    83  	}
    84  
    85  	if !Verify(&priv.PublicKey, hashed, r, s) {
    86  		t.Errorf("Verify failed")
    87  	}
    88  
    89  	hashed[0] ^= 0xff
    90  	if Verify(&priv.PublicKey, hashed, r, s) {
    91  		t.Errorf("Verify always works!")
    92  	}
    93  }
    94  
    95  func TestSignAndVerifyASN1(t *testing.T) {
    96  	testAllCurves(t, testSignAndVerifyASN1)
    97  }
    98  
    99  func testSignAndVerifyASN1(t *testing.T, c elliptic.Curve) {
   100  	priv, _ := GenerateKey(c, rand.Reader)
   101  
   102  	hashed := []byte("testing")
   103  	sig, err := SignASN1(rand.Reader, priv, hashed)
   104  	if err != nil {
   105  		t.Errorf("error signing: %s", err)
   106  		return
   107  	}
   108  
   109  	if !VerifyASN1(&priv.PublicKey, hashed, sig) {
   110  		t.Errorf("VerifyASN1 failed")
   111  	}
   112  
   113  	hashed[0] ^= 0xff
   114  	if VerifyASN1(&priv.PublicKey, hashed, sig) {
   115  		t.Errorf("VerifyASN1 always works!")
   116  	}
   117  }
   118  
   119  func TestNonceSafety(t *testing.T) {
   120  	testAllCurves(t, testNonceSafety)
   121  }
   122  
   123  func testNonceSafety(t *testing.T, c elliptic.Curve) {
   124  	priv, _ := GenerateKey(c, rand.Reader)
   125  
   126  	hashed := []byte("testing")
   127  	r0, s0, err := Sign(zeroReader, priv, hashed)
   128  	if err != nil {
   129  		t.Errorf("error signing: %s", err)
   130  		return
   131  	}
   132  
   133  	hashed = []byte("testing...")
   134  	r1, s1, err := Sign(zeroReader, priv, hashed)
   135  	if err != nil {
   136  		t.Errorf("error signing: %s", err)
   137  		return
   138  	}
   139  
   140  	if s0.Cmp(s1) == 0 {
   141  		// This should never happen.
   142  		t.Errorf("the signatures on two different messages were the same")
   143  	}
   144  
   145  	if r0.Cmp(r1) == 0 {
   146  		t.Errorf("the nonce used for two different messages was the same")
   147  	}
   148  }
   149  
   150  func TestINDCCA(t *testing.T) {
   151  	testAllCurves(t, testINDCCA)
   152  }
   153  
   154  func testINDCCA(t *testing.T, c elliptic.Curve) {
   155  	priv, _ := GenerateKey(c, rand.Reader)
   156  
   157  	hashed := []byte("testing")
   158  	r0, s0, err := Sign(rand.Reader, priv, hashed)
   159  	if err != nil {
   160  		t.Errorf("error signing: %s", err)
   161  		return
   162  	}
   163  
   164  	r1, s1, err := Sign(rand.Reader, priv, hashed)
   165  	if err != nil {
   166  		t.Errorf("error signing: %s", err)
   167  		return
   168  	}
   169  
   170  	if s0.Cmp(s1) == 0 {
   171  		t.Errorf("two signatures of the same message produced the same result")
   172  	}
   173  
   174  	if r0.Cmp(r1) == 0 {
   175  		t.Errorf("two signatures of the same message produced the same nonce")
   176  	}
   177  }
   178  
   179  func fromHex(s string) *big.Int {
   180  	r, ok := new(big.Int).SetString(s, 16)
   181  	if !ok {
   182  		panic("bad hex")
   183  	}
   184  	return r
   185  }
   186  
   187  func TestVectors(t *testing.T) {
   188  	// This test runs the full set of NIST test vectors from
   189  	// https://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip
   190  	//
   191  	// The SigVer.rsp file has been edited to remove test vectors for
   192  	// unsupported algorithms and has been compressed.
   193  
   194  	if testing.Short() {
   195  		return
   196  	}
   197  
   198  	f, err := os.Open("testdata/SigVer.rsp.bz2")
   199  	if err != nil {
   200  		t.Fatal(err)
   201  	}
   202  
   203  	buf := bufio.NewReader(bzip2.NewReader(f))
   204  
   205  	lineNo := 1
   206  	var h hash.Hash
   207  	var msg []byte
   208  	var hashed []byte
   209  	var r, s *big.Int
   210  	pub := new(PublicKey)
   211  
   212  	for {
   213  		line, err := buf.ReadString('\n')
   214  		if len(line) == 0 {
   215  			if err == io.EOF {
   216  				break
   217  			}
   218  			t.Fatalf("error reading from input: %s", err)
   219  		}
   220  		lineNo++
   221  		// Need to remove \r\n from the end of the line.
   222  		if !strings.HasSuffix(line, "\r\n") {
   223  			t.Fatalf("bad line ending (expected \\r\\n) on line %d", lineNo)
   224  		}
   225  		line = line[:len(line)-2]
   226  
   227  		if len(line) == 0 || line[0] == '#' {
   228  			continue
   229  		}
   230  
   231  		if line[0] == '[' {
   232  			line = line[1 : len(line)-1]
   233  			curve, hash, _ := strings.Cut(line, ",")
   234  
   235  			switch curve {
   236  			case "P-224":
   237  				pub.Curve = elliptic.P224()
   238  			case "P-256":
   239  				pub.Curve = elliptic.P256()
   240  			case "P-384":
   241  				pub.Curve = elliptic.P384()
   242  			case "P-521":
   243  				pub.Curve = elliptic.P521()
   244  			default:
   245  				pub.Curve = nil
   246  			}
   247  
   248  			switch hash {
   249  			case "SHA-1":
   250  				h = sha1.New()
   251  			case "SHA-224":
   252  				h = sha256.New224()
   253  			case "SHA-256":
   254  				h = sha256.New()
   255  			case "SHA-384":
   256  				h = sha512.New384()
   257  			case "SHA-512":
   258  				h = sha512.New()
   259  			default:
   260  				h = nil
   261  			}
   262  
   263  			continue
   264  		}
   265  
   266  		if h == nil || pub.Curve == nil {
   267  			continue
   268  		}
   269  
   270  		switch {
   271  		case strings.HasPrefix(line, "Msg = "):
   272  			if msg, err = hex.DecodeString(line[6:]); err != nil {
   273  				t.Fatalf("failed to decode message on line %d: %s", lineNo, err)
   274  			}
   275  		case strings.HasPrefix(line, "Qx = "):
   276  			pub.X = fromHex(line[5:])
   277  		case strings.HasPrefix(line, "Qy = "):
   278  			pub.Y = fromHex(line[5:])
   279  		case strings.HasPrefix(line, "R = "):
   280  			r = fromHex(line[4:])
   281  		case strings.HasPrefix(line, "S = "):
   282  			s = fromHex(line[4:])
   283  		case strings.HasPrefix(line, "Result = "):
   284  			expected := line[9] == 'P'
   285  			h.Reset()
   286  			h.Write(msg)
   287  			hashed := h.Sum(hashed[:0])
   288  			if Verify(pub, hashed, r, s) != expected {
   289  				t.Fatalf("incorrect result on line %d", lineNo)
   290  			}
   291  		default:
   292  			t.Fatalf("unknown variable on line %d: %s", lineNo, line)
   293  		}
   294  	}
   295  }
   296  
   297  func TestNegativeInputs(t *testing.T) {
   298  	testAllCurves(t, testNegativeInputs)
   299  }
   300  
   301  func testNegativeInputs(t *testing.T, curve elliptic.Curve) {
   302  	key, err := GenerateKey(curve, rand.Reader)
   303  	if err != nil {
   304  		t.Errorf("failed to generate key")
   305  	}
   306  
   307  	var hash [32]byte
   308  	r := new(big.Int).SetInt64(1)
   309  	r.Lsh(r, 550 /* larger than any supported curve */)
   310  	r.Neg(r)
   311  
   312  	if Verify(&key.PublicKey, hash[:], r, r) {
   313  		t.Errorf("bogus signature accepted")
   314  	}
   315  }
   316  
   317  func TestZeroHashSignature(t *testing.T) {
   318  	testAllCurves(t, testZeroHashSignature)
   319  }
   320  
   321  func testZeroHashSignature(t *testing.T, curve elliptic.Curve) {
   322  	zeroHash := make([]byte, 64)
   323  
   324  	privKey, err := GenerateKey(curve, rand.Reader)
   325  	if err != nil {
   326  		panic(err)
   327  	}
   328  
   329  	// Sign a hash consisting of all zeros.
   330  	r, s, err := Sign(rand.Reader, privKey, zeroHash)
   331  	if err != nil {
   332  		panic(err)
   333  	}
   334  
   335  	// Confirm that it can be verified.
   336  	if !Verify(&privKey.PublicKey, zeroHash, r, s) {
   337  		t.Errorf("zero hash signature verify failed for %T", curve)
   338  	}
   339  }
   340  
   341  func TestRandomPoint(t *testing.T) {
   342  	t.Run("P-224", func(t *testing.T) { testRandomPoint(t, p224()) })
   343  	t.Run("P-256", func(t *testing.T) { testRandomPoint(t, p256()) })
   344  	t.Run("P-384", func(t *testing.T) { testRandomPoint(t, p384()) })
   345  	t.Run("P-521", func(t *testing.T) { testRandomPoint(t, p521()) })
   346  }
   347  
   348  func testRandomPoint[Point nistPoint[Point]](t *testing.T, c *nistCurve[Point]) {
   349  	t.Cleanup(func() { testingOnlyRejectionSamplingLooped = nil })
   350  	var loopCount int
   351  	testingOnlyRejectionSamplingLooped = func() { loopCount++ }
   352  
   353  	// A sequence of all ones will generate 2^N-1, which should be rejected.
   354  	// (Unless, for example, we are masking too many bits.)
   355  	r := io.MultiReader(bytes.NewReader(bytes.Repeat([]byte{0xff}, 100)), rand.Reader)
   356  	if k, p, err := randomPoint(c, r); err != nil {
   357  		t.Fatal(err)
   358  	} else if k.IsZero() == 1 {
   359  		t.Error("k is zero")
   360  	} else if p.Bytes()[0] != 4 {
   361  		t.Error("p is infinity")
   362  	}
   363  	if loopCount == 0 {
   364  		t.Error("overflow was not rejected")
   365  	}
   366  	loopCount = 0
   367  
   368  	// A sequence of all zeroes will generate zero, which should be rejected.
   369  	r = io.MultiReader(bytes.NewReader(bytes.Repeat([]byte{0}, 100)), rand.Reader)
   370  	if k, p, err := randomPoint(c, r); err != nil {
   371  		t.Fatal(err)
   372  	} else if k.IsZero() == 1 {
   373  		t.Error("k is zero")
   374  	} else if p.Bytes()[0] != 4 {
   375  		t.Error("p is infinity")
   376  	}
   377  	if loopCount == 0 {
   378  		t.Error("zero was not rejected")
   379  	}
   380  	loopCount = 0
   381  
   382  	// P-256 has a 2⁻³² chance or randomly hitting a rejection. For P-224 it's
   383  	// 2⁻¹¹², for P-384 it's 2⁻¹⁹⁴, and for P-521 it's 2⁻²⁶², so if we hit in
   384  	// tests, something is horribly wrong. (For example, we are masking the
   385  	// wrong bits.)
   386  	if c.curve == elliptic.P256() {
   387  		return
   388  	}
   389  	if k, p, err := randomPoint(c, rand.Reader); err != nil {
   390  		t.Fatal(err)
   391  	} else if k.IsZero() == 1 {
   392  		t.Error("k is zero")
   393  	} else if p.Bytes()[0] != 4 {
   394  		t.Error("p is infinity")
   395  	}
   396  	if loopCount > 0 {
   397  		t.Error("unexpected rejection")
   398  	}
   399  }
   400  
   401  func TestZeroSignature(t *testing.T) {
   402  	testAllCurves(t, testZeroSignature)
   403  }
   404  
   405  func testZeroSignature(t *testing.T, curve elliptic.Curve) {
   406  	privKey, err := GenerateKey(curve, rand.Reader)
   407  	if err != nil {
   408  		panic(err)
   409  	}
   410  
   411  	if Verify(&privKey.PublicKey, make([]byte, 64), big.NewInt(0), big.NewInt(0)) {
   412  		t.Errorf("Verify with r,s=0 succeeded: %T", curve)
   413  	}
   414  }
   415  
   416  func TestNegtativeSignature(t *testing.T) {
   417  	testAllCurves(t, testNegativeSignature)
   418  }
   419  
   420  func testNegativeSignature(t *testing.T, curve elliptic.Curve) {
   421  	zeroHash := make([]byte, 64)
   422  
   423  	privKey, err := GenerateKey(curve, rand.Reader)
   424  	if err != nil {
   425  		panic(err)
   426  	}
   427  	r, s, err := Sign(rand.Reader, privKey, zeroHash)
   428  	if err != nil {
   429  		panic(err)
   430  	}
   431  
   432  	r = r.Neg(r)
   433  	if Verify(&privKey.PublicKey, zeroHash, r, s) {
   434  		t.Errorf("Verify with r=-r succeeded: %T", curve)
   435  	}
   436  }
   437  
   438  func TestRPlusNSignature(t *testing.T) {
   439  	testAllCurves(t, testRPlusNSignature)
   440  }
   441  
   442  func testRPlusNSignature(t *testing.T, curve elliptic.Curve) {
   443  	zeroHash := make([]byte, 64)
   444  
   445  	privKey, err := GenerateKey(curve, rand.Reader)
   446  	if err != nil {
   447  		panic(err)
   448  	}
   449  	r, s, err := Sign(rand.Reader, privKey, zeroHash)
   450  	if err != nil {
   451  		panic(err)
   452  	}
   453  
   454  	r = r.Add(r, curve.Params().N)
   455  	if Verify(&privKey.PublicKey, zeroHash, r, s) {
   456  		t.Errorf("Verify with r=r+n succeeded: %T", curve)
   457  	}
   458  }
   459  
   460  func TestRMinusNSignature(t *testing.T) {
   461  	testAllCurves(t, testRMinusNSignature)
   462  }
   463  
   464  func testRMinusNSignature(t *testing.T, curve elliptic.Curve) {
   465  	zeroHash := make([]byte, 64)
   466  
   467  	privKey, err := GenerateKey(curve, rand.Reader)
   468  	if err != nil {
   469  		panic(err)
   470  	}
   471  	r, s, err := Sign(rand.Reader, privKey, zeroHash)
   472  	if err != nil {
   473  		panic(err)
   474  	}
   475  
   476  	r = r.Sub(r, curve.Params().N)
   477  	if Verify(&privKey.PublicKey, zeroHash, r, s) {
   478  		t.Errorf("Verify with r=r-n succeeded: %T", curve)
   479  	}
   480  }
   481  
   482  func randomPointForCurve(curve elliptic.Curve, rand io.Reader) error {
   483  	switch curve.Params() {
   484  	case elliptic.P224().Params():
   485  		_, _, err := randomPoint(p224(), rand)
   486  		return err
   487  	case elliptic.P256().Params():
   488  		_, _, err := randomPoint(p256(), rand)
   489  		return err
   490  	case elliptic.P384().Params():
   491  		_, _, err := randomPoint(p384(), rand)
   492  		return err
   493  	case elliptic.P521().Params():
   494  		_, _, err := randomPoint(p521(), rand)
   495  		return err
   496  	default:
   497  		panic("unknown curve")
   498  	}
   499  }
   500  
   501  func benchmarkAllCurves(b *testing.B, f func(*testing.B, elliptic.Curve)) {
   502  	tests := []struct {
   503  		name  string
   504  		curve elliptic.Curve
   505  	}{
   506  		{"P256", elliptic.P256()},
   507  		{"P384", elliptic.P384()},
   508  		{"P521", elliptic.P521()},
   509  	}
   510  	for _, test := range tests {
   511  		curve := test.curve
   512  		b.Run(test.name, func(b *testing.B) {
   513  			f(b, curve)
   514  		})
   515  	}
   516  }
   517  
   518  func BenchmarkSign(b *testing.B) {
   519  	benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
   520  		r := bufio.NewReaderSize(rand.Reader, 1<<15)
   521  		priv, err := GenerateKey(curve, r)
   522  		if err != nil {
   523  			b.Fatal(err)
   524  		}
   525  		hashed := []byte("testing")
   526  
   527  		b.ReportAllocs()
   528  		b.ResetTimer()
   529  		for i := 0; i < b.N; i++ {
   530  			sig, err := SignASN1(r, priv, hashed)
   531  			if err != nil {
   532  				b.Fatal(err)
   533  			}
   534  			// Prevent the compiler from optimizing out the operation.
   535  			hashed[0] = sig[0]
   536  		}
   537  	})
   538  }
   539  
   540  func BenchmarkVerify(b *testing.B) {
   541  	benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
   542  		r := bufio.NewReaderSize(rand.Reader, 1<<15)
   543  		priv, err := GenerateKey(curve, r)
   544  		if err != nil {
   545  			b.Fatal(err)
   546  		}
   547  		hashed := []byte("testing")
   548  		sig, err := SignASN1(r, priv, hashed)
   549  		if err != nil {
   550  			b.Fatal(err)
   551  		}
   552  
   553  		b.ReportAllocs()
   554  		b.ResetTimer()
   555  		for i := 0; i < b.N; i++ {
   556  			if !VerifyASN1(&priv.PublicKey, hashed, sig) {
   557  				b.Fatal("verify failed")
   558  			}
   559  		}
   560  	})
   561  }
   562  
   563  func BenchmarkGenerateKey(b *testing.B) {
   564  	benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
   565  		r := bufio.NewReaderSize(rand.Reader, 1<<15)
   566  		b.ReportAllocs()
   567  		b.ResetTimer()
   568  		for i := 0; i < b.N; i++ {
   569  			if _, err := GenerateKey(curve, r); err != nil {
   570  				b.Fatal(err)
   571  			}
   572  		}
   573  	})
   574  }
   575  

View as plain text