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