1/* $NetBSD: ks_p11.c,v 1.1.1.1 2011/04/13 18:15:11 elric Exp $ */ 2 3/* 4 * Copyright (c) 2004 - 2008 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include "hx_locl.h" 37#ifdef HAVE_DLFCN_H 38#include <dlfcn.h> 39#endif 40 41#ifdef HAVE_DLOPEN 42 43#include "pkcs11.h" 44 45struct p11_slot { 46 int flags; 47#define P11_SESSION 1 48#define P11_SESSION_IN_USE 2 49#define P11_LOGIN_REQ 4 50#define P11_LOGIN_DONE 8 51#define P11_TOKEN_PRESENT 16 52 CK_SESSION_HANDLE session; 53 CK_SLOT_ID id; 54 CK_BBOOL token; 55 char *name; 56 hx509_certs certs; 57 char *pin; 58 struct { 59 CK_MECHANISM_TYPE_PTR list; 60 CK_ULONG num; 61 CK_MECHANISM_INFO_PTR *infos; 62 } mechs; 63}; 64 65struct p11_module { 66 void *dl_handle; 67 CK_FUNCTION_LIST_PTR funcs; 68 CK_ULONG num_slots; 69 unsigned int ref; 70 struct p11_slot *slot; 71}; 72 73#define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args 74 75static int p11_get_session(hx509_context, 76 struct p11_module *, 77 struct p11_slot *, 78 hx509_lock, 79 CK_SESSION_HANDLE *); 80static int p11_put_session(struct p11_module *, 81 struct p11_slot *, 82 CK_SESSION_HANDLE); 83static void p11_release_module(struct p11_module *); 84 85static int p11_list_keys(hx509_context, 86 struct p11_module *, 87 struct p11_slot *, 88 CK_SESSION_HANDLE, 89 hx509_lock, 90 hx509_certs *); 91 92/* 93 * 94 */ 95 96struct p11_rsa { 97 struct p11_module *p; 98 struct p11_slot *slot; 99 CK_OBJECT_HANDLE private_key; 100 CK_OBJECT_HANDLE public_key; 101}; 102 103static int 104p11_rsa_public_encrypt(int flen, 105 const unsigned char *from, 106 unsigned char *to, 107 RSA *rsa, 108 int padding) 109{ 110 return -1; 111} 112 113static int 114p11_rsa_public_decrypt(int flen, 115 const unsigned char *from, 116 unsigned char *to, 117 RSA *rsa, 118 int padding) 119{ 120 return -1; 121} 122 123 124static int 125p11_rsa_private_encrypt(int flen, 126 const unsigned char *from, 127 unsigned char *to, 128 RSA *rsa, 129 int padding) 130{ 131 struct p11_rsa *p11rsa = RSA_get_app_data(rsa); 132 CK_OBJECT_HANDLE key = p11rsa->private_key; 133 CK_SESSION_HANDLE session; 134 CK_MECHANISM mechanism; 135 CK_ULONG ck_sigsize; 136 int ret; 137 138 if (padding != RSA_PKCS1_PADDING) 139 return -1; 140 141 memset(&mechanism, 0, sizeof(mechanism)); 142 mechanism.mechanism = CKM_RSA_PKCS; 143 144 ck_sigsize = RSA_size(rsa); 145 146 ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session); 147 if (ret) 148 return -1; 149 150 ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key)); 151 if (ret != CKR_OK) { 152 p11_put_session(p11rsa->p, p11rsa->slot, session); 153 return -1; 154 } 155 156 ret = P11FUNC(p11rsa->p, Sign, 157 (session, (CK_BYTE *)from, flen, to, &ck_sigsize)); 158 p11_put_session(p11rsa->p, p11rsa->slot, session); 159 if (ret != CKR_OK) 160 return -1; 161 162 return ck_sigsize; 163} 164 165static int 166p11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, 167 RSA * rsa, int padding) 168{ 169 struct p11_rsa *p11rsa = RSA_get_app_data(rsa); 170 CK_OBJECT_HANDLE key = p11rsa->private_key; 171 CK_SESSION_HANDLE session; 172 CK_MECHANISM mechanism; 173 CK_ULONG ck_sigsize; 174 int ret; 175 176 if (padding != RSA_PKCS1_PADDING) 177 return -1; 178 179 memset(&mechanism, 0, sizeof(mechanism)); 180 mechanism.mechanism = CKM_RSA_PKCS; 181 182 ck_sigsize = RSA_size(rsa); 183 184 ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session); 185 if (ret) 186 return -1; 187 188 ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key)); 189 if (ret != CKR_OK) { 190 p11_put_session(p11rsa->p, p11rsa->slot, session); 191 return -1; 192 } 193 194 ret = P11FUNC(p11rsa->p, Decrypt, 195 (session, (CK_BYTE *)from, flen, to, &ck_sigsize)); 196 p11_put_session(p11rsa->p, p11rsa->slot, session); 197 if (ret != CKR_OK) 198 return -1; 199 200 return ck_sigsize; 201} 202 203static int 204p11_rsa_init(RSA *rsa) 205{ 206 return 1; 207} 208 209static int 210p11_rsa_finish(RSA *rsa) 211{ 212 struct p11_rsa *p11rsa = RSA_get_app_data(rsa); 213 p11_release_module(p11rsa->p); 214 free(p11rsa); 215 return 1; 216} 217 218static const RSA_METHOD p11_rsa_pkcs1_method = { 219 "hx509 PKCS11 PKCS#1 RSA", 220 p11_rsa_public_encrypt, 221 p11_rsa_public_decrypt, 222 p11_rsa_private_encrypt, 223 p11_rsa_private_decrypt, 224 NULL, 225 NULL, 226 p11_rsa_init, 227 p11_rsa_finish, 228 0, 229 NULL, 230 NULL, 231 NULL 232}; 233 234/* 235 * 236 */ 237 238static int 239p11_mech_info(hx509_context context, 240 struct p11_module *p, 241 struct p11_slot *slot, 242 int num) 243{ 244 CK_ULONG i; 245 int ret; 246 247 ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i)); 248 if (ret) { 249 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 250 "Failed to get mech list count for slot %d", 251 num); 252 return HX509_PKCS11_NO_MECH; 253 } 254 if (i == 0) { 255 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 256 "no mech supported for slot %d", num); 257 return HX509_PKCS11_NO_MECH; 258 } 259 slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0])); 260 if (slot->mechs.list == NULL) { 261 hx509_set_error_string(context, 0, ENOMEM, 262 "out of memory"); 263 return ENOMEM; 264 } 265 slot->mechs.num = i; 266 ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i)); 267 if (ret) { 268 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 269 "Failed to get mech list for slot %d", 270 num); 271 return HX509_PKCS11_NO_MECH; 272 } 273 assert(i == slot->mechs.num); 274 275 slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos)); 276 if (slot->mechs.list == NULL) { 277 hx509_set_error_string(context, 0, ENOMEM, 278 "out of memory"); 279 return ENOMEM; 280 } 281 282 for (i = 0; i < slot->mechs.num; i++) { 283 slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0]))); 284 if (slot->mechs.infos[i] == NULL) { 285 hx509_set_error_string(context, 0, ENOMEM, 286 "out of memory"); 287 return ENOMEM; 288 } 289 ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i], 290 slot->mechs.infos[i])); 291 if (ret) { 292 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 293 "Failed to get mech info for slot %d", 294 num); 295 return HX509_PKCS11_NO_MECH; 296 } 297 } 298 299 return 0; 300} 301 302static int 303p11_init_slot(hx509_context context, 304 struct p11_module *p, 305 hx509_lock lock, 306 CK_SLOT_ID id, 307 int num, 308 struct p11_slot *slot) 309{ 310 CK_SESSION_HANDLE session; 311 CK_SLOT_INFO slot_info; 312 CK_TOKEN_INFO token_info; 313 size_t i; 314 int ret; 315 316 slot->certs = NULL; 317 slot->id = id; 318 319 ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info)); 320 if (ret) { 321 hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED, 322 "Failed to init PKCS11 slot %d", 323 num); 324 return HX509_PKCS11_TOKEN_CONFUSED; 325 } 326 327 for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) { 328 char c = slot_info.slotDescription[i]; 329 if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0') 330 continue; 331 i++; 332 break; 333 } 334 335 asprintf(&slot->name, "%.*s", 336 (int)i, slot_info.slotDescription); 337 338 if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0) 339 return 0; 340 341 ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info)); 342 if (ret) { 343 hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN, 344 "Failed to init PKCS11 slot %d " 345 "with error 0x08x", 346 num, ret); 347 return HX509_PKCS11_NO_TOKEN; 348 } 349 slot->flags |= P11_TOKEN_PRESENT; 350 351 if (token_info.flags & CKF_LOGIN_REQUIRED) 352 slot->flags |= P11_LOGIN_REQ; 353 354 ret = p11_get_session(context, p, slot, lock, &session); 355 if (ret) 356 return ret; 357 358 ret = p11_mech_info(context, p, slot, num); 359 if (ret) 360 goto out; 361 362 ret = p11_list_keys(context, p, slot, session, lock, &slot->certs); 363 out: 364 p11_put_session(p, slot, session); 365 366 return ret; 367} 368 369static int 370p11_get_session(hx509_context context, 371 struct p11_module *p, 372 struct p11_slot *slot, 373 hx509_lock lock, 374 CK_SESSION_HANDLE *psession) 375{ 376 CK_RV ret; 377 378 if (slot->flags & P11_SESSION_IN_USE) 379 _hx509_abort("slot already in session"); 380 381 if (slot->flags & P11_SESSION) { 382 slot->flags |= P11_SESSION_IN_USE; 383 *psession = slot->session; 384 return 0; 385 } 386 387 ret = P11FUNC(p, OpenSession, (slot->id, 388 CKF_SERIAL_SESSION, 389 NULL, 390 NULL, 391 &slot->session)); 392 if (ret != CKR_OK) { 393 if (context) 394 hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION, 395 "Failed to OpenSession for slot id %d " 396 "with error: 0x%08x", 397 (int)slot->id, ret); 398 return HX509_PKCS11_OPEN_SESSION; 399 } 400 401 slot->flags |= P11_SESSION; 402 403 /* 404 * If we have have to login, and haven't tried before and have a 405 * prompter or known to work pin code. 406 * 407 * This code is very conversative and only uses the prompter in 408 * the hx509_lock, the reason is that it's bad to try many 409 * passwords on a pkcs11 token, it might lock up and have to be 410 * unlocked by a administrator. 411 * 412 * XXX try harder to not use pin several times on the same card. 413 */ 414 415 if ( (slot->flags & P11_LOGIN_REQ) 416 && (slot->flags & P11_LOGIN_DONE) == 0 417 && (lock || slot->pin)) 418 { 419 hx509_prompt prompt; 420 char pin[20]; 421 char *str; 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 return HX509_PKCS11_LOGIN; 457 } else 458 slot->flags |= P11_LOGIN_DONE; 459 460 if (slot->pin == NULL) { 461 slot->pin = strdup(pin); 462 if (slot->pin == NULL) { 463 if (context) 464 hx509_set_error_string(context, 0, ENOMEM, 465 "out of memory"); 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 479static int 480p11_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 491static int 492iterate_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, ret2, 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 ret2 = P11FUNC(p, FindObjectsFinal, (session)); 560 if (ret2 != CKR_OK) { 561 return ret2; 562 } 563 564 return ret; 565} 566 567static BIGNUM * 568getattr_bn(struct p11_module *p, 569 struct p11_slot *slot, 570 CK_SESSION_HANDLE session, 571 CK_OBJECT_HANDLE object, 572 unsigned int type) 573{ 574 CK_ATTRIBUTE query; 575 BIGNUM *bn; 576 int ret; 577 578 query.type = type; 579 query.pValue = NULL; 580 query.ulValueLen = 0; 581 582 ret = P11FUNC(p, GetAttributeValue, 583 (session, object, &query, 1)); 584 if (ret != CKR_OK) 585 return NULL; 586 587 query.pValue = malloc(query.ulValueLen); 588 589 ret = P11FUNC(p, GetAttributeValue, 590 (session, object, &query, 1)); 591 if (ret != CKR_OK) { 592 free(query.pValue); 593 return NULL; 594 } 595 bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL); 596 free(query.pValue); 597 598 return bn; 599} 600 601static int 602collect_private_key(hx509_context context, 603 struct p11_module *p, struct p11_slot *slot, 604 CK_SESSION_HANDLE session, 605 CK_OBJECT_HANDLE object, 606 void *ptr, CK_ATTRIBUTE *query, int num_query) 607{ 608 struct hx509_collector *collector = ptr; 609 hx509_private_key key; 610 heim_octet_string localKeyId; 611 int ret; 612 RSA *rsa; 613 struct p11_rsa *p11rsa; 614 615 localKeyId.data = query[0].pValue; 616 localKeyId.length = query[0].ulValueLen; 617 618 ret = hx509_private_key_init(&key, NULL, NULL); 619 if (ret) 620 return ret; 621 622 rsa = RSA_new(); 623 if (rsa == NULL) 624 _hx509_abort("out of memory"); 625 626 /* 627 * The exponent and modulus should always be present according to 628 * the pkcs11 specification, but some smartcards leaves it out, 629 * let ignore any failure to fetch it. 630 */ 631 rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS); 632 rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT); 633 634 p11rsa = calloc(1, sizeof(*p11rsa)); 635 if (p11rsa == NULL) 636 _hx509_abort("out of memory"); 637 638 p11rsa->p = p; 639 p11rsa->slot = slot; 640 p11rsa->private_key = object; 641 642 if (p->ref == 0) 643 _hx509_abort("pkcs11 ref == 0 on alloc"); 644 p->ref++; 645 if (p->ref == UINT_MAX) 646 _hx509_abort("pkcs11 ref == UINT_MAX on alloc"); 647 648 RSA_set_method(rsa, &p11_rsa_pkcs1_method); 649 ret = RSA_set_app_data(rsa, p11rsa); 650 if (ret != 1) 651 _hx509_abort("RSA_set_app_data"); 652 653 hx509_private_key_assign_rsa(key, rsa); 654 655 ret = _hx509_collector_private_key_add(context, 656 collector, 657 hx509_signature_rsa(), 658 key, 659 NULL, 660 &localKeyId); 661 662 if (ret) { 663 hx509_private_key_free(&key); 664 return ret; 665 } 666 return 0; 667} 668 669static void 670p11_cert_release(hx509_cert cert, void *ctx) 671{ 672 struct p11_module *p = ctx; 673 p11_release_module(p); 674} 675 676 677static int 678collect_cert(hx509_context context, 679 struct p11_module *p, struct p11_slot *slot, 680 CK_SESSION_HANDLE session, 681 CK_OBJECT_HANDLE object, 682 void *ptr, CK_ATTRIBUTE *query, int num_query) 683{ 684 struct hx509_collector *collector = ptr; 685 hx509_cert cert; 686 int ret; 687 688 if ((CK_LONG)query[0].ulValueLen == -1 || 689 (CK_LONG)query[1].ulValueLen == -1) 690 { 691 return 0; 692 } 693 694 ret = hx509_cert_init_data(context, query[1].pValue, 695 query[1].ulValueLen, &cert); 696 if (ret) 697 return ret; 698 699 if (p->ref == 0) 700 _hx509_abort("pkcs11 ref == 0 on alloc"); 701 p->ref++; 702 if (p->ref == UINT_MAX) 703 _hx509_abort("pkcs11 ref to high"); 704 705 _hx509_cert_set_release(cert, p11_cert_release, p); 706 707 { 708 heim_octet_string data; 709 710 data.data = query[0].pValue; 711 data.length = query[0].ulValueLen; 712 713 _hx509_set_cert_attribute(context, 714 cert, 715 &asn1_oid_id_pkcs_9_at_localKeyId, 716 &data); 717 } 718 719 if ((CK_LONG)query[2].ulValueLen != -1) { 720 char *str; 721 722 asprintf(&str, "%.*s", 723 (int)query[2].ulValueLen, (char *)query[2].pValue); 724 if (str) { 725 hx509_cert_set_friendly_name(cert, str); 726 free(str); 727 } 728 } 729 730 ret = _hx509_collector_certs_add(context, collector, cert); 731 hx509_cert_free(cert); 732 733 return ret; 734} 735 736 737static int 738p11_list_keys(hx509_context context, 739 struct p11_module *p, 740 struct p11_slot *slot, 741 CK_SESSION_HANDLE session, 742 hx509_lock lock, 743 hx509_certs *certs) 744{ 745 struct hx509_collector *collector; 746 CK_OBJECT_CLASS key_class; 747 CK_ATTRIBUTE search_data[] = { 748 {CKA_CLASS, NULL, 0}, 749 }; 750 CK_ATTRIBUTE query_data[3] = { 751 {CKA_ID, NULL, 0}, 752 {CKA_VALUE, NULL, 0}, 753 {CKA_LABEL, NULL, 0} 754 }; 755 int ret; 756 757 search_data[0].pValue = &key_class; 758 search_data[0].ulValueLen = sizeof(key_class); 759 760 if (lock == NULL) 761 lock = _hx509_empty_lock; 762 763 ret = _hx509_collector_alloc(context, lock, &collector); 764 if (ret) 765 return ret; 766 767 key_class = CKO_PRIVATE_KEY; 768 ret = iterate_entries(context, p, slot, session, 769 search_data, 1, 770 query_data, 1, 771 collect_private_key, collector); 772 if (ret) 773 goto out; 774 775 key_class = CKO_CERTIFICATE; 776 ret = iterate_entries(context, p, slot, session, 777 search_data, 1, 778 query_data, 3, 779 collect_cert, collector); 780 if (ret) 781 goto out; 782 783 ret = _hx509_collector_collect_certs(context, collector, &slot->certs); 784 785out: 786 _hx509_collector_free(collector); 787 788 return ret; 789} 790 791 792static int 793p11_init(hx509_context context, 794 hx509_certs certs, void **data, int flags, 795 const char *residue, hx509_lock lock) 796{ 797 CK_C_GetFunctionList getFuncs; 798 struct p11_module *p; 799 char *list, *str; 800 int ret; 801 802 *data = NULL; 803 804 list = strdup(residue); 805 if (list == NULL) 806 return ENOMEM; 807 808 p = calloc(1, sizeof(*p)); 809 if (p == NULL) { 810 free(list); 811 return ENOMEM; 812 } 813 814 p->ref = 1; 815 816 str = strchr(list, ','); 817 if (str) 818 *str++ = '\0'; 819 while (str) { 820 char *strnext; 821 strnext = strchr(str, ','); 822 if (strnext) 823 *strnext++ = '\0'; 824#if 0 825 if (strncasecmp(str, "slot=", 5) == 0) 826 p->selected_slot = atoi(str + 5); 827#endif 828 str = strnext; 829 } 830 831 p->dl_handle = dlopen(list, RTLD_NOW); 832 free(list); 833 if (p->dl_handle == NULL) { 834 ret = HX509_PKCS11_LOAD; 835 hx509_set_error_string(context, 0, ret, 836 "Failed to open %s: %s", list, dlerror()); 837 goto out; 838 } 839 840 getFuncs = (CK_C_GetFunctionList) dlsym(p->dl_handle, "C_GetFunctionList"); 841 if (getFuncs == NULL) { 842 ret = HX509_PKCS11_LOAD; 843 hx509_set_error_string(context, 0, ret, 844 "C_GetFunctionList missing in %s: %s", 845 list, dlerror()); 846 goto out; 847 } 848 849 ret = (*getFuncs)(&p->funcs); 850 if (ret) { 851 ret = HX509_PKCS11_LOAD; 852 hx509_set_error_string(context, 0, ret, 853 "C_GetFunctionList failed in %s", list); 854 goto out; 855 } 856 857 ret = P11FUNC(p, Initialize, (NULL_PTR)); 858 if (ret != CKR_OK) { 859 ret = HX509_PKCS11_TOKEN_CONFUSED; 860 hx509_set_error_string(context, 0, ret, 861 "Failed initialize the PKCS11 module"); 862 goto out; 863 } 864 865 ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots)); 866 if (ret) { 867 ret = HX509_PKCS11_TOKEN_CONFUSED; 868 hx509_set_error_string(context, 0, ret, 869 "Failed to get number of PKCS11 slots"); 870 goto out; 871 } 872 873 if (p->num_slots == 0) { 874 ret = HX509_PKCS11_NO_SLOT; 875 hx509_set_error_string(context, 0, ret, 876 "Selected PKCS11 module have no slots"); 877 goto out; 878 } 879 880 881 { 882 CK_SLOT_ID_PTR slot_ids; 883 int i, num_tokens = 0; 884 885 slot_ids = malloc(p->num_slots * sizeof(*slot_ids)); 886 if (slot_ids == NULL) { 887 hx509_clear_error_string(context); 888 ret = ENOMEM; 889 goto out; 890 } 891 892 ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots)); 893 if (ret) { 894 free(slot_ids); 895 hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED, 896 "Failed getting slot-list from " 897 "PKCS11 module"); 898 ret = HX509_PKCS11_TOKEN_CONFUSED; 899 goto out; 900 } 901 902 p->slot = calloc(p->num_slots, sizeof(p->slot[0])); 903 if (p->slot == NULL) { 904 free(slot_ids); 905 hx509_set_error_string(context, 0, ENOMEM, 906 "Failed to get memory for slot-list"); 907 ret = ENOMEM; 908 goto out; 909 } 910 911 for (i = 0; i < p->num_slots; i++) { 912 ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]); 913 if (ret) 914 break; 915 if (p->slot[i].flags & P11_TOKEN_PRESENT) 916 num_tokens++; 917 } 918 free(slot_ids); 919 if (ret) 920 goto out; 921 if (num_tokens == 0) { 922 ret = HX509_PKCS11_NO_TOKEN; 923 goto out; 924 } 925 } 926 927 *data = p; 928 929 return 0; 930 out: 931 p11_release_module(p); 932 return ret; 933} 934 935static void 936p11_release_module(struct p11_module *p) 937{ 938 int i; 939 940 if (p->ref == 0) 941 _hx509_abort("pkcs11 ref to low"); 942 if (--p->ref > 0) 943 return; 944 945 for (i = 0; i < p->num_slots; i++) { 946 if (p->slot[i].flags & P11_SESSION_IN_USE) 947 _hx509_abort("pkcs11 module release while session in use"); 948 if (p->slot[i].flags & P11_SESSION) { 949 P11FUNC(p, CloseSession, (p->slot[i].session)); 950 } 951 952 if (p->slot[i].name) 953 free(p->slot[i].name); 954 if (p->slot[i].pin) { 955 memset(p->slot[i].pin, 0, strlen(p->slot[i].pin)); 956 free(p->slot[i].pin); 957 } 958 if (p->slot[i].mechs.num) { 959 free(p->slot[i].mechs.list); 960 961 if (p->slot[i].mechs.infos) { 962 int j; 963 964 for (j = 0 ; j < p->slot[i].mechs.num ; j++) 965 free(p->slot[i].mechs.infos[j]); 966 free(p->slot[i].mechs.infos); 967 } 968 } 969 } 970 free(p->slot); 971 972 if (p->funcs) 973 P11FUNC(p, Finalize, (NULL)); 974 975 if (p->dl_handle) 976 dlclose(p->dl_handle); 977 978 memset(p, 0, sizeof(*p)); 979 free(p); 980} 981 982static int 983p11_free(hx509_certs certs, void *data) 984{ 985 struct p11_module *p = data; 986 int i; 987 988 for (i = 0; i < p->num_slots; i++) { 989 if (p->slot[i].certs) 990 hx509_certs_free(&p->slot[i].certs); 991 } 992 p11_release_module(p); 993 return 0; 994} 995 996struct p11_cursor { 997 hx509_certs certs; 998 void *cursor; 999}; 1000 1001static int 1002p11_iter_start(hx509_context context, 1003 hx509_certs certs, void *data, void **cursor) 1004{ 1005 struct p11_module *p = data; 1006 struct p11_cursor *c; 1007 int ret, 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 1042static int 1043p11_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 1050static int 1051p11_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 } 1063static 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 1100static int 1101p11_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 int 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 1168static 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 1184void 1185_hx509_ks_pkcs11_register(hx509_context context) 1186{ 1187#ifdef HAVE_DLOPEN 1188 _hx509_ks_register(context, &keyset_pkcs11); 1189#endif 1190} 1191