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
5package ecdsa
6
7import (
8	"bufio"
9	"compress/bzip2"
10	"crypto/elliptic"
11	"crypto/rand"
12	"crypto/sha1"
13	"crypto/sha256"
14	"crypto/sha512"
15	"encoding/hex"
16	"hash"
17	"io"
18	"math/big"
19	"os"
20	"strings"
21	"testing"
22)
23
24func testKeyGeneration(t *testing.T, c elliptic.Curve, tag string) {
25	priv, err := GenerateKey(c, rand.Reader)
26	if err != nil {
27		t.Errorf("%s: error: %s", tag, err)
28		return
29	}
30	if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) {
31		t.Errorf("%s: public key invalid: %s", tag, err)
32	}
33}
34
35func TestKeyGeneration(t *testing.T) {
36	testKeyGeneration(t, elliptic.P224(), "p224")
37	if testing.Short() {
38		return
39	}
40	testKeyGeneration(t, elliptic.P256(), "p256")
41	testKeyGeneration(t, elliptic.P384(), "p384")
42	testKeyGeneration(t, elliptic.P521(), "p521")
43}
44
45func BenchmarkSignP256(b *testing.B) {
46	b.ResetTimer()
47	p256 := elliptic.P256()
48	hashed := []byte("testing")
49	priv, _ := GenerateKey(p256, rand.Reader)
50
51	b.ReportAllocs()
52	b.ResetTimer()
53	b.RunParallel(func(pb *testing.PB) {
54		for pb.Next() {
55			_, _, _ = Sign(rand.Reader, priv, hashed)
56		}
57	})
58}
59
60func BenchmarkSignP384(b *testing.B) {
61	b.ResetTimer()
62	p384 := elliptic.P384()
63	hashed := []byte("testing")
64	priv, _ := GenerateKey(p384, rand.Reader)
65
66	b.ReportAllocs()
67	b.ResetTimer()
68	b.RunParallel(func(pb *testing.PB) {
69		for pb.Next() {
70			_, _, _ = Sign(rand.Reader, priv, hashed)
71		}
72	})
73}
74
75func BenchmarkVerifyP256(b *testing.B) {
76	b.ResetTimer()
77	p256 := elliptic.P256()
78	hashed := []byte("testing")
79	priv, _ := GenerateKey(p256, rand.Reader)
80	r, s, _ := Sign(rand.Reader, priv, hashed)
81
82	b.ReportAllocs()
83	b.ResetTimer()
84	b.RunParallel(func(pb *testing.PB) {
85		for pb.Next() {
86			Verify(&priv.PublicKey, hashed, r, s)
87		}
88	})
89}
90
91func BenchmarkKeyGeneration(b *testing.B) {
92	b.ResetTimer()
93	p256 := elliptic.P256()
94
95	b.ReportAllocs()
96	b.ResetTimer()
97	b.RunParallel(func(pb *testing.PB) {
98		for pb.Next() {
99			GenerateKey(p256, rand.Reader)
100		}
101	})
102}
103
104func testSignAndVerify(t *testing.T, c elliptic.Curve, tag string) {
105	priv, _ := GenerateKey(c, rand.Reader)
106
107	hashed := []byte("testing")
108	r, s, err := Sign(rand.Reader, priv, hashed)
109	if err != nil {
110		t.Errorf("%s: error signing: %s", tag, err)
111		return
112	}
113
114	if !Verify(&priv.PublicKey, hashed, r, s) {
115		t.Errorf("%s: Verify failed", tag)
116	}
117
118	hashed[0] ^= 0xff
119	if Verify(&priv.PublicKey, hashed, r, s) {
120		t.Errorf("%s: Verify always works!", tag)
121	}
122}
123
124func TestSignAndVerify(t *testing.T) {
125	testSignAndVerify(t, elliptic.P224(), "p224")
126	if testing.Short() {
127		return
128	}
129	testSignAndVerify(t, elliptic.P256(), "p256")
130	testSignAndVerify(t, elliptic.P384(), "p384")
131	testSignAndVerify(t, elliptic.P521(), "p521")
132}
133
134func testSignAndVerifyASN1(t *testing.T, c elliptic.Curve, tag string) {
135	priv, _ := GenerateKey(c, rand.Reader)
136
137	hashed := []byte("testing")
138	sig, err := SignASN1(rand.Reader, priv, hashed)
139	if err != nil {
140		t.Errorf("%s: error signing: %s", tag, err)
141		return
142	}
143
144	if !VerifyASN1(&priv.PublicKey, hashed, sig) {
145		t.Errorf("%s: VerifyASN1 failed", tag)
146	}
147
148	hashed[0] ^= 0xff
149	if VerifyASN1(&priv.PublicKey, hashed, sig) {
150		t.Errorf("%s: VerifyASN1 always works!", tag)
151	}
152}
153
154func TestSignAndVerifyASN1(t *testing.T) {
155	testSignAndVerifyASN1(t, elliptic.P224(), "p224")
156	if testing.Short() {
157		return
158	}
159	testSignAndVerifyASN1(t, elliptic.P256(), "p256")
160	testSignAndVerifyASN1(t, elliptic.P384(), "p384")
161	testSignAndVerifyASN1(t, elliptic.P521(), "p521")
162}
163
164func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) {
165	priv, _ := GenerateKey(c, rand.Reader)
166
167	hashed := []byte("testing")
168	r0, s0, err := Sign(zeroReader, priv, hashed)
169	if err != nil {
170		t.Errorf("%s: error signing: %s", tag, err)
171		return
172	}
173
174	hashed = []byte("testing...")
175	r1, s1, err := Sign(zeroReader, priv, hashed)
176	if err != nil {
177		t.Errorf("%s: error signing: %s", tag, err)
178		return
179	}
180
181	if s0.Cmp(s1) == 0 {
182		// This should never happen.
183		t.Errorf("%s: the signatures on two different messages were the same", tag)
184	}
185
186	if r0.Cmp(r1) == 0 {
187		t.Errorf("%s: the nonce used for two different messages was the same", tag)
188	}
189}
190
191func TestNonceSafety(t *testing.T) {
192	testNonceSafety(t, elliptic.P224(), "p224")
193	if testing.Short() {
194		return
195	}
196	testNonceSafety(t, elliptic.P256(), "p256")
197	testNonceSafety(t, elliptic.P384(), "p384")
198	testNonceSafety(t, elliptic.P521(), "p521")
199}
200
201func testINDCCA(t *testing.T, c elliptic.Curve, tag string) {
202	priv, _ := GenerateKey(c, rand.Reader)
203
204	hashed := []byte("testing")
205	r0, s0, err := Sign(rand.Reader, priv, hashed)
206	if err != nil {
207		t.Errorf("%s: error signing: %s", tag, err)
208		return
209	}
210
211	r1, s1, err := Sign(rand.Reader, priv, hashed)
212	if err != nil {
213		t.Errorf("%s: error signing: %s", tag, err)
214		return
215	}
216
217	if s0.Cmp(s1) == 0 {
218		t.Errorf("%s: two signatures of the same message produced the same result", tag)
219	}
220
221	if r0.Cmp(r1) == 0 {
222		t.Errorf("%s: two signatures of the same message produced the same nonce", tag)
223	}
224}
225
226func TestINDCCA(t *testing.T) {
227	testINDCCA(t, elliptic.P224(), "p224")
228	if testing.Short() {
229		return
230	}
231	testINDCCA(t, elliptic.P256(), "p256")
232	testINDCCA(t, elliptic.P384(), "p384")
233	testINDCCA(t, elliptic.P521(), "p521")
234}
235
236func fromHex(s string) *big.Int {
237	r, ok := new(big.Int).SetString(s, 16)
238	if !ok {
239		panic("bad hex")
240	}
241	return r
242}
243
244func TestVectors(t *testing.T) {
245	// This test runs the full set of NIST test vectors from
246	// https://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip
247	//
248	// The SigVer.rsp file has been edited to remove test vectors for
249	// unsupported algorithms and has been compressed.
250
251	if testing.Short() {
252		return
253	}
254
255	f, err := os.Open("testdata/SigVer.rsp.bz2")
256	if err != nil {
257		t.Fatal(err)
258	}
259
260	buf := bufio.NewReader(bzip2.NewReader(f))
261
262	lineNo := 1
263	var h hash.Hash
264	var msg []byte
265	var hashed []byte
266	var r, s *big.Int
267	pub := new(PublicKey)
268
269	for {
270		line, err := buf.ReadString('\n')
271		if len(line) == 0 {
272			if err == io.EOF {
273				break
274			}
275			t.Fatalf("error reading from input: %s", err)
276		}
277		lineNo++
278		// Need to remove \r\n from the end of the line.
279		if !strings.HasSuffix(line, "\r\n") {
280			t.Fatalf("bad line ending (expected \\r\\n) on line %d", lineNo)
281		}
282		line = line[:len(line)-2]
283
284		if len(line) == 0 || line[0] == '#' {
285			continue
286		}
287
288		if line[0] == '[' {
289			line = line[1 : len(line)-1]
290			parts := strings.SplitN(line, ",", 2)
291
292			switch parts[0] {
293			case "P-224":
294				pub.Curve = elliptic.P224()
295			case "P-256":
296				pub.Curve = elliptic.P256()
297			case "P-384":
298				pub.Curve = elliptic.P384()
299			case "P-521":
300				pub.Curve = elliptic.P521()
301			default:
302				pub.Curve = nil
303			}
304
305			switch parts[1] {
306			case "SHA-1":
307				h = sha1.New()
308			case "SHA-224":
309				h = sha256.New224()
310			case "SHA-256":
311				h = sha256.New()
312			case "SHA-384":
313				h = sha512.New384()
314			case "SHA-512":
315				h = sha512.New()
316			default:
317				h = nil
318			}
319
320			continue
321		}
322
323		if h == nil || pub.Curve == nil {
324			continue
325		}
326
327		switch {
328		case strings.HasPrefix(line, "Msg = "):
329			if msg, err = hex.DecodeString(line[6:]); err != nil {
330				t.Fatalf("failed to decode message on line %d: %s", lineNo, err)
331			}
332		case strings.HasPrefix(line, "Qx = "):
333			pub.X = fromHex(line[5:])
334		case strings.HasPrefix(line, "Qy = "):
335			pub.Y = fromHex(line[5:])
336		case strings.HasPrefix(line, "R = "):
337			r = fromHex(line[4:])
338		case strings.HasPrefix(line, "S = "):
339			s = fromHex(line[4:])
340		case strings.HasPrefix(line, "Result = "):
341			expected := line[9] == 'P'
342			h.Reset()
343			h.Write(msg)
344			hashed := h.Sum(hashed[:0])
345			if Verify(pub, hashed, r, s) != expected {
346				t.Fatalf("incorrect result on line %d", lineNo)
347			}
348		default:
349			t.Fatalf("unknown variable on line %d: %s", lineNo, line)
350		}
351	}
352}
353
354func testNegativeInputs(t *testing.T, curve elliptic.Curve, tag string) {
355	key, err := GenerateKey(curve, rand.Reader)
356	if err != nil {
357		t.Errorf("failed to generate key for %q", tag)
358	}
359
360	var hash [32]byte
361	r := new(big.Int).SetInt64(1)
362	r.Lsh(r, 550 /* larger than any supported curve */)
363	r.Neg(r)
364
365	if Verify(&key.PublicKey, hash[:], r, r) {
366		t.Errorf("bogus signature accepted for %q", tag)
367	}
368}
369
370func TestNegativeInputs(t *testing.T) {
371	testNegativeInputs(t, elliptic.P224(), "p224")
372	testNegativeInputs(t, elliptic.P256(), "p256")
373	testNegativeInputs(t, elliptic.P384(), "p384")
374	testNegativeInputs(t, elliptic.P521(), "p521")
375}
376
377func TestZeroHashSignature(t *testing.T) {
378	zeroHash := make([]byte, 64)
379
380	for _, curve := range []elliptic.Curve{elliptic.P224(), elliptic.P256(), elliptic.P384(), elliptic.P521()} {
381		privKey, err := GenerateKey(curve, rand.Reader)
382		if err != nil {
383			panic(err)
384		}
385
386		// Sign a hash consisting of all zeros.
387		r, s, err := Sign(rand.Reader, privKey, zeroHash)
388		if err != nil {
389			panic(err)
390		}
391
392		// Confirm that it can be verified.
393		if !Verify(&privKey.PublicKey, zeroHash, r, s) {
394			t.Errorf("zero hash signature verify failed for %T", curve)
395		}
396	}
397}
398