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 #define FILENAME_PROMPT gettext("Filename:") 713 #define FILENAME_MINLEN 1 714 #define FILENAME_MAXLEN MAXPATHLEN 715 716 #define COUNTRY_PROMPT gettext("Country Name (2 letter code) [US]:") 717 #define STATE_PROMPT gettext("State or Province Name (full name) " \ 718 "[Some-State]:") 719 #define LOCALITY_PROMPT gettext("Locality Name (eg, city) []:") 720 #define ORG_PROMPT gettext("Organization Name (eg, company) []:") 721 #define UNIT_PROMPT gettext("Organizational Unit Name (eg, section) []:") 722 #define NAME_PROMPT gettext("Common Name (eg, YOUR name) []:") 723 #define EMAIL_PROMPT gettext("Email Address []:") 724 725 #define SERNO_PROMPT gettext("Serial Number (hex value, example: " \ 726 "0x01020304):") 727 #define SERNO_MINLEN 3 728 #define SERNO_MAXLEN 42 729 730 #define LABEL_PROMPT gettext("Enter a label for the certificate:") 731 #define LABEL_MINLEN 1 732 #define LABEL_MAXLEN 1024 733 734 #define COUNTRY_DEFAULT "US" 735 #define STATE_DEFAULT NULL 736 #define INVALID_INPUT gettext("Invalid input; please re-enter ...") 737 738 #define SUBNAMESIZ 1024 739 #define RDN_MIN 1 740 #define RDN_MAX 64 741 #define COUNTRYNAME_MIN 2 742 #define COUNTRYNAME_MAX 2 743 744 static char * 745 get_input_string(char *prompt, char *default_str, int min_len, int max_len) 746 { 747 char buf[1024]; 748 char *response = NULL; 749 char *ret = NULL; 750 int len; 751 752 for (;;) { 753 (void) printf("\t%s", prompt); 754 (void) fflush(stdout); 755 756 response = fgets(buf, sizeof (buf), stdin); 757 if (response == NULL) { 758 if (default_str != NULL) { 759 ret = strdup(default_str); 760 } 761 break; 762 } 763 764 /* Skip any leading white space. */ 765 while (isspace(*response)) 766 response++; 767 if (*response == '\0') { 768 if (default_str != NULL) { 769 ret = strdup(default_str); 770 } 771 break; 772 } 773 774 len = strlen(response); 775 response[len-1] = '\0'; /* get rid of "LF" */ 776 len--; 777 if (len >= min_len && len <= max_len) { 778 ret = strdup(response); 779 break; 780 } 781 782 (void) printf("%s\n", INVALID_INPUT); 783 784 } 785 786 return (ret); 787 } 788 789 int 790 get_filename(char *txt, char **result) 791 { 792 char prompt[1024]; 793 char *fname = NULL; 794 795 (void) snprintf(prompt, sizeof (prompt), 796 gettext("Enter filename for the %s: "), 797 txt); 798 fname = get_input_string(prompt, NULL, 799 FILENAME_MINLEN, FILENAME_MAXLEN); 800 *result = fname; 801 return (0); 802 } 803 804 int 805 get_certlabel(char **result) 806 { 807 char *label = NULL; 808 809 label = get_input_string(LABEL_PROMPT, NULL, 810 LABEL_MINLEN, LABEL_MAXLEN); 811 *result = label; 812 return (0); 813 } 814 815 int 816 get_serial(char **result) 817 { 818 char *serial = NULL; 819 820 serial = get_input_string(SERNO_PROMPT, NULL, SERNO_MINLEN, 821 SERNO_MAXLEN); 822 823 *result = serial; 824 return (0); 825 } 826 827 int 828 get_subname(char **result) 829 { 830 char *country = NULL; 831 char *state = NULL; 832 char *locality = NULL; 833 char *org = NULL; 834 char *unit = NULL; 835 char *name = NULL; 836 char *email = NULL; 837 char *subname = NULL; 838 839 (void) printf("Entering following fields for subject (a DN) ...\n"); 840 country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT, 841 COUNTRYNAME_MIN, COUNTRYNAME_MAX); 842 if (country == NULL) 843 return (-1); 844 845 state = get_input_string(STATE_PROMPT, STATE_DEFAULT, 846 RDN_MIN, RDN_MAX); 847 848 locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX); 849 org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX); 850 unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX); 851 name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX); 852 email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX); 853 854 /* Now create a subject name from the input strings */ 855 if ((subname = malloc(SUBNAMESIZ)) == NULL) 856 goto out; 857 858 (void) memset(subname, 0, SUBNAMESIZ); 859 (void) strlcpy(subname, "C=", SUBNAMESIZ); 860 (void) strlcat(subname, country, SUBNAMESIZ); 861 if (state != NULL) { 862 (void) strlcat(subname, ", ST=", SUBNAMESIZ); 863 (void) strlcat(subname, state, SUBNAMESIZ); 864 } 865 866 if (locality != NULL) { 867 (void) strlcat(subname, ", L=", SUBNAMESIZ); 868 (void) strlcat(subname, locality, SUBNAMESIZ); 869 } 870 871 if (org != NULL) { 872 (void) strlcat(subname, ", O=", SUBNAMESIZ); 873 (void) strlcat(subname, org, SUBNAMESIZ); 874 } 875 876 if (unit != NULL) { 877 (void) strlcat(subname, ", OU=", SUBNAMESIZ); 878 (void) strlcat(subname, unit, SUBNAMESIZ); 879 } 880 881 if (name != NULL) { 882 (void) strlcat(subname, ", CN=", SUBNAMESIZ); 883 (void) strlcat(subname, name, SUBNAMESIZ); 884 } 885 886 if (email != NULL) { 887 (void) strlcat(subname, ", E=", SUBNAMESIZ); 888 (void) strlcat(subname, email, SUBNAMESIZ); 889 } 890 891 out: 892 if (country) 893 free(country); 894 if (state) 895 free(state); 896 if (locality) 897 free(locality); 898 if (org) 899 free(org); 900 if (unit) 901 free(unit); 902 if (name) 903 free(name); 904 if (email) 905 free(email); 906 907 if (subname == NULL) 908 return (-1); 909 else { 910 *result = subname; 911 return (0); 912 } 913 } 914 915 /* 916 * Parse a string of KeyUsage values and convert 917 * them to the correct KU Bits. 918 * The field may be marked "critical" by prepending 919 * "critical:" to the list. 920 * EX: critical:digitialSignature,keyEncipherment 921 */ 922 KMF_RETURN 923 verify_keyusage(char *kustr, uint16_t *kubits, int *critical) 924 { 925 KMF_RETURN ret = KMF_OK; 926 uint16_t kuval; 927 char *k; 928 929 *kubits = 0; 930 if (kustr == NULL || !strlen(kustr)) 931 return (KMF_ERR_BAD_PARAMETER); 932 933 /* Check to see if this is critical */ 934 if (!strncasecmp(kustr, "critical:", strlen("critical:"))) { 935 *critical = TRUE; 936 kustr += strlen("critical:"); 937 } else { 938 *critical = FALSE; 939 } 940 941 k = strtok(kustr, ","); 942 while (k != NULL) { 943 kuval = kmf_string_to_ku(k); 944 if (kuval == 0) { 945 *kubits = 0; 946 return (KMF_ERR_BAD_PARAMETER); 947 } 948 *kubits |= kuval; 949 k = strtok(NULL, ","); 950 } 951 952 return (ret); 953 } 954 955 /* 956 * Verify the alternate subject label is real or invalid. 957 * 958 * The field may be marked "critical" by prepending 959 * "critical:" to the list. 960 * EX: "critical:IP=1.2.3.4" 961 */ 962 KMF_RETURN 963 verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical) 964 { 965 char *p; 966 KMF_RETURN rv = KMF_OK; 967 968 /* Check to see if this is critical */ 969 if (!strncasecmp(arg, "critical:", strlen("critical:"))) { 970 *critical = TRUE; 971 arg += strlen("critical:"); 972 } else { 973 *critical = FALSE; 974 } 975 976 /* Make sure there is an "=" sign */ 977 p = strchr(arg, '='); 978 if (p == NULL) 979 return (KMF_ERR_BAD_PARAMETER); 980 981 p[0] = '\0'; 982 983 if (strcmp(arg, "IP") == 0) 984 *type = GENNAME_IPADDRESS; 985 else if (strcmp(arg, "DNS") == 0) 986 *type = GENNAME_DNSNAME; 987 else if (strcmp(arg, "EMAIL") == 0) 988 *type = GENNAME_RFC822NAME; 989 else if (strcmp(arg, "URI") == 0) 990 *type = GENNAME_URI; 991 else if (strcmp(arg, "DN") == 0) 992 *type = GENNAME_DIRECTORYNAME; 993 else if (strcmp(arg, "RID") == 0) 994 *type = GENNAME_REGISTEREDID; 995 else 996 rv = KMF_ERR_BAD_PARAMETER; 997 998 p[0] = '='; 999 1000 return (rv); 1001 } 1002 1003 int 1004 get_token_password(KMF_KEYSTORE_TYPE kstype, 1005 char *token_spec, KMF_CREDENTIAL *cred) 1006 { 1007 char prompt[1024]; 1008 char *p = NULL; 1009 1010 if (kstype == KMF_KEYSTORE_PK11TOKEN) { 1011 p = strchr(token_spec, ':'); 1012 if (p != NULL) 1013 *p = 0; 1014 } 1015 /* 1016 * Login to the token first. 1017 */ 1018 (void) snprintf(prompt, sizeof (prompt), 1019 gettext(DEFAULT_TOKEN_PROMPT), token_spec); 1020 1021 if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, 1022 (ulong_t *)&cred->credlen) != CKR_OK) { 1023 cred->cred = NULL; 1024 cred->credlen = 0; 1025 } 1026 1027 if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL) 1028 *p = ':'; 1029 return (KMF_OK); 1030 } 1031 1032 KMF_RETURN 1033 verify_file(char *filename) 1034 { 1035 KMF_RETURN ret = KMF_OK; 1036 int fd; 1037 1038 /* 1039 * Attempt to open with the EXCL flag so that if 1040 * it already exists, the open will fail. It will 1041 * also fail if the file cannot be created due to 1042 * permissions on the parent directory, or if the 1043 * parent directory itself does not exist. 1044 */ 1045 fd = open(filename, O_CREAT | O_EXCL, 0600); 1046 if (fd == -1) 1047 return (KMF_ERR_OPEN_FILE); 1048 1049 /* If we were able to create it, delete it. */ 1050 (void) close(fd); 1051 (void) unlink(filename); 1052 1053 return (ret); 1054 } 1055 1056 void 1057 display_error(void *handle, KMF_RETURN errcode, char *prefix) 1058 { 1059 KMF_RETURN rv1, rv2; 1060 char *plugin_errmsg = NULL; 1061 char *kmf_errmsg = NULL; 1062 1063 rv1 = kmf_get_plugin_error_str(handle, &plugin_errmsg); 1064 rv2 = kmf_get_kmf_error_str(errcode, &kmf_errmsg); 1065 1066 cryptoerror(LOG_STDERR, "%s:", prefix); 1067 if (rv1 == KMF_OK && plugin_errmsg) { 1068 cryptoerror(LOG_STDERR, gettext("keystore error: %s"), 1069 plugin_errmsg); 1070 kmf_free_str(plugin_errmsg); 1071 } 1072 1073 if (rv2 == KMF_OK && kmf_errmsg) { 1074 cryptoerror(LOG_STDERR, gettext("libkmf error: %s"), 1075 kmf_errmsg); 1076 kmf_free_str(kmf_errmsg); 1077 } 1078 1079 if (rv1 != KMF_OK && rv2 != KMF_OK) 1080 cryptoerror(LOG_STDERR, gettext("<unknown error>\n")); 1081 1082 } 1083