tor-browser

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

sdrtest.c (12776B)


      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 /*
      6 * Test program for SDR (Secret Decoder Ring) functions.
      7 */
      8 
      9 #include "nspr.h"
     10 #include "pkcs11t.h"
     11 #include "string.h"
     12 #include "nss.h"
     13 #include "secutil.h"
     14 #include "cert.h"
     15 #include "pk11func.h"
     16 
     17 #include "plgetopt.h"
     18 #include "pk11sdr.h"
     19 #include "nssb64.h"
     20 
     21 #define DEFAULT_VALUE "Test"
     22 static const char default_value[] = { DEFAULT_VALUE };
     23 
     24 PRFileDesc *pr_stderr;
     25 PRBool verbose = PR_FALSE;
     26 
     27 static void
     28 synopsis(char *program_name)
     29 {
     30    PR_fprintf(pr_stderr,
     31               "Usage: %s [<common>] -i <input-file>\n"
     32               "       %s [<common>]  -o <output-file>\n"
     33               "       <common> [-d dir] [-v] [-t text] [-a] [-f pwfile | -p pwd] [-m aes|des3]\n",
     34               program_name, program_name);
     35 }
     36 
     37 static void
     38 short_usage(char *program_name)
     39 {
     40    PR_fprintf(pr_stderr,
     41               "Type %s -H for more detailed descriptions\n",
     42               program_name);
     43    synopsis(program_name);
     44 }
     45 
     46 static void
     47 long_usage(char *program_name)
     48 {
     49    synopsis(program_name);
     50    PR_fprintf(pr_stderr, "\nSecret Decoder Test:\n");
     51    PR_fprintf(pr_stderr,
     52               "  %-13s Read encrypted data from \"file\"\n",
     53               "-i file");
     54    PR_fprintf(pr_stderr,
     55               "  %-13s Write newly generated encrypted data to \"file\"\n",
     56               "-o file");
     57    PR_fprintf(pr_stderr,
     58               "  %-13s Use \"text\" as the plaintext for encryption and verification\n",
     59               "-t text");
     60    PR_fprintf(pr_stderr,
     61               "  %-13s Find security databases in \"dbdir\"\n",
     62               "-d dbdir");
     63    PR_fprintf(pr_stderr,
     64               "  %-13s read the password from \"pwfile\"\n",
     65               "-f pwfile");
     66    PR_fprintf(pr_stderr,
     67               "  %-13s supply \"password\" on the command line\n",
     68               "-p password");
     69    PR_fprintf(pr_stderr,
     70               "  %-13s Mechanism to use for encryption (aes or des3)\n",
     71               "-m mechanism");
     72 }
     73 
     74 int
     75 readStdin(SECItem *result)
     76 {
     77    unsigned int bufsize = 0;
     78    int cc;
     79    unsigned int wanted = 8192U;
     80 
     81    result->len = 0;
     82    result->data = NULL;
     83    do {
     84        if (bufsize < wanted) {
     85            unsigned char *tmpData = (unsigned char *)PR_Realloc(result->data, wanted);
     86            if (!tmpData) {
     87                if (verbose)
     88                    PR_fprintf(pr_stderr, "Allocation of buffer failed\n");
     89                return -1;
     90            }
     91            result->data = tmpData;
     92            bufsize = wanted;
     93        }
     94        cc = PR_Read(PR_STDIN, result->data + result->len, bufsize - result->len);
     95        if (cc > 0) {
     96            result->len += (unsigned)cc;
     97            if (result->len >= wanted)
     98                wanted *= 2;
     99        }
    100    } while (cc > 0);
    101    return cc;
    102 }
    103 
    104 int
    105 readInputFile(const char *filename, SECItem *result)
    106 {
    107    PRFileDesc *file /* = PR_OpenFile(input_file, 0) */;
    108    PRFileInfo info;
    109    PRStatus s;
    110    PRInt32 count;
    111    int retval = -1;
    112 
    113    file = PR_Open(filename, PR_RDONLY, 0);
    114    if (!file) {
    115        if (verbose)
    116            PR_fprintf(pr_stderr, "Open of file %s failed\n", filename);
    117        goto loser;
    118    }
    119 
    120    s = PR_GetOpenFileInfo(file, &info);
    121    if (s != PR_SUCCESS) {
    122        if (verbose)
    123            PR_fprintf(pr_stderr, "File info operation failed\n");
    124        goto file_loser;
    125    }
    126 
    127    result->len = info.size;
    128    result->data = (unsigned char *)PR_Malloc(result->len);
    129    if (!result->data) {
    130        if (verbose)
    131            PR_fprintf(pr_stderr, "Allocation of buffer failed\n");
    132        goto file_loser;
    133    }
    134 
    135    count = PR_Read(file, result->data, result->len);
    136    if (count != result->len) {
    137        if (verbose)
    138            PR_fprintf(pr_stderr, "Read failed\n");
    139        goto file_loser;
    140    }
    141    retval = 0;
    142 
    143 file_loser:
    144    PR_Close(file);
    145 loser:
    146    return retval;
    147 }
    148 
    149 int
    150 main(int argc, char **argv)
    151 {
    152    int retval = 0; /* 0 - test succeeded.  -1 - test failed */
    153    SECStatus rv;
    154    PLOptState *optstate;
    155    PLOptStatus optstatus;
    156    char *program_name;
    157    const char *input_file = NULL;     /* read encrypted data from here (or create) */
    158    const char *output_file = NULL;    /* write new encrypted data here */
    159    const char *value = default_value; /* Use this for plaintext */
    160    SECItem data;
    161    SECItem result = { 0, 0, 0 };
    162    SECItem text;
    163    PRBool ascii = PR_FALSE;
    164    secuPWData pwdata = { PW_NONE, 0 };
    165    CK_MECHANISM_TYPE mechanism = CKM_AES_CBC;
    166 
    167    pr_stderr = PR_STDERR;
    168    result.data = 0;
    169    text.data = 0;
    170    text.len = 0;
    171 
    172    program_name = PL_strrchr(argv[0], '/');
    173    program_name = program_name ? (program_name + 1) : argv[0];
    174 
    175    optstate = PL_CreateOptState(argc, argv, "?Had:i:o:t:vf:p:m:");
    176    if (optstate == NULL) {
    177        SECU_PrintError(program_name, "PL_CreateOptState failed");
    178        return -1;
    179    }
    180 
    181    while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
    182        switch (optstate->option) {
    183            case '?':
    184                short_usage(program_name);
    185                return retval;
    186 
    187            case 'H':
    188                long_usage(program_name);
    189                return retval;
    190 
    191            case 'a':
    192                ascii = PR_TRUE;
    193                break;
    194 
    195            case 'd':
    196                SECU_ConfigDirectory(optstate->value);
    197                break;
    198 
    199            case 'i':
    200                input_file = optstate->value;
    201                break;
    202 
    203            case 'o':
    204                output_file = optstate->value;
    205                break;
    206 
    207            case 't':
    208                value = optstate->value;
    209                break;
    210 
    211            case 'f':
    212                if (pwdata.data) {
    213                    PORT_Free(pwdata.data);
    214                    short_usage(program_name);
    215                    return -1;
    216                }
    217                pwdata.source = PW_FROMFILE;
    218                pwdata.data = PORT_Strdup(optstate->value);
    219                break;
    220 
    221            case 'p':
    222                if (pwdata.data) {
    223                    PORT_Free(pwdata.data);
    224                    short_usage(program_name);
    225                    return -1;
    226                }
    227                pwdata.source = PW_PLAINTEXT;
    228                pwdata.data = PORT_Strdup(optstate->value);
    229                break;
    230 
    231            case 'v':
    232                verbose = PR_TRUE;
    233                break;
    234 
    235            case 'm':
    236                if (!strcmp(optstate->value, "des3")) {
    237                    mechanism = CKM_DES3_CBC;
    238                } else if (strcmp(optstate->value, "aes")) {
    239                    short_usage(program_name);
    240                    return -1;
    241                }
    242                break;
    243        }
    244    }
    245    PL_DestroyOptState(optstate);
    246    if (optstatus == PL_OPT_BAD) {
    247        short_usage(program_name);
    248        return -1;
    249    }
    250    if (!output_file && !input_file && value == default_value) {
    251        short_usage(program_name);
    252        PR_fprintf(pr_stderr, "Must specify at least one of -t, -i or -o \n");
    253        return -1;
    254    }
    255 
    256    /*
    257     * Initialize the Security libraries.
    258     */
    259    PK11_SetPasswordFunc(SECU_GetModulePassword);
    260 
    261    if (output_file) {
    262        rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL));
    263    } else {
    264        rv = NSS_Init(SECU_ConfigDirectory(NULL));
    265    }
    266    if (rv != SECSuccess) {
    267        SECU_PrintError(program_name, "NSS_Init failed");
    268        retval = -1;
    269        goto prdone;
    270    }
    271 
    272    /* Convert value into an item */
    273    data.data = (unsigned char *)value;
    274    data.len = strlen(value);
    275 
    276    /* Get the encrypted result, either from the input file
    277     * or from encrypting the plaintext value
    278     */
    279    if (input_file) {
    280        if (verbose)
    281            printf("Reading data from %s\n", input_file);
    282 
    283        if (!strcmp(input_file, "-")) {
    284            retval = readStdin(&result);
    285            ascii = PR_TRUE;
    286        } else {
    287            retval = readInputFile(input_file, &result);
    288        }
    289        if (retval != 0)
    290            goto loser;
    291        if (ascii) {
    292            /* input was base64 encoded.  Decode it. */
    293            SECItem newResult = { 0, 0, 0 };
    294            SECItem *ok = NSSBase64_DecodeBuffer(NULL, &newResult,
    295                                                 (const char *)result.data, result.len);
    296            if (!ok) {
    297                SECU_PrintError(program_name, "Base 64 decode failed");
    298                retval = -1;
    299                goto loser;
    300            }
    301            SECITEM_ZfreeItem(&result, PR_FALSE);
    302            result = *ok;
    303        }
    304    } else {
    305        SECItem keyid = { 0, 0, 0 };
    306        SECItem outBuf = { 0, 0, 0 };
    307        PK11SlotInfo *slot = NULL;
    308 
    309        /* sigh, initialize the key database */
    310        slot = PK11_GetInternalKeySlot();
    311        if (slot && PK11_NeedUserInit(slot)) {
    312            switch (pwdata.source) {
    313                case PW_FROMFILE:
    314                    rv = SECU_ChangePW(slot, 0, pwdata.data);
    315                    break;
    316                case PW_PLAINTEXT:
    317                    rv = SECU_ChangePW(slot, pwdata.data, 0);
    318                    break;
    319                default:
    320                    rv = SECU_ChangePW(slot, "", 0);
    321                    break;
    322            }
    323            if (rv != SECSuccess) {
    324                SECU_PrintError(program_name, "Failed to initialize slot \"%s\"",
    325                                PK11_GetSlotName(slot));
    326                return SECFailure;
    327            }
    328        }
    329 
    330        rv = PK11SDR_EncryptWithMechanism(slot, &keyid, mechanism, &data, &result, &pwdata);
    331        if (rv != SECSuccess) {
    332            if (verbose)
    333                SECU_PrintError(program_name, "Encrypt operation failed\n");
    334            retval = -1;
    335            goto loser;
    336        }
    337 
    338        if (slot) {
    339            PK11_FreeSlot(slot);
    340        }
    341 
    342        if (verbose)
    343            printf("Encrypted result is %d bytes long\n", result.len);
    344 
    345        if (!strcmp(output_file, "-")) {
    346            ascii = PR_TRUE;
    347        }
    348 
    349        if (ascii) {
    350            /* base64 encode output. */
    351            char *newResult = NSSBase64_EncodeItem(NULL, NULL, 0, &result);
    352            if (!newResult) {
    353                SECU_PrintError(program_name, "Base 64 encode failed\n");
    354                retval = -1;
    355                goto loser;
    356            }
    357            outBuf.data = (unsigned char *)newResult;
    358            outBuf.len = strlen(newResult);
    359            if (verbose)
    360                printf("Base 64 encoded result is %d bytes long\n", outBuf.len);
    361        } else {
    362            outBuf = result;
    363        }
    364 
    365        /* -v printf("Result is %.*s\n", text.len, text.data); */
    366        if (output_file) {
    367            PRFileDesc *file;
    368            PRInt32 count;
    369 
    370            if (verbose)
    371                printf("Writing result to %s\n", output_file);
    372            if (!strcmp(output_file, "-")) {
    373                file = PR_STDOUT;
    374            } else {
    375                /* Write to file */
    376                file = PR_Open(output_file, PR_CREATE_FILE | PR_WRONLY, 0666);
    377            }
    378            if (!file) {
    379                if (verbose)
    380                    SECU_PrintError(program_name,
    381                                    "Open of output file %s failed\n",
    382                                    output_file);
    383                retval = -1;
    384                goto loser;
    385            }
    386 
    387            count = PR_Write(file, outBuf.data, outBuf.len);
    388 
    389            if (file == PR_STDOUT) {
    390                puts("");
    391            } else {
    392                PR_Close(file);
    393            }
    394 
    395            if (count != outBuf.len) {
    396                if (verbose)
    397                    SECU_PrintError(program_name, "Write failed\n");
    398                retval = -1;
    399                goto loser;
    400            }
    401            if (ascii) {
    402                free(outBuf.data);
    403            }
    404        }
    405    }
    406 
    407    /* Decrypt the value */
    408    rv = PK11SDR_Decrypt(&result, &text, &pwdata);
    409    if (rv != SECSuccess) {
    410        if (verbose)
    411            SECU_PrintError(program_name, "Decrypt operation failed\n");
    412        retval = -1;
    413        goto loser;
    414    }
    415 
    416    if (verbose)
    417        printf("Decrypted result is \"%.*s\"\n", text.len, text.data);
    418 
    419    /* Compare to required value */
    420    if (text.len != data.len || memcmp(data.data, text.data, text.len) != 0) {
    421        if (verbose)
    422            PR_fprintf(pr_stderr, "Comparison failed\n");
    423        retval = -1;
    424        goto loser;
    425    }
    426 
    427 loser:
    428    if (text.data)
    429        SECITEM_ZfreeItem(&text, PR_FALSE);
    430    if (result.data)
    431        SECITEM_ZfreeItem(&result, PR_FALSE);
    432    if (NSS_Shutdown() != SECSuccess) {
    433        exit(1);
    434    }
    435 
    436 prdone:
    437    PR_Cleanup();
    438    if (pwdata.data) {
    439        PORT_Free(pwdata.data);
    440    }
    441    return retval;
    442 }