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 | PK_PUBKEY_OBJ); 564 } else if (!strcasecmp(objclass, "private")) { 565 if (retval) 566 return (-1); 567 return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ); 568 } else if (!strcasecmp(objclass, "both")) { 569 if (retval) 570 return (-1); 571 return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ); 572 } else if (!strcasecmp(objclass, "cert")) { 573 return (retval | PK_CERT_OBJ); 574 } else if (!strcasecmp(objclass, "key")) { 575 if (retval == 0) /* return all keys */ 576 return (retval | PK_KEY_OBJ); 577 else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ)) 578 /* return all keys */ 579 return (retval | PK_KEY_OBJ); 580 else if (retval & PK_PUBLIC_OBJ) 581 /* Only return public keys */ 582 return (retval | PK_PUBKEY_OBJ); 583 else if (retval & PK_PRIVATE_OBJ) 584 /* Only return private keys */ 585 return (retval | PK_PRIKEY_OBJ); 586 } else if (!strcasecmp(objclass, "crl")) { 587 if (retval) 588 return (-1); 589 return (retval | PK_CRL_OBJ); 590 } 591 592 if (retval == 0) /* No matches found */ 593 retval = -1; 594 return (retval); 595 } 596 597 KMF_ENCODE_FORMAT 598 Str2Format(char *formstr) 599 { 600 if (formstr == NULL || !strcasecmp(formstr, "der")) 601 return (KMF_FORMAT_ASN1); 602 if (!strcasecmp(formstr, "pem")) 603 return (KMF_FORMAT_PEM); 604 if (!strcasecmp(formstr, "pkcs12")) 605 return (KMF_FORMAT_PKCS12); 606 if (!strcasecmp(formstr, "raw")) 607 return (KMF_FORMAT_RAWKEY); 608 609 return (KMF_FORMAT_UNDEF); 610 } 611 612 613 KMF_RETURN 614 select_token(void *kmfhandle, char *token, 615 int readonly) 616 { 617 KMF_ATTRIBUTE attlist[10]; 618 int i = 0; 619 KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; 620 KMF_RETURN rv = KMF_OK; 621 622 if (token == NULL) 623 return (KMF_ERR_BAD_PARAMETER); 624 625 kmf_set_attr_at_index(attlist, i, 626 KMF_KEYSTORE_TYPE_ATTR, &kstype, 627 sizeof (kstype)); 628 i++; 629 630 if (token) { 631 kmf_set_attr_at_index(attlist, i, 632 KMF_TOKEN_LABEL_ATTR, token, 633 strlen(token)); 634 i++; 635 } 636 637 kmf_set_attr_at_index(attlist, i, 638 KMF_READONLY_ATTR, &readonly, 639 sizeof (readonly)); 640 i++; 641 642 rv = kmf_configure_keystore(kmfhandle, i, attlist); 643 if (rv == KMF_ERR_TOKEN_SELECTED) 644 rv = KMF_OK; 645 return (rv); 646 } 647 648 649 KMF_RETURN 650 configure_nss(void *kmfhandle, char *dir, char *prefix) 651 { 652 653 KMF_ATTRIBUTE attlist[10]; 654 int i = 0; 655 KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; 656 KMF_RETURN rv = KMF_OK; 657 658 kmf_set_attr_at_index(attlist, i, 659 KMF_KEYSTORE_TYPE_ATTR, &kstype, 660 sizeof (kstype)); 661 i++; 662 663 if (dir) { 664 kmf_set_attr_at_index(attlist, i, 665 KMF_DIRPATH_ATTR, dir, 666 strlen(dir)); 667 i++; 668 } 669 670 if (prefix) { 671 kmf_set_attr_at_index(attlist, i, 672 KMF_CERTPREFIX_ATTR, prefix, 673 strlen(prefix)); 674 i++; 675 676 kmf_set_attr_at_index(attlist, i, 677 KMF_KEYPREFIX_ATTR, prefix, 678 strlen(prefix)); 679 i++; 680 } 681 682 rv = kmf_configure_keystore(kmfhandle, i, attlist); 683 if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED) 684 rv = KMF_OK; 685 686 return (rv); 687 } 688 689 690 KMF_RETURN 691 get_pk12_password(KMF_CREDENTIAL *cred) 692 { 693 KMF_RETURN rv = KMF_OK; 694 char prompt[1024]; 695 696 /* 697 * Get the password to use for the PK12 encryption. 698 */ 699 (void) strlcpy(prompt, 700 gettext("Enter password to use for " 701 "accessing the PKCS12 file: "), sizeof (prompt)); 702 703 if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, 704 (ulong_t *)&cred->credlen) != CKR_OK) { 705 cred->cred = NULL; 706 cred->credlen = 0; 707 } 708 709 return (rv); 710 } 711 712 713 #define COUNTRY_PROMPT "Country Name (2 letter code) [US]:" 714 #define STATE_PROMPT "State or Province Name (full name) [Some-State]:" 715 #define LOCALITY_PROMPT "Locality Name (eg, city) []:" 716 #define ORG_PROMPT "Organization Name (eg, company) []:" 717 #define UNIT_PROMPT "Organizational Unit Name (eg, section) []:" 718 #define NAME_PROMPT "Common Name (eg, YOUR name) []:" 719 #define EMAIL_PROMPT "Email Address []:" 720 721 #define COUNTRY_DEFAULT "US" 722 #define STATE_DEFAULT "Some-State" 723 #define INVALID_INPUT "Invalid input; please re-enter ..." 724 725 #define SUBNAMESIZ 1024 726 #define RDN_MIN 1 727 #define RDN_MAX 64 728 #define COUNTRYNAME_MIN 2 729 #define COUNTRYNAME_MAX 2 730 731 static char * 732 get_input_string(char *prompt, char *default_str, int min_len, int max_len) 733 { 734 char buf[1024]; 735 char *response = NULL; 736 char *ret = NULL; 737 int len; 738 739 for (;;) { 740 (void) printf("\t%s", prompt); 741 (void) fflush(stdout); 742 743 response = fgets(buf, sizeof (buf), stdin); 744 if (response == NULL) { 745 if (default_str != NULL) { 746 ret = strdup(default_str); 747 } 748 break; 749 } 750 751 /* Skip any leading white space. */ 752 while (isspace(*response)) 753 response++; 754 if (*response == '\0') { 755 if (default_str != NULL) { 756 ret = strdup(default_str); 757 } 758 break; 759 } 760 761 len = strlen(response); 762 response[len-1] = '\0'; /* get rid of "LF" */ 763 len--; 764 if (len >= min_len && len <= max_len) { 765 ret = strdup(response); 766 break; 767 } 768 769 (void) printf("%s\n", INVALID_INPUT); 770 771 } 772 773 return (ret); 774 } 775 776 int 777 get_subname(char **result) 778 { 779 char *country = NULL; 780 char *state = NULL; 781 char *locality = NULL; 782 char *org = NULL; 783 char *unit = NULL; 784 char *name = NULL; 785 char *email = NULL; 786 char *subname = NULL; 787 788 (void) printf("Entering following fields for subject (a DN) ...\n"); 789 country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT, 790 COUNTRYNAME_MIN, COUNTRYNAME_MAX); 791 if (country == NULL) 792 return (-1); 793 794 state = get_input_string(STATE_PROMPT, STATE_DEFAULT, 795 RDN_MIN, RDN_MAX); 796 if (state == NULL) { 797 goto out; 798 } 799 800 locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX); 801 org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX); 802 unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX); 803 name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX); 804 email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX); 805 806 /* Now create a subject name from the input strings */ 807 if ((subname = malloc(SUBNAMESIZ)) == NULL) 808 goto out; 809 810 (void) memset(subname, 0, SUBNAMESIZ); 811 (void) strlcpy(subname, "C=", SUBNAMESIZ); 812 (void) strlcat(subname, country, SUBNAMESIZ); 813 (void) strlcat(subname, ", ", SUBNAMESIZ); 814 (void) strlcat(subname, "ST=", SUBNAMESIZ); 815 (void) strlcat(subname, state, SUBNAMESIZ); 816 817 if (locality) { 818 (void) strlcat(subname, ", ", SUBNAMESIZ); 819 (void) strlcat(subname, "L=", SUBNAMESIZ); 820 (void) strlcat(subname, locality, SUBNAMESIZ); 821 } 822 823 if (org) { 824 (void) strlcat(subname, ", ", SUBNAMESIZ); 825 (void) strlcat(subname, "O=", SUBNAMESIZ); 826 (void) strlcat(subname, org, SUBNAMESIZ); 827 } 828 829 if (unit) { 830 (void) strlcat(subname, ", ", SUBNAMESIZ); 831 (void) strlcat(subname, "OU=", SUBNAMESIZ); 832 (void) strlcat(subname, unit, SUBNAMESIZ); 833 } 834 835 if (name) { 836 (void) strlcat(subname, ", ", SUBNAMESIZ); 837 (void) strlcat(subname, "CN=", SUBNAMESIZ); 838 (void) strlcat(subname, name, SUBNAMESIZ); 839 } 840 841 if (email) { 842 (void) strlcat(subname, ", ", SUBNAMESIZ); 843 (void) strlcat(subname, "E=", SUBNAMESIZ); 844 (void) strlcat(subname, email, SUBNAMESIZ); 845 } 846 847 out: 848 if (country) 849 free(country); 850 if (state) 851 free(state); 852 if (locality) 853 free(locality); 854 if (org) 855 free(org); 856 if (unit) 857 free(unit); 858 if (name) 859 free(name); 860 if (email) 861 free(email); 862 863 if (subname == NULL) 864 return (-1); 865 else { 866 *result = subname; 867 return (0); 868 } 869 } 870 871 /* 872 * Parse a string of KeyUsage values and convert 873 * them to the correct KU Bits. 874 * The field may be marked "critical" by prepending 875 * "critical:" to the list. 876 * EX: critical:digitialSignature,keyEncipherment 877 */ 878 KMF_RETURN 879 verify_keyusage(char *kustr, uint16_t *kubits, int *critical) 880 { 881 KMF_RETURN ret = KMF_OK; 882 uint16_t kuval; 883 char *k; 884 885 *kubits = 0; 886 if (kustr == NULL || !strlen(kustr)) 887 return (KMF_ERR_BAD_PARAMETER); 888 889 /* Check to see if this is critical */ 890 if (!strncasecmp(kustr, "critical:", strlen("critical:"))) { 891 *critical = TRUE; 892 kustr += strlen("critical:"); 893 } else { 894 *critical = FALSE; 895 } 896 897 k = strtok(kustr, ","); 898 while (k != NULL) { 899 kuval = kmf_string_to_ku(k); 900 if (kuval == 0) { 901 *kubits = 0; 902 return (KMF_ERR_BAD_PARAMETER); 903 } 904 *kubits |= kuval; 905 k = strtok(NULL, ","); 906 } 907 908 return (ret); 909 } 910 911 /* 912 * Verify the alternate subject label is real or invalid. 913 * 914 * The field may be marked "critical" by prepending 915 * "critical:" to the list. 916 * EX: "critical:IP=1.2.3.4" 917 */ 918 KMF_RETURN 919 verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical) 920 { 921 char *p; 922 KMF_RETURN rv = KMF_OK; 923 924 /* Check to see if this is critical */ 925 if (!strncasecmp(arg, "critical:", strlen("critical:"))) { 926 *critical = TRUE; 927 arg += strlen("critical:"); 928 } else { 929 *critical = FALSE; 930 } 931 932 /* Make sure there is an "=" sign */ 933 p = strchr(arg, '='); 934 if (p == NULL) 935 return (KMF_ERR_BAD_PARAMETER); 936 937 p[0] = '\0'; 938 939 if (strcmp(arg, "IP") == 0) 940 *type = GENNAME_IPADDRESS; 941 else if (strcmp(arg, "DNS") == 0) 942 *type = GENNAME_DNSNAME; 943 else if (strcmp(arg, "EMAIL") == 0) 944 *type = GENNAME_RFC822NAME; 945 else if (strcmp(arg, "URI") == 0) 946 *type = GENNAME_URI; 947 else if (strcmp(arg, "DN") == 0) 948 *type = GENNAME_DIRECTORYNAME; 949 else if (strcmp(arg, "RID") == 0) 950 *type = GENNAME_REGISTEREDID; 951 else 952 rv = KMF_ERR_BAD_PARAMETER; 953 954 p[0] = '='; 955 956 return (rv); 957 } 958 959 int 960 get_token_password(KMF_KEYSTORE_TYPE kstype, 961 char *token_spec, KMF_CREDENTIAL *cred) 962 { 963 char prompt[1024]; 964 char *p = NULL; 965 966 if (kstype == KMF_KEYSTORE_PK11TOKEN) { 967 p = strchr(token_spec, ':'); 968 if (p != NULL) 969 *p = 0; 970 } 971 /* 972 * Login to the token first. 973 */ 974 (void) snprintf(prompt, sizeof (prompt), 975 gettext(DEFAULT_TOKEN_PROMPT), token_spec); 976 977 if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, 978 (ulong_t *)&cred->credlen) != CKR_OK) { 979 cred->cred = NULL; 980 cred->credlen = 0; 981 } 982 983 if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL) 984 *p = ':'; 985 return (KMF_OK); 986 } 987 988 KMF_RETURN 989 verify_file(char *filename) 990 { 991 KMF_RETURN ret = KMF_OK; 992 int fd; 993 994 /* 995 * Attempt to open with the EXCL flag so that if 996 * it already exists, the open will fail. It will 997 * also fail if the file cannot be created due to 998 * permissions on the parent directory, or if the 999 * parent directory itself does not exist. 1000 */ 1001 fd = open(filename, O_CREAT | O_EXCL, 0600); 1002 if (fd == -1) 1003 return (KMF_ERR_OPEN_FILE); 1004 1005 /* If we were able to create it, delete it. */ 1006 (void) close(fd); 1007 (void) unlink(filename); 1008 1009 return (ret); 1010 } 1011 1012 void 1013 display_error(void *handle, KMF_RETURN errcode, char *prefix) 1014 { 1015 KMF_RETURN rv1, rv2; 1016 char *plugin_errmsg = NULL; 1017 char *kmf_errmsg = NULL; 1018 1019 rv1 = kmf_get_plugin_error_str(handle, &plugin_errmsg); 1020 rv2 = kmf_get_kmf_error_str(errcode, &kmf_errmsg); 1021 1022 cryptoerror(LOG_STDERR, "%s:", prefix); 1023 if (rv1 == KMF_OK && plugin_errmsg) { 1024 cryptoerror(LOG_STDERR, gettext("keystore error: %s"), 1025 plugin_errmsg); 1026 kmf_free_str(plugin_errmsg); 1027 } 1028 1029 if (rv2 == KMF_OK && kmf_errmsg) { 1030 cryptoerror(LOG_STDERR, gettext("libkmf error: %s"), 1031 kmf_errmsg); 1032 kmf_free_str(kmf_errmsg); 1033 } 1034 1035 if (rv1 != KMF_OK && rv2 != KMF_OK) 1036 cryptoerror(LOG_STDERR, gettext("<unknown error>\n")); 1037 1038 } 1039