1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "blapi.h"
6 #include "ec.h"
7 #include "ecl-curve.h"
8 #include "prprf.h"
9 #include "basicutil.h"
10 #include "secder.h"
11 #include "secitem.h"
12 #include "nspr.h"
13 #include <stdio.h>
14
15 typedef struct {
16 ECCurveName curve;
17 int iterations;
18 char *privhex;
19 char *our_pubhex;
20 char *their_pubhex;
21 char *common_key;
22 char *name;
23 ECFieldType fieldType;
24 } ECDH_KAT;
25
26 typedef struct {
27 ECCurveName curve;
28 char *point;
29 char *name;
30 ECFieldType fieldType;
31 } ECDH_BAD;
32
33 #include "testvecs.h"
34
35 void
printBuf(const SECItem * item)36 printBuf(const SECItem *item)
37 {
38 int i;
39 if (!item || !item->len) {
40 printf("(null)\n");
41 return;
42 }
43
44 for (i = 0; i < item->len; i++) {
45 printf("%02x", item->data[i]);
46 }
47 printf("\n");
48 }
49
50 /* Initialise test with basic curve populate with only the necessary things */
51 SECStatus
init_params(ECParams * ecParams,ECCurveName curve,PLArenaPool ** arena,ECFieldType type)52 init_params(ECParams *ecParams, ECCurveName curve, PLArenaPool **arena,
53 ECFieldType type)
54 {
55 if ((curve < ECCurve_noName) || (curve > ECCurve_pastLastCurve)) {
56 return SECFailure;
57 }
58 *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
59 if (!*arena) {
60 return SECFailure;
61 }
62 ecParams->name = curve;
63 ecParams->type = ec_params_named;
64 ecParams->curveOID.data = NULL;
65 ecParams->curveOID.len = 0;
66 ecParams->curve.seed.data = NULL;
67 ecParams->curve.seed.len = 0;
68 ecParams->DEREncoding.data = NULL;
69 ecParams->DEREncoding.len = 0;
70 ecParams->arena = *arena;
71 ecParams->fieldID.size = ecCurve_map[curve]->size;
72 ecParams->fieldID.type = type;
73 ecParams->cofactor = ecCurve_map[curve]->cofactor;
74
75 return SECSuccess;
76 }
77
78 SECStatus
ectest_ecdh_kat(ECDH_KAT * kat)79 ectest_ecdh_kat(ECDH_KAT *kat)
80 {
81 ECCurveName curve = kat->curve;
82 ECParams ecParams = { 0 };
83 ECPrivateKey *ecPriv = NULL;
84 SECItem theirKey = { siBuffer, NULL, 0 };
85 SECStatus rv = SECFailure;
86 PLArenaPool *arena = NULL;
87 SECItem seed = { siBuffer, NULL, 0 };
88 SECItem answer = { siBuffer, NULL, 0 };
89 SECItem answer2 = { siBuffer, NULL, 0 };
90 SECItem derived = { siBuffer, NULL, 0 };
91 SECItem ecEncodedParams = { siBuffer, NULL, 0 };
92 int i;
93
94 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
95 if (!arena) {
96 return SECFailure;
97 }
98
99 rv = SECU_ecName2params(curve, &ecEncodedParams);
100 if (rv != SECSuccess) {
101 goto cleanup;
102 }
103 EC_FillParams(arena, &ecEncodedParams, &ecParams);
104
105 if (kat->our_pubhex) {
106 SECU_HexString2SECItem(arena, &answer, kat->our_pubhex);
107 }
108 SECU_HexString2SECItem(arena, &seed, kat->privhex);
109 rv = EC_NewKeyFromSeed(&ecParams, &ecPriv, seed.data, seed.len);
110 if (rv != SECSuccess) {
111 rv = SECFailure;
112 goto cleanup;
113 }
114 if (kat->our_pubhex) {
115 if (SECITEM_CompareItem(&answer, &ecPriv->publicValue) != SECEqual) {
116 rv = SECFailure;
117 goto cleanup;
118 }
119 }
120
121 SECU_HexString2SECItem(arena, &theirKey, kat->their_pubhex);
122 SECU_HexString2SECItem(arena, &answer2, kat->common_key);
123
124 rv = EC_ValidatePublicKey(&ecParams, &theirKey);
125 if (rv != SECSuccess) {
126 printf("EC_ValidatePublicKey failed\n");
127 goto cleanup;
128 }
129
130 for (i = 0; i < kat->iterations; ++i) {
131 rv = ECDH_Derive(&theirKey, &ecParams, &ecPriv->privateValue, PR_TRUE, &derived);
132 if (rv != SECSuccess) {
133 rv = SECFailure;
134 goto cleanup;
135 }
136 rv = SECITEM_CopyItem(ecParams.arena, &theirKey, &ecPriv->privateValue);
137 if (rv != SECSuccess) {
138 goto cleanup;
139 }
140 rv = SECITEM_CopyItem(ecParams.arena, &ecPriv->privateValue, &derived);
141 if (rv != SECSuccess) {
142 goto cleanup;
143 }
144 SECITEM_FreeItem(&derived, PR_FALSE);
145 }
146
147 if (SECITEM_CompareItem(&answer2, &ecPriv->privateValue) != SECEqual) {
148 printf("expected: ");
149 printBuf(&answer2);
150 printf("derived: ");
151 printBuf(&ecPriv->privateValue);
152 rv = SECFailure;
153 goto cleanup;
154 }
155
156 cleanup:
157 SECITEM_FreeItem(&ecEncodedParams, PR_FALSE);
158 PORT_FreeArena(arena, PR_FALSE);
159 if (ecPriv) {
160 PORT_FreeArena(ecPriv->ecParams.arena, PR_FALSE);
161 }
162 if (derived.data) {
163 SECITEM_FreeItem(&derived, PR_FALSE);
164 }
165 return rv;
166 }
167
168 SECStatus
ectest_validate_point(ECDH_BAD * bad)169 ectest_validate_point(ECDH_BAD *bad)
170 {
171 ECParams ecParams = { 0 };
172 SECItem point = { siBuffer, NULL, 0 };
173 SECStatus rv = SECFailure;
174 PLArenaPool *arena = NULL;
175
176 rv = init_params(&ecParams, bad->curve, &arena, bad->fieldType);
177 if (rv != SECSuccess) {
178 return rv;
179 }
180
181 SECU_HexString2SECItem(arena, &point, bad->point);
182 rv = EC_ValidatePublicKey(&ecParams, &point);
183
184 PORT_FreeArena(arena, PR_FALSE);
185 return rv;
186 }
187
188 void
printUsage(char * prog)189 printUsage(char *prog)
190 {
191 printf("Usage: %s [-fp] [-nd]\n"
192 "\t-n: NIST curves\n"
193 "\t-d: non-NIST curves\n"
194 "You have to specify at at least one of n or d.\n"
195 "By default no tests are executed.\n",
196 prog);
197 }
198
199 /* Performs tests of elliptic curve cryptography over prime fields If
200 * tests fail, then it prints an error message, aborts, and returns an
201 * error code. Otherwise, returns 0. */
202 int
main(int argv,char ** argc)203 main(int argv, char **argc)
204 {
205 SECStatus rv = SECSuccess;
206 int numkats = 0;
207 int i = 0;
208 int nist = 0;
209 int nonnist = 0;
210
211 for (i = 1; i < argv; i++) {
212 if (PL_strcasecmp(argc[i], "-n") == 0) {
213 nist = 1;
214 } else if (PL_strcasecmp(argc[i], "-d") == 0) {
215 nonnist = 1;
216 } else {
217 printUsage(argc[0]);
218 return 1;
219 }
220 }
221 if (!nist && !nonnist) {
222 printUsage(argc[0]);
223 return 1;
224 }
225
226 rv = SECOID_Init();
227 if (rv != SECSuccess) {
228 SECU_PrintError("Error:", "SECOID_Init");
229 goto cleanup;
230 }
231
232 /* Test P256, P384, P521 */
233 if (nist) {
234 while (ecdh_testvecs[numkats].curve != ECCurve_pastLastCurve) {
235 numkats++;
236 }
237 printf("1..%d\n", numkats);
238 for (i = 0; ecdh_testvecs[i].curve != ECCurve_pastLastCurve; i++) {
239 if (ectest_ecdh_kat(&ecdh_testvecs[i]) != SECSuccess) {
240 printf("not okay %d - %s\n", i + 1, ecdh_testvecs[i].name);
241 rv = SECFailure;
242 } else {
243 printf("okay %d - %s\n", i + 1, ecdh_testvecs[i].name);
244 }
245 }
246 }
247
248 /* Test KAT for non-NIST curves */
249 if (nonnist) {
250 for (i = 0; nonnist_testvecs[i].curve != ECCurve_pastLastCurve; i++) {
251 if (ectest_ecdh_kat(&nonnist_testvecs[i]) != SECSuccess) {
252 printf("not okay %d - %s\n", i + 1, nonnist_testvecs[i].name);
253 rv = SECFailure;
254 } else {
255 printf("okay %d - %s\n", i + 1, nonnist_testvecs[i].name);
256 }
257 }
258 for (i = 0; nonnist_testvecs_bad_values[i].curve != ECCurve_pastLastCurve; i++) {
259 if (ectest_validate_point(&nonnist_testvecs_bad_values[i]) == SECSuccess) {
260 printf("not okay %d - %s\n", i + 1, nonnist_testvecs_bad_values[i].name);
261 rv = SECFailure;
262 } else {
263 printf("okay %d - %s\n", i + 1, nonnist_testvecs_bad_values[i].name);
264 }
265 }
266 }
267
268 cleanup:
269 rv |= SECOID_Shutdown();
270
271 if (rv != SECSuccess) {
272 printf("Error: exiting with error value\n");
273 }
274 return rv;
275 }
276