Back to index

lightning-sunbird  0.9+nobinonly
symkeyutil.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038 ** symkeyutil.c
00039 **
00040 ** utility for managing symetric keys in the database or the token
00041 **
00042 */
00043 
00044 /*
00045  * Wish List for this utility:
00046  *  1) Display and Set the CKA_ operation flags for the key.
00047  *  2) Modify existing keys
00048  *  3) Copy keys
00049  *  4) Read CKA_ID and display for keys.
00050  *  5) Option to store CKA_ID in a file on key creation.
00051  *  6) Encrypt, Decrypt, Hash, and Mac with generated keys.
00052  *  7) Use asymetric keys to wrap and unwrap keys.
00053  *  8) Derive.
00054  *  9) PBE keys.
00055  */
00056 
00057 #include <stdio.h>
00058 #include <string.h>
00059 
00060 #include "secutil.h"
00061 
00062 #include "nspr.h"
00063 
00064 #include "pk11func.h"
00065 #include "secasn1.h"
00066 #include "cert.h"
00067 #include "cryptohi.h"
00068 #include "secoid.h"
00069 #include "certdb.h"
00070 #include "nss.h"
00071 
00072 typedef struct _KeyTypes {
00073     CK_KEY_TYPE      keyType;
00074     CK_MECHANISM_TYPE mechType;
00075     CK_MECHANISM_TYPE wrapMech;
00076     char *label;
00077 } KeyTypes;
00078 
00079 static KeyTypes keyArray[] = {
00080 #ifdef RECOGNIZE_ASYMETRIC_TYPES
00081     { CKK_RSA, CKM_RSA_PKCS, CKM_RSA_PKCS, "rsa" },
00082     { CKK_DSA, CKM_DSA, CKM_INVALID_MECHANISM, "dsa" },
00083     { CKK_DH, CKM_DH_PKCS_DERIVE, CKM_INVALID_MECHANISM, "dh" },
00084     { CKK_EC, CKM_ECDSA, CKM_INVALID_MECHANISM, "ec" },
00085     { CKK_X9_42_DH, CKM_X9_42_DH_DERIVE, CKM_INVALID_MECHANISM, "x9.42dh" },
00086     { CKK_KEA, CKM_KEA_KEY_DERIVE, CKM_INVALID_MECHANISM, "kea" },
00087 #endif
00088     { CKK_GENERIC_SECRET, CKM_SHA_1_HMAC, CKM_INVALID_MECHANISM, "generic" },
00089     { CKK_RC2, CKM_RC2_CBC, CKM_RC2_ECB,"rc2" },
00090     /* don't define a wrap mech for RC-4 since it's note really safe */
00091     { CKK_RC4, CKM_RC4, CKM_INVALID_MECHANISM, "rc4" }, 
00092     { CKK_DES, CKM_DES_CBC, CKM_DES_ECB,"des" },
00093     { CKK_DES2, CKM_DES2_KEY_GEN, CKM_DES3_ECB, "des2" },
00094     { CKK_DES3, CKM_DES3_KEY_GEN, CKM_DES3_ECB, "des3" },
00095     { CKK_CAST, CKM_CAST_CBC, CKM_CAST_ECB, "cast" },
00096     { CKK_CAST3, CKM_CAST3_CBC, CKM_CAST3_ECB, "cast3" },
00097     { CKK_CAST5, CKM_CAST5_CBC, CKM_CAST5_ECB, "cast5" },
00098     { CKK_CAST128, CKM_CAST128_CBC, CKM_CAST128_ECB, "cast128" },
00099     { CKK_RC5, CKM_RC5_CBC, CKM_RC5_ECB, "rc5" },
00100     { CKK_IDEA, CKM_IDEA_CBC, CKM_IDEA_ECB, "idea" },
00101     { CKK_SKIPJACK, CKM_SKIPJACK_CBC64, CKM_SKIPJACK_WRAP, "skipjack" },
00102     { CKK_BATON, CKM_BATON_CBC128, CKM_BATON_WRAP, "baton" },
00103     { CKK_JUNIPER, CKM_JUNIPER_CBC128, CKM_JUNIPER_WRAP, "juniper" },
00104     { CKK_CDMF, CKM_CDMF_CBC, CKM_CDMF_ECB, "cdmf" },
00105     { CKK_AES, CKM_AES_CBC, CKM_AES_ECB, "aes" },
00106 };
00107 
00108 static int keyArraySize = sizeof(keyArray)/sizeof(keyArray[0]);
00109 
00110 int
00111 GetLen(PRFileDesc* fd)
00112 {
00113     PRFileInfo info;
00114 
00115     if (PR_SUCCESS != PR_GetOpenFileInfo(fd, &info)) {
00116         return -1;
00117     }
00118 
00119     return info.size;
00120 }
00121 
00122 int
00123 ReadBuf(char *inFile, SECItem *item)
00124 {
00125     int len;
00126     int ret;
00127     PRFileDesc* fd = PR_Open(inFile, PR_RDONLY, 0);
00128     if (NULL == fd) {
00129         SECU_PrintError("symkeyutil", "PR_Open failed");
00130        return -1;
00131     }
00132 
00133     len = GetLen(fd);
00134     if (len < 0) {
00135        SECU_PrintError("symkeyutil", "PR_GetOpenFileInfo failed");
00136        return -1;
00137     }
00138     item->data = (unsigned char *)PORT_Alloc(len);
00139     if (item->data == NULL) {
00140        fprintf(stderr,"Failed to allocate %d to read file %s\n",len,inFile);
00141        return -1;
00142     }
00143 
00144     ret = PR_Read(fd,item->data,item->len);
00145     if (ret < 0) {
00146        SECU_PrintError("symkeyutil", "PR_Read failed");
00147        PORT_Free(item->data);
00148        item->data = NULL;
00149        return -1;
00150     }
00151     PR_Close(fd);
00152     item->len = len;
00153     return 0;
00154 }
00155 
00156 int
00157 WriteBuf(char *inFile, SECItem *item)
00158 {
00159     int ret;
00160     PRFileDesc* fd = PR_Open(inFile, PR_WRONLY|PR_CREATE_FILE, 0x200);
00161     if (NULL == fd) {
00162         SECU_PrintError("symkeyutil", "PR_Open failed");
00163        return -1;
00164     }
00165 
00166     ret = PR_Write(fd,item->data,item->len);
00167     if (ret < 0) {
00168        SECU_PrintError("symkeyutil", "PR_Write failed");
00169        return -1;
00170     }
00171     PR_Close(fd);
00172     return 0;
00173 }
00174 
00175 CK_KEY_TYPE
00176 GetKeyTypeFromString(const char *keyString)
00177 {
00178     int i;
00179     for (i=0; i < keyArraySize; i++) {
00180        if (PL_strcasecmp(keyString,keyArray[i].label) == 0) {
00181            return keyArray[i].keyType;
00182        }
00183     }
00184     return (CK_KEY_TYPE)-1;
00185 }
00186 
00187 CK_MECHANISM_TYPE
00188 GetKeyMechFromString(const char *keyString)
00189 {
00190     int i;
00191     for (i=0; i < keyArraySize; i++) {
00192        if (PL_strcasecmp(keyString,keyArray[i].label) == 0) {
00193            return keyArray[i].mechType;
00194        }
00195     }
00196     return (CK_MECHANISM_TYPE)-1;
00197 }
00198 
00199 const char *
00200 GetStringFromKeyType(CK_KEY_TYPE type)
00201 {
00202     int i;
00203     for (i=0; i < keyArraySize; i++) {
00204        if (keyArray[i].keyType == type) {
00205            return keyArray[i].label;
00206        }
00207     }
00208     return "unmatched";
00209 }
00210 
00211 CK_MECHANISM_TYPE
00212 GetWrapFromKeyType(CK_KEY_TYPE type)
00213 {
00214     int i;
00215     for (i=0; i < keyArraySize; i++) {
00216        if (keyArray[i].keyType == type) {
00217            return keyArray[i].wrapMech;
00218        }
00219     }
00220     return CKM_INVALID_MECHANISM;
00221 }
00222 
00223 CK_MECHANISM_TYPE
00224 GetWrapMechanism(PK11SymKey *symKey)
00225 {
00226     CK_KEY_TYPE type = PK11_GetSymKeyType(symKey);
00227 
00228     return GetWrapFromKeyType(type);
00229 }
00230 
00231 int
00232 GetDigit(char c)
00233 {
00234     if (c == 0) {
00235        return -1;
00236     }
00237     if (c <= '9' && c >= '0') {
00238        return c - '0';
00239     }
00240     if (c <= 'f' && c >= 'a') {
00241        return c - 'a' + 0xa;
00242     }
00243     if (c <= 'F' && c >= 'A') {
00244        return c - 'A' + 0xa;
00245     }
00246     return -1;
00247 }
00248 
00249 char
00250 ToDigit(unsigned char c)
00251 {
00252     c = c & 0xf;
00253     if (c <= 9) {
00254        return (char) (c+'0');
00255     }
00256     return (char) (c+'a'-0xa);
00257 }
00258 
00259 char *
00260 BufToHex(SECItem *outbuf)
00261 {
00262     int len = outbuf->len * 2 +1;
00263     char *string, *ptr;
00264     unsigned int i;
00265 
00266     string = PORT_Alloc(len);
00267 
00268     ptr = string;
00269     for (i=0; i < outbuf->len; i++) {
00270        *ptr++ = ToDigit(outbuf->data[i] >> 4);
00271        *ptr++ = ToDigit(outbuf->data[i] & 0xf);
00272     }
00273     *ptr = 0;
00274     return string;
00275 }
00276 
00277 
00278 int
00279 HexToBuf(char *inString, SECItem *outbuf)
00280 {
00281     int len = strlen(inString);
00282     int outlen = len+1/2;
00283     int trueLen = 0;
00284 
00285     outbuf->data = PORT_Alloc(outlen);
00286     if (outbuf->data) {
00287        return -1;
00288     }
00289 
00290     while (*inString) {
00291        int digit1, digit2;
00292        digit1 = GetDigit(*inString++);
00293        digit2 = GetDigit(*inString++);
00294        if ((digit1 == -1) || (digit2 == -1)) {
00295            PORT_Free(outbuf->data);
00296            outbuf->data = NULL;
00297            return -1;
00298        }
00299        outbuf->data[trueLen++] = digit1 << 4 | digit2;
00300     }
00301     outbuf->len = trueLen;
00302     return 0;
00303 }
00304 
00305 void
00306 printBuf(unsigned char *data, int len)
00307 {
00308     int i;
00309 
00310     for (i=0; i < len; i++) {
00311        printf("%02x",data[i]);
00312     }
00313 }
00314 
00315 void
00316 PrintKey(PK11SymKey *symKey)
00317 {
00318     char *name = PK11_GetSymKeyNickname(symKey);
00319     int len = PK11_GetKeyLength(symKey);
00320     int strength = PK11_GetKeyStrength(symKey, NULL);
00321     SECItem *value = NULL;
00322     CK_KEY_TYPE type = PK11_GetSymKeyType(symKey);
00323     (void) PK11_ExtractKeyValue(symKey);
00324 
00325     value = PK11_GetKeyData(symKey);
00326 
00327     printf("%-20s %3d   %4d   %10s  ", name ? name: " ", len, strength, 
00328                             GetStringFromKeyType(type));
00329     if (value && value->data) {
00330        printBuf(value->data, value->len);
00331     } else {
00332        printf("<restricted>");
00333     }
00334     printf("\n");
00335 }
00336 
00337 SECStatus
00338 ListKeys(PK11SlotInfo *slot, int *printLabel, void *pwd) {
00339     PK11SymKey *keyList;
00340     SECStatus rv = PK11_Authenticate(slot, PR_FALSE, pwd);
00341     if (rv != SECSuccess) {
00342         return rv;;
00343     }
00344 
00345     keyList = PK11_ListFixedKeysInSlot(slot, NULL, pwd);
00346     if (keyList) {
00347        if (*printLabel) {
00348             printf("     Name            Len Strength     Type    Data\n");
00349            *printLabel = 0;
00350        }
00351        printf("%s:\n",PK11_GetTokenName(slot));
00352     }
00353     while (keyList) {
00354         PK11SymKey *freeKey = keyList;
00355         PrintKey(keyList);
00356         keyList = PK11_GetNextSymKey(keyList);
00357         PK11_FreeSymKey(freeKey);
00358     }
00359     return SECSuccess;
00360 }
00361 
00362 PK11SymKey *
00363 FindKey(PK11SlotInfo *slot, char *name, SECItem *id, void *pwd)
00364 {
00365     PK11SymKey *key = NULL;
00366     SECStatus rv = PK11_Authenticate(slot, PR_FALSE, pwd);
00367 
00368     if (rv != SECSuccess) {
00369        return NULL;
00370     }
00371 
00372 
00373     if (id->data) {
00374        key = PK11_FindFixedKey(slot,CKM_INVALID_MECHANISM, id, pwd);
00375     }
00376     if (name && !key) {
00377        key = PK11_ListFixedKeysInSlot(slot,name, pwd);
00378     }
00379 
00380     if (key) {
00381        printf("Found a key\n");
00382        PrintKey(key);
00383     }
00384     return key;
00385 }
00386 
00387 PRBool
00388 IsKeyList(PK11SymKey *symKey)
00389 {
00390    return (PRBool) (PK11_GetNextSymKey(symKey) != NULL);
00391 }
00392 
00393 void
00394 FreeKeyList(PK11SymKey *symKey)
00395 {
00396    PK11SymKey *next,*current;
00397 
00398    for (current = symKey; current; current = next) {
00399        next = PK11_GetNextSymKey(current);
00400        PK11_FreeSymKey(current);
00401    }
00402    return;
00403 }
00404           
00405 static void 
00406 Usage(char *progName)
00407 {
00408 #define FPS fprintf(stderr, 
00409     FPS "Type %s -H for more detailed descriptions\n", progName);
00410     FPS "Usage:");
00411     FPS "\t%s -L [std_opts] [-r]\n", progName);
00412     FPS "\t%s -K [-n name] -t type [-s size] [-i id |-j id_file] [std_opts]\n", progName);
00413     FPS "\t%s -D <[-n name | -i id | -j id_file> [std_opts]\n", progName);
00414     FPS "\t%s -I [-n name] [-t type] [-i id | -j id_file] -k data_file [std_opts]\n", progName);
00415     FPS "\t%s -E  <-nname | -i id | -j id_file> [-t type] -k data_file [-r] [std_opts]\n", progName);
00416     FPS "\t%s -U [-n name] [-t type] [-i id | -j id_file] -k data_file <wrap_opts> [std_opts]\n", progName);
00417     FPS "\t%s -W <-n name | -i id | -j id_file> [-t type] -k data_file [-r] <wrap_opts> [std_opts]\n", progName);
00418     FPS "\t%s -M <-n name | -i id | -j id_file> -g target_token [std_opts]\n", progName);
00419     FPS "\t\t std_opts -> [-d certdir] [-P dbprefix] [-p password] [-f passwordFile] [-h token]\n");
00420     FPS "\t\t wrap_opts -> <-w wrap_name | -x wrap_id | -y id_file>\n");
00421     exit(1);
00422 }
00423 
00424 static void LongUsage(char *progName)
00425 {
00426     int i;
00427     FPS "%-15s List all the keys.\n", "-L");
00428     FPS "%-15s Generate a new key.\n", "-K");
00429     FPS "%-20s Specify the nickname of the new key\n",
00430        "   -n name");
00431     FPS "%-20s Specify the id in hex of the new key\n",
00432        "   -i key id");
00433     FPS "%-20s Specify a file to read the id of the new key\n",
00434        "   -j key id file");
00435     FPS "%-20s Specify the keyType of the new key\n",
00436        "   -t type");
00437     FPS "%-20s", "  valid types: ");
00438     for (i=0; i < keyArraySize ; i++) {
00439        FPS "%s%c", keyArray[i].label, i == keyArraySize-1? '\n':',');
00440     }
00441     FPS "%-20s Specify the size of the new key in bytes (required by some types)\n",
00442        "   -s size");
00443     FPS "%-15s Delete a key.\n", "-D");
00444     FPS "%-20s Specify the nickname of the key to delete\n",
00445        "   -n name");
00446     FPS "%-20s Specify the id in hex of the key to delete\n",
00447        "   -i key id");
00448     FPS "%-20s Specify a file to read the id of the key to delete\n",
00449        "   -j key id file");
00450     FPS "%-15s Import a new key from a data file.\n", "-I");
00451     FPS "%-20s Specify the data file to read the key from.\n",
00452        "   -k key file");
00453     FPS "%-20s Specify the nickname of the new key\n",
00454        "   -n name");
00455     FPS "%-20s Specify the id in hex of the new key\n",
00456        "   -i key id");
00457     FPS "%-20s Specify a file to read the id of the new key\n",
00458        "   -j key id file");
00459     FPS "%-20s Specify the keyType of the new key\n",
00460        "   -t type");
00461     FPS "%-20s", "  valid types: ");
00462     for (i=0; i < keyArraySize ; i++) {
00463        FPS "%s%c", keyArray[i].label, i == keyArraySize-1? '\n':',');
00464     }
00465     FPS "%-15s Export a key to a data file.\n", "-E");
00466     FPS "%-20s Specify the data file to write the key to.\n",
00467        "   -k key file");
00468     FPS "%-20s Specify the nickname of the key to export\n",
00469        "   -n name");
00470     FPS "%-20s Specify the id in hex of the key to export\n",
00471        "   -i key id");
00472     FPS "%-20s Specify a file to read the id of the key to export\n",
00473        "   -j key id file");
00474     FPS "%-15s Move a key to a new token.\n", "-M");
00475     FPS "%-20s Specify the nickname of the key to move\n",
00476        "   -n name");
00477     FPS "%-20s Specify the id in hex of the key to move\n",
00478        "   -i key id");
00479     FPS "%-20s Specify a file to read the id of the key to move\n",
00480        "   -j key id file");
00481     FPS "%-20s Specify the token to move the key to\n",
00482        "   -g target token");
00483     FPS "%-15s Unwrap a new key from a data file.\n", "-U");
00484     FPS "%-20s Specify the data file to read the encrypted key from.\n",
00485        "   -k key file");
00486     FPS "%-20s Specify the nickname of the new key\n",
00487        "   -n name");
00488     FPS "%-20s Specify the id in hex of the new key\n",
00489        "   -i key id");
00490     FPS "%-20s Specify a file to read the id of the new key\n",
00491        "   -j key id file");
00492     FPS "%-20s Specify the keyType of the new key\n",
00493        "   -t type");
00494     FPS "%-20s", "  valid types: ");
00495     for (i=0; i < keyArraySize ; i++) {
00496        FPS "%s%c", keyArray[i].label, i == keyArraySize-1? '\n':',');
00497     }
00498     FPS "%-20s Specify the nickname of the wrapping key\n",
00499        "   -w wrap name");
00500     FPS "%-20s Specify the id in hex of the wrapping key\n",
00501        "   -x wrap key id");
00502     FPS "%-20s Specify a file to read the id of the wrapping key\n",
00503        "   -y wrap key id file");
00504     FPS "%-15s Wrap a new key to a data file. [not yet implemented]\n", "-W");
00505     FPS "%-20s Specify the data file to write the encrypted key to.\n",
00506        "   -k key file");
00507     FPS "%-20s Specify the nickname of the key to wrap\n",
00508        "   -n name");
00509     FPS "%-20s Specify the id in hex of the key to wrap\n",
00510        "   -i key id");
00511     FPS "%-20s Specify a file to read the id of the key to wrap\n",
00512        "   -j key id file");
00513     FPS "%-20s Specify the nickname of the wrapping key\n",
00514        "   -w wrap name");
00515     FPS "%-20s Specify the id in hex of the wrapping key\n",
00516        "   -x wrap key id");
00517     FPS "%-20s Specify a file to read the id of the wrapping key\n",
00518        "   -y wrap key id file");
00519     FPS "%-15s Options valid for all commands\n", "std_opts");
00520     FPS "%-20s The directory where the NSS db's reside\n",
00521        "   -d certdir");
00522     FPS "%-20s Prefix for the NSS db's\n",
00523        "   -P db prefix");
00524     FPS "%-20s Specify password on the command line\n",
00525        "   -p password");
00526     FPS "%-20s Specify password file on the command line\n",
00527        "   -f password file");
00528     FPS "%-20s Specify token to act on\n",
00529        "   -h token");
00530     exit(1);
00531 #undef FPS
00532 }
00533 
00534 /*  Certutil commands  */
00535 enum {
00536     cmd_CreateNewKey = 0,
00537     cmd_DeleteKey,
00538     cmd_ImportKey,
00539     cmd_ExportKey,
00540     cmd_WrapKey,
00541     cmd_UnwrapKey,
00542     cmd_MoveKey,
00543     cmd_ListKeys,
00544     cmd_PrintHelp
00545 };
00546 
00547 /*  Certutil options */
00548 enum {
00549     opt_CertDir = 0,
00550     opt_PasswordFile,
00551     opt_TargetToken,
00552     opt_TokenName,
00553     opt_KeyID,
00554     opt_KeyIDFile,
00555     opt_KeyType,
00556     opt_Nickname,
00557     opt_KeyFile,
00558     opt_Password,
00559     opt_dbPrefix,
00560     opt_RW,
00561     opt_KeySize,
00562     opt_WrapKeyName,
00563     opt_WrapKeyID,
00564     opt_WrapKeyIDFile,
00565     opt_NoiseFile
00566 };
00567 
00568 static secuCommandFlag symKeyUtil_commands[] =
00569 {
00570        { /* cmd_CreateNewKey        */  'K', PR_FALSE, 0, PR_FALSE },
00571        { /* cmd_DeleteKey           */  'D', PR_FALSE, 0, PR_FALSE },
00572        { /* cmd_ImportKey           */  'I', PR_FALSE, 0, PR_FALSE },
00573        { /* cmd_ExportKey           */  'E', PR_FALSE, 0, PR_FALSE },
00574        { /* cmd_WrapKey             */  'W', PR_FALSE, 0, PR_FALSE },
00575        { /* cmd_UnwrapKey           */  'U', PR_FALSE, 0, PR_FALSE },
00576        { /* cmd_MoveKey             */  'M', PR_FALSE, 0, PR_FALSE },
00577        { /* cmd_ListKeys            */  'L', PR_FALSE, 0, PR_FALSE },
00578        { /* cmd_PrintHelp           */  'H', PR_FALSE, 0, PR_FALSE },
00579 };
00580 
00581 static secuCommandFlag symKeyUtil_options[] =
00582 {
00583        { /* opt_CertDir             */  'd', PR_TRUE,  0, PR_FALSE },
00584        { /* opt_PasswordFile        */  'f', PR_TRUE,  0, PR_FALSE },
00585        { /* opt_TargetToken         */  'g', PR_TRUE,  0, PR_FALSE },
00586        { /* opt_TokenName           */  'h', PR_TRUE,  0, PR_FALSE },
00587        { /* opt_KeyID               */  'i', PR_TRUE,  0, PR_FALSE },
00588        { /* opt_KeyIDFile           */  'j', PR_TRUE,  0, PR_FALSE },
00589        { /* opt_KeyType             */  't', PR_TRUE,  0, PR_FALSE },
00590        { /* opt_Nickname            */  'n', PR_TRUE,  0, PR_FALSE },
00591        { /* opt_KeyFile             */  'k', PR_TRUE,  0, PR_FALSE },
00592        { /* opt_Password            */  'p', PR_TRUE,  0, PR_FALSE },
00593        { /* opt_dbPrefix            */  'P', PR_TRUE,  0, PR_FALSE },
00594        { /* opt_RW                  */  'r', PR_FALSE, 0, PR_FALSE },
00595        { /* opt_KeySize             */  's', PR_TRUE,  0, PR_FALSE },
00596        { /* opt_WrapKeyName         */  'w', PR_TRUE,  0, PR_FALSE },
00597        { /* opt_WrapKeyID           */  'x', PR_TRUE,  0, PR_FALSE },
00598        { /* opt_WrapKeyIDFile       */  'y', PR_TRUE,  0, PR_FALSE },
00599        { /* opt_NoiseFile           */  'z', PR_TRUE,  0, PR_FALSE },
00600 };
00601 
00602 int 
00603 main(int argc, char **argv)
00604 {
00605     PK11SlotInfo *slot = NULL;
00606     char *      slotname        = "internal";
00607     char *      certPrefix      = "";
00608     CK_MECHANISM_TYPE keyType   = CKM_SHA_1_HMAC;
00609     int         keySize            = 0;
00610     char *      name            = NULL;
00611     char *      wrapName        = NULL;
00612     secuPWData  pwdata          = { PW_NONE, 0 };
00613     PRBool    readOnly      = PR_FALSE;
00614     SECItem   key;
00615     SECItem   keyID;
00616     SECItem   wrapKeyID;
00617     int commandsEntered = 0;
00618     int commandToRun = 0;
00619     char *progName;
00620     int i;
00621     SECStatus rv = SECFailure;
00622 
00623     secuCommand symKeyUtil;
00624     symKeyUtil.numCommands=sizeof(symKeyUtil_commands)/sizeof(secuCommandFlag);
00625     symKeyUtil.numOptions=sizeof(symKeyUtil_options)/sizeof(secuCommandFlag);
00626     symKeyUtil.commands = symKeyUtil_commands;
00627     symKeyUtil.options = symKeyUtil_options;
00628 
00629     key.data = NULL; key.len = 0;
00630     keyID.data = NULL; keyID.len = 0;
00631     wrapKeyID.data = NULL; wrapKeyID.len = 0;
00632 
00633     progName = strrchr(argv[0], '/');
00634     progName = progName ? progName+1 : argv[0];
00635 
00636     rv = SECU_ParseCommandLine(argc, argv, progName, &symKeyUtil);
00637 
00638     if (rv != SECSuccess)
00639        Usage(progName);
00640 
00641     rv = SECFailure;
00642 
00643     /* -H print help */
00644     if (symKeyUtil.commands[cmd_PrintHelp].activated)
00645        LongUsage(progName);
00646 
00647     /* -f password file, -p password */
00648     if (symKeyUtil.options[opt_PasswordFile].arg) {
00649        pwdata.source = PW_FROMFILE;
00650        pwdata.data = symKeyUtil.options[opt_PasswordFile].arg;
00651     } else if (symKeyUtil.options[opt_Password].arg) {
00652        pwdata.source = PW_PLAINTEXT;
00653        pwdata.data = symKeyUtil.options[opt_Password].arg;
00654     } 
00655 
00656     /* -d directory */
00657     if (symKeyUtil.options[opt_CertDir].activated)
00658        SECU_ConfigDirectory(symKeyUtil.options[opt_CertDir].arg);
00659 
00660     /* -s key size */
00661     if (symKeyUtil.options[opt_KeySize].activated) {
00662        keySize = PORT_Atoi(symKeyUtil.options[opt_KeySize].arg);
00663     }
00664 
00665     /*  -h specify token name  */
00666     if (symKeyUtil.options[opt_TokenName].activated) {
00667        if (PL_strcmp(symKeyUtil.options[opt_TokenName].arg, "all") == 0)
00668            slotname = NULL;
00669        else
00670            slotname = PL_strdup(symKeyUtil.options[opt_TokenName].arg);
00671     }
00672 
00673     /* -t key type */
00674     if  (symKeyUtil.options[opt_KeyType].activated) {
00675        keyType = GetKeyMechFromString(symKeyUtil.options[opt_KeyType].arg);
00676        if (keyType == (CK_MECHANISM_TYPE)-1) {
00677            PR_fprintf(PR_STDERR, 
00678                  "%s unknown key type (%s).\n",
00679                   progName, symKeyUtil.options[opt_KeyType].arg);
00680            return 255;
00681        }
00682     }
00683 
00684     /* -k for import and unwrap, it specifies an input file to read from,
00685      * for export and wrap it specifies an output file to write to */
00686     if (symKeyUtil.options[opt_KeyFile].activated) {
00687         if (symKeyUtil.commands[cmd_ImportKey].activated ||
00688               symKeyUtil.commands[cmd_UnwrapKey].activated ) {
00689            int ret = ReadBuf(symKeyUtil.options[opt_KeyFile].arg, &key);
00690            if (ret < 0) {
00691                PR_fprintf(PR_STDERR, 
00692                  "%s Couldn't read key file (%s).\n",
00693                   progName, symKeyUtil.options[opt_KeyFile].arg);
00694               return 255;
00695            }
00696        }
00697     }
00698 
00699     /* -i specify the key ID */
00700     if (symKeyUtil.options[opt_KeyID].activated) {
00701        int ret = HexToBuf(symKeyUtil.options[opt_KeyID].arg, &keyID);
00702        if (ret < 0) {
00703            PR_fprintf(PR_STDERR, 
00704                  "%s invalid key ID (%s).\n",
00705                   progName, symKeyUtil.options[opt_KeyID].arg);
00706            return 255;
00707        }
00708     }
00709 
00710     /* -i & -j are mutually exclusive */
00711     if ((symKeyUtil.options[opt_KeyID].activated) &&
00712                (symKeyUtil.options[opt_KeyIDFile].activated)) {
00713        PR_fprintf(PR_STDERR, 
00714                  "%s -i and -j options are mutually exclusive.\n", progName);
00715        return 255;
00716     }
00717 
00718     /* -x specify the Wrap key ID */
00719     if (symKeyUtil.options[opt_WrapKeyID].activated) {
00720        int ret = HexToBuf(symKeyUtil.options[opt_WrapKeyID].arg, &wrapKeyID);
00721        if (ret < 0) {
00722            PR_fprintf(PR_STDERR, 
00723                  "%s invalid key ID (%s).\n",
00724                   progName, symKeyUtil.options[opt_WrapKeyID].arg);
00725            return 255;
00726        }
00727     }
00728 
00729     /* -x & -y are mutually exclusive */
00730     if ((symKeyUtil.options[opt_KeyID].activated) &&
00731                (symKeyUtil.options[opt_KeyIDFile].activated)) {
00732        PR_fprintf(PR_STDERR, 
00733                  "%s -i and -j options are mutually exclusive.\n", progName);
00734        return 255;
00735     }
00736        
00737 
00738     /* -y specify the key ID */
00739     if (symKeyUtil.options[opt_WrapKeyIDFile].activated) {
00740        int ret = ReadBuf(symKeyUtil.options[opt_WrapKeyIDFile].arg,
00741                                                          &wrapKeyID);
00742        if (ret < 0) {
00743            PR_fprintf(PR_STDERR, 
00744                  "%s Couldn't read key ID file (%s).\n",
00745                   progName, symKeyUtil.options[opt_WrapKeyIDFile].arg);
00746            return 255;
00747        }
00748     }
00749 
00750     /*  -P certdb name prefix */
00751     if (symKeyUtil.options[opt_dbPrefix].activated)
00752        certPrefix = strdup(symKeyUtil.options[opt_dbPrefix].arg);
00753 
00754     /*  Check number of commands entered.  */
00755     commandsEntered = 0;
00756     for (i=0; i< symKeyUtil.numCommands; i++) {
00757        if (symKeyUtil.commands[i].activated) {
00758            commandToRun = symKeyUtil.commands[i].flag;
00759            commandsEntered++;
00760        }
00761        if (commandsEntered > 1)
00762            break;
00763     }
00764     if (commandsEntered > 1) {
00765        PR_fprintf(PR_STDERR, "%s: only one command at a time!\n", progName);
00766        PR_fprintf(PR_STDERR, "You entered: ");
00767        for (i=0; i< symKeyUtil.numCommands; i++) {
00768            if (symKeyUtil.commands[i].activated)
00769               PR_fprintf(PR_STDERR, " -%c", symKeyUtil.commands[i].flag);
00770        }
00771        PR_fprintf(PR_STDERR, "\n");
00772        return 255;
00773     }
00774     if (commandsEntered == 0) {
00775        PR_fprintf(PR_STDERR, "%s: you must enter a command!\n", progName);
00776        Usage(progName);
00777     }
00778 
00779     if (symKeyUtil.commands[cmd_ListKeys].activated ||
00780          symKeyUtil.commands[cmd_PrintHelp].activated ||
00781          symKeyUtil.commands[cmd_ExportKey].activated ||
00782          symKeyUtil.commands[cmd_WrapKey].activated) {
00783        readOnly = !symKeyUtil.options[opt_RW].activated;
00784     }
00785 
00786     if ((symKeyUtil.commands[cmd_ImportKey].activated ||
00787          symKeyUtil.commands[cmd_ExportKey].activated ||
00788          symKeyUtil.commands[cmd_WrapKey].activated ||
00789          symKeyUtil.commands[cmd_UnwrapKey].activated ) &&
00790         !symKeyUtil.options[opt_KeyFile].activated) {
00791        PR_fprintf(PR_STDERR, 
00792                  "%s -%c: keyfile is required for this command (-k).\n",
00793                   progName, commandToRun);
00794        return 255;
00795     }
00796 
00797     /*  -E, -D, -W, and all require -n, -i, or -j to identify the key  */
00798     if ((symKeyUtil.commands[cmd_ExportKey].activated ||
00799          symKeyUtil.commands[cmd_DeleteKey].activated ||
00800          symKeyUtil.commands[cmd_WrapKey].activated) &&
00801         !(symKeyUtil.options[opt_Nickname].activated ||
00802          symKeyUtil.options[opt_KeyID].activated ||
00803          symKeyUtil.options[opt_KeyIDFile].activated)) {
00804        PR_fprintf(PR_STDERR, 
00805          "%s -%c: nickname or id is required for this command (-n, -i, -j).\n",
00806                   progName, commandToRun);
00807        return 255;
00808     }
00809 
00810     /*  -W, -U, and all  -w, -x, or -y to identify the wrapping key  */
00811     if (( symKeyUtil.commands[cmd_WrapKey].activated ||
00812          symKeyUtil.commands[cmd_UnwrapKey].activated) &&
00813         !(symKeyUtil.options[opt_WrapKeyName].activated ||
00814          symKeyUtil.options[opt_WrapKeyID].activated ||
00815          symKeyUtil.options[opt_WrapKeyIDFile].activated)) {
00816        PR_fprintf(PR_STDERR, 
00817          "%s -%c: wrap key is required for this command (-w, -x, or -y).\n",
00818                   progName, commandToRun);
00819        return 255;
00820     }
00821 
00822     /* -M needs the target slot  (-g) */
00823     if (symKeyUtil.commands[cmd_MoveKey].activated  &&
00824                      !symKeyUtil.options[opt_TargetToken].activated) {
00825        PR_fprintf(PR_STDERR, 
00826                  "%s -%c: target token is required for this command (-g).\n",
00827                   progName, commandToRun);
00828        return 255;
00829     }
00830 
00831     /*  Using slotname == NULL for listing keys and certs on all slots, 
00832      *  but only that. */
00833     if (!(symKeyUtil.commands[cmd_ListKeys].activated) && slotname == NULL) {
00834        PR_fprintf(PR_STDERR,
00835                   "%s -%c: cannot use \"-h all\" for this command.\n",
00836                   progName, commandToRun);
00837        return 255;
00838     }
00839 
00840     name = SECU_GetOptionArg(&symKeyUtil, opt_Nickname);
00841     wrapName = SECU_GetOptionArg(&symKeyUtil, opt_WrapKeyName);
00842 
00843     PK11_SetPasswordFunc(SECU_GetModulePassword);
00844 
00845     /*  Initialize NSPR and NSS.  */
00846     PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
00847     rv = NSS_Initialize(SECU_ConfigDirectory(NULL), certPrefix, certPrefix,
00848                         "secmod.db", readOnly ? NSS_INIT_READONLY: 0);
00849     if (rv != SECSuccess) {
00850        SECU_PrintPRandOSError(progName);
00851        goto shutdown;
00852     }
00853     rv = SECFailure;
00854 
00855     if (PL_strcmp(slotname, "internal") == 0)
00856        slot = PK11_GetInternalKeySlot();
00857     else if (slotname != NULL)
00858        slot = PK11_FindSlotByName(slotname);
00859 
00860     /* generating a new key */
00861     if (symKeyUtil.commands[cmd_CreateNewKey].activated)  {
00862        PK11SymKey *symKey;
00863 
00864        symKey = PK11_TokenKeyGen(slot, keyType, NULL, keySize, 
00865                                                  NULL, PR_TRUE, &pwdata);
00866        if (!symKey) {
00867            PR_fprintf(PR_STDERR, "%s: Token Key Gen Failed\n", progName);
00868            goto shutdown;
00869        }
00870        if (symKeyUtil.options[opt_Nickname].activated) {
00871            rv = PK11_SetSymKeyNickname(symKey, name);
00872            if (rv != SECSuccess) {
00873               PK11_DeleteTokenSymKey(symKey);
00874               PK11_FreeSymKey(symKey);
00875                PR_fprintf(PR_STDERR, "%s: Couldn't set nickname on key\n",
00876                                                          progName);
00877               goto shutdown;
00878            }
00879        }
00880        rv = SECSuccess;
00881        PrintKey(symKey);
00882        PK11_FreeSymKey(symKey);
00883     }
00884     if (symKeyUtil.commands[cmd_DeleteKey].activated) {
00885        PK11SymKey *symKey = FindKey(slot,name,&keyID,&pwdata);
00886 
00887        if (!symKey) {
00888            char *keyName = keyID.data ? BufToHex(&keyID) : PORT_Strdup(name);
00889            PR_fprintf(PR_STDERR, "%s: Couldn't find key %s on %s\n",
00890                      progName, keyName, PK11_GetTokenName(slot));
00891            PORT_Free(keyName);
00892            goto shutdown;
00893        }
00894 
00895        rv = PK11_DeleteTokenSymKey(symKey);
00896        FreeKeyList(symKey);
00897        if (rv != SECSuccess) {
00898            PR_fprintf(PR_STDERR, "%s: Couldn't Delete Key \n", progName);
00899            goto shutdown;
00900        }
00901     }
00902     if (symKeyUtil.commands[cmd_UnwrapKey].activated) {
00903        PK11SymKey *wrapKey = FindKey(slot,wrapName,&wrapKeyID,&pwdata);
00904        PK11SymKey *symKey;
00905        CK_MECHANISM_TYPE mechanism;
00906 
00907        if (!wrapKey) {
00908            char *keyName = wrapKeyID.data ? BufToHex(&wrapKeyID) 
00909                                                  : PORT_Strdup(wrapName);
00910            PR_fprintf(PR_STDERR, "%s: Couldn't find key %s on %s\n",
00911                      progName, keyName, PK11_GetTokenName(slot));
00912            PORT_Free(keyName);
00913            goto shutdown;
00914        }
00915        mechanism = GetWrapMechanism(wrapKey);
00916        if (mechanism == CKM_INVALID_MECHANISM) {
00917            char *keyName = wrapKeyID.data ? BufToHex(&wrapKeyID) 
00918                                                  : PORT_Strdup(wrapName);
00919            PR_fprintf(PR_STDERR, "%s: %s on %s is an invalid wrapping key\n",
00920                      progName, keyName, PK11_GetTokenName(slot));
00921            PORT_Free(keyName);
00922            PK11_FreeSymKey(wrapKey);
00923            goto shutdown;
00924        }
00925 
00926        symKey = PK11_UnwrapSymKeyWithFlagsPerm(wrapKey, mechanism, NULL,
00927                      &key, keyType, CKA_ENCRYPT, keySize, 0, PR_TRUE);
00928        PK11_FreeSymKey(wrapKey);
00929        if (!symKey) {
00930            PR_fprintf(PR_STDERR, "%s: Unwrap Key Failed\n", progName);
00931            goto shutdown;
00932        }
00933 
00934        if (symKeyUtil.options[opt_Nickname].activated) {
00935            rv = PK11_SetSymKeyNickname(symKey, name);
00936            if (rv != SECSuccess) {
00937                PR_fprintf(PR_STDERR, "%s: Couldn't set name on key\n", 
00938                                                         progName);
00939               PK11_DeleteTokenSymKey(symKey);
00940               PK11_FreeSymKey(symKey);
00941               goto shutdown;
00942            }
00943        }
00944        rv = SECSuccess;
00945        PrintKey(symKey);
00946        PK11_FreeSymKey(symKey);
00947     }
00948 
00949 #define MAX_KEY_SIZE 4098
00950     if (symKeyUtil.commands[cmd_WrapKey].activated) {
00951        PK11SymKey *symKey = FindKey(slot, name, &keyID, &pwdata);
00952        PK11SymKey *wrapKey;
00953        CK_MECHANISM_TYPE mechanism;
00954        SECItem data;
00955        unsigned char buf[MAX_KEY_SIZE];
00956        int ret;
00957 
00958        if (!symKey) {
00959            char *keyName = keyID.data ? BufToHex(&keyID) : PORT_Strdup(name);
00960            PR_fprintf(PR_STDERR, "%s: Couldn't find key %s on %s\n",
00961                      progName, keyName, PK11_GetTokenName(slot));
00962            PORT_Free(keyName);
00963            goto shutdown;
00964        }
00965 
00966        wrapKey = FindKey(slot, wrapName, &wrapKeyID, &pwdata);
00967        if (!wrapKey) {
00968            char *keyName = wrapKeyID.data ? BufToHex(&wrapKeyID) 
00969                                                  : PORT_Strdup(wrapName);
00970            PR_fprintf(PR_STDERR, "%s: Couldn't find key %s on %s\n",
00971                      progName, keyName, PK11_GetTokenName(slot));
00972            PORT_Free(keyName);
00973            PK11_FreeSymKey(symKey);
00974            goto shutdown;
00975        }
00976 
00977        mechanism = GetWrapMechanism(wrapKey);
00978        if (mechanism == CKM_INVALID_MECHANISM) {
00979            char *keyName = wrapKeyID.data ? BufToHex(&wrapKeyID) 
00980                                                  : PORT_Strdup(wrapName);
00981            PR_fprintf(PR_STDERR, "%s: %s on %s is an invalid wrapping key\n",
00982                      progName, keyName, PK11_GetTokenName(slot));
00983            PORT_Free(keyName);
00984            PK11_FreeSymKey(symKey);
00985            PK11_FreeSymKey(wrapKey);
00986            goto shutdown;
00987        }
00988 
00989        data.data = buf;
00990        data.len = sizeof(buf);
00991        rv = PK11_WrapSymKey(mechanism, NULL,  wrapKey, symKey, &data);
00992        PK11_FreeSymKey(symKey);
00993        PK11_FreeSymKey(wrapKey);
00994        if (rv != SECSuccess) {
00995            PR_fprintf(PR_STDERR, "%s: Couldn't wrap key\n",progName);
00996            goto shutdown;
00997        }
00998 
00999        /* WriteBuf outputs it's own error using SECU_PrintError */
01000        ret = WriteBuf(symKeyUtil.options[opt_KeyFile].arg, &data);
01001        if (ret < 0) {
01002            goto shutdown;
01003        }
01004     }
01005 
01006     if (symKeyUtil.commands[cmd_ImportKey].activated) {
01007        PK11SymKey *symKey = PK11_ImportSymKey(slot, keyType,
01008                       PK11_OriginUnwrap, CKA_ENCRYPT, &key,&pwdata);
01009        if (!symKey) {
01010            PR_fprintf(PR_STDERR, "%s: Import Key Failed\n", progName);
01011            goto shutdown;
01012        }
01013        if (symKeyUtil.options[opt_Nickname].activated) {
01014            rv = PK11_SetSymKeyNickname(symKey, name);
01015            if (rv != SECSuccess) {
01016                PR_fprintf(PR_STDERR, "%s: Couldn't set name on key\n", 
01017                                                         progName);
01018               PK11_DeleteTokenSymKey(symKey);
01019               PK11_FreeSymKey(symKey);
01020               goto shutdown;
01021            }
01022        }
01023        rv = SECSuccess;
01024        PrintKey(symKey);
01025        PK11_FreeSymKey(symKey);
01026     }
01027 
01028     /*  List certs (-L)  */
01029     if (symKeyUtil.commands[cmd_ListKeys].activated) {
01030        int printLabel = 1;
01031        if (slot) {
01032            rv = ListKeys(slot,&printLabel,&pwdata);
01033        } else {
01034            /* loop over all the slots */
01035            PK11SlotList *slotList = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
01036                                    PR_FALSE, PR_FALSE, &pwdata);
01037            PK11SlotListElement *se;
01038 
01039            if (slotList == NULL) {
01040                PR_fprintf(PR_STDERR, "%s: No tokens found\n",progName);
01041            }
01042            for (se = PK11_GetFirstSafe(slotList); se; 
01043                             se=PK11_GetNextSafe(slotList,se, PR_FALSE)) {
01044                rv = ListKeys(se->slot,&printLabel,&pwdata);
01045                if (rv !=SECSuccess) {
01046                   break;
01047               }
01048            }
01049        }
01050     }
01051 
01052     /*  Move key (-M)  */
01053     if (symKeyUtil.commands[cmd_MoveKey].activated) {
01054        PK11SlotInfo *target;
01055        char *targetName = symKeyUtil.options[opt_TargetToken].arg;
01056        PK11SymKey *newKey;
01057        PK11SymKey *symKey = FindKey(slot,name,&keyID,&pwdata);
01058        char *keyName = PK11_GetSymKeyNickname(symKey);
01059 
01060        if (!symKey) {
01061            char *keyName = keyID.data ? BufToHex(&keyID) : PORT_Strdup(name);
01062            PR_fprintf(PR_STDERR, "%s: Couldn't find key %s on %s\n",
01063                      progName, keyName, PK11_GetTokenName(slot));
01064            PORT_Free(keyName);
01065            goto shutdown;
01066        }
01067        target = PK11_FindSlotByName(targetName);
01068        if (!target) {
01069            PR_fprintf(PR_STDERR, "%s: Couldn't find slot %s\n",
01070                      progName, targetName);
01071            goto shutdown;
01072        }
01073        rv = PK11_Authenticate(target, PR_FALSE, &pwdata);
01074        if (rv != SECSuccess) {
01075            PR_fprintf(PR_STDERR, "%s: Failed to log into %s\n",
01076                      progName, targetName);
01077            goto shutdown;
01078        }
01079        rv = SECFailure;
01080        newKey = PK11_MoveSymKey(target, CKA_ENCRYPT, 0, PR_TRUE, symKey);
01081        if (!newKey) {
01082            PR_fprintf(PR_STDERR, "%s: Couldn't move the key \n",progName);
01083            goto shutdown;
01084        }
01085        if (keyName) {
01086            rv = PK11_SetSymKeyNickname(newKey, keyName);
01087            if (rv != SECSuccess) {
01088               PK11_DeleteTokenSymKey(newKey);
01089               PK11_FreeSymKey(newKey);
01090                PR_fprintf(PR_STDERR, "%s: Couldn't set nickname on key\n",
01091                                                          progName);
01092               goto shutdown;
01093            }
01094        }
01095        PK11_FreeSymKey(newKey);
01096        rv = SECSuccess;
01097     }
01098 
01099 shutdown:
01100     if (rv != SECSuccess) {
01101        PR_fprintf(PR_STDERR, "%s: %s\n", progName,
01102                                    SECU_Strerror(PORT_GetError()));
01103     }
01104 
01105     if (key.data) {
01106        PORT_Free(key.data);
01107     }
01108 
01109     if (keyID.data) {
01110        PORT_Free(keyID.data);
01111     }
01112 
01113     if (slot) {
01114        PK11_FreeSlot(slot);
01115     }
01116 
01117     if (NSS_Shutdown() != SECSuccess) {
01118         exit(1);
01119     }
01120 
01121     if (rv == SECSuccess) {
01122        return 0;
01123     } else {
01124        return 255;
01125     }
01126 }
01127 
01128 
01129