| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #include "secutil.h" |
| #include "secmod.h" |
| #include "cert.h" |
| #include "secoid.h" |
| #include "nss.h" |
| #include "pk11pub.h" |
| #include "pk11pqg.h" |
| |
| /* NSPR 2.0 header files */ |
| #include "prinit.h" |
| #include "prprf.h" |
| #include "prsystem.h" |
| #include "prmem.h" |
| /* Portable layer header files */ |
| #include "plstr.h" |
| |
| SECOidData * |
| getCurveFromString(char *curve_name) |
| { |
| SECOidTag tag = SEC_OID_SECG_EC_SECP256R1; |
| |
| if (PORT_Strcasecmp(curve_name, "NISTP256") == 0) { |
| } else if (PORT_Strcasecmp(curve_name, "NISTP384") == 0) { |
| tag = SEC_OID_SECG_EC_SECP384R1; |
| } else if (PORT_Strcasecmp(curve_name, "NISTP521") == 0) { |
| tag = SEC_OID_SECG_EC_SECP521R1; |
| } else if (PORT_Strcasecmp(curve_name, "Curve25519") == 0) { |
| tag = SEC_OID_CURVE25519; |
| } |
| return SECOID_FindOIDByTag(tag); |
| } |
| |
| void |
| dumpItem(const char *label, const SECItem *item) |
| { |
| int i; |
| printf("%s = [%d bytes] {", label, item->len); |
| for (i = 0; i < item->len; i++) { |
| if ((i & 0xf) == 0) |
| printf("\n "); |
| else |
| printf(", "); |
| printf("%02x", item->data[i]); |
| } |
| printf("};\n"); |
| } |
| |
| SECStatus |
| handleEncryptedPrivateImportTest(char *progName, PK11SlotInfo *slot, |
| char *testname, CK_MECHANISM_TYPE genMech, void *params, void *pwArgs) |
| { |
| SECStatus rv = SECSuccess; |
| SECItem privID = { 0 }; |
| SECItem pubID = { 0 }; |
| SECItem pubValue = { 0 }; |
| SECItem pbePwItem = { 0 }; |
| SECItem nickname = { 0 }; |
| SECItem token = { 0 }; |
| SECKEYPublicKey *pubKey = NULL; |
| SECKEYPrivateKey *privKey = NULL; |
| PK11GenericObject *objs = NULL; |
| PK11GenericObject *obj = NULL; |
| SECKEYEncryptedPrivateKeyInfo *epki = NULL; |
| PRBool keyFound = 0; |
| KeyType keyType; |
| |
| fprintf(stderr, "Testing %s PrivateKeyImport ***********************\n", |
| testname); |
| |
| /* generate a temp key */ |
| privKey = PK11_GenerateKeyPair(slot, genMech, params, &pubKey, |
| PR_FALSE, PR_TRUE, pwArgs); |
| if (privKey == NULL) { |
| SECU_PrintError(progName, "PK11_GenerateKeyPair Failed"); |
| goto cleanup; |
| } |
| |
| /* wrap the temp key */ |
| pbePwItem.data = (unsigned char *)"pw"; |
| pbePwItem.len = 2; |
| epki = PK11_ExportEncryptedPrivKeyInfo(slot, SEC_OID_AES_256_CBC, |
| &pbePwItem, privKey, 1, NULL); |
| if (epki == NULL) { |
| SECU_PrintError(progName, "PK11_ExportEncryptedPrivKeyInfo Failed"); |
| goto cleanup; |
| } |
| |
| /* Save the public value, which we will need on import */ |
| keyType = pubKey->keyType; |
| switch (keyType) { |
| case rsaKey: |
| SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.rsa.modulus); |
| break; |
| case dhKey: |
| SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.dh.publicValue); |
| break; |
| case dsaKey: |
| SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.dsa.publicValue); |
| break; |
| case ecKey: |
| SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.ec.publicValue); |
| break; |
| default: |
| fprintf(stderr, "Unknown keytype = %d\n", keyType); |
| goto cleanup; |
| } |
| if (pubValue.data == NULL) { |
| SECU_PrintError(progName, "Unable to allocate memory"); |
| goto cleanup; |
| } |
| dumpItem("pubValue", &pubValue); |
| |
| /* when Asymetric keys represent session keys, those session keys are |
| * destroyed when we destroy the Asymetric key representations */ |
| SECKEY_DestroyPublicKey(pubKey); |
| pubKey = NULL; |
| SECKEY_DestroyPrivateKey(privKey); |
| privKey = NULL; |
| |
| /* unwrap the temp key as a perm */ |
| nickname.data = (unsigned char *)"testKey"; |
| nickname.len = sizeof("testKey"); |
| rv = PK11_ImportEncryptedPrivateKeyInfoAndReturnKey( |
| slot, epki, &pbePwItem, &nickname, &pubValue, |
| PR_TRUE, PR_TRUE, keyType, 0, &privKey, NULL); |
| if (rv != SECSuccess) { |
| SECU_PrintError(progName, "PK11_ImportEncryptedPrivateKeyInfo Failed"); |
| goto cleanup; |
| } |
| |
| /* verify the public key exists */ |
| rv = PK11_ReadRawAttribute(PK11_TypePrivKey, privKey, CKA_ID, &privID); |
| if (rv != SECSuccess) { |
| SECU_PrintError(progName, |
| "Couldn't read CKA_ID from pub key, checking next key"); |
| goto cleanup; |
| } |
| dumpItem("privKey CKA_ID", &privID); |
| objs = PK11_FindGenericObjects(slot, CKO_PUBLIC_KEY); |
| for (obj = objs; obj; obj = PK11_GetNextGenericObject(obj)) { |
| rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_ID, &pubID); |
| if (rv != SECSuccess) { |
| SECU_PrintError(progName, |
| "Couldn't read CKA_ID from object, checking next key"); |
| continue; |
| } |
| dumpItem("pubKey CKA_ID", &pubID); |
| if (!SECITEM_ItemsAreEqual(&privID, &pubID)) { |
| fprintf(stderr, |
| "CKA_ID does not match priv key, checking next key\n"); |
| SECITEM_FreeItem(&pubID, PR_FALSE); |
| continue; |
| } |
| SECITEM_FreeItem(&pubID, PR_FALSE); |
| rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_TOKEN, &token); |
| if (rv == SECSuccess) { |
| if (token.len == 1) { |
| keyFound = token.data[0]; |
| } |
| SECITEM_FreeItem(&token, PR_FALSE); |
| } |
| if (keyFound) { |
| printf("matching public key found\n"); |
| break; |
| } |
| printf("Matching key was not a token key, checking next key\n"); |
| } |
| |
| cleanup: |
| if (objs) { |
| PK11_DestroyGenericObjects(objs); |
| } |
| SECITEM_FreeItem(&pubValue, PR_FALSE); |
| SECITEM_FreeItem(&privID, PR_FALSE); |
| if (epki && epki->arena) { |
| PORT_FreeArena(epki->arena, PR_TRUE); |
| } |
| SECKEY_DestroyPublicKey(pubKey); |
| SECKEY_DestroyPrivateKey(privKey); |
| fprintf(stderr, "%s PrivateKeyImport %s ***********************\n", |
| testname, keyFound ? "PASSED" : "FAILED"); |
| return keyFound ? SECSuccess : SECFailure; |
| } |
| |
| static const char *const usageInfo[] = { |
| "pk11import - test PK11_PrivateKeyImport()", |
| "Options:", |
| " -d certdir directory containing cert database", |
| " -k keysize size of the rsa, dh, and dsa key to test (default 1024)", |
| " -C ecc_curve ecc curve (default )", |
| " -f pwFile file to fetch the password from", |
| " -p pwString password", |
| " -r skip rsa test", |
| " -D skip dsa test", |
| " -h skip dh test", |
| " -e skip ec test", |
| }; |
| static int nUsageInfo = sizeof(usageInfo) / sizeof(char *); |
| |
| static void |
| Usage(char *progName, FILE *outFile) |
| { |
| int i; |
| fprintf(outFile, "Usage: %s [ commands ] options\n", progName); |
| for (i = 0; i < nUsageInfo; i++) |
| fprintf(outFile, "%s\n", usageInfo[i]); |
| exit(-1); |
| } |
| |
| enum { |
| opt_CertDir, |
| opt_KeySize, |
| opt_ECCurve, |
| opt_PWFile, |
| opt_PWString, |
| opt_NoRSA, |
| opt_NoDSA, |
| opt_NoEC, |
| opt_NoDH |
| }; |
| |
| static secuCommandFlag options[] = |
| { |
| { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE }, |
| { /* opt_KeySize */ 'k', PR_TRUE, 0, PR_FALSE }, |
| { /* opt_ECCurve */ 'C', PR_TRUE, 0, PR_FALSE }, |
| { /* opt_PWFile */ 'f', PR_TRUE, 0, PR_FALSE }, |
| { /* opt_PWString */ 'p', PR_TRUE, 0, PR_FALSE }, |
| { /* opt_NORSA */ 'r', PR_TRUE, 0, PR_FALSE }, |
| { /* opt_NoDSA */ 'D', PR_TRUE, 0, PR_FALSE }, |
| { /* opt_NoDH */ 'h', PR_TRUE, 0, PR_FALSE }, |
| { /* opt_NoEC */ 'e', PR_TRUE, 0, PR_FALSE }, |
| }; |
| |
| int |
| main(int argc, char **argv) |
| { |
| char *progName; |
| SECStatus rv; |
| secuCommand args; |
| PK11SlotInfo *slot = NULL; |
| PRBool failed = PR_FALSE; |
| secuPWData pwArgs = { PW_NONE, 0 }; |
| PRBool doRSA = PR_TRUE; |
| PRBool doDSA = PR_TRUE; |
| PRBool doDH = PR_FALSE; /* NSS currently can't export wrapped DH keys */ |
| PRBool doEC = PR_TRUE; |
| PQGParams *pqgParams = NULL; |
| int keySize; |
| |
| args.numCommands = 0; |
| args.numOptions = sizeof(options) / sizeof(secuCommandFlag); |
| args.commands = NULL; |
| args.options = options; |
| |
| #ifdef XP_PC |
| progName = strrchr(argv[0], '\\'); |
| #else |
| progName = strrchr(argv[0], '/'); |
| #endif |
| progName = progName ? progName + 1 : argv[0]; |
| |
| rv = SECU_ParseCommandLine(argc, argv, progName, &args); |
| if (SECSuccess != rv) { |
| Usage(progName, stderr); |
| } |
| |
| /* Set the certdb directory (default is ~/.netscape) */ |
| rv = NSS_InitReadWrite(SECU_ConfigDirectory(args.options[opt_CertDir].arg)); |
| if (rv != SECSuccess) { |
| SECU_PrintPRandOSError(progName); |
| return 255; |
| } |
| PK11_SetPasswordFunc(SECU_GetModulePassword); |
| |
| /* below here, goto cleanup */ |
| SECU_RegisterDynamicOids(); |
| |
| /* handle the arguments */ |
| if (args.options[opt_PWFile].arg) { |
| pwArgs.source = PW_FROMFILE; |
| pwArgs.data = args.options[opt_PWFile].arg; |
| } |
| if (args.options[opt_PWString].arg) { |
| pwArgs.source = PW_PLAINTEXT; |
| pwArgs.data = args.options[opt_PWString].arg; |
| } |
| if (args.options[opt_NoRSA].activated) { |
| doRSA = PR_FALSE; |
| } |
| if (args.options[opt_NoDSA].activated) { |
| doDSA = PR_FALSE; |
| } |
| if (args.options[opt_NoDH].activated) { |
| doDH = PR_FALSE; |
| } |
| if (args.options[opt_NoEC].activated) { |
| doEC = PR_FALSE; |
| } |
| |
| slot = PK11_GetInternalKeySlot(); |
| if (slot == NULL) { |
| SECU_PrintError(progName, "Couldn't find the internal key slot\n"); |
| return 255; |
| } |
| rv = PK11_Authenticate(slot, PR_TRUE, &pwArgs); |
| if (rv != SECSuccess) { |
| SECU_PrintError(progName, "Failed to log into slot"); |
| PK11_FreeSlot(slot); |
| return 255; |
| } |
| |
| keySize = 1024; |
| if (args.options[opt_KeySize].activated && |
| args.options[opt_KeySize].arg) { |
| keySize = atoi(args.options[opt_KeySize].arg); |
| } |
| |
| if (doDSA || doDH) { |
| PQGVerify *pqgVfy; |
| rv = PK11_PQG_ParamGenV2(keySize, 0, keySize / 16, &pqgParams, &pqgVfy); |
| if (rv == SECSuccess) { |
| PK11_PQG_DestroyVerify(pqgVfy); |
| } else { |
| SECU_PrintError(progName, |
| "PK11_PQG_ParamGenV2 failed, can't test DH or DSA"); |
| doDSA = doDH = PR_FALSE; |
| failed = PR_TRUE; |
| } |
| } |
| |
| if (doRSA) { |
| PK11RSAGenParams rsaParams; |
| rsaParams.keySizeInBits = keySize; |
| rsaParams.pe = 0x010001; |
| rv = handleEncryptedPrivateImportTest(progName, slot, "RSA", |
| CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams, &pwArgs); |
| if (rv != SECSuccess) { |
| fprintf(stderr, "RSA Import Failed!\n"); |
| failed = PR_TRUE; |
| } |
| } |
| if (doDSA) { |
| rv = handleEncryptedPrivateImportTest(progName, slot, "DSA", |
| CKM_DSA_KEY_PAIR_GEN, pqgParams, &pwArgs); |
| if (rv != SECSuccess) { |
| fprintf(stderr, "DSA Import Failed!\n"); |
| failed = PR_TRUE; |
| } |
| } |
| if (doDH) { |
| SECKEYDHParams dhParams; |
| dhParams.prime = pqgParams->prime; |
| dhParams.base = pqgParams->base; |
| rv = handleEncryptedPrivateImportTest(progName, slot, "DH", |
| CKM_DH_PKCS_KEY_PAIR_GEN, &dhParams, &pwArgs); |
| if (rv != SECSuccess) { |
| fprintf(stderr, "DH Import Failed!\n"); |
| failed = PR_TRUE; |
| } |
| } |
| if (doEC) { |
| SECKEYECParams ecParams; |
| SECOidData *curve = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); |
| if (args.options[opt_ECCurve].activated && |
| args.options[opt_ECCurve].arg) { |
| curve = getCurveFromString(args.options[opt_ECCurve].arg); |
| } |
| ecParams.data = PORT_Alloc(curve->oid.len + 2); |
| if (ecParams.data == NULL) { |
| rv = SECFailure; |
| goto ec_failed; |
| } |
| ecParams.data[0] = SEC_ASN1_OBJECT_ID; |
| ecParams.data[1] = (unsigned char)curve->oid.len; |
| PORT_Memcpy(&ecParams.data[2], curve->oid.data, curve->oid.len); |
| ecParams.len = curve->oid.len + 2; |
| rv = handleEncryptedPrivateImportTest(progName, slot, "ECC", |
| CKM_EC_KEY_PAIR_GEN, &ecParams, &pwArgs); |
| PORT_Free(ecParams.data); |
| ec_failed: |
| if (rv != SECSuccess) { |
| fprintf(stderr, "ECC Import Failed!\n"); |
| failed = PR_TRUE; |
| } |
| } |
| |
| if (pqgParams) { |
| PK11_PQG_DestroyParams(pqgParams); |
| } |
| |
| if (slot) { |
| PK11_FreeSlot(slot); |
| } |
| |
| rv = NSS_Shutdown(); |
| if (rv != SECSuccess) { |
| fprintf(stderr, "Shutdown failed\n"); |
| SECU_PrintPRandOSError(progName); |
| return 255; |
| } |
| |
| return failed ? 1 : 0; |
| } |