tor-browser

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

symkeyutil.c (35905B)


      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 ** symkeyutil.c
      7 **
      8 ** utility for managing symetric keys in the database or the token
      9 **
     10 */
     11 
     12 /*
     13 * Wish List for this utility:
     14 *  1) Display and Set the CKA_ operation flags for the key.
     15 *  2) Modify existing keys
     16 *  3) Copy keys
     17 *  4) Read CKA_ID and display for keys.
     18 *  5) Option to store CKA_ID in a file on key creation.
     19 *  6) Encrypt, Decrypt, Hash, and Mac with generated keys.
     20 *  7) Use asymetric keys to wrap and unwrap keys.
     21 *  8) Derive.
     22 *  9) PBE keys.
     23 */
     24 
     25 #include <stdio.h>
     26 #include <string.h>
     27 
     28 #include "secutil.h"
     29 
     30 #include "nspr.h"
     31 
     32 #include "pk11func.h"
     33 #include "secasn1.h"
     34 #include "cert.h"
     35 #include "cryptohi.h"
     36 #include "secoid.h"
     37 #include "certdb.h"
     38 #include "nss.h"
     39 
     40 typedef struct _KeyTypes {
     41    CK_KEY_TYPE keyType;
     42    CK_MECHANISM_TYPE mechType;
     43    CK_MECHANISM_TYPE wrapMech;
     44    char *label;
     45 } KeyTypes;
     46 
     47 static KeyTypes keyArray[] = {
     48 #ifdef RECOGNIZE_ASYMETRIC_TYPES
     49    { CKK_RSA, CKM_RSA_PKCS, CKM_RSA_PKCS, "rsa" },
     50    { CKK_DSA, CKM_DSA, CKM_INVALID_MECHANISM, "dsa" },
     51    { CKK_DH, CKM_DH_PKCS_DERIVE, CKM_INVALID_MECHANISM, "dh" },
     52    { CKK_EC, CKM_ECDSA, CKM_INVALID_MECHANISM, "ec" },
     53    { CKK_X9_42_DH, CKM_X9_42_DH_DERIVE, CKM_INVALID_MECHANISM, "x9.42dh" },
     54    { CKK_KEA, CKM_KEA_KEY_DERIVE, CKM_INVALID_MECHANISM, "kea" },
     55 #endif
     56    { CKK_GENERIC_SECRET, CKM_SHA_1_HMAC, CKM_INVALID_MECHANISM, "generic" },
     57    { CKK_RC2, CKM_RC2_CBC, CKM_RC2_ECB, "rc2" },
     58    /* don't define a wrap mech for RC-4 since it's note really safe */
     59    { CKK_RC4, CKM_RC4, CKM_INVALID_MECHANISM, "rc4" },
     60    { CKK_DES, CKM_DES_CBC, CKM_DES_ECB, "des" },
     61    { CKK_DES2, CKM_DES2_KEY_GEN, CKM_DES3_ECB, "des2" },
     62    { CKK_DES3, CKM_DES3_KEY_GEN, CKM_DES3_ECB, "des3" },
     63    { CKK_CAST, CKM_CAST_CBC, CKM_CAST_ECB, "cast" },
     64    { CKK_CAST3, CKM_CAST3_CBC, CKM_CAST3_ECB, "cast3" },
     65    { CKK_CAST5, CKM_CAST5_CBC, CKM_CAST5_ECB, "cast5" },
     66    { CKK_CAST128, CKM_CAST128_CBC, CKM_CAST128_ECB, "cast128" },
     67    { CKK_RC5, CKM_RC5_CBC, CKM_RC5_ECB, "rc5" },
     68    { CKK_IDEA, CKM_IDEA_CBC, CKM_IDEA_ECB, "idea" },
     69    { CKK_SKIPJACK, CKM_SKIPJACK_CBC64, CKM_SKIPJACK_WRAP, "skipjack" },
     70    { CKK_BATON, CKM_BATON_CBC128, CKM_BATON_WRAP, "baton" },
     71    { CKK_JUNIPER, CKM_JUNIPER_CBC128, CKM_JUNIPER_WRAP, "juniper" },
     72    { CKK_CDMF, CKM_CDMF_CBC, CKM_CDMF_ECB, "cdmf" },
     73    { CKK_AES, CKM_AES_CBC, CKM_AES_ECB, "aes" },
     74    { CKK_CAMELLIA, CKM_CAMELLIA_CBC, CKM_CAMELLIA_ECB, "camellia" },
     75 };
     76 
     77 static int keyArraySize = sizeof(keyArray) / sizeof(keyArray[0]);
     78 
     79 int
     80 GetLen(PRFileDesc *fd)
     81 {
     82    PRFileInfo info;
     83 
     84    if (PR_SUCCESS != PR_GetOpenFileInfo(fd, &info)) {
     85        return -1;
     86    }
     87 
     88    return info.size;
     89 }
     90 
     91 int
     92 ReadBuf(char *inFile, SECItem *item)
     93 {
     94    int len;
     95    int ret;
     96    PRFileDesc *fd = PR_Open(inFile, PR_RDONLY, 0);
     97    if (NULL == fd) {
     98        SECU_PrintError("symkeyutil", "PR_Open failed");
     99        return -1;
    100    }
    101 
    102    len = GetLen(fd);
    103    if (len < 0) {
    104        SECU_PrintError("symkeyutil", "PR_GetOpenFileInfo failed");
    105        return -1;
    106    }
    107    item->data = (unsigned char *)PORT_Alloc(len);
    108    if (item->data == NULL) {
    109        fprintf(stderr, "Failed to allocate %d to read file %s\n", len, inFile);
    110        return -1;
    111    }
    112 
    113    ret = PR_Read(fd, item->data, item->len);
    114    if (ret < 0) {
    115        SECU_PrintError("symkeyutil", "PR_Read failed");
    116        PORT_Free(item->data);
    117        item->data = NULL;
    118        return -1;
    119    }
    120    PR_Close(fd);
    121    item->len = len;
    122    return 0;
    123 }
    124 
    125 int
    126 WriteBuf(char *inFile, SECItem *item)
    127 {
    128    int ret;
    129    PRFileDesc *fd = PR_Open(inFile, PR_WRONLY | PR_CREATE_FILE, 0x200);
    130    if (NULL == fd) {
    131        SECU_PrintError("symkeyutil", "PR_Open failed");
    132        return -1;
    133    }
    134 
    135    ret = PR_Write(fd, item->data, item->len);
    136    if (ret < 0) {
    137        SECU_PrintError("symkeyutil", "PR_Write failed");
    138        return -1;
    139    }
    140    PR_Close(fd);
    141    return 0;
    142 }
    143 
    144 CK_KEY_TYPE
    145 GetKeyTypeFromString(const char *keyString)
    146 {
    147    int i;
    148    for (i = 0; i < keyArraySize; i++) {
    149        if (PL_strcasecmp(keyString, keyArray[i].label) == 0) {
    150            return keyArray[i].keyType;
    151        }
    152    }
    153    return (CK_KEY_TYPE)-1;
    154 }
    155 
    156 CK_MECHANISM_TYPE
    157 GetKeyMechFromString(const char *keyString)
    158 {
    159    int i;
    160    for (i = 0; i < keyArraySize; i++) {
    161        if (PL_strcasecmp(keyString, keyArray[i].label) == 0) {
    162            return keyArray[i].mechType;
    163        }
    164    }
    165    return (CK_MECHANISM_TYPE)-1;
    166 }
    167 
    168 const char *
    169 GetStringFromKeyType(CK_KEY_TYPE type)
    170 {
    171    int i;
    172    for (i = 0; i < keyArraySize; i++) {
    173        if (keyArray[i].keyType == type) {
    174            return keyArray[i].label;
    175        }
    176    }
    177    return "unmatched";
    178 }
    179 
    180 CK_MECHANISM_TYPE
    181 GetWrapFromKeyType(CK_KEY_TYPE type)
    182 {
    183    int i;
    184    for (i = 0; i < keyArraySize; i++) {
    185        if (keyArray[i].keyType == type) {
    186            return keyArray[i].wrapMech;
    187        }
    188    }
    189    return CKM_INVALID_MECHANISM;
    190 }
    191 
    192 CK_MECHANISM_TYPE
    193 GetWrapMechanism(PK11SymKey *symKey)
    194 {
    195    CK_KEY_TYPE type = PK11_GetSymKeyType(symKey);
    196 
    197    return GetWrapFromKeyType(type);
    198 }
    199 
    200 int
    201 GetDigit(char c)
    202 {
    203    if (c == 0) {
    204        return -1;
    205    }
    206    if (c <= '9' && c >= '0') {
    207        return c - '0';
    208    }
    209    if (c <= 'f' && c >= 'a') {
    210        return c - 'a' + 0xa;
    211    }
    212    if (c <= 'F' && c >= 'A') {
    213        return c - 'A' + 0xa;
    214    }
    215    return -1;
    216 }
    217 
    218 char
    219 ToDigit(unsigned char c)
    220 {
    221    c = c & 0xf;
    222    if (c <= 9) {
    223        return (char)(c + '0');
    224    }
    225    return (char)(c + 'a' - 0xa);
    226 }
    227 
    228 char *
    229 BufToHex(SECItem *outbuf)
    230 {
    231    int len = outbuf->len * 2 + 1;
    232    char *string, *ptr;
    233    unsigned int i;
    234 
    235    string = PORT_Alloc(len);
    236    if (!string) {
    237        return NULL;
    238    }
    239 
    240    ptr = string;
    241    for (i = 0; i < outbuf->len; i++) {
    242        *ptr++ = ToDigit(outbuf->data[i] >> 4);
    243        *ptr++ = ToDigit(outbuf->data[i] & 0xf);
    244    }
    245    *ptr = 0;
    246    return string;
    247 }
    248 
    249 int
    250 HexToBuf(char *inString, SECItem *outbuf)
    251 {
    252    int len = strlen(inString);
    253    int outlen = len + 1 / 2;
    254    int trueLen = 0;
    255 
    256    outbuf->data = PORT_Alloc(outlen);
    257    if (!outbuf->data) {
    258        return -1;
    259    }
    260 
    261    while (*inString) {
    262        int digit1, digit2;
    263        digit1 = GetDigit(*inString++);
    264        digit2 = GetDigit(*inString++);
    265        if ((digit1 == -1) || (digit2 == -1)) {
    266            PORT_Free(outbuf->data);
    267            outbuf->data = NULL;
    268            return -1;
    269        }
    270        outbuf->data[trueLen++] = digit1 << 4 | digit2;
    271    }
    272    outbuf->len = trueLen;
    273    return 0;
    274 }
    275 
    276 void
    277 printBuf(unsigned char *data, int len)
    278 {
    279    int i;
    280 
    281    for (i = 0; i < len; i++) {
    282        printf("%02x", data[i]);
    283    }
    284 }
    285 
    286 void
    287 PrintKey(PK11SymKey *symKey)
    288 {
    289    char *name = PK11_GetSymKeyNickname(symKey);
    290    int len = PK11_GetKeyLength(symKey);
    291    int strength = PK11_GetKeyStrength(symKey, NULL);
    292    SECItem *value = NULL;
    293    CK_KEY_TYPE type = PK11_GetSymKeyType(symKey);
    294    (void)PK11_ExtractKeyValue(symKey);
    295 
    296    value = PK11_GetKeyData(symKey);
    297 
    298    printf("%-20s %3d   %4d   %10s  ", name ? name : " ", len, strength,
    299           GetStringFromKeyType(type));
    300    if (value && value->data) {
    301        printBuf(value->data, value->len);
    302    } else {
    303        printf("<restricted>");
    304    }
    305    printf("\n");
    306    PORT_Free(name);
    307 }
    308 
    309 SECStatus
    310 ListKeys(PK11SlotInfo *slot, int *printLabel, void *pwd)
    311 {
    312    PK11SymKey *keyList;
    313    SECStatus rv = PK11_Authenticate(slot, PR_FALSE, pwd);
    314    if (rv != SECSuccess) {
    315        return rv;
    316        ;
    317    }
    318 
    319    keyList = PK11_ListFixedKeysInSlot(slot, NULL, pwd);
    320    if (keyList) {
    321        if (*printLabel) {
    322            printf("     Name            Len Strength     Type    Data\n");
    323            *printLabel = 0;
    324        }
    325        printf("%s:\n", PK11_GetTokenName(slot));
    326    }
    327    while (keyList) {
    328        PK11SymKey *freeKey = keyList;
    329        PrintKey(keyList);
    330        keyList = PK11_GetNextSymKey(keyList);
    331        PK11_FreeSymKey(freeKey);
    332    }
    333    return SECSuccess;
    334 }
    335 
    336 PK11SymKey *
    337 FindKey(PK11SlotInfo *slot, char *name, SECItem *id, void *pwd)
    338 {
    339    PK11SymKey *key = NULL;
    340    SECStatus rv = PK11_Authenticate(slot, PR_FALSE, pwd);
    341 
    342    if (rv != SECSuccess) {
    343        return NULL;
    344    }
    345 
    346    if (id->data) {
    347        key = PK11_FindFixedKey(slot, CKM_INVALID_MECHANISM, id, pwd);
    348    }
    349    if (name && !key) {
    350        key = PK11_ListFixedKeysInSlot(slot, name, pwd);
    351    }
    352 
    353    if (key) {
    354        printf("Found a key\n");
    355        PrintKey(key);
    356    }
    357    return key;
    358 }
    359 
    360 PRBool
    361 IsKeyList(PK11SymKey *symKey)
    362 {
    363    return (PRBool)(PK11_GetNextSymKey(symKey) != NULL);
    364 }
    365 
    366 void
    367 FreeKeyList(PK11SymKey *symKey)
    368 {
    369    PK11SymKey *next, *current;
    370 
    371    for (current = symKey; current; current = next) {
    372        next = PK11_GetNextSymKey(current);
    373        PK11_FreeSymKey(current);
    374    }
    375    return;
    376 }
    377 
    378 static void
    379 Usage(char *progName)
    380 {
    381 #define FPS fprintf(stderr,
    382    FPS "Type %s -H for more detailed descriptions\n", progName);
    383    FPS "Usage:");
    384    FPS "\t%s -L [std_opts] [-r]\n", progName);
    385    FPS "\t%s -K [-n name] -t type [-s size] [-i id |-j id_file] [std_opts]\n", progName);
    386    FPS "\t%s -D <[-n name | -i id | -j id_file> [std_opts]\n", progName);
    387    FPS "\t%s -I [-n name] [-t type] [-i id | -j id_file] -k data_file [std_opts]\n", progName);
    388    FPS "\t%s -E  <-nname | -i id | -j id_file> [-t type] -k data_file [-r] [std_opts]\n", progName);
    389    FPS "\t%s -U [-n name] [-t type] [-i id | -j id_file] -k data_file <wrap_opts> [std_opts]\n", progName);
    390    FPS "\t%s -W <-n name | -i id | -j id_file> [-t type] -k data_file [-r] <wrap_opts> [std_opts]\n", progName);
    391    FPS "\t%s -M <-n name | -i id | -j id_file> -g target_token [std_opts]\n", progName);
    392    FPS "\t\t std_opts -> [-d certdir] [-P dbprefix] [-p password] [-f passwordFile] [-h token]\n");
    393    FPS "\t\t wrap_opts -> <-w wrap_name | -x wrap_id | -y id_file>\n");
    394    exit(1);
    395 }
    396 
    397 static void
    398 LongUsage(char *progName)
    399 {
    400    int i;
    401    FPS "%-15s List all the keys.\n", "-L");
    402    FPS "%-15s Generate a new key.\n", "-K");
    403    FPS "%-20s Specify the nickname of the new key\n",
    404    "   -n name");
    405    FPS "%-20s Specify the id in hex of the new key\n",
    406    "   -i key id");
    407    FPS "%-20s Specify a file to read the id of the new key\n",
    408    "   -j key id file");
    409    FPS "%-20s Specify the keyType of the new key\n",
    410    "   -t type");
    411    FPS "%-20s", "  valid types: ");
    412    for (i = 0; i < keyArraySize; i++) {
    413        FPS "%s%c", keyArray[i].label, i == keyArraySize-1? '\n':',');
    414    }
    415    FPS "%-20s Specify the size of the new key in bytes (required by some types)\n",
    416    "   -s size");
    417    FPS "%-15s Delete a key.\n", "-D");
    418    FPS "%-20s Specify the nickname of the key to delete\n",
    419    "   -n name");
    420    FPS "%-20s Specify the id in hex of the key to delete\n",
    421    "   -i key id");
    422    FPS "%-20s Specify a file to read the id of the key to delete\n",
    423    "   -j key id file");
    424    FPS "%-15s Import a new key from a data file.\n", "-I");
    425    FPS "%-20s Specify the data file to read the key from.\n",
    426    "   -k key file");
    427    FPS "%-20s Specify the nickname of the new key\n",
    428    "   -n name");
    429    FPS "%-20s Specify the id in hex of the new key\n",
    430    "   -i key id");
    431    FPS "%-20s Specify a file to read the id of the new key\n",
    432    "   -j key id file");
    433    FPS "%-20s Specify the keyType of the new key\n",
    434    "   -t type");
    435    FPS "%-20s", "  valid types: ");
    436    for (i = 0; i < keyArraySize; i++) {
    437        FPS "%s%c", keyArray[i].label, i == keyArraySize-1? '\n':',');
    438    }
    439    FPS "%-15s Export a key to a data file.\n", "-E");
    440    FPS "%-20s Specify the data file to write the key to.\n",
    441    "   -k key file");
    442    FPS "%-20s Specify the nickname of the key to export\n",
    443    "   -n name");
    444    FPS "%-20s Specify the id in hex of the key to export\n",
    445    "   -i key id");
    446    FPS "%-20s Specify a file to read the id of the key to export\n",
    447    "   -j key id file");
    448    FPS "%-15s Move a key to a new token.\n", "-M");
    449    FPS "%-20s Specify the nickname of the key to move\n",
    450    "   -n name");
    451    FPS "%-20s Specify the id in hex of the key to move\n",
    452    "   -i key id");
    453    FPS "%-20s Specify a file to read the id of the key to move\n",
    454    "   -j key id file");
    455    FPS "%-20s Specify the token to move the key to\n",
    456    "   -g target token");
    457    FPS "%-15s Unwrap a new key from a data file.\n", "-U");
    458    FPS "%-20s Specify the data file to read the encrypted key from.\n",
    459    "   -k key file");
    460    FPS "%-20s Specify the nickname of the new key\n",
    461    "   -n name");
    462    FPS "%-20s Specify the id in hex of the new key\n",
    463    "   -i key id");
    464    FPS "%-20s Specify a file to read the id of the new key\n",
    465    "   -j key id file");
    466    FPS "%-20s Specify the keyType of the new key\n",
    467    "   -t type");
    468    FPS "%-20s", "  valid types: ");
    469    for (i = 0; i < keyArraySize; i++) {
    470        FPS "%s%c", keyArray[i].label, i == keyArraySize-1? '\n':',');
    471    }
    472    FPS "%-20s Specify the nickname of the wrapping key\n",
    473    "   -w wrap name");
    474    FPS "%-20s Specify the id in hex of the wrapping key\n",
    475    "   -x wrap key id");
    476    FPS "%-20s Specify a file to read the id of the wrapping key\n",
    477    "   -y wrap key id file");
    478    FPS "%-15s Wrap a new key to a data file. [not yet implemented]\n", "-W");
    479    FPS "%-20s Specify the data file to write the encrypted key to.\n",
    480    "   -k key file");
    481    FPS "%-20s Specify the nickname of the key to wrap\n",
    482    "   -n name");
    483    FPS "%-20s Specify the id in hex of the key to wrap\n",
    484    "   -i key id");
    485    FPS "%-20s Specify a file to read the id of the key to wrap\n",
    486    "   -j key id file");
    487    FPS "%-20s Specify the nickname of the wrapping key\n",
    488    "   -w wrap name");
    489    FPS "%-20s Specify the id in hex of the wrapping key\n",
    490    "   -x wrap key id");
    491    FPS "%-20s Specify a file to read the id of the wrapping key\n",
    492    "   -y wrap key id file");
    493    FPS "%-15s Options valid for all commands\n", "std_opts");
    494    FPS "%-20s The directory where the NSS db's reside\n",
    495    "   -d certdir");
    496    FPS "%-20s Prefix for the NSS db's\n",
    497    "   -P db prefix");
    498    FPS "%-20s Specify password on the command line\n",
    499    "   -p password");
    500    FPS "%-20s Specify password file on the command line\n",
    501    "   -f password file");
    502    FPS "%-20s Specify token to act on\n",
    503    "   -h token");
    504    exit(1);
    505 #undef FPS
    506 }
    507 
    508 /*  Certutil commands  */
    509 enum {
    510    cmd_CreateNewKey = 0,
    511    cmd_DeleteKey,
    512    cmd_ImportKey,
    513    cmd_ExportKey,
    514    cmd_WrapKey,
    515    cmd_UnwrapKey,
    516    cmd_MoveKey,
    517    cmd_ListKeys,
    518    cmd_PrintHelp
    519 };
    520 
    521 /*  Certutil options */
    522 enum {
    523    opt_CertDir = 0,
    524    opt_PasswordFile,
    525    opt_TargetToken,
    526    opt_TokenName,
    527    opt_KeyID,
    528    opt_KeyIDFile,
    529    opt_KeyType,
    530    opt_Nickname,
    531    opt_KeyFile,
    532    opt_Password,
    533    opt_dbPrefix,
    534    opt_RW,
    535    opt_KeySize,
    536    opt_WrapKeyName,
    537    opt_WrapKeyID,
    538    opt_WrapKeyIDFile,
    539    opt_NoiseFile
    540 };
    541 
    542 static secuCommandFlag symKeyUtil_commands[] = {
    543    { /* cmd_CreateNewKey        */ 'K', PR_FALSE, 0, PR_FALSE },
    544    { /* cmd_DeleteKey           */ 'D', PR_FALSE, 0, PR_FALSE },
    545    { /* cmd_ImportKey           */ 'I', PR_FALSE, 0, PR_FALSE },
    546    { /* cmd_ExportKey           */ 'E', PR_FALSE, 0, PR_FALSE },
    547    { /* cmd_WrapKey             */ 'W', PR_FALSE, 0, PR_FALSE },
    548    { /* cmd_UnwrapKey           */ 'U', PR_FALSE, 0, PR_FALSE },
    549    { /* cmd_MoveKey             */ 'M', PR_FALSE, 0, PR_FALSE },
    550    { /* cmd_ListKeys            */ 'L', PR_FALSE, 0, PR_FALSE },
    551    { /* cmd_PrintHelp           */ 'H', PR_FALSE, 0, PR_FALSE },
    552 };
    553 
    554 static secuCommandFlag symKeyUtil_options[] = {
    555    { /* opt_CertDir             */ 'd', PR_TRUE, 0, PR_FALSE },
    556    { /* opt_PasswordFile        */ 'f', PR_TRUE, 0, PR_FALSE },
    557    { /* opt_TargetToken         */ 'g', PR_TRUE, 0, PR_FALSE },
    558    { /* opt_TokenName           */ 'h', PR_TRUE, 0, PR_FALSE },
    559    { /* opt_KeyID               */ 'i', PR_TRUE, 0, PR_FALSE },
    560    { /* opt_KeyIDFile           */ 'j', PR_TRUE, 0, PR_FALSE },
    561    { /* opt_KeyType             */ 't', PR_TRUE, 0, PR_FALSE },
    562    { /* opt_Nickname            */ 'n', PR_TRUE, 0, PR_FALSE },
    563    { /* opt_KeyFile             */ 'k', PR_TRUE, 0, PR_FALSE },
    564    { /* opt_Password            */ 'p', PR_TRUE, 0, PR_FALSE },
    565    { /* opt_dbPrefix            */ 'P', PR_TRUE, 0, PR_FALSE },
    566    { /* opt_RW                  */ 'r', PR_FALSE, 0, PR_FALSE },
    567    { /* opt_KeySize             */ 's', PR_TRUE, 0, PR_FALSE },
    568    { /* opt_WrapKeyName         */ 'w', PR_TRUE, 0, PR_FALSE },
    569    { /* opt_WrapKeyID           */ 'x', PR_TRUE, 0, PR_FALSE },
    570    { /* opt_WrapKeyIDFile       */ 'y', PR_TRUE, 0, PR_FALSE },
    571    { /* opt_NoiseFile           */ 'z', PR_TRUE, 0, PR_FALSE },
    572 };
    573 
    574 int
    575 main(int argc, char **argv)
    576 {
    577    PK11SlotInfo *slot = NULL;
    578    char *slotname = "internal";
    579    char *certPrefix = "";
    580    CK_MECHANISM_TYPE keyType = CKM_SHA_1_HMAC;
    581    int keySize = 0;
    582    char *name = NULL;
    583    char *wrapName = NULL;
    584    secuPWData pwdata = { PW_NONE, 0 };
    585    PRBool readOnly = PR_FALSE;
    586    SECItem key;
    587    SECItem keyID;
    588    SECItem wrapKeyID;
    589    int commandsEntered = 0;
    590    int commandToRun = 0;
    591    char *progName;
    592    int i;
    593    SECStatus rv = SECFailure;
    594 
    595    secuCommand symKeyUtil;
    596    symKeyUtil.numCommands = sizeof(symKeyUtil_commands) / sizeof(secuCommandFlag);
    597    symKeyUtil.numOptions = sizeof(symKeyUtil_options) / sizeof(secuCommandFlag);
    598    symKeyUtil.commands = symKeyUtil_commands;
    599    symKeyUtil.options = symKeyUtil_options;
    600 
    601    key.data = NULL;
    602    key.len = 0;
    603    keyID.data = NULL;
    604    keyID.len = 0;
    605    wrapKeyID.data = NULL;
    606    wrapKeyID.len = 0;
    607 
    608    progName = strrchr(argv[0], '/');
    609    progName = progName ? progName + 1 : argv[0];
    610 
    611    rv = SECU_ParseCommandLine(argc, argv, progName, &symKeyUtil);
    612 
    613    if (rv != SECSuccess)
    614        Usage(progName);
    615 
    616    rv = SECFailure;
    617 
    618    /* -H print help */
    619    if (symKeyUtil.commands[cmd_PrintHelp].activated)
    620        LongUsage(progName);
    621 
    622    /* -f password file, -p password */
    623    if (symKeyUtil.options[opt_PasswordFile].arg) {
    624        pwdata.source = PW_FROMFILE;
    625        pwdata.data = symKeyUtil.options[opt_PasswordFile].arg;
    626    } else if (symKeyUtil.options[opt_Password].arg) {
    627        pwdata.source = PW_PLAINTEXT;
    628        pwdata.data = symKeyUtil.options[opt_Password].arg;
    629    }
    630 
    631    /* -d directory */
    632    if (symKeyUtil.options[opt_CertDir].activated)
    633        SECU_ConfigDirectory(symKeyUtil.options[opt_CertDir].arg);
    634 
    635    /* -s key size */
    636    if (symKeyUtil.options[opt_KeySize].activated) {
    637        keySize = PORT_Atoi(symKeyUtil.options[opt_KeySize].arg);
    638    }
    639 
    640    /*  -h specify token name  */
    641    if (symKeyUtil.options[opt_TokenName].activated) {
    642        if (PL_strcmp(symKeyUtil.options[opt_TokenName].arg, "all") == 0)
    643            slotname = NULL;
    644        else
    645            slotname = PL_strdup(symKeyUtil.options[opt_TokenName].arg);
    646    }
    647 
    648    /* -t key type */
    649    if (symKeyUtil.options[opt_KeyType].activated) {
    650        keyType = GetKeyMechFromString(symKeyUtil.options[opt_KeyType].arg);
    651        if (keyType == (CK_MECHANISM_TYPE)-1) {
    652            PR_fprintf(PR_STDERR,
    653                       "%s unknown key type (%s).\n",
    654                       progName, symKeyUtil.options[opt_KeyType].arg);
    655            return 255;
    656        }
    657    }
    658 
    659    /* -k for import and unwrap, it specifies an input file to read from,
    660     * for export and wrap it specifies an output file to write to */
    661    if (symKeyUtil.options[opt_KeyFile].activated) {
    662        if (symKeyUtil.commands[cmd_ImportKey].activated ||
    663            symKeyUtil.commands[cmd_UnwrapKey].activated) {
    664            int ret = ReadBuf(symKeyUtil.options[opt_KeyFile].arg, &key);
    665            if (ret < 0) {
    666                PR_fprintf(PR_STDERR,
    667                           "%s Couldn't read key file (%s).\n",
    668                           progName, symKeyUtil.options[opt_KeyFile].arg);
    669                return 255;
    670            }
    671        }
    672    }
    673 
    674    /* -i specify the key ID */
    675    if (symKeyUtil.options[opt_KeyID].activated) {
    676        int ret = HexToBuf(symKeyUtil.options[opt_KeyID].arg, &keyID);
    677        if (ret < 0) {
    678            PR_fprintf(PR_STDERR,
    679                       "%s invalid key ID (%s).\n",
    680                       progName, symKeyUtil.options[opt_KeyID].arg);
    681            return 255;
    682        }
    683    }
    684 
    685    /* -i & -j are mutually exclusive */
    686    if ((symKeyUtil.options[opt_KeyID].activated) &&
    687        (symKeyUtil.options[opt_KeyIDFile].activated)) {
    688        PR_fprintf(PR_STDERR,
    689                   "%s -i and -j options are mutually exclusive.\n", progName);
    690        return 255;
    691    }
    692 
    693    /* -x specify the Wrap key ID */
    694    if (symKeyUtil.options[opt_WrapKeyID].activated) {
    695        int ret = HexToBuf(symKeyUtil.options[opt_WrapKeyID].arg, &wrapKeyID);
    696        if (ret < 0) {
    697            PR_fprintf(PR_STDERR,
    698                       "%s invalid key ID (%s).\n",
    699                       progName, symKeyUtil.options[opt_WrapKeyID].arg);
    700            return 255;
    701        }
    702    }
    703 
    704    /* -x & -y are mutually exclusive */
    705    if ((symKeyUtil.options[opt_KeyID].activated) &&
    706        (symKeyUtil.options[opt_KeyIDFile].activated)) {
    707        PR_fprintf(PR_STDERR,
    708                   "%s -i and -j options are mutually exclusive.\n", progName);
    709        return 255;
    710    }
    711 
    712    /* -y specify the key ID */
    713    if (symKeyUtil.options[opt_WrapKeyIDFile].activated) {
    714        int ret = ReadBuf(symKeyUtil.options[opt_WrapKeyIDFile].arg,
    715                          &wrapKeyID);
    716        if (ret < 0) {
    717            PR_fprintf(PR_STDERR,
    718                       "%s Couldn't read key ID file (%s).\n",
    719                       progName, symKeyUtil.options[opt_WrapKeyIDFile].arg);
    720            return 255;
    721        }
    722    }
    723 
    724    /*  -P certdb name prefix */
    725    if (symKeyUtil.options[opt_dbPrefix].activated)
    726        certPrefix = symKeyUtil.options[opt_dbPrefix].arg;
    727 
    728    /*  Check number of commands entered.  */
    729    commandsEntered = 0;
    730    for (i = 0; i < symKeyUtil.numCommands; i++) {
    731        if (symKeyUtil.commands[i].activated) {
    732            commandToRun = symKeyUtil.commands[i].flag;
    733            commandsEntered++;
    734        }
    735        if (commandsEntered > 1)
    736            break;
    737    }
    738    if (commandsEntered > 1) {
    739        PR_fprintf(PR_STDERR, "%s: only one command at a time!\n", progName);
    740        PR_fprintf(PR_STDERR, "You entered: ");
    741        for (i = 0; i < symKeyUtil.numCommands; i++) {
    742            if (symKeyUtil.commands[i].activated)
    743                PR_fprintf(PR_STDERR, " -%c", symKeyUtil.commands[i].flag);
    744        }
    745        PR_fprintf(PR_STDERR, "\n");
    746        return 255;
    747    }
    748    if (commandsEntered == 0) {
    749        PR_fprintf(PR_STDERR, "%s: you must enter a command!\n", progName);
    750        Usage(progName);
    751    }
    752 
    753    if (symKeyUtil.commands[cmd_ListKeys].activated ||
    754        symKeyUtil.commands[cmd_PrintHelp].activated ||
    755        symKeyUtil.commands[cmd_ExportKey].activated ||
    756        symKeyUtil.commands[cmd_WrapKey].activated) {
    757        readOnly = !symKeyUtil.options[opt_RW].activated;
    758    }
    759 
    760    if ((symKeyUtil.commands[cmd_ImportKey].activated ||
    761         symKeyUtil.commands[cmd_ExportKey].activated ||
    762         symKeyUtil.commands[cmd_WrapKey].activated ||
    763         symKeyUtil.commands[cmd_UnwrapKey].activated) &&
    764        !symKeyUtil.options[opt_KeyFile].activated) {
    765        PR_fprintf(PR_STDERR,
    766                   "%s -%c: keyfile is required for this command (-k).\n",
    767                   progName, commandToRun);
    768        return 255;
    769    }
    770 
    771    /*  -E, -D, -W, and all require -n, -i, or -j to identify the key  */
    772    if ((symKeyUtil.commands[cmd_ExportKey].activated ||
    773         symKeyUtil.commands[cmd_DeleteKey].activated ||
    774         symKeyUtil.commands[cmd_WrapKey].activated) &&
    775        !(symKeyUtil.options[opt_Nickname].activated ||
    776          symKeyUtil.options[opt_KeyID].activated ||
    777          symKeyUtil.options[opt_KeyIDFile].activated)) {
    778        PR_fprintf(PR_STDERR,
    779                   "%s -%c: nickname or id is required for this command (-n, -i, -j).\n",
    780                   progName, commandToRun);
    781        return 255;
    782    }
    783 
    784    /*  -W, -U, and all  -w, -x, or -y to identify the wrapping key  */
    785    if ((symKeyUtil.commands[cmd_WrapKey].activated ||
    786         symKeyUtil.commands[cmd_UnwrapKey].activated) &&
    787        !(symKeyUtil.options[opt_WrapKeyName].activated ||
    788          symKeyUtil.options[opt_WrapKeyID].activated ||
    789          symKeyUtil.options[opt_WrapKeyIDFile].activated)) {
    790        PR_fprintf(PR_STDERR,
    791                   "%s -%c: wrap key is required for this command (-w, -x, or -y).\n",
    792                   progName, commandToRun);
    793        return 255;
    794    }
    795 
    796    /* -M needs the target slot  (-g) */
    797    if (symKeyUtil.commands[cmd_MoveKey].activated &&
    798        !symKeyUtil.options[opt_TargetToken].activated) {
    799        PR_fprintf(PR_STDERR,
    800                   "%s -%c: target token is required for this command (-g).\n",
    801                   progName, commandToRun);
    802        return 255;
    803    }
    804 
    805    /*  Using slotname == NULL for listing keys and certs on all slots,
    806     *  but only that. */
    807    if (!(symKeyUtil.commands[cmd_ListKeys].activated) && slotname == NULL) {
    808        PR_fprintf(PR_STDERR,
    809                   "%s -%c: cannot use \"-h all\" for this command.\n",
    810                   progName, commandToRun);
    811        return 255;
    812    }
    813 
    814    name = SECU_GetOptionArg(&symKeyUtil, opt_Nickname);
    815    wrapName = SECU_GetOptionArg(&symKeyUtil, opt_WrapKeyName);
    816 
    817    PK11_SetPasswordFunc(SECU_GetModulePassword);
    818 
    819    /*  Initialize NSPR and NSS.  */
    820    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
    821    rv = NSS_Initialize(SECU_ConfigDirectory(NULL), certPrefix, certPrefix,
    822                        "secmod.db", readOnly ? NSS_INIT_READONLY : 0);
    823    if (rv != SECSuccess) {
    824        SECU_PrintPRandOSError(progName);
    825        goto shutdown;
    826    }
    827    rv = SECFailure;
    828 
    829    if (PL_strcmp(slotname, "internal") == 0)
    830        slot = PK11_GetInternalKeySlot();
    831    else if (slotname != NULL)
    832        slot = PK11_FindSlotByName(slotname);
    833 
    834    /* generating a new key */
    835    if (symKeyUtil.commands[cmd_CreateNewKey].activated) {
    836        PK11SymKey *symKey;
    837 
    838        symKey = PK11_TokenKeyGen(slot, keyType, NULL, keySize,
    839                                  NULL, PR_TRUE, &pwdata);
    840        if (!symKey) {
    841            PR_fprintf(PR_STDERR, "%s: Token Key Gen Failed\n", progName);
    842            goto shutdown;
    843        }
    844        if (symKeyUtil.options[opt_Nickname].activated) {
    845            rv = PK11_SetSymKeyNickname(symKey, name);
    846            if (rv != SECSuccess) {
    847                PK11_DeleteTokenSymKey(symKey);
    848                PK11_FreeSymKey(symKey);
    849                PR_fprintf(PR_STDERR, "%s: Couldn't set nickname on key\n",
    850                           progName);
    851                goto shutdown;
    852            }
    853        }
    854        rv = SECSuccess;
    855        PrintKey(symKey);
    856        PK11_FreeSymKey(symKey);
    857    }
    858    if (symKeyUtil.commands[cmd_DeleteKey].activated) {
    859        PK11SymKey *symKey = FindKey(slot, name, &keyID, &pwdata);
    860 
    861        if (!symKey) {
    862            char *keyName = keyID.data ? BufToHex(&keyID) : PORT_Strdup(name);
    863            PR_fprintf(PR_STDERR, "%s: Couldn't find key %s on %s\n",
    864                       progName, keyName, PK11_GetTokenName(slot));
    865            PORT_Free(keyName);
    866            goto shutdown;
    867        }
    868 
    869        rv = PK11_DeleteTokenSymKey(symKey);
    870        FreeKeyList(symKey);
    871        if (rv != SECSuccess) {
    872            PR_fprintf(PR_STDERR, "%s: Couldn't Delete Key \n", progName);
    873            goto shutdown;
    874        }
    875    }
    876    if (symKeyUtil.commands[cmd_UnwrapKey].activated) {
    877        PK11SymKey *wrapKey = FindKey(slot, wrapName, &wrapKeyID, &pwdata);
    878        PK11SymKey *symKey;
    879        CK_MECHANISM_TYPE mechanism;
    880 
    881        if (!wrapKey) {
    882            char *keyName = wrapKeyID.data ? BufToHex(&wrapKeyID)
    883                                           : PORT_Strdup(wrapName);
    884            PR_fprintf(PR_STDERR, "%s: Couldn't find key %s on %s\n",
    885                       progName, keyName, PK11_GetTokenName(slot));
    886            PORT_Free(keyName);
    887            goto shutdown;
    888        }
    889        mechanism = GetWrapMechanism(wrapKey);
    890        if (mechanism == CKM_INVALID_MECHANISM) {
    891            char *keyName = wrapKeyID.data ? BufToHex(&wrapKeyID)
    892                                           : PORT_Strdup(wrapName);
    893            PR_fprintf(PR_STDERR, "%s: %s on %s is an invalid wrapping key\n",
    894                       progName, keyName, PK11_GetTokenName(slot));
    895            PORT_Free(keyName);
    896            PK11_FreeSymKey(wrapKey);
    897            goto shutdown;
    898        }
    899 
    900        symKey = PK11_UnwrapSymKeyWithFlagsPerm(wrapKey, mechanism, NULL,
    901                                                &key, keyType, CKA_ENCRYPT, keySize, 0, PR_TRUE);
    902        PK11_FreeSymKey(wrapKey);
    903        if (!symKey) {
    904            PR_fprintf(PR_STDERR, "%s: Unwrap Key Failed\n", progName);
    905            goto shutdown;
    906        }
    907 
    908        if (symKeyUtil.options[opt_Nickname].activated) {
    909            rv = PK11_SetSymKeyNickname(symKey, name);
    910            if (rv != SECSuccess) {
    911                PR_fprintf(PR_STDERR, "%s: Couldn't set name on key\n",
    912                           progName);
    913                PK11_DeleteTokenSymKey(symKey);
    914                PK11_FreeSymKey(symKey);
    915                goto shutdown;
    916            }
    917        }
    918        rv = SECSuccess;
    919        PrintKey(symKey);
    920        PK11_FreeSymKey(symKey);
    921    }
    922 
    923 #define MAX_KEY_SIZE 4098
    924    if (symKeyUtil.commands[cmd_WrapKey].activated) {
    925        PK11SymKey *symKey = FindKey(slot, name, &keyID, &pwdata);
    926        PK11SymKey *wrapKey;
    927        CK_MECHANISM_TYPE mechanism;
    928        SECItem data;
    929        unsigned char buf[MAX_KEY_SIZE];
    930        int ret;
    931 
    932        if (!symKey) {
    933            char *keyName = keyID.data ? BufToHex(&keyID) : PORT_Strdup(name);
    934            PR_fprintf(PR_STDERR, "%s: Couldn't find key %s on %s\n",
    935                       progName, keyName, PK11_GetTokenName(slot));
    936            PORT_Free(keyName);
    937            goto shutdown;
    938        }
    939 
    940        wrapKey = FindKey(slot, wrapName, &wrapKeyID, &pwdata);
    941        if (!wrapKey) {
    942            char *keyName = wrapKeyID.data ? BufToHex(&wrapKeyID)
    943                                           : PORT_Strdup(wrapName);
    944            PR_fprintf(PR_STDERR, "%s: Couldn't find key %s on %s\n",
    945                       progName, keyName, PK11_GetTokenName(slot));
    946            PORT_Free(keyName);
    947            PK11_FreeSymKey(symKey);
    948            goto shutdown;
    949        }
    950 
    951        mechanism = GetWrapMechanism(wrapKey);
    952        if (mechanism == CKM_INVALID_MECHANISM) {
    953            char *keyName = wrapKeyID.data ? BufToHex(&wrapKeyID)
    954                                           : PORT_Strdup(wrapName);
    955            PR_fprintf(PR_STDERR, "%s: %s on %s is an invalid wrapping key\n",
    956                       progName, keyName, PK11_GetTokenName(slot));
    957            PORT_Free(keyName);
    958            PK11_FreeSymKey(symKey);
    959            PK11_FreeSymKey(wrapKey);
    960            goto shutdown;
    961        }
    962 
    963        data.data = buf;
    964        data.len = sizeof(buf);
    965        rv = PK11_WrapSymKey(mechanism, NULL, wrapKey, symKey, &data);
    966        PK11_FreeSymKey(symKey);
    967        PK11_FreeSymKey(wrapKey);
    968        if (rv != SECSuccess) {
    969            PR_fprintf(PR_STDERR, "%s: Couldn't wrap key\n", progName);
    970            goto shutdown;
    971        }
    972 
    973        /* WriteBuf outputs it's own error using SECU_PrintError */
    974        ret = WriteBuf(symKeyUtil.options[opt_KeyFile].arg, &data);
    975        if (ret < 0) {
    976            goto shutdown;
    977        }
    978    }
    979 
    980    if (symKeyUtil.commands[cmd_ImportKey].activated) {
    981        PK11SymKey *symKey = PK11_ImportSymKey(slot, keyType,
    982                                               PK11_OriginUnwrap, CKA_ENCRYPT, &key, &pwdata);
    983        if (!symKey) {
    984            PR_fprintf(PR_STDERR, "%s: Import Key Failed\n", progName);
    985            goto shutdown;
    986        }
    987        if (symKeyUtil.options[opt_Nickname].activated) {
    988            rv = PK11_SetSymKeyNickname(symKey, name);
    989            if (rv != SECSuccess) {
    990                PR_fprintf(PR_STDERR, "%s: Couldn't set name on key\n",
    991                           progName);
    992                PK11_DeleteTokenSymKey(symKey);
    993                PK11_FreeSymKey(symKey);
    994                goto shutdown;
    995            }
    996        }
    997        rv = SECSuccess;
    998        PrintKey(symKey);
    999        PK11_FreeSymKey(symKey);
   1000    }
   1001 
   1002    /*  List certs (-L)  */
   1003    if (symKeyUtil.commands[cmd_ListKeys].activated) {
   1004        int printLabel = 1;
   1005        if (slot) {
   1006            rv = ListKeys(slot, &printLabel, &pwdata);
   1007        } else {
   1008            /* loop over all the slots */
   1009            PK11SlotList *slotList = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
   1010                                                       PR_FALSE, PR_FALSE, &pwdata);
   1011            if (slotList == NULL) {
   1012                PR_fprintf(PR_STDERR, "%s: No tokens found\n", progName);
   1013            } else {
   1014                PK11SlotListElement *se;
   1015                for (se = PK11_GetFirstSafe(slotList); se;
   1016                     se = PK11_GetNextSafe(slotList, se, PR_FALSE)) {
   1017                    rv = ListKeys(se->slot, &printLabel, &pwdata);
   1018                    if (rv != SECSuccess) {
   1019                        break;
   1020                    }
   1021                }
   1022                if (se) {
   1023                    PORT_CheckSuccess(PK11_FreeSlotListElement(slotList, se));
   1024                }
   1025                PK11_FreeSlotList(slotList);
   1026            }
   1027        }
   1028    }
   1029 
   1030    /*  Move key (-M)  */
   1031    if (symKeyUtil.commands[cmd_MoveKey].activated) {
   1032        PK11SlotInfo *target;
   1033        char *targetName = symKeyUtil.options[opt_TargetToken].arg;
   1034        PK11SymKey *newKey;
   1035        PK11SymKey *symKey = FindKey(slot, name, &keyID, &pwdata);
   1036        char *keyName;
   1037 
   1038        if (!symKey) {
   1039            keyName = keyID.data ? BufToHex(&keyID) : PORT_Strdup(name);
   1040            PR_fprintf(PR_STDERR, "%s: Couldn't find key %s on %s\n",
   1041                       progName, keyName, PK11_GetTokenName(slot));
   1042            PORT_Free(keyName);
   1043            goto shutdown;
   1044        }
   1045        target = PK11_FindSlotByName(targetName);
   1046        if (!target) {
   1047            PR_fprintf(PR_STDERR, "%s: Couldn't find slot %s\n",
   1048                       progName, targetName);
   1049            goto shutdown;
   1050        }
   1051        rv = PK11_Authenticate(target, PR_FALSE, &pwdata);
   1052        if (rv != SECSuccess) {
   1053            PR_fprintf(PR_STDERR, "%s: Failed to log into %s\n",
   1054                       progName, targetName);
   1055            goto shutdown;
   1056        }
   1057        rv = SECFailure;
   1058        newKey = PK11_MoveSymKey(target, CKA_ENCRYPT, 0, PR_TRUE, symKey);
   1059        if (!newKey) {
   1060            PR_fprintf(PR_STDERR, "%s: Couldn't move the key \n", progName);
   1061            goto shutdown;
   1062        }
   1063        keyName = PK11_GetSymKeyNickname(symKey);
   1064        if (keyName) {
   1065            rv = PK11_SetSymKeyNickname(newKey, keyName);
   1066            if (rv != SECSuccess) {
   1067                PK11_DeleteTokenSymKey(newKey);
   1068                PK11_FreeSymKey(newKey);
   1069                PR_fprintf(PR_STDERR, "%s: Couldn't set nickname on key\n",
   1070                           progName);
   1071                goto shutdown;
   1072            }
   1073        }
   1074        PK11_FreeSymKey(newKey);
   1075        rv = SECSuccess;
   1076    }
   1077 
   1078 shutdown:
   1079    if (rv != SECSuccess) {
   1080        PR_fprintf(PR_STDERR, "%s: %s\n", progName,
   1081                   SECU_Strerror(PORT_GetError()));
   1082    }
   1083 
   1084    if (key.data) {
   1085        PORT_Free(key.data);
   1086    }
   1087 
   1088    if (keyID.data) {
   1089        PORT_Free(keyID.data);
   1090    }
   1091 
   1092    if (slot) {
   1093        PK11_FreeSlot(slot);
   1094    }
   1095 
   1096    if (NSS_Shutdown() != SECSuccess) {
   1097        exit(1);
   1098    }
   1099 
   1100    if (rv == SECSuccess) {
   1101        return 0;
   1102    } else {
   1103        return 255;
   1104    }
   1105 }