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 2006 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 *synopsis; 55 } verbcmd; 56 57 /* External declarations for supported verb actions. */ 58 extern int pk_setpin(int argc, char *argv[]); 59 extern int pk_list(int argc, char *argv[]); 60 extern int pk_delete(int argc, char *argv[]); 61 extern int pk_import(int argc, char *argv[]); 62 extern int pk_export(int argc, char *argv[]); 63 extern int pk_tokens(int argc, char *argv[]); 64 extern int pk_gencert(int argc, char *argv[]); 65 extern int pk_gencsr(int argc, char *argv[]); 66 extern int pk_download(int argc, char *argv[]); 67 extern int pk_genkey(int argc, char *argv[]); 68 69 /* Forward declarations for "built-in" verb actions. */ 70 static int pk_help(int argc, char *argv[]); 71 72 /* Command structure for verbs and their actions. Do NOT i18n/l10n. */ 73 static verbcmd cmds[] = { 74 { "tokens", pk_tokens, 0, "tokens" }, 75 { "setpin", pk_setpin, 0, 76 "setpin [ keystore=pkcs11 ]\n\t\t" 77 "[ token=token[:manuf[:serial]]]\n\t" 78 79 "setpin keystore=nss\n\t\t" 80 "[ token=token ]\n\t\t" 81 "[ dir=directory-path ]\n\t\t" 82 "[ prefix=DBprefix ]\n\t" 83 }, 84 { "list", pk_list, 0, 85 86 "list [ token=token[:manuf[:serial]]]\n\t\t" 87 "[ objtype=private|public|both ]\n\t\t" 88 "[ label=label ]\n\t" 89 90 "list objtype=cert[:[public | private | both ]]\n\t\t" 91 "[ subject=subject-DN ]\n\t\t" 92 "[ keystore=pkcs11 ]\n\t\t" 93 "[ issuer=issuer-DN ]\n\t\t" 94 "[ serial=serial number]\n\t\t" 95 "[ label=cert-label ]\n\t\t" 96 "[ token=token[:manuf[:serial]]]\n\t\t" 97 "[ criteria=valid|expired|both ]\n\t" 98 99 "list objtype=key[:[public | private | both ]]\n\t\t" 100 "[ keystore=pkcs11 ]\n\t\t" 101 "[ subject=subject-DN ]\n\t\t" 102 "[ label=key-label ]\n\t\t" 103 "[ token=token[:manuf[:serial]]]\n\t" 104 105 "list keystore=pkcs11 objtype=crl\n\t\t" 106 "infile=crl-fn\n\t\t" 107 "[ dir=directory-path ]\n\t" 108 109 "list keystore=nss objtype=cert\n\t\t" 110 "[ subject=subject-DN ]\n\t\t" 111 "[ issuer=issuer-DN ]\n\t\t" 112 "[ serial=serial number]\n\t\t" 113 "[ nickname=cert-nickname ]\n\t\t" 114 "[ token=token[:manuf[:serial]]]\n\t\t" 115 "[ dir=directory-path ]\n\t\t" 116 "[ prefix=DBprefix ]\n\t\t" 117 "[ criteria=valid|expired|both ]\n\t" 118 119 "list keystore=nss objtype=key\n\t\t" 120 "[ token=token[:manuf[:serial]]]\n\t\t" 121 "[ dir=directory-path ]\n\t\t" 122 "[ prefix=DBprefix ]\n\t\t" 123 "[ nickname=key-nickname ]\n\t" 124 125 "list keystore=file objtype=cert\n\t\t" 126 "[ subject=subject-DN ]\n\t\t" 127 "[ issuer=issuer-DN ]\n\t\t" 128 "[ serial=serial number]\n\t\t" 129 "[ infile=cert-fn ]\n\t\t" 130 "[ dir=directory-path ]\n\t\t" 131 "[ criteria=valid|expired|both ]\n\t" 132 133 "list keystore=file objtype=key\n\t\t" 134 "[ infile=key-fn ]\n\t\t" 135 "[ dir=directory-path ]\n\t" 136 137 "list keystore=file objtype=crl\n\t\t" 138 "infile=crl-fn\n\t\t" 139 "[ dir=directory-path ]\n\t" 140 }, 141 142 { "delete", pk_delete, 0, 143 144 "delete [ token=token[:manuf[:serial]]]\n\t\t" 145 "[ objtype=private|public|both ]\n\t\t" 146 "[ label=object-label ]\n\t" 147 148 "delete keystore=nss objtype=cert\n\t\t" 149 "[ subject=subject-DN ]\n\t\t" 150 "[ issuer=issuer-DN ]\n\t\t" 151 "[ serial=serial number]\n\t\t" 152 "[ nickname=cert-nickname ]\n\t\t" 153 "[ token=token[:manuf[:serial]]]\n\t\t" 154 "[ dir=directory-path ]\n\t\t" 155 "[ prefix=DBprefix ]\n\t\t" 156 "[ criteria=valid|expired|both ]\n\t" 157 158 "delete keystore=nss objtype=key\n\t\t" 159 "[ token=token[:manuf[:serial]]]\n\t\t" 160 "[ dir=directory-path ]\n\t\t" 161 "[ prefix=DBprefix ]\n\t\t" 162 "[ nickname=key-nickname ]\n\t\t" 163 164 "delete keystore=nss objtype=crl\n\t\t" 165 "[ nickname=issuer-nickname ]\n\t\t" 166 "[ subject=subject-DN ]\n\t\t" 167 "[ token=token[:manuf[:serial]]]\n\t\t" 168 "[ dir=directory-path ]\n\t\t" 169 "[ prefix=DBprefix ]\n\t" 170 171 "delete keystore=pkcs11 objtype=cert[:[public | private | both]]\n\t\t" 172 "[ subject=subject-DN ]\n\t\t" 173 "[ issuer=issuer-DN ]\n\t\t" 174 "[ serial=serial number]\n\t\t" 175 "[ label=cert-label ]\n\t\t" 176 "[ token=token[:manuf[:serial]]]\n\t\t" 177 "[ criteria=valid|expired|both ]\n\t" 178 179 "delete keystore=pkcs11 objtype=key[:[public | private | both]]\n\t\t" 180 "[ subject=subject-DN ]\n\t\t" 181 "[ label=key-label ]\n\t\t" 182 "[ token=token[:manuf[:serial]]]\n\t" 183 184 "delete keystore=pkcs11 objtype=crl\n\t\t" 185 "infile=crl-fn\n\t\t" 186 "[ dir=directory-path ]\n\t" 187 188 "delete keystore=file objtype=cert\n\t\t" 189 "[ subject=subject-DN ]\n\t\t" 190 "[ issuer=issuer-DN ]\n\t\t" 191 "[ serial=serial number]\n\t\t" 192 "[ infile=cert-fn ]\n\t\t" 193 "[ dir=directory-path ]\n\t\t" 194 "[ criteria=valid|expired|both ]\n\t" 195 196 "delete keystore=file objtype=key\n\t\t" 197 "[ infile=key-fn ]\n\t\t" 198 "[ dir=directory-path ]\n\t" 199 200 "delete keystore=file objtype=crl\n\t\t" 201 "infile=crl-fn\n\t\t" 202 "[ dir=directory-path ]\n\t" 203 }, 204 { "import", pk_import, 0, 205 206 "import [token=token[:manuf[:serial]]]\n\t\t" 207 "infile=input-fn\n\t" 208 209 "import keystore=nss objtype=cert\n\t\t" 210 "infile=input-fn\n\t\t" 211 "nickname=cert-nickname\n\t\t" 212 "[ trust=trust-value ]\n\t\t" 213 "[ token=token[:manuf[:serial]]]\n\t\t" 214 "[ dir=directory-path ]\n\t\t" 215 "[ prefix=DBprefix ]\n\t" 216 217 "import keystore=nss objtype=crl\n\t\t" 218 "infile=input-fn\n\t\t" 219 "[ verifycrl=y|n ]\n\t\t" 220 "[ token=token[:manuf[:serial]]]\n\t\t" 221 "[ dir=directory-path ]\n\t\t" 222 "[ prefix=DBprefix ]\n\t" 223 224 "import keystore=pkcs11\n\t\t" 225 "infile=input-fn\n\t\t" 226 "label=cert-label\n\t\t" 227 "[ token=token[:manuf[:serial]]]\n\t" 228 229 "import keystore=pkcs11 objtype=crl\n\t\t" 230 "infile=input-crl-fn\n\t\t" 231 "outcrl=output-crl-fn\n\t\t" 232 "outformat=pem|der\n\t\t" 233 "[ dir=output-crl-directory-path ]\n\t" 234 235 "import keystore=file\n\t\t" 236 "infile=input-fn\n\t\t" 237 "outkey=output-key-fn\n\t\t" 238 "outcert=output-cert-fn\n\t\t" 239 "[ dir=output-cert-dir-path ]\n\t\t" 240 "[ keydir=output-key-dir-path ]\n\t\t" 241 "[ outformat=pem|der|pkcs12 ]\n\t" 242 243 "import keystore=file objtype=crl\n\t\t" 244 "infile=input-crl-fn\n\t\t" 245 "outcrl=output-crl-fn\n\t\t" 246 "outformat=pem|der\n\t\t" 247 "[ dir=output-crl-directory-path ]\n\t" 248 }, 249 250 { "export", pk_export, 0, 251 252 "export [token=token[:manuf[:serial]]]\n\t\t" 253 "outfile=output-fn\n\t" 254 255 "export keystore=nss\n\t\t" 256 "outfile=output-fn\n\t\t" 257 "[ objtype=cert|key ]\n\t\t" 258 "[ subject=subject-DN ]\n\t\t" 259 "[ issuer=issuer-DN ]\n\t\t" 260 "[ serial=serial number]\n\t\t" 261 "[ nickname=cert-nickname]\n\t\t" 262 "[ token=token[:manuf[:serial]]]\n\t\t" 263 "[ dir=directory-path ]\n\t\t" 264 "[ prefix=DBPrefix ]\n\t\t" 265 "[ outformat=pem|der|pkcs12 ]\n\t" 266 267 "export keystore=pkcs11\n\t\t" 268 "outfile=output-fn\n\t\t" 269 "[ label=cert-label]\n\t\t" 270 "[ subject=subject-DN ]\n\t\t" 271 "[ issuer=issuer-DN ]\n\t\t" 272 "[ serial=serial number]\n\t\t" 273 "[ outformat=pem|der|pkcs12]\n\t\t" 274 "[ token=token[:manuf[:serial]]]\n\t" 275 276 "export keystore=file\n\t\t" 277 "certfile=cert-input-fn\n\t\t" 278 "keyfile=key-input-fn\n\t\t" 279 "outfile=output-pkcs12-fn\n\t\t" 280 "[ dir=directory-path ]\n\t" 281 }, 282 283 { "gencert", pk_gencert, 0, 284 "gencert [-i] keystore=nss\n\t\t" 285 "label=cert-nickname\n\t\t" 286 "serial=serial number hex string]\n\t\t" 287 "subject=subject-DN\n\t\t" 288 "[ altname=[critical:]SubjectAltName ]\n\t\t" 289 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 290 "[ token=token[:manuf[:serial]]]\n\t\t" 291 "[ dir=directory-path ]\n\t\t" 292 "[ prefix=DBprefix ]\n\t\t" 293 "[ keytype=rsa|dsa ]\n\t\t" 294 "[ keylen=key-size ]\n\t\t" 295 "[ trust=trust-value ]\n\t\t" 296 "[ lifetime=number-hour|number-day|number-year ]\n\t" 297 298 "gencert [-i] [ keystore=pkcs11 ]\n\t\t" 299 "label=key/cert-label\n\t\t" 300 "subject=subject-DN\n\t\t" 301 "serial=serial number hex string\n\t\t" 302 "[ altname=[critical:]SubjectAltName ]\n\t\t" 303 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 304 "[ token=token[:manuf[:serial]]]\n\t\t" 305 "[ keytype=rsa|dsa ]\n\t\t" 306 "[ keylen=key-size ]\n\t\t" 307 "[ lifetime=number-hour|number-day|number-year ]\n\t" 308 309 "gencert [-i] keystore=file\n\t\t" 310 "outcert=cert_filename\n\t\t" 311 "outkey=key_filename\n\t\t" 312 "subject=subject-DN\n\t\t" 313 "serial=serial number hex string\n\t\t" 314 "[ altname=[critical:]SubjectAltName ]\n\t\t" 315 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 316 "[ format=der|pem ]\n\t\t" 317 "[ dir=directory-path ]\n\t\t" 318 "[ prefix=DBprefix ]\n\t\t" 319 "[ keytype=rsa|dsa ]\n\t\t" 320 "[ keylen=key-size ]\n\t\t" 321 "[ lifetime=number-hour|number-day|number-year ]\n\t" 322 }, 323 { "gencsr", pk_gencsr, 0, 324 "gencsr [-i] keystore=nss \n\t\t" 325 "nickname=cert-nickname\n\t\t" 326 "outcsr=csr-fn\n\t\t" 327 "subject=subject-DN\n\t\t" 328 "[ altname=[critical:]SubjectAltName ]\n\t\t" 329 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 330 "[ token=token[:manuf[:serial]]]\n\t\t" 331 "[ dir=directory-path ]\n\t\t" 332 "[ prefix=DBprefix ]\n\t\t" 333 "[ keytype=rsa|dsa ]\n\t\t" 334 "[ keylen=key-size ]\n\t\t" 335 "[ format=pem|der]\n\t" 336 "gencsr [-i] [ keystore=pkcs11 ]\n\t\t" 337 "label=key-label\n\t\t" 338 "outcsr=csr-fn\n\t\t" 339 "subject=subject-DN\n\t\t" 340 "[ altname=[critical:]SubjectAltName ]\n\t\t" 341 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 342 "[ token=token[:manuf[:serial]]]\n\t\t" 343 "[ keytype=rsa|dsa ]\n\t\t" 344 "[ keylen=key-size ]\n\t\t" 345 "[ format=pem|der]\n\t" 346 "gencsr [-i] keystore=file\n\t\t" 347 "outcsr=csr-fn\n\t\t" 348 "outkey=key-fn\n\t\t" 349 "subject=subject-DN\n\t\t" 350 "[ altname=[critical:]SubjectAltName ]\n\t\t" 351 "[ keyusage=[critical:]usage,usage,...]\n\t\t" 352 "[ keytype=rsa|dsa ]\n\t\t" 353 "[ keylen=key-size ]\n\t\t" 354 "[ dir=directory-path ]\n\t\t" 355 "[ format=pem|der]\n\t" 356 }, 357 358 { "download", pk_download, 0, 359 "download url=url_str\n\t\t" 360 "[ objtype=crl|cert ]\n\t\t" 361 "[ http_proxy=proxy_str ]\n\t\t" 362 "[ outfile = outfile ]\n\t\t" 363 }, 364 365 { "genkey", pk_genkey, 0, 366 "genkey [ keystore=pkcs11 ]\n\t\t" 367 "label=key-label\n\t\t" 368 "[ keytype=aes|arcfour|des|3des ]\n\t\t" 369 "[ keylen=key-size (AES or ARCFOUR only)]\n\t\t" 370 "[ token=token[:manuf[:serial]]]\n\t\t" 371 "[ sensitive=y|n ]\n\t\t" 372 "[ extractable=y|n ]\n\t\t" 373 "[ print=y|n ]\n\t" 374 375 "genkey keystore=nss\n\t\t" 376 "label=key-label\n\t\t" 377 "[ keytype=aes|arcfour|des|3des ]\n\t\t" 378 "[ keylen=key-size (AES or ARCFOUR only)]\n\t\t" 379 "[ token=token[:manuf[:serial]]]\n\t\t" 380 "[ dir=directory-path ]\n\t\t" 381 "[ prefix=DBprefix ]\n\t" 382 383 "genkey keystore=file\n\t\t" 384 "outkey=key-fn\n\t\t" 385 "[ keytype=aes|arcfour|des|3des ]\n\t\t" 386 "[ keylen=key-size (AES or ARCFOUR only)]\n\t\t" 387 "[ dir=directory-path ]\n\t\t" 388 "[ print=y|n ]\n\t" 389 }, 390 391 { "-?", pk_help, 0, "help\t(help and usage)" }, 392 { "-f", pk_help, 0, "-f option_file" } 393 }; 394 static int num_cmds = sizeof (cmds) / sizeof (verbcmd); 395 396 static char *prog; 397 static void usage(int); 398 399 /* 400 * Usage information. This function must be updated when new verbs or 401 * options are added. 402 */ 403 static void 404 usage(int idx) 405 { 406 int i; 407 408 /* Display this block only in command-line mode. */ 409 (void) fprintf(stdout, gettext("Usage:\n")); 410 (void) fprintf(stdout, gettext("\t%s -?\t(help and usage)\n"), prog); 411 (void) fprintf(stdout, gettext("\t%s -f option_file\n"), prog); 412 (void) fprintf(stdout, gettext("\t%s subcommand [options...]\n"), prog); 413 (void) fprintf(stdout, gettext("where subcommands may be:\n")); 414 415 /* Display only those verbs that match the current tool mode. */ 416 if (idx == -1) { 417 for (i = 0; i < num_cmds; i++) { 418 /* Do NOT i18n/l10n. */ 419 (void) fprintf(stdout, "\t%s\n", cmds[i].synopsis); 420 } 421 } else { 422 (void) fprintf(stdout, "\t%s\n", cmds[idx].synopsis); 423 } 424 } 425 426 /* 427 * Provide help, in the form of displaying the usage. 428 */ 429 static int 430 pk_help(int argc, char *argv[]) 431 /* ARGSUSED */ 432 { 433 usage(-1); 434 return (0); 435 } 436 437 /* 438 * Process arguments from the argfile and create a new 439 * argv/argc list to be processed later. 440 */ 441 static int 442 process_arg_file(char *argfile, char ***argv, int *argc) 443 { 444 FILE *fp; 445 char argline[2 * BUFSIZ]; /* 2048 bytes should be plenty */ 446 char *p; 447 int nargs = 0; 448 449 if ((fp = fopen(argfile, "rF")) == NULL) { 450 (void) fprintf(stderr, 451 gettext("Cannot read argfile %s: %s\n"), 452 argfile, strerror(errno)); 453 return (errno); 454 } 455 456 while (fgets(argline, sizeof (argline), fp) != NULL) { 457 int j; 458 /* remove trailing whitespace */ 459 j = strlen(argline) - 1; 460 while (j >= 0 && isspace(argline[j])) { 461 argline[j] = 0; 462 j--; 463 } 464 /* If it was a blank line, get the next one. */ 465 if (!strlen(argline)) 466 continue; 467 468 (*argv) = realloc((*argv), 469 (nargs + 1) * sizeof (char *)); 470 if ((*argv) == NULL) { 471 perror("memory error"); 472 (void) fclose(fp); 473 return (errno); 474 } 475 p = (char *)strdup(argline); 476 if (p == NULL) { 477 perror("memory error"); 478 (void) fclose(fp); 479 return (errno); 480 } 481 (*argv)[nargs] = p; 482 nargs++; 483 } 484 *argc = nargs; 485 (void) fclose(fp); 486 return (0); 487 } 488 489 /* 490 * MAIN() -- where all the action is 491 */ 492 int 493 main(int argc, char *argv[], char *envp[]) 494 /* ARGSUSED2 */ 495 { 496 int i, found = -1; 497 int rv; 498 int pk_argc = 0; 499 char **pk_argv = NULL; 500 int save_errno = 0; 501 502 /* Set up for i18n/l10n. */ 503 (void) setlocale(LC_ALL, ""); 504 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D. */ 505 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */ 506 #endif 507 (void) textdomain(TEXT_DOMAIN); 508 509 /* Get program base name and move pointer over 0th arg. */ 510 prog = basename(argv[0]); 511 argv++, argc--; 512 513 /* Set up for debug and error output. */ 514 if (argc == 0) { 515 usage(-1); 516 return (1); 517 } 518 519 /* Check for help options. For CLIP-compliance. */ 520 if (strcmp(argv[0], "-?") == 0) { 521 return (pk_help(argc, argv)); 522 } else if (strcmp(argv[0], "-f") == 0 && argc == 2) { 523 rv = process_arg_file(argv[1], &pk_argv, &pk_argc); 524 if (rv) 525 return (rv); 526 } else if (argc >= 1 && argv[0][0] == '-') { 527 usage(-1); 528 return (1); 529 } 530 531 /* Always turns off Metaslot so that we can see softtoken. */ 532 if (setenv("METASLOT_ENABLED", "false", 1) < 0) { 533 save_errno = errno; 534 cryptoerror(LOG_STDERR, 535 gettext("Disabling Metaslot failed (%s)."), 536 strerror(save_errno)); 537 return (1); 538 } 539 540 /* Begin parsing command line. */ 541 if (pk_argc == 0 && pk_argv == NULL) { 542 pk_argc = argc; 543 pk_argv = argv; 544 } 545 546 /* Check for valid verb (or an abbreviation of it). */ 547 found = -1; 548 for (i = 0; i < num_cmds; i++) { 549 if (strcmp(cmds[i].verb, pk_argv[0]) == 0) { 550 if (found < 0) { 551 found = i; 552 break; 553 } 554 } 555 } 556 /* Stop here if no valid verb found. */ 557 if (found < 0) { 558 cryptoerror(LOG_STDERR, gettext("Invalid verb: %s"), 559 pk_argv[0]); 560 return (1); 561 } 562 563 /* Get to work! */ 564 rv = (*cmds[found].action)(pk_argc, pk_argv); 565 switch (rv) { 566 case PK_ERR_NONE: 567 break; /* Command succeeded, do nothing. */ 568 case PK_ERR_USAGE: 569 usage(found); 570 break; 571 case PK_ERR_QUIT: 572 exit(0); 573 /* NOTREACHED */ 574 case PK_ERR_PK11: 575 case PK_ERR_SYSTEM: 576 case PK_ERR_OPENSSL: 577 case PK_ERR_NSS: 578 default: 579 break; 580 } 581 return (rv); 582 } 583