PageRenderTime 87ms CodeModel.GetById 18ms app.highlight 61ms RepoModel.GetById 1ms app.codeStats 1ms

/security/nss/cmd/symkeyutil/symkeyutil.c

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