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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains the functions that are shared among 31 * the various services this tool will ultimately provide. 32 * The functions in this file return PKCS#11 CK_RV errors. 33 * Only one session and one login per token is supported 34 * at this time. 35 */ 36 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <ctype.h> 41 #include <cryptoutil.h> 42 #include <security/cryptoki.h> 43 #include "common.h" 44 #include "biginteger.h" 45 46 /* True and false for attribute templates. */ 47 CK_BBOOL pk_true = B_TRUE; 48 CK_BBOOL pk_false = B_FALSE; 49 50 /* Local status variables. */ 51 static boolean_t initialized = B_FALSE; 52 static boolean_t session_opened = B_FALSE; 53 static boolean_t session_writable = B_FALSE; 54 static boolean_t logged_in = B_FALSE; 55 56 /* 57 * Perform PKCS#11 setup here. Currently only C_Initialize is required, 58 * along with setting/resetting state variables. 59 */ 60 CK_RV 61 init_pk11(void) 62 { 63 CK_RV rv = CKR_OK; 64 65 cryptodebug("inside init_pk11"); 66 67 /* If C_Initialize() already called, nothing to do here. */ 68 if (initialized == B_TRUE) 69 return (CKR_OK); 70 71 /* Reset state variables because C_Initialize() not yet done. */ 72 session_opened = B_FALSE; 73 session_writable = B_FALSE; 74 logged_in = B_FALSE; 75 76 /* Initialize PKCS#11 library. */ 77 cryptodebug("calling C_Initialize()"); 78 if ((rv = C_Initialize(NULL_PTR)) != CKR_OK && 79 rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { 80 return (rv); 81 } 82 83 initialized = B_TRUE; 84 return (CKR_OK); 85 } 86 87 /* 88 * Finalize PKCS#11 library and reset state variables. Open sessions, 89 * if any, are closed, and thereby any logins are logged out also. 90 */ 91 void 92 final_pk11(CK_SESSION_HANDLE sess) 93 { 94 cryptodebug("inside final_pk11"); 95 96 /* If the library wasn't initialized, nothing to do here. */ 97 if (!initialized) 98 return; 99 100 /* Make sure the sesion is closed first. */ 101 close_sess(sess); 102 103 cryptodebug("calling C_Finalize()"); 104 (void) C_Finalize(NULL); 105 initialized = B_FALSE; 106 } 107 108 /* 109 * Create a PKCS#11 session on the given slot, and set state information. 110 * If session is already open, check that the read-only/read-write state 111 * requested matches that of the session. If it doesn't, make it so. 112 */ 113 CK_RV 114 open_sess(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_SESSION_HANDLE_PTR sess) 115 { 116 CK_RV rv = CKR_OK; 117 118 cryptodebug("inside open_sess"); 119 120 /* If the session is already open, check the session flags. */ 121 if (session_opened) { 122 /* 123 * If requesting R/W session and it is currently R/O, 124 * need to close the session and reopen it R/W. The 125 * other cases are considered acceptable: 126 * sess_flags current state 127 * ---------- ------------- 128 * ~CKF_RW_SESSION !session_writable 129 * ~CKF_RW_SESSION session_writable 130 * CKF_RW_SESSION session_writable 131 */ 132 if ((sess_flags & CKF_RW_SESSION) && !session_writable) 133 close_sess(*sess); 134 else 135 return (CKR_OK); 136 } 137 138 /* Make sure the PKCS#11 is already initialized. */ 139 if (!initialized) 140 if ((rv = init_pk11()) != CKR_OK) 141 return (rv); 142 143 /* Create a session for subsequent operations. */ 144 cryptodebug("calling C_OpenSession()"); 145 if ((rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION|sess_flags, 146 NULL, NULL, sess)) != CKR_OK) 147 return (rv); 148 session_opened = B_TRUE; 149 session_writable = (sess_flags & CKF_RW_SESSION) ? B_TRUE : B_FALSE; 150 return (CKR_OK); 151 } 152 153 /* 154 * Close PKCS#11 session and reset state variables. Any logins are 155 * logged out. 156 */ 157 void 158 close_sess(CK_SESSION_HANDLE sess) 159 { 160 cryptodebug("inside close_sess"); 161 162 if (sess == NULL) { 163 cryptodebug("session handle is null"); 164 return; 165 } 166 167 /* If session is already closed, nothing to do here. */ 168 session_writable = B_FALSE; 169 if (!session_opened) 170 return; 171 172 /* Make sure user is logged out of token. */ 173 logout_token(sess); 174 175 cryptodebug("calling C_CloseSession()"); 176 (void) C_CloseSession(sess); 177 session_opened = B_FALSE; 178 } 179 180 /* 181 * Log user into token in given slot. If this first login ever for this 182 * token, the initial PIN is "changeme", C_Login() will succeed, but all 183 * PKCS#11 calls following the C_Login() will fail with CKR_PIN_EXPIRED. 184 */ 185 CK_RV 186 login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, 187 CK_SESSION_HANDLE_PTR sess) 188 { 189 CK_RV rv = CKR_OK; 190 191 cryptodebug("inside login_token"); 192 193 /* If already logged in, nothing to do here. */ 194 if (logged_in) 195 return (CKR_OK); 196 197 /* Make sure we have a session first, assume R/O is enough. */ 198 if (!session_opened) 199 if ((rv = open_sess(slot_id, CKF_SERIAL_SESSION, sess)) != 200 CKR_OK) 201 return (rv); 202 203 /* Log the user into the token. */ 204 cryptodebug("calling C_Login()"); 205 if ((rv = C_Login(*sess, CKU_USER, pin, pinlen)) != CKR_OK) { 206 cryptodebug("C_Login returns %s", pkcs11_strerror(rv)); 207 return (rv); 208 } 209 210 logged_in = B_TRUE; 211 return (CKR_OK); 212 } 213 214 /* 215 * Log user out of token and reset status variable. 216 */ 217 void 218 logout_token(CK_SESSION_HANDLE sess) 219 { 220 cryptodebug("inside logout_token"); 221 222 if (sess == NULL) { 223 cryptodebug("session handle is null"); 224 return; 225 } 226 227 /* If already logged out, nothing to do here. */ 228 if (!logged_in) 229 return; 230 231 cryptodebug("calling C_Logout()"); 232 (void) C_Logout(sess); 233 logged_in = B_FALSE; 234 } 235 236 /* 237 * Shortcut function to get from an uninitialized state to user logged in. 238 * If the library is already initialized, the session is already opened, 239 * or the user is already logged in, those steps are skipped and the next 240 * step is checked. 241 */ 242 CK_RV 243 quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_UTF8CHAR_PTR pin, 244 CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess) 245 { 246 CK_RV rv = CKR_OK; 247 248 cryptodebug("inside quick_start"); 249 250 /* Call open_sess() explicitly if R/W session is needed. */ 251 if (sess_flags & CKF_RW_SESSION) 252 if ((rv = open_sess(slot_id, sess_flags, sess)) != CKR_OK) 253 return (rv); 254 255 if ((rv = login_token(slot_id, pin, pinlen, sess)) != CKR_OK) 256 return (rv); 257 258 return (CKR_OK); 259 } 260 261 /* 262 * Shortcut function to go from any state to uninitialized PKCS#11 library. 263 */ 264 void 265 quick_finish(CK_SESSION_HANDLE sess) 266 { 267 cryptodebug("inside quick_finish"); 268 269 /* All the needed calls are done implicitly. */ 270 final_pk11(sess); 271 } 272 273 /* 274 * Gets PIN from user. Caller needs to free the returned PIN when done. 275 * If two prompts are given, the PIN is confirmed with second prompt. 276 * Note that getphassphrase() may return data in static memory area. 277 */ 278 CK_RV 279 get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen) 280 { 281 char *save_phrase, *phrase1, *phrase2; 282 283 cryptodebug("inside get_pin"); 284 285 /* Prompt user for a PIN. */ 286 if (prompt1 == NULL) { 287 cryptodebug("no passphrase prompt given"); 288 return (CKR_ARGUMENTS_BAD); 289 } 290 if ((phrase1 = getpassphrase(prompt1)) == NULL) { 291 cryptodebug("getpassphrase() failed"); 292 return (CKR_FUNCTION_FAILED); 293 } 294 295 /* Duplicate 1st PIN in separate chunk of memory. */ 296 if ((save_phrase = strdup(phrase1)) == NULL) 297 return (CKR_HOST_MEMORY); 298 299 /* If second prompt given, PIN confirmation is requested. */ 300 if (prompt2 != NULL) { 301 if ((phrase2 = getpassphrase(prompt2)) == NULL) { 302 cryptodebug("getpassphrase() confirmation failed"); 303 free(save_phrase); 304 return (CKR_FUNCTION_FAILED); 305 } 306 if (strcmp(save_phrase, phrase2) != 0) { 307 cryptodebug("passphrases do not match"); 308 free(save_phrase); 309 return (CKR_PIN_INCORRECT); 310 } 311 } 312 313 *pin = (CK_UTF8CHAR_PTR)save_phrase; 314 *pinlen = strlen(save_phrase); 315 return (CKR_OK); 316 } 317 318 /* 319 * Gets yes/no response from user. If either no prompt is supplied, a 320 * default prompt is used. If not message for invalid input is supplied, 321 * a default will not be provided. If the user provides no response, 322 * the input default B_TRUE == yes, B_FALSE == no is returned. 323 * Otherwise, B_TRUE is returned for yes, and B_FALSE for no. 324 */ 325 boolean_t 326 yesno(char *prompt, char *invalid, boolean_t dflt) 327 { 328 char *response, buf[1024]; 329 char *yes = gettext("yes"); 330 char *no = gettext("no"); 331 332 cryptodebug("inside yesno"); 333 334 if (prompt == NULL) 335 prompt = gettext("Enter (y)es or (n)o? "); 336 337 for (;;) { 338 /* Prompt user. */ 339 (void) printf("%s", prompt); 340 (void) fflush(stdout); 341 342 /* Get the response. */ 343 if ((response = fgets(buf, sizeof (buf), stdin)) == NULL) 344 break; /* go to default response */ 345 346 /* Skip any leading white space. */ 347 while (isspace(*response)) 348 response++; 349 if (*response == '\0') 350 break; /* go to default response */ 351 352 /* Is it valid input? Return appropriately. */ 353 if (strncasecmp(response, yes, 1) == 0) 354 return (B_TRUE); 355 if (strncasecmp(response, no, 1) == 0) 356 return (B_FALSE); 357 358 /* Indicate invalid input, and try again. */ 359 if (invalid != NULL) 360 (void) printf("%s", invalid); 361 } 362 return (dflt); 363 } 364 365 /* 366 * Gets the list of slots which have tokens in them. Keeps adjusting 367 * the size of the slot list buffer until the call is successful or an 368 * irrecoverable error occurs. 369 */ 370 CK_RV 371 get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) 372 { 373 CK_ULONG tmp_count = 0; 374 CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR; 375 int rv = CKR_OK; 376 377 cryptodebug("inside get_token_slots"); 378 379 if (!initialized) 380 if ((rv = init_pk11()) != CKR_OK) 381 return (rv); 382 383 /* 384 * Get the slot count first because we don't know how many 385 * slots there are and how many of those slots even have tokens. 386 * Don't specify an arbitrary buffer size for the slot list; 387 * it may be too small (see section 11.5 of PKCS#11 spec). 388 * Also select only those slots that have tokens in them, 389 * because this tool has no need to know about empty slots. 390 */ 391 cryptodebug("calling C_GetSlotList() for slot count"); 392 if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK) 393 return (rv); 394 395 if (tmp_count == 0) { 396 cryptodebug("no slots with tokens found"); 397 *slot_list = NULL_PTR; 398 *slot_count = 0; 399 return (CKR_OK); 400 } 401 402 /* Allocate initial space for the slot list. */ 403 if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count * 404 sizeof (CK_SLOT_ID))) == NULL) 405 return (CKR_HOST_MEMORY); 406 407 /* Then get the slot list itself. */ 408 for (;;) { 409 cryptodebug("calling C_GetSlotList()"); 410 if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) { 411 *slot_list = tmp_list; 412 *slot_count = tmp_count; 413 break; 414 } 415 416 if (rv != CKR_BUFFER_TOO_SMALL) { 417 free(tmp_list); 418 break; 419 } 420 421 /* If the number of slots grew, try again. */ 422 cryptodebug("number of tokens present increased"); 423 if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list, 424 tmp_count * sizeof (CK_SLOT_ID))) == NULL) { 425 free(tmp_list); 426 rv = CKR_HOST_MEMORY; 427 break; 428 } 429 tmp_list = tmp2_list; 430 } 431 432 return (rv); 433 } 434 435 /* 436 * memcmp_pad_max() is a specialized version of memcmp() which 437 * compares two pieces of data up to a maximum length. If the 438 * the two data match up the maximum length, they are considered 439 * matching. Trailing blanks do not cause the match to fail if 440 * one of the data is shorted. 441 * 442 * Examples of matches: 443 * "one" | 444 * "one " | 445 * ^maximum length 446 * 447 * "Number One | X" (X is beyond maximum length) 448 * "Number One " | 449 * ^maximum length 450 * 451 * Examples of mismatches: 452 * " one" 453 * "one" 454 * 455 * "Number One X|" 456 * "Number One |" 457 * ^maximum length 458 */ 459 static int 460 memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz) 461 { 462 uint_t len, extra_len; 463 char *marker; 464 465 /* No point in comparing anything beyond max_sz */ 466 if (d1_len > max_sz) 467 d1_len = max_sz; 468 if (d2_len > max_sz) 469 d2_len = max_sz; 470 471 /* Find shorter of the two data. */ 472 if (d1_len <= d2_len) { 473 len = d1_len; 474 extra_len = d2_len; 475 marker = d2; 476 } else { /* d1_len > d2_len */ 477 len = d2_len; 478 extra_len = d1_len; 479 marker = d1; 480 } 481 482 /* Have a match in the shortest length of data? */ 483 if (memcmp(d1, d2, len) != 0) 484 /* CONSTCOND */ 485 return (!0); 486 487 /* If the rest of longer data is nulls or blanks, call it a match. */ 488 while (len < extra_len) 489 if (!isspace(marker[len++])) 490 /* CONSTCOND */ 491 return (!0); 492 return (0); 493 } 494 495 /* 496 * Locate a token slot whose token matches the label, manufacturer ID, and 497 * serial number given. Token label must be specified, manufacturer ID and 498 * serial number are optional. When the token is located, the PIN state 499 * is also returned to determine if it still has the default PIN. 500 */ 501 CK_RV 502 find_token_slot(char *token_name, char *manuf_id, char *serial_no, 503 CK_SLOT_ID *slot_id, CK_FLAGS *pin_state) 504 { 505 CK_SLOT_ID_PTR slot_list; 506 CK_TOKEN_INFO token_info; 507 CK_ULONG slot_count = 0; 508 int rv = CKR_OK; 509 int i; 510 uint_t len, max_sz; 511 boolean_t tok_match = B_FALSE, 512 man_match = B_FALSE, 513 ser_match = B_FALSE; 514 515 cryptodebug("inside find_token_slot"); 516 517 if (token_name == NULL) 518 return (CKR_ARGUMENTS_BAD); 519 520 /* Get a list of all slots with tokens present. */ 521 if ((rv = get_token_slots(&slot_list, &slot_count)) != CKR_OK) 522 return (rv); 523 524 /* If there are no such slots, the desired token won't be found. */ 525 if (slot_count == 0) 526 return (CKR_TOKEN_NOT_PRESENT); 527 528 /* Search the slot list for the token. */ 529 for (i = 0; i < slot_count; i++) { 530 cryptodebug("calling C_GetTokenInfo()"); 531 if ((rv = C_GetTokenInfo(slot_list[i], &token_info)) != 532 CKR_OK) { 533 cryptodebug("token in slot %d returns %s", i, 534 pkcs11_strerror(rv)); 535 continue; 536 } 537 538 /* See if the token label matches. */ 539 len = strlen(token_name); 540 max_sz = sizeof (token_info.label); 541 if (memcmp_pad_max(&(token_info.label), max_sz, token_name, len, 542 max_sz) == 0) 543 tok_match = B_TRUE; 544 545 /* 546 * If manufacturer id was given, see if it actually matches. 547 * If no manufacturer id was given, assume match is true. 548 */ 549 if (manuf_id) { 550 len = strlen(manuf_id); 551 max_sz = sizeof ((char *)(token_info.manufacturerID)); 552 if (memcmp_pad_max(&(token_info.manufacturerID), max_sz, 553 manuf_id, len, max_sz) == 0) 554 man_match = B_TRUE; 555 } else 556 man_match = B_TRUE; 557 558 /* 559 * If serial number was given, see if it actually matches. 560 * If no serial number was given, assume match is true. 561 */ 562 if (serial_no) { 563 len = strlen(serial_no); 564 max_sz = sizeof ((char *)(token_info.serialNumber)); 565 if (memcmp_pad_max(&(token_info.serialNumber), max_sz, 566 serial_no, len, max_sz) == 0) 567 ser_match = B_TRUE; 568 } else 569 ser_match = B_TRUE; 570 571 cryptodebug("slot %d:", i); 572 cryptodebug("\tlabel = \"%.32s\"%s", token_info.label, 573 tok_match ? " match" : ""); 574 cryptodebug("\tmanuf = \"%.32s\"%s", token_info.manufacturerID, 575 man_match ? " match" : ""); 576 cryptodebug("\tserno = \"%.16s\"%s", token_info.serialNumber, 577 ser_match ? " match" : ""); 578 cryptodebug("\tmodel = \"%.16s\"", token_info.model); 579 580 cryptodebug("\tCKF_USER_PIN_INITIALIZED = %s", 581 (token_info.flags & CKF_USER_PIN_INITIALIZED) ? 582 "true" : "false"); 583 cryptodebug("\tCKF_USER_PIN_TO_BE_CHANGED = %s", 584 (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ? 585 "true" : "false"); 586 587 if (tok_match && man_match && ser_match) 588 break; /* found it! */ 589 } 590 591 /* Scanned the whole list without finding the token. */ 592 if (i == slot_count) { 593 cryptodebug("token not found"); 594 free(slot_list); 595 return (CKR_TOKEN_NOT_PRESENT); 596 } 597 598 /* Return slot id where token was found and its PIN state. */ 599 cryptodebug("token found at slot %d", i); 600 *slot_id = slot_list[i]; 601 *pin_state = (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED); 602 free(slot_list); 603 return (CKR_OK); 604 } 605 606 /* 607 * Constructs a fully qualified token name from its label, manufacturer ID 608 * (if any), and its serial number (if any). Note that the given buf must 609 * be big enough. Do NOT i18n/l10n. 610 * 611 * FULL_NAME_LEN is defined in common.h to be 91 because a fully qualified 612 * token name adds up this way: 613 * =32(label) + 32(manuf) + 16(serial) + 4("", ) + 4("", ) + 3("" and nul) 614 */ 615 void 616 full_token_name(char *token_name, char *manuf_id, char *serial_no, char *buf) 617 { 618 char *marker = buf; 619 int n_written = 0; 620 int space_left = FULL_NAME_LEN; 621 622 if (!token_name) 623 return; 624 625 n_written = sprintf(buf, "\"%.32s\"", token_name); 626 marker += n_written; 627 space_left -= n_written; 628 629 n_written = sprintf(marker, ", \"%.32s\"", manuf_id ? manuf_id : ""); 630 marker += n_written; 631 space_left -= n_written; 632 633 n_written = sprintf(marker, ", \"%.16s\"", serial_no ? serial_no : ""); 634 marker += n_written; 635 space_left -= n_written; 636 637 /* space_left should always be >= 1 */ 638 } 639 640 /* 641 * Find how many token objects with the given label. 642 */ 643 CK_RV 644 find_obj_count(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label, 645 CK_ULONG *count) 646 { 647 CK_RV rv = CKR_OK; 648 CK_ATTRIBUTE attrs[4] = { 649 { CKA_TOKEN, &pk_true, sizeof (pk_true) }, 650 { 0, NULL, 0 }, 651 { 0, NULL, 0 }, 652 { 0, NULL, 0 } 653 }; 654 CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); 655 CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */ 656 CK_OBJECT_CLASS obj_class; 657 CK_OBJECT_HANDLE tmp_obj; 658 CK_ULONG obj_count = 0; 659 660 cryptodebug("inside find_obj_count"); 661 662 if (!session_opened || sess == NULL) { 663 cryptodebug("session handle is null"); 664 return (CKR_SESSION_HANDLE_INVALID); 665 } 666 667 if (label) { 668 cryptodebug("object label was specified"); 669 attrs[cur_attr].type = CKA_LABEL; 670 attrs[cur_attr].pValue = label; 671 attrs[cur_attr].ulValueLen = strlen((char *)label); 672 cur_attr++; 673 } 674 675 if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) { 676 cryptodebug("only searching for private objects"); 677 attrs[cur_attr].type = CKA_PRIVATE; 678 attrs[cur_attr].pValue = &pk_true; 679 attrs[cur_attr].ulValueLen = sizeof (pk_true); 680 cur_attr++; 681 } 682 683 /* 684 * If "certs and all keys" is not specified, but at least either 685 * "certs" or some "keys" is specified, then go into this block. 686 * If all certs and keys were specified, there's no point in 687 * putting that fact in the attribute template -- leave that open, 688 * and all certs and keys will be matched automatically. 689 * In other words, only if at least one of 0x10,0x20,0x40,0x80 690 * bits is off, go into this code block. 691 * 692 * NOTE: For now, only one of cert or key types is allowed. 693 * This needs to change in the future. 694 */ 695 if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) && 696 ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) { 697 if (obj_type & PK_CERT_OBJ) { 698 cryptodebug("only searching for certificates"); 699 obj_class = CKO_CERTIFICATE; 700 } else if (obj_type & PK_PRIKEY_OBJ) { 701 cryptodebug("only searching for private keys"); 702 obj_class = CKO_PRIVATE_KEY; 703 } else if (obj_type & PK_PUBKEY_OBJ) { 704 cryptodebug("only searching for public keys"); 705 obj_class = CKO_PUBLIC_KEY; 706 } else if (obj_type & PK_SECKEY_OBJ) { 707 cryptodebug("only searching for secret keys"); 708 obj_class = CKO_SECRET_KEY; 709 } 710 711 attrs[cur_attr].type = CKA_CLASS; 712 attrs[cur_attr].pValue = &obj_class; 713 attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS); 714 cur_attr++; 715 } 716 717 /* 718 * This can't happen now. When finding objects is enhanced in the 719 * future. this could lead to buffer overruns. 720 */ 721 if (cur_attr > num_attrs) 722 cryptodebug("internal error: attr template overrun"); 723 724 cryptodebug("calling C_FindObjectsInit"); 725 if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK) 726 return (rv); 727 728 /* Look for the object, checking if there are more than one. */ 729 cryptodebug("calling C_FindObjects"); 730 for (*count = 0; /* empty */; (*count)++) { 731 if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) != 732 CKR_OK) 733 break; 734 735 /* No more found. */ 736 if (obj_count == 0) 737 break; 738 } 739 740 cryptodebug("%d matching objects found", *count); 741 742 cryptodebug("calling C_FindObjectsFinal"); 743 (void) C_FindObjectsFinal(sess); 744 return (rv); 745 } 746 747 /* 748 * Find the token object with the given label. 749 */ 750 CK_RV 751 find_objs(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label, 752 CK_OBJECT_HANDLE_PTR *obj, CK_ULONG *count) 753 { 754 CK_RV rv = CKR_OK; 755 CK_ATTRIBUTE attrs[4] = { 756 { CKA_TOKEN, &pk_true, sizeof (pk_true) }, 757 { 0, NULL, 0 }, 758 { 0, NULL, 0 }, 759 { 0, NULL, 0 } 760 }; 761 CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); 762 CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */ 763 CK_OBJECT_CLASS obj_class; 764 CK_OBJECT_HANDLE tmp_obj; 765 CK_ULONG obj_count = 0; 766 int i; 767 768 cryptodebug("inside find_obj"); 769 770 if ((rv = find_obj_count(sess, obj_type, label, count)) != CKR_OK) 771 return (rv); 772 773 if (*count == 0) 774 return (CKR_OK); 775 776 if ((*obj = (CK_OBJECT_HANDLE_PTR) malloc((*count) * 777 sizeof (CK_OBJECT_HANDLE))) == NULL) { 778 cryptodebug("no memory for found object"); 779 return (CKR_HOST_MEMORY); 780 } 781 782 if (label) { 783 cryptodebug("object label was specified"); 784 attrs[cur_attr].type = CKA_LABEL; 785 attrs[cur_attr].pValue = label; 786 attrs[cur_attr].ulValueLen = strlen((char *)label); 787 cur_attr++; 788 } 789 790 if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) { 791 cryptodebug("only searching for private objects"); 792 attrs[cur_attr].type = CKA_PRIVATE; 793 attrs[cur_attr].pValue = &pk_true; 794 attrs[cur_attr].ulValueLen = sizeof (pk_true); 795 cur_attr++; 796 } 797 798 /* 799 * If "certs and all keys" is not specified, but at least either 800 * "certs" or some "keys" is specified, then go into this block. 801 * If all certs and keys were specified, there's no point in 802 * putting that fact in the attribute template -- leave that open, 803 * and all certs and keys will be matched automatically. 804 * In other words, only if at least one of 0x10,0x20,0x40,0x80 805 * bits is off, go into this code block. 806 * 807 * NOTE: For now, only one of cert or key types is allowed. 808 * This needs to change in the future. 809 */ 810 if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) && 811 ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) { 812 if (obj_type & PK_CERT_OBJ) { 813 cryptodebug("only searching for certificates"); 814 obj_class = CKO_CERTIFICATE; 815 } else if (obj_type & PK_PRIKEY_OBJ) { 816 cryptodebug("only searching for private keys"); 817 obj_class = CKO_PRIVATE_KEY; 818 } else if (obj_type & PK_PUBKEY_OBJ) { 819 cryptodebug("only searching for public keys"); 820 obj_class = CKO_PUBLIC_KEY; 821 } else if (obj_type & PK_SECKEY_OBJ) { 822 cryptodebug("only searching for secret keys"); 823 obj_class = CKO_SECRET_KEY; 824 } 825 826 attrs[cur_attr].type = CKA_CLASS; 827 attrs[cur_attr].pValue = &obj_class; 828 attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS); 829 cur_attr++; 830 } 831 832 /* 833 * This can't happen now. When finding objects is enhanced in the 834 * future. this could lead to buffer overruns. 835 */ 836 if (cur_attr > num_attrs) 837 cryptodebug("internal error: attr template overrun"); 838 839 cryptodebug("calling C_FindObjectsInit"); 840 if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK) { 841 free(*obj); 842 return (rv); 843 } 844 845 /* 846 * Find all the matching objects. The loop goes 1 more beyond 847 * the number of objects found to determine if any new objects 848 * were created since the time the object count was done. 849 */ 850 cryptodebug("calling C_FindObjects"); 851 for (i = 0; i < (*count) + 1; i++) { 852 if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) != 853 CKR_OK) 854 break; 855 856 /* No more found. */ 857 if (obj_count == 0) 858 break; 859 860 /* 861 * Save the object in the list being created, as long as 862 * we don't overrun the size of the list. 863 */ 864 if (i < *count) 865 (*obj)[i] = tmp_obj; 866 else 867 cryptodebug("number of objects changed since last count"); 868 } 869 870 if (rv != CKR_OK) { 871 free(*obj); 872 } else { 873 /* 874 * There are three cases to handle: (1) fewer objects were 875 * found than originally counted => change *count to the 876 * smaller number; (2) the number of objects found matches 877 * the number originally counted => do nothing; (3) more 878 * objects found than originally counted => list passed 879 * in is too small to contain the extra object(s), flag 880 * that in the debug output but don't change number of 881 * objects returned. The caller can double-check by 882 * calling find_obj_count() after this function to make 883 * sure the numbers match, if desired. 884 */ 885 /* Case 1: Fewer objects. */ 886 if (i < *count) { 887 cryptodebug("%d objects found, expected %d", i, *count); 888 *count = i; 889 /* Case 3: More objects. */ 890 } else if (i > *count) { 891 cryptodebug("at least %d objects found, expected %d", 892 i, *count); 893 } 894 /* 895 * Case 2: Same number of objects. 896 * 897 * else if (i == *count) 898 * ; 899 */ 900 } 901 902 cryptodebug("calling C_FindObjectsFinal"); 903 (void) C_FindObjectsFinal(sess); 904 return (rv); 905 } 906 907 char * 908 class_str(CK_OBJECT_CLASS class) 909 { 910 switch (class) { 911 case CKO_DATA: return (gettext("data")); 912 case CKO_CERTIFICATE: return (gettext("certificate")); 913 case CKO_PUBLIC_KEY: return (gettext("public key")); 914 case CKO_PRIVATE_KEY: return (gettext("private key")); 915 case CKO_SECRET_KEY: return (gettext("secret key")); 916 case CKO_DOMAIN_PARAMETERS: return (gettext("domain parameter")); 917 default: return (gettext("unknown object")); 918 } 919 } 920 921 char * 922 keytype_str(CK_KEY_TYPE keytype) 923 { 924 switch (keytype) { 925 case CKK_RSA: return (gettext("RSA")); 926 case CKK_DSA: return (gettext("DSA")); 927 case CKK_DH: return (gettext("Diffie-Hellman")); 928 case CKK_X9_42_DH: return (gettext("X9.42 Diffie-Hellman")); 929 case CKK_GENERIC_SECRET: return (gettext("generic")); 930 case CKK_RC2: return (gettext("RC2")); 931 case CKK_RC4: return (gettext("RC4")); 932 case CKK_DES: return (gettext("DES")); 933 case CKK_DES2: return (gettext("Double-DES")); 934 case CKK_DES3: return (gettext("Triple-DES")); 935 case CKK_RC5: return (gettext("RC5")); 936 case CKK_AES: return (gettext("AES")); 937 default: return (gettext("typeless")); 938 } 939 } 940 941 char * 942 attr_str(CK_ATTRIBUTE_TYPE attrtype) 943 { 944 switch (attrtype) { 945 case CKA_PRIVATE: return (gettext("private")); 946 case CKA_LOCAL: return (gettext("local")); 947 case CKA_SENSITIVE: return (gettext("sensitive")); 948 case CKA_EXTRACTABLE: return (gettext("extractable")); 949 case CKA_ENCRYPT: return (gettext("encrypt")); 950 case CKA_DECRYPT: return (gettext("decrypt")); 951 case CKA_WRAP: return (gettext("wrap")); 952 case CKA_UNWRAP: return (gettext("unwrap")); 953 case CKA_SIGN: return (gettext("sign")); 954 case CKA_SIGN_RECOVER: return (gettext("sign-recover")); 955 case CKA_VERIFY: return (gettext("verify")); 956 case CKA_VERIFY_RECOVER: return (gettext("verify-recover")); 957 case CKA_DERIVE: return (gettext("derive")); 958 case CKA_ALWAYS_SENSITIVE: return (gettext("always sensitive")); 959 case CKA_NEVER_EXTRACTABLE: return (gettext("never extractable")); 960 default: return (gettext("unknown capability")); 961 } 962 } 963 964 /* 965 * Convert a byte string into a string of octets formatted like this: 966 * oo oo oo oo oo ... oo 967 * where each "oo" is an octet is space separated and in the form: 968 * [0-f][0-f] if the octet is a non-printable character 969 * <space><char> if the octet is a printable character 970 * 971 * Note: octets_sz must be 3 * str_sz + 1, or at least as long as "blank" 972 */ 973 void 974 octetify(CK_BYTE *str, CK_ULONG str_sz, char *octets, int octets_sz, 975 boolean_t stop_on_nul, boolean_t do_ascii, int limit, char *indent, 976 char *blank) 977 { 978 char *marker; 979 int nc; 980 int newline; 981 int indent_len; 982 boolean_t first = B_TRUE; 983 984 cryptodebug("inside octetify"); 985 986 cryptodebug(stop_on_nul ? "stopping on first nul found" : 987 "continuing to full length of buffer"); 988 cryptodebug(do_ascii ? "using ascii chars where printable" : 989 "using only hex octets"); 990 cryptodebug("every %d characters indent with \"%s\"\n ", limit, indent); 991 cryptodebug("return \"%s\" if buffer is null or empty", blank); 992 993 /* If string is empty, write as much of the blank string and leave. */ 994 if (str_sz == 0) { 995 (void) snprintf(octets, octets_sz, "%s", blank); 996 return; 997 } 998 999 /* If only limit or indent is set, pick default for the other. */ 1000 if (limit > 0 && indent == NULL) 1001 indent = "\n"; 1002 if (indent != NULL && limit == 0) 1003 limit = 60; 1004 indent_len = strlen(indent); 1005 1006 for (marker = octets, newline = 0, first = B_TRUE; 1007 (stop_on_nul && *str != '\0') || 1008 (!stop_on_nul && str_sz > 0 && octets_sz > 0); 1009 str++, str_sz--, marker += nc, octets_sz -= nc) { 1010 if (!first) { 1011 if (limit > 0 && ((marker - octets) / limit) > 1012 newline) { 1013 nc = snprintf(marker, indent_len, "%s", indent); 1014 newline++; 1015 continue; 1016 } 1017 nc = sprintf(marker, 1018 ((do_ascii && isprint(*str) && !isspace(*str)) ? 1019 "%s%c" : "%s%02x"), (do_ascii ? " " : ":"), *str); 1020 } else { 1021 nc = sprintf(marker, 1022 ((do_ascii && isprint(*str) && !isspace(*str)) ? 1023 "%c" : "%02x"), *str); 1024 first = B_FALSE; 1025 } 1026 } 1027 *marker = '\0'; 1028 } 1029 1030 /* 1031 * Copies a biginteger_t to a template attribute. 1032 * Should be a macro instead of a function. 1033 */ 1034 void 1035 copy_bigint_to_attr(biginteger_t big, CK_ATTRIBUTE_PTR attr) 1036 { 1037 attr->pValue = big.big_value; 1038 attr->ulValueLen = big.big_value_len; 1039 } 1040 1041 /* 1042 * Copies a string and its length to a template attribute. 1043 * Should be a macro instead of a function. 1044 */ 1045 void 1046 copy_string_to_attr(CK_BYTE *buf, CK_ULONG buflen, CK_ATTRIBUTE_PTR attr) 1047 { 1048 attr->pValue = buf; 1049 attr->ulValueLen = buflen; 1050 } 1051 1052 /* 1053 * Copies a template attribute to a biginteger_t. 1054 * Should be a macro instead of a function. 1055 */ 1056 void 1057 copy_attr_to_bigint(CK_ATTRIBUTE_PTR attr, biginteger_t *big) 1058 { 1059 big->big_value = attr->pValue; 1060 big->big_value_len = attr->ulValueLen; 1061 } 1062 1063 /* 1064 * Copies a template attribute to a string and its length. 1065 * Should be a macro instead of a function. 1066 */ 1067 void 1068 copy_attr_to_string(CK_ATTRIBUTE_PTR attr, CK_BYTE **buf, CK_ULONG *buflen) 1069 { 1070 *buf = attr->pValue; 1071 *buflen = attr->ulValueLen; 1072 } 1073 1074 /* 1075 * Copies a template attribute to a date and its length. 1076 * Should be a macro instead of a function. 1077 */ 1078 void 1079 copy_attr_to_date(CK_ATTRIBUTE_PTR attr, CK_DATE **buf, CK_ULONG *buflen) 1080 { 1081 *buf = (CK_DATE *)attr->pValue; 1082 *buflen = attr->ulValueLen; 1083 } 1084