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 /* 23 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Developer command for adding the signature section to an ELF object 28 * PSARC 2001/488 29 * 30 * DEBUG Information: 31 * This command uses the cryptodebug() function from libcryptoutil. 32 * Set SUNW_CRYPTO_DEBUG to stderr or syslog for all debug to go to auth.debug 33 */ 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <stdarg.h> 38 #include <limits.h> 39 #include <time.h> 40 #include <unistd.h> 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <fcntl.h> 44 #include <libintl.h> 45 #include <locale.h> 46 #include <errno.h> 47 #include <strings.h> 48 49 #include <cryptoutil.h> 50 #include <sys/crypto/elfsign.h> 51 #include <libelfsign.h> 52 53 #include <kmfapi.h> 54 55 #define SIGN "sign" 56 #define SIGN_OPTS "c:e:F:k:P:T:v" 57 #define VERIFY "verify" 58 #define VERIFY_OPTS "c:e:v" 59 #define REQUEST "request" 60 #define REQUEST_OPTS "i:k:r:T:" 61 #define LIST "list" 62 #define LIST_OPTS "c:e:f:" 63 64 enum cmd_e { 65 ES_SIGN, 66 ES_VERIFY, 67 ES_REQUEST, 68 ES_LIST 69 }; 70 71 enum field_e { 72 FLD_UNKNOWN, 73 FLD_SUBJECT, 74 FLD_ISSUER, 75 FLD_FORMAT, 76 FLD_SIGNER, 77 FLD_TIME 78 }; 79 80 #define MIN_ARGS 3 /* The minimum # args to do anything */ 81 #define ES_DEFAULT_KEYSIZE 1024 82 83 static struct { 84 enum cmd_e cmd; /* sub command: sign | verify | request */ 85 char *cert; /* -c <certificate_file> | */ 86 /* -r <certificate_request_file> */ 87 char **elfobj; /* -e <elf_object> */ 88 int elfcnt; 89 enum ES_ACTION es_action; 90 ELFsign_t ess; /* libelfsign opaque "state" */ 91 int extracnt; 92 enum field_e field; /* -f <field> */ 93 char internal_req; /* Sun internal certificate request */ 94 char *pinpath; /* -P <pin> */ 95 char *privpath; /* -k <private_key> */ 96 char *token_label; /* -T <token_label> */ 97 boolean_t verbose; /* chatty output */ 98 } cmd_info; 99 100 enum ret_e { 101 EXIT_OKAY, 102 EXIT_INVALID_ARG, 103 EXIT_VERIFY_FAILED, 104 EXIT_CANT_OPEN_ELF_OBJECT, 105 EXIT_BAD_CERT, 106 EXIT_BAD_PRIVATEKEY, 107 EXIT_SIGN_FAILED, 108 EXIT_VERIFY_FAILED_UNSIGNED, 109 EXIT_CSR_FAILED, 110 EXIT_MEMORY_ERROR 111 }; 112 113 struct field_s { 114 char *name; 115 enum field_e field; 116 } fields[] = { 117 { "subject", FLD_SUBJECT }, 118 { "issuer", FLD_ISSUER }, 119 { "format", FLD_FORMAT }, 120 { "signer", FLD_SIGNER }, 121 { "time", FLD_TIME }, 122 NULL, 0 123 }; 124 125 typedef enum ret_e ret_t; 126 127 static void usage(void); 128 static ret_t getelfobj(char *); 129 static char *getpin(void); 130 static ret_t do_sign(char *); 131 static ret_t do_verify(char *); 132 static ret_t do_cert_request(char *); 133 static ret_t do_list(char *); 134 static void es_error(const char *fmt, ...); 135 static char *time_str(time_t t); 136 static void sig_info_print(struct ELFsign_sig_info *esip); 137 138 int 139 main(int argc, char **argv) 140 { 141 extern char *optarg; 142 char *scmd = NULL; 143 char *opts; /* The set of flags for cmd */ 144 int errflag = 0; /* We had an options parse error */ 145 char c; /* current getopts flag */ 146 ret_t (*action)(char *); /* Function pointer for the action */ 147 ret_t ret; 148 149 (void) setlocale(LC_ALL, ""); 150 #if !defined(TEXT_DOMAIN) /* Should be defiend by cc -D */ 151 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 152 #endif 153 (void) textdomain(TEXT_DOMAIN); 154 155 cryptodebug_init("elfsign"); 156 157 if (argc < MIN_ARGS) { 158 es_error(gettext("invalid number of arguments")); 159 usage(); 160 return (EXIT_INVALID_ARG); 161 } 162 163 scmd = argv[1]; 164 cmd_info.cert = NULL; 165 cmd_info.elfobj = NULL; 166 cmd_info.elfcnt = 0; 167 cmd_info.es_action = ES_GET; 168 cmd_info.ess = NULL; 169 cmd_info.extracnt = 0; 170 cmd_info.field = FLD_UNKNOWN; 171 cmd_info.internal_req = '\0'; 172 cmd_info.pinpath = NULL; 173 cmd_info.privpath = NULL; 174 cmd_info.token_label = NULL; 175 cmd_info.verbose = B_FALSE; 176 177 if (strcmp(scmd, SIGN) == 0) { 178 cmd_info.cmd = ES_SIGN; 179 opts = SIGN_OPTS; 180 cryptodebug("cmd=sign opts=%s", opts); 181 action = do_sign; 182 cmd_info.es_action = ES_UPDATE_RSA_SHA1; 183 } else if (strcmp(scmd, VERIFY) == 0) { 184 cmd_info.cmd = ES_VERIFY; 185 opts = VERIFY_OPTS; 186 cryptodebug("cmd=verify opts=%s", opts); 187 action = do_verify; 188 } else if (strcmp(scmd, REQUEST) == 0) { 189 cmd_info.cmd = ES_REQUEST; 190 opts = REQUEST_OPTS; 191 cryptodebug("cmd=request opts=%s", opts); 192 action = do_cert_request; 193 } else if (strcmp(scmd, LIST) == 0) { 194 cmd_info.cmd = ES_LIST; 195 opts = LIST_OPTS; 196 cryptodebug("cmd=list opts=%s", opts); 197 action = do_list; 198 } else { 199 es_error(gettext("Unknown sub-command: %s"), 200 scmd); 201 usage(); 202 return (EXIT_INVALID_ARG); 203 } 204 205 /* 206 * Note: There is no need to check that optarg isn't NULL 207 * because getopt does that for us. 208 */ 209 while (!errflag && (c = getopt(argc - 1, argv + 1, opts)) != EOF) { 210 if (strchr("ceFihkPTr", c) != NULL) 211 cryptodebug("c=%c, '%s'", c, optarg); 212 else 213 cryptodebug("c=%c", c); 214 215 switch (c) { 216 case 'c': 217 cmd_info.cert = optarg; 218 break; 219 case 'e': 220 cmd_info.elfcnt++; 221 cmd_info.elfobj = (char **)realloc(cmd_info.elfobj, 222 sizeof (char *) * cmd_info.elfcnt); 223 if (cmd_info.elfobj == NULL) { 224 es_error(gettext( 225 "Too many elf objects specified.")); 226 return (EXIT_INVALID_ARG); 227 } 228 cmd_info.elfobj[cmd_info.elfcnt - 1] = optarg; 229 break; 230 case 'f': 231 { 232 struct field_s *fp; 233 cmd_info.field = FLD_UNKNOWN; 234 for (fp = fields; fp->name != NULL; fp++) { 235 if (strcasecmp(optarg, fp->name) == 0) { 236 cmd_info.field = fp->field; 237 break; 238 } 239 } 240 if (cmd_info.field == FLD_UNKNOWN) { 241 cryptodebug("Invalid field option"); 242 errflag++; 243 } 244 } 245 break; 246 case 'F': 247 if (strcasecmp(optarg, ES_FMT_RSA_MD5_SHA1) == 0) 248 cmd_info.es_action = ES_UPDATE_RSA_MD5_SHA1; 249 else if (strcasecmp(optarg, ES_FMT_RSA_SHA1) == 0) 250 cmd_info.es_action = ES_UPDATE_RSA_SHA1; 251 else { 252 cryptodebug("Invalid format option"); 253 errflag++; 254 } 255 break; 256 case 'i': /* Undocumented internal Sun use only */ 257 cmd_info.internal_req = *optarg; 258 break; 259 case 'k': 260 cmd_info.privpath = optarg; 261 if (cmd_info.token_label != NULL || 262 cmd_info.pinpath != NULL) 263 errflag++; 264 break; 265 case 'P': 266 cmd_info.pinpath = optarg; 267 if (cmd_info.privpath != NULL) 268 errflag++; 269 break; 270 case 'r': 271 cmd_info.cert = optarg; 272 break; 273 case 'T': 274 cmd_info.token_label = optarg; 275 if (cmd_info.privpath != NULL) 276 errflag++; 277 break; 278 case 'v': 279 cmd_info.verbose = B_TRUE; 280 break; 281 default: 282 errflag++; 283 } 284 } 285 286 optind++; /* we skipped over subcommand */ 287 cmd_info.extracnt = argc - optind; 288 289 if (cmd_info.extracnt != 0 && 290 cmd_info.cmd != ES_SIGN && cmd_info.cmd != ES_VERIFY) { 291 cryptodebug("Extra arguments, optind=%d, argc=%d", 292 optind, argc); 293 errflag++; 294 } 295 296 switch (cmd_info.cmd) { 297 case ES_VERIFY: 298 if (cmd_info.elfcnt + argc - optind == 0) { 299 cryptodebug("Missing elfobj"); 300 errflag++; 301 } 302 break; 303 304 case ES_SIGN: 305 if (((cmd_info.privpath == NULL) && 306 (cmd_info.token_label == NULL)) || 307 (cmd_info.cert == NULL) || 308 (cmd_info.elfcnt + argc - optind == 0)) { 309 cryptodebug("Missing privpath|token_label/cert/elfobj"); 310 errflag++; 311 } 312 break; 313 314 case ES_REQUEST: 315 if (((cmd_info.privpath == NULL) && 316 (cmd_info.token_label == NULL)) || 317 (cmd_info.cert == NULL)) { 318 cryptodebug("Missing privpath|token_label/certreq"); 319 errflag++; 320 } 321 break; 322 case ES_LIST: 323 if ((cmd_info.cert != NULL) == (cmd_info.elfcnt > 0)) { 324 cryptodebug("Neither or both of cert/elfobj"); 325 errflag++; 326 } 327 break; 328 } 329 330 if (errflag) { 331 usage(); 332 return (EXIT_INVALID_ARG); 333 } 334 335 switch (cmd_info.cmd) { 336 case ES_REQUEST: 337 case ES_LIST: 338 ret = action(NULL); 339 break; 340 default: 341 { 342 int i; 343 ret_t iret; 344 345 ret = EXIT_OKAY; 346 iret = EXIT_OKAY; 347 for (i = 0; i < cmd_info.elfcnt && 348 (ret == EXIT_OKAY || cmd_info.cmd != ES_SIGN); i++) { 349 iret = action(cmd_info.elfobj[i]); 350 if (iret > ret) 351 ret = iret; 352 } 353 for (i = optind; i < argc && 354 (ret == EXIT_OKAY || cmd_info.cmd != ES_SIGN); i++) { 355 iret = action(argv[i]); 356 if (iret > ret) 357 ret = iret; 358 } 359 break; 360 } 361 } 362 363 if (cmd_info.elfobj != NULL) 364 free(cmd_info.elfobj); 365 366 return (ret); 367 } 368 369 370 static void 371 usage(void) 372 { 373 /* BEGIN CSTYLED */ 374 (void) fprintf(stderr, gettext( 375 "usage:\n" 376 "\telfsign sign [-v] [-e <elf_object>] -c <certificate_file>\n" 377 "\t\t[-F <format>] -k <private_key_file> [elf_object]..." 378 "\n" 379 "\telfsign sign [-v] [-e <elf_object>] -c <certificate_file>\n" 380 "\t\t[-F <format>] -T <token_label> [-P <pin_file>] [elf_object]..." 381 "\n\n" 382 "\telfsign verify [-v] [-c <certificate_file>] [-e <elf_object>]\n" 383 "\t\t[elf_object]..." 384 "\n\n" 385 "\telfsign request -r <certificate_request_file> -k <private_key_file>" 386 "\n" 387 "\telfsign request -r <certificate_request_file> -T <token_label>" 388 "\n\n" 389 "\telfsign list -f field -c <certificate_file>" 390 "\n" 391 "\telfsign list -f field -e <elf_object>" 392 "\n")); 393 /* END CSTYLED */ 394 } 395 396 static ret_t 397 getelfobj(char *elfpath) 398 { 399 ELFsign_status_t estatus; 400 ret_t ret = EXIT_SIGN_FAILED; 401 402 estatus = elfsign_begin(elfpath, cmd_info.es_action, &(cmd_info.ess)); 403 switch (estatus) { 404 case ELFSIGN_SUCCESS: 405 ret = EXIT_OKAY; 406 break; 407 case ELFSIGN_INVALID_ELFOBJ: 408 es_error(gettext( 409 "Unable to open %s as an ELF object."), 410 elfpath); 411 ret = EXIT_CANT_OPEN_ELF_OBJECT; 412 break; 413 default: 414 es_error(gettext("unexpected failure: %d"), estatus); 415 if (cmd_info.cmd == ES_SIGN) { 416 ret = EXIT_SIGN_FAILED; 417 } else if (cmd_info.cmd == ES_VERIFY) { 418 ret = EXIT_VERIFY_FAILED; 419 } 420 } 421 422 return (ret); 423 } 424 425 static ret_t 426 setcertpath(void) 427 { 428 ELFsign_status_t estatus; 429 ret_t ret = EXIT_SIGN_FAILED; 430 431 if (cmd_info.cert == NULL) 432 return (EXIT_OKAY); 433 estatus = elfsign_setcertpath(cmd_info.ess, cmd_info.cert); 434 switch (estatus) { 435 case ELFSIGN_SUCCESS: 436 ret = EXIT_OKAY; 437 break; 438 case ELFSIGN_INVALID_CERTPATH: 439 if (cmd_info.cert != NULL) { 440 es_error(gettext("Unable to open %s as a certificate."), 441 cmd_info.cert); 442 } 443 ret = EXIT_BAD_CERT; 444 break; 445 default: 446 es_error(gettext("unusable certificate: %s"), cmd_info.cert); 447 if (cmd_info.cmd == ES_SIGN) { 448 ret = EXIT_SIGN_FAILED; 449 } else if (cmd_info.cmd == ES_VERIFY) { 450 ret = EXIT_VERIFY_FAILED; 451 } 452 } 453 454 return (ret); 455 } 456 457 /* 458 * getpin - return pointer to token PIN in static storage 459 */ 460 static char * 461 getpin(void) 462 { 463 static char pinbuf[PASS_MAX + 1]; 464 char *pp; 465 FILE *pinfile; 466 467 if (cmd_info.pinpath == NULL) 468 return (getpassphrase( 469 gettext("Enter PIN for PKCS#11 token: "))); 470 if ((pinfile = fopen(cmd_info.pinpath, "r")) == NULL) { 471 es_error(gettext("failed to open %s."), 472 cmd_info.pinpath); 473 return (NULL); 474 } 475 476 pp = fgets(pinbuf, sizeof (pinbuf), pinfile); 477 (void) fclose(pinfile); 478 if (pp == NULL) { 479 es_error(gettext("failed to read PIN from %s."), 480 cmd_info.pinpath); 481 return (NULL); 482 } 483 pp = &pinbuf[strlen(pinbuf) - 1]; 484 if (*pp == '\n') 485 *pp = '\0'; 486 return (pinbuf); 487 } 488 489 /* 490 * Add the .SUNW_signature sections for the ELF signature 491 */ 492 static ret_t 493 do_sign(char *object) 494 { 495 ret_t ret; 496 ELFsign_status_t elfstat; 497 struct filesignatures *fssp = NULL; 498 size_t fs_len; 499 uchar_t sig[SIG_MAX_LENGTH]; 500 size_t sig_len = SIG_MAX_LENGTH; 501 uchar_t hash[SIG_MAX_LENGTH]; 502 size_t hash_len = SIG_MAX_LENGTH; 503 ELFCert_t cert = NULL; 504 char *dn; 505 size_t dn_len; 506 507 cryptodebug("do_sign"); 508 if ((ret = getelfobj(object)) != EXIT_OKAY) 509 return (ret); 510 511 if (cmd_info.token_label && 512 !elfcertlib_settoken(cmd_info.ess, cmd_info.token_label)) { 513 es_error(gettext("Unable to access token: %s"), 514 cmd_info.token_label); 515 ret = EXIT_SIGN_FAILED; 516 goto cleanup; 517 } 518 519 if ((ret = setcertpath()) != EXIT_OKAY) 520 goto cleanup; 521 522 if (!elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, &cert, 523 cmd_info.es_action)) { 524 es_error(gettext("Unable to load certificate: %s"), 525 cmd_info.cert); 526 ret = EXIT_BAD_CERT; 527 goto cleanup; 528 } 529 530 if (cmd_info.privpath != NULL) { 531 if (!elfcertlib_loadprivatekey(cmd_info.ess, cert, 532 cmd_info.privpath)) { 533 es_error(gettext("Unable to load private key: %s"), 534 cmd_info.privpath); 535 ret = EXIT_BAD_PRIVATEKEY; 536 goto cleanup; 537 } 538 } else { 539 char *pin = getpin(); 540 if (pin == NULL) { 541 es_error(gettext("Unable to get PIN")); 542 ret = EXIT_BAD_PRIVATEKEY; 543 goto cleanup; 544 } 545 if (!elfcertlib_loadtokenkey(cmd_info.ess, cert, 546 cmd_info.token_label, pin)) { 547 es_error(gettext("Unable to access private key " 548 "in token %s"), cmd_info.token_label); 549 ret = EXIT_BAD_PRIVATEKEY; 550 goto cleanup; 551 } 552 } 553 554 /* 555 * Get the DN from the certificate. 556 */ 557 if ((dn = elfcertlib_getdn(cert)) == NULL) { 558 es_error(gettext("Unable to find DN in certificate %s"), 559 cmd_info.cert); 560 ret = EXIT_SIGN_FAILED; 561 goto cleanup; 562 } 563 dn_len = strlen(dn); 564 cryptodebug("DN = %s", dn); 565 566 elfstat = elfsign_signatures(cmd_info.ess, &fssp, &fs_len, ES_GET); 567 if (elfstat != ELFSIGN_SUCCESS) { 568 if (elfstat != ELFSIGN_NOTSIGNED) { 569 es_error(gettext("Unable to retrieve existing " 570 "signature block in %s"), object); 571 ret = EXIT_SIGN_FAILED; 572 goto cleanup; 573 } 574 fssp = NULL; 575 /* 576 * force creation and naming of signature section 577 * so the hash doesn't change 578 */ 579 if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len, 580 cmd_info.es_action) != ELFSIGN_SUCCESS) { 581 es_error(gettext("Unable to insert " 582 "signature block into %s"), object); 583 ret = EXIT_SIGN_FAILED; 584 goto cleanup; 585 } 586 } 587 588 bzero(hash, sizeof (hash)); 589 if (elfsign_hash(cmd_info.ess, hash, &hash_len) != ELFSIGN_SUCCESS) { 590 es_error(gettext("Unable to calculate hash of ELF object %s"), 591 object); 592 ret = EXIT_SIGN_FAILED; 593 goto cleanup; 594 } 595 596 bzero(sig, sizeof (sig)); 597 if (!elfcertlib_sign(cmd_info.ess, cert, 598 hash, hash_len, sig, &sig_len)) { 599 es_error(gettext("Unable to sign %s using key from %s"), 600 object, cmd_info.privpath ? 601 cmd_info.privpath : cmd_info.token_label); 602 ret = EXIT_SIGN_FAILED; 603 goto cleanup; 604 } 605 606 { /* DEBUG START */ 607 const int sigstr_len = sizeof (char) * sig_len * 2 + 1; 608 char *sigstr = malloc(sigstr_len); 609 610 tohexstr(sig, sig_len, sigstr, sigstr_len); 611 cryptodebug("sig value is: %s", sigstr); 612 free(sigstr); 613 } /* DEBUG END */ 614 615 fssp = elfsign_insert_dso(cmd_info.ess, fssp, 616 dn, dn_len, sig, sig_len, NULL, 0); 617 if (fssp == NULL) { 618 es_error(gettext("Unable to prepare signature for %s"), 619 object); 620 ret = EXIT_SIGN_FAILED; 621 goto cleanup; 622 } 623 if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len, 624 cmd_info.es_action) != ELFSIGN_SUCCESS) { 625 es_error(gettext("Unable to update %s: with signature"), 626 object); 627 ret = EXIT_SIGN_FAILED; 628 goto cleanup; 629 } 630 if (cmd_info.verbose || (cmd_info.elfcnt + cmd_info.extracnt) > 1) { 631 (void) fprintf(stdout, 632 gettext("elfsign: %s signed successfully.\n"), 633 object); 634 } 635 if (cmd_info.verbose) { 636 struct ELFsign_sig_info *esip; 637 638 if (elfsign_sig_info(fssp, &esip)) { 639 sig_info_print(esip); 640 elfsign_sig_info_free(esip); 641 } 642 } 643 644 ret = EXIT_OKAY; 645 646 cleanup: 647 free(fssp); 648 bzero(sig, sig_len); 649 bzero(hash, hash_len); 650 651 if (cert != NULL) 652 elfcertlib_releasecert(cmd_info.ess, cert); 653 if (cmd_info.ess != NULL) 654 elfsign_end(cmd_info.ess); 655 656 return (ret); 657 } 658 659 /* 660 * Verify the signature of the object 661 * This subcommand is intended to be used by developers during their build 662 * processes. Therefore we can not assume that the certificate is in 663 * /etc/crypto/certs so we must use the path we got from the commandline. 664 */ 665 static ret_t 666 do_verify(char *object) 667 { 668 ELFsign_status_t res; 669 struct ELFsign_sig_info *esip; 670 ret_t retval; 671 672 cryptodebug("do_verify"); 673 if ((retval = getelfobj(object)) != EXIT_OKAY) 674 return (retval); 675 676 if ((retval = setcertpath()) != EXIT_OKAY) { 677 elfsign_end(cmd_info.ess); 678 return (retval); 679 } 680 681 res = elfsign_verify_signature(cmd_info.ess, &esip); 682 switch (res) { 683 case ELFSIGN_SUCCESS: 684 (void) fprintf(stdout, 685 gettext("elfsign: verification of %s passed.\n"), 686 object); 687 if (cmd_info.verbose) 688 sig_info_print(esip); 689 retval = EXIT_OKAY; 690 break; 691 case ELFSIGN_FAILED: 692 case ELFSIGN_INVALID_CERTPATH: 693 es_error(gettext("verification of %s failed."), 694 object); 695 if (cmd_info.verbose) 696 sig_info_print(esip); 697 retval = EXIT_VERIFY_FAILED; 698 break; 699 case ELFSIGN_NOTSIGNED: 700 es_error(gettext("no signature found in %s."), 701 object); 702 retval = EXIT_VERIFY_FAILED_UNSIGNED; 703 break; 704 default: 705 es_error(gettext("unexpected failure attempting verification " 706 "of %s."), object); 707 retval = EXIT_VERIFY_FAILED_UNSIGNED; 708 break; 709 } 710 711 if (esip != NULL) 712 elfsign_sig_info_free(esip); 713 if (cmd_info.ess != NULL) 714 elfsign_end(cmd_info.ess); 715 return (retval); 716 } 717 718 #define SET_VALUE(f, s) \ 719 kmfrv = f; \ 720 if (kmfrv != KMF_OK) { \ 721 char *e = NULL; \ 722 (void) kmf_get_kmf_error_str(kmfrv, &e); \ 723 cryptoerror(LOG_STDERR, \ 724 gettext("Failed to %s: %s\n"), \ 725 s, (e ? e : "unknown error")); \ 726 if (e) free(e); \ 727 goto cleanup; \ 728 } 729 730 static KMF_RETURN 731 create_csr(char *dn) 732 { 733 KMF_RETURN kmfrv = KMF_OK; 734 KMF_HANDLE_T kmfhandle = NULL; 735 KMF_KEY_HANDLE pubk, prik; 736 KMF_X509_NAME csrSubject; 737 KMF_CSR_DATA csr; 738 KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_MD5WithRSA; 739 KMF_DATA signedCsr = { NULL, 0 }; 740 char *err; 741 KMF_ATTRIBUTE attrlist[16]; 742 KMF_ENCODE_FORMAT format; 743 KMF_KEYSTORE_TYPE kstype; 744 KMF_KEY_ALG keytype; 745 uint32_t keylength; 746 KMF_CREDENTIAL cred; 747 char *pin = NULL; 748 int numattr; 749 750 if ((kmfrv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { 751 (void) kmf_get_kmf_error_str(kmfrv, &err); 752 cryptoerror(LOG_STDERR, 753 gettext("Error initializing KMF: %s\n"), 754 (err ? err : "unknown error")); 755 if (err) 756 free(err); 757 return (kmfrv); 758 } 759 (void) memset(&csr, 0, sizeof (csr)); 760 (void) memset(&csrSubject, 0, sizeof (csrSubject)); 761 762 if (cmd_info.privpath != NULL) { 763 kstype = KMF_KEYSTORE_OPENSSL; 764 format = KMF_FORMAT_ASN1; 765 } else { 766 boolean_t readonly; 767 /* args checking verified (cmd_info.token_label != NULL) */ 768 769 /* Get a PIN to store the private key in the token */ 770 pin = getpin(); 771 772 if (pin == NULL) { 773 (void) kmf_finalize(kmfhandle); 774 return (KMF_ERR_AUTH_FAILED); 775 } 776 777 kstype = KMF_KEYSTORE_PK11TOKEN; 778 readonly = B_FALSE; 779 780 numattr = 0; 781 kmf_set_attr_at_index(attrlist, numattr++, 782 KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); 783 kmf_set_attr_at_index(attrlist, numattr++, 784 KMF_TOKEN_LABEL_ATTR, cmd_info.token_label, 785 strlen(cmd_info.token_label)); 786 kmf_set_attr_at_index(attrlist, numattr++, 787 KMF_READONLY_ATTR, &readonly, sizeof (readonly)); 788 kmfrv = kmf_configure_keystore(kmfhandle, numattr, attrlist); 789 if (kmfrv != KMF_OK) { 790 goto cleanup; 791 } 792 } 793 794 /* Create the RSA keypair */ 795 keytype = KMF_RSA; 796 keylength = ES_DEFAULT_KEYSIZE; 797 (void) memset(&prik, 0, sizeof (prik)); 798 (void) memset(&pubk, 0, sizeof (pubk)); 799 800 numattr = 0; 801 kmf_set_attr_at_index(attrlist, numattr++, 802 KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); 803 kmf_set_attr_at_index(attrlist, numattr++, 804 KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); 805 kmf_set_attr_at_index(attrlist, numattr++, 806 KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength)); 807 if (pin != NULL) { 808 cred.cred = pin; 809 cred.credlen = strlen(pin); 810 kmf_set_attr_at_index(attrlist, numattr++, 811 KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL)); 812 } 813 kmf_set_attr_at_index(attrlist, numattr++, 814 KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE)); 815 kmf_set_attr_at_index(attrlist, numattr++, 816 KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE)); 817 if (kstype == KMF_KEYSTORE_OPENSSL) { 818 kmf_set_attr_at_index(attrlist, numattr++, 819 KMF_KEY_FILENAME_ATTR, cmd_info.privpath, 820 strlen(cmd_info.privpath)); 821 kmf_set_attr_at_index(attrlist, numattr++, 822 KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); 823 } 824 825 kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist); 826 if (kmfrv != KMF_OK) { 827 (void) kmf_get_kmf_error_str(kmfrv, &err); 828 cryptoerror(LOG_STDERR, 829 gettext("Create RSA keypair failed: %s"), 830 (err ? err : "unknown error")); 831 free(err); 832 goto cleanup; 833 } 834 835 kmfrv = kmf_dn_parser(dn, &csrSubject); 836 if (kmfrv != KMF_OK) { 837 (void) kmf_get_kmf_error_str(kmfrv, &err); 838 cryptoerror(LOG_STDERR, 839 gettext("Error parsing subject name: %s\n"), 840 (err ? err : "unknown error")); 841 free(err); 842 goto cleanup; 843 } 844 845 SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "keypair"); 846 847 SET_VALUE(kmf_set_csr_version(&csr, 2), "version number"); 848 849 SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), "subject name"); 850 851 SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "SignatureAlgorithm"); 852 853 if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) == 854 KMF_OK) { 855 kmfrv = kmf_create_csr_file(&signedCsr, KMF_FORMAT_PEM, 856 cmd_info.cert); 857 } 858 859 cleanup: 860 (void) kmf_free_kmf_key(kmfhandle, &prik); 861 (void) kmf_free_data(&signedCsr); 862 (void) kmf_free_signed_csr(&csr); 863 (void) kmf_finalize(kmfhandle); 864 865 return (kmfrv); 866 } 867 868 869 #define CN_MAX_LENGTH 64 /* Verisign implementation limit */ 870 /* 871 * Generate a certificate request into the file named cmd_info.cert 872 */ 873 /*ARGSUSED*/ 874 static ret_t 875 do_cert_request(char *object) 876 { 877 const char PartnerDNFMT[] = 878 "CN=%s, " 879 "OU=Class B, " 880 "OU=Solaris Cryptographic Framework, " 881 "OU=Partner Object Signing, " 882 "O=Sun Microsystems Inc"; 883 const char SunCDNFMT[] = 884 "CN=%s, " 885 "OU=Class B, " 886 "OU=Solaris Cryptographic Framework, " 887 "OU=Corporate Object Signing, " 888 "O=Sun Microsystems Inc"; 889 const char SunSDNFMT[] = 890 "CN=%s, " 891 "OU=Class B, " 892 "OU=Solaris Signed Execution, " 893 "OU=Corporate Object Signing, " 894 "O=Sun Microsystems Inc"; 895 const char *dnfmt = NULL; 896 char cn[CN_MAX_LENGTH + 1]; 897 char *dn = NULL; 898 size_t dn_len; 899 KMF_RETURN kmfret; 900 cryptodebug("do_cert_request"); 901 902 /* 903 * Get the DN prefix from the user 904 */ 905 switch (cmd_info.internal_req) { 906 case 'c': 907 dnfmt = SunCDNFMT; 908 (void) fprintf(stdout, gettext( 909 "Enter Sun Microsystems, Inc. Release name.\n" 910 "This will be the prefix of the Certificate DN: ")); 911 break; 912 case 's': 913 dnfmt = SunSDNFMT; 914 (void) fprintf(stdout, gettext( 915 "Enter Sun Microsystems, Inc. Release name.\n" 916 "This will be the prefix of the Certificate DN: ")); 917 break; 918 default: 919 dnfmt = PartnerDNFMT; 920 (void) fprintf(stdout, gettext( 921 "Enter Company Name / Stock Symbol" 922 " or some other globally unique identifier.\n" 923 "This will be the prefix of the Certificate DN: ")); 924 break; 925 } 926 927 (void) fgets(cn, sizeof (cn), stdin); 928 if ((cn == NULL) || (cn[0] == '\n')) { 929 es_error(gettext("you must specify a Certificate DN prefix")); 930 return (EXIT_INVALID_ARG); 931 } 932 933 if (cn[strlen(cn) - 1] == '\n') { 934 cn[strlen(cn) - 1] = '\0'; /* chop trailing \n */ 935 } else { 936 es_error(gettext("You must specify a Certificate DN prefix " 937 "of no more than %d characters"), CN_MAX_LENGTH); 938 return (EXIT_INVALID_ARG); 939 } 940 941 /* Update DN string */ 942 dn_len = strlen(cn) + strlen(dnfmt); 943 dn = malloc(dn_len + 1); 944 (void) snprintf(dn, dn_len, dnfmt, cn); 945 946 cryptodebug("Generating Certificate request for DN: %s", dn); 947 kmfret = create_csr(dn); 948 free(dn); 949 if (kmfret == KMF_OK) 950 return (EXIT_OKAY); 951 else 952 return (EXIT_CSR_FAILED); 953 } 954 955 static void 956 str_print(char *s) 957 { 958 if (s == NULL) 959 return; 960 (void) fprintf(stdout, "%s\n", s); 961 } 962 963 /*ARGSUSED*/ 964 static ret_t 965 do_list(char *object) 966 { 967 ret_t retval; 968 969 if (cmd_info.elfcnt > 0) { 970 ELFsign_status_t elfstat; 971 struct filesignatures *fssp = NULL; 972 size_t fs_len; 973 struct ELFsign_sig_info *esip; 974 975 if ((retval = getelfobj(cmd_info.elfobj[0])) != EXIT_OKAY) 976 return (retval); 977 elfstat = elfsign_signatures(cmd_info.ess, 978 &fssp, &fs_len, ES_GET); 979 if (elfstat == ELFSIGN_SUCCESS) { 980 retval = EXIT_OKAY; 981 if (elfsign_sig_info(fssp, &esip)) { 982 switch (cmd_info.field) { 983 case FLD_FORMAT: 984 str_print(esip->esi_format); 985 break; 986 case FLD_SIGNER: 987 str_print(esip->esi_signer); 988 break; 989 case FLD_TIME: 990 if (esip->esi_time == 0) 991 retval = EXIT_INVALID_ARG; 992 else 993 str_print(time_str( 994 esip->esi_time)); 995 break; 996 default: 997 retval = EXIT_INVALID_ARG; 998 } 999 elfsign_sig_info_free(esip); 1000 } 1001 free(fssp); 1002 } else 1003 retval = EXIT_VERIFY_FAILED_UNSIGNED; 1004 elfsign_end(cmd_info.ess); 1005 } else { 1006 ELFCert_t cert; 1007 /* 1008 * Initialize the ESS record here even though we are not 1009 * actually opening any ELF files. 1010 */ 1011 if (elfsign_begin(NULL, ES_GET, &(cmd_info.ess)) != 1012 ELFSIGN_SUCCESS) 1013 return (EXIT_MEMORY_ERROR); 1014 1015 if (elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, 1016 &cert, cmd_info.es_action)) { 1017 retval = EXIT_OKAY; 1018 switch (cmd_info.field) { 1019 case FLD_SUBJECT: 1020 str_print(elfcertlib_getdn(cert)); 1021 break; 1022 case FLD_ISSUER: 1023 str_print(elfcertlib_getissuer(cert)); 1024 break; 1025 default: 1026 retval = EXIT_INVALID_ARG; 1027 } 1028 elfcertlib_releasecert(cmd_info.ess, cert); 1029 } else 1030 retval = EXIT_BAD_CERT; 1031 elfsign_end(cmd_info.ess); 1032 } 1033 1034 return (retval); 1035 } 1036 1037 static void 1038 es_error(const char *fmt, ...) 1039 { 1040 char msgbuf[BUFSIZ]; 1041 va_list args; 1042 1043 va_start(args, fmt); 1044 (void) vsnprintf(msgbuf, sizeof (msgbuf), fmt, args); 1045 va_end(args); 1046 (void) fflush(stdout); 1047 cryptoerror(LOG_STDERR, "%s", msgbuf); 1048 (void) fflush(stderr); 1049 } 1050 1051 static char * 1052 time_str(time_t t) 1053 { 1054 static char buf[80]; 1055 char *bufp; 1056 1057 bufp = buf; 1058 if (strftime(buf, sizeof (buf), NULL, localtime(&t)) == 0) 1059 bufp = ctime(&t); 1060 return (bufp); 1061 } 1062 1063 static void 1064 sig_info_print(struct ELFsign_sig_info *esip) 1065 { 1066 if (esip == NULL) 1067 return; 1068 (void) fprintf(stdout, gettext("format: %s.\n"), esip->esi_format); 1069 (void) fprintf(stdout, gettext("signer: %s.\n"), esip->esi_signer); 1070 if (esip->esi_time == 0) 1071 return; 1072 (void) fprintf(stdout, gettext("signed on: %s.\n"), 1073 time_str(esip->esi_time)); 1074 } 1075