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