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