security/nss/cmd/ecperf/ecperf.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial