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 contains the functions that are shared among 30 * the various services this tool will ultimately provide. 31 * The functions in this file return PKCS#11 CK_RV errors. 32 * Only one session and one login per token is supported 33 * at this time. 34 */ 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <ctype.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <fcntl.h> 43 #include <tzfile.h> 44 #include <cryptoutil.h> 45 #include <security/cryptoki.h> 46 #include <kmfapi.h> 47 48 #include "common.h" 49 50 /* Local status variables. */ 51 static boolean_t initialized = B_FALSE; 52 static boolean_t session_opened = B_FALSE; 53 static boolean_t logged_in = B_FALSE; 54 55 /* Supporting structures and global variables for getopt_av(). */ 56 typedef struct av_opts_s { 57 int shortnm; /* short name character */ 58 char *longnm; /* long name string, NOT terminated */ 59 int longnm_len; /* length of long name string */ 60 boolean_t has_arg; /* takes optional argument */ 61 } av_opts; 62 static av_opts *opts_av = NULL; 63 static const char *_save_optstr = NULL; 64 static int _save_numopts = 0; 65 66 int optind_av = 1; 67 char *optarg_av = NULL; 68 69 static void close_sess(CK_SESSION_HANDLE); 70 static void logout_token(CK_SESSION_HANDLE); 71 72 /* 73 * Perform PKCS#11 setup here. Currently only C_Initialize is required, 74 * along with setting/resetting state variables. 75 */ 76 CK_RV 77 init_pk11(void) 78 { 79 CK_RV rv = CKR_OK; 80 81 /* If C_Initialize() already called, nothing to do here. */ 82 if (initialized == B_TRUE) 83 return (CKR_OK); 84 85 /* Reset state variables because C_Initialize() not yet done. */ 86 session_opened = B_FALSE; 87 logged_in = B_FALSE; 88 89 /* Initialize PKCS#11 library. */ 90 if ((rv = C_Initialize(NULL_PTR)) != CKR_OK && 91 rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { 92 return (rv); 93 } 94 95 initialized = B_TRUE; 96 return (CKR_OK); 97 } 98 99 /* 100 * Finalize PKCS#11 library and reset state variables. Open sessions, 101 * if any, are closed, and thereby any logins are logged out also. 102 */ 103 void 104 final_pk11(CK_SESSION_HANDLE sess) 105 { 106 107 /* If the library wasn't initialized, nothing to do here. */ 108 if (!initialized) 109 return; 110 111 /* Make sure the sesion is closed first. */ 112 close_sess(sess); 113 114 (void) C_Finalize(NULL); 115 initialized = B_FALSE; 116 } 117 118 /* 119 * Close PKCS#11 session and reset state variables. Any logins are 120 * logged out. 121 */ 122 static void 123 close_sess(CK_SESSION_HANDLE sess) 124 { 125 126 if (sess == NULL) { 127 return; 128 } 129 130 /* If session is already closed, nothing to do here. */ 131 if (!session_opened) 132 return; 133 134 /* Make sure user is logged out of token. */ 135 logout_token(sess); 136 137 (void) C_CloseSession(sess); 138 session_opened = B_FALSE; 139 } 140 141 /* 142 * Log user out of token and reset status variable. 143 */ 144 static void 145 logout_token(CK_SESSION_HANDLE sess) 146 { 147 148 if (sess == NULL) { 149 return; 150 } 151 152 /* If already logged out, nothing to do here. */ 153 if (!logged_in) 154 return; 155 156 (void) C_Logout(sess); 157 logged_in = B_FALSE; 158 } 159 160 /* 161 * Gets PIN from user. Caller needs to free the returned PIN when done. 162 * If two prompts are given, the PIN is confirmed with second prompt. 163 * Note that getphassphrase() may return data in static memory area. 164 */ 165 CK_RV 166 get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen) 167 { 168 char *save_phrase, *phrase1, *phrase2; 169 170 171 #ifdef DEBUG 172 if (getenv("TOKENPIN") != NULL) { 173 *pin = (CK_UTF8CHAR_PTR)strdup(getenv("TOKENPIN")); 174 *pinlen = strlen((char *)(*pin)); 175 return (CKR_OK); 176 } 177 #endif /* DEBUG */ 178 179 /* Prompt user for a PIN. */ 180 if (prompt1 == NULL) { 181 return (CKR_ARGUMENTS_BAD); 182 } 183 if ((phrase1 = getpassphrase(prompt1)) == NULL) { 184 return (CKR_FUNCTION_FAILED); 185 } 186 187 /* Duplicate 1st PIN in separate chunk of memory. */ 188 if ((save_phrase = strdup(phrase1)) == NULL) 189 return (CKR_HOST_MEMORY); 190 191 /* If second prompt given, PIN confirmation is requested. */ 192 if (prompt2 != NULL) { 193 if ((phrase2 = getpassphrase(prompt2)) == NULL) { 194 free(save_phrase); 195 return (CKR_FUNCTION_FAILED); 196 } 197 if (strcmp(save_phrase, phrase2) != 0) { 198 free(save_phrase); 199 return (CKR_PIN_INCORRECT); 200 } 201 } 202 203 *pin = (CK_UTF8CHAR_PTR)save_phrase; 204 *pinlen = strlen(save_phrase); 205 return (CKR_OK); 206 } 207 208 /* 209 * Gets yes/no response from user. If either no prompt is supplied, a 210 * default prompt is used. If not message for invalid input is supplied, 211 * a default will not be provided. If the user provides no response, 212 * the input default B_TRUE == yes, B_FALSE == no is returned. 213 * Otherwise, B_TRUE is returned for yes, and B_FALSE for no. 214 */ 215 boolean_t 216 yesno(char *prompt, char *invalid, boolean_t dflt) 217 { 218 char *response, buf[1024]; 219 char *yes = gettext("yes"); 220 char *no = gettext("no"); 221 222 223 #ifdef DEBUG 224 /* If debugging or testing, return TRUE and avoid prompting */ 225 if (getenv("TOKENPIN") != NULL) { 226 return (B_TRUE); 227 } 228 #endif /* DEBUG */ 229 230 if (prompt == NULL) 231 prompt = gettext("Enter (y)es or (n)o? "); 232 233 for (;;) { 234 /* Prompt user. */ 235 (void) printf("%s", prompt); 236 (void) fflush(stdout); 237 238 /* Get the response. */ 239 if ((response = fgets(buf, sizeof (buf), stdin)) == NULL) 240 break; /* go to default response */ 241 242 /* Skip any leading white space. */ 243 while (isspace(*response)) 244 response++; 245 if (*response == '\0') 246 break; /* go to default response */ 247 248 /* Is it valid input? Return appropriately. */ 249 if (strncasecmp(response, yes, 1) == 0) 250 return (B_TRUE); 251 if (strncasecmp(response, no, 1) == 0) 252 return (B_FALSE); 253 254 /* Indicate invalid input, and try again. */ 255 if (invalid != NULL) 256 (void) printf("%s", invalid); 257 } 258 return (dflt); 259 } 260 261 /* 262 * Gets the list of slots which have tokens in them. Keeps adjusting 263 * the size of the slot list buffer until the call is successful or an 264 * irrecoverable error occurs. 265 */ 266 CK_RV 267 get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) 268 { 269 CK_ULONG tmp_count = 0; 270 CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR; 271 int rv = CKR_OK; 272 273 if (!initialized) 274 if ((rv = init_pk11()) != CKR_OK) 275 return (rv); 276 277 /* 278 * Get the slot count first because we don't know how many 279 * slots there are and how many of those slots even have tokens. 280 * Don't specify an arbitrary buffer size for the slot list; 281 * it may be too small (see section 11.5 of PKCS#11 spec). 282 * Also select only those slots that have tokens in them, 283 * because this tool has no need to know about empty slots. 284 */ 285 if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK) 286 return (rv); 287 288 if (tmp_count == 0) { 289 *slot_list = NULL_PTR; 290 *slot_count = 0; 291 return (CKR_OK); 292 } 293 294 /* Allocate initial space for the slot list. */ 295 if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count * 296 sizeof (CK_SLOT_ID))) == NULL) 297 return (CKR_HOST_MEMORY); 298 299 /* Then get the slot list itself. */ 300 for (;;) { 301 if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) { 302 *slot_list = tmp_list; 303 *slot_count = tmp_count; 304 break; 305 } 306 307 if (rv != CKR_BUFFER_TOO_SMALL) { 308 free(tmp_list); 309 break; 310 } 311 312 /* If the number of slots grew, try again. */ 313 if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list, 314 tmp_count * sizeof (CK_SLOT_ID))) == NULL) { 315 free(tmp_list); 316 rv = CKR_HOST_MEMORY; 317 break; 318 } 319 tmp_list = tmp2_list; 320 } 321 322 return (rv); 323 } 324 325 /* 326 * Breaks out the getopt-style option string into a structure that can be 327 * traversed later for calls to getopt_av(). Option string is NOT altered, 328 * but the struct fields point to locations within option string. 329 */ 330 static int 331 populate_opts(char *optstring) 332 { 333 int i; 334 av_opts *temp; 335 char *marker; 336 337 if (optstring == NULL || *optstring == '\0') 338 return (0); 339 340 /* 341 * This tries to imitate getopt(3c) Each option must conform to: 342 * <short name char> [ ':' ] [ '(' <long name string> ')' ] 343 * If long name is missing, the short name is used for long name. 344 */ 345 for (i = 0; *optstring != '\0'; i++) { 346 if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : 347 realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { 348 if (opts_av != NULL) 349 free(opts_av); 350 opts_av = NULL; 351 return (0); 352 } else { 353 opts_av = (av_opts *)temp; 354 } 355 356 (void) memset(&opts_av[i], 0, sizeof (av_opts)); 357 marker = optstring; /* may need optstring later */ 358 359 opts_av[i].shortnm = *marker++; /* set short name */ 360 361 if (*marker == ':') { /* check for opt arg */ 362 marker++; 363 opts_av[i].has_arg = B_TRUE; 364 } 365 366 if (*marker == '(') { /* check and set long name */ 367 marker++; 368 opts_av[i].longnm = marker; 369 opts_av[i].longnm_len = strcspn(marker, ")"); 370 optstring = marker + opts_av[i].longnm_len + 1; 371 } else { 372 /* use short name option character */ 373 opts_av[i].longnm = optstring; 374 opts_av[i].longnm_len = 1; 375 optstring = marker; 376 } 377 } 378 379 return (i); 380 } 381 382 /* 383 * getopt_av() is very similar to getopt(3c) in that the takes an option 384 * string, compares command line arguments for matches, and returns a single 385 * letter option when a match is found. However, getopt_av() differs from 386 * getopt(3c) by requiring that only longname options and values be found 387 * on the command line and all leading dashes are omitted. In other words, 388 * it tries to enforce only longname "option=value" arguments on the command 389 * line. Boolean options are not allowed either. 390 */ 391 int 392 getopt_av(int argc, char * const *argv, const char *optstring) 393 { 394 int i; 395 int len; 396 char *cur_option; 397 398 if (optind_av >= argc) 399 return (EOF); 400 401 /* First time or when optstring changes from previous one */ 402 if (_save_optstr != optstring) { 403 if (opts_av != NULL) 404 free(opts_av); 405 opts_av = NULL; 406 _save_optstr = optstring; 407 _save_numopts = populate_opts((char *)optstring); 408 } 409 410 for (i = 0; i < _save_numopts; i++) { 411 cur_option = argv[optind_av]; 412 413 if (strcmp(cur_option, "--") == 0) { 414 optind_av++; 415 break; 416 } 417 418 if (cur_option[0] == '-' && strlen(cur_option) == 2) { 419 len = 1; 420 cur_option++; /* remove "-" */ 421 } else { 422 len = strcspn(cur_option, "="); 423 } 424 425 if (len == opts_av[i].longnm_len && strncmp(cur_option, 426 opts_av[i].longnm, opts_av[i].longnm_len) == 0) { 427 /* matched */ 428 if (!opts_av[i].has_arg) { 429 optind_av++; 430 return (opts_av[i].shortnm); 431 } 432 433 /* needs optarg */ 434 if (cur_option[len] == '=') { 435 optarg_av = &(cur_option[len+1]); 436 optind_av++; 437 return (opts_av[i].shortnm); 438 } 439 440 optarg_av = NULL; 441 optind_av++; 442 return ((int)'?'); 443 } 444 } 445 446 return (EOF); 447 } 448 449 KMF_KEYSTORE_TYPE 450 KS2Int(char *keystore_str) 451 { 452 if (keystore_str == NULL) 453 return (0); 454 if (!strcasecmp(keystore_str, "pkcs11")) 455 return (KMF_KEYSTORE_PK11TOKEN); 456 else if (!strcasecmp(keystore_str, "nss")) 457 return (KMF_KEYSTORE_NSS); 458 else if (!strcasecmp(keystore_str, "file")) 459 return (KMF_KEYSTORE_OPENSSL); 460 else 461 return (0); 462 } 463 464 465 int 466 Str2KeyType(char *algm, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg) 467 { 468 if (algm == NULL) { 469 *sigAlg = KMF_ALGID_MD5WithRSA; 470 *ktype = KMF_RSA; 471 } else if (strcasecmp(algm, "DSA") == 0) { 472 *sigAlg = KMF_ALGID_SHA1WithDSA; 473 *ktype = KMF_DSA; 474 } else if (strcasecmp(algm, "RSA") == 0) { 475 *sigAlg = KMF_ALGID_MD5WithRSA; 476 *ktype = KMF_RSA; 477 } else { 478 return (-1); 479 } 480 return (0); 481 } 482 483 int 484 Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype) 485 { 486 if (algm == NULL) 487 *ktype = KMF_AES; 488 else if (strcasecmp(algm, "aes") == 0) 489 *ktype = KMF_AES; 490 else if (strcasecmp(algm, "arcfour") == 0) 491 *ktype = KMF_RC4; 492 else if (strcasecmp(algm, "des") == 0) 493 *ktype = KMF_DES; 494 else if (strcasecmp(algm, "3des") == 0) 495 *ktype = KMF_DES3; 496 else if (strcasecmp(algm, "generic") == 0) 497 *ktype = KMF_GENERIC_SECRET; 498 else 499 return (-1); 500 501 return (0); 502 } 503 504 int 505 Str2Lifetime(char *ltimestr, uint32_t *ltime) 506 { 507 int num; 508 char timetok[6]; 509 510 if (ltimestr == NULL || !strlen(ltimestr)) { 511 /* default to 1 year lifetime */ 512 *ltime = SECSPERDAY * DAYSPERNYEAR; 513 return (0); 514 } 515 516 (void) memset(timetok, 0, sizeof (timetok)); 517 if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2) 518 return (-1); 519 520 if (!strcasecmp(timetok, "day") || 521 !strcasecmp(timetok, "days")) { 522 *ltime = num * SECSPERDAY; 523 } else if (!strcasecmp(timetok, "hour") || 524 !strcasecmp(timetok, "hours")) { 525 *ltime = num * SECSPERHOUR; 526 } else if (!strcasecmp(timetok, "year") || 527 !strcasecmp(timetok, "years")) { 528 *ltime = num * SECSPERDAY * DAYSPERNYEAR; 529 } else { 530 *ltime = 0; 531 return (-1); 532 } 533 534 return (0); 535 } 536 537 int 538 OT2Int(char *objclass) 539 { 540 char *c = NULL; 541 int retval = 0; 542 543 if (objclass == NULL) 544 return (-1); 545 546 c = strchr(objclass, ':'); 547 if (c != NULL) { 548 if (!strcasecmp(c, ":private")) 549 retval = PK_PRIVATE_OBJ; 550 else if (!strcasecmp(c, ":public")) 551 retval = PK_PUBLIC_OBJ; 552 else if (!strcasecmp(c, ":both")) 553 retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ; 554 else /* unrecognized option */ 555 return (-1); 556 557 *c = '\0'; 558 } 559 560 if (!strcasecmp(objclass, "public")) { 561 if (retval) 562 return (-1); 563 return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | 564 PK_PUBKEY_OBJ); 565 } else if (!strcasecmp(objclass, "private")) { 566 if (retval) 567 return (-1); 568 return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ); 569 } else if (!strcasecmp(objclass, "both")) { 570 if (retval) 571 return (-1); 572 return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ); 573 } else if (!strcasecmp(objclass, "cert")) { 574 return (retval | PK_CERT_OBJ); 575 } else if (!strcasecmp(objclass, "key")) { 576 if (retval == 0) /* return all keys */ 577 return (retval | PK_KEY_OBJ); 578 else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ)) 579 /* return all keys */ 580 return (retval | PK_KEY_OBJ); 581 else if (retval & PK_PUBLIC_OBJ) 582 /* Only return public keys */ 583 return (retval | PK_PUBKEY_OBJ); 584 else if (retval & PK_PRIVATE_OBJ) 585 /* Only return private keys */ 586 return (retval | PK_PRIKEY_OBJ); 587 } else if (!strcasecmp(objclass, "crl")) { 588 if (retval) 589 return (-1); 590 return (retval | PK_CRL_OBJ); 591 } 592 593 if (retval == 0) /* No matches found */ 594 retval = -1; 595 return (retval); 596 } 597 598 KMF_ENCODE_FORMAT 599 Str2Format(char *formstr) 600 { 601 if (formstr == NULL || !strcasecmp(formstr, "der")) 602 return (KMF_FORMAT_ASN1); 603 if (!strcasecmp(formstr, "pem")) 604 return (KMF_FORMAT_PEM); 605 if (!strcasecmp(formstr, "pkcs12")) 606 return (KMF_FORMAT_PKCS12); 607 608 return (KMF_FORMAT_UNDEF); 609 } 610 611 612 KMF_RETURN 613 select_token(void *kmfhandle, char *token, 614 int readonly) 615 { 616 KMF_RETURN rv = KMF_OK; 617 KMF_CONFIG_PARAMS config; 618 619 if (token == NULL) 620 return (KMF_ERR_BAD_PARAMETER); 621 622 (void) memset(&config, 0, sizeof (config)); 623 config.kstype = KMF_KEYSTORE_PK11TOKEN; 624 config.pkcs11config.label = token; 625 config.pkcs11config.readonly = readonly; 626 627 rv = KMF_ConfigureKeystore(kmfhandle, &config); 628 if (rv == KMF_ERR_TOKEN_SELECTED) 629 rv = KMF_OK; 630 return (rv); 631 } 632 633 634 KMF_RETURN 635 configure_nss(void *kmfhandle, char *dir, char *prefix) 636 { 637 KMF_RETURN rv = KMF_OK; 638 KMF_CONFIG_PARAMS config; 639 640 (void) memset(&config, 0, sizeof (config)); 641 config.kstype = KMF_KEYSTORE_NSS; 642 config.nssconfig.configdir = dir; 643 config.nssconfig.certPrefix = prefix; 644 config.nssconfig.keyPrefix = prefix; 645 config.nssconfig.secModName = NULL; 646 647 rv = KMF_ConfigureKeystore(kmfhandle, &config); 648 if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED) 649 rv = KMF_OK; 650 651 return (rv); 652 } 653 654 655 KMF_RETURN 656 get_pk12_password(KMF_CREDENTIAL *cred) 657 { 658 KMF_RETURN rv = KMF_OK; 659 char prompt[1024]; 660 661 /* 662 * Get the password to use for the PK12 encryption. 663 */ 664 (void) strlcpy(prompt, 665 gettext("Enter password to use for " 666 "accessing the PKCS12 file: "), 667 sizeof (prompt)); 668 669 if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, 670 (ulong_t *)&cred->credlen) != CKR_OK) { 671 cred->cred = NULL; 672 cred->credlen = 0; 673 } 674 675 return (rv); 676 } 677 678 679 #define COUNTRY_PROMPT "Country Name (2 letter code) [US]:" 680 #define STATE_PROMPT "State or Province Name (full name) [Some-State]:" 681 #define LOCALITY_PROMPT "Locality Name (eg, city) []:" 682 #define ORG_PROMPT "Organization Name (eg, company) []:" 683 #define UNIT_PROMPT "Organizational Unit Name (eg, section) []:" 684 #define NAME_PROMPT "Common Name (eg, YOUR name) []:" 685 #define EMAIL_PROMPT "Email Address []:" 686 687 #define COUNTRY_DEFAULT "US" 688 #define STATE_DEFAULT "Some-State" 689 #define INVALID_INPUT "Invalid input; please re-enter ..." 690 691 #define SUBNAMESIZ 1024 692 #define RDN_MIN 1 693 #define RDN_MAX 64 694 #define COUNTRYNAME_MIN 2 695 #define COUNTRYNAME_MAX 2 696 697 static char * 698 get_input_string(char *prompt, char *default_str, int min_len, int max_len) 699 { 700 char buf[1024]; 701 char *response = NULL; 702 char *ret = NULL; 703 int len; 704 705 for (;;) { 706 (void) printf("\t%s", prompt); 707 (void) fflush(stdout); 708 709 response = fgets(buf, sizeof (buf), stdin); 710 if (response == NULL) { 711 if (default_str != NULL) { 712 ret = strdup(default_str); 713 } 714 break; 715 } 716 717 /* Skip any leading white space. */ 718 while (isspace(*response)) 719 response++; 720 if (*response == '\0') { 721 if (default_str != NULL) { 722 ret = strdup(default_str); 723 } 724 break; 725 } 726 727 len = strlen(response); 728 response[len-1] = '\0'; /* get rid of "LF" */ 729 len--; 730 if (len >= min_len && len <= max_len) { 731 ret = strdup(response); 732 break; 733 } 734 735 (void) printf("%s\n", INVALID_INPUT); 736 737 } 738 739 return (ret); 740 } 741 742 int 743 get_subname(char **result) 744 { 745 char *country = NULL; 746 char *state = NULL; 747 char *locality = NULL; 748 char *org = NULL; 749 char *unit = NULL; 750 char *name = NULL; 751 char *email = NULL; 752 char *subname = NULL; 753 754 (void) printf("Entering following fields for subject (a DN) ...\n"); 755 country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT, 756 COUNTRYNAME_MIN, COUNTRYNAME_MAX); 757 if (country == NULL) 758 return (-1); 759 760 state = get_input_string(STATE_PROMPT, STATE_DEFAULT, 761 RDN_MIN, RDN_MAX); 762 if (state == NULL) { 763 goto out; 764 } 765 766 locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX); 767 org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX); 768 unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX); 769 name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX); 770 email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX); 771 772 /* Now create a subject name from the input strings */ 773 if ((subname = malloc(SUBNAMESIZ)) == NULL) 774 goto out; 775 776 (void) memset(subname, 0, SUBNAMESIZ); 777 (void) strlcpy(subname, "C=", SUBNAMESIZ); 778 (void) strlcat(subname, country, SUBNAMESIZ); 779 (void) strlcat(subname, ", ", SUBNAMESIZ); 780 (void) strlcat(subname, "ST=", SUBNAMESIZ); 781 (void) strlcat(subname, state, SUBNAMESIZ); 782 783 if (locality) { 784 (void) strlcat(subname, ", ", SUBNAMESIZ); 785 (void) strlcat(subname, "L=", SUBNAMESIZ); 786 (void) strlcat(subname, locality, SUBNAMESIZ); 787 } 788 789 if (org) { 790 (void) strlcat(subname, ", ", SUBNAMESIZ); 791 (void) strlcat(subname, "O=", SUBNAMESIZ); 792 (void) strlcat(subname, org, SUBNAMESIZ); 793 } 794 795 if (unit) { 796 (void) strlcat(subname, ", ", SUBNAMESIZ); 797 (void) strlcat(subname, "OU=", SUBNAMESIZ); 798 (void) strlcat(subname, unit, SUBNAMESIZ); 799 } 800 801 if (name) { 802 (void) strlcat(subname, ", ", SUBNAMESIZ); 803 (void) strlcat(subname, "CN=", SUBNAMESIZ); 804 (void) strlcat(subname, name, SUBNAMESIZ); 805 } 806 807 if (email) { 808 (void) strlcat(subname, ", ", SUBNAMESIZ); 809 (void) strlcat(subname, "E=", SUBNAMESIZ); 810 (void) strlcat(subname, email, SUBNAMESIZ); 811 } 812 813 out: 814 if (country) 815 free(country); 816 if (state) 817 free(state); 818 if (locality) 819 free(locality); 820 if (org) 821 free(org); 822 if (unit) 823 free(unit); 824 if (name) 825 free(name); 826 if (email) 827 free(email); 828 829 if (subname == NULL) 830 return (-1); 831 else { 832 *result = subname; 833 return (0); 834 } 835 } 836 837 /* 838 * Parse a string of KeyUsage values and convert 839 * them to the correct KU Bits. 840 * The field may be marked "critical" by prepending 841 * "critical:" to the list. 842 * EX: critical:digitialSignature,keyEncipherment 843 */ 844 KMF_RETURN 845 verify_keyusage(char *kustr, uint16_t *kubits, int *critical) 846 { 847 KMF_RETURN ret = KMF_OK; 848 uint16_t kuval; 849 char *k; 850 851 *kubits = 0; 852 if (kustr == NULL || !strlen(kustr)) 853 return (KMF_ERR_BAD_PARAMETER); 854 855 /* Check to see if this is critical */ 856 if (!strncasecmp(kustr, "critical:", strlen("critical:"))) { 857 *critical = TRUE; 858 kustr += strlen("critical:"); 859 } else { 860 *critical = FALSE; 861 } 862 863 k = strtok(kustr, ","); 864 while (k != NULL) { 865 kuval = KMF_StringToKeyUsage(k); 866 if (kuval == 0) { 867 *kubits = 0; 868 return (KMF_ERR_BAD_PARAMETER); 869 } 870 *kubits |= kuval; 871 k = strtok(NULL, ","); 872 } 873 874 return (ret); 875 } 876 877 /* 878 * Verify the alternate subject label is real or invalid. 879 * 880 * The field may be marked "critical" by prepending 881 * "critical:" to the list. 882 * EX: "critical:IP=1.2.3.4" 883 */ 884 KMF_RETURN 885 verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical) 886 { 887 char *p; 888 KMF_RETURN rv = KMF_OK; 889 890 /* Check to see if this is critical */ 891 if (!strncasecmp(arg, "critical:", strlen("critical:"))) { 892 *critical = TRUE; 893 arg += strlen("critical:"); 894 } else { 895 *critical = FALSE; 896 } 897 898 /* Make sure there is an "=" sign */ 899 p = strchr(arg, '='); 900 if (p == NULL) 901 return (KMF_ERR_BAD_PARAMETER); 902 903 p[0] = '\0'; 904 905 if (strcmp(arg, "IP") == 0) 906 *type = GENNAME_IPADDRESS; 907 else if (strcmp(arg, "DNS") == 0) 908 *type = GENNAME_DNSNAME; 909 else if (strcmp(arg, "EMAIL") == 0) 910 *type = GENNAME_RFC822NAME; 911 else if (strcmp(arg, "URI") == 0) 912 *type = GENNAME_URI; 913 else if (strcmp(arg, "DN") == 0) 914 *type = GENNAME_DIRECTORYNAME; 915 else if (strcmp(arg, "RID") == 0) 916 *type = GENNAME_REGISTEREDID; 917 else 918 rv = KMF_ERR_BAD_PARAMETER; 919 920 p[0] = '='; 921 922 return (rv); 923 } 924 925 int 926 get_token_password(KMF_KEYSTORE_TYPE kstype, 927 char *token_spec, KMF_CREDENTIAL *cred) 928 { 929 char prompt[1024]; 930 char *p = NULL; 931 932 if (kstype == KMF_KEYSTORE_PK11TOKEN) { 933 p = strchr(token_spec, ':'); 934 if (p != NULL) 935 *p = 0; 936 } 937 /* 938 * Login to the token first. 939 */ 940 (void) snprintf(prompt, sizeof (prompt), 941 gettext(DEFAULT_TOKEN_PROMPT), 942 token_spec); 943 944 if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, 945 (ulong_t *)&cred->credlen) != CKR_OK) { 946 cred->cred = NULL; 947 cred->credlen = 0; 948 } 949 950 if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL) 951 *p = ':'; 952 return (KMF_OK); 953 } 954 955 KMF_RETURN 956 verify_file(char *filename) 957 { 958 KMF_RETURN ret = KMF_OK; 959 int fd; 960 961 /* 962 * Attempt to open with the EXCL flag so that if 963 * it already exists, the open will fail. It will 964 * also fail if the file cannot be created due to 965 * permissions on the parent directory, or if the 966 * parent directory itself does not exist. 967 */ 968 fd = open(filename, O_CREAT | O_EXCL, 0600); 969 if (fd == -1) 970 return (KMF_ERR_OPEN_FILE); 971 972 /* If we were able to create it, delete it. */ 973 (void) close(fd); 974 (void) unlink(filename); 975 976 return (ret); 977 } 978 979 void 980 display_error(void *handle, KMF_RETURN errcode, char *prefix) 981 { 982 KMF_RETURN rv1, rv2; 983 char *plugin_errmsg = NULL; 984 char *kmf_errmsg = NULL; 985 986 rv1 = KMF_GetPluginErrorString(handle, &plugin_errmsg); 987 rv2 = KMF_GetKMFErrorString(errcode, &kmf_errmsg); 988 989 cryptoerror(LOG_STDERR, "%s:", prefix); 990 if (rv1 == KMF_OK && plugin_errmsg) { 991 cryptoerror(LOG_STDERR, 992 gettext("keystore error: %s"), 993 plugin_errmsg); 994 KMF_FreeString(plugin_errmsg); 995 } 996 997 if (rv2 == KMF_OK && kmf_errmsg) { 998 cryptoerror(LOG_STDERR, 999 gettext("libkmf error: %s"), 1000 kmf_errmsg); 1001 KMF_FreeString(kmf_errmsg); 1002 } 1003 1004 if (rv1 != KMF_OK && rv2 != KMF_OK) 1005 cryptoerror(LOG_STDERR, gettext("<unknown error>\n")); 1006 1007 } 1008