tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

rsapoptst.c (21736B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include "plgetopt.h"
      8 #include "nss.h"
      9 #include "secutil.h"
     10 #include "pk11table.h"
     11 #include "secmodt.h"
     12 #include "pk11pub.h"
     13 
     14 struct test_args {
     15    char *arg;
     16    int mask_value;
     17    char *description;
     18 };
     19 
     20 static const struct test_args test_array[] = {
     21    { "all", 0x1f, "run all the tests" },
     22    { "e_n_p", 0x01, "public exponent, modulus, prime1" },
     23    { "d_n_q", 0x02, "private exponent, modulus, prime2" },
     24    { "d_p_q", 0x04, "private exponent, prime1, prime2" },
     25    { "e_d_q", 0x08, "public exponent, private exponent, prime2" },
     26    { "e_d_n", 0x10, "public exponent, private exponent, modulus" }
     27 };
     28 static const int test_array_size =
     29    (sizeof(test_array) / sizeof(struct test_args));
     30 
     31 static void
     32 Usage(char *progName)
     33 {
     34    int i;
     35 #define PRINTUSAGE(subject, option, predicate) \
     36    fprintf(stderr, "%10s %s\t%s\n", subject, option, predicate);
     37    fprintf(stderr, "%s [-k keysize] [-e exp] [-r rounds] [-t tests]\n "
     38                    "Test creating RSA private keys from Partial components\n",
     39            progName);
     40    PRINTUSAGE("", "-k", "key size (in bit)");
     41    PRINTUSAGE("", "-e", "rsa public exponent");
     42    PRINTUSAGE("", "-r", "number times to repeat the test");
     43    PRINTUSAGE("", "-t", "run the specified tests");
     44    for (i = 0; i < test_array_size; i++) {
     45        PRINTUSAGE("", test_array[i].arg, test_array[i].description);
     46    }
     47    fprintf(stderr, "\n");
     48 }
     49 
     50 /*
     51 * Test the RSA populate command to see that it can really build
     52 * keys from it's components.
     53 */
     54 
     55 const static CK_ATTRIBUTE rsaTemplate[] = {
     56    { CKA_CLASS, NULL, 0 },
     57    { CKA_KEY_TYPE, NULL, 0 },
     58    { CKA_TOKEN, NULL, 0 },
     59    { CKA_SENSITIVE, NULL, 0 },
     60    { CKA_PRIVATE, NULL, 0 },
     61    { CKA_ID, NULL, 0 },
     62    { CKA_MODULUS, NULL, 0 },
     63    { CKA_PUBLIC_EXPONENT, NULL, 0 },
     64    { CKA_PRIVATE_EXPONENT, NULL, 0 },
     65    { CKA_PRIME_1, NULL, 0 },
     66    { CKA_PRIME_2, NULL, 0 },
     67    { CKA_EXPONENT_1, NULL, 0 },
     68    { CKA_EXPONENT_2, NULL, 0 },
     69    { CKA_COEFFICIENT, NULL, 0 },
     70 };
     71 
     72 #define RSA_SIZE (sizeof(rsaTemplate))
     73 #define RSA_ATTRIBUTES (sizeof(rsaTemplate) / sizeof(CK_ATTRIBUTE))
     74 
     75 static void
     76 resetTemplate(CK_ATTRIBUTE *attribute, int start, int end)
     77 {
     78    int i;
     79    for (i = start; i < end; i++) {
     80        if (attribute[i].pValue) {
     81            PORT_Free(attribute[i].pValue);
     82        }
     83        attribute[i].pValue = NULL;
     84        attribute[i].ulValueLen = 0;
     85    }
     86 }
     87 
     88 static SECStatus
     89 copyAttribute(PK11ObjectType objType, void *object, CK_ATTRIBUTE *template,
     90              int offset, CK_ATTRIBUTE_TYPE attrType)
     91 {
     92    SECItem attributeItem = { 0, 0, 0 };
     93    SECStatus rv;
     94 
     95    rv = PK11_ReadRawAttribute(objType, object, attrType, &attributeItem);
     96    if (rv != SECSuccess) {
     97        return rv;
     98    }
     99    template[offset].type = attrType;
    100    template[offset].pValue = attributeItem.data;
    101    template[offset].ulValueLen = attributeItem.len;
    102    return SECSuccess;
    103 }
    104 
    105 static SECStatus
    106 readKey(PK11ObjectType objType, void *object, CK_ATTRIBUTE *template,
    107        int start, int end)
    108 {
    109    int i;
    110    SECStatus rv;
    111 
    112    for (i = start; i < end; i++) {
    113        rv = copyAttribute(objType, object, template, i, template[i].type);
    114        if (rv != SECSuccess) {
    115            goto fail;
    116        }
    117    }
    118    return SECSuccess;
    119 
    120 fail:
    121    resetTemplate(template, start, i);
    122    return rv;
    123 }
    124 
    125 #define ATTR_STRING(x) getNameFromAttribute(x)
    126 
    127 static void
    128 dumphex(FILE *file, const unsigned char *cpval, int start, int end)
    129 {
    130    int i;
    131    for (i = start; i < end; i++) {
    132        if ((i % 16) == 0)
    133            fprintf(file, "\n ");
    134        fprintf(file, " %02x", cpval[i]);
    135    }
    136    return;
    137 }
    138 
    139 void
    140 dumpTemplate(FILE *file, const CK_ATTRIBUTE *template, int start, int end)
    141 {
    142    int i;
    143    for (i = start; i < end; i++) {
    144        unsigned char cval;
    145        CK_ULONG ulval;
    146        const unsigned char *cpval;
    147 
    148        fprintf(file, "%s:", ATTR_STRING(template[i].type));
    149        switch (template[i].ulValueLen) {
    150            case 1:
    151                cval = *(unsigned char *)template[i].pValue;
    152                switch (cval) {
    153                    case 0:
    154                        fprintf(file, " false");
    155                        break;
    156                    case 1:
    157                        fprintf(file, " true");
    158                        break;
    159                    default:
    160                        fprintf(file, " %d (=0x%02x,'%c')", cval, cval, cval);
    161                        break;
    162                }
    163                break;
    164            case sizeof(CK_ULONG):
    165                ulval = *(CK_ULONG *)template[i].pValue;
    166                fprintf(file, " %ld (=0x%04lx)", ulval, ulval);
    167                break;
    168            default:
    169                cpval = (const unsigned char *)template[i].pValue;
    170                dumphex(file, cpval, 0, template[i].ulValueLen);
    171                break;
    172        }
    173        fprintf(file, "\n");
    174    }
    175 }
    176 
    177 void
    178 dumpItem(FILE *file, const SECItem *item)
    179 {
    180    const unsigned char *cpval;
    181 
    182    if (item == NULL) {
    183        fprintf(file, " pNULL ");
    184        return;
    185    }
    186    if (item->data == NULL) {
    187        fprintf(file, " NULL ");
    188        return;
    189    }
    190    if (item->len == 0) {
    191        fprintf(file, " Empty ");
    192        return;
    193    }
    194    cpval = item->data;
    195    dumphex(file, cpval, 0, item->len);
    196    fprintf(file, " ");
    197    return;
    198 }
    199 
    200 PRBool
    201 rsaKeysAreEqual(PK11ObjectType srcType, void *src,
    202                PK11ObjectType destType, void *dest)
    203 {
    204 
    205    CK_ATTRIBUTE srcTemplate[RSA_ATTRIBUTES];
    206    CK_ATTRIBUTE destTemplate[RSA_ATTRIBUTES];
    207    PRBool areEqual = PR_TRUE;
    208    SECStatus rv;
    209    int i;
    210 
    211    memcpy(srcTemplate, rsaTemplate, RSA_SIZE);
    212    memcpy(destTemplate, rsaTemplate, RSA_SIZE);
    213 
    214    rv = readKey(srcType, src, srcTemplate, 0, RSA_ATTRIBUTES);
    215    if (rv != SECSuccess) {
    216        printf("Could read source key\n");
    217        return PR_FALSE;
    218    }
    219    rv = readKey(destType, dest, destTemplate, 0, RSA_ATTRIBUTES);
    220    if (rv != SECSuccess) {
    221        printf("Could read dest key\n");
    222        return PR_FALSE;
    223    }
    224 
    225    for (i = 0; i < RSA_ATTRIBUTES; i++) {
    226        if (srcTemplate[i].type == CKA_ID) {
    227            continue; /* we purposefully make the CKA_ID different */
    228        }
    229        if (srcTemplate[i].ulValueLen != destTemplate[i].ulValueLen) {
    230            printf("key->%s not equal src_len = %ld, dest_len=%ld\n",
    231                   ATTR_STRING(srcTemplate[i].type),
    232                   srcTemplate[i].ulValueLen, destTemplate[i].ulValueLen);
    233            areEqual = 0;
    234        } else if (memcmp(srcTemplate[i].pValue, destTemplate[i].pValue,
    235                          destTemplate[i].ulValueLen) != 0) {
    236            printf("key->%s not equal.\n", ATTR_STRING(srcTemplate[i].type));
    237            areEqual = 0;
    238        }
    239    }
    240    if (!areEqual) {
    241        fprintf(stderr, "original key:\n");
    242        dumpTemplate(stderr, srcTemplate, 0, RSA_ATTRIBUTES);
    243        fprintf(stderr, "created key:\n");
    244        dumpTemplate(stderr, destTemplate, 0, RSA_ATTRIBUTES);
    245    }
    246    resetTemplate(srcTemplate, 0, RSA_ATTRIBUTES);
    247    resetTemplate(destTemplate, 0, RSA_ATTRIBUTES);
    248    return areEqual;
    249 }
    250 
    251 static int exp_exp_prime_fail_count = 0;
    252 
    253 #define LEAK_ID 0xf
    254 
    255 static int
    256 doRSAPopulateTest(unsigned int keySize, unsigned long exponent,
    257                  int mask, int round, void *pwarg)
    258 {
    259    SECKEYPrivateKey *rsaPrivKey;
    260    SECKEYPublicKey *rsaPubKey;
    261    PK11GenericObject *tstPrivKey;
    262    CK_ATTRIBUTE tstTemplate[RSA_ATTRIBUTES];
    263    int tstHeaderCount;
    264    PK11SlotInfo *slot = NULL;
    265    PK11RSAGenParams rsaParams;
    266    CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY;
    267    CK_KEY_TYPE key_type = CKK_RSA;
    268    CK_BBOOL ck_false = CK_FALSE;
    269    CK_BYTE cka_id[2] = { 0, 0 };
    270    int failed = 0;
    271    int leak_found;      /* did we find the expected leak */
    272    int expect_leak = 0; /* are we expecting a leak? */
    273 
    274    rsaParams.pe = exponent;
    275    rsaParams.keySizeInBits = keySize;
    276 
    277    slot = PK11_GetInternalSlot();
    278    if (slot == NULL) {
    279        fprintf(stderr, "Couldn't get the internal slot for the test \n");
    280        return -1;
    281    }
    282 
    283    rsaPrivKey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
    284                                      &rsaParams, &rsaPubKey, PR_FALSE,
    285                                      PR_FALSE, pwarg);
    286    if (rsaPrivKey == NULL) {
    287        fprintf(stderr, "RSA Key Gen failed");
    288        PK11_FreeSlot(slot);
    289        return -1;
    290    }
    291 
    292    memcpy(tstTemplate, rsaTemplate, RSA_SIZE);
    293 
    294    tstTemplate[0].pValue = &obj_class;
    295    tstTemplate[0].ulValueLen = sizeof(obj_class);
    296    tstTemplate[1].pValue = &key_type;
    297    tstTemplate[1].ulValueLen = sizeof(key_type);
    298    tstTemplate[2].pValue = &ck_false;
    299    tstTemplate[2].ulValueLen = sizeof(ck_false);
    300    tstTemplate[3].pValue = &ck_false;
    301    tstTemplate[3].ulValueLen = sizeof(ck_false);
    302    tstTemplate[4].pValue = &ck_false;
    303    tstTemplate[4].ulValueLen = sizeof(ck_false);
    304    tstTemplate[5].pValue = &cka_id[0];
    305    tstTemplate[5].ulValueLen = sizeof(cka_id);
    306    tstHeaderCount = 6;
    307    cka_id[0] = round;
    308 
    309    if (mask & 1) {
    310        printf("%s\n", test_array[1].description);
    311        resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
    312        cka_id[1] = 0;
    313        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    314                      tstHeaderCount, CKA_PUBLIC_EXPONENT);
    315        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    316                      tstHeaderCount + 1, CKA_MODULUS);
    317        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    318                      tstHeaderCount + 2, CKA_PRIME_1);
    319 
    320        tstPrivKey = PK11_CreateManagedGenericObject(slot, tstTemplate,
    321                                                     tstHeaderCount +
    322                                                         3,
    323                                                     PR_FALSE);
    324        if (tstPrivKey == NULL) {
    325            fprintf(stderr, "RSA Populate failed: pubExp mod p\n");
    326            failed = 1;
    327        } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey,
    328                                    PK11_TypeGeneric, tstPrivKey)) {
    329            fprintf(stderr, "RSA Populate key mismatch: pubExp mod p\n");
    330            failed = 1;
    331        }
    332        if (tstPrivKey)
    333            PK11_DestroyGenericObject(tstPrivKey);
    334    }
    335    if (mask & 2) {
    336        printf("%s\n", test_array[2].description);
    337        /* test the basic2 case, public exponent, modulus, prime2 */
    338        resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
    339        cka_id[1] = 1;
    340        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    341                      tstHeaderCount, CKA_PUBLIC_EXPONENT);
    342        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    343                      tstHeaderCount + 1, CKA_MODULUS);
    344        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    345                      tstHeaderCount + 2, CKA_PRIME_2);
    346        /* test with q in the prime1 position */
    347        tstTemplate[tstHeaderCount + 2].type = CKA_PRIME_1;
    348 
    349        tstPrivKey = PK11_CreateManagedGenericObject(slot, tstTemplate,
    350                                                     tstHeaderCount +
    351                                                         3,
    352                                                     PR_FALSE);
    353        if (tstPrivKey == NULL) {
    354            fprintf(stderr, "RSA Populate failed: pubExp mod q\n");
    355            failed = 1;
    356        } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey,
    357                                    PK11_TypeGeneric, tstPrivKey)) {
    358            fprintf(stderr, "RSA Populate key mismatch: pubExp mod q\n");
    359            failed = 1;
    360        }
    361        if (tstPrivKey)
    362            PK11_DestroyGenericObject(tstPrivKey);
    363    }
    364    if (mask & 4) {
    365        printf("%s\n", test_array[3].description);
    366        /* test the medium case, private exponent, prime1, prime2 */
    367        resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
    368        cka_id[1] = 2;
    369 
    370        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    371                      tstHeaderCount, CKA_PRIVATE_EXPONENT);
    372        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    373                      tstHeaderCount + 1, CKA_PRIME_1);
    374        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    375                      tstHeaderCount + 2, CKA_PRIME_2);
    376        /* test with p & q swapped. Underlying code should swap these back */
    377        tstTemplate[tstHeaderCount + 2].type = CKA_PRIME_1;
    378        tstTemplate[tstHeaderCount + 1].type = CKA_PRIME_2;
    379 
    380        tstPrivKey = PK11_CreateManagedGenericObject(slot, tstTemplate,
    381                                                     tstHeaderCount +
    382                                                         3,
    383                                                     PR_FALSE);
    384        if (tstPrivKey == NULL) {
    385            fprintf(stderr, "RSA Populate failed: privExp p q\n");
    386            failed = 1;
    387        } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey,
    388                                    PK11_TypeGeneric, tstPrivKey)) {
    389            fprintf(stderr, "RSA Populate key mismatch: privExp p q\n");
    390            failed = 1;
    391        }
    392        if (tstPrivKey)
    393            PK11_DestroyGenericObject(tstPrivKey);
    394    }
    395    if (mask & 8) {
    396        printf("%s\n", test_array[4].description);
    397        /* test the advanced case, public exponent, private exponent, prime2 */
    398        resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
    399        cka_id[1] = 3;
    400        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    401                      tstHeaderCount, CKA_PRIVATE_EXPONENT);
    402        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    403                      tstHeaderCount + 1, CKA_PUBLIC_EXPONENT);
    404        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    405                      tstHeaderCount + 2, CKA_PRIME_2);
    406 
    407        tstPrivKey = PK11_CreateManagedGenericObject(slot, tstTemplate,
    408                                                     tstHeaderCount +
    409                                                         3,
    410                                                     PR_FALSE);
    411        if (tstPrivKey == NULL) {
    412            fprintf(stderr, "RSA Populate failed: pubExp privExp q\n");
    413            fprintf(stderr, " this is expected periodically. It means we\n");
    414            fprintf(stderr, " had more than one key that meets the "
    415                            "specification\n");
    416            exp_exp_prime_fail_count++;
    417        } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey,
    418                                    PK11_TypeGeneric, tstPrivKey)) {
    419            fprintf(stderr, "RSA Populate key mismatch: pubExp privExp q\n");
    420            failed = 1;
    421        }
    422        if (tstPrivKey)
    423            PK11_DestroyGenericObject(tstPrivKey);
    424    }
    425    if (mask & 0x10) {
    426        printf("%s\n", test_array[5].description);
    427        /* test the advanced case2, public exponent, private exponent, modulus
    428         */
    429        resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
    430        cka_id[1] = LEAK_ID;
    431 
    432        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    433                      tstHeaderCount, CKA_PRIVATE_EXPONENT);
    434        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    435                      tstHeaderCount + 1, CKA_PUBLIC_EXPONENT);
    436        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
    437                      tstHeaderCount + 2, CKA_MODULUS);
    438 
    439        /* purposefully use the old version. This will create a leak */
    440        tstPrivKey = PK11_CreateGenericObject(slot, tstTemplate,
    441                                              tstHeaderCount +
    442                                                  3,
    443                                              PR_FALSE);
    444        if (tstPrivKey == NULL) {
    445            fprintf(stderr, "RSA Populate failed: pubExp privExp mod\n");
    446            failed = 1;
    447        } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey,
    448                                    PK11_TypeGeneric, tstPrivKey)) {
    449            fprintf(stderr, "RSA Populate key mismatch: pubExp privExp mod\n");
    450            failed = 1;
    451        }
    452        expect_leak = 1;
    453        if (tstPrivKey)
    454            PK11_DestroyGenericObject(tstPrivKey);
    455    }
    456    resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
    457    SECKEY_DestroyPrivateKey(rsaPrivKey);
    458    SECKEY_DestroyPublicKey(rsaPubKey);
    459 
    460    /* make sure we didn't leak */
    461    leak_found = 0;
    462    tstPrivKey = PK11_FindGenericObjects(slot, CKO_PRIVATE_KEY);
    463    if (tstPrivKey) {
    464        SECStatus rv;
    465        PK11GenericObject *thisKey;
    466        int i;
    467 
    468        fprintf(stderr, "Leaking keys...\n");
    469        for (i = 0, thisKey = tstPrivKey; thisKey; i++,
    470            thisKey = PK11_GetNextGenericObject(thisKey)) {
    471            SECItem id = { 0, NULL, 0 };
    472 
    473            rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisKey,
    474                                       CKA_ID, &id);
    475            if (rv != SECSuccess) {
    476                fprintf(stderr, "Key %d: couldn't read CKA_ID: %s\n",
    477                        i, PORT_ErrorToString(PORT_GetError()));
    478                continue;
    479            }
    480            fprintf(stderr, "id = { ");
    481            dumpItem(stderr, &id);
    482            fprintf(stderr, "};");
    483            if (id.data[1] == LEAK_ID) {
    484                fprintf(stderr, " ---> leak expected\n");
    485                if (id.data[0] == round)
    486                    leak_found = 1;
    487            } else {
    488                if (id.len != sizeof(cka_id)) {
    489                    fprintf(stderr,
    490                            " ---> ERROR unexpected leak in generated key\n");
    491                } else {
    492                    fprintf(stderr,
    493                            " ---> ERROR unexpected leak in constructed key\n");
    494                }
    495                failed = 1;
    496            }
    497            SECITEM_FreeItem(&id, PR_FALSE);
    498        }
    499        PK11_DestroyGenericObjects(tstPrivKey);
    500    }
    501    if (expect_leak && !leak_found) {
    502        fprintf(stderr, "ERROR expected leak not found\n");
    503        failed = 1;
    504    }
    505 
    506    PK11_FreeSlot(slot);
    507    return failed ? -1 : 0;
    508 }
    509 
    510 /* populate options */
    511 enum {
    512    opt_Exponent = 0,
    513    opt_KeySize,
    514    opt_Repeat,
    515    opt_Tests
    516 };
    517 
    518 static secuCommandFlag populate_options[] = {
    519    { /* opt_Exponent   */ 'e', PR_TRUE, 0, PR_FALSE },
    520    { /* opt_KeySize    */ 'k', PR_TRUE, 0, PR_FALSE },
    521    { /* opt_Repeat     */ 'r', PR_TRUE, 0, PR_FALSE },
    522    { /* opt_Tests      */ 't', PR_TRUE, 0, PR_FALSE },
    523 };
    524 
    525 int
    526 is_delimiter(char c)
    527 {
    528    if ((c == '+') || (c == ',') || (c == '|')) {
    529        return 1;
    530    }
    531    return 0;
    532 }
    533 
    534 int
    535 parse_tests(char *test_string)
    536 {
    537    int mask = 0;
    538    int i;
    539 
    540    while (*test_string) {
    541        if (is_delimiter(*test_string)) {
    542            test_string++;
    543        }
    544        for (i = 0; i < test_array_size; i++) {
    545            char *arg = test_array[i].arg;
    546            int len = strlen(arg);
    547            if (strncmp(test_string, arg, len) == 0) {
    548                test_string += len;
    549                mask |= test_array[i].mask_value;
    550                break;
    551            }
    552        }
    553        if (i == test_array_size) {
    554            break;
    555        }
    556    }
    557    return mask;
    558 }
    559 
    560 int
    561 main(int argc, char **argv)
    562 {
    563    unsigned int keySize = 1024;
    564    unsigned long exponent = 65537;
    565    int i, repeat = 1, ret = 0;
    566    SECStatus rv = SECFailure;
    567    secuCommand populateArgs;
    568    char *progName;
    569    int mask = 0xff;
    570 
    571    populateArgs.numCommands = 0;
    572    populateArgs.numOptions = sizeof(populate_options) /
    573                              sizeof(secuCommandFlag);
    574    populateArgs.commands = NULL;
    575    populateArgs.options = populate_options;
    576 
    577    progName = strrchr(argv[0], '/');
    578    if (!progName)
    579        progName = strrchr(argv[0], '\\');
    580    progName = progName ? progName + 1 : argv[0];
    581 
    582    rv = NSS_NoDB_Init(NULL);
    583    if (rv != SECSuccess) {
    584        SECU_PrintPRandOSError(progName);
    585        return -1;
    586    }
    587 
    588    rv = SECU_ParseCommandLine(argc, argv, progName, &populateArgs);
    589    if (rv == SECFailure) {
    590        fprintf(stderr, "%s: command line parsing error!\n", progName);
    591        Usage(progName);
    592        return -1;
    593    }
    594    rv = SECFailure;
    595 
    596    if (populateArgs.options[opt_KeySize].activated) {
    597        keySize = PORT_Atoi(populateArgs.options[opt_KeySize].arg);
    598    }
    599    if (populateArgs.options[opt_Repeat].activated) {
    600        repeat = PORT_Atoi(populateArgs.options[opt_Repeat].arg);
    601    }
    602    if (populateArgs.options[opt_Exponent].activated) {
    603        exponent = PORT_Atoi(populateArgs.options[opt_Exponent].arg);
    604    }
    605    if (populateArgs.options[opt_Tests].activated) {
    606        char *test_string = populateArgs.options[opt_Tests].arg;
    607        mask = PORT_Atoi(test_string);
    608        if (mask == 0) {
    609            mask = parse_tests(test_string);
    610        }
    611        if (mask == 0) {
    612            Usage(progName);
    613            return -1;
    614        }
    615    }
    616 
    617    exp_exp_prime_fail_count = 0;
    618    for (i = 0; i < repeat; i++) {
    619        printf("Running RSA Populate test run %d\n", i);
    620        ret = doRSAPopulateTest(keySize, exponent, mask, i, NULL);
    621        if (ret != 0) {
    622            i++;
    623            break;
    624        }
    625    }
    626    if (ret != 0) {
    627        fprintf(stderr, "RSA Populate test round %d: FAILED\n", i);
    628    }
    629    if (repeat > 1) {
    630        printf(" pub priv prime test:  %d failures out of %d runs (%f %%)\n",
    631               exp_exp_prime_fail_count, i,
    632               (((double)exp_exp_prime_fail_count) * 100.0) / (double)i);
    633    }
    634    if (NSS_Shutdown() != SECSuccess) {
    635        fprintf(stderr, "Shutdown failed\n");
    636        ret = -1;
    637    }
    638    return ret;
    639 }