1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * This file comprises the main driver for this tool. 30 * Upon parsing the command verbs from user input, it 31 * branches to the appropriate modules to perform the 32 * requested task. 33 */ 34 35 #include <stdio.h> 36 #include <string.h> 37 #include <ctype.h> 38 #include <malloc.h> 39 #include <libgen.h> 40 #include <errno.h> 41 #include <cryptoutil.h> 42 #include <security/cryptoki.h> 43 #include "common.h" 44 45 /* 46 * The verbcmd construct allows genericizing information about a verb so 47 * that it is easier to manipulate. Makes parsing code easier to read, 48 * fix, and extend with new verbs. 49 */ 50 typedef struct verbcmd_s { 51 char *verb; 52 int (*action)(int, char *[]); 53 int mode; 54 char *summary; 55 char *synopsis; 56 } verbcmd; 57 58 /* External declarations for supported verb actions. */ 59 extern int pk_setpin(int argc, char *argv[]); 60 extern int pk_list(int argc, char *argv[]); 61 extern int pk_delete(int argc, char *argv[]); 62 extern int pk_import(int argc, char *argv[]); 63 extern int pk_export(int argc, char *argv[]); 64 extern int pk_tokens(int argc, char *argv[]); 65 extern int pk_gencert(int argc, char *argv[]); 66 extern int pk_gencsr(int argc, char *argv[]); 67 extern int pk_download(int argc, char *argv[]); 68 extern int pk_genkey(int argc, char *argv[]); 69 70 /* Forward declarations for "built-in" verb actions. */ 71 static int pk_help(int argc, char *argv[]); 72 73 /* Command structure for verbs and their actions. Do NOT i18n/l10n. */ 74 static verbcmd cmds[] = { 75 { "tokens", pk_tokens, 0, 76 "lists all visible PKCS#11 tokens", "tokens" }, 77 { "setpin", pk_setpin, 0, 78 "changes user authentication passphrase for keystore access", 79 "setpin [ keystore=pkcs11 ]\n\t\t" 80 "[ token=token[:manuf[:serial]]]\n\t" 81 82 "setpin keystore=nss\n\t\t" 83 "[ token=token ]\n\t\t" 84 "[ dir=directory-path ]\n\t\t" 85 "[ prefix=DBprefix ]\n\t" 86 }, 87 { "list", pk_list, 0, 88 "lists a summary of objects in the keystore", 89 "list [ token=token[:manuf[:serial]]]\n\t\t" 90 "[ objtype=private|public|both ]\n\t\t" 91 "[ label=label ]\n\t" 92 93 "list objtype=cert[:[public | private | both ]]\n\t\t" 94 "[ subject=subject-DN ]\n\t\t" 95 "[ keystore=pkcs11 ]\n\t\t" 96 "[ issuer=issuer-DN ]\n\t\t" 97 "[ serial=serial number ]\n\t\t" 98 "[ label=cert-label ]\n\t\t" 99 "[ token=token[:manuf[:serial]]]\n\t\t" 100 "[ criteria=valid|expired|both ]\n\t" 101 102 "list objtype=key[:[public | private | both ]]\n\t\t" 103 "[ keystore=pkcs11 ]\n\t\t" 104 "[ subject=subject-DN ]\n\t\t" 105 "[ label=key-label ]\n\t\t" 106 "[ token=token[:manuf[:serial]]]\n\t" 107 108 "list keystore=pkcs11 objtype=crl\n\t\t" 109 "infile=crl-fn\n\t\t" 110 "[ dir=directory-path ]\n\t" 111 112 "list keystore=nss objtype=cert\n\t\t" 113 "[ subject=subject-DN ]\n\t\t" 114 "[ issuer=issuer-DN ]\n\t\t" 115 "[ serial=serial number ]\n\t\t" 116 "[ nickname=cert-nickname ]\n\t\t" 117 "[ token=token[:manuf[:serial]]]\n\t\t" 118 "[ dir=directory-path ]\n\t\t" 119 "[ prefix=DBprefix ]\n\t\t" 120 "[ criteria=valid|expired|both ]\n\t" 121 122 "list keystore=nss objtype=key\n\t\t" 123 "[ token=token[:manuf[:serial]]]\n\t\t" 124 "[ dir=directory-path ]\n\t\t" 125 "[ prefix=DBprefix ]\n\t\t" 126 "[ nickname=key-nickname ]\n\t" 127 128 "list keystore=file objtype=cert\n\t\t" 129 "[ subject=subject-DN ]\n\t\t" 130 "[ issuer=issuer-DN ]\n\t\t" 131 "[ serial=serial number ]\n\t\t" 132 "[ infile=cert-fn ]\n\t\t" 133 "[ dir=directory-path ]\n\t\t" 134 "[ criteria=valid|expired|both ]\n\t" 135 136 "list keystore=file objtype=key\n\t\t" 137 "[ infile=key-fn ]\n\t\t" 138 "[ dir=directory-path ]\n\t" 139 140 "list keystore=file objtype=crl\n\t\t" 141 "infile=crl-fn\n\t\t" 142 "[ dir=directory-path ]\n\t" 143 }, 144 145 { "delete", pk_delete, 0, 146 "deletes objects in the keystore", 147 148 "delete [ token=token[:manuf[:serial]]]\n\t\t" 149 "[ objtype=private|public|both ]\n\t\t" 150 "[ label=object-label ]\n\t" 151 152 "delete keystore=nss objtype=cert\n\t\t" 153 "[ subject=subject-DN ]\n\t\t" 154 "[ issuer=issuer-DN ]\n\t\t" 155 "[ serial=serial number ]\n\t\t" 156 "[ label=cert-label ]\n\t\t" 157 "[ token=token[:manuf[:serial]]]\n\t\t" 158 "[ dir=directory-path ]\n\t\t" 159 "[ prefix=DBprefix ]\n\t\t" 160 "[ criteria=valid|expired|both ]\n\t" 161 162 "delete keystore=nss objtype=key\n\t\t" 163 "[ token=token[:manuf[:serial]]]\n\t\t" 164 "[ dir=directory-path ]\n\t\t" 165 "[ prefix=DBprefix ]\n\t\t" 166 "[ nickname=key-nickname ]\n\t\t" 167 168 "delete keystore=nss objtype=crl\n\t\t" 169 "[ nickname=issuer-nickname ]\n\t\t" 170 "[ subject=subject-DN ]\n\t\t" 171 "[ token=token[:manuf[:serial]]]\n\t\t" 172 "[ dir=directory-path ]\n\t\t" 173 "[ prefix=DBprefix ]\n\t" 174 175 "delete keystore=pkcs11 objtype=cert[:[public | private | both]]\n\t\t" 176 "[ subject=subject-DN ]\n\t\t" 177 "[ issuer=issuer-DN ]\n\t\t" 178 "[ serial=serial number ]\n\t\t" 179 "[ label=cert-label ]\n\t\t" 180 "[ token=token[:manuf[:serial]]]\n\t\t" 181 "[ criteria=valid|expired|both ]\n\t" 182 183 "delete keystore=pkcs11 objtype=key[:[public | private | both]]\n\t\t" 184 "[ subject=subject-DN ]\n\t\t" 185 "[ label=key-label ]\n\t\t" 186 "[ token=token[:manuf[:serial]]]\n\t" 187 188 "delete keystore=pkcs11 objtype=crl\n\t\t" 189 "infile=crl-fn\n\t\t" 190 "[ dir=directory-path ]\n\t" 191 192 "delete keystore=file objtype=cert\n\t\t" 193 "[ subject=subject-DN ]\n\t\t" 194 "[ issuer=issuer-DN ]\n\t\t" 195 "[ serial=serial number ]\n\t\t" 196 "[ infile=cert-fn ]\n\t\t" 197 "[ dir=directory-path ]\n\t\t" 198 "[ criteria=valid|expired|both ]\n\t" 199 200 "delete keystore=file objtype=key\n\t\t" 201 "[ infile=key-fn ]\n\t\t" 202 "[ dir=directory-path ]\n\t" 203 204 "delete keystore=file objtype=crl\n\t\t" 205 "infile=crl-fn\n\t\t" 206 "[ dir=directory-path ]\n\t" 207 }, 208 { "import", pk_import, 0, 209 "imports objects from an external source", 210 211 "import [token=token[:manuf[:serial]]]\n\t\t" 212 "infile=input-fn\n\t" 213 214 "import keystore=nss objtype=cert\n\t\t" 215 "infile=input-fn\n\t\t" 216 "label=cert-label\n\t\t" 217 "[ trust=trust-value ]\n\t\t" 218 "[ token=token[:manuf[:serial]]]\n\t\t" 219 "[ dir=directory-path ]\n\t\t" 220 "[ prefix=DBprefix ]\n\t" 221 222 "import keystore=nss objtype=crl\n\t\t" 223 "infile=input-fn\n\t\t" 224 "[ verifycrl=y|n ]\n\t\t" 225 "[ token=token[:manuf[:serial]]]\n\t\t" 226 "[ dir=directory-path ]\n\t\t" 227 "[ prefix=DBprefix ]\n\t" 228 229 "import keystore=pkcs11\n\t\t" 230 "infile=input-fn\n\t\t" 231 "label=label\n\t\t" 232 "[ objtype=cert|key ]\n\t\t" 233 "[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" 234 "[ sensitive=y|n ]\n\t\t" 235 "[ extractable=y|n ]\n\t\t" 236 "[ token=token[:manuf[:serial]]]\n\t" 237 238 "import keystore=pkcs11 objtype=crl\n\t\t" 239 "infile=input-crl-fn\n\t\t" 240 "outcrl=output-crl-fn\n\t\t" 241 "outformat=pem|der\n\t\t" 242 "[ dir=output-crl-directory-path ]\n\t" 243 244 "import keystore=file\n\t\t" 245 "infile=input-fn\n\t\t" 246 "outkey=output-key-fn\n\t\t" 247 "outcert=output-cert-fn\n\t\t" 248 "[ dir=output-cert-dir-path ]\n\t\t" 249 "[ keydir=output-key-dir-path ]\n\t\t" 250 "[ outformat=pem|der|pkcs12 ]\n\t" 251 252 "import keystore=file objtype=crl\n\t\t" 253 "infile=input-crl-fn\n\t\t" 254 "outcrl=output-crl-fn\n\t\t" 255 "outformat=pem|der\n\t\t" 256 "[ dir=output-crl-directory-path ]\n\t" 257 }, 258 259 { "export", pk_export, 0, 260 "exports objects from the keystore to a file", 261 262 "export [token=token[:manuf[:serial]]]\n\t\t" 263 "outfile=output-fn\n\t" 264 265 "export keystore=nss\n\t\t" 266 "outfile=output-fn\n\t\t" 267 "[ objtype=cert|key ]\n\t\t" 268 "[ subject=subject-DN ]\n\t\t" 269 "[ issuer=issuer-DN ]\n\t\t" 270 "[ serial=serial number ]\n\t\t" 271 "[ nickname=cert-nickname ]\n\t\t" 272 "[ token=token[:manuf[:serial]]]\n\t\t" 273 "[ dir=directory-path ]\n\t\t" 274 "[ prefix=DBPrefix ]\n\t\t" 275 "[ outformat=pem|der|pkcs12 ]\n\t" 276 277 "export keystore=pkcs11\n\t\t" 278 "outfile=output-fn\n\t\t" 279 "[ objtype=cert|key ]\n\t\t" 280 "[ label=label ]\n\t\t" 281 "[ subject=subject-DN ]\n\t\t" 282 "[ issuer=issuer-DN ]\n\t\t" 283 "[ serial=serial number ]\n\t\t" 284 "[ outformat=pem|der|pkcs12|raw ]\n\t\t" 285 "[ token=token[:manuf[:serial]]]\n\t" 286 287 "export keystore=file\n\t\t" 288 "certfile=cert-input-fn\n\t\t" 289 "keyfile=key-input-fn\n\t\t" 290 "outfile=output-pkcs12-fn\n\t\t" 291 "[ dir=directory-path ]\n\t" 292 }, 293 294 { "gencert", pk_gencert, 0, 295 "creates a self-signed X.509v3 certificate", 296 297 "gencert [-i] keystore=nss\n\t\t" 298 "label=cert-nickname\n\t\t" 299 "serial=serial number hex string]\n\t\t" 300 "subject=subject-DN\n\t\t" 301 "[ altname=[critical:]SubjectAltName ]\n\t\t" 302 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 303 "[ token=token[:manuf[:serial]]]\n\t\t" 304 "[ dir=directory-path ]\n\t\t" 305 "[ prefix=DBprefix ]\n\t\t" 306 "[ keytype=rsa|dsa ]\n\t\t" 307 "[ keylen=key-size ]\n\t\t" 308 "[ trust=trust-value ]\n\t\t" 309 "[ lifetime=number-hour|number-day|number-year ]\n\t" 310 311 "gencert [-i] [ keystore=pkcs11 ]\n\t\t" 312 "label=key/cert-label\n\t\t" 313 "subject=subject-DN\n\t\t" 314 "serial=serial number hex string\n\t\t" 315 "[ altname=[critical:]SubjectAltName ]\n\t\t" 316 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 317 "[ token=token[:manuf[:serial]]]\n\t\t" 318 "[ keytype=rsa|dsa ]\n\t\t" 319 "[ keylen=key-size ]\n\t\t" 320 "[ lifetime=number-hour|number-day|number-year ]\n\t" 321 322 "gencert [-i] keystore=file\n\t\t" 323 "outcert=cert_filename\n\t\t" 324 "outkey=key_filename\n\t\t" 325 "subject=subject-DN\n\t\t" 326 "serial=serial number hex string\n\t\t" 327 "[ altname=[critical:]SubjectAltName ]\n\t\t" 328 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 329 "[ format=der|pem ]\n\t\t" 330 "[ dir=directory-path ]\n\t\t" 331 "[ prefix=DBprefix ]\n\t\t" 332 "[ keytype=rsa|dsa ]\n\t\t" 333 "[ keylen=key-size ]\n\t\t" 334 "[ lifetime=number-hour|number-day|number-year ]\n\t" 335 }, 336 { "gencsr", pk_gencsr, 0, 337 "creates a PKCS#10 certificate signing request file", 338 "gencsr [-i] keystore=nss \n\t\t" 339 "nickname=cert-nickname\n\t\t" 340 "outcsr=csr-fn\n\t\t" 341 "subject=subject-DN\n\t\t" 342 "[ altname=[critical:]SubjectAltName ]\n\t\t" 343 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 344 "[ token=token[:manuf[:serial]]]\n\t\t" 345 "[ dir=directory-path ]\n\t\t" 346 "[ prefix=DBprefix ]\n\t\t" 347 "[ keytype=rsa|dsa ]\n\t\t" 348 "[ keylen=key-size ]\n\t\t" 349 "[ format=pem|der ]\n\t" 350 "gencsr [-i] [ keystore=pkcs11 ]\n\t\t" 351 "label=key-label\n\t\t" 352 "outcsr=csr-fn\n\t\t" 353 "subject=subject-DN\n\t\t" 354 "[ altname=[critical:]SubjectAltName ]\n\t\t" 355 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 356 "[ token=token[:manuf[:serial]]]\n\t\t" 357 "[ keytype=rsa|dsa ]\n\t\t" 358 "[ keylen=key-size ]\n\t\t" 359 "[ format=pem|der ]]\n\t" 360 "gencsr [-i] keystore=file\n\t\t" 361 "outcsr=csr-fn\n\t\t" 362 "outkey=key-fn\n\t\t" 363 "subject=subject-DN\n\t\t" 364 "[ altname=[critical:]SubjectAltName ]\n\t\t" 365 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 366 "[ keytype=rsa|dsa ]\n\t\t" 367 "[ keylen=key-size ]\n\t\t" 368 "[ dir=directory-path ]\n\t\t" 369 "[ format=pem|der ]\n\t" 370 }, 371 372 { "download", pk_download, 0, 373 "downloads a CRL or certificate file from an external source", 374 375 "download url=url_str\n\t\t" 376 "[ objtype=crl|cert ]\n\t\t" 377 "[ http_proxy=proxy_str ]\n\t\t" 378 "[ outfile = outfile ]\n\t\t" 379 }, 380 381 { "genkey", pk_genkey, 0, 382 "creates a symmetric key in the keystore", 383 384 "genkey [ keystore=pkcs11 ]\n\t\t" 385 "label=key-label\n\t\t" 386 "[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" 387 "[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t" 388 "[ token=token[:manuf[:serial]]]\n\t\t" 389 "[ sensitive=y|n ]\n\t\t" 390 "[ extractable=y|n ]\n\t\t" 391 "[ print=y|n ]\n\t" 392 393 "genkey keystore=nss\n\t\t" 394 "label=key-label\n\t\t" 395 "[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" 396 "[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t" 397 "[ token=token[:manuf[:serial]]]\n\t\t" 398 "[ dir=directory-path ]\n\t\t" 399 "[ prefix=DBprefix ]\n\t" 400 401 "genkey keystore=file\n\t\t" 402 "outkey=key-fn\n\t\t" 403 "[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" 404 "[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t" 405 "[ dir=directory-path ]\n\t\t" 406 "[ print=y|n ]\n\t" 407 }, 408 409 { "help", pk_help, 0, 410 "displays help message", 411 "help\t(help and usage)" } 412 }; 413 414 static int num_cmds = sizeof (cmds) / sizeof (verbcmd); 415 416 static char *prog; 417 static void usage(int); 418 419 /* 420 * Usage information. This function must be updated when new verbs or 421 * options are added. 422 */ 423 static void 424 usage(int idx) 425 { 426 int i; 427 428 /* Display this block only in command-line mode. */ 429 (void) fprintf(stdout, gettext("Usage:\n")); 430 (void) fprintf(stdout, gettext(" %s -?\t(help and usage)\n"), 431 prog); 432 (void) fprintf(stdout, gettext(" %s -f option_file\n"), prog); 433 (void) fprintf(stdout, gettext(" %s subcommand [options...]\n"), 434 prog); 435 (void) fprintf(stdout, gettext("where subcommands may be:\n")); 436 437 /* Display only those verbs that match the current tool mode. */ 438 if (idx == -1) { 439 for (i = 0; i < num_cmds; i++) { 440 /* Do NOT i18n/l10n. */ 441 (void) fprintf(stdout, " %-8s - %s\n", 442 cmds[i].verb, cmds[i].summary); 443 } 444 (void) fprintf(stdout, gettext("\nFurther details on the " 445 "subcommands can be found by adding \'help\'.\n" 446 "Ex: pktool gencert help\n\n")); 447 } else { 448 (void) fprintf(stdout, "\t%s\n", cmds[idx].synopsis); 449 } 450 } 451 452 /* 453 * Provide help, in the form of displaying the usage. 454 */ 455 static int 456 pk_help(int argc, char *argv[]) 457 /* ARGSUSED */ 458 { 459 usage(-1); 460 return (0); 461 } 462 463 /* 464 * Process arguments from the argfile and create a new 465 * argv/argc list to be processed later. 466 */ 467 static int 468 process_arg_file(char *argfile, char ***argv, int *argc) 469 { 470 FILE *fp; 471 char argline[2 * BUFSIZ]; /* 2048 bytes should be plenty */ 472 char *p; 473 int nargs = 0; 474 475 if ((fp = fopen(argfile, "rF")) == NULL) { 476 (void) fprintf(stderr, 477 gettext("Cannot read argfile %s: %s\n"), 478 argfile, strerror(errno)); 479 return (errno); 480 } 481 482 while (fgets(argline, sizeof (argline), fp) != NULL) { 483 int j; 484 /* remove trailing whitespace */ 485 j = strlen(argline) - 1; 486 while (j >= 0 && isspace(argline[j])) { 487 argline[j] = 0; 488 j--; 489 } 490 /* If it was a blank line, get the next one. */ 491 if (!strlen(argline)) 492 continue; 493 494 (*argv) = realloc((*argv), 495 (nargs + 1) * sizeof (char *)); 496 if ((*argv) == NULL) { 497 perror("memory error"); 498 (void) fclose(fp); 499 return (errno); 500 } 501 p = (char *)strdup(argline); 502 if (p == NULL) { 503 perror("memory error"); 504 (void) fclose(fp); 505 return (errno); 506 } 507 (*argv)[nargs] = p; 508 nargs++; 509 } 510 *argc = nargs; 511 (void) fclose(fp); 512 return (0); 513 } 514 515 /* 516 * MAIN() -- where all the action is 517 */ 518 int 519 main(int argc, char *argv[], char *envp[]) 520 /* ARGSUSED2 */ 521 { 522 int i, found = -1; 523 int rv; 524 int pk_argc = 0; 525 char **pk_argv = NULL; 526 int save_errno = 0; 527 528 /* Set up for i18n/l10n. */ 529 (void) setlocale(LC_ALL, ""); 530 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D. */ 531 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */ 532 #endif 533 (void) textdomain(TEXT_DOMAIN); 534 535 /* Get program base name and move pointer over 0th arg. */ 536 prog = basename(argv[0]); 537 argv++, argc--; 538 539 /* Set up for debug and error output. */ 540 if (argc == 0) { 541 usage(-1); 542 return (1); 543 } 544 545 /* Check for help options. For CLIP-compliance. */ 546 if (strcmp(argv[0], "-?") == 0) { 547 return (pk_help(argc, argv)); 548 } else if (strcmp(argv[0], "-f") == 0 && argc == 2) { 549 rv = process_arg_file(argv[1], &pk_argv, &pk_argc); 550 if (rv) 551 return (rv); 552 } else if (argc >= 1 && argv[0][0] == '-') { 553 usage(-1); 554 return (1); 555 } 556 557 /* Always turns off Metaslot so that we can see softtoken. */ 558 if (setenv("METASLOT_ENABLED", "false", 1) < 0) { 559 save_errno = errno; 560 cryptoerror(LOG_STDERR, 561 gettext("Disabling Metaslot failed (%s)."), 562 strerror(save_errno)); 563 return (1); 564 } 565 566 /* Begin parsing command line. */ 567 if (pk_argc == 0 && pk_argv == NULL) { 568 pk_argc = argc; 569 pk_argv = argv; 570 } 571 572 /* Check for valid verb (or an abbreviation of it). */ 573 found = -1; 574 for (i = 0; i < num_cmds; i++) { 575 if (strcmp(cmds[i].verb, pk_argv[0]) == 0) { 576 if (found < 0) { 577 found = i; 578 break; 579 } 580 } 581 } 582 /* Stop here if no valid verb found. */ 583 if (found < 0) { 584 cryptoerror(LOG_STDERR, gettext("Invalid verb: %s"), 585 pk_argv[0]); 586 return (1); 587 } 588 589 /* Get to work! */ 590 rv = (*cmds[found].action)(pk_argc, pk_argv); 591 switch (rv) { 592 case PK_ERR_NONE: 593 break; /* Command succeeded, do nothing. */ 594 case PK_ERR_USAGE: 595 usage(found); 596 break; 597 case PK_ERR_QUIT: 598 exit(0); 599 /* NOTREACHED */ 600 case PK_ERR_PK11: 601 case PK_ERR_SYSTEM: 602 case PK_ERR_OPENSSL: 603 case PK_ERR_NSS: 604 default: 605 break; 606 } 607 return (rv); 608 } 609