1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/ecperf/ecperf.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,726 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "blapi.h" 1.9 +#include "ec.h" 1.10 +#include "ecl-curve.h" 1.11 +#include "nss.h" 1.12 +#include "secutil.h" 1.13 +#include "pkcs11.h" 1.14 +#include <nspr.h> 1.15 +#include <stdio.h> 1.16 +#include <strings.h> 1.17 +#include <assert.h> 1.18 + 1.19 +#include <time.h> 1.20 +#include <sys/time.h> 1.21 +#include <sys/resource.h> 1.22 + 1.23 +#define __PASTE(x,y) x##y 1.24 + 1.25 +/* 1.26 + * Get the NSS specific PKCS #11 function names. 1.27 + */ 1.28 +#undef CK_PKCS11_FUNCTION_INFO 1.29 +#undef CK_NEED_ARG_LIST 1.30 + 1.31 +#define CK_EXTERN extern 1.32 +#define CK_PKCS11_FUNCTION_INFO(func) \ 1.33 + CK_RV __PASTE(NS,func) 1.34 +#define CK_NEED_ARG_LIST 1 1.35 + 1.36 +#include "pkcs11f.h" 1.37 + 1.38 + 1.39 + 1.40 +/* mapping between ECCurveName enum and pointers to ECCurveParams */ 1.41 +static SECOidTag ecCurve_oid_map[] = { 1.42 + SEC_OID_UNKNOWN, /* ECCurve_noName */ 1.43 + SEC_OID_ANSIX962_EC_PRIME192V1, /* ECCurve_NIST_P192 */ 1.44 + SEC_OID_SECG_EC_SECP224R1, /* ECCurve_NIST_P224 */ 1.45 + SEC_OID_ANSIX962_EC_PRIME256V1, /* ECCurve_NIST_P256 */ 1.46 + SEC_OID_SECG_EC_SECP384R1, /* ECCurve_NIST_P384 */ 1.47 + SEC_OID_SECG_EC_SECP521R1, /* ECCurve_NIST_P521 */ 1.48 + SEC_OID_SECG_EC_SECT163K1, /* ECCurve_NIST_K163 */ 1.49 + SEC_OID_SECG_EC_SECT163R1, /* ECCurve_NIST_B163 */ 1.50 + SEC_OID_SECG_EC_SECT233K1, /* ECCurve_NIST_K233 */ 1.51 + SEC_OID_SECG_EC_SECT233R1, /* ECCurve_NIST_B233 */ 1.52 + SEC_OID_SECG_EC_SECT283K1, /* ECCurve_NIST_K283 */ 1.53 + SEC_OID_SECG_EC_SECT283R1, /* ECCurve_NIST_B283 */ 1.54 + SEC_OID_SECG_EC_SECT409K1, /* ECCurve_NIST_K409 */ 1.55 + SEC_OID_SECG_EC_SECT409R1, /* ECCurve_NIST_B409 */ 1.56 + SEC_OID_SECG_EC_SECT571K1, /* ECCurve_NIST_K571 */ 1.57 + SEC_OID_SECG_EC_SECT571R1, /* ECCurve_NIST_B571 */ 1.58 + SEC_OID_ANSIX962_EC_PRIME192V2, 1.59 + SEC_OID_ANSIX962_EC_PRIME192V3, 1.60 + SEC_OID_ANSIX962_EC_PRIME239V1, 1.61 + SEC_OID_ANSIX962_EC_PRIME239V2, 1.62 + SEC_OID_ANSIX962_EC_PRIME239V3, 1.63 + SEC_OID_ANSIX962_EC_C2PNB163V1, 1.64 + SEC_OID_ANSIX962_EC_C2PNB163V2, 1.65 + SEC_OID_ANSIX962_EC_C2PNB163V3, 1.66 + SEC_OID_ANSIX962_EC_C2PNB176V1, 1.67 + SEC_OID_ANSIX962_EC_C2TNB191V1, 1.68 + SEC_OID_ANSIX962_EC_C2TNB191V2, 1.69 + SEC_OID_ANSIX962_EC_C2TNB191V3, 1.70 + SEC_OID_ANSIX962_EC_C2PNB208W1, 1.71 + SEC_OID_ANSIX962_EC_C2TNB239V1, 1.72 + SEC_OID_ANSIX962_EC_C2TNB239V2, 1.73 + SEC_OID_ANSIX962_EC_C2TNB239V3, 1.74 + SEC_OID_ANSIX962_EC_C2PNB272W1, 1.75 + SEC_OID_ANSIX962_EC_C2PNB304W1, 1.76 + SEC_OID_ANSIX962_EC_C2TNB359V1, 1.77 + SEC_OID_ANSIX962_EC_C2PNB368W1, 1.78 + SEC_OID_ANSIX962_EC_C2TNB431R1, 1.79 + SEC_OID_SECG_EC_SECP112R1, 1.80 + SEC_OID_SECG_EC_SECP112R2, 1.81 + SEC_OID_SECG_EC_SECP128R1, 1.82 + SEC_OID_SECG_EC_SECP128R2, 1.83 + SEC_OID_SECG_EC_SECP160K1, 1.84 + SEC_OID_SECG_EC_SECP160R1, 1.85 + SEC_OID_SECG_EC_SECP160R2, 1.86 + SEC_OID_SECG_EC_SECP192K1, 1.87 + SEC_OID_SECG_EC_SECP224K1, 1.88 + SEC_OID_SECG_EC_SECP256K1, 1.89 + SEC_OID_SECG_EC_SECT113R1, 1.90 + SEC_OID_SECG_EC_SECT113R2, 1.91 + SEC_OID_SECG_EC_SECT131R1, 1.92 + SEC_OID_SECG_EC_SECT131R2, 1.93 + SEC_OID_SECG_EC_SECT163R1, 1.94 + SEC_OID_SECG_EC_SECT193R1, 1.95 + SEC_OID_SECG_EC_SECT193R2, 1.96 + SEC_OID_SECG_EC_SECT239K1, 1.97 + SEC_OID_UNKNOWN /* ECCurve_pastLastCurve */ 1.98 +}; 1.99 + 1.100 +typedef SECStatus (*op_func) (void *, void *, void *); 1.101 +typedef SECStatus (*pk11_op_func) (CK_SESSION_HANDLE, void *, void *, void *); 1.102 + 1.103 +typedef struct ThreadDataStr { 1.104 + op_func op; 1.105 + void *p1; 1.106 + void *p2; 1.107 + void *p3; 1.108 + int iters; 1.109 + PRLock *lock; 1.110 + int count; 1.111 + SECStatus status; 1.112 + int isSign; 1.113 +} ThreadData; 1.114 + 1.115 +void PKCS11Thread(void *data) 1.116 +{ 1.117 + ThreadData *threadData = (ThreadData *)data; 1.118 + pk11_op_func op = (pk11_op_func) threadData->op; 1.119 + int iters = threadData->iters; 1.120 + unsigned char sigData [256]; 1.121 + SECItem sig; 1.122 + CK_SESSION_HANDLE session; 1.123 + CK_RV crv; 1.124 + 1.125 + threadData->status = SECSuccess; 1.126 + threadData->count = 0; 1.127 + 1.128 + /* get our thread's session */ 1.129 + PR_Lock(threadData->lock); 1.130 + crv = NSC_OpenSession(1, CKF_SERIAL_SESSION, NULL, 0, &session); 1.131 + PR_Unlock(threadData->lock); 1.132 + 1.133 + if (threadData->isSign) { 1.134 + sig.data = sigData; 1.135 + sig.len = sizeof(sigData); 1.136 + threadData->p2 = (void *)&sig; 1.137 + } 1.138 + 1.139 + while (iters --) { 1.140 + threadData->status = (*op)(session, threadData->p1, 1.141 + threadData->p2, threadData->p3); 1.142 + if (threadData->status != SECSuccess) { 1.143 + break; 1.144 + } 1.145 + threadData->count++; 1.146 + } 1.147 + return; 1.148 +} 1.149 + 1.150 +void genericThread(void *data) 1.151 +{ 1.152 + ThreadData *threadData = (ThreadData *)data; 1.153 + int iters = threadData->iters; 1.154 + unsigned char sigData [256]; 1.155 + SECItem sig; 1.156 + 1.157 + threadData->status = SECSuccess; 1.158 + threadData->count = 0; 1.159 + 1.160 + if (threadData->isSign) { 1.161 + sig.data = sigData; 1.162 + sig.len = sizeof(sigData); 1.163 + threadData->p2 = (void *)&sig; 1.164 + } 1.165 + 1.166 + while (iters --) { 1.167 + threadData->status = (*threadData->op)(threadData->p1, 1.168 + threadData->p2, threadData->p3); 1.169 + if (threadData->status != SECSuccess) { 1.170 + break; 1.171 + } 1.172 + threadData->count++; 1.173 + } 1.174 + return; 1.175 +} 1.176 + 1.177 + 1.178 +/* Time iter repetitions of operation op. */ 1.179 +SECStatus 1.180 +M_TimeOperation(void (*threadFunc)(void *), 1.181 + op_func opfunc, char *op, void *param1, void *param2, 1.182 + void *param3, int iters, int numThreads, PRLock *lock, 1.183 + CK_SESSION_HANDLE session, int isSign, double *rate) 1.184 +{ 1.185 + double dUserTime; 1.186 + int i, total; 1.187 + PRIntervalTime startTime, totalTime; 1.188 + PRThread **threadIDs; 1.189 + ThreadData *threadData; 1.190 + pk11_op_func pk11_op = (pk11_op_func) opfunc; 1.191 + SECStatus rv; 1.192 + 1.193 + /* verify operation works before testing performance */ 1.194 + if (session) { 1.195 + rv = (*pk11_op)(session, param1, param2, param3); 1.196 + } else { 1.197 + rv = (*opfunc)(param1, param2, param3); 1.198 + } 1.199 + if (rv != SECSuccess) { 1.200 + SECU_PrintError("Error:", op); 1.201 + return rv; 1.202 + } 1.203 + 1.204 + /* get Data structures */ 1.205 + threadIDs = (PRThread **)PORT_Alloc(numThreads*sizeof(PRThread *)); 1.206 + threadData = (ThreadData *)PORT_Alloc(numThreads*sizeof(ThreadData)); 1.207 + 1.208 + startTime = PR_Now(); 1.209 + if (numThreads == 1) { 1.210 + for (i=0; i < iters; i++) { 1.211 + if (session) { 1.212 + rv = (*pk11_op)(session, param1, param2, param3); 1.213 + } else { 1.214 + rv = (*opfunc)(param1, param2, param3); 1.215 + } 1.216 + } 1.217 + total = iters; 1.218 + } else { 1.219 + for (i = 0; i < numThreads; i++) { 1.220 + threadData[i].op = opfunc; 1.221 + threadData[i].p1 = (void *)param1; 1.222 + threadData[i].p2 = (void *)param2; 1.223 + threadData[i].p3 = (void *)param3; 1.224 + threadData[i].iters = iters; 1.225 + threadData[i].lock = lock; 1.226 + threadData[i].isSign = isSign; 1.227 + threadIDs[i] = PR_CreateThread(PR_USER_THREAD, threadFunc, 1.228 + (void *)&threadData[i], PR_PRIORITY_NORMAL, 1.229 + PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); 1.230 + } 1.231 + 1.232 + total = 0; 1.233 + for (i = 0; i < numThreads; i++) { 1.234 + PR_JoinThread(threadIDs[i]); 1.235 + /* check the status */ 1.236 + total += threadData[i].count; 1.237 + } 1.238 + 1.239 + PORT_Free(threadIDs); 1.240 + PORT_Free(threadData); 1.241 + } 1.242 + 1.243 + totalTime = PR_Now()- startTime; 1.244 + /* SecondsToInterval seems to be broken here ... */ 1.245 + dUserTime = (double)totalTime/(double)1000000; 1.246 + if (dUserTime) { 1.247 + printf(" %-15s count:%4d sec: %3.2f op/sec: %6.2f\n", 1.248 + op, total, dUserTime, (double)total/dUserTime); 1.249 + if (rate) { 1.250 + *rate = ((double)total)/dUserTime; 1.251 + } 1.252 + } 1.253 + return SECSuccess; 1.254 +} 1.255 + 1.256 +#define GFP_POPULATE(params,name_v) \ 1.257 + params.name = name_v; \ 1.258 + if ((params.name < ECCurve_noName) || \ 1.259 + (params.name > ECCurve_pastLastCurve)) goto cleanup; \ 1.260 + params.type = ec_params_named; \ 1.261 + params.curveOID.data = NULL; \ 1.262 + params.curveOID.len = 0; \ 1.263 + params.curve.seed.data = NULL; \ 1.264 + params.curve.seed.len = 0; \ 1.265 + params.DEREncoding.data = NULL; \ 1.266 + params.DEREncoding.len = 0; \ 1.267 + params.arena = NULL; \ 1.268 + params.fieldID.size = ecCurve_map[name_v]->size; \ 1.269 + params.fieldID.type = ec_field_GFp; \ 1.270 + hexString2SECItem(params.arena, ¶ms.fieldID.u.prime, \ 1.271 + ecCurve_map[name_v]->irr); \ 1.272 + hexString2SECItem(params.arena, ¶ms.curve.a, \ 1.273 + ecCurve_map[name_v]->curvea); \ 1.274 + hexString2SECItem(params.arena, ¶ms.curve.b, \ 1.275 + ecCurve_map[name_v]->curveb); \ 1.276 + genenc[0] = '0'; \ 1.277 + genenc[1] = '4'; \ 1.278 + genenc[2] = '\0'; \ 1.279 + strcat(genenc, ecCurve_map[name_v]->genx); \ 1.280 + strcat(genenc, ecCurve_map[name_v]->geny); \ 1.281 + hexString2SECItem(params.arena, ¶ms.base, \ 1.282 + genenc); \ 1.283 + hexString2SECItem(params.arena, ¶ms.order, \ 1.284 + ecCurve_map[name_v]->order); \ 1.285 + params.cofactor = ecCurve_map[name_v]->cofactor; 1.286 + 1.287 + 1.288 +/* Test curve using specific field arithmetic. */ 1.289 +#define ECTEST_NAMED_GFP(name_c, name_v) \ 1.290 + if (usefreebl) { \ 1.291 + printf("Testing %s using freebl implementation...\n", name_c); \ 1.292 + rv = ectest_curve_freebl(name_v, iterations, numThreads); \ 1.293 + if (rv != SECSuccess) goto cleanup; \ 1.294 + printf("... okay.\n"); \ 1.295 + } \ 1.296 + if (usepkcs11) { \ 1.297 + printf("Testing %s using pkcs11 implementation...\n", name_c); \ 1.298 + rv = ectest_curve_pkcs11(name_v, iterations, numThreads); \ 1.299 + if (rv != SECSuccess) goto cleanup; \ 1.300 + printf("... okay.\n"); \ 1.301 + } 1.302 + 1.303 +/* 1.304 + * Initializes a SECItem from a hexadecimal string 1.305 + * 1.306 + * Warning: This function ignores leading 00's, so any leading 00's 1.307 + * in the hexadecimal string must be optional. 1.308 + */ 1.309 +static SECItem * 1.310 +hexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str) 1.311 +{ 1.312 + int i = 0; 1.313 + int byteval = 0; 1.314 + int tmp = PORT_Strlen(str); 1.315 + 1.316 + if ((tmp % 2) != 0) return NULL; 1.317 + 1.318 + /* skip leading 00's unless the hex string is "00" */ 1.319 + while ((tmp > 2) && (str[0] == '0') && (str[1] == '0')) { 1.320 + str += 2; 1.321 + tmp -= 2; 1.322 + } 1.323 + 1.324 + item->data = (unsigned char *) PORT_Alloc( tmp/2); 1.325 + if (item->data == NULL) return NULL; 1.326 + item->len = tmp/2; 1.327 + 1.328 + while (str[i]) { 1.329 + if ((str[i] >= '0') && (str[i] <= '9')) 1.330 + tmp = str[i] - '0'; 1.331 + else if ((str[i] >= 'a') && (str[i] <= 'f')) 1.332 + tmp = str[i] - 'a' + 10; 1.333 + else if ((str[i] >= 'A') && (str[i] <= 'F')) 1.334 + tmp = str[i] - 'A' + 10; 1.335 + else 1.336 + return NULL; 1.337 + 1.338 + byteval = byteval * 16 + tmp; 1.339 + if ((i % 2) != 0) { 1.340 + item->data[i/2] = byteval; 1.341 + byteval = 0; 1.342 + } 1.343 + i++; 1.344 + } 1.345 + 1.346 + return item; 1.347 +} 1.348 + 1.349 +#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \ 1.350 + (x)->pValue=(v); (x)->ulValueLen = (l); 1.351 + 1.352 + 1.353 +SECStatus 1.354 +PKCS11_Derive(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey, 1.355 + CK_MECHANISM *pMech , int *dummy) 1.356 +{ 1.357 + CK_RV crv; 1.358 + CK_OBJECT_HANDLE newKey; 1.359 + CK_BBOOL cktrue = CK_TRUE; 1.360 + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; 1.361 + CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; 1.362 + CK_ATTRIBUTE keyTemplate[3]; 1.363 + CK_ATTRIBUTE *attrs = keyTemplate; 1.364 + 1.365 + PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); 1.366 + attrs++; 1.367 + PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); 1.368 + attrs++; 1.369 + PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, 1); attrs++; 1.370 + 1.371 + 1.372 + crv = NSC_DeriveKey(session, pMech, *hKey, keyTemplate, 3, &newKey); 1.373 + if (crv != CKR_OK) { 1.374 + printf("Derive Failed CK_RV=0x%x\n", (int)crv); 1.375 + return SECFailure; 1.376 + } 1.377 + return SECSuccess; 1.378 +} 1.379 + 1.380 +SECStatus 1.381 +PKCS11_Sign(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey, 1.382 + SECItem *sig, SECItem *digest) 1.383 +{ 1.384 + CK_RV crv; 1.385 + CK_MECHANISM mech; 1.386 + 1.387 + mech.mechanism = CKM_ECDSA; 1.388 + mech.pParameter = NULL; 1.389 + mech.ulParameterLen = 0; 1.390 + 1.391 + crv = NSC_SignInit(session, &mech, *hKey); 1.392 + if (crv != CKR_OK) { 1.393 + printf("Sign Failed CK_RV=0x%x\n", (int)crv); 1.394 + return SECFailure; 1.395 + } 1.396 + crv = NSC_Sign(session, digest->data, digest->len, sig->data, 1.397 + (CK_ULONG_PTR)&sig->len); 1.398 + if (crv != CKR_OK) { 1.399 + printf("Sign Failed CK_RV=0x%x\n", (int)crv); 1.400 + return SECFailure; 1.401 + } 1.402 + return SECSuccess; 1.403 +} 1.404 + 1.405 +SECStatus 1.406 +PKCS11_Verify(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey, 1.407 + SECItem *sig, SECItem *digest) 1.408 +{ 1.409 + CK_RV crv; 1.410 + CK_MECHANISM mech; 1.411 + 1.412 + mech.mechanism = CKM_ECDSA; 1.413 + mech.pParameter = NULL; 1.414 + mech.ulParameterLen = 0; 1.415 + 1.416 + crv = NSC_VerifyInit(session, &mech, *hKey); 1.417 + if (crv != CKR_OK) { 1.418 + printf("Verify Failed CK_RV=0x%x\n", (int)crv); 1.419 + return SECFailure; 1.420 + } 1.421 + crv = NSC_Verify(session, digest->data, digest->len, sig->data, sig->len); 1.422 + if (crv != CKR_OK) { 1.423 + printf("Verify Failed CK_RV=0x%x\n", (int)crv); 1.424 + return SECFailure; 1.425 + } 1.426 + return SECSuccess; 1.427 +} 1.428 + 1.429 +static SECStatus 1.430 +ecName2params(ECCurveName curve, SECKEYECParams * params) 1.431 +{ 1.432 + SECOidData *oidData = NULL; 1.433 + 1.434 + if ((curve < ECCurve_noName) || (curve > ECCurve_pastLastCurve) || 1.435 + ((oidData = SECOID_FindOIDByTag(ecCurve_oid_map[curve])) == NULL)) { 1.436 + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); 1.437 + return SECFailure; 1.438 + } 1.439 + 1.440 + SECITEM_AllocItem(NULL, params, (2 + oidData->oid.len)); 1.441 + /* 1.442 + * params->data needs to contain the ASN encoding of an object ID (OID) 1.443 + * representing the named curve. The actual OID is in 1.444 + * oidData->oid.data so we simply prepend 0x06 and OID length 1.445 + */ 1.446 + params->data[0] = SEC_ASN1_OBJECT_ID; 1.447 + params->data[1] = oidData->oid.len; 1.448 + memcpy(params->data + 2, oidData->oid.data, oidData->oid.len); 1.449 + 1.450 + return SECSuccess; 1.451 +} 1.452 + 1.453 + 1.454 + 1.455 +/* Performs basic tests of elliptic curve cryptography over prime fields. 1.456 + * If tests fail, then it prints an error message, aborts, and returns an 1.457 + * error code. Otherwise, returns 0. */ 1.458 +SECStatus 1.459 +ectest_curve_pkcs11(ECCurveName curve, int iterations, int numThreads) 1.460 +{ 1.461 + CK_OBJECT_HANDLE ecPriv; 1.462 + CK_OBJECT_HANDLE ecPub; 1.463 + CK_SESSION_HANDLE session; 1.464 + SECItem sig; 1.465 + SECItem digest; 1.466 + SECKEYECParams ecParams; 1.467 + CK_MECHANISM mech; 1.468 + CK_ECDH1_DERIVE_PARAMS ecdh_params; 1.469 + unsigned char sigData [256]; 1.470 + unsigned char digestData[20]; 1.471 + unsigned char pubKeyData[256]; 1.472 + PRLock *lock = NULL; 1.473 + double signRate, deriveRate; 1.474 + CK_ATTRIBUTE template; 1.475 + SECStatus rv; 1.476 + CK_RV crv; 1.477 + 1.478 + ecParams.data = NULL; 1.479 + ecParams.len = 0; 1.480 + rv = ecName2params(curve, &ecParams); 1.481 + if (rv != SECSuccess) { 1.482 + goto cleanup; 1.483 + } 1.484 + 1.485 + crv = NSC_OpenSession(1, CKF_SERIAL_SESSION, NULL, 0, &session); 1.486 + if (crv != CKR_OK) { 1.487 + printf("OpenSession Failed CK_RV=0x%x\n", (int)crv); 1.488 + return SECFailure; 1.489 + } 1.490 + 1.491 + PORT_Memset(digestData, 0xa5, sizeof(digestData)); 1.492 + digest.data = digestData; 1.493 + digest.len = sizeof(digestData); 1.494 + sig.data = sigData; 1.495 + sig.len = sizeof(sigData); 1.496 + 1.497 + template.type = CKA_EC_PARAMS; 1.498 + template.pValue = ecParams.data; 1.499 + template.ulValueLen = ecParams.len; 1.500 + mech.mechanism = CKM_EC_KEY_PAIR_GEN; 1.501 + mech.pParameter = NULL; 1.502 + mech.ulParameterLen = 0; 1.503 + crv = NSC_GenerateKeyPair(session, &mech, 1.504 + &template, 1, NULL, 0, &ecPub, &ecPriv); 1.505 + if (crv != CKR_OK) { 1.506 + printf("GenerateKeyPair Failed CK_RV=0x%x\n", (int)crv); 1.507 + return SECFailure; 1.508 + } 1.509 + 1.510 + template.type = CKA_EC_POINT; 1.511 + template.pValue = pubKeyData; 1.512 + template.ulValueLen = sizeof(pubKeyData); 1.513 + crv = NSC_GetAttributeValue(session, ecPub, &template, 1); 1.514 + if (crv != CKR_OK) { 1.515 + printf("GenerateKeyPair Failed CK_RV=0x%x\n", (int)crv); 1.516 + return SECFailure; 1.517 + } 1.518 + 1.519 + ecdh_params.kdf = CKD_NULL; 1.520 + ecdh_params.ulSharedDataLen = 0; 1.521 + ecdh_params.pSharedData = NULL; 1.522 + ecdh_params.ulPublicDataLen = template.ulValueLen; 1.523 + ecdh_params.pPublicData = template.pValue; 1.524 + 1.525 + mech.mechanism = CKM_ECDH1_DERIVE; 1.526 + mech.pParameter = (void *)&ecdh_params; 1.527 + mech.ulParameterLen = sizeof(ecdh_params); 1.528 + 1.529 + lock = PR_NewLock(); 1.530 + 1.531 + rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Derive, "ECDH_Derive", 1.532 + &ecPriv, &mech, NULL, iterations, numThreads, 1.533 + lock, session, 0, &deriveRate); 1.534 + if (rv != SECSuccess) goto cleanup; 1.535 + rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Sign, "ECDSA_Sign", 1.536 + (void *)&ecPriv, &sig, &digest, iterations, numThreads, 1.537 + lock, session, 1, &signRate); 1.538 + if (rv != SECSuccess) goto cleanup; 1.539 + printf(" ECDHE max rate = %.2f\n", (deriveRate+signRate)/4.0); 1.540 + /* get a signature */ 1.541 + rv = PKCS11_Sign(session, &ecPriv, &sig, &digest); 1.542 + if (rv != SECSuccess) goto cleanup; 1.543 + rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Verify, "ECDSA_Verify", 1.544 + (void *)&ecPub, &sig, &digest, iterations, numThreads, 1.545 + lock, session, 0, NULL); 1.546 + if (rv != SECSuccess) goto cleanup; 1.547 + 1.548 +cleanup: 1.549 + if (lock) { 1.550 + PR_DestroyLock(lock); 1.551 + } 1.552 + return rv; 1.553 +} 1.554 + 1.555 +SECStatus 1.556 +ECDH_DeriveWrap(ECPrivateKey *priv, ECPublicKey *pub, int *dummy) 1.557 +{ 1.558 + SECItem secret; 1.559 + unsigned char secretData[256]; 1.560 + SECStatus rv; 1.561 + 1.562 + secret.data = secretData; 1.563 + secret.len = sizeof(secretData); 1.564 + 1.565 + rv = ECDH_Derive(&pub->publicValue, &pub->ecParams, 1.566 + &priv->privateValue, 0, &secret); 1.567 +#ifdef notdef 1.568 + if (rv == SECSuccess) { 1.569 + PORT_Free(secret.data); 1.570 + } 1.571 +#endif 1.572 + return rv; 1.573 +} 1.574 + 1.575 +/* Performs basic tests of elliptic curve cryptography over prime fields. 1.576 + * If tests fail, then it prints an error message, aborts, and returns an 1.577 + * error code. Otherwise, returns 0. */ 1.578 +SECStatus 1.579 +ectest_curve_freebl(ECCurveName curve, int iterations, int numThreads) 1.580 +{ 1.581 + ECParams ecParams; 1.582 + ECPrivateKey *ecPriv = NULL; 1.583 + ECPublicKey ecPub; 1.584 + SECItem sig; 1.585 + SECItem digest; 1.586 + unsigned char sigData [256]; 1.587 + unsigned char digestData[20]; 1.588 + double signRate, deriveRate; 1.589 + char genenc[3 + 2 * 2 * MAX_ECKEY_LEN]; 1.590 + SECStatus rv; 1.591 + 1.592 + 1.593 + GFP_POPULATE(ecParams, curve); 1.594 + 1.595 + PORT_Memset(digestData, 0xa5, sizeof(digestData)); 1.596 + digest.data = digestData; 1.597 + digest.len = sizeof(digestData); 1.598 + sig.data = sigData; 1.599 + sig.len = sizeof(sigData); 1.600 + 1.601 + rv = EC_NewKey(&ecParams, &ecPriv); 1.602 + if (rv != SECSuccess) { 1.603 + return SECFailure; 1.604 + } 1.605 + ecPub.ecParams = ecParams; 1.606 + ecPub.publicValue = ecPriv->publicValue; 1.607 + 1.608 + M_TimeOperation(genericThread, (op_func) ECDH_DeriveWrap, "ECDH_Derive", 1.609 + ecPriv, &ecPub, NULL, iterations, numThreads, 0, 0, 0, &deriveRate); 1.610 + if (rv != SECSuccess) goto cleanup; 1.611 + M_TimeOperation(genericThread, (op_func) ECDSA_SignDigest, "ECDSA_Sign", 1.612 + ecPriv, &sig, &digest, iterations, numThreads, 0, 0, 1, &signRate); 1.613 + if (rv != SECSuccess) goto cleanup; 1.614 + printf(" ECDHE max rate = %.2f\n", (deriveRate+signRate)/4.0); 1.615 + rv = ECDSA_SignDigest(ecPriv, &sig, &digest); 1.616 + if (rv != SECSuccess) goto cleanup; 1.617 + M_TimeOperation(genericThread, (op_func) ECDSA_VerifyDigest, "ECDSA_Verify", 1.618 + &ecPub, &sig, &digest, iterations, numThreads, 0, 0, 0, NULL); 1.619 + if (rv != SECSuccess) goto cleanup; 1.620 + 1.621 +cleanup: 1.622 + return rv; 1.623 +} 1.624 + 1.625 +/* Prints help information. */ 1.626 +void 1.627 +printUsage(char *prog) 1.628 +{ 1.629 + printf("Usage: %s [-i iterations] [-t threads ] [-ans] [-fp] [-A]\n",prog); 1.630 +} 1.631 + 1.632 +/* Performs tests of elliptic curve cryptography over prime fields If 1.633 + * tests fail, then it prints an error message, aborts, and returns an 1.634 + * error code. Otherwise, returns 0. */ 1.635 +int 1.636 +main(int argv, char **argc) 1.637 +{ 1.638 + int ansi = 0; 1.639 + int nist = 0; 1.640 + int secp = 0; 1.641 + int usefreebl = 0; 1.642 + int usepkcs11 = 0; 1.643 + int i; 1.644 + SECStatus rv = SECSuccess; 1.645 + int iterations = 100; 1.646 + int numThreads = 1; 1.647 + 1.648 + /* read command-line arguments */ 1.649 + for (i = 1; i < argv; i++) { 1.650 + if (strcasecmp(argc[i], "-i") == 0) { 1.651 + i++; 1.652 + iterations = atoi(argc[i]); 1.653 + } else if (strcasecmp(argc[i], "-t") == 0) { 1.654 + i++; 1.655 + numThreads = atoi(argc[i]); 1.656 + } else if (strcasecmp(argc[i], "-A") == 0) { 1.657 + ansi = nist = secp = 1; 1.658 + usepkcs11 = usefreebl = 1; 1.659 + } else if (strcasecmp(argc[i], "-a") == 0) { 1.660 + ansi = 1; 1.661 + } else if (strcasecmp(argc[i], "-n") == 0) { 1.662 + nist = 1; 1.663 + } else if (strcasecmp(argc[i], "-s") == 0) { 1.664 + secp = 1; 1.665 + } else if (strcasecmp(argc[i], "-p") == 0) { 1.666 + usepkcs11 = 1; 1.667 + } else if (strcasecmp(argc[i], "-f") == 0) { 1.668 + usefreebl = 1; 1.669 + } else { 1.670 + printUsage(argc[0]); 1.671 + return 0; 1.672 + } 1.673 + } 1.674 + 1.675 + if ((ansi | nist | secp) == 0) { 1.676 + nist = 1; 1.677 + } 1.678 + if ((usepkcs11|usefreebl) == 0) { 1.679 + usefreebl = 1; 1.680 + } 1.681 + 1.682 + rv = NSS_NoDB_Init(NULL); 1.683 + if (rv != SECSuccess) { 1.684 + SECU_PrintError("Error:", "NSS_NoDB_Init"); 1.685 + goto cleanup; 1.686 + } 1.687 + 1.688 + /* specific arithmetic tests */ 1.689 + if (nist) { 1.690 + ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1); 1.691 + ECTEST_NAMED_GFP("NIST-P192", ECCurve_NIST_P192); 1.692 + ECTEST_NAMED_GFP("NIST-P224", ECCurve_NIST_P224); 1.693 + ECTEST_NAMED_GFP("NIST-P256", ECCurve_NIST_P256); 1.694 + ECTEST_NAMED_GFP("NIST-P384", ECCurve_NIST_P384); 1.695 + ECTEST_NAMED_GFP("NIST-P521", ECCurve_NIST_P521); 1.696 + } 1.697 + if (ansi) { 1.698 + ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v1", ECCurve_X9_62_PRIME_192V1); 1.699 + ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v2", ECCurve_X9_62_PRIME_192V2); 1.700 + ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v3", ECCurve_X9_62_PRIME_192V3); 1.701 + ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v1", ECCurve_X9_62_PRIME_239V1); 1.702 + ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v2", ECCurve_X9_62_PRIME_239V2); 1.703 + ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v3", ECCurve_X9_62_PRIME_239V3); 1.704 + ECTEST_NAMED_GFP("ANSI X9.62 PRIME256v1", ECCurve_X9_62_PRIME_256V1); 1.705 + } 1.706 + if (secp) { 1.707 + ECTEST_NAMED_GFP("SECP-112R1", ECCurve_SECG_PRIME_112R1); 1.708 + ECTEST_NAMED_GFP("SECP-112R2", ECCurve_SECG_PRIME_112R2); 1.709 + ECTEST_NAMED_GFP("SECP-128R1", ECCurve_SECG_PRIME_128R1); 1.710 + ECTEST_NAMED_GFP("SECP-128R2", ECCurve_SECG_PRIME_128R2); 1.711 + ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1); 1.712 + ECTEST_NAMED_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1); 1.713 + ECTEST_NAMED_GFP("SECP-160R2", ECCurve_SECG_PRIME_160R2); 1.714 + ECTEST_NAMED_GFP("SECP-192K1", ECCurve_SECG_PRIME_192K1); 1.715 + ECTEST_NAMED_GFP("SECP-192R1", ECCurve_SECG_PRIME_192R1); 1.716 + ECTEST_NAMED_GFP("SECP-224K1", ECCurve_SECG_PRIME_224K1); 1.717 + ECTEST_NAMED_GFP("SECP-224R1", ECCurve_SECG_PRIME_224R1); 1.718 + ECTEST_NAMED_GFP("SECP-256K1", ECCurve_SECG_PRIME_256K1); 1.719 + ECTEST_NAMED_GFP("SECP-256R1", ECCurve_SECG_PRIME_256R1); 1.720 + ECTEST_NAMED_GFP("SECP-384R1", ECCurve_SECG_PRIME_384R1); 1.721 + ECTEST_NAMED_GFP("SECP-521R1", ECCurve_SECG_PRIME_521R1); 1.722 + } 1.723 + 1.724 + cleanup: 1.725 + if (rv != SECSuccess) { 1.726 + printf("Error: exiting with error value\n"); 1.727 + } 1.728 + return rv; 1.729 +}