|
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 "nss.h" |
|
9 #include "secutil.h" |
|
10 #include "pkcs11.h" |
|
11 #include <nspr.h> |
|
12 #include <stdio.h> |
|
13 #include <strings.h> |
|
14 #include <assert.h> |
|
15 |
|
16 #include <time.h> |
|
17 #include <sys/time.h> |
|
18 #include <sys/resource.h> |
|
19 |
|
20 #define __PASTE(x,y) x##y |
|
21 |
|
22 /* |
|
23 * Get the NSS specific PKCS #11 function names. |
|
24 */ |
|
25 #undef CK_PKCS11_FUNCTION_INFO |
|
26 #undef CK_NEED_ARG_LIST |
|
27 |
|
28 #define CK_EXTERN extern |
|
29 #define CK_PKCS11_FUNCTION_INFO(func) \ |
|
30 CK_RV __PASTE(NS,func) |
|
31 #define CK_NEED_ARG_LIST 1 |
|
32 |
|
33 #include "pkcs11f.h" |
|
34 |
|
35 |
|
36 |
|
37 /* mapping between ECCurveName enum and pointers to ECCurveParams */ |
|
38 static SECOidTag ecCurve_oid_map[] = { |
|
39 SEC_OID_UNKNOWN, /* ECCurve_noName */ |
|
40 SEC_OID_ANSIX962_EC_PRIME192V1, /* ECCurve_NIST_P192 */ |
|
41 SEC_OID_SECG_EC_SECP224R1, /* ECCurve_NIST_P224 */ |
|
42 SEC_OID_ANSIX962_EC_PRIME256V1, /* ECCurve_NIST_P256 */ |
|
43 SEC_OID_SECG_EC_SECP384R1, /* ECCurve_NIST_P384 */ |
|
44 SEC_OID_SECG_EC_SECP521R1, /* ECCurve_NIST_P521 */ |
|
45 SEC_OID_SECG_EC_SECT163K1, /* ECCurve_NIST_K163 */ |
|
46 SEC_OID_SECG_EC_SECT163R1, /* ECCurve_NIST_B163 */ |
|
47 SEC_OID_SECG_EC_SECT233K1, /* ECCurve_NIST_K233 */ |
|
48 SEC_OID_SECG_EC_SECT233R1, /* ECCurve_NIST_B233 */ |
|
49 SEC_OID_SECG_EC_SECT283K1, /* ECCurve_NIST_K283 */ |
|
50 SEC_OID_SECG_EC_SECT283R1, /* ECCurve_NIST_B283 */ |
|
51 SEC_OID_SECG_EC_SECT409K1, /* ECCurve_NIST_K409 */ |
|
52 SEC_OID_SECG_EC_SECT409R1, /* ECCurve_NIST_B409 */ |
|
53 SEC_OID_SECG_EC_SECT571K1, /* ECCurve_NIST_K571 */ |
|
54 SEC_OID_SECG_EC_SECT571R1, /* ECCurve_NIST_B571 */ |
|
55 SEC_OID_ANSIX962_EC_PRIME192V2, |
|
56 SEC_OID_ANSIX962_EC_PRIME192V3, |
|
57 SEC_OID_ANSIX962_EC_PRIME239V1, |
|
58 SEC_OID_ANSIX962_EC_PRIME239V2, |
|
59 SEC_OID_ANSIX962_EC_PRIME239V3, |
|
60 SEC_OID_ANSIX962_EC_C2PNB163V1, |
|
61 SEC_OID_ANSIX962_EC_C2PNB163V2, |
|
62 SEC_OID_ANSIX962_EC_C2PNB163V3, |
|
63 SEC_OID_ANSIX962_EC_C2PNB176V1, |
|
64 SEC_OID_ANSIX962_EC_C2TNB191V1, |
|
65 SEC_OID_ANSIX962_EC_C2TNB191V2, |
|
66 SEC_OID_ANSIX962_EC_C2TNB191V3, |
|
67 SEC_OID_ANSIX962_EC_C2PNB208W1, |
|
68 SEC_OID_ANSIX962_EC_C2TNB239V1, |
|
69 SEC_OID_ANSIX962_EC_C2TNB239V2, |
|
70 SEC_OID_ANSIX962_EC_C2TNB239V3, |
|
71 SEC_OID_ANSIX962_EC_C2PNB272W1, |
|
72 SEC_OID_ANSIX962_EC_C2PNB304W1, |
|
73 SEC_OID_ANSIX962_EC_C2TNB359V1, |
|
74 SEC_OID_ANSIX962_EC_C2PNB368W1, |
|
75 SEC_OID_ANSIX962_EC_C2TNB431R1, |
|
76 SEC_OID_SECG_EC_SECP112R1, |
|
77 SEC_OID_SECG_EC_SECP112R2, |
|
78 SEC_OID_SECG_EC_SECP128R1, |
|
79 SEC_OID_SECG_EC_SECP128R2, |
|
80 SEC_OID_SECG_EC_SECP160K1, |
|
81 SEC_OID_SECG_EC_SECP160R1, |
|
82 SEC_OID_SECG_EC_SECP160R2, |
|
83 SEC_OID_SECG_EC_SECP192K1, |
|
84 SEC_OID_SECG_EC_SECP224K1, |
|
85 SEC_OID_SECG_EC_SECP256K1, |
|
86 SEC_OID_SECG_EC_SECT113R1, |
|
87 SEC_OID_SECG_EC_SECT113R2, |
|
88 SEC_OID_SECG_EC_SECT131R1, |
|
89 SEC_OID_SECG_EC_SECT131R2, |
|
90 SEC_OID_SECG_EC_SECT163R1, |
|
91 SEC_OID_SECG_EC_SECT193R1, |
|
92 SEC_OID_SECG_EC_SECT193R2, |
|
93 SEC_OID_SECG_EC_SECT239K1, |
|
94 SEC_OID_UNKNOWN /* ECCurve_pastLastCurve */ |
|
95 }; |
|
96 |
|
97 typedef SECStatus (*op_func) (void *, void *, void *); |
|
98 typedef SECStatus (*pk11_op_func) (CK_SESSION_HANDLE, void *, void *, void *); |
|
99 |
|
100 typedef struct ThreadDataStr { |
|
101 op_func op; |
|
102 void *p1; |
|
103 void *p2; |
|
104 void *p3; |
|
105 int iters; |
|
106 PRLock *lock; |
|
107 int count; |
|
108 SECStatus status; |
|
109 int isSign; |
|
110 } ThreadData; |
|
111 |
|
112 void PKCS11Thread(void *data) |
|
113 { |
|
114 ThreadData *threadData = (ThreadData *)data; |
|
115 pk11_op_func op = (pk11_op_func) threadData->op; |
|
116 int iters = threadData->iters; |
|
117 unsigned char sigData [256]; |
|
118 SECItem sig; |
|
119 CK_SESSION_HANDLE session; |
|
120 CK_RV crv; |
|
121 |
|
122 threadData->status = SECSuccess; |
|
123 threadData->count = 0; |
|
124 |
|
125 /* get our thread's session */ |
|
126 PR_Lock(threadData->lock); |
|
127 crv = NSC_OpenSession(1, CKF_SERIAL_SESSION, NULL, 0, &session); |
|
128 PR_Unlock(threadData->lock); |
|
129 |
|
130 if (threadData->isSign) { |
|
131 sig.data = sigData; |
|
132 sig.len = sizeof(sigData); |
|
133 threadData->p2 = (void *)&sig; |
|
134 } |
|
135 |
|
136 while (iters --) { |
|
137 threadData->status = (*op)(session, threadData->p1, |
|
138 threadData->p2, threadData->p3); |
|
139 if (threadData->status != SECSuccess) { |
|
140 break; |
|
141 } |
|
142 threadData->count++; |
|
143 } |
|
144 return; |
|
145 } |
|
146 |
|
147 void genericThread(void *data) |
|
148 { |
|
149 ThreadData *threadData = (ThreadData *)data; |
|
150 int iters = threadData->iters; |
|
151 unsigned char sigData [256]; |
|
152 SECItem sig; |
|
153 |
|
154 threadData->status = SECSuccess; |
|
155 threadData->count = 0; |
|
156 |
|
157 if (threadData->isSign) { |
|
158 sig.data = sigData; |
|
159 sig.len = sizeof(sigData); |
|
160 threadData->p2 = (void *)&sig; |
|
161 } |
|
162 |
|
163 while (iters --) { |
|
164 threadData->status = (*threadData->op)(threadData->p1, |
|
165 threadData->p2, threadData->p3); |
|
166 if (threadData->status != SECSuccess) { |
|
167 break; |
|
168 } |
|
169 threadData->count++; |
|
170 } |
|
171 return; |
|
172 } |
|
173 |
|
174 |
|
175 /* Time iter repetitions of operation op. */ |
|
176 SECStatus |
|
177 M_TimeOperation(void (*threadFunc)(void *), |
|
178 op_func opfunc, char *op, void *param1, void *param2, |
|
179 void *param3, int iters, int numThreads, PRLock *lock, |
|
180 CK_SESSION_HANDLE session, int isSign, double *rate) |
|
181 { |
|
182 double dUserTime; |
|
183 int i, total; |
|
184 PRIntervalTime startTime, totalTime; |
|
185 PRThread **threadIDs; |
|
186 ThreadData *threadData; |
|
187 pk11_op_func pk11_op = (pk11_op_func) opfunc; |
|
188 SECStatus rv; |
|
189 |
|
190 /* verify operation works before testing performance */ |
|
191 if (session) { |
|
192 rv = (*pk11_op)(session, param1, param2, param3); |
|
193 } else { |
|
194 rv = (*opfunc)(param1, param2, param3); |
|
195 } |
|
196 if (rv != SECSuccess) { |
|
197 SECU_PrintError("Error:", op); |
|
198 return rv; |
|
199 } |
|
200 |
|
201 /* get Data structures */ |
|
202 threadIDs = (PRThread **)PORT_Alloc(numThreads*sizeof(PRThread *)); |
|
203 threadData = (ThreadData *)PORT_Alloc(numThreads*sizeof(ThreadData)); |
|
204 |
|
205 startTime = PR_Now(); |
|
206 if (numThreads == 1) { |
|
207 for (i=0; i < iters; i++) { |
|
208 if (session) { |
|
209 rv = (*pk11_op)(session, param1, param2, param3); |
|
210 } else { |
|
211 rv = (*opfunc)(param1, param2, param3); |
|
212 } |
|
213 } |
|
214 total = iters; |
|
215 } else { |
|
216 for (i = 0; i < numThreads; i++) { |
|
217 threadData[i].op = opfunc; |
|
218 threadData[i].p1 = (void *)param1; |
|
219 threadData[i].p2 = (void *)param2; |
|
220 threadData[i].p3 = (void *)param3; |
|
221 threadData[i].iters = iters; |
|
222 threadData[i].lock = lock; |
|
223 threadData[i].isSign = isSign; |
|
224 threadIDs[i] = PR_CreateThread(PR_USER_THREAD, threadFunc, |
|
225 (void *)&threadData[i], PR_PRIORITY_NORMAL, |
|
226 PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); |
|
227 } |
|
228 |
|
229 total = 0; |
|
230 for (i = 0; i < numThreads; i++) { |
|
231 PR_JoinThread(threadIDs[i]); |
|
232 /* check the status */ |
|
233 total += threadData[i].count; |
|
234 } |
|
235 |
|
236 PORT_Free(threadIDs); |
|
237 PORT_Free(threadData); |
|
238 } |
|
239 |
|
240 totalTime = PR_Now()- startTime; |
|
241 /* SecondsToInterval seems to be broken here ... */ |
|
242 dUserTime = (double)totalTime/(double)1000000; |
|
243 if (dUserTime) { |
|
244 printf(" %-15s count:%4d sec: %3.2f op/sec: %6.2f\n", |
|
245 op, total, dUserTime, (double)total/dUserTime); |
|
246 if (rate) { |
|
247 *rate = ((double)total)/dUserTime; |
|
248 } |
|
249 } |
|
250 return SECSuccess; |
|
251 } |
|
252 |
|
253 #define GFP_POPULATE(params,name_v) \ |
|
254 params.name = name_v; \ |
|
255 if ((params.name < ECCurve_noName) || \ |
|
256 (params.name > ECCurve_pastLastCurve)) goto cleanup; \ |
|
257 params.type = ec_params_named; \ |
|
258 params.curveOID.data = NULL; \ |
|
259 params.curveOID.len = 0; \ |
|
260 params.curve.seed.data = NULL; \ |
|
261 params.curve.seed.len = 0; \ |
|
262 params.DEREncoding.data = NULL; \ |
|
263 params.DEREncoding.len = 0; \ |
|
264 params.arena = NULL; \ |
|
265 params.fieldID.size = ecCurve_map[name_v]->size; \ |
|
266 params.fieldID.type = ec_field_GFp; \ |
|
267 hexString2SECItem(params.arena, ¶ms.fieldID.u.prime, \ |
|
268 ecCurve_map[name_v]->irr); \ |
|
269 hexString2SECItem(params.arena, ¶ms.curve.a, \ |
|
270 ecCurve_map[name_v]->curvea); \ |
|
271 hexString2SECItem(params.arena, ¶ms.curve.b, \ |
|
272 ecCurve_map[name_v]->curveb); \ |
|
273 genenc[0] = '0'; \ |
|
274 genenc[1] = '4'; \ |
|
275 genenc[2] = '\0'; \ |
|
276 strcat(genenc, ecCurve_map[name_v]->genx); \ |
|
277 strcat(genenc, ecCurve_map[name_v]->geny); \ |
|
278 hexString2SECItem(params.arena, ¶ms.base, \ |
|
279 genenc); \ |
|
280 hexString2SECItem(params.arena, ¶ms.order, \ |
|
281 ecCurve_map[name_v]->order); \ |
|
282 params.cofactor = ecCurve_map[name_v]->cofactor; |
|
283 |
|
284 |
|
285 /* Test curve using specific field arithmetic. */ |
|
286 #define ECTEST_NAMED_GFP(name_c, name_v) \ |
|
287 if (usefreebl) { \ |
|
288 printf("Testing %s using freebl implementation...\n", name_c); \ |
|
289 rv = ectest_curve_freebl(name_v, iterations, numThreads); \ |
|
290 if (rv != SECSuccess) goto cleanup; \ |
|
291 printf("... okay.\n"); \ |
|
292 } \ |
|
293 if (usepkcs11) { \ |
|
294 printf("Testing %s using pkcs11 implementation...\n", name_c); \ |
|
295 rv = ectest_curve_pkcs11(name_v, iterations, numThreads); \ |
|
296 if (rv != SECSuccess) goto cleanup; \ |
|
297 printf("... okay.\n"); \ |
|
298 } |
|
299 |
|
300 /* |
|
301 * Initializes a SECItem from a hexadecimal string |
|
302 * |
|
303 * Warning: This function ignores leading 00's, so any leading 00's |
|
304 * in the hexadecimal string must be optional. |
|
305 */ |
|
306 static SECItem * |
|
307 hexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str) |
|
308 { |
|
309 int i = 0; |
|
310 int byteval = 0; |
|
311 int tmp = PORT_Strlen(str); |
|
312 |
|
313 if ((tmp % 2) != 0) return NULL; |
|
314 |
|
315 /* skip leading 00's unless the hex string is "00" */ |
|
316 while ((tmp > 2) && (str[0] == '0') && (str[1] == '0')) { |
|
317 str += 2; |
|
318 tmp -= 2; |
|
319 } |
|
320 |
|
321 item->data = (unsigned char *) PORT_Alloc( tmp/2); |
|
322 if (item->data == NULL) return NULL; |
|
323 item->len = tmp/2; |
|
324 |
|
325 while (str[i]) { |
|
326 if ((str[i] >= '0') && (str[i] <= '9')) |
|
327 tmp = str[i] - '0'; |
|
328 else if ((str[i] >= 'a') && (str[i] <= 'f')) |
|
329 tmp = str[i] - 'a' + 10; |
|
330 else if ((str[i] >= 'A') && (str[i] <= 'F')) |
|
331 tmp = str[i] - 'A' + 10; |
|
332 else |
|
333 return NULL; |
|
334 |
|
335 byteval = byteval * 16 + tmp; |
|
336 if ((i % 2) != 0) { |
|
337 item->data[i/2] = byteval; |
|
338 byteval = 0; |
|
339 } |
|
340 i++; |
|
341 } |
|
342 |
|
343 return item; |
|
344 } |
|
345 |
|
346 #define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \ |
|
347 (x)->pValue=(v); (x)->ulValueLen = (l); |
|
348 |
|
349 |
|
350 SECStatus |
|
351 PKCS11_Derive(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey, |
|
352 CK_MECHANISM *pMech , int *dummy) |
|
353 { |
|
354 CK_RV crv; |
|
355 CK_OBJECT_HANDLE newKey; |
|
356 CK_BBOOL cktrue = CK_TRUE; |
|
357 CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; |
|
358 CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; |
|
359 CK_ATTRIBUTE keyTemplate[3]; |
|
360 CK_ATTRIBUTE *attrs = keyTemplate; |
|
361 |
|
362 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); |
|
363 attrs++; |
|
364 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); |
|
365 attrs++; |
|
366 PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, 1); attrs++; |
|
367 |
|
368 |
|
369 crv = NSC_DeriveKey(session, pMech, *hKey, keyTemplate, 3, &newKey); |
|
370 if (crv != CKR_OK) { |
|
371 printf("Derive Failed CK_RV=0x%x\n", (int)crv); |
|
372 return SECFailure; |
|
373 } |
|
374 return SECSuccess; |
|
375 } |
|
376 |
|
377 SECStatus |
|
378 PKCS11_Sign(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey, |
|
379 SECItem *sig, SECItem *digest) |
|
380 { |
|
381 CK_RV crv; |
|
382 CK_MECHANISM mech; |
|
383 |
|
384 mech.mechanism = CKM_ECDSA; |
|
385 mech.pParameter = NULL; |
|
386 mech.ulParameterLen = 0; |
|
387 |
|
388 crv = NSC_SignInit(session, &mech, *hKey); |
|
389 if (crv != CKR_OK) { |
|
390 printf("Sign Failed CK_RV=0x%x\n", (int)crv); |
|
391 return SECFailure; |
|
392 } |
|
393 crv = NSC_Sign(session, digest->data, digest->len, sig->data, |
|
394 (CK_ULONG_PTR)&sig->len); |
|
395 if (crv != CKR_OK) { |
|
396 printf("Sign Failed CK_RV=0x%x\n", (int)crv); |
|
397 return SECFailure; |
|
398 } |
|
399 return SECSuccess; |
|
400 } |
|
401 |
|
402 SECStatus |
|
403 PKCS11_Verify(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey, |
|
404 SECItem *sig, SECItem *digest) |
|
405 { |
|
406 CK_RV crv; |
|
407 CK_MECHANISM mech; |
|
408 |
|
409 mech.mechanism = CKM_ECDSA; |
|
410 mech.pParameter = NULL; |
|
411 mech.ulParameterLen = 0; |
|
412 |
|
413 crv = NSC_VerifyInit(session, &mech, *hKey); |
|
414 if (crv != CKR_OK) { |
|
415 printf("Verify Failed CK_RV=0x%x\n", (int)crv); |
|
416 return SECFailure; |
|
417 } |
|
418 crv = NSC_Verify(session, digest->data, digest->len, sig->data, sig->len); |
|
419 if (crv != CKR_OK) { |
|
420 printf("Verify Failed CK_RV=0x%x\n", (int)crv); |
|
421 return SECFailure; |
|
422 } |
|
423 return SECSuccess; |
|
424 } |
|
425 |
|
426 static SECStatus |
|
427 ecName2params(ECCurveName curve, SECKEYECParams * params) |
|
428 { |
|
429 SECOidData *oidData = NULL; |
|
430 |
|
431 if ((curve < ECCurve_noName) || (curve > ECCurve_pastLastCurve) || |
|
432 ((oidData = SECOID_FindOIDByTag(ecCurve_oid_map[curve])) == NULL)) { |
|
433 PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
|
434 return SECFailure; |
|
435 } |
|
436 |
|
437 SECITEM_AllocItem(NULL, params, (2 + oidData->oid.len)); |
|
438 /* |
|
439 * params->data needs to contain the ASN encoding of an object ID (OID) |
|
440 * representing the named curve. The actual OID is in |
|
441 * oidData->oid.data so we simply prepend 0x06 and OID length |
|
442 */ |
|
443 params->data[0] = SEC_ASN1_OBJECT_ID; |
|
444 params->data[1] = oidData->oid.len; |
|
445 memcpy(params->data + 2, oidData->oid.data, oidData->oid.len); |
|
446 |
|
447 return SECSuccess; |
|
448 } |
|
449 |
|
450 |
|
451 |
|
452 /* Performs basic tests of elliptic curve cryptography over prime fields. |
|
453 * If tests fail, then it prints an error message, aborts, and returns an |
|
454 * error code. Otherwise, returns 0. */ |
|
455 SECStatus |
|
456 ectest_curve_pkcs11(ECCurveName curve, int iterations, int numThreads) |
|
457 { |
|
458 CK_OBJECT_HANDLE ecPriv; |
|
459 CK_OBJECT_HANDLE ecPub; |
|
460 CK_SESSION_HANDLE session; |
|
461 SECItem sig; |
|
462 SECItem digest; |
|
463 SECKEYECParams ecParams; |
|
464 CK_MECHANISM mech; |
|
465 CK_ECDH1_DERIVE_PARAMS ecdh_params; |
|
466 unsigned char sigData [256]; |
|
467 unsigned char digestData[20]; |
|
468 unsigned char pubKeyData[256]; |
|
469 PRLock *lock = NULL; |
|
470 double signRate, deriveRate; |
|
471 CK_ATTRIBUTE template; |
|
472 SECStatus rv; |
|
473 CK_RV crv; |
|
474 |
|
475 ecParams.data = NULL; |
|
476 ecParams.len = 0; |
|
477 rv = ecName2params(curve, &ecParams); |
|
478 if (rv != SECSuccess) { |
|
479 goto cleanup; |
|
480 } |
|
481 |
|
482 crv = NSC_OpenSession(1, CKF_SERIAL_SESSION, NULL, 0, &session); |
|
483 if (crv != CKR_OK) { |
|
484 printf("OpenSession Failed CK_RV=0x%x\n", (int)crv); |
|
485 return SECFailure; |
|
486 } |
|
487 |
|
488 PORT_Memset(digestData, 0xa5, sizeof(digestData)); |
|
489 digest.data = digestData; |
|
490 digest.len = sizeof(digestData); |
|
491 sig.data = sigData; |
|
492 sig.len = sizeof(sigData); |
|
493 |
|
494 template.type = CKA_EC_PARAMS; |
|
495 template.pValue = ecParams.data; |
|
496 template.ulValueLen = ecParams.len; |
|
497 mech.mechanism = CKM_EC_KEY_PAIR_GEN; |
|
498 mech.pParameter = NULL; |
|
499 mech.ulParameterLen = 0; |
|
500 crv = NSC_GenerateKeyPair(session, &mech, |
|
501 &template, 1, NULL, 0, &ecPub, &ecPriv); |
|
502 if (crv != CKR_OK) { |
|
503 printf("GenerateKeyPair Failed CK_RV=0x%x\n", (int)crv); |
|
504 return SECFailure; |
|
505 } |
|
506 |
|
507 template.type = CKA_EC_POINT; |
|
508 template.pValue = pubKeyData; |
|
509 template.ulValueLen = sizeof(pubKeyData); |
|
510 crv = NSC_GetAttributeValue(session, ecPub, &template, 1); |
|
511 if (crv != CKR_OK) { |
|
512 printf("GenerateKeyPair Failed CK_RV=0x%x\n", (int)crv); |
|
513 return SECFailure; |
|
514 } |
|
515 |
|
516 ecdh_params.kdf = CKD_NULL; |
|
517 ecdh_params.ulSharedDataLen = 0; |
|
518 ecdh_params.pSharedData = NULL; |
|
519 ecdh_params.ulPublicDataLen = template.ulValueLen; |
|
520 ecdh_params.pPublicData = template.pValue; |
|
521 |
|
522 mech.mechanism = CKM_ECDH1_DERIVE; |
|
523 mech.pParameter = (void *)&ecdh_params; |
|
524 mech.ulParameterLen = sizeof(ecdh_params); |
|
525 |
|
526 lock = PR_NewLock(); |
|
527 |
|
528 rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Derive, "ECDH_Derive", |
|
529 &ecPriv, &mech, NULL, iterations, numThreads, |
|
530 lock, session, 0, &deriveRate); |
|
531 if (rv != SECSuccess) goto cleanup; |
|
532 rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Sign, "ECDSA_Sign", |
|
533 (void *)&ecPriv, &sig, &digest, iterations, numThreads, |
|
534 lock, session, 1, &signRate); |
|
535 if (rv != SECSuccess) goto cleanup; |
|
536 printf(" ECDHE max rate = %.2f\n", (deriveRate+signRate)/4.0); |
|
537 /* get a signature */ |
|
538 rv = PKCS11_Sign(session, &ecPriv, &sig, &digest); |
|
539 if (rv != SECSuccess) goto cleanup; |
|
540 rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Verify, "ECDSA_Verify", |
|
541 (void *)&ecPub, &sig, &digest, iterations, numThreads, |
|
542 lock, session, 0, NULL); |
|
543 if (rv != SECSuccess) goto cleanup; |
|
544 |
|
545 cleanup: |
|
546 if (lock) { |
|
547 PR_DestroyLock(lock); |
|
548 } |
|
549 return rv; |
|
550 } |
|
551 |
|
552 SECStatus |
|
553 ECDH_DeriveWrap(ECPrivateKey *priv, ECPublicKey *pub, int *dummy) |
|
554 { |
|
555 SECItem secret; |
|
556 unsigned char secretData[256]; |
|
557 SECStatus rv; |
|
558 |
|
559 secret.data = secretData; |
|
560 secret.len = sizeof(secretData); |
|
561 |
|
562 rv = ECDH_Derive(&pub->publicValue, &pub->ecParams, |
|
563 &priv->privateValue, 0, &secret); |
|
564 #ifdef notdef |
|
565 if (rv == SECSuccess) { |
|
566 PORT_Free(secret.data); |
|
567 } |
|
568 #endif |
|
569 return rv; |
|
570 } |
|
571 |
|
572 /* Performs basic tests of elliptic curve cryptography over prime fields. |
|
573 * If tests fail, then it prints an error message, aborts, and returns an |
|
574 * error code. Otherwise, returns 0. */ |
|
575 SECStatus |
|
576 ectest_curve_freebl(ECCurveName curve, int iterations, int numThreads) |
|
577 { |
|
578 ECParams ecParams; |
|
579 ECPrivateKey *ecPriv = NULL; |
|
580 ECPublicKey ecPub; |
|
581 SECItem sig; |
|
582 SECItem digest; |
|
583 unsigned char sigData [256]; |
|
584 unsigned char digestData[20]; |
|
585 double signRate, deriveRate; |
|
586 char genenc[3 + 2 * 2 * MAX_ECKEY_LEN]; |
|
587 SECStatus rv; |
|
588 |
|
589 |
|
590 GFP_POPULATE(ecParams, curve); |
|
591 |
|
592 PORT_Memset(digestData, 0xa5, sizeof(digestData)); |
|
593 digest.data = digestData; |
|
594 digest.len = sizeof(digestData); |
|
595 sig.data = sigData; |
|
596 sig.len = sizeof(sigData); |
|
597 |
|
598 rv = EC_NewKey(&ecParams, &ecPriv); |
|
599 if (rv != SECSuccess) { |
|
600 return SECFailure; |
|
601 } |
|
602 ecPub.ecParams = ecParams; |
|
603 ecPub.publicValue = ecPriv->publicValue; |
|
604 |
|
605 M_TimeOperation(genericThread, (op_func) ECDH_DeriveWrap, "ECDH_Derive", |
|
606 ecPriv, &ecPub, NULL, iterations, numThreads, 0, 0, 0, &deriveRate); |
|
607 if (rv != SECSuccess) goto cleanup; |
|
608 M_TimeOperation(genericThread, (op_func) ECDSA_SignDigest, "ECDSA_Sign", |
|
609 ecPriv, &sig, &digest, iterations, numThreads, 0, 0, 1, &signRate); |
|
610 if (rv != SECSuccess) goto cleanup; |
|
611 printf(" ECDHE max rate = %.2f\n", (deriveRate+signRate)/4.0); |
|
612 rv = ECDSA_SignDigest(ecPriv, &sig, &digest); |
|
613 if (rv != SECSuccess) goto cleanup; |
|
614 M_TimeOperation(genericThread, (op_func) ECDSA_VerifyDigest, "ECDSA_Verify", |
|
615 &ecPub, &sig, &digest, iterations, numThreads, 0, 0, 0, NULL); |
|
616 if (rv != SECSuccess) goto cleanup; |
|
617 |
|
618 cleanup: |
|
619 return rv; |
|
620 } |
|
621 |
|
622 /* Prints help information. */ |
|
623 void |
|
624 printUsage(char *prog) |
|
625 { |
|
626 printf("Usage: %s [-i iterations] [-t threads ] [-ans] [-fp] [-A]\n",prog); |
|
627 } |
|
628 |
|
629 /* Performs tests of elliptic curve cryptography over prime fields If |
|
630 * tests fail, then it prints an error message, aborts, and returns an |
|
631 * error code. Otherwise, returns 0. */ |
|
632 int |
|
633 main(int argv, char **argc) |
|
634 { |
|
635 int ansi = 0; |
|
636 int nist = 0; |
|
637 int secp = 0; |
|
638 int usefreebl = 0; |
|
639 int usepkcs11 = 0; |
|
640 int i; |
|
641 SECStatus rv = SECSuccess; |
|
642 int iterations = 100; |
|
643 int numThreads = 1; |
|
644 |
|
645 /* read command-line arguments */ |
|
646 for (i = 1; i < argv; i++) { |
|
647 if (strcasecmp(argc[i], "-i") == 0) { |
|
648 i++; |
|
649 iterations = atoi(argc[i]); |
|
650 } else if (strcasecmp(argc[i], "-t") == 0) { |
|
651 i++; |
|
652 numThreads = atoi(argc[i]); |
|
653 } else if (strcasecmp(argc[i], "-A") == 0) { |
|
654 ansi = nist = secp = 1; |
|
655 usepkcs11 = usefreebl = 1; |
|
656 } else if (strcasecmp(argc[i], "-a") == 0) { |
|
657 ansi = 1; |
|
658 } else if (strcasecmp(argc[i], "-n") == 0) { |
|
659 nist = 1; |
|
660 } else if (strcasecmp(argc[i], "-s") == 0) { |
|
661 secp = 1; |
|
662 } else if (strcasecmp(argc[i], "-p") == 0) { |
|
663 usepkcs11 = 1; |
|
664 } else if (strcasecmp(argc[i], "-f") == 0) { |
|
665 usefreebl = 1; |
|
666 } else { |
|
667 printUsage(argc[0]); |
|
668 return 0; |
|
669 } |
|
670 } |
|
671 |
|
672 if ((ansi | nist | secp) == 0) { |
|
673 nist = 1; |
|
674 } |
|
675 if ((usepkcs11|usefreebl) == 0) { |
|
676 usefreebl = 1; |
|
677 } |
|
678 |
|
679 rv = NSS_NoDB_Init(NULL); |
|
680 if (rv != SECSuccess) { |
|
681 SECU_PrintError("Error:", "NSS_NoDB_Init"); |
|
682 goto cleanup; |
|
683 } |
|
684 |
|
685 /* specific arithmetic tests */ |
|
686 if (nist) { |
|
687 ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1); |
|
688 ECTEST_NAMED_GFP("NIST-P192", ECCurve_NIST_P192); |
|
689 ECTEST_NAMED_GFP("NIST-P224", ECCurve_NIST_P224); |
|
690 ECTEST_NAMED_GFP("NIST-P256", ECCurve_NIST_P256); |
|
691 ECTEST_NAMED_GFP("NIST-P384", ECCurve_NIST_P384); |
|
692 ECTEST_NAMED_GFP("NIST-P521", ECCurve_NIST_P521); |
|
693 } |
|
694 if (ansi) { |
|
695 ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v1", ECCurve_X9_62_PRIME_192V1); |
|
696 ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v2", ECCurve_X9_62_PRIME_192V2); |
|
697 ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v3", ECCurve_X9_62_PRIME_192V3); |
|
698 ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v1", ECCurve_X9_62_PRIME_239V1); |
|
699 ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v2", ECCurve_X9_62_PRIME_239V2); |
|
700 ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v3", ECCurve_X9_62_PRIME_239V3); |
|
701 ECTEST_NAMED_GFP("ANSI X9.62 PRIME256v1", ECCurve_X9_62_PRIME_256V1); |
|
702 } |
|
703 if (secp) { |
|
704 ECTEST_NAMED_GFP("SECP-112R1", ECCurve_SECG_PRIME_112R1); |
|
705 ECTEST_NAMED_GFP("SECP-112R2", ECCurve_SECG_PRIME_112R2); |
|
706 ECTEST_NAMED_GFP("SECP-128R1", ECCurve_SECG_PRIME_128R1); |
|
707 ECTEST_NAMED_GFP("SECP-128R2", ECCurve_SECG_PRIME_128R2); |
|
708 ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1); |
|
709 ECTEST_NAMED_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1); |
|
710 ECTEST_NAMED_GFP("SECP-160R2", ECCurve_SECG_PRIME_160R2); |
|
711 ECTEST_NAMED_GFP("SECP-192K1", ECCurve_SECG_PRIME_192K1); |
|
712 ECTEST_NAMED_GFP("SECP-192R1", ECCurve_SECG_PRIME_192R1); |
|
713 ECTEST_NAMED_GFP("SECP-224K1", ECCurve_SECG_PRIME_224K1); |
|
714 ECTEST_NAMED_GFP("SECP-224R1", ECCurve_SECG_PRIME_224R1); |
|
715 ECTEST_NAMED_GFP("SECP-256K1", ECCurve_SECG_PRIME_256K1); |
|
716 ECTEST_NAMED_GFP("SECP-256R1", ECCurve_SECG_PRIME_256R1); |
|
717 ECTEST_NAMED_GFP("SECP-384R1", ECCurve_SECG_PRIME_384R1); |
|
718 ECTEST_NAMED_GFP("SECP-521R1", ECCurve_SECG_PRIME_521R1); |
|
719 } |
|
720 |
|
721 cleanup: |
|
722 if (rv != SECSuccess) { |
|
723 printf("Error: exiting with error value\n"); |
|
724 } |
|
725 return rv; |
|
726 } |