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