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 michael@0: #include michael@0: #include "plgetopt.h" michael@0: #include "nss.h" michael@0: #include "secutil.h" michael@0: #include "pk11table.h" michael@0: #include "secmodt.h" michael@0: #include "pk11pub.h" michael@0: michael@0: michael@0: struct test_args { michael@0: char *arg; michael@0: int mask_value; michael@0: char *description; michael@0: }; michael@0: michael@0: static const struct test_args test_array[] = { michael@0: {"all", 0x1f, "run all the tests" }, michael@0: {"e_n_p", 0x01, "public exponent, modulus, prime1"}, michael@0: {"d_n_q", 0x02, "private exponent, modulus, prime2"}, michael@0: {"d_p_q", 0x04, "private exponent, prime1, prime2"}, michael@0: {"e_d_q", 0x08, "public exponent, private exponent, prime2"}, michael@0: {"e_d_n", 0x10, "public exponent, private exponent, moduls"} michael@0: }; michael@0: static const int test_array_size = michael@0: (sizeof(test_array)/sizeof(struct test_args)); michael@0: michael@0: static void Usage(char *progName) michael@0: { michael@0: int i; michael@0: #define PRINTUSAGE(subject, option, predicate) \ michael@0: fprintf(stderr, "%10s %s\t%s\n", subject, option, predicate); michael@0: fprintf(stderr, "%s [-k keysize] [-e exp] [-r rounds] [-t tests]\n " michael@0: "Test creating RSA private keys from Partial components\n", michael@0: progName); michael@0: PRINTUSAGE("", "-k", "key size (in bit)"); michael@0: PRINTUSAGE("", "-e", "rsa public exponent"); michael@0: PRINTUSAGE("", "-r", "number times to repeat the test"); michael@0: PRINTUSAGE("", "-t", "run the specified tests"); michael@0: for (i=0; i < test_array_size; i++) { michael@0: PRINTUSAGE("", test_array[i].arg, test_array[i].description); michael@0: } michael@0: fprintf(stderr,"\n"); michael@0: } michael@0: michael@0: /* michael@0: * Test the RSA populate command to see that it can really build michael@0: * keys from it's components. michael@0: */ michael@0: michael@0: const static CK_ATTRIBUTE rsaTemplate[] = { michael@0: {CKA_CLASS, NULL, 0 }, michael@0: {CKA_KEY_TYPE, NULL, 0 }, michael@0: {CKA_TOKEN, NULL, 0 }, michael@0: {CKA_SENSITIVE, NULL, 0 }, michael@0: {CKA_PRIVATE, NULL, 0 }, michael@0: {CKA_MODULUS, NULL, 0 }, michael@0: {CKA_PUBLIC_EXPONENT, NULL, 0 }, michael@0: {CKA_PRIVATE_EXPONENT, NULL, 0 }, michael@0: {CKA_PRIME_1, NULL, 0 }, michael@0: {CKA_PRIME_2, NULL, 0 }, michael@0: {CKA_EXPONENT_1, NULL, 0 }, michael@0: {CKA_EXPONENT_2, NULL, 0 }, michael@0: {CKA_COEFFICIENT, NULL, 0 }, michael@0: }; michael@0: michael@0: #define RSA_SIZE (sizeof(rsaTemplate)) michael@0: #define RSA_ATTRIBUTES (sizeof(rsaTemplate)/sizeof(CK_ATTRIBUTE)) michael@0: michael@0: static void michael@0: resetTemplate(CK_ATTRIBUTE *attribute, int start, int end) michael@0: { michael@0: int i; michael@0: for (i=start; i < end; i++) { michael@0: if (attribute[i].pValue) { michael@0: PORT_Free(attribute[i].pValue); michael@0: } michael@0: attribute[i].pValue = NULL; michael@0: attribute[i].ulValueLen = 0; michael@0: } michael@0: } michael@0: michael@0: static SECStatus michael@0: copyAttribute(PK11ObjectType objType, void *object, CK_ATTRIBUTE *template, michael@0: int offset, CK_ATTRIBUTE_TYPE attrType) michael@0: { michael@0: SECItem attributeItem = {0, 0, 0}; michael@0: SECStatus rv; michael@0: michael@0: rv = PK11_ReadRawAttribute(objType, object, attrType, &attributeItem); michael@0: if (rv != SECSuccess) { michael@0: return rv; michael@0: } michael@0: template[offset].type = attrType; michael@0: template[offset].pValue = attributeItem.data; michael@0: template[offset].ulValueLen = attributeItem.len; michael@0: return SECSuccess; michael@0: } michael@0: michael@0: static SECStatus michael@0: readKey(PK11ObjectType objType, void *object, CK_ATTRIBUTE *template, michael@0: int start, int end) michael@0: { michael@0: int i; michael@0: SECStatus rv; michael@0: michael@0: for (i=start; i < end; i++) { michael@0: rv = copyAttribute(objType, object, template, i, template[i].type); michael@0: if (rv != SECSuccess) { michael@0: goto fail; michael@0: } michael@0: } michael@0: return SECSuccess; michael@0: michael@0: fail: michael@0: resetTemplate(template, start, i); michael@0: return rv; michael@0: } michael@0: michael@0: #define ATTR_STRING(x) getNameFromAttribute(x) michael@0: michael@0: void michael@0: dumpTemplate(CK_ATTRIBUTE *template, int start, int end) michael@0: { michael@0: int i,j; michael@0: for (i=0; i < end; i++) { michael@0: unsigned char cval; michael@0: CK_ULONG ulval; michael@0: unsigned char *cpval; michael@0: michael@0: fprintf(stderr, "%s:", ATTR_STRING(template[i].type)); michael@0: switch (template[i].ulValueLen) { michael@0: case 1: michael@0: cval =*(unsigned char *)template[i].pValue; michael@0: switch(cval) { michael@0: case 0: fprintf(stderr, " false"); break; michael@0: case 1: fprintf(stderr, " true"); break; michael@0: default: michael@0: fprintf(stderr, " %d (=0x%02x,'%c')",cval,cval,cval); michael@0: break; michael@0: } michael@0: break; michael@0: case sizeof(CK_ULONG): michael@0: ulval = *(CK_ULONG *)template[i].pValue; michael@0: fprintf(stderr," %ld (=0x%04lx)", ulval, ulval); michael@0: break; michael@0: default: michael@0: cpval = (unsigned char *)template[i].pValue; michael@0: for (j=0; j < template[i].ulValueLen; j++) { michael@0: if ((j % 16) == 0) fprintf(stderr, "\n "); michael@0: fprintf(stderr," %02x",cpval[j]); michael@0: } michael@0: break; michael@0: } michael@0: fprintf(stderr,"\n"); michael@0: } michael@0: } michael@0: michael@0: PRBool michael@0: rsaKeysAreEqual(PK11ObjectType srcType, void *src, michael@0: PK11ObjectType destType, void *dest) michael@0: { michael@0: michael@0: CK_ATTRIBUTE srcTemplate[RSA_ATTRIBUTES]; michael@0: CK_ATTRIBUTE destTemplate[RSA_ATTRIBUTES]; michael@0: PRBool areEqual = PR_TRUE; michael@0: SECStatus rv; michael@0: int i; michael@0: michael@0: memcpy(srcTemplate, rsaTemplate, RSA_SIZE); michael@0: memcpy(destTemplate, rsaTemplate, RSA_SIZE); michael@0: michael@0: rv = readKey(srcType, src, srcTemplate, 0, RSA_ATTRIBUTES); michael@0: if (rv != SECSuccess) { michael@0: printf("Could read source key\n"); michael@0: return PR_FALSE; michael@0: } michael@0: readKey(destType, dest, destTemplate, 0, RSA_ATTRIBUTES); michael@0: if (rv != SECSuccess) { michael@0: printf("Could read dest key\n"); michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: for (i=0; i < RSA_ATTRIBUTES; i++) { michael@0: if (srcTemplate[i].ulValueLen != destTemplate[i].ulValueLen) { michael@0: printf("key->%s not equal src_len = %ld, dest_len=%ld\n", michael@0: ATTR_STRING(srcTemplate[i].type), michael@0: srcTemplate[i].ulValueLen, destTemplate[i].ulValueLen); michael@0: areEqual = 0; michael@0: } else if (memcmp(srcTemplate[i].pValue, destTemplate[i].pValue, michael@0: destTemplate[i].ulValueLen) != 0) { michael@0: printf("key->%s not equal.\n", ATTR_STRING(srcTemplate[i].type)); michael@0: areEqual = 0; michael@0: } michael@0: } michael@0: if (!areEqual) { michael@0: fprintf(stderr, "original key:\n"); michael@0: dumpTemplate(srcTemplate,0, RSA_ATTRIBUTES); michael@0: fprintf(stderr, "created key:\n"); michael@0: dumpTemplate(destTemplate,0, RSA_ATTRIBUTES); michael@0: } michael@0: return areEqual; michael@0: } michael@0: michael@0: static int exp_exp_prime_fail_count = 0; michael@0: michael@0: static int michael@0: doRSAPopulateTest(unsigned int keySize, unsigned long exponent, michael@0: int mask, void *pwarg) michael@0: { michael@0: SECKEYPrivateKey *rsaPrivKey; michael@0: SECKEYPublicKey *rsaPubKey; michael@0: PK11GenericObject *tstPrivKey; michael@0: CK_ATTRIBUTE tstTemplate[RSA_ATTRIBUTES]; michael@0: int tstHeaderCount; michael@0: PK11SlotInfo *slot = NULL; michael@0: PK11RSAGenParams rsaParams; michael@0: CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY; michael@0: CK_KEY_TYPE key_type = CKK_RSA; michael@0: CK_BBOOL ck_false = CK_FALSE; michael@0: int failed = 0; michael@0: michael@0: rsaParams.pe = exponent; michael@0: rsaParams.keySizeInBits = keySize; michael@0: michael@0: slot = PK11_GetInternalSlot(); michael@0: if (slot == NULL) { michael@0: fprintf(stderr, "Couldn't get the internal slot for the test \n"); michael@0: return -1; michael@0: } michael@0: michael@0: rsaPrivKey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, michael@0: &rsaParams, &rsaPubKey, PR_FALSE, michael@0: PR_FALSE, pwarg); michael@0: if (rsaPrivKey == NULL) { michael@0: fprintf(stderr, "RSA Key Gen failed"); michael@0: PK11_FreeSlot(slot); michael@0: return -1; michael@0: } michael@0: michael@0: memcpy(tstTemplate, rsaTemplate, RSA_SIZE); michael@0: michael@0: tstTemplate[0].pValue = &obj_class; michael@0: tstTemplate[0].ulValueLen = sizeof(obj_class); michael@0: tstTemplate[1].pValue = &key_type; michael@0: tstTemplate[1].ulValueLen = sizeof(key_type); michael@0: tstTemplate[2].pValue = &ck_false; michael@0: tstTemplate[2].ulValueLen = sizeof(ck_false); michael@0: tstTemplate[3].pValue = &ck_false; michael@0: tstTemplate[3].ulValueLen = sizeof(ck_false); michael@0: tstTemplate[4].pValue = &ck_false; michael@0: tstTemplate[4].ulValueLen = sizeof(ck_false); michael@0: tstHeaderCount = 5; michael@0: michael@0: if (mask & 1) { michael@0: printf("%s\n",test_array[1].description); michael@0: resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount, CKA_PUBLIC_EXPONENT); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount+1, CKA_MODULUS); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount+2, CKA_PRIME_1); michael@0: michael@0: tstPrivKey = PK11_CreateGenericObject(slot, tstTemplate, michael@0: tstHeaderCount+3, PR_FALSE); michael@0: if (tstPrivKey == NULL) { michael@0: fprintf(stderr, "RSA Populate failed: pubExp mod p\n"); michael@0: failed = 1; michael@0: } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey, michael@0: PK11_TypeGeneric, tstPrivKey)) { michael@0: fprintf(stderr, "RSA Populate key mismatch: pubExp mod p\n"); michael@0: failed = 1; michael@0: } michael@0: if (tstPrivKey) PK11_DestroyGenericObject(tstPrivKey); michael@0: } michael@0: if (mask & 2) { michael@0: printf("%s\n",test_array[2].description); michael@0: /* test the basic2 case, public exponent, modulus, prime2 */ michael@0: resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount, CKA_PUBLIC_EXPONENT); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount+1, CKA_MODULUS); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount+2, CKA_PRIME_2); michael@0: /* test with q in the prime1 position */ michael@0: tstTemplate[tstHeaderCount+2].type = CKA_PRIME_1; michael@0: michael@0: tstPrivKey = PK11_CreateGenericObject(slot, tstTemplate, michael@0: tstHeaderCount+3, PR_FALSE); michael@0: if (tstPrivKey == NULL) { michael@0: fprintf(stderr, "RSA Populate failed: pubExp mod q\n"); michael@0: failed = 1; michael@0: } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey, michael@0: PK11_TypeGeneric, tstPrivKey)) { michael@0: fprintf(stderr, "RSA Populate key mismatch: pubExp mod q\n"); michael@0: failed = 1; michael@0: } michael@0: if (tstPrivKey) PK11_DestroyGenericObject(tstPrivKey); michael@0: } michael@0: if (mask & 4) { michael@0: printf("%s\n",test_array[3].description); michael@0: /* test the medium case, private exponent, prime1, prime2 */ michael@0: resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES); michael@0: michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount, CKA_PRIVATE_EXPONENT); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount+1, CKA_PRIME_1); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount+2, CKA_PRIME_2); michael@0: /* test with p & q swapped. Underlying code should swap these back */ michael@0: tstTemplate[tstHeaderCount+2].type = CKA_PRIME_1; michael@0: tstTemplate[tstHeaderCount+1].type = CKA_PRIME_2; michael@0: michael@0: tstPrivKey = PK11_CreateGenericObject(slot, tstTemplate, michael@0: tstHeaderCount+3, PR_FALSE); michael@0: if (tstPrivKey == NULL) { michael@0: fprintf(stderr, "RSA Populate failed: privExp p q\n"); michael@0: failed = 1; michael@0: } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey, michael@0: PK11_TypeGeneric, tstPrivKey)) { michael@0: fprintf(stderr, "RSA Populate key mismatch: privExp p q\n"); michael@0: failed = 1; michael@0: } michael@0: if (tstPrivKey) PK11_DestroyGenericObject(tstPrivKey); michael@0: } michael@0: if (mask & 8) { michael@0: printf("%s\n",test_array[4].description); michael@0: /* test the advanced case, public exponent, private exponent, prime2 */ michael@0: resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount, CKA_PRIVATE_EXPONENT); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount+1, CKA_PUBLIC_EXPONENT); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount+2, CKA_PRIME_2); michael@0: michael@0: tstPrivKey = PK11_CreateGenericObject(slot, tstTemplate, michael@0: tstHeaderCount+3, PR_FALSE); michael@0: if (tstPrivKey == NULL) { michael@0: fprintf(stderr, "RSA Populate failed: pubExp privExp q\n"); michael@0: fprintf(stderr, " this is expected periodically. It means we\n"); michael@0: fprintf(stderr, " had more than one key that meets the " michael@0: "specification\n"); michael@0: exp_exp_prime_fail_count++; michael@0: } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey, michael@0: PK11_TypeGeneric, tstPrivKey)) { michael@0: fprintf(stderr, "RSA Populate key mismatch: pubExp privExp q\n"); michael@0: failed = 1; michael@0: } michael@0: if (tstPrivKey) PK11_DestroyGenericObject(tstPrivKey); michael@0: } michael@0: if (mask & 16) { michael@0: printf("%s\n",test_array[5].description); michael@0: /* test the advanced case2, public exponent, private exponent, modulus michael@0: */ michael@0: resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES); michael@0: michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount, CKA_PRIVATE_EXPONENT); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount+1, CKA_PUBLIC_EXPONENT); michael@0: copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate, michael@0: tstHeaderCount+2, CKA_MODULUS); michael@0: michael@0: tstPrivKey = PK11_CreateGenericObject(slot, tstTemplate, michael@0: tstHeaderCount+3, PR_FALSE); michael@0: if (tstPrivKey == NULL) { michael@0: fprintf(stderr, "RSA Populate failed: pubExp privExp mod\n"); michael@0: failed = 1; michael@0: } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey, michael@0: PK11_TypeGeneric, tstPrivKey)) { michael@0: fprintf(stderr, "RSA Populate key mismatch: pubExp privExp mod\n"); michael@0: failed = 1; michael@0: } michael@0: if (tstPrivKey) PK11_DestroyGenericObject(tstPrivKey); michael@0: } michael@0: michael@0: michael@0: PK11_FreeSlot(slot); michael@0: return failed ? -1 : 0; michael@0: } michael@0: michael@0: /* populate options */ michael@0: enum { michael@0: opt_Exponent = 0, michael@0: opt_KeySize, michael@0: opt_Repeat, michael@0: opt_Tests michael@0: }; michael@0: michael@0: static secuCommandFlag populate_options[] = michael@0: { michael@0: { /* opt_Exponent */ 'e', PR_TRUE, 0, PR_FALSE }, michael@0: { /* opt_KeySize */ 'k', PR_TRUE, 0, PR_FALSE }, michael@0: { /* opt_Repeat */ 'r', PR_TRUE, 0, PR_FALSE }, michael@0: { /* opt_Tests */ 't', PR_TRUE, 0, PR_FALSE }, michael@0: }; michael@0: michael@0: int michael@0: is_delimiter(char c) michael@0: { michael@0: if ((c=='+') || (c==',') || (c=='|')) { michael@0: return 1; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: int michael@0: parse_tests(char *test_string) michael@0: { michael@0: int mask = 0; michael@0: int i; michael@0: michael@0: while (*test_string) { michael@0: if (is_delimiter(*test_string)) { michael@0: test_string++; michael@0: } michael@0: for (i=0; i < test_array_size; i++) { michael@0: char *arg = test_array[i].arg; michael@0: int len = strlen(arg); michael@0: if (strncmp(test_string,arg,len) == 0) { michael@0: test_string += len; michael@0: mask |= test_array[i].mask_value; michael@0: break; michael@0: } michael@0: } michael@0: if (i == test_array_size) { michael@0: break; michael@0: } michael@0: } michael@0: return mask; michael@0: } michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: unsigned int keySize = 1024; michael@0: unsigned long exponent = 65537; michael@0: int i, repeat = 1, ret = 0; michael@0: SECStatus rv = SECFailure; michael@0: secuCommand populateArgs; michael@0: char *progName; michael@0: int mask = 0xff; michael@0: michael@0: populateArgs.numCommands = 0; michael@0: populateArgs.numOptions = sizeof(populate_options) / michael@0: sizeof(secuCommandFlag); michael@0: populateArgs.commands = NULL; michael@0: populateArgs.options = populate_options; michael@0: michael@0: progName = strrchr(argv[0], '/'); michael@0: if (!progName) michael@0: progName = strrchr(argv[0], '\\'); michael@0: progName = progName ? progName+1 : argv[0]; michael@0: michael@0: rv = NSS_NoDB_Init(NULL); michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintPRandOSError(progName); michael@0: return -1; michael@0: } michael@0: michael@0: rv = SECU_ParseCommandLine(argc, argv, progName, &populateArgs); michael@0: if (rv == SECFailure) { michael@0: fprintf(stderr, "%s: command line parsing error!\n", progName); michael@0: Usage(progName); michael@0: return -1; michael@0: } michael@0: rv = SECFailure; michael@0: michael@0: michael@0: if (populateArgs.options[opt_KeySize].activated) { michael@0: keySize = PORT_Atoi(populateArgs.options[opt_KeySize].arg); michael@0: } michael@0: if (populateArgs.options[opt_Repeat].activated) { michael@0: repeat = PORT_Atoi(populateArgs.options[opt_Repeat].arg); michael@0: } michael@0: if (populateArgs.options[opt_Exponent].activated) { michael@0: exponent = PORT_Atoi(populateArgs.options[opt_Exponent].arg); michael@0: } michael@0: if (populateArgs.options[opt_Tests].activated) { michael@0: char * test_string = populateArgs.options[opt_Tests].arg; michael@0: mask = PORT_Atoi(test_string); michael@0: if (mask == 0) { michael@0: mask = parse_tests(test_string); michael@0: } michael@0: if (mask == 0) { michael@0: Usage(progName); michael@0: return -1; michael@0: } michael@0: } michael@0: michael@0: exp_exp_prime_fail_count = 0; michael@0: for (i=0; i < repeat; i++) { michael@0: printf("Running RSA Populate test run %d\n",i); michael@0: ret = doRSAPopulateTest(keySize, exponent, mask, NULL); michael@0: if (ret != 0) { michael@0: i++; michael@0: break; michael@0: } michael@0: } michael@0: if (ret != 0) { michael@0: fprintf(stderr,"RSA Populate test round %d: FAILED\n",i); michael@0: } michael@0: if (repeat > 1) { michael@0: printf(" pub priv prime test: %d failures out of %d runs (%f %%)\n", michael@0: exp_exp_prime_fail_count, i, michael@0: (((double)exp_exp_prime_fail_count) * 100.0)/(double) i); michael@0: } michael@0: return ret; michael@0: }