1 /* 2 * Copyright (c) 2004 - 2006 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "hx_locl.h" 35 RCSID("$Id: ks_p11.c 22071 2007-11-14 20:04:50Z lha $"); 36 #ifdef HAVE_DLFCN_H 37 #include <dlfcn.h> 38 #endif 39 40 #ifdef HAVE_DLOPEN 41 42 #include "pkcs11.h" 43 44 struct p11_slot { 45 int flags; 46 #define P11_SESSION 1 47 #define P11_SESSION_IN_USE 2 48 #define P11_LOGIN_REQ 4 49 #define P11_LOGIN_DONE 8 50 #define P11_TOKEN_PRESENT 16 51 CK_SESSION_HANDLE session; 52 CK_SLOT_ID id; 53 CK_BBOOL token; 54 char *name; 55 hx509_certs certs; 56 char *pin; 57 struct { 58 CK_MECHANISM_TYPE_PTR list; 59 CK_ULONG num; 60 CK_MECHANISM_INFO_PTR *infos; 61 } mechs; 62 }; 63 64 struct p11_module { 65 void *dl_handle; 66 CK_FUNCTION_LIST_PTR funcs; 67 CK_ULONG num_slots; 68 unsigned int refcount; 69 struct p11_slot *slot; 70 }; 71 72 #define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args 73 74 static int p11_get_session(hx509_context, 75 struct p11_module *, 76 struct p11_slot *, 77 hx509_lock, 78 CK_SESSION_HANDLE *); 79 static int p11_put_session(struct p11_module *, 80 struct p11_slot *, 81 CK_SESSION_HANDLE); 82 static void p11_release_module(struct p11_module *); 83 84 static int p11_list_keys(hx509_context, 85 struct p11_module *, 86 struct p11_slot *, 87 CK_SESSION_HANDLE, 88 hx509_lock, 89 hx509_certs *); 90 91 /* 92 * 93 */ 94 95 struct p11_rsa { 96 struct p11_module *p; 97 struct p11_slot *slot; 98 CK_OBJECT_HANDLE private_key; 99 CK_OBJECT_HANDLE public_key; 100 }; 101 102 static int 103 p11_rsa_public_encrypt(int flen, 104 const unsigned char *from, 105 unsigned char *to, 106 RSA *rsa, 107 int padding) 108 { 109 return -1; 110 } 111 112 static int 113 p11_rsa_public_decrypt(int flen, 114 const unsigned char *from, 115 unsigned char *to, 116 RSA *rsa, 117 int padding) 118 { 119 return -1; 120 } 121 122 123 static int 124 p11_rsa_private_encrypt(int flen, 125 const unsigned char *from, 126 unsigned char *to, 127 RSA *rsa, 128 int padding) 129 { 130 struct p11_rsa *p11rsa = RSA_get_app_data(rsa); 131 CK_OBJECT_HANDLE key = p11rsa->private_key; 132 CK_SESSION_HANDLE session; 133 CK_MECHANISM mechanism; 134 CK_ULONG ck_sigsize; 135 int ret; 136 137 if (padding != RSA_PKCS1_PADDING) 138 return -1; 139 140 memset(&mechanism, 0, sizeof(mechanism)); 141 mechanism.mechanism = CKM_RSA_PKCS; 142 143 ck_sigsize = RSA_size(rsa); 144 145 ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session); 146 if (ret) 147 return -1; 148 149 ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key)); 150 if (ret != CKR_OK) { 151 p11_put_session(p11rsa->p, p11rsa->slot, session); 152 return -1; 153 } 154 155 ret = P11FUNC(p11rsa->p, Sign, 156 (session, (CK_BYTE *)from, flen, to, &ck_sigsize)); 157 p11_put_session(p11rsa->p, p11rsa->slot, session); 158 if (ret != CKR_OK) 159 return -1; 160 161 return ck_sigsize; 162 } 163 164 static int 165 p11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, 166 RSA * rsa, int padding) 167 { 168 struct p11_rsa *p11rsa = RSA_get_app_data(rsa); 169 CK_OBJECT_HANDLE key = p11rsa->private_key; 170 CK_SESSION_HANDLE session; 171 CK_MECHANISM mechanism; 172 CK_ULONG ck_sigsize; 173 int ret; 174 175 if (padding != RSA_PKCS1_PADDING) 176 return -1; 177 178 memset(&mechanism, 0, sizeof(mechanism)); 179 mechanism.mechanism = CKM_RSA_PKCS; 180 181 ck_sigsize = RSA_size(rsa); 182 183 ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session); 184 if (ret) 185 return -1; 186 187 ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key)); 188 if (ret != CKR_OK) { 189 p11_put_session(p11rsa->p, p11rsa->slot, session); 190 return -1; 191 } 192 193 ret = P11FUNC(p11rsa->p, Decrypt, 194 (session, (CK_BYTE *)from, flen, to, &ck_sigsize)); 195 p11_put_session(p11rsa->p, p11rsa->slot, session); 196 if (ret != CKR_OK) 197 return -1; 198 199 return ck_sigsize; 200 } 201 202 static int 203 p11_rsa_init(RSA *rsa) 204 { 205 return 1; 206 } 207 208 static int 209 p11_rsa_finish(RSA *rsa) 210 { 211 struct p11_rsa *p11rsa = RSA_get_app_data(rsa); 212 p11_release_module(p11rsa->p); 213 free(p11rsa); 214 return 1; 215 } 216 217 static const RSA_METHOD p11_rsa_pkcs1_method = { 218 "hx509 PKCS11 PKCS#1 RSA", 219 p11_rsa_public_encrypt, 220 p11_rsa_public_decrypt, 221 p11_rsa_private_encrypt, 222 p11_rsa_private_decrypt, 223 NULL, 224 NULL, 225 p11_rsa_init, 226 p11_rsa_finish, 227 0, 228 NULL, 229 NULL, 230 NULL 231 }; 232 233 /* 234 * 235 */ 236 237 static int 238 p11_mech_info(hx509_context context, 239 struct p11_module *p, 240 struct p11_slot *slot, 241 int num) 242 { 243 CK_ULONG i; 244 int ret; 245 246 ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i)); 247 if (ret) { 248 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 249 "Failed to get mech list count for slot %d", 250 num); 251 return HX509_PKCS11_NO_MECH; 252 } 253 if (i == 0) { 254 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 255 "no mech supported for slot %d", num); 256 return HX509_PKCS11_NO_MECH; 257 } 258 slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0])); 259 if (slot->mechs.list == NULL) { 260 hx509_set_error_string(context, 0, ENOMEM, 261 "out of memory"); 262 return ENOMEM; 263 } 264 slot->mechs.num = i; 265 ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i)); 266 if (ret) { 267 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 268 "Failed to get mech list for slot %d", 269 num); 270 return HX509_PKCS11_NO_MECH; 271 } 272 assert(i == slot->mechs.num); 273 274 slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos)); 275 if (slot->mechs.list == NULL) { 276 hx509_set_error_string(context, 0, ENOMEM, 277 "out of memory"); 278 return ENOMEM; 279 } 280 281 for (i = 0; i < slot->mechs.num; i++) { 282 slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0]))); 283 if (slot->mechs.infos[i] == NULL) { 284 hx509_set_error_string(context, 0, ENOMEM, 285 "out of memory"); 286 return ENOMEM; 287 } 288 ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i], 289 slot->mechs.infos[i])); 290 if (ret) { 291 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 292 "Failed to get mech info for slot %d", 293 num); 294 return HX509_PKCS11_NO_MECH; 295 } 296 } 297 298 return 0; 299 } 300 301 static int 302 p11_init_slot(hx509_context context, 303 struct p11_module *p, 304 hx509_lock lock, 305 CK_SLOT_ID id, 306 int num, 307 struct p11_slot *slot) 308 { 309 CK_SESSION_HANDLE session; 310 CK_SLOT_INFO slot_info; 311 CK_TOKEN_INFO token_info; 312 int ret, i; 313 314 slot->certs = NULL; 315 slot->id = id; 316 317 ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info)); 318 if (ret) { 319 hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED, 320 "Failed to init PKCS11 slot %d", 321 num); 322 return HX509_PKCS11_TOKEN_CONFUSED; 323 } 324 325 for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) { 326 char c = slot_info.slotDescription[i]; 327 if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0') 328 continue; 329 i++; 330 break; 331 } 332 333 asprintf(&slot->name, "%.*s", 334 i, slot_info.slotDescription); 335 336 if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0) 337 return 0; 338 339 ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info)); 340 if (ret) { 341 hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN, 342 "Failed to init PKCS11 slot %d " 343 "with error 0x08x", 344 num, ret); 345 return HX509_PKCS11_NO_TOKEN; 346 } 347 slot->flags |= P11_TOKEN_PRESENT; 348 349 if (token_info.flags & CKF_LOGIN_REQUIRED) 350 slot->flags |= P11_LOGIN_REQ; 351 352 ret = p11_get_session(context, p, slot, lock, &session); 353 if (ret) 354 return ret; 355 356 ret = p11_mech_info(context, p, slot, num); 357 if (ret) 358 goto out; 359 360 ret = p11_list_keys(context, p, slot, session, lock, &slot->certs); 361 out: 362 p11_put_session(p, slot, session); 363 364 return ret; 365 } 366 367 static int 368 p11_get_session(hx509_context context, 369 struct p11_module *p, 370 struct p11_slot *slot, 371 hx509_lock lock, 372 CK_SESSION_HANDLE *psession) 373 { 374 CK_RV ret; 375 376 if (slot->flags & P11_SESSION_IN_USE) 377 _hx509_abort("slot already in session"); 378 379 if (slot->flags & P11_SESSION) { 380 slot->flags |= P11_SESSION_IN_USE; 381 *psession = slot->session; 382 return 0; 383 } 384 385 ret = P11FUNC(p, OpenSession, (slot->id, 386 CKF_SERIAL_SESSION, 387 NULL, 388 NULL, 389 &slot->session)); 390 if (ret != CKR_OK) { 391 if (context) 392 hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION, 393 "Failed to OpenSession for slot id %d " 394 "with error: 0x%08x", 395 (int)slot->id, ret); 396 return HX509_PKCS11_OPEN_SESSION; 397 } 398 399 slot->flags |= P11_SESSION; 400 401 /* 402 * If we have have to login, and haven't tried before and have a 403 * prompter or known to work pin code. 404 * 405 * This code is very conversative and only uses the prompter in 406 * the hx509_lock, the reason is that it's bad to try many 407 * passwords on a pkcs11 token, it might lock up and have to be 408 * unlocked by a administrator. 409 * 410 * XXX try harder to not use pin several times on the same card. 411 */ 412 413 if ( (slot->flags & P11_LOGIN_REQ) 414 && (slot->flags & P11_LOGIN_DONE) == 0 415 && (lock || slot->pin)) 416 { 417 hx509_prompt prompt; 418 char pin[20]; 419 char *str; 420 421 slot->flags |= P11_LOGIN_DONE; 422 423 if (slot->pin == NULL) { 424 425 memset(&prompt, 0, sizeof(prompt)); 426 427 asprintf(&str, "PIN code for %s: ", slot->name); 428 prompt.prompt = str; 429 prompt.type = HX509_PROMPT_TYPE_PASSWORD; 430 prompt.reply.data = pin; 431 prompt.reply.length = sizeof(pin); 432 433 ret = hx509_lock_prompt(lock, &prompt); 434 if (ret) { 435 free(str); 436 if (context) 437 hx509_set_error_string(context, 0, ret, 438 "Failed to get pin code for slot " 439 "id %d with error: %d", 440 (int)slot->id, ret); 441 return ret; 442 } 443 free(str); 444 } else { 445 strlcpy(pin, slot->pin, sizeof(pin)); 446 } 447 448 ret = P11FUNC(p, Login, (slot->session, CKU_USER, 449 (unsigned char*)pin, strlen(pin))); 450 if (ret != CKR_OK) { 451 if (context) 452 hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN, 453 "Failed to login on slot id %d " 454 "with error: 0x%08x", 455 (int)slot->id, ret); 456 p11_put_session(p, slot, slot->session); 457 return HX509_PKCS11_LOGIN; 458 } 459 if (slot->pin == NULL) { 460 slot->pin = strdup(pin); 461 if (slot->pin == NULL) { 462 if (context) 463 hx509_set_error_string(context, 0, ENOMEM, 464 "out of memory"); 465 p11_put_session(p, slot, slot->session); 466 return ENOMEM; 467 } 468 } 469 } else 470 slot->flags |= P11_LOGIN_DONE; 471 472 slot->flags |= P11_SESSION_IN_USE; 473 474 *psession = slot->session; 475 476 return 0; 477 } 478 479 static int 480 p11_put_session(struct p11_module *p, 481 struct p11_slot *slot, 482 CK_SESSION_HANDLE session) 483 { 484 if ((slot->flags & P11_SESSION_IN_USE) == 0) 485 _hx509_abort("slot not in session"); 486 slot->flags &= ~P11_SESSION_IN_USE; 487 488 return 0; 489 } 490 491 static int 492 iterate_entries(hx509_context context, 493 struct p11_module *p, struct p11_slot *slot, 494 CK_SESSION_HANDLE session, 495 CK_ATTRIBUTE *search_data, int num_search_data, 496 CK_ATTRIBUTE *query, int num_query, 497 int (*func)(hx509_context, 498 struct p11_module *, struct p11_slot *, 499 CK_SESSION_HANDLE session, 500 CK_OBJECT_HANDLE object, 501 void *, CK_ATTRIBUTE *, int), void *ptr) 502 { 503 CK_OBJECT_HANDLE object; 504 CK_ULONG object_count; 505 int ret, i; 506 507 ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data)); 508 if (ret != CKR_OK) { 509 return -1; 510 } 511 while (1) { 512 ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count)); 513 if (ret != CKR_OK) { 514 return -1; 515 } 516 if (object_count == 0) 517 break; 518 519 for (i = 0; i < num_query; i++) 520 query[i].pValue = NULL; 521 522 ret = P11FUNC(p, GetAttributeValue, 523 (session, object, query, num_query)); 524 if (ret != CKR_OK) { 525 return -1; 526 } 527 for (i = 0; i < num_query; i++) { 528 query[i].pValue = malloc(query[i].ulValueLen); 529 if (query[i].pValue == NULL) { 530 ret = ENOMEM; 531 goto out; 532 } 533 } 534 ret = P11FUNC(p, GetAttributeValue, 535 (session, object, query, num_query)); 536 if (ret != CKR_OK) { 537 ret = -1; 538 goto out; 539 } 540 541 ret = (*func)(context, p, slot, session, object, ptr, query, num_query); 542 if (ret) 543 goto out; 544 545 for (i = 0; i < num_query; i++) { 546 if (query[i].pValue) 547 free(query[i].pValue); 548 query[i].pValue = NULL; 549 } 550 } 551 out: 552 553 for (i = 0; i < num_query; i++) { 554 if (query[i].pValue) 555 free(query[i].pValue); 556 query[i].pValue = NULL; 557 } 558 559 ret = P11FUNC(p, FindObjectsFinal, (session)); 560 if (ret != CKR_OK) { 561 return -2; 562 } 563 564 565 return 0; 566 } 567 568 static BIGNUM * 569 getattr_bn(struct p11_module *p, 570 struct p11_slot *slot, 571 CK_SESSION_HANDLE session, 572 CK_OBJECT_HANDLE object, 573 unsigned int type) 574 { 575 CK_ATTRIBUTE query; 576 BIGNUM *bn; 577 int ret; 578 579 query.type = type; 580 query.pValue = NULL; 581 query.ulValueLen = 0; 582 583 ret = P11FUNC(p, GetAttributeValue, 584 (session, object, &query, 1)); 585 if (ret != CKR_OK) 586 return NULL; 587 588 query.pValue = malloc(query.ulValueLen); 589 590 ret = P11FUNC(p, GetAttributeValue, 591 (session, object, &query, 1)); 592 if (ret != CKR_OK) { 593 free(query.pValue); 594 return NULL; 595 } 596 bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL); 597 free(query.pValue); 598 599 return bn; 600 } 601 602 static int 603 collect_private_key(hx509_context context, 604 struct p11_module *p, struct p11_slot *slot, 605 CK_SESSION_HANDLE session, 606 CK_OBJECT_HANDLE object, 607 void *ptr, CK_ATTRIBUTE *query, int num_query) 608 { 609 struct hx509_collector *collector = ptr; 610 hx509_private_key key; 611 heim_octet_string localKeyId; 612 int ret; 613 RSA *rsa; 614 struct p11_rsa *p11rsa; 615 616 localKeyId.data = query[0].pValue; 617 localKeyId.length = query[0].ulValueLen; 618 619 ret = _hx509_private_key_init(&key, NULL, NULL); 620 if (ret) 621 return ret; 622 623 rsa = RSA_new(); 624 if (rsa == NULL) 625 _hx509_abort("out of memory"); 626 627 /* 628 * The exponent and modulus should always be present according to 629 * the pkcs11 specification, but some smartcards leaves it out, 630 * let ignore any failure to fetch it. 631 */ 632 rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS); 633 rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT); 634 635 p11rsa = calloc(1, sizeof(*p11rsa)); 636 if (p11rsa == NULL) 637 _hx509_abort("out of memory"); 638 639 p11rsa->p = p; 640 p11rsa->slot = slot; 641 p11rsa->private_key = object; 642 643 p->refcount++; 644 if (p->refcount == 0) 645 _hx509_abort("pkcs11 refcount to high"); 646 647 RSA_set_method(rsa, &p11_rsa_pkcs1_method); 648 ret = RSA_set_app_data(rsa, p11rsa); 649 if (ret != 1) 650 _hx509_abort("RSA_set_app_data"); 651 652 _hx509_private_key_assign_rsa(key, rsa); 653 654 ret = _hx509_collector_private_key_add(context, 655 collector, 656 hx509_signature_rsa(), 657 key, 658 NULL, 659 &localKeyId); 660 661 if (ret) { 662 _hx509_private_key_free(&key); 663 return ret; 664 } 665 return 0; 666 } 667 668 static void 669 p11_cert_release(hx509_cert cert, void *ctx) 670 { 671 struct p11_module *p = ctx; 672 p11_release_module(p); 673 } 674 675 676 static int 677 collect_cert(hx509_context context, 678 struct p11_module *p, struct p11_slot *slot, 679 CK_SESSION_HANDLE session, 680 CK_OBJECT_HANDLE object, 681 void *ptr, CK_ATTRIBUTE *query, int num_query) 682 { 683 struct hx509_collector *collector = ptr; 684 hx509_cert cert; 685 int ret; 686 687 if ((CK_LONG)query[0].ulValueLen == -1 || 688 (CK_LONG)query[1].ulValueLen == -1) 689 { 690 return 0; 691 } 692 693 ret = hx509_cert_init_data(context, query[1].pValue, 694 query[1].ulValueLen, &cert); 695 if (ret) 696 return ret; 697 698 p->refcount++; 699 if (p->refcount == 0) 700 _hx509_abort("pkcs11 refcount to high"); 701 702 _hx509_cert_set_release(cert, p11_cert_release, p); 703 704 { 705 heim_octet_string data; 706 707 data.data = query[0].pValue; 708 data.length = query[0].ulValueLen; 709 710 _hx509_set_cert_attribute(context, 711 cert, 712 oid_id_pkcs_9_at_localKeyId(), 713 &data); 714 } 715 716 if ((CK_LONG)query[2].ulValueLen != -1) { 717 char *str; 718 719 asprintf(&str, "%.*s", 720 (int)query[2].ulValueLen, (char *)query[2].pValue); 721 if (str) { 722 hx509_cert_set_friendly_name(cert, str); 723 free(str); 724 } 725 } 726 727 ret = _hx509_collector_certs_add(context, collector, cert); 728 hx509_cert_free(cert); 729 730 return ret; 731 } 732 733 734 static int 735 p11_list_keys(hx509_context context, 736 struct p11_module *p, 737 struct p11_slot *slot, 738 CK_SESSION_HANDLE session, 739 hx509_lock lock, 740 hx509_certs *certs) 741 { 742 struct hx509_collector *collector; 743 CK_OBJECT_CLASS key_class; 744 CK_ATTRIBUTE search_data[] = { 745 {CKA_CLASS, NULL, 0}, 746 }; 747 CK_ATTRIBUTE query_data[3] = { 748 {CKA_ID, NULL, 0}, 749 {CKA_VALUE, NULL, 0}, 750 {CKA_LABEL, NULL, 0} 751 }; 752 int ret; 753 754 search_data[0].pValue = &key_class; 755 search_data[0].ulValueLen = sizeof(key_class); 756 757 if (lock == NULL) 758 lock = _hx509_empty_lock; 759 760 ret = _hx509_collector_alloc(context, lock, &collector); 761 if (ret) 762 return ret; 763 764 key_class = CKO_PRIVATE_KEY; 765 ret = iterate_entries(context, p, slot, session, 766 search_data, 1, 767 query_data, 1, 768 collect_private_key, collector); 769 if (ret) 770 goto out; 771 772 key_class = CKO_CERTIFICATE; 773 ret = iterate_entries(context, p, slot, session, 774 search_data, 1, 775 query_data, 3, 776 collect_cert, collector); 777 if (ret) 778 goto out; 779 780 ret = _hx509_collector_collect_certs(context, collector, &slot->certs); 781 782 out: 783 _hx509_collector_free(collector); 784 785 return ret; 786 } 787 788 789 static int 790 p11_init(hx509_context context, 791 hx509_certs certs, void **data, int flags, 792 const char *residue, hx509_lock lock) 793 { 794 CK_C_GetFunctionList getFuncs; 795 struct p11_module *p; 796 char *list, *str; 797 int ret; 798 799 *data = NULL; 800 801 list = strdup(residue); 802 if (list == NULL) 803 return ENOMEM; 804 805 p = calloc(1, sizeof(*p)); 806 if (p == NULL) { 807 free(list); 808 return ENOMEM; 809 } 810 811 p->refcount = 1; 812 813 str = strchr(list, ','); 814 if (str) 815 *str++ = '\0'; 816 while (str) { 817 char *strnext; 818 strnext = strchr(str, ','); 819 if (strnext) 820 *strnext++ = '\0'; 821 #if 0 822 if (strncasecmp(str, "slot=", 5) == 0) 823 p->selected_slot = atoi(str + 5); 824 #endif 825 str = strnext; 826 } 827 828 p->dl_handle = dlopen(list, RTLD_NOW); 829 free(list); 830 if (p->dl_handle == NULL) { 831 ret = HX509_PKCS11_LOAD; 832 hx509_set_error_string(context, 0, ret, 833 "Failed to open %s: %s", list, dlerror()); 834 goto out; 835 } 836 837 getFuncs = dlsym(p->dl_handle, "C_GetFunctionList"); 838 if (getFuncs == NULL) { 839 ret = HX509_PKCS11_LOAD; 840 hx509_set_error_string(context, 0, ret, 841 "C_GetFunctionList missing in %s: %s", 842 list, dlerror()); 843 goto out; 844 } 845 846 ret = (*getFuncs)(&p->funcs); 847 if (ret) { 848 ret = HX509_PKCS11_LOAD; 849 hx509_set_error_string(context, 0, ret, 850 "C_GetFunctionList failed in %s", list); 851 goto out; 852 } 853 854 ret = P11FUNC(p, Initialize, (NULL_PTR)); 855 if (ret != CKR_OK) { 856 ret = HX509_PKCS11_TOKEN_CONFUSED; 857 hx509_set_error_string(context, 0, ret, 858 "Failed initialize the PKCS11 module"); 859 goto out; 860 } 861 862 ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots)); 863 if (ret) { 864 ret = HX509_PKCS11_TOKEN_CONFUSED; 865 hx509_set_error_string(context, 0, ret, 866 "Failed to get number of PKCS11 slots"); 867 goto out; 868 } 869 870 if (p->num_slots == 0) { 871 ret = HX509_PKCS11_NO_SLOT; 872 hx509_set_error_string(context, 0, ret, 873 "Selected PKCS11 module have no slots"); 874 goto out; 875 } 876 877 878 { 879 CK_SLOT_ID_PTR slot_ids; 880 int i, num_tokens = 0; 881 882 slot_ids = malloc(p->num_slots * sizeof(*slot_ids)); 883 if (slot_ids == NULL) { 884 hx509_clear_error_string(context); 885 ret = ENOMEM; 886 goto out; 887 } 888 889 ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots)); 890 if (ret) { 891 free(slot_ids); 892 hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED, 893 "Failed getting slot-list from " 894 "PKCS11 module"); 895 ret = HX509_PKCS11_TOKEN_CONFUSED; 896 goto out; 897 } 898 899 p->slot = calloc(p->num_slots, sizeof(p->slot[0])); 900 if (p->slot == NULL) { 901 free(slot_ids); 902 hx509_set_error_string(context, 0, ENOMEM, 903 "Failed to get memory for slot-list"); 904 ret = ENOMEM; 905 goto out; 906 } 907 908 for (i = 0; i < p->num_slots; i++) { 909 ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]); 910 if (ret) 911 break; 912 if (p->slot[i].flags & P11_TOKEN_PRESENT) 913 num_tokens++; 914 } 915 free(slot_ids); 916 if (ret) 917 goto out; 918 if (num_tokens == 0) { 919 ret = HX509_PKCS11_NO_TOKEN; 920 goto out; 921 } 922 } 923 924 *data = p; 925 926 return 0; 927 out: 928 p11_release_module(p); 929 return ret; 930 } 931 932 static void 933 p11_release_module(struct p11_module *p) 934 { 935 int i; 936 937 if (p->refcount == 0) 938 _hx509_abort("pkcs11 refcount to low"); 939 if (--p->refcount > 0) 940 return; 941 942 for (i = 0; i < p->num_slots; i++) { 943 if (p->slot[i].flags & P11_SESSION_IN_USE) 944 _hx509_abort("pkcs11 module release while session in use"); 945 if (p->slot[i].flags & P11_SESSION) { 946 int ret; 947 948 ret = P11FUNC(p, CloseSession, (p->slot[i].session)); 949 if (ret != CKR_OK) 950 ; 951 } 952 953 if (p->slot[i].name) 954 free(p->slot[i].name); 955 if (p->slot[i].pin) { 956 memset(p->slot[i].pin, 0, strlen(p->slot[i].pin)); 957 free(p->slot[i].pin); 958 } 959 if (p->slot[i].mechs.num) { 960 free(p->slot[i].mechs.list); 961 962 if (p->slot[i].mechs.infos) { 963 int j; 964 965 for (j = 0 ; j < p->slot[i].mechs.num ; j++) 966 free(p->slot[i].mechs.infos[j]); 967 free(p->slot[i].mechs.infos); 968 } 969 } 970 } 971 free(p->slot); 972 973 if (p->funcs) 974 P11FUNC(p, Finalize, (NULL)); 975 976 if (p->dl_handle) 977 dlclose(p->dl_handle); 978 979 memset(p, 0, sizeof(*p)); 980 free(p); 981 } 982 983 static int 984 p11_free(hx509_certs certs, void *data) 985 { 986 struct p11_module *p = data; 987 int i; 988 989 for (i = 0; i < p->num_slots; i++) { 990 if (p->slot[i].certs) 991 hx509_certs_free(&p->slot[i].certs); 992 } 993 p11_release_module(p); 994 return 0; 995 } 996 997 struct p11_cursor { 998 hx509_certs certs; 999 void *cursor; 1000 }; 1001 1002 static int 1003 p11_iter_start(hx509_context context, 1004 hx509_certs certs, void *data, void **cursor) 1005 { 1006 struct p11_module *p = data; 1007 struct p11_cursor *c; 1008 int ret, i; 1009 1010 c = malloc(sizeof(*c)); 1011 if (c == NULL) { 1012 hx509_clear_error_string(context); 1013 return ENOMEM; 1014 } 1015 ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs); 1016 if (ret) { 1017 free(c); 1018 return ret; 1019 } 1020 1021 for (i = 0 ; i < p->num_slots; i++) { 1022 if (p->slot[i].certs == NULL) 1023 continue; 1024 ret = hx509_certs_merge(context, c->certs, p->slot[i].certs); 1025 if (ret) { 1026 hx509_certs_free(&c->certs); 1027 free(c); 1028 return ret; 1029 } 1030 } 1031 1032 ret = hx509_certs_start_seq(context, c->certs, &c->cursor); 1033 if (ret) { 1034 hx509_certs_free(&c->certs); 1035 free(c); 1036 return 0; 1037 } 1038 *cursor = c; 1039 1040 return 0; 1041 } 1042 1043 static int 1044 p11_iter(hx509_context context, 1045 hx509_certs certs, void *data, void *cursor, hx509_cert *cert) 1046 { 1047 struct p11_cursor *c = cursor; 1048 return hx509_certs_next_cert(context, c->certs, c->cursor, cert); 1049 } 1050 1051 static int 1052 p11_iter_end(hx509_context context, 1053 hx509_certs certs, void *data, void *cursor) 1054 { 1055 struct p11_cursor *c = cursor; 1056 int ret; 1057 ret = hx509_certs_end_seq(context, c->certs, c->cursor); 1058 hx509_certs_free(&c->certs); 1059 free(c); 1060 return ret; 1061 } 1062 1063 #define MECHFLAG(x) { "unknown-flag-" #x, x } 1064 static struct units mechflags[] = { 1065 MECHFLAG(0x80000000), 1066 MECHFLAG(0x40000000), 1067 MECHFLAG(0x20000000), 1068 MECHFLAG(0x10000000), 1069 MECHFLAG(0x08000000), 1070 MECHFLAG(0x04000000), 1071 {"ec-compress", 0x2000000 }, 1072 {"ec-uncompress", 0x1000000 }, 1073 {"ec-namedcurve", 0x0800000 }, 1074 {"ec-ecparameters", 0x0400000 }, 1075 {"ec-f-2m", 0x0200000 }, 1076 {"ec-f-p", 0x0100000 }, 1077 {"derive", 0x0080000 }, 1078 {"unwrap", 0x0040000 }, 1079 {"wrap", 0x0020000 }, 1080 {"genereate-key-pair", 0x0010000 }, 1081 {"generate", 0x0008000 }, 1082 {"verify-recover", 0x0004000 }, 1083 {"verify", 0x0002000 }, 1084 {"sign-recover", 0x0001000 }, 1085 {"sign", 0x0000800 }, 1086 {"digest", 0x0000400 }, 1087 {"decrypt", 0x0000200 }, 1088 {"encrypt", 0x0000100 }, 1089 MECHFLAG(0x00080), 1090 MECHFLAG(0x00040), 1091 MECHFLAG(0x00020), 1092 MECHFLAG(0x00010), 1093 MECHFLAG(0x00008), 1094 MECHFLAG(0x00004), 1095 MECHFLAG(0x00002), 1096 {"hw", 0x0000001 }, 1097 { NULL, 0x0000000 } 1098 }; 1099 #undef MECHFLAG 1100 1101 static int 1102 p11_printinfo(hx509_context context, 1103 hx509_certs certs, 1104 void *data, 1105 int (*func)(void *, const char *), 1106 void *ctx) 1107 { 1108 struct p11_module *p = data; 1109 int i, j; 1110 1111 _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s", 1112 p->num_slots, p->num_slots > 1 ? "s" : ""); 1113 1114 for (i = 0; i < p->num_slots; i++) { 1115 struct p11_slot *s = &p->slot[i]; 1116 1117 _hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x", 1118 i, (int)s->id, s->name, s->flags); 1119 1120 _hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu", 1121 (unsigned long)s->mechs.num); 1122 for (j = 0; j < s->mechs.num; j++) { 1123 const char *mechname = "unknown"; 1124 char flags[256], unknownname[40]; 1125 #define MECHNAME(s,n) case s: mechname = n; break 1126 switch(s->mechs.list[j]) { 1127 MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen"); 1128 MECHNAME(CKM_RSA_PKCS, "rsa-pkcs"); 1129 MECHNAME(CKM_RSA_X_509, "rsa-x-509"); 1130 MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs"); 1131 MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs"); 1132 MECHNAME(CKM_SHA256_RSA_PKCS, "sha256-rsa-pkcs"); 1133 MECHNAME(CKM_SHA384_RSA_PKCS, "sha384-rsa-pkcs"); 1134 MECHNAME(CKM_SHA512_RSA_PKCS, "sha512-rsa-pkcs"); 1135 MECHNAME(CKM_RIPEMD160_RSA_PKCS, "ripemd160-rsa-pkcs"); 1136 MECHNAME(CKM_RSA_PKCS_OAEP, "rsa-pkcs-oaep"); 1137 MECHNAME(CKM_SHA512_HMAC, "sha512-hmac"); 1138 MECHNAME(CKM_SHA512, "sha512"); 1139 MECHNAME(CKM_SHA384_HMAC, "sha384-hmac"); 1140 MECHNAME(CKM_SHA384, "sha384"); 1141 MECHNAME(CKM_SHA256_HMAC, "sha256-hmac"); 1142 MECHNAME(CKM_SHA256, "sha256"); 1143 MECHNAME(CKM_SHA_1, "sha1"); 1144 MECHNAME(CKM_MD5, "md5"); 1145 MECHNAME(CKM_MD2, "md2"); 1146 MECHNAME(CKM_RIPEMD160, "ripemd-160"); 1147 MECHNAME(CKM_DES_ECB, "des-ecb"); 1148 MECHNAME(CKM_DES_CBC, "des-cbc"); 1149 MECHNAME(CKM_AES_ECB, "aes-ecb"); 1150 MECHNAME(CKM_AES_CBC, "aes-cbc"); 1151 MECHNAME(CKM_DH_PKCS_PARAMETER_GEN, "dh-pkcs-parameter-gen"); 1152 default: 1153 snprintf(unknownname, sizeof(unknownname), 1154 "unknown-mech-%lu", 1155 (unsigned long)s->mechs.list[j]); 1156 mechname = unknownname; 1157 break; 1158 } 1159 #undef MECHNAME 1160 unparse_flags(s->mechs.infos[j]->flags, mechflags, 1161 flags, sizeof(flags)); 1162 1163 _hx509_pi_printf(func, ctx, " %s: %s", mechname, flags); 1164 } 1165 } 1166 1167 return 0; 1168 } 1169 1170 static struct hx509_keyset_ops keyset_pkcs11 = { 1171 "PKCS11", 1172 0, 1173 p11_init, 1174 NULL, 1175 p11_free, 1176 NULL, 1177 NULL, 1178 p11_iter_start, 1179 p11_iter, 1180 p11_iter_end, 1181 p11_printinfo 1182 }; 1183 1184 #endif /* HAVE_DLOPEN */ 1185 1186 void 1187 _hx509_ks_pkcs11_register(hx509_context context) 1188 { 1189 #ifdef HAVE_DLOPEN 1190 _hx509_ks_register(context, &keyset_pkcs11); 1191 #endif 1192 } 1193