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