michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "blapi.h" michael@0: #include "ec.h" michael@0: #include "ecl-curve.h" michael@0: #include "nss.h" michael@0: #include "secutil.h" michael@0: #include "pkcs11.h" michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #define __PASTE(x,y) x##y michael@0: michael@0: /* michael@0: * Get the NSS specific PKCS #11 function names. michael@0: */ michael@0: #undef CK_PKCS11_FUNCTION_INFO michael@0: #undef CK_NEED_ARG_LIST michael@0: michael@0: #define CK_EXTERN extern michael@0: #define CK_PKCS11_FUNCTION_INFO(func) \ michael@0: CK_RV __PASTE(NS,func) michael@0: #define CK_NEED_ARG_LIST 1 michael@0: michael@0: #include "pkcs11f.h" michael@0: michael@0: michael@0: michael@0: /* mapping between ECCurveName enum and pointers to ECCurveParams */ michael@0: static SECOidTag ecCurve_oid_map[] = { michael@0: SEC_OID_UNKNOWN, /* ECCurve_noName */ michael@0: SEC_OID_ANSIX962_EC_PRIME192V1, /* ECCurve_NIST_P192 */ michael@0: SEC_OID_SECG_EC_SECP224R1, /* ECCurve_NIST_P224 */ michael@0: SEC_OID_ANSIX962_EC_PRIME256V1, /* ECCurve_NIST_P256 */ michael@0: SEC_OID_SECG_EC_SECP384R1, /* ECCurve_NIST_P384 */ michael@0: SEC_OID_SECG_EC_SECP521R1, /* ECCurve_NIST_P521 */ michael@0: SEC_OID_SECG_EC_SECT163K1, /* ECCurve_NIST_K163 */ michael@0: SEC_OID_SECG_EC_SECT163R1, /* ECCurve_NIST_B163 */ michael@0: SEC_OID_SECG_EC_SECT233K1, /* ECCurve_NIST_K233 */ michael@0: SEC_OID_SECG_EC_SECT233R1, /* ECCurve_NIST_B233 */ michael@0: SEC_OID_SECG_EC_SECT283K1, /* ECCurve_NIST_K283 */ michael@0: SEC_OID_SECG_EC_SECT283R1, /* ECCurve_NIST_B283 */ michael@0: SEC_OID_SECG_EC_SECT409K1, /* ECCurve_NIST_K409 */ michael@0: SEC_OID_SECG_EC_SECT409R1, /* ECCurve_NIST_B409 */ michael@0: SEC_OID_SECG_EC_SECT571K1, /* ECCurve_NIST_K571 */ michael@0: SEC_OID_SECG_EC_SECT571R1, /* ECCurve_NIST_B571 */ michael@0: SEC_OID_ANSIX962_EC_PRIME192V2, michael@0: SEC_OID_ANSIX962_EC_PRIME192V3, michael@0: SEC_OID_ANSIX962_EC_PRIME239V1, michael@0: SEC_OID_ANSIX962_EC_PRIME239V2, michael@0: SEC_OID_ANSIX962_EC_PRIME239V3, michael@0: SEC_OID_ANSIX962_EC_C2PNB163V1, michael@0: SEC_OID_ANSIX962_EC_C2PNB163V2, michael@0: SEC_OID_ANSIX962_EC_C2PNB163V3, michael@0: SEC_OID_ANSIX962_EC_C2PNB176V1, michael@0: SEC_OID_ANSIX962_EC_C2TNB191V1, michael@0: SEC_OID_ANSIX962_EC_C2TNB191V2, michael@0: SEC_OID_ANSIX962_EC_C2TNB191V3, michael@0: SEC_OID_ANSIX962_EC_C2PNB208W1, michael@0: SEC_OID_ANSIX962_EC_C2TNB239V1, michael@0: SEC_OID_ANSIX962_EC_C2TNB239V2, michael@0: SEC_OID_ANSIX962_EC_C2TNB239V3, michael@0: SEC_OID_ANSIX962_EC_C2PNB272W1, michael@0: SEC_OID_ANSIX962_EC_C2PNB304W1, michael@0: SEC_OID_ANSIX962_EC_C2TNB359V1, michael@0: SEC_OID_ANSIX962_EC_C2PNB368W1, michael@0: SEC_OID_ANSIX962_EC_C2TNB431R1, michael@0: SEC_OID_SECG_EC_SECP112R1, michael@0: SEC_OID_SECG_EC_SECP112R2, michael@0: SEC_OID_SECG_EC_SECP128R1, michael@0: SEC_OID_SECG_EC_SECP128R2, michael@0: SEC_OID_SECG_EC_SECP160K1, michael@0: SEC_OID_SECG_EC_SECP160R1, michael@0: SEC_OID_SECG_EC_SECP160R2, michael@0: SEC_OID_SECG_EC_SECP192K1, michael@0: SEC_OID_SECG_EC_SECP224K1, michael@0: SEC_OID_SECG_EC_SECP256K1, michael@0: SEC_OID_SECG_EC_SECT113R1, michael@0: SEC_OID_SECG_EC_SECT113R2, michael@0: SEC_OID_SECG_EC_SECT131R1, michael@0: SEC_OID_SECG_EC_SECT131R2, michael@0: SEC_OID_SECG_EC_SECT163R1, michael@0: SEC_OID_SECG_EC_SECT193R1, michael@0: SEC_OID_SECG_EC_SECT193R2, michael@0: SEC_OID_SECG_EC_SECT239K1, michael@0: SEC_OID_UNKNOWN /* ECCurve_pastLastCurve */ michael@0: }; michael@0: michael@0: typedef SECStatus (*op_func) (void *, void *, void *); michael@0: typedef SECStatus (*pk11_op_func) (CK_SESSION_HANDLE, void *, void *, void *); michael@0: michael@0: typedef struct ThreadDataStr { michael@0: op_func op; michael@0: void *p1; michael@0: void *p2; michael@0: void *p3; michael@0: int iters; michael@0: PRLock *lock; michael@0: int count; michael@0: SECStatus status; michael@0: int isSign; michael@0: } ThreadData; michael@0: michael@0: void PKCS11Thread(void *data) michael@0: { michael@0: ThreadData *threadData = (ThreadData *)data; michael@0: pk11_op_func op = (pk11_op_func) threadData->op; michael@0: int iters = threadData->iters; michael@0: unsigned char sigData [256]; michael@0: SECItem sig; michael@0: CK_SESSION_HANDLE session; michael@0: CK_RV crv; michael@0: michael@0: threadData->status = SECSuccess; michael@0: threadData->count = 0; michael@0: michael@0: /* get our thread's session */ michael@0: PR_Lock(threadData->lock); michael@0: crv = NSC_OpenSession(1, CKF_SERIAL_SESSION, NULL, 0, &session); michael@0: PR_Unlock(threadData->lock); michael@0: michael@0: if (threadData->isSign) { michael@0: sig.data = sigData; michael@0: sig.len = sizeof(sigData); michael@0: threadData->p2 = (void *)&sig; michael@0: } michael@0: michael@0: while (iters --) { michael@0: threadData->status = (*op)(session, threadData->p1, michael@0: threadData->p2, threadData->p3); michael@0: if (threadData->status != SECSuccess) { michael@0: break; michael@0: } michael@0: threadData->count++; michael@0: } michael@0: return; michael@0: } michael@0: michael@0: void genericThread(void *data) michael@0: { michael@0: ThreadData *threadData = (ThreadData *)data; michael@0: int iters = threadData->iters; michael@0: unsigned char sigData [256]; michael@0: SECItem sig; michael@0: michael@0: threadData->status = SECSuccess; michael@0: threadData->count = 0; michael@0: michael@0: if (threadData->isSign) { michael@0: sig.data = sigData; michael@0: sig.len = sizeof(sigData); michael@0: threadData->p2 = (void *)&sig; michael@0: } michael@0: michael@0: while (iters --) { michael@0: threadData->status = (*threadData->op)(threadData->p1, michael@0: threadData->p2, threadData->p3); michael@0: if (threadData->status != SECSuccess) { michael@0: break; michael@0: } michael@0: threadData->count++; michael@0: } michael@0: return; michael@0: } michael@0: michael@0: michael@0: /* Time iter repetitions of operation op. */ michael@0: SECStatus michael@0: M_TimeOperation(void (*threadFunc)(void *), michael@0: op_func opfunc, char *op, void *param1, void *param2, michael@0: void *param3, int iters, int numThreads, PRLock *lock, michael@0: CK_SESSION_HANDLE session, int isSign, double *rate) michael@0: { michael@0: double dUserTime; michael@0: int i, total; michael@0: PRIntervalTime startTime, totalTime; michael@0: PRThread **threadIDs; michael@0: ThreadData *threadData; michael@0: pk11_op_func pk11_op = (pk11_op_func) opfunc; michael@0: SECStatus rv; michael@0: michael@0: /* verify operation works before testing performance */ michael@0: if (session) { michael@0: rv = (*pk11_op)(session, param1, param2, param3); michael@0: } else { michael@0: rv = (*opfunc)(param1, param2, param3); michael@0: } michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError("Error:", op); michael@0: return rv; michael@0: } michael@0: michael@0: /* get Data structures */ michael@0: threadIDs = (PRThread **)PORT_Alloc(numThreads*sizeof(PRThread *)); michael@0: threadData = (ThreadData *)PORT_Alloc(numThreads*sizeof(ThreadData)); michael@0: michael@0: startTime = PR_Now(); michael@0: if (numThreads == 1) { michael@0: for (i=0; i < iters; i++) { michael@0: if (session) { michael@0: rv = (*pk11_op)(session, param1, param2, param3); michael@0: } else { michael@0: rv = (*opfunc)(param1, param2, param3); michael@0: } michael@0: } michael@0: total = iters; michael@0: } else { michael@0: for (i = 0; i < numThreads; i++) { michael@0: threadData[i].op = opfunc; michael@0: threadData[i].p1 = (void *)param1; michael@0: threadData[i].p2 = (void *)param2; michael@0: threadData[i].p3 = (void *)param3; michael@0: threadData[i].iters = iters; michael@0: threadData[i].lock = lock; michael@0: threadData[i].isSign = isSign; michael@0: threadIDs[i] = PR_CreateThread(PR_USER_THREAD, threadFunc, michael@0: (void *)&threadData[i], PR_PRIORITY_NORMAL, michael@0: PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); michael@0: } michael@0: michael@0: total = 0; michael@0: for (i = 0; i < numThreads; i++) { michael@0: PR_JoinThread(threadIDs[i]); michael@0: /* check the status */ michael@0: total += threadData[i].count; michael@0: } michael@0: michael@0: PORT_Free(threadIDs); michael@0: PORT_Free(threadData); michael@0: } michael@0: michael@0: totalTime = PR_Now()- startTime; michael@0: /* SecondsToInterval seems to be broken here ... */ michael@0: dUserTime = (double)totalTime/(double)1000000; michael@0: if (dUserTime) { michael@0: printf(" %-15s count:%4d sec: %3.2f op/sec: %6.2f\n", michael@0: op, total, dUserTime, (double)total/dUserTime); michael@0: if (rate) { michael@0: *rate = ((double)total)/dUserTime; michael@0: } michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: #define GFP_POPULATE(params,name_v) \ michael@0: params.name = name_v; \ michael@0: if ((params.name < ECCurve_noName) || \ michael@0: (params.name > ECCurve_pastLastCurve)) goto cleanup; \ michael@0: params.type = ec_params_named; \ michael@0: params.curveOID.data = NULL; \ michael@0: params.curveOID.len = 0; \ michael@0: params.curve.seed.data = NULL; \ michael@0: params.curve.seed.len = 0; \ michael@0: params.DEREncoding.data = NULL; \ michael@0: params.DEREncoding.len = 0; \ michael@0: params.arena = NULL; \ michael@0: params.fieldID.size = ecCurve_map[name_v]->size; \ michael@0: params.fieldID.type = ec_field_GFp; \ michael@0: hexString2SECItem(params.arena, ¶ms.fieldID.u.prime, \ michael@0: ecCurve_map[name_v]->irr); \ michael@0: hexString2SECItem(params.arena, ¶ms.curve.a, \ michael@0: ecCurve_map[name_v]->curvea); \ michael@0: hexString2SECItem(params.arena, ¶ms.curve.b, \ michael@0: ecCurve_map[name_v]->curveb); \ michael@0: genenc[0] = '0'; \ michael@0: genenc[1] = '4'; \ michael@0: genenc[2] = '\0'; \ michael@0: strcat(genenc, ecCurve_map[name_v]->genx); \ michael@0: strcat(genenc, ecCurve_map[name_v]->geny); \ michael@0: hexString2SECItem(params.arena, ¶ms.base, \ michael@0: genenc); \ michael@0: hexString2SECItem(params.arena, ¶ms.order, \ michael@0: ecCurve_map[name_v]->order); \ michael@0: params.cofactor = ecCurve_map[name_v]->cofactor; michael@0: michael@0: michael@0: /* Test curve using specific field arithmetic. */ michael@0: #define ECTEST_NAMED_GFP(name_c, name_v) \ michael@0: if (usefreebl) { \ michael@0: printf("Testing %s using freebl implementation...\n", name_c); \ michael@0: rv = ectest_curve_freebl(name_v, iterations, numThreads); \ michael@0: if (rv != SECSuccess) goto cleanup; \ michael@0: printf("... okay.\n"); \ michael@0: } \ michael@0: if (usepkcs11) { \ michael@0: printf("Testing %s using pkcs11 implementation...\n", name_c); \ michael@0: rv = ectest_curve_pkcs11(name_v, iterations, numThreads); \ michael@0: if (rv != SECSuccess) goto cleanup; \ michael@0: printf("... okay.\n"); \ michael@0: } michael@0: michael@0: /* michael@0: * Initializes a SECItem from a hexadecimal string michael@0: * michael@0: * Warning: This function ignores leading 00's, so any leading 00's michael@0: * in the hexadecimal string must be optional. michael@0: */ michael@0: static SECItem * michael@0: hexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str) michael@0: { michael@0: int i = 0; michael@0: int byteval = 0; michael@0: int tmp = PORT_Strlen(str); michael@0: michael@0: if ((tmp % 2) != 0) return NULL; michael@0: michael@0: /* skip leading 00's unless the hex string is "00" */ michael@0: while ((tmp > 2) && (str[0] == '0') && (str[1] == '0')) { michael@0: str += 2; michael@0: tmp -= 2; michael@0: } michael@0: michael@0: item->data = (unsigned char *) PORT_Alloc( tmp/2); michael@0: if (item->data == NULL) return NULL; michael@0: item->len = tmp/2; michael@0: michael@0: while (str[i]) { michael@0: if ((str[i] >= '0') && (str[i] <= '9')) michael@0: tmp = str[i] - '0'; michael@0: else if ((str[i] >= 'a') && (str[i] <= 'f')) michael@0: tmp = str[i] - 'a' + 10; michael@0: else if ((str[i] >= 'A') && (str[i] <= 'F')) michael@0: tmp = str[i] - 'A' + 10; michael@0: else michael@0: return NULL; michael@0: michael@0: byteval = byteval * 16 + tmp; michael@0: if ((i % 2) != 0) { michael@0: item->data[i/2] = byteval; michael@0: byteval = 0; michael@0: } michael@0: i++; michael@0: } michael@0: michael@0: return item; michael@0: } michael@0: michael@0: #define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \ michael@0: (x)->pValue=(v); (x)->ulValueLen = (l); michael@0: michael@0: michael@0: SECStatus michael@0: PKCS11_Derive(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey, michael@0: CK_MECHANISM *pMech , int *dummy) michael@0: { michael@0: CK_RV crv; michael@0: CK_OBJECT_HANDLE newKey; michael@0: CK_BBOOL cktrue = CK_TRUE; michael@0: CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; michael@0: CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; michael@0: CK_ATTRIBUTE keyTemplate[3]; michael@0: CK_ATTRIBUTE *attrs = keyTemplate; michael@0: michael@0: PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); michael@0: attrs++; michael@0: PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); michael@0: attrs++; michael@0: PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, 1); attrs++; michael@0: michael@0: michael@0: crv = NSC_DeriveKey(session, pMech, *hKey, keyTemplate, 3, &newKey); michael@0: if (crv != CKR_OK) { michael@0: printf("Derive Failed CK_RV=0x%x\n", (int)crv); michael@0: return SECFailure; michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: PKCS11_Sign(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey, michael@0: SECItem *sig, SECItem *digest) michael@0: { michael@0: CK_RV crv; michael@0: CK_MECHANISM mech; michael@0: michael@0: mech.mechanism = CKM_ECDSA; michael@0: mech.pParameter = NULL; michael@0: mech.ulParameterLen = 0; michael@0: michael@0: crv = NSC_SignInit(session, &mech, *hKey); michael@0: if (crv != CKR_OK) { michael@0: printf("Sign Failed CK_RV=0x%x\n", (int)crv); michael@0: return SECFailure; michael@0: } michael@0: crv = NSC_Sign(session, digest->data, digest->len, sig->data, michael@0: (CK_ULONG_PTR)&sig->len); michael@0: if (crv != CKR_OK) { michael@0: printf("Sign Failed CK_RV=0x%x\n", (int)crv); michael@0: return SECFailure; michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: PKCS11_Verify(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey, michael@0: SECItem *sig, SECItem *digest) michael@0: { michael@0: CK_RV crv; michael@0: CK_MECHANISM mech; michael@0: michael@0: mech.mechanism = CKM_ECDSA; michael@0: mech.pParameter = NULL; michael@0: mech.ulParameterLen = 0; michael@0: michael@0: crv = NSC_VerifyInit(session, &mech, *hKey); michael@0: if (crv != CKR_OK) { michael@0: printf("Verify Failed CK_RV=0x%x\n", (int)crv); michael@0: return SECFailure; michael@0: } michael@0: crv = NSC_Verify(session, digest->data, digest->len, sig->data, sig->len); michael@0: if (crv != CKR_OK) { michael@0: printf("Verify Failed CK_RV=0x%x\n", (int)crv); michael@0: return SECFailure; michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: static SECStatus michael@0: ecName2params(ECCurveName curve, SECKEYECParams * params) michael@0: { michael@0: SECOidData *oidData = NULL; michael@0: michael@0: if ((curve < ECCurve_noName) || (curve > ECCurve_pastLastCurve) || michael@0: ((oidData = SECOID_FindOIDByTag(ecCurve_oid_map[curve])) == NULL)) { michael@0: PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); michael@0: return SECFailure; michael@0: } michael@0: michael@0: SECITEM_AllocItem(NULL, params, (2 + oidData->oid.len)); michael@0: /* michael@0: * params->data needs to contain the ASN encoding of an object ID (OID) michael@0: * representing the named curve. The actual OID is in michael@0: * oidData->oid.data so we simply prepend 0x06 and OID length michael@0: */ michael@0: params->data[0] = SEC_ASN1_OBJECT_ID; michael@0: params->data[1] = oidData->oid.len; michael@0: memcpy(params->data + 2, oidData->oid.data, oidData->oid.len); michael@0: michael@0: return SECSuccess; michael@0: } michael@0: michael@0: michael@0: michael@0: /* Performs basic tests of elliptic curve cryptography over prime fields. michael@0: * If tests fail, then it prints an error message, aborts, and returns an michael@0: * error code. Otherwise, returns 0. */ michael@0: SECStatus michael@0: ectest_curve_pkcs11(ECCurveName curve, int iterations, int numThreads) michael@0: { michael@0: CK_OBJECT_HANDLE ecPriv; michael@0: CK_OBJECT_HANDLE ecPub; michael@0: CK_SESSION_HANDLE session; michael@0: SECItem sig; michael@0: SECItem digest; michael@0: SECKEYECParams ecParams; michael@0: CK_MECHANISM mech; michael@0: CK_ECDH1_DERIVE_PARAMS ecdh_params; michael@0: unsigned char sigData [256]; michael@0: unsigned char digestData[20]; michael@0: unsigned char pubKeyData[256]; michael@0: PRLock *lock = NULL; michael@0: double signRate, deriveRate; michael@0: CK_ATTRIBUTE template; michael@0: SECStatus rv; michael@0: CK_RV crv; michael@0: michael@0: ecParams.data = NULL; michael@0: ecParams.len = 0; michael@0: rv = ecName2params(curve, &ecParams); michael@0: if (rv != SECSuccess) { michael@0: goto cleanup; michael@0: } michael@0: michael@0: crv = NSC_OpenSession(1, CKF_SERIAL_SESSION, NULL, 0, &session); michael@0: if (crv != CKR_OK) { michael@0: printf("OpenSession Failed CK_RV=0x%x\n", (int)crv); michael@0: return SECFailure; michael@0: } michael@0: michael@0: PORT_Memset(digestData, 0xa5, sizeof(digestData)); michael@0: digest.data = digestData; michael@0: digest.len = sizeof(digestData); michael@0: sig.data = sigData; michael@0: sig.len = sizeof(sigData); michael@0: michael@0: template.type = CKA_EC_PARAMS; michael@0: template.pValue = ecParams.data; michael@0: template.ulValueLen = ecParams.len; michael@0: mech.mechanism = CKM_EC_KEY_PAIR_GEN; michael@0: mech.pParameter = NULL; michael@0: mech.ulParameterLen = 0; michael@0: crv = NSC_GenerateKeyPair(session, &mech, michael@0: &template, 1, NULL, 0, &ecPub, &ecPriv); michael@0: if (crv != CKR_OK) { michael@0: printf("GenerateKeyPair Failed CK_RV=0x%x\n", (int)crv); michael@0: return SECFailure; michael@0: } michael@0: michael@0: template.type = CKA_EC_POINT; michael@0: template.pValue = pubKeyData; michael@0: template.ulValueLen = sizeof(pubKeyData); michael@0: crv = NSC_GetAttributeValue(session, ecPub, &template, 1); michael@0: if (crv != CKR_OK) { michael@0: printf("GenerateKeyPair Failed CK_RV=0x%x\n", (int)crv); michael@0: return SECFailure; michael@0: } michael@0: michael@0: ecdh_params.kdf = CKD_NULL; michael@0: ecdh_params.ulSharedDataLen = 0; michael@0: ecdh_params.pSharedData = NULL; michael@0: ecdh_params.ulPublicDataLen = template.ulValueLen; michael@0: ecdh_params.pPublicData = template.pValue; michael@0: michael@0: mech.mechanism = CKM_ECDH1_DERIVE; michael@0: mech.pParameter = (void *)&ecdh_params; michael@0: mech.ulParameterLen = sizeof(ecdh_params); michael@0: michael@0: lock = PR_NewLock(); michael@0: michael@0: rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Derive, "ECDH_Derive", michael@0: &ecPriv, &mech, NULL, iterations, numThreads, michael@0: lock, session, 0, &deriveRate); michael@0: if (rv != SECSuccess) goto cleanup; michael@0: rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Sign, "ECDSA_Sign", michael@0: (void *)&ecPriv, &sig, &digest, iterations, numThreads, michael@0: lock, session, 1, &signRate); michael@0: if (rv != SECSuccess) goto cleanup; michael@0: printf(" ECDHE max rate = %.2f\n", (deriveRate+signRate)/4.0); michael@0: /* get a signature */ michael@0: rv = PKCS11_Sign(session, &ecPriv, &sig, &digest); michael@0: if (rv != SECSuccess) goto cleanup; michael@0: rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Verify, "ECDSA_Verify", michael@0: (void *)&ecPub, &sig, &digest, iterations, numThreads, michael@0: lock, session, 0, NULL); michael@0: if (rv != SECSuccess) goto cleanup; michael@0: michael@0: cleanup: michael@0: if (lock) { michael@0: PR_DestroyLock(lock); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: SECStatus michael@0: ECDH_DeriveWrap(ECPrivateKey *priv, ECPublicKey *pub, int *dummy) michael@0: { michael@0: SECItem secret; michael@0: unsigned char secretData[256]; michael@0: SECStatus rv; michael@0: michael@0: secret.data = secretData; michael@0: secret.len = sizeof(secretData); michael@0: michael@0: rv = ECDH_Derive(&pub->publicValue, &pub->ecParams, michael@0: &priv->privateValue, 0, &secret); michael@0: #ifdef notdef michael@0: if (rv == SECSuccess) { michael@0: PORT_Free(secret.data); michael@0: } michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: /* Performs basic tests of elliptic curve cryptography over prime fields. michael@0: * If tests fail, then it prints an error message, aborts, and returns an michael@0: * error code. Otherwise, returns 0. */ michael@0: SECStatus michael@0: ectest_curve_freebl(ECCurveName curve, int iterations, int numThreads) michael@0: { michael@0: ECParams ecParams; michael@0: ECPrivateKey *ecPriv = NULL; michael@0: ECPublicKey ecPub; michael@0: SECItem sig; michael@0: SECItem digest; michael@0: unsigned char sigData [256]; michael@0: unsigned char digestData[20]; michael@0: double signRate, deriveRate; michael@0: char genenc[3 + 2 * 2 * MAX_ECKEY_LEN]; michael@0: SECStatus rv; michael@0: michael@0: michael@0: GFP_POPULATE(ecParams, curve); michael@0: michael@0: PORT_Memset(digestData, 0xa5, sizeof(digestData)); michael@0: digest.data = digestData; michael@0: digest.len = sizeof(digestData); michael@0: sig.data = sigData; michael@0: sig.len = sizeof(sigData); michael@0: michael@0: rv = EC_NewKey(&ecParams, &ecPriv); michael@0: if (rv != SECSuccess) { michael@0: return SECFailure; michael@0: } michael@0: ecPub.ecParams = ecParams; michael@0: ecPub.publicValue = ecPriv->publicValue; michael@0: michael@0: M_TimeOperation(genericThread, (op_func) ECDH_DeriveWrap, "ECDH_Derive", michael@0: ecPriv, &ecPub, NULL, iterations, numThreads, 0, 0, 0, &deriveRate); michael@0: if (rv != SECSuccess) goto cleanup; michael@0: M_TimeOperation(genericThread, (op_func) ECDSA_SignDigest, "ECDSA_Sign", michael@0: ecPriv, &sig, &digest, iterations, numThreads, 0, 0, 1, &signRate); michael@0: if (rv != SECSuccess) goto cleanup; michael@0: printf(" ECDHE max rate = %.2f\n", (deriveRate+signRate)/4.0); michael@0: rv = ECDSA_SignDigest(ecPriv, &sig, &digest); michael@0: if (rv != SECSuccess) goto cleanup; michael@0: M_TimeOperation(genericThread, (op_func) ECDSA_VerifyDigest, "ECDSA_Verify", michael@0: &ecPub, &sig, &digest, iterations, numThreads, 0, 0, 0, NULL); michael@0: if (rv != SECSuccess) goto cleanup; michael@0: michael@0: cleanup: michael@0: return rv; michael@0: } michael@0: michael@0: /* Prints help information. */ michael@0: void michael@0: printUsage(char *prog) michael@0: { michael@0: printf("Usage: %s [-i iterations] [-t threads ] [-ans] [-fp] [-A]\n",prog); michael@0: } michael@0: michael@0: /* Performs tests of elliptic curve cryptography over prime fields If michael@0: * tests fail, then it prints an error message, aborts, and returns an michael@0: * error code. Otherwise, returns 0. */ michael@0: int michael@0: main(int argv, char **argc) michael@0: { michael@0: int ansi = 0; michael@0: int nist = 0; michael@0: int secp = 0; michael@0: int usefreebl = 0; michael@0: int usepkcs11 = 0; michael@0: int i; michael@0: SECStatus rv = SECSuccess; michael@0: int iterations = 100; michael@0: int numThreads = 1; michael@0: michael@0: /* read command-line arguments */ michael@0: for (i = 1; i < argv; i++) { michael@0: if (strcasecmp(argc[i], "-i") == 0) { michael@0: i++; michael@0: iterations = atoi(argc[i]); michael@0: } else if (strcasecmp(argc[i], "-t") == 0) { michael@0: i++; michael@0: numThreads = atoi(argc[i]); michael@0: } else if (strcasecmp(argc[i], "-A") == 0) { michael@0: ansi = nist = secp = 1; michael@0: usepkcs11 = usefreebl = 1; michael@0: } else if (strcasecmp(argc[i], "-a") == 0) { michael@0: ansi = 1; michael@0: } else if (strcasecmp(argc[i], "-n") == 0) { michael@0: nist = 1; michael@0: } else if (strcasecmp(argc[i], "-s") == 0) { michael@0: secp = 1; michael@0: } else if (strcasecmp(argc[i], "-p") == 0) { michael@0: usepkcs11 = 1; michael@0: } else if (strcasecmp(argc[i], "-f") == 0) { michael@0: usefreebl = 1; michael@0: } else { michael@0: printUsage(argc[0]); michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: if ((ansi | nist | secp) == 0) { michael@0: nist = 1; michael@0: } michael@0: if ((usepkcs11|usefreebl) == 0) { michael@0: usefreebl = 1; michael@0: } michael@0: michael@0: rv = NSS_NoDB_Init(NULL); michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError("Error:", "NSS_NoDB_Init"); michael@0: goto cleanup; michael@0: } michael@0: michael@0: /* specific arithmetic tests */ michael@0: if (nist) { michael@0: ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1); michael@0: ECTEST_NAMED_GFP("NIST-P192", ECCurve_NIST_P192); michael@0: ECTEST_NAMED_GFP("NIST-P224", ECCurve_NIST_P224); michael@0: ECTEST_NAMED_GFP("NIST-P256", ECCurve_NIST_P256); michael@0: ECTEST_NAMED_GFP("NIST-P384", ECCurve_NIST_P384); michael@0: ECTEST_NAMED_GFP("NIST-P521", ECCurve_NIST_P521); michael@0: } michael@0: if (ansi) { michael@0: ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v1", ECCurve_X9_62_PRIME_192V1); michael@0: ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v2", ECCurve_X9_62_PRIME_192V2); michael@0: ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v3", ECCurve_X9_62_PRIME_192V3); michael@0: ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v1", ECCurve_X9_62_PRIME_239V1); michael@0: ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v2", ECCurve_X9_62_PRIME_239V2); michael@0: ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v3", ECCurve_X9_62_PRIME_239V3); michael@0: ECTEST_NAMED_GFP("ANSI X9.62 PRIME256v1", ECCurve_X9_62_PRIME_256V1); michael@0: } michael@0: if (secp) { michael@0: ECTEST_NAMED_GFP("SECP-112R1", ECCurve_SECG_PRIME_112R1); michael@0: ECTEST_NAMED_GFP("SECP-112R2", ECCurve_SECG_PRIME_112R2); michael@0: ECTEST_NAMED_GFP("SECP-128R1", ECCurve_SECG_PRIME_128R1); michael@0: ECTEST_NAMED_GFP("SECP-128R2", ECCurve_SECG_PRIME_128R2); michael@0: ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1); michael@0: ECTEST_NAMED_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1); michael@0: ECTEST_NAMED_GFP("SECP-160R2", ECCurve_SECG_PRIME_160R2); michael@0: ECTEST_NAMED_GFP("SECP-192K1", ECCurve_SECG_PRIME_192K1); michael@0: ECTEST_NAMED_GFP("SECP-192R1", ECCurve_SECG_PRIME_192R1); michael@0: ECTEST_NAMED_GFP("SECP-224K1", ECCurve_SECG_PRIME_224K1); michael@0: ECTEST_NAMED_GFP("SECP-224R1", ECCurve_SECG_PRIME_224R1); michael@0: ECTEST_NAMED_GFP("SECP-256K1", ECCurve_SECG_PRIME_256K1); michael@0: ECTEST_NAMED_GFP("SECP-256R1", ECCurve_SECG_PRIME_256R1); michael@0: ECTEST_NAMED_GFP("SECP-384R1", ECCurve_SECG_PRIME_384R1); michael@0: ECTEST_NAMED_GFP("SECP-521R1", ECCurve_SECG_PRIME_521R1); michael@0: } michael@0: michael@0: cleanup: michael@0: if (rv != SECSuccess) { michael@0: printf("Error: exiting with error value\n"); michael@0: } michael@0: return rv; michael@0: }