Source file
src/crypto/ecdh/ecdh_wycheproof_test.go
1
2
3
4 package ecdh_test
5
6 import (
7 "bytes"
8 "crypto/ecdh"
9 "crypto/ecdsa"
10 "crypto/internal/cryptotest/wycheproof"
11 "crypto/x509"
12 "fmt"
13 "testing"
14 )
15
16 func TestSecpECDHWycheproof(t *testing.T) {
17 flagsShouldPass := map[string]bool{
18
19 "CompressedPoint": false,
20 "CompressedPublic": false,
21 }
22
23 curveToCurve := map[string]ecdh.Curve{
24 "secp256r1": ecdh.P256(),
25 "secp384r1": ecdh.P384(),
26 "secp521r1": ecdh.P521(),
27 }
28
29 curveToKeySize := map[string]int{
30 "secp256r1": 32,
31 "secp384r1": 48,
32 "secp521r1": 66,
33 }
34
35 for _, file := range []string{
36 "ecdh_secp256r1_ecpoint_test.json",
37 "ecdh_secp384r1_ecpoint_test.json",
38 "ecdh_secp521r1_ecpoint_test.json",
39 } {
40 var testdata wycheproof.EcdhEcpointTestSchemaV1Json
41 wycheproof.LoadVectorFile(t, file, &testdata)
42
43 for _, tg := range testdata.TestGroups {
44 if _, ok := curveToCurve[tg.Curve]; !ok {
45 continue
46 }
47 curve := curveToCurve[tg.Curve]
48 keySize := curveToKeySize[tg.Curve]
49
50 for _, tv := range tg.Tests {
51 testName := wycheproof.TestName(file, tv)
52 tv := ecdhWycheproofTV{
53 tcID: tv.TcId,
54 comment: tv.Comment,
55 flags: tv.Flags,
56 result: tv.Result,
57 public: tv.Public,
58 private: tv.Private,
59 shared: tv.Shared,
60 }
61 t.Run(testName, func(t *testing.T) {
62 t.Parallel()
63 runECDHWycheproofTest(t, curve, keySize, flagsShouldPass, tv, curve.NewPublicKey)
64 })
65 }
66 }
67 }
68 }
69
70 func TestSecpECDHSPKIWycheproof(t *testing.T) {
71 flagsShouldPass := map[string]bool{
72 "CompressedPublic": false,
73 "CompressedPoint": false,
74 "UnnamedCurve": false,
75 "WrongOrder": false,
76 "UnusedParam": false,
77 "ModifiedGenerator": false,
78 "ModifiedCofactor": false,
79 "ModifiedCurveParameter": false,
80 "NoCofactor": false,
81 "Modified curve parameter": false,
82 "InvalidAsn": false,
83 }
84
85 parseSPKIPub := func(p []byte) (*ecdh.PublicKey, error) {
86 pubKeyAny, err := x509.ParsePKIXPublicKey(p)
87 if err != nil {
88 return nil, err
89 }
90 ecdsaPub, ok := pubKeyAny.(*ecdsa.PublicKey)
91 if !ok {
92 return nil, fmt.Errorf("unexpected key type %T", pubKeyAny)
93 }
94 return ecdsaPub.ECDH()
95 }
96
97 curveToCurve := map[string]ecdh.Curve{
98 "secp256r1": ecdh.P256(),
99 "secp384r1": ecdh.P384(),
100 "secp521r1": ecdh.P521(),
101 }
102
103 curveToKeySize := map[string]int{
104 "secp256r1": 32,
105 "secp384r1": 48,
106 "secp521r1": 66,
107 }
108
109 for _, file := range []string{
110 "ecdh_secp256r1_test.json",
111 "ecdh_secp384r1_test.json",
112 "ecdh_secp521r1_test.json",
113 } {
114 var testdata wycheproof.EcdhTestSchemaV1Json
115 wycheproof.LoadVectorFile(t, file, &testdata)
116
117 for _, tg := range testdata.TestGroups {
118 if _, ok := curveToCurve[tg.Curve]; !ok {
119 continue
120 }
121 curve := curveToCurve[tg.Curve]
122 keySize := curveToKeySize[tg.Curve]
123
124 for _, tv := range tg.Tests {
125 testName := wycheproof.TestName(file, tv)
126 tv := ecdhWycheproofTV{
127 tcID: tv.TcId,
128 comment: tv.Comment,
129 flags: tv.Flags,
130 result: tv.Result,
131 public: tv.Public,
132 private: tv.Private,
133 shared: tv.Shared,
134 }
135 t.Run(testName, func(t *testing.T) {
136 t.Parallel()
137 runECDHWycheproofTest(t, curve, keySize, flagsShouldPass, tv, parseSPKIPub)
138 })
139 }
140 }
141 }
142 }
143
144 func TestX25519ECDHWycheproof(t *testing.T) {
145 flagsShouldPass := map[string]bool{
146 "Twist": true,
147 "SmallPublicKey": false,
148 "LowOrderPublic": false,
149 "ZeroSharedSecret": false,
150 "NonCanonicalPublic": true,
151 "SpecialPublicKey": true,
152 "EdgeCaseMultiplication": true,
153 "EdgeCaseShared": true,
154 "Ktv": true,
155 }
156
157 file := "x25519_test.json"
158 var testdata wycheproof.XdhCompSchemaV1Json
159 wycheproof.LoadVectorFile(t, file, &testdata)
160
161 for _, tg := range testdata.TestGroups {
162 if tg.Curve != "curve25519" {
163 continue
164 }
165
166 for _, tv := range tg.Tests {
167 testName := wycheproof.TestName(file, tv)
168 tv := ecdhWycheproofTV{
169 tcID: tv.TcId,
170 comment: tv.Comment,
171 flags: tv.Flags,
172 result: tv.Result,
173 public: tv.Public,
174 private: tv.Private,
175 shared: tv.Shared,
176 }
177 t.Run(testName, func(t *testing.T) {
178 t.Parallel()
179 runECDHWycheproofTest(t, ecdh.X25519(), 32, flagsShouldPass, tv, ecdh.X25519().NewPublicKey)
180 })
181 }
182 }
183 }
184
185
186
187
188 type ecdhWycheproofTV struct {
189 tcID int
190 comment string
191 flags []string
192 result wycheproof.Result
193 public string
194 private string
195 shared string
196 }
197
198
199
200 func runECDHWycheproofTest(
201 t *testing.T,
202 curve ecdh.Curve,
203 expectedKeySize int,
204 flagsShouldPass map[string]bool,
205 tv ecdhWycheproofTV,
206 parsePub func([]byte) (*ecdh.PublicKey, error)) {
207 t.Helper()
208
209 shouldPass := wycheproof.ShouldPass(t, tv.result, tv.flags, flagsShouldPass)
210
211 pub, err := parsePub(wycheproof.MustDecodeHex(tv.public))
212 if err != nil {
213 if shouldPass {
214 t.Errorf("parsePub: %v", err)
215 }
216 return
217 }
218
219 privBytes := wycheproof.MustDecodeHex(tv.private)
220 priv, err := curve.NewPrivateKey(privBytes)
221 if err != nil {
222 if shouldPass && len(privBytes) == expectedKeySize {
223 t.Errorf("NewPrivateKey: %v", err)
224 }
225 return
226 }
227
228 x, err := priv.ECDH(pub)
229 if err != nil {
230 if shouldPass {
231 t.Fatalf("ECDH: %v", err)
232 }
233 return
234 }
235
236 shared := wycheproof.MustDecodeHex(tv.shared)
237 if shouldPass {
238 if !bytes.Equal(shared, x) {
239 t.Errorf("ECDH = %x, want %x", x, shared)
240 }
241 } else if tv.result == "invalid" {
242
243 if bytes.Equal(shared, x) {
244 t.Errorf("ECDH = %x, want anything else", x)
245 }
246 }
247 }
248
View as plain text