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 * 217 get_p11_rsa_pkcs1_method(void) 218 { 219 static const RSA_METHOD *p11_rsa_pkcs1_method; 220 RSA_METHOD *new_method; 221 222 if (p11_rsa_pkcs1_method != NULL) 223 return p11_rsa_pkcs1_method; 224 225 new_method = RSA_meth_new("hx509 PKCS11 PKCS#1 RSA", 0); 226 if (new_method == NULL) 227 return NULL; 228 229 if (RSA_meth_set_pub_enc(new_method, p11_rsa_public_encrypt) != 1) 230 goto out; 231 232 if (RSA_meth_set_pub_dec(new_method, p11_rsa_public_decrypt) != 1) 233 goto out; 234 235 if (RSA_meth_set_priv_enc(new_method, p11_rsa_private_encrypt) != 1) 236 goto out; 237 238 if (RSA_meth_set_priv_dec(new_method, p11_rsa_private_decrypt) != 1) 239 goto out; 240 241 if (RSA_meth_set_init(new_method, p11_rsa_init) != 1) 242 goto out; 243 244 if (RSA_meth_set_finish(new_method, p11_rsa_finish) != 1) 245 goto out; 246 247 /* 248 * This might overwrite a previously-created method if multiple 249 * threads invoke this concurrently which will leak memory. 250 */ 251 p11_rsa_pkcs1_method = new_method; 252 return p11_rsa_pkcs1_method; 253 out: 254 RSA_meth_free(new_method); 255 return NULL; 256 } 257 258 /* 259 * 260 */ 261 262 static int 263 p11_mech_info(hx509_context context, 264 struct p11_module *p, 265 struct p11_slot *slot, 266 int num) 267 { 268 CK_ULONG i; 269 int ret; 270 271 ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i)); 272 if (ret) { 273 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 274 "Failed to get mech list count for slot %d", 275 num); 276 return HX509_PKCS11_NO_MECH; 277 } 278 if (i == 0) { 279 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 280 "no mech supported for slot %d", num); 281 return HX509_PKCS11_NO_MECH; 282 } 283 slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0])); 284 if (slot->mechs.list == NULL) { 285 hx509_set_error_string(context, 0, ENOMEM, 286 "out of memory"); 287 return ENOMEM; 288 } 289 slot->mechs.num = i; 290 ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i)); 291 if (ret) { 292 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 293 "Failed to get mech list for slot %d", 294 num); 295 return HX509_PKCS11_NO_MECH; 296 } 297 assert(i == slot->mechs.num); 298 299 slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos)); 300 if (slot->mechs.list == NULL) { 301 hx509_set_error_string(context, 0, ENOMEM, 302 "out of memory"); 303 return ENOMEM; 304 } 305 306 for (i = 0; i < slot->mechs.num; i++) { 307 slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0]))); 308 if (slot->mechs.infos[i] == NULL) { 309 hx509_set_error_string(context, 0, ENOMEM, 310 "out of memory"); 311 return ENOMEM; 312 } 313 ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i], 314 slot->mechs.infos[i])); 315 if (ret) { 316 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, 317 "Failed to get mech info for slot %d", 318 num); 319 return HX509_PKCS11_NO_MECH; 320 } 321 } 322 323 return 0; 324 } 325 326 static int 327 p11_init_slot(hx509_context context, 328 struct p11_module *p, 329 hx509_lock lock, 330 CK_SLOT_ID id, 331 int num, 332 struct p11_slot *slot) 333 { 334 CK_SESSION_HANDLE session; 335 CK_SLOT_INFO slot_info; 336 CK_TOKEN_INFO token_info; 337 size_t i; 338 int ret; 339 340 slot->certs = NULL; 341 slot->id = id; 342 343 ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info)); 344 if (ret) { 345 hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED, 346 "Failed to init PKCS11 slot %d", 347 num); 348 return HX509_PKCS11_TOKEN_CONFUSED; 349 } 350 351 for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) { 352 char c = slot_info.slotDescription[i]; 353 if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0') 354 continue; 355 i++; 356 break; 357 } 358 359 asprintf(&slot->name, "%.*s", 360 (int)i, slot_info.slotDescription); 361 362 if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0) 363 return 0; 364 365 ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info)); 366 if (ret) { 367 hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN, 368 "Failed to init PKCS11 slot %d " 369 "with error 0x08x", 370 num, ret); 371 return HX509_PKCS11_NO_TOKEN; 372 } 373 slot->flags |= P11_TOKEN_PRESENT; 374 375 if (token_info.flags & CKF_LOGIN_REQUIRED) 376 slot->flags |= P11_LOGIN_REQ; 377 378 ret = p11_get_session(context, p, slot, lock, &session); 379 if (ret) 380 return ret; 381 382 ret = p11_mech_info(context, p, slot, num); 383 if (ret) 384 goto out; 385 386 ret = p11_list_keys(context, p, slot, session, lock, &slot->certs); 387 out: 388 p11_put_session(p, slot, session); 389 390 return ret; 391 } 392 393 static int 394 p11_get_session(hx509_context context, 395 struct p11_module *p, 396 struct p11_slot *slot, 397 hx509_lock lock, 398 CK_SESSION_HANDLE *psession) 399 { 400 CK_RV ret; 401 402 if (slot->flags & P11_SESSION_IN_USE) 403 _hx509_abort("slot already in session"); 404 405 if (slot->flags & P11_SESSION) { 406 slot->flags |= P11_SESSION_IN_USE; 407 *psession = slot->session; 408 return 0; 409 } 410 411 ret = P11FUNC(p, OpenSession, (slot->id, 412 CKF_SERIAL_SESSION, 413 NULL, 414 NULL, 415 &slot->session)); 416 if (ret != CKR_OK) { 417 if (context) 418 hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION, 419 "Failed to OpenSession for slot id %d " 420 "with error: 0x%08x", 421 (int)slot->id, ret); 422 return HX509_PKCS11_OPEN_SESSION; 423 } 424 425 slot->flags |= P11_SESSION; 426 427 /* 428 * If we have have to login, and haven't tried before and have a 429 * prompter or known to work pin code. 430 * 431 * This code is very conversative and only uses the prompter in 432 * the hx509_lock, the reason is that it's bad to try many 433 * passwords on a pkcs11 token, it might lock up and have to be 434 * unlocked by a administrator. 435 * 436 * XXX try harder to not use pin several times on the same card. 437 */ 438 439 if ( (slot->flags & P11_LOGIN_REQ) 440 && (slot->flags & P11_LOGIN_DONE) == 0 441 && (lock || slot->pin)) 442 { 443 hx509_prompt prompt; 444 char pin[20]; 445 char *str; 446 447 if (slot->pin == NULL) { 448 449 memset(&prompt, 0, sizeof(prompt)); 450 451 asprintf(&str, "PIN code for %s: ", slot->name); 452 prompt.prompt = str; 453 prompt.type = HX509_PROMPT_TYPE_PASSWORD; 454 prompt.reply.data = pin; 455 prompt.reply.length = sizeof(pin); 456 457 ret = hx509_lock_prompt(lock, &prompt); 458 if (ret) { 459 free(str); 460 if (context) 461 hx509_set_error_string(context, 0, ret, 462 "Failed to get pin code for slot " 463 "id %d with error: %d", 464 (int)slot->id, ret); 465 return ret; 466 } 467 free(str); 468 } else { 469 strlcpy(pin, slot->pin, sizeof(pin)); 470 } 471 472 ret = P11FUNC(p, Login, (slot->session, CKU_USER, 473 (unsigned char*)pin, strlen(pin))); 474 if (ret != CKR_OK) { 475 if (context) 476 hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN, 477 "Failed to login on slot id %d " 478 "with error: 0x%08x", 479 (int)slot->id, ret); 480 return HX509_PKCS11_LOGIN; 481 } else 482 slot->flags |= P11_LOGIN_DONE; 483 484 if (slot->pin == NULL) { 485 slot->pin = strdup(pin); 486 if (slot->pin == NULL) { 487 if (context) 488 hx509_set_error_string(context, 0, ENOMEM, 489 "out of memory"); 490 return ENOMEM; 491 } 492 } 493 } else 494 slot->flags |= P11_LOGIN_DONE; 495 496 slot->flags |= P11_SESSION_IN_USE; 497 498 *psession = slot->session; 499 500 return 0; 501 } 502 503 static int 504 p11_put_session(struct p11_module *p, 505 struct p11_slot *slot, 506 CK_SESSION_HANDLE session) 507 { 508 if ((slot->flags & P11_SESSION_IN_USE) == 0) 509 _hx509_abort("slot not in session"); 510 slot->flags &= ~P11_SESSION_IN_USE; 511 512 return 0; 513 } 514 515 static int 516 iterate_entries(hx509_context context, 517 struct p11_module *p, struct p11_slot *slot, 518 CK_SESSION_HANDLE session, 519 CK_ATTRIBUTE *search_data, int num_search_data, 520 CK_ATTRIBUTE *query, int num_query, 521 int (*func)(hx509_context, 522 struct p11_module *, struct p11_slot *, 523 CK_SESSION_HANDLE session, 524 CK_OBJECT_HANDLE object, 525 void *, CK_ATTRIBUTE *, int), void *ptr) 526 { 527 CK_OBJECT_HANDLE object; 528 CK_ULONG object_count; 529 int ret, ret2, i; 530 531 ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data)); 532 if (ret != CKR_OK) { 533 return -1; 534 } 535 while (1) { 536 ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count)); 537 if (ret != CKR_OK) { 538 return -1; 539 } 540 if (object_count == 0) 541 break; 542 543 for (i = 0; i < num_query; i++) 544 query[i].pValue = NULL; 545 546 ret = P11FUNC(p, GetAttributeValue, 547 (session, object, query, num_query)); 548 if (ret != CKR_OK) { 549 return -1; 550 } 551 for (i = 0; i < num_query; i++) { 552 query[i].pValue = malloc(query[i].ulValueLen); 553 if (query[i].pValue == NULL) { 554 ret = ENOMEM; 555 goto out; 556 } 557 } 558 ret = P11FUNC(p, GetAttributeValue, 559 (session, object, query, num_query)); 560 if (ret != CKR_OK) { 561 ret = -1; 562 goto out; 563 } 564 565 ret = (*func)(context, p, slot, session, object, ptr, query, num_query); 566 if (ret) 567 goto out; 568 569 for (i = 0; i < num_query; i++) { 570 if (query[i].pValue) 571 free(query[i].pValue); 572 query[i].pValue = NULL; 573 } 574 } 575 out: 576 577 for (i = 0; i < num_query; i++) { 578 if (query[i].pValue) 579 free(query[i].pValue); 580 query[i].pValue = NULL; 581 } 582 583 ret2 = P11FUNC(p, FindObjectsFinal, (session)); 584 if (ret2 != CKR_OK) { 585 return ret2; 586 } 587 588 return ret; 589 } 590 591 static BIGNUM * 592 getattr_bn(struct p11_module *p, 593 struct p11_slot *slot, 594 CK_SESSION_HANDLE session, 595 CK_OBJECT_HANDLE object, 596 unsigned int type) 597 { 598 CK_ATTRIBUTE query; 599 BIGNUM *bn; 600 int ret; 601 602 query.type = type; 603 query.pValue = NULL; 604 query.ulValueLen = 0; 605 606 ret = P11FUNC(p, GetAttributeValue, 607 (session, object, &query, 1)); 608 if (ret != CKR_OK) 609 return NULL; 610 611 query.pValue = malloc(query.ulValueLen); 612 613 ret = P11FUNC(p, GetAttributeValue, 614 (session, object, &query, 1)); 615 if (ret != CKR_OK) { 616 free(query.pValue); 617 return NULL; 618 } 619 bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL); 620 free(query.pValue); 621 622 return bn; 623 } 624 625 static int 626 collect_private_key(hx509_context context, 627 struct p11_module *p, struct p11_slot *slot, 628 CK_SESSION_HANDLE session, 629 CK_OBJECT_HANDLE object, 630 void *ptr, CK_ATTRIBUTE *query, int num_query) 631 { 632 struct hx509_collector *collector = ptr; 633 hx509_private_key key; 634 heim_octet_string localKeyId; 635 int ret; 636 const RSA_METHOD *meth; 637 BIGNUM *n, *e; 638 RSA *rsa; 639 struct p11_rsa *p11rsa; 640 641 localKeyId.data = query[0].pValue; 642 localKeyId.length = query[0].ulValueLen; 643 644 ret = hx509_private_key_init(&key, NULL, NULL); 645 if (ret) 646 return ret; 647 648 rsa = RSA_new(); 649 if (rsa == NULL) 650 _hx509_abort("out of memory"); 651 652 /* 653 * The exponent and modulus should always be present according to 654 * the pkcs11 specification, but some smartcards leaves it out, 655 * let ignore any failure to fetch it. 656 */ 657 n = getattr_bn(p, slot, session, object, CKA_MODULUS); 658 e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT); 659 if (RSA_set0_key(rsa, n, e, NULL) != 1) { 660 BN_free(n); 661 BN_free(e); 662 RSA_free(rsa); 663 hx509_private_key_free(&key); 664 return EINVAL; 665 } 666 667 p11rsa = calloc(1, sizeof(*p11rsa)); 668 if (p11rsa == NULL) 669 _hx509_abort("out of memory"); 670 671 p11rsa->p = p; 672 p11rsa->slot = slot; 673 p11rsa->private_key = object; 674 675 if (p->ref == 0) 676 _hx509_abort("pkcs11 ref == 0 on alloc"); 677 p->ref++; 678 if (p->ref == UINT_MAX) 679 _hx509_abort("pkcs11 ref == UINT_MAX on alloc"); 680 681 meth = get_p11_rsa_pkcs1_method(); 682 if (meth == NULL) 683 _hx509_abort("failed to create RSA method"); 684 RSA_set_method(rsa, meth); 685 ret = RSA_set_app_data(rsa, p11rsa); 686 if (ret != 1) 687 _hx509_abort("RSA_set_app_data"); 688 689 hx509_private_key_assign_rsa(key, rsa); 690 691 ret = _hx509_collector_private_key_add(context, 692 collector, 693 hx509_signature_rsa(), 694 key, 695 NULL, 696 &localKeyId); 697 698 if (ret) { 699 hx509_private_key_free(&key); 700 return ret; 701 } 702 return 0; 703 } 704 705 static void 706 p11_cert_release(hx509_cert cert, void *ctx) 707 { 708 struct p11_module *p = ctx; 709 p11_release_module(p); 710 } 711 712 713 static int 714 collect_cert(hx509_context context, 715 struct p11_module *p, struct p11_slot *slot, 716 CK_SESSION_HANDLE session, 717 CK_OBJECT_HANDLE object, 718 void *ptr, CK_ATTRIBUTE *query, int num_query) 719 { 720 struct hx509_collector *collector = ptr; 721 hx509_cert cert; 722 int ret; 723 724 if ((CK_LONG)query[0].ulValueLen == -1 || 725 (CK_LONG)query[1].ulValueLen == -1) 726 { 727 return 0; 728 } 729 730 ret = hx509_cert_init_data(context, query[1].pValue, 731 query[1].ulValueLen, &cert); 732 if (ret) 733 return ret; 734 735 if (p->ref == 0) 736 _hx509_abort("pkcs11 ref == 0 on alloc"); 737 p->ref++; 738 if (p->ref == UINT_MAX) 739 _hx509_abort("pkcs11 ref to high"); 740 741 _hx509_cert_set_release(cert, p11_cert_release, p); 742 743 { 744 heim_octet_string data; 745 746 data.data = query[0].pValue; 747 data.length = query[0].ulValueLen; 748 749 _hx509_set_cert_attribute(context, 750 cert, 751 &asn1_oid_id_pkcs_9_at_localKeyId, 752 &data); 753 } 754 755 if ((CK_LONG)query[2].ulValueLen != -1) { 756 char *str; 757 758 asprintf(&str, "%.*s", 759 (int)query[2].ulValueLen, (char *)query[2].pValue); 760 if (str) { 761 hx509_cert_set_friendly_name(cert, str); 762 free(str); 763 } 764 } 765 766 ret = _hx509_collector_certs_add(context, collector, cert); 767 hx509_cert_free(cert); 768 769 return ret; 770 } 771 772 773 static int 774 p11_list_keys(hx509_context context, 775 struct p11_module *p, 776 struct p11_slot *slot, 777 CK_SESSION_HANDLE session, 778 hx509_lock lock, 779 hx509_certs *certs) 780 { 781 struct hx509_collector *collector; 782 CK_OBJECT_CLASS key_class; 783 CK_ATTRIBUTE search_data[] = { 784 {CKA_CLASS, NULL, 0}, 785 }; 786 CK_ATTRIBUTE query_data[3] = { 787 {CKA_ID, NULL, 0}, 788 {CKA_VALUE, NULL, 0}, 789 {CKA_LABEL, NULL, 0} 790 }; 791 int ret; 792 793 search_data[0].pValue = &key_class; 794 search_data[0].ulValueLen = sizeof(key_class); 795 796 if (lock == NULL) 797 lock = _hx509_empty_lock; 798 799 ret = _hx509_collector_alloc(context, lock, &collector); 800 if (ret) 801 return ret; 802 803 key_class = CKO_PRIVATE_KEY; 804 ret = iterate_entries(context, p, slot, session, 805 search_data, 1, 806 query_data, 1, 807 collect_private_key, collector); 808 if (ret) 809 goto out; 810 811 key_class = CKO_CERTIFICATE; 812 ret = iterate_entries(context, p, slot, session, 813 search_data, 1, 814 query_data, 3, 815 collect_cert, collector); 816 if (ret) 817 goto out; 818 819 ret = _hx509_collector_collect_certs(context, collector, &slot->certs); 820 821 out: 822 _hx509_collector_free(collector); 823 824 return ret; 825 } 826 827 828 static int 829 p11_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 = calloc(1, sizeof(*p)); 845 if (p == NULL) { 846 free(list); 847 return ENOMEM; 848 } 849 850 p->ref = 1; 851 852 str = strchr(list, ','); 853 if (str) 854 *str++ = '\0'; 855 while (str) { 856 char *strnext; 857 strnext = strchr(str, ','); 858 if (strnext) 859 *strnext++ = '\0'; 860 #if 0 861 if (strncasecmp(str, "slot=", 5) == 0) 862 p->selected_slot = atoi(str + 5); 863 #endif 864 str = strnext; 865 } 866 867 p->dl_handle = dlopen(list, RTLD_NOW); 868 free(list); 869 if (p->dl_handle == NULL) { 870 ret = HX509_PKCS11_LOAD; 871 hx509_set_error_string(context, 0, ret, 872 "Failed to open %s: %s", list, dlerror()); 873 goto out; 874 } 875 876 getFuncs = (CK_C_GetFunctionList) dlsym(p->dl_handle, "C_GetFunctionList"); 877 if (getFuncs == NULL) { 878 ret = HX509_PKCS11_LOAD; 879 hx509_set_error_string(context, 0, ret, 880 "C_GetFunctionList missing in %s: %s", 881 list, dlerror()); 882 goto out; 883 } 884 885 ret = (*getFuncs)(&p->funcs); 886 if (ret) { 887 ret = HX509_PKCS11_LOAD; 888 hx509_set_error_string(context, 0, ret, 889 "C_GetFunctionList failed in %s", list); 890 goto out; 891 } 892 893 ret = P11FUNC(p, Initialize, (NULL_PTR)); 894 if (ret != CKR_OK) { 895 ret = HX509_PKCS11_TOKEN_CONFUSED; 896 hx509_set_error_string(context, 0, ret, 897 "Failed initialize the PKCS11 module"); 898 goto out; 899 } 900 901 ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots)); 902 if (ret) { 903 ret = HX509_PKCS11_TOKEN_CONFUSED; 904 hx509_set_error_string(context, 0, ret, 905 "Failed to get number of PKCS11 slots"); 906 goto out; 907 } 908 909 if (p->num_slots == 0) { 910 ret = HX509_PKCS11_NO_SLOT; 911 hx509_set_error_string(context, 0, ret, 912 "Selected PKCS11 module have no slots"); 913 goto out; 914 } 915 916 917 { 918 CK_SLOT_ID_PTR slot_ids; 919 int num_tokens = 0; 920 size_t i; 921 922 slot_ids = malloc(p->num_slots * sizeof(*slot_ids)); 923 if (slot_ids == NULL) { 924 hx509_clear_error_string(context); 925 ret = ENOMEM; 926 goto out; 927 } 928 929 ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots)); 930 if (ret) { 931 free(slot_ids); 932 hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED, 933 "Failed getting slot-list from " 934 "PKCS11 module"); 935 ret = HX509_PKCS11_TOKEN_CONFUSED; 936 goto out; 937 } 938 939 p->slot = calloc(p->num_slots, sizeof(p->slot[0])); 940 if (p->slot == NULL) { 941 free(slot_ids); 942 hx509_set_error_string(context, 0, ENOMEM, 943 "Failed to get memory for slot-list"); 944 ret = ENOMEM; 945 goto out; 946 } 947 948 for (i = 0; i < p->num_slots; i++) { 949 ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]); 950 if (ret) 951 break; 952 if (p->slot[i].flags & P11_TOKEN_PRESENT) 953 num_tokens++; 954 } 955 free(slot_ids); 956 if (ret) 957 goto out; 958 if (num_tokens == 0) { 959 ret = HX509_PKCS11_NO_TOKEN; 960 goto out; 961 } 962 } 963 964 *data = p; 965 966 return 0; 967 out: 968 p11_release_module(p); 969 return ret; 970 } 971 972 static void 973 p11_release_module(struct p11_module *p) 974 { 975 size_t i; 976 977 if (p->ref == 0) 978 _hx509_abort("pkcs11 ref to low"); 979 if (--p->ref > 0) 980 return; 981 982 for (i = 0; i < p->num_slots; i++) { 983 if (p->slot[i].flags & P11_SESSION_IN_USE) 984 _hx509_abort("pkcs11 module release while session in use"); 985 if (p->slot[i].flags & P11_SESSION) { 986 P11FUNC(p, CloseSession, (p->slot[i].session)); 987 } 988 989 if (p->slot[i].name) 990 free(p->slot[i].name); 991 if (p->slot[i].pin) { 992 memset(p->slot[i].pin, 0, strlen(p->slot[i].pin)); 993 free(p->slot[i].pin); 994 } 995 if (p->slot[i].mechs.num) { 996 free(p->slot[i].mechs.list); 997 998 if (p->slot[i].mechs.infos) { 999 size_t j; 1000 1001 for (j = 0 ; j < p->slot[i].mechs.num ; j++) 1002 free(p->slot[i].mechs.infos[j]); 1003 free(p->slot[i].mechs.infos); 1004 } 1005 } 1006 } 1007 free(p->slot); 1008 1009 if (p->funcs) 1010 P11FUNC(p, Finalize, (NULL)); 1011 1012 if (p->dl_handle) 1013 dlclose(p->dl_handle); 1014 1015 memset(p, 0, sizeof(*p)); 1016 free(p); 1017 } 1018 1019 static int 1020 p11_free(hx509_certs certs, void *data) 1021 { 1022 struct p11_module *p = data; 1023 size_t i; 1024 1025 for (i = 0; i < p->num_slots; i++) { 1026 if (p->slot[i].certs) 1027 hx509_certs_free(&p->slot[i].certs); 1028 } 1029 p11_release_module(p); 1030 return 0; 1031 } 1032 1033 struct p11_cursor { 1034 hx509_certs certs; 1035 void *cursor; 1036 }; 1037 1038 static int 1039 p11_iter_start(hx509_context context, 1040 hx509_certs certs, void *data, void **cursor) 1041 { 1042 struct p11_module *p = data; 1043 struct p11_cursor *c; 1044 int ret; 1045 size_t i; 1046 1047 c = malloc(sizeof(*c)); 1048 if (c == NULL) { 1049 hx509_clear_error_string(context); 1050 return ENOMEM; 1051 } 1052 ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs); 1053 if (ret) { 1054 free(c); 1055 return ret; 1056 } 1057 1058 for (i = 0 ; i < p->num_slots; i++) { 1059 if (p->slot[i].certs == NULL) 1060 continue; 1061 ret = hx509_certs_merge(context, c->certs, p->slot[i].certs); 1062 if (ret) { 1063 hx509_certs_free(&c->certs); 1064 free(c); 1065 return ret; 1066 } 1067 } 1068 1069 ret = hx509_certs_start_seq(context, c->certs, &c->cursor); 1070 if (ret) { 1071 hx509_certs_free(&c->certs); 1072 free(c); 1073 return 0; 1074 } 1075 *cursor = c; 1076 1077 return 0; 1078 } 1079 1080 static int 1081 p11_iter(hx509_context context, 1082 hx509_certs certs, void *data, void *cursor, hx509_cert *cert) 1083 { 1084 struct p11_cursor *c = cursor; 1085 return hx509_certs_next_cert(context, c->certs, c->cursor, cert); 1086 } 1087 1088 static int 1089 p11_iter_end(hx509_context context, 1090 hx509_certs certs, void *data, void *cursor) 1091 { 1092 struct p11_cursor *c = cursor; 1093 int ret; 1094 ret = hx509_certs_end_seq(context, c->certs, c->cursor); 1095 hx509_certs_free(&c->certs); 1096 free(c); 1097 return ret; 1098 } 1099 1100 #define MECHFLAG(x) { "unknown-flag-" #x, x } 1101 static struct units mechflags[] = { 1102 MECHFLAG(0x80000000), 1103 MECHFLAG(0x40000000), 1104 MECHFLAG(0x20000000), 1105 MECHFLAG(0x10000000), 1106 MECHFLAG(0x08000000), 1107 MECHFLAG(0x04000000), 1108 {"ec-compress", 0x2000000 }, 1109 {"ec-uncompress", 0x1000000 }, 1110 {"ec-namedcurve", 0x0800000 }, 1111 {"ec-ecparameters", 0x0400000 }, 1112 {"ec-f-2m", 0x0200000 }, 1113 {"ec-f-p", 0x0100000 }, 1114 {"derive", 0x0080000 }, 1115 {"unwrap", 0x0040000 }, 1116 {"wrap", 0x0020000 }, 1117 {"genereate-key-pair", 0x0010000 }, 1118 {"generate", 0x0008000 }, 1119 {"verify-recover", 0x0004000 }, 1120 {"verify", 0x0002000 }, 1121 {"sign-recover", 0x0001000 }, 1122 {"sign", 0x0000800 }, 1123 {"digest", 0x0000400 }, 1124 {"decrypt", 0x0000200 }, 1125 {"encrypt", 0x0000100 }, 1126 MECHFLAG(0x00080), 1127 MECHFLAG(0x00040), 1128 MECHFLAG(0x00020), 1129 MECHFLAG(0x00010), 1130 MECHFLAG(0x00008), 1131 MECHFLAG(0x00004), 1132 MECHFLAG(0x00002), 1133 {"hw", 0x0000001 }, 1134 { NULL, 0x0000000 } 1135 }; 1136 #undef MECHFLAG 1137 1138 static int 1139 p11_printinfo(hx509_context context, 1140 hx509_certs certs, 1141 void *data, 1142 int (*func)(void *, const char *), 1143 void *ctx) 1144 { 1145 struct p11_module *p = data; 1146 size_t i, j; 1147 1148 _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s", 1149 p->num_slots, p->num_slots > 1 ? "s" : ""); 1150 1151 for (i = 0; i < p->num_slots; i++) { 1152 struct p11_slot *s = &p->slot[i]; 1153 1154 _hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x", 1155 i, (int)s->id, s->name, s->flags); 1156 1157 _hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu", 1158 (unsigned long)s->mechs.num); 1159 for (j = 0; j < s->mechs.num; j++) { 1160 const char *mechname = "unknown"; 1161 char flags[256], unknownname[40]; 1162 #define MECHNAME(s,n) case s: mechname = n; break 1163 switch(s->mechs.list[j]) { 1164 MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen"); 1165 MECHNAME(CKM_RSA_PKCS, "rsa-pkcs"); 1166 MECHNAME(CKM_RSA_X_509, "rsa-x-509"); 1167 MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs"); 1168 MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs"); 1169 MECHNAME(CKM_SHA256_RSA_PKCS, "sha256-rsa-pkcs"); 1170 MECHNAME(CKM_SHA384_RSA_PKCS, "sha384-rsa-pkcs"); 1171 MECHNAME(CKM_SHA512_RSA_PKCS, "sha512-rsa-pkcs"); 1172 MECHNAME(CKM_RIPEMD160_RSA_PKCS, "ripemd160-rsa-pkcs"); 1173 MECHNAME(CKM_RSA_PKCS_OAEP, "rsa-pkcs-oaep"); 1174 MECHNAME(CKM_SHA512_HMAC, "sha512-hmac"); 1175 MECHNAME(CKM_SHA512, "sha512"); 1176 MECHNAME(CKM_SHA384_HMAC, "sha384-hmac"); 1177 MECHNAME(CKM_SHA384, "sha384"); 1178 MECHNAME(CKM_SHA256_HMAC, "sha256-hmac"); 1179 MECHNAME(CKM_SHA256, "sha256"); 1180 MECHNAME(CKM_SHA_1, "sha1"); 1181 MECHNAME(CKM_MD5, "md5"); 1182 MECHNAME(CKM_RIPEMD160, "ripemd-160"); 1183 MECHNAME(CKM_DES_ECB, "des-ecb"); 1184 MECHNAME(CKM_DES_CBC, "des-cbc"); 1185 MECHNAME(CKM_AES_ECB, "aes-ecb"); 1186 MECHNAME(CKM_AES_CBC, "aes-cbc"); 1187 MECHNAME(CKM_DH_PKCS_PARAMETER_GEN, "dh-pkcs-parameter-gen"); 1188 default: 1189 snprintf(unknownname, sizeof(unknownname), 1190 "unknown-mech-%lu", 1191 (unsigned long)s->mechs.list[j]); 1192 mechname = unknownname; 1193 break; 1194 } 1195 #undef MECHNAME 1196 unparse_flags(s->mechs.infos[j]->flags, mechflags, 1197 flags, sizeof(flags)); 1198 1199 _hx509_pi_printf(func, ctx, " %s: %s", mechname, flags); 1200 } 1201 } 1202 1203 return 0; 1204 } 1205 1206 static struct hx509_keyset_ops keyset_pkcs11 = { 1207 "PKCS11", 1208 0, 1209 p11_init, 1210 NULL, 1211 p11_free, 1212 NULL, 1213 NULL, 1214 p11_iter_start, 1215 p11_iter, 1216 p11_iter_end, 1217 p11_printinfo 1218 }; 1219 1220 #endif /* HAVE_DLOPEN */ 1221 1222 void 1223 _hx509_ks_pkcs11_register(hx509_context context) 1224 { 1225 #ifdef HAVE_DLOPEN 1226 _hx509_ks_register(context, &keyset_pkcs11); 1227 #endif 1228 } 1229