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