Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
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, ¶ms.fieldID.u.prime, \ |
michael@0 | 268 | ecCurve_map[name_v]->irr); \ |
michael@0 | 269 | hexString2SECItem(params.arena, ¶ms.curve.a, \ |
michael@0 | 270 | ecCurve_map[name_v]->curvea); \ |
michael@0 | 271 | hexString2SECItem(params.arena, ¶ms.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, ¶ms.base, \ |
michael@0 | 279 | genenc); \ |
michael@0 | 280 | hexString2SECItem(params.arena, ¶ms.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 | } |