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