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