1/* $NetBSD: ssh-pkcs11.c,v 1.26 2023/10/25 20:19:57 christos Exp $ */ 2/* $OpenBSD: ssh-pkcs11.c,v 1.59 2023/07/27 22:26:49 djm Exp $ */ 3 4/* 5 * Copyright (c) 2010 Markus Friedl. All rights reserved. 6 * Copyright (c) 2014 Pedro Martelletto. All rights reserved. 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20#include "includes.h" 21__RCSID("$NetBSD: ssh-pkcs11.c,v 1.26 2023/10/25 20:19:57 christos Exp $"); 22 23#include <sys/types.h> 24#include <sys/queue.h> 25#include <sys/time.h> 26#include <stdarg.h> 27#include <stdio.h> 28 29#include <ctype.h> 30#include <string.h> 31#include <dlfcn.h> 32 33#include <openssl/ecdsa.h> 34#include <openssl/x509.h> 35#include <openssl/err.h> 36 37#define CRYPTOKI_COMPAT 38#include "pkcs11.h" 39 40#include "log.h" 41#include "misc.h" 42#include "sshkey.h" 43#include "ssh-pkcs11.h" 44#include "digest.h" 45#include "xmalloc.h" 46 47struct pkcs11_slotinfo { 48 CK_TOKEN_INFO token; 49 CK_SESSION_HANDLE session; 50 int logged_in; 51}; 52 53struct pkcs11_provider { 54 char *name; 55 void *handle; 56 CK_FUNCTION_LIST *function_list; 57 CK_INFO info; 58 CK_ULONG nslots; 59 CK_SLOT_ID *slotlist; 60 struct pkcs11_slotinfo *slotinfo; 61 int valid; 62 int refcount; 63 TAILQ_ENTRY(pkcs11_provider) next; 64}; 65 66TAILQ_HEAD(, pkcs11_provider) pkcs11_providers; 67 68struct pkcs11_key { 69 struct pkcs11_provider *provider; 70 CK_ULONG slotidx; 71 char *keyid; 72 int keyid_len; 73}; 74 75int pkcs11_interactive = 0; 76 77#ifdef HAVE_DLOPEN 78static void 79ossl_error(const char *msg) 80{ 81 unsigned long e; 82 83 error_f("%s", msg); 84 while ((e = ERR_get_error()) != 0) 85 error_f("libcrypto error: %s", ERR_error_string(e, NULL)); 86} 87#endif 88 89int 90pkcs11_init(int interactive) 91{ 92 pkcs11_interactive = interactive; 93 TAILQ_INIT(&pkcs11_providers); 94 return (0); 95} 96 97/* 98 * finalize a provider shared library, it's no longer usable. 99 * however, there might still be keys referencing this provider, 100 * so the actual freeing of memory is handled by pkcs11_provider_unref(). 101 * this is called when a provider gets unregistered. 102 */ 103static void 104pkcs11_provider_finalize(struct pkcs11_provider *p) 105{ 106 CK_RV rv; 107 CK_ULONG i; 108 109 debug_f("provider \"%s\" refcount %d valid %d", 110 p->name, p->refcount, p->valid); 111 if (!p->valid) 112 return; 113 for (i = 0; i < p->nslots; i++) { 114 if (p->slotinfo[i].session && 115 (rv = p->function_list->C_CloseSession( 116 p->slotinfo[i].session)) != CKR_OK) 117 error("C_CloseSession failed: %lu", rv); 118 } 119 if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK) 120 error("C_Finalize failed: %lu", rv); 121 p->valid = 0; 122 p->function_list = NULL; 123#ifdef HAVE_DLOPEN 124 dlclose(p->handle); 125#endif 126} 127 128/* 129 * remove a reference to the provider. 130 * called when a key gets destroyed or when the provider is unregistered. 131 */ 132static void 133pkcs11_provider_unref(struct pkcs11_provider *p) 134{ 135 debug_f("provider \"%s\" refcount %d", p->name, p->refcount); 136 if (--p->refcount <= 0) { 137 if (p->valid) 138 error_f("provider \"%s\" still valid", p->name); 139 free(p->name); 140 free(p->slotlist); 141 free(p->slotinfo); 142 free(p); 143 } 144} 145 146/* unregister all providers, keys might still point to the providers */ 147void 148pkcs11_terminate(void) 149{ 150 struct pkcs11_provider *p; 151 152 while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) { 153 TAILQ_REMOVE(&pkcs11_providers, p, next); 154 pkcs11_provider_finalize(p); 155 pkcs11_provider_unref(p); 156 } 157} 158 159/* lookup provider by name */ 160static struct pkcs11_provider * 161pkcs11_provider_lookup(char *provider_id) 162{ 163 struct pkcs11_provider *p; 164 165 TAILQ_FOREACH(p, &pkcs11_providers, next) { 166 debug("check provider \"%s\"", p->name); 167 if (!strcmp(provider_id, p->name)) 168 return (p); 169 } 170 return (NULL); 171} 172 173/* unregister provider by name */ 174int 175pkcs11_del_provider(char *provider_id) 176{ 177 struct pkcs11_provider *p; 178 179 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) { 180 TAILQ_REMOVE(&pkcs11_providers, p, next); 181 pkcs11_provider_finalize(p); 182 pkcs11_provider_unref(p); 183 return (0); 184 } 185 return (-1); 186} 187 188#ifdef HAVE_DLOPEN 189static RSA_METHOD *rsa_method; 190static int rsa_idx = 0; 191static EC_KEY_METHOD *ec_key_method; 192static int ec_key_idx = 0; 193 194/* release a wrapped object */ 195static void 196pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, 197 long argl, void *argp) 198{ 199 struct pkcs11_key *k11 = ptr; 200 201 debug_f("parent %p ptr %p idx %d", parent, ptr, idx); 202 if (k11 == NULL) 203 return; 204 if (k11->provider) 205 pkcs11_provider_unref(k11->provider); 206 free(k11->keyid); 207 free(k11); 208} 209 210/* find a single 'obj' for given attributes */ 211static int 212pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr, 213 CK_ULONG nattr, CK_OBJECT_HANDLE *obj) 214{ 215 CK_FUNCTION_LIST *f; 216 CK_SESSION_HANDLE session; 217 CK_ULONG nfound = 0; 218 CK_RV rv; 219 int ret = -1; 220 221 f = p->function_list; 222 session = p->slotinfo[slotidx].session; 223 if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) { 224 error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv); 225 return (-1); 226 } 227 if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK || 228 nfound != 1) { 229 debug("C_FindObjects failed (nfound %lu nattr %lu): %lu", 230 nfound, nattr, rv); 231 } else 232 ret = 0; 233 if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK) 234 error("C_FindObjectsFinal failed: %lu", rv); 235 return (ret); 236} 237 238static int 239pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si, 240 CK_USER_TYPE type) 241{ 242 char *pin = NULL, prompt[1024]; 243 CK_RV rv; 244 245 if (provider == NULL || si == NULL || !provider->valid) { 246 error("no pkcs11 (valid) provider found"); 247 return (-1); 248 } 249 250 if (!pkcs11_interactive) { 251 error("need pin entry%s", 252 (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ? 253 " on reader keypad" : ""); 254 return (-1); 255 } 256 if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) 257 verbose("Deferring PIN entry to reader keypad."); 258 else { 259 snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ", 260 si->token.label); 261 if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) { 262 debug_f("no pin specified"); 263 return (-1); /* bail out */ 264 } 265 } 266 rv = provider->function_list->C_Login(si->session, type, (u_char *)pin, 267 (pin != NULL) ? strlen(pin) : 0); 268 if (pin != NULL) 269 freezero(pin, strlen(pin)); 270 271 switch (rv) { 272 case CKR_OK: 273 case CKR_USER_ALREADY_LOGGED_IN: 274 /* success */ 275 break; 276 case CKR_PIN_LEN_RANGE: 277 error("PKCS#11 login failed: PIN length out of range"); 278 return -1; 279 case CKR_PIN_INCORRECT: 280 error("PKCS#11 login failed: PIN incorrect"); 281 return -1; 282 case CKR_PIN_LOCKED: 283 error("PKCS#11 login failed: PIN locked"); 284 return -1; 285 default: 286 error("PKCS#11 login failed: error %lu", rv); 287 return -1; 288 } 289 si->logged_in = 1; 290 return (0); 291} 292 293static int 294pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type) 295{ 296 if (k11 == NULL || k11->provider == NULL || !k11->provider->valid) { 297 error("no pkcs11 (valid) provider found"); 298 return (-1); 299 } 300 301 return pkcs11_login_slot(k11->provider, 302 &k11->provider->slotinfo[k11->slotidx], type); 303} 304 305 306static int 307pkcs11_check_obj_bool_attrib(struct pkcs11_key *k11, CK_OBJECT_HANDLE obj, 308 CK_ATTRIBUTE_TYPE type, int *val) 309{ 310 struct pkcs11_slotinfo *si; 311 CK_FUNCTION_LIST *f; 312 CK_BBOOL flag = 0; 313 CK_ATTRIBUTE attr; 314 CK_RV rv; 315 316 *val = 0; 317 318 if (!k11->provider || !k11->provider->valid) { 319 error("no pkcs11 (valid) provider found"); 320 return (-1); 321 } 322 323 f = k11->provider->function_list; 324 si = &k11->provider->slotinfo[k11->slotidx]; 325 326 attr.type = type; 327 attr.pValue = &flag; 328 attr.ulValueLen = sizeof(flag); 329 330 rv = f->C_GetAttributeValue(si->session, obj, &attr, 1); 331 if (rv != CKR_OK) { 332 error("C_GetAttributeValue failed: %lu", rv); 333 return (-1); 334 } 335 *val = flag != 0; 336 debug_f("provider \"%s\" slot %lu object %lu: attrib %lu = %d", 337 k11->provider->name, k11->slotidx, obj, type, *val); 338 return (0); 339} 340 341static int 342pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type) 343{ 344 struct pkcs11_slotinfo *si; 345 CK_FUNCTION_LIST *f; 346 CK_OBJECT_HANDLE obj; 347 CK_RV rv; 348 CK_OBJECT_CLASS private_key_class; 349 CK_BBOOL true_val; 350 CK_MECHANISM mech; 351 CK_ATTRIBUTE key_filter[3]; 352 int always_auth = 0; 353 int did_login = 0; 354 355 if (!k11->provider || !k11->provider->valid) { 356 error("no pkcs11 (valid) provider found"); 357 return (-1); 358 } 359 360 f = k11->provider->function_list; 361 si = &k11->provider->slotinfo[k11->slotidx]; 362 363 if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { 364 if (pkcs11_login(k11, CKU_USER) < 0) { 365 error("login failed"); 366 return (-1); 367 } 368 did_login = 1; 369 } 370 371 memset(&key_filter, 0, sizeof(key_filter)); 372 private_key_class = CKO_PRIVATE_KEY; 373 key_filter[0].type = CKA_CLASS; 374 key_filter[0].pValue = &private_key_class; 375 key_filter[0].ulValueLen = sizeof(private_key_class); 376 377 key_filter[1].type = CKA_ID; 378 key_filter[1].pValue = k11->keyid; 379 key_filter[1].ulValueLen = k11->keyid_len; 380 381 true_val = CK_TRUE; 382 key_filter[2].type = CKA_SIGN; 383 key_filter[2].pValue = &true_val; 384 key_filter[2].ulValueLen = sizeof(true_val); 385 386 /* try to find object w/CKA_SIGN first, retry w/o */ 387 if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 && 388 pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) { 389 error("cannot find private key"); 390 return (-1); 391 } 392 393 memset(&mech, 0, sizeof(mech)); 394 mech.mechanism = mech_type; 395 mech.pParameter = NULL_PTR; 396 mech.ulParameterLen = 0; 397 398 if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) { 399 error("C_SignInit failed: %lu", rv); 400 return (-1); 401 } 402 403 pkcs11_check_obj_bool_attrib(k11, obj, CKA_ALWAYS_AUTHENTICATE, 404 &always_auth); /* ignore errors here */ 405 if (always_auth && !did_login) { 406 debug_f("always-auth key"); 407 if (pkcs11_login(k11, CKU_CONTEXT_SPECIFIC) < 0) { 408 error("login failed for always-auth key"); 409 return (-1); 410 } 411 } 412 413 return (0); 414} 415 416/* openssl callback doing the actual signing operation */ 417static int 418pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, 419 int padding) 420{ 421 struct pkcs11_key *k11; 422 struct pkcs11_slotinfo *si; 423 CK_FUNCTION_LIST *f; 424 CK_ULONG tlen = 0; 425 CK_RV rv; 426 int rval = -1; 427 428 if ((k11 = RSA_get_ex_data(rsa, rsa_idx)) == NULL) { 429 error("RSA_get_ex_data failed"); 430 return (-1); 431 } 432 433 if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) { 434 error("pkcs11_get_key failed"); 435 return (-1); 436 } 437 438 f = k11->provider->function_list; 439 si = &k11->provider->slotinfo[k11->slotidx]; 440 tlen = RSA_size(rsa); 441 442 /* XXX handle CKR_BUFFER_TOO_SMALL */ 443 rv = f->C_Sign(si->session, __UNCONST(from), flen, to, &tlen); 444 if (rv == CKR_OK) 445 rval = tlen; 446 else 447 error("C_Sign failed: %lu", rv); 448 449 return (rval); 450} 451 452static int 453pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa, 454 int padding) 455{ 456 return (-1); 457} 458 459static int 460pkcs11_rsa_start_wrapper(void) 461{ 462 if (rsa_method != NULL) 463 return (0); 464 rsa_method = RSA_meth_dup(RSA_get_default_method()); 465 if (rsa_method == NULL) 466 return (-1); 467 rsa_idx = RSA_get_ex_new_index(0, __UNCONST("ssh-pkcs11-rsa"), 468 NULL, NULL, pkcs11_k11_free); 469 if (rsa_idx == -1) 470 return (-1); 471 if (!RSA_meth_set1_name(rsa_method, "pkcs11") || 472 !RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt) || 473 !RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt)) { 474 error_f("setup pkcs11 method failed"); 475 return (-1); 476 } 477 return (0); 478} 479 480/* redirect private key operations for rsa key to pkcs11 token */ 481static int 482pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, 483 CK_ATTRIBUTE *keyid_attrib, RSA *rsa) 484{ 485 struct pkcs11_key *k11; 486 487 if (pkcs11_rsa_start_wrapper() == -1) 488 return (-1); 489 490 k11 = xcalloc(1, sizeof(*k11)); 491 k11->provider = provider; 492 provider->refcount++; /* provider referenced by RSA key */ 493 k11->slotidx = slotidx; 494 /* identify key object on smartcard */ 495 k11->keyid_len = keyid_attrib->ulValueLen; 496 if (k11->keyid_len > 0) { 497 k11->keyid = xmalloc(k11->keyid_len); 498 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); 499 } 500 501 RSA_set_method(rsa, rsa_method); 502 RSA_set_ex_data(rsa, rsa_idx, k11); 503 return (0); 504} 505 506/* openssl callback doing the actual signing operation */ 507static ECDSA_SIG * 508ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, 509 const BIGNUM *rp, EC_KEY *ec) 510{ 511 struct pkcs11_key *k11; 512 struct pkcs11_slotinfo *si; 513 CK_FUNCTION_LIST *f; 514 CK_ULONG siglen = 0, bnlen; 515 CK_RV rv; 516 ECDSA_SIG *ret = NULL; 517 u_char *sig; 518 BIGNUM *r = NULL, *s = NULL; 519 520 if ((k11 = EC_KEY_get_ex_data(ec, ec_key_idx)) == NULL) { 521 ossl_error("EC_KEY_get_ex_data failed for ec"); 522 return (NULL); 523 } 524 525 if (pkcs11_get_key(k11, CKM_ECDSA) == -1) { 526 error("pkcs11_get_key failed"); 527 return (NULL); 528 } 529 530 f = k11->provider->function_list; 531 si = &k11->provider->slotinfo[k11->slotidx]; 532 533 siglen = ECDSA_size(ec); 534 sig = xmalloc(siglen); 535 536 /* XXX handle CKR_BUFFER_TOO_SMALL */ 537 rv = f->C_Sign(si->session, __UNCONST(dgst), dgst_len, sig, &siglen); 538 if (rv != CKR_OK) { 539 error("C_Sign failed: %lu", rv); 540 goto done; 541 } 542 if (siglen < 64 || siglen > 132 || siglen % 2) { 543 error_f("bad signature length: %lu", (u_long)siglen); 544 goto done; 545 } 546 bnlen = siglen/2; 547 if ((ret = ECDSA_SIG_new()) == NULL) { 548 error("ECDSA_SIG_new failed"); 549 goto done; 550 } 551 if ((r = BN_bin2bn(sig, bnlen, NULL)) == NULL || 552 (s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) { 553 ossl_error("BN_bin2bn failed"); 554 ECDSA_SIG_free(ret); 555 ret = NULL; 556 goto done; 557 } 558 if (!ECDSA_SIG_set0(ret, r, s)) { 559 error_f("ECDSA_SIG_set0 failed"); 560 ECDSA_SIG_free(ret); 561 ret = NULL; 562 goto done; 563 } 564 r = s = NULL; /* now owned by ret */ 565 /* success */ 566 done: 567 BN_free(r); 568 BN_free(s); 569 free(sig); 570 571 return (ret); 572} 573 574static int 575pkcs11_ecdsa_start_wrapper(void) 576{ 577 int (*orig_sign)(int, const unsigned char *, int, unsigned char *, 578 unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL; 579 580 if (ec_key_method != NULL) 581 return (0); 582 ec_key_idx = EC_KEY_get_ex_new_index(0, __UNCONST("ssh-pkcs11-ecdsa"), 583 NULL, NULL, pkcs11_k11_free); 584 if (ec_key_idx == -1) 585 return (-1); 586 ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL()); 587 if (ec_key_method == NULL) 588 return (-1); 589 EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL); 590 EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign); 591 return (0); 592} 593 594static int 595pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, 596 CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec) 597{ 598 struct pkcs11_key *k11; 599 600 if (pkcs11_ecdsa_start_wrapper() == -1) 601 return (-1); 602 603 k11 = xcalloc(1, sizeof(*k11)); 604 k11->provider = provider; 605 provider->refcount++; /* provider referenced by ECDSA key */ 606 k11->slotidx = slotidx; 607 /* identify key object on smartcard */ 608 k11->keyid_len = keyid_attrib->ulValueLen; 609 if (k11->keyid_len > 0) { 610 k11->keyid = xmalloc(k11->keyid_len); 611 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); 612 } 613 EC_KEY_set_method(ec, ec_key_method); 614 EC_KEY_set_ex_data(ec, ec_key_idx, k11); 615 616 return (0); 617} 618 619/* remove trailing spaces */ 620static char * 621rmspace(u_char *buf, size_t len) 622{ 623 size_t i; 624 625 if (len == 0) 626 return buf; 627 for (i = len - 1; i > 0; i--) 628 if (buf[i] == ' ') 629 buf[i] = '\0'; 630 else 631 break; 632 return buf; 633} 634/* Used to printf fixed-width, space-padded, unterminated strings using %.*s */ 635#define RMSPACE(s) (int)sizeof(s), rmspace(s, sizeof(s)) 636 637/* 638 * open a pkcs11 session and login if required. 639 * if pin == NULL we delay login until key use 640 */ 641static int 642pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin, 643 CK_ULONG user) 644{ 645 struct pkcs11_slotinfo *si; 646 CK_FUNCTION_LIST *f; 647 CK_RV rv; 648 CK_SESSION_HANDLE session; 649 int login_required, ret; 650 651 f = p->function_list; 652 si = &p->slotinfo[slotidx]; 653 654 login_required = si->token.flags & CKF_LOGIN_REQUIRED; 655 656 /* fail early before opening session */ 657 if (login_required && !pkcs11_interactive && 658 (pin == NULL || strlen(pin) == 0)) { 659 error("pin required"); 660 return (-SSH_PKCS11_ERR_PIN_REQUIRED); 661 } 662 if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION| 663 CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) { 664 error("C_OpenSession failed: %lu", rv); 665 return (-1); 666 } 667 if (login_required && pin != NULL && strlen(pin) != 0) { 668 rv = f->C_Login(session, user, (u_char *)pin, strlen(pin)); 669 if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) { 670 error("C_Login failed: %lu", rv); 671 ret = (rv == CKR_PIN_LOCKED) ? 672 -SSH_PKCS11_ERR_PIN_LOCKED : 673 -SSH_PKCS11_ERR_LOGIN_FAIL; 674 if ((rv = f->C_CloseSession(session)) != CKR_OK) 675 error("C_CloseSession failed: %lu", rv); 676 return (ret); 677 } 678 si->logged_in = 1; 679 } 680 si->session = session; 681 return (0); 682} 683 684static int 685pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key) 686{ 687 int i; 688 689 for (i = 0; i < *nkeys; i++) 690 if (sshkey_equal(key, (*keysp)[i])) 691 return (1); 692 return (0); 693} 694 695static struct sshkey * 696pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, 697 CK_OBJECT_HANDLE *obj) 698{ 699 CK_ATTRIBUTE key_attr[3]; 700 CK_SESSION_HANDLE session; 701 CK_FUNCTION_LIST *f = NULL; 702 CK_RV rv; 703 ASN1_OCTET_STRING *octet = NULL; 704 EC_KEY *ec = NULL; 705 EC_GROUP *group = NULL; 706 struct sshkey *key = NULL; 707 const unsigned char *attrp = NULL; 708 int i; 709 int nid; 710 711 memset(&key_attr, 0, sizeof(key_attr)); 712 key_attr[0].type = CKA_ID; 713 key_attr[1].type = CKA_EC_POINT; 714 key_attr[2].type = CKA_EC_PARAMS; 715 716 session = p->slotinfo[slotidx].session; 717 f = p->function_list; 718 719 /* figure out size of the attributes */ 720 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); 721 if (rv != CKR_OK) { 722 error("C_GetAttributeValue failed: %lu", rv); 723 return (NULL); 724 } 725 726 /* 727 * Allow CKA_ID (always first attribute) to be empty, but 728 * ensure that none of the others are zero length. 729 * XXX assumes CKA_ID is always first. 730 */ 731 if (key_attr[1].ulValueLen == 0 || 732 key_attr[2].ulValueLen == 0) { 733 error("invalid attribute length"); 734 return (NULL); 735 } 736 737 /* allocate buffers for attributes */ 738 for (i = 0; i < 3; i++) 739 if (key_attr[i].ulValueLen > 0) 740 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen); 741 742 /* retrieve ID, public point and curve parameters of EC key */ 743 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); 744 if (rv != CKR_OK) { 745 error("C_GetAttributeValue failed: %lu", rv); 746 goto fail; 747 } 748 749 ec = EC_KEY_new(); 750 if (ec == NULL) { 751 error("EC_KEY_new failed"); 752 goto fail; 753 } 754 755 attrp = key_attr[2].pValue; 756 group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen); 757 if (group == NULL) { 758 ossl_error("d2i_ECPKParameters failed"); 759 goto fail; 760 } 761 762 if (EC_KEY_set_group(ec, group) == 0) { 763 ossl_error("EC_KEY_set_group failed"); 764 goto fail; 765 } 766 767 if (key_attr[1].ulValueLen <= 2) { 768 error("CKA_EC_POINT too small"); 769 goto fail; 770 } 771 772 attrp = key_attr[1].pValue; 773 octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen); 774 if (octet == NULL) { 775 ossl_error("d2i_ASN1_OCTET_STRING failed"); 776 goto fail; 777 } 778 attrp = octet->data; 779 if (o2i_ECPublicKey(&ec, &attrp, octet->length) == NULL) { 780 ossl_error("o2i_ECPublicKey failed"); 781 goto fail; 782 } 783 784 nid = sshkey_ecdsa_key_to_nid(ec); 785 if (nid < 0) { 786 error("couldn't get curve nid"); 787 goto fail; 788 } 789 790 if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec)) 791 goto fail; 792 793 key = sshkey_new(KEY_UNSPEC); 794 if (key == NULL) { 795 error("sshkey_new failed"); 796 goto fail; 797 } 798 799 key->ecdsa = ec; 800 key->ecdsa_nid = nid; 801 key->type = KEY_ECDSA; 802 key->flags |= SSHKEY_FLAG_EXT; 803 ec = NULL; /* now owned by key */ 804 805fail: 806 for (i = 0; i < 3; i++) 807 free(key_attr[i].pValue); 808 if (ec) 809 EC_KEY_free(ec); 810 if (group) 811 EC_GROUP_free(group); 812 if (octet) 813 ASN1_OCTET_STRING_free(octet); 814 815 return (key); 816} 817 818static struct sshkey * 819pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, 820 CK_OBJECT_HANDLE *obj) 821{ 822 CK_ATTRIBUTE key_attr[3]; 823 CK_SESSION_HANDLE session; 824 CK_FUNCTION_LIST *f = NULL; 825 CK_RV rv; 826 RSA *rsa = NULL; 827 BIGNUM *rsa_n, *rsa_e; 828 struct sshkey *key = NULL; 829 int i; 830 831 memset(&key_attr, 0, sizeof(key_attr)); 832 key_attr[0].type = CKA_ID; 833 key_attr[1].type = CKA_MODULUS; 834 key_attr[2].type = CKA_PUBLIC_EXPONENT; 835 836 session = p->slotinfo[slotidx].session; 837 f = p->function_list; 838 839 /* figure out size of the attributes */ 840 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); 841 if (rv != CKR_OK) { 842 error("C_GetAttributeValue failed: %lu", rv); 843 return (NULL); 844 } 845 846 /* 847 * Allow CKA_ID (always first attribute) to be empty, but 848 * ensure that none of the others are zero length. 849 * XXX assumes CKA_ID is always first. 850 */ 851 if (key_attr[1].ulValueLen == 0 || 852 key_attr[2].ulValueLen == 0) { 853 error("invalid attribute length"); 854 return (NULL); 855 } 856 857 /* allocate buffers for attributes */ 858 for (i = 0; i < 3; i++) 859 if (key_attr[i].ulValueLen > 0) 860 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen); 861 862 /* retrieve ID, modulus and public exponent of RSA key */ 863 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); 864 if (rv != CKR_OK) { 865 error("C_GetAttributeValue failed: %lu", rv); 866 goto fail; 867 } 868 869 rsa = RSA_new(); 870 if (rsa == NULL) { 871 error("RSA_new failed"); 872 goto fail; 873 } 874 875 rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL); 876 rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL); 877 if (rsa_n == NULL || rsa_e == NULL) { 878 error("BN_bin2bn failed"); 879 goto fail; 880 } 881 if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) 882 fatal_f("set key"); 883 rsa_n = rsa_e = NULL; /* transferred */ 884 885 if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa)) 886 goto fail; 887 888 key = sshkey_new(KEY_UNSPEC); 889 if (key == NULL) { 890 error("sshkey_new failed"); 891 goto fail; 892 } 893 894 key->rsa = rsa; 895 key->type = KEY_RSA; 896 key->flags |= SSHKEY_FLAG_EXT; 897 rsa = NULL; /* now owned by key */ 898 899fail: 900 for (i = 0; i < 3; i++) 901 free(key_attr[i].pValue); 902 RSA_free(rsa); 903 904 return (key); 905} 906 907static int 908pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, 909 CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp) 910{ 911 CK_ATTRIBUTE cert_attr[3]; 912 CK_SESSION_HANDLE session; 913 CK_FUNCTION_LIST *f = NULL; 914 CK_RV rv; 915 X509 *x509 = NULL; 916 X509_NAME *x509_name = NULL; 917 EVP_PKEY *evp; 918 RSA *rsa = NULL; 919 EC_KEY *ec = NULL; 920 struct sshkey *key = NULL; 921 int i; 922 int nid; 923 const u_char *cp; 924 char *subject = NULL; 925 926 *keyp = NULL; 927 *labelp = NULL; 928 929 memset(&cert_attr, 0, sizeof(cert_attr)); 930 cert_attr[0].type = CKA_ID; 931 cert_attr[1].type = CKA_SUBJECT; 932 cert_attr[2].type = CKA_VALUE; 933 934 session = p->slotinfo[slotidx].session; 935 f = p->function_list; 936 937 /* figure out size of the attributes */ 938 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3); 939 if (rv != CKR_OK) { 940 error("C_GetAttributeValue failed: %lu", rv); 941 return -1; 942 } 943 944 /* 945 * Allow CKA_ID (always first attribute) to be empty, but 946 * ensure that none of the others are zero length. 947 * XXX assumes CKA_ID is always first. 948 */ 949 if (cert_attr[1].ulValueLen == 0 || 950 cert_attr[2].ulValueLen == 0) { 951 error("invalid attribute length"); 952 return -1; 953 } 954 955 /* allocate buffers for attributes */ 956 for (i = 0; i < 3; i++) 957 if (cert_attr[i].ulValueLen > 0) 958 cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen); 959 960 /* retrieve ID, subject and value of certificate */ 961 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3); 962 if (rv != CKR_OK) { 963 error("C_GetAttributeValue failed: %lu", rv); 964 goto out; 965 } 966 967 /* Decode DER-encoded cert subject */ 968 cp = cert_attr[1].pValue; 969 if ((x509_name = d2i_X509_NAME(NULL, &cp, 970 cert_attr[1].ulValueLen)) == NULL || 971 (subject = X509_NAME_oneline(x509_name, NULL, 0)) == NULL) 972 subject = xstrdup("invalid subject"); 973 X509_NAME_free(x509_name); 974 975 cp = cert_attr[2].pValue; 976 if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) { 977 error("d2i_x509 failed"); 978 goto out; 979 } 980 981 if ((evp = X509_get_pubkey(x509)) == NULL) { 982 error("X509_get_pubkey failed"); 983 goto out; 984 } 985 986 if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) { 987 if (EVP_PKEY_get0_RSA(evp) == NULL) { 988 error("invalid x509; no rsa key"); 989 goto out; 990 } 991 if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) { 992 error("RSAPublicKey_dup failed"); 993 goto out; 994 } 995 996 if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa)) 997 goto out; 998 999 key = sshkey_new(KEY_UNSPEC); 1000 if (key == NULL) { 1001 error("sshkey_new failed"); 1002 goto out; 1003 } 1004 1005 key->rsa = rsa; 1006 key->type = KEY_RSA; 1007 key->flags |= SSHKEY_FLAG_EXT; 1008 rsa = NULL; /* now owned by key */ 1009 } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) { 1010 if (EVP_PKEY_get0_EC_KEY(evp) == NULL) { 1011 error("invalid x509; no ec key"); 1012 goto out; 1013 } 1014 if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) { 1015 error("EC_KEY_dup failed"); 1016 goto out; 1017 } 1018 1019 nid = sshkey_ecdsa_key_to_nid(ec); 1020 if (nid < 0) { 1021 error("couldn't get curve nid"); 1022 goto out; 1023 } 1024 1025 if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec)) 1026 goto out; 1027 1028 key = sshkey_new(KEY_UNSPEC); 1029 if (key == NULL) { 1030 error("sshkey_new failed"); 1031 goto out; 1032 } 1033 1034 key->ecdsa = ec; 1035 key->ecdsa_nid = nid; 1036 key->type = KEY_ECDSA; 1037 key->flags |= SSHKEY_FLAG_EXT; 1038 ec = NULL; /* now owned by key */ 1039 } else { 1040 error("unknown certificate key type"); 1041 goto out; 1042 } 1043 out: 1044 for (i = 0; i < 3; i++) 1045 free(cert_attr[i].pValue); 1046 X509_free(x509); 1047 RSA_free(rsa); 1048 EC_KEY_free(ec); 1049 if (key == NULL) { 1050 free(subject); 1051 return -1; 1052 } 1053 /* success */ 1054 *keyp = key; 1055 *labelp = subject; 1056 return 0; 1057} 1058 1059#if 0 1060static int 1061have_rsa_key(const RSA *rsa) 1062{ 1063 const BIGNUM *rsa_n, *rsa_e; 1064 1065 RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL); 1066 return rsa_n != NULL && rsa_e != NULL; 1067} 1068#endif 1069 1070static void 1071note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context, 1072 struct sshkey *key) 1073{ 1074 char *fp; 1075 1076 if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT, 1077 SSH_FP_DEFAULT)) == NULL) { 1078 error_f("sshkey_fingerprint failed"); 1079 return; 1080 } 1081 debug2("%s: provider %s slot %lu: %s %s", context, p->name, 1082 (u_long)slotidx, sshkey_type(key), fp); 1083 free(fp); 1084} 1085 1086/* 1087 * lookup certificates for token in slot identified by slotidx, 1088 * add 'wrapped' public keys to the 'keysp' array and increment nkeys. 1089 * keysp points to an (possibly empty) array with *nkeys keys. 1090 */ 1091static int 1092pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx, 1093 struct sshkey ***keysp, char ***labelsp, int *nkeys) 1094{ 1095 struct sshkey *key = NULL; 1096 CK_OBJECT_CLASS key_class; 1097 CK_ATTRIBUTE key_attr[1]; 1098 CK_SESSION_HANDLE session; 1099 CK_FUNCTION_LIST *f = NULL; 1100 CK_RV rv; 1101 CK_OBJECT_HANDLE obj; 1102 CK_ULONG n = 0; 1103 int ret = -1; 1104 char *label; 1105 1106 memset(&key_attr, 0, sizeof(key_attr)); 1107 memset(&obj, 0, sizeof(obj)); 1108 1109 key_class = CKO_CERTIFICATE; 1110 key_attr[0].type = CKA_CLASS; 1111 key_attr[0].pValue = &key_class; 1112 key_attr[0].ulValueLen = sizeof(key_class); 1113 1114 session = p->slotinfo[slotidx].session; 1115 f = p->function_list; 1116 1117 rv = f->C_FindObjectsInit(session, key_attr, 1); 1118 if (rv != CKR_OK) { 1119 error("C_FindObjectsInit failed: %lu", rv); 1120 goto fail; 1121 } 1122 1123 while (1) { 1124 CK_CERTIFICATE_TYPE ck_cert_type; 1125 1126 rv = f->C_FindObjects(session, &obj, 1, &n); 1127 if (rv != CKR_OK) { 1128 error("C_FindObjects failed: %lu", rv); 1129 goto fail; 1130 } 1131 if (n == 0) 1132 break; 1133 1134 memset(&ck_cert_type, 0, sizeof(ck_cert_type)); 1135 memset(&key_attr, 0, sizeof(key_attr)); 1136 key_attr[0].type = CKA_CERTIFICATE_TYPE; 1137 key_attr[0].pValue = &ck_cert_type; 1138 key_attr[0].ulValueLen = sizeof(ck_cert_type); 1139 1140 rv = f->C_GetAttributeValue(session, obj, key_attr, 1); 1141 if (rv != CKR_OK) { 1142 error("C_GetAttributeValue failed: %lu", rv); 1143 goto fail; 1144 } 1145 1146 key = NULL; 1147 label = NULL; 1148 switch (ck_cert_type) { 1149 case CKC_X_509: 1150 if (pkcs11_fetch_x509_pubkey(p, slotidx, &obj, 1151 &key, &label) != 0) { 1152 error("failed to fetch key"); 1153 continue; 1154 } 1155 break; 1156 default: 1157 error("skipping unsupported certificate type %lu", 1158 ck_cert_type); 1159 continue; 1160 } 1161 note_key(p, slotidx, __func__, key); 1162 if (pkcs11_key_included(keysp, nkeys, key)) { 1163 debug2_f("key already included");; 1164 sshkey_free(key); 1165 } else { 1166 /* expand key array and add key */ 1167 *keysp = xrecallocarray(*keysp, *nkeys, 1168 *nkeys + 1, sizeof(struct sshkey *)); 1169 (*keysp)[*nkeys] = key; 1170 if (labelsp != NULL) { 1171 *labelsp = xrecallocarray(*labelsp, *nkeys, 1172 *nkeys + 1, sizeof(char *)); 1173 (*labelsp)[*nkeys] = xstrdup((char *)label); 1174 } 1175 *nkeys = *nkeys + 1; 1176 debug("have %d keys", *nkeys); 1177 } 1178 } 1179 1180 ret = 0; 1181fail: 1182 rv = f->C_FindObjectsFinal(session); 1183 if (rv != CKR_OK) { 1184 error("C_FindObjectsFinal failed: %lu", rv); 1185 ret = -1; 1186 } 1187 1188 return (ret); 1189} 1190 1191/* 1192 * lookup public keys for token in slot identified by slotidx, 1193 * add 'wrapped' public keys to the 'keysp' array and increment nkeys. 1194 * keysp points to an (possibly empty) array with *nkeys keys. 1195 */ 1196static int 1197pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, 1198 struct sshkey ***keysp, char ***labelsp, int *nkeys) 1199{ 1200 struct sshkey *key = NULL; 1201 CK_OBJECT_CLASS key_class; 1202 CK_ATTRIBUTE key_attr[2]; 1203 CK_SESSION_HANDLE session; 1204 CK_FUNCTION_LIST *f = NULL; 1205 CK_RV rv; 1206 CK_OBJECT_HANDLE obj; 1207 CK_ULONG n = 0; 1208 int ret = -1; 1209 1210 memset(&key_attr, 0, sizeof(key_attr)); 1211 memset(&obj, 0, sizeof(obj)); 1212 1213 key_class = CKO_PUBLIC_KEY; 1214 key_attr[0].type = CKA_CLASS; 1215 key_attr[0].pValue = &key_class; 1216 key_attr[0].ulValueLen = sizeof(key_class); 1217 1218 session = p->slotinfo[slotidx].session; 1219 f = p->function_list; 1220 1221 rv = f->C_FindObjectsInit(session, key_attr, 1); 1222 if (rv != CKR_OK) { 1223 error("C_FindObjectsInit failed: %lu", rv); 1224 goto fail; 1225 } 1226 1227 while (1) { 1228 CK_KEY_TYPE ck_key_type; 1229 CK_UTF8CHAR label[256]; 1230 1231 rv = f->C_FindObjects(session, &obj, 1, &n); 1232 if (rv != CKR_OK) { 1233 error("C_FindObjects failed: %lu", rv); 1234 goto fail; 1235 } 1236 if (n == 0) 1237 break; 1238 1239 memset(&ck_key_type, 0, sizeof(ck_key_type)); 1240 memset(&key_attr, 0, sizeof(key_attr)); 1241 key_attr[0].type = CKA_KEY_TYPE; 1242 key_attr[0].pValue = &ck_key_type; 1243 key_attr[0].ulValueLen = sizeof(ck_key_type); 1244 key_attr[1].type = CKA_LABEL; 1245 key_attr[1].pValue = &label; 1246 key_attr[1].ulValueLen = sizeof(label) - 1; 1247 1248 rv = f->C_GetAttributeValue(session, obj, key_attr, 2); 1249 if (rv != CKR_OK) { 1250 error("C_GetAttributeValue failed: %lu", rv); 1251 goto fail; 1252 } 1253 1254 label[key_attr[1].ulValueLen] = '\0'; 1255 1256 switch (ck_key_type) { 1257 case CKK_RSA: 1258 key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj); 1259 break; 1260 case CKK_ECDSA: 1261 key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj); 1262 break; 1263 default: 1264 /* XXX print key type? */ 1265 key = NULL; 1266 error("skipping unsupported key type"); 1267 } 1268 1269 if (key == NULL) { 1270 error("failed to fetch key"); 1271 continue; 1272 } 1273 note_key(p, slotidx, __func__, key); 1274 if (pkcs11_key_included(keysp, nkeys, key)) { 1275 debug2_f("key already included");; 1276 sshkey_free(key); 1277 } else { 1278 /* expand key array and add key */ 1279 *keysp = xrecallocarray(*keysp, *nkeys, 1280 *nkeys + 1, sizeof(struct sshkey *)); 1281 (*keysp)[*nkeys] = key; 1282 if (labelsp != NULL) { 1283 *labelsp = xrecallocarray(*labelsp, *nkeys, 1284 *nkeys + 1, sizeof(char *)); 1285 (*labelsp)[*nkeys] = xstrdup((char *)label); 1286 } 1287 *nkeys = *nkeys + 1; 1288 debug("have %d keys", *nkeys); 1289 } 1290 } 1291 1292 ret = 0; 1293fail: 1294 rv = f->C_FindObjectsFinal(session); 1295 if (rv != CKR_OK) { 1296 error("C_FindObjectsFinal failed: %lu", rv); 1297 ret = -1; 1298 } 1299 1300 return (ret); 1301} 1302 1303#ifdef WITH_PKCS11_KEYGEN 1304#define FILL_ATTR(attr, idx, typ, val, len) \ 1305 { (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; } 1306 1307static struct sshkey * 1308pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx, 1309 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err) 1310{ 1311 struct pkcs11_slotinfo *si; 1312 char *plabel = label ? label : ""; 1313 int npub = 0, npriv = 0; 1314 CK_RV rv; 1315 CK_FUNCTION_LIST *f; 1316 CK_SESSION_HANDLE session; 1317 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE; 1318 CK_OBJECT_HANDLE pubKey, privKey; 1319 CK_ATTRIBUTE tpub[16], tpriv[16]; 1320 CK_MECHANISM mech = { 1321 CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 1322 }; 1323 CK_BYTE pubExponent[] = { 1324 0x01, 0x00, 0x01 /* RSA_F4 in bytes */ 1325 }; 1326 1327 *err = 0; 1328 1329 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val)); 1330 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel)); 1331 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val)); 1332 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val)); 1333 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val, 1334 sizeof(false_val)); 1335 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val)); 1336 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val)); 1337 FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits)); 1338 FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent, 1339 sizeof(pubExponent)); 1340 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid)); 1341 1342 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val)); 1343 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel)); 1344 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val)); 1345 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val)); 1346 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val)); 1347 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val)); 1348 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val, 1349 sizeof(false_val)); 1350 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val)); 1351 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val)); 1352 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid)); 1353 1354 f = p->function_list; 1355 si = &p->slotinfo[slotidx]; 1356 session = si->session; 1357 1358 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv, 1359 &pubKey, &privKey)) != CKR_OK) { 1360 error_f("key generation failed: error 0x%lx", rv); 1361 *err = rv; 1362 return NULL; 1363 } 1364 1365 return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey); 1366} 1367 1368static int 1369pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen) 1370{ 1371 size_t i, len; 1372 char ptr[3]; 1373 1374 if (dest) 1375 *dest = NULL; 1376 if (rlen) 1377 *rlen = 0; 1378 1379 if ((len = strlen(hex)) % 2) 1380 return -1; 1381 len /= 2; 1382 1383 *dest = xmalloc(len); 1384 1385 ptr[2] = '\0'; 1386 for (i = 0; i < len; i++) { 1387 ptr[0] = hex[2 * i]; 1388 ptr[1] = hex[(2 * i) + 1]; 1389 if (!isxdigit(ptr[0]) || !isxdigit(ptr[1])) 1390 return -1; 1391 (*dest)[i] = (unsigned char)strtoul(ptr, NULL, 16); 1392 } 1393 1394 if (rlen) 1395 *rlen = len; 1396 1397 return 0; 1398} 1399 1400static struct ec_curve_info { 1401 const char *name; 1402 const char *oid; 1403 const char *oid_encoded; 1404 size_t size; 1405} ec_curve_infos[] = { 1406 {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, 1407 {"secp384r1", "1.3.132.0.34", "06052B81040022", 384}, 1408 {"secp521r1", "1.3.132.0.35", "06052B81040023", 521}, 1409 {NULL, NULL, NULL, 0}, 1410}; 1411 1412static struct sshkey * 1413pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx, 1414 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err) 1415{ 1416 struct pkcs11_slotinfo *si; 1417 char *plabel = label ? label : ""; 1418 int i; 1419 size_t ecparams_size; 1420 unsigned char *ecparams = NULL; 1421 int npub = 0, npriv = 0; 1422 CK_RV rv; 1423 CK_FUNCTION_LIST *f; 1424 CK_SESSION_HANDLE session; 1425 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE; 1426 CK_OBJECT_HANDLE pubKey, privKey; 1427 CK_MECHANISM mech = { 1428 CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0 1429 }; 1430 CK_ATTRIBUTE tpub[16], tpriv[16]; 1431 1432 *err = 0; 1433 1434 for (i = 0; ec_curve_infos[i].name; i++) { 1435 if (ec_curve_infos[i].size == bits) 1436 break; 1437 } 1438 if (!ec_curve_infos[i].name) { 1439 error_f("invalid key size %lu", bits); 1440 return NULL; 1441 } 1442 if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams, 1443 &ecparams_size) == -1) { 1444 error_f("invalid oid"); 1445 return NULL; 1446 } 1447 1448 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val)); 1449 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel)); 1450 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val)); 1451 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val)); 1452 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val, 1453 sizeof(false_val)); 1454 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val)); 1455 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val)); 1456 FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size); 1457 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid)); 1458 1459 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val)); 1460 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel)); 1461 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val)); 1462 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val)); 1463 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val)); 1464 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val)); 1465 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val, 1466 sizeof(false_val)); 1467 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val)); 1468 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val)); 1469 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid)); 1470 1471 f = p->function_list; 1472 si = &p->slotinfo[slotidx]; 1473 session = si->session; 1474 1475 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv, 1476 &pubKey, &privKey)) != CKR_OK) { 1477 error_f("key generation failed: error 0x%lx", rv); 1478 *err = rv; 1479 return NULL; 1480 } 1481 1482 return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey); 1483} 1484#endif /* WITH_PKCS11_KEYGEN */ 1485 1486/* 1487 * register a new provider, fails if provider already exists. if 1488 * keyp is provided, fetch keys. 1489 */ 1490static int 1491pkcs11_register_provider(char *provider_id, char *pin, 1492 struct sshkey ***keyp, char ***labelsp, 1493 struct pkcs11_provider **providerp, CK_ULONG user) 1494{ 1495 int nkeys, need_finalize = 0; 1496 int ret = -1; 1497 struct pkcs11_provider *p = NULL; 1498 void *handle = NULL; 1499 CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **); 1500 CK_RV rv; 1501 CK_FUNCTION_LIST *f = NULL; 1502 CK_TOKEN_INFO *token; 1503 CK_ULONG i; 1504 1505 if (providerp == NULL) 1506 goto fail; 1507 *providerp = NULL; 1508 1509 if (keyp != NULL) 1510 *keyp = NULL; 1511 if (labelsp != NULL) 1512 *labelsp = NULL; 1513 1514 if (pkcs11_provider_lookup(provider_id) != NULL) { 1515 debug_f("provider already registered: %s", provider_id); 1516 goto fail; 1517 } 1518 if (lib_contains_symbol(provider_id, "C_GetFunctionList") != 0) { 1519 error("provider %s is not a PKCS11 library", provider_id); 1520 goto fail; 1521 } 1522 /* open shared pkcs11-library */ 1523 if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) { 1524 error("dlopen %s failed: %s", provider_id, dlerror()); 1525 goto fail; 1526 } 1527 if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) 1528 fatal("dlsym(C_GetFunctionList) failed: %s", dlerror()); 1529 p = xcalloc(1, sizeof(*p)); 1530 p->name = xstrdup(provider_id); 1531 p->handle = handle; 1532 /* setup the pkcs11 callbacks */ 1533 if ((rv = (*getfunctionlist)(&f)) != CKR_OK) { 1534 error("C_GetFunctionList for provider %s failed: %lu", 1535 provider_id, rv); 1536 goto fail; 1537 } 1538 p->function_list = f; 1539 if ((rv = f->C_Initialize(NULL)) != CKR_OK) { 1540 error("C_Initialize for provider %s failed: %lu", 1541 provider_id, rv); 1542 goto fail; 1543 } 1544 need_finalize = 1; 1545 if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) { 1546 error("C_GetInfo for provider %s failed: %lu", 1547 provider_id, rv); 1548 goto fail; 1549 } 1550 debug("provider %s: manufacturerID <%.*s> cryptokiVersion %d.%d" 1551 " libraryDescription <%.*s> libraryVersion %d.%d", 1552 provider_id, 1553 RMSPACE(p->info.manufacturerID), 1554 p->info.cryptokiVersion.major, 1555 p->info.cryptokiVersion.minor, 1556 RMSPACE(p->info.libraryDescription), 1557 p->info.libraryVersion.major, 1558 p->info.libraryVersion.minor); 1559 if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) { 1560 error("C_GetSlotList failed: %lu", rv); 1561 goto fail; 1562 } 1563 if (p->nslots == 0) { 1564 debug_f("provider %s returned no slots", provider_id); 1565 ret = -SSH_PKCS11_ERR_NO_SLOTS; 1566 goto fail; 1567 } 1568 p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID)); 1569 if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots)) 1570 != CKR_OK) { 1571 error("C_GetSlotList for provider %s failed: %lu", 1572 provider_id, rv); 1573 goto fail; 1574 } 1575 p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo)); 1576 p->valid = 1; 1577 nkeys = 0; 1578 for (i = 0; i < p->nslots; i++) { 1579 token = &p->slotinfo[i].token; 1580 if ((rv = f->C_GetTokenInfo(p->slotlist[i], token)) 1581 != CKR_OK) { 1582 error("C_GetTokenInfo for provider %s slot %lu " 1583 "failed: %lu", provider_id, (u_long)i, rv); 1584 continue; 1585 } 1586 if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { 1587 debug2_f("ignoring uninitialised token in " 1588 "provider %s slot %lu", provider_id, (u_long)i); 1589 continue; 1590 } 1591 debug("provider %s slot %lu: label <%.*s> " 1592 "manufacturerID <%.*s> model <%.*s> serial <%.*s> " 1593 "flags 0x%lx", 1594 provider_id, (unsigned long)i, 1595 RMSPACE(token->label), RMSPACE(token->manufacturerID), 1596 RMSPACE(token->model), RMSPACE(token->serialNumber), 1597 token->flags); 1598 /* 1599 * open session, login with pin and retrieve public 1600 * keys (if keyp is provided) 1601 */ 1602 if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 || 1603 keyp == NULL) 1604 continue; 1605 pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys); 1606 pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys); 1607 if (nkeys == 0 && !p->slotinfo[i].logged_in && 1608 pkcs11_interactive) { 1609 /* 1610 * Some tokens require login before they will 1611 * expose keys. 1612 */ 1613 if (pkcs11_login_slot(p, &p->slotinfo[i], 1614 CKU_USER) < 0) { 1615 error("login failed"); 1616 continue; 1617 } 1618 pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys); 1619 pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys); 1620 } 1621 } 1622 1623 /* now owned by caller */ 1624 *providerp = p; 1625 1626 TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); 1627 p->refcount++; /* add to provider list */ 1628 1629 return (nkeys); 1630fail: 1631 if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) 1632 error("C_Finalize for provider %s failed: %lu", 1633 provider_id, rv); 1634 if (p) { 1635 free(p->name); 1636 free(p->slotlist); 1637 free(p->slotinfo); 1638 free(p); 1639 } 1640 if (handle) 1641 dlclose(handle); 1642 if (ret > 0) 1643 ret = -1; 1644 return (ret); 1645} 1646 1647/* 1648 * register a new provider and get number of keys hold by the token, 1649 * fails if provider already exists 1650 */ 1651int 1652pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp, 1653 char ***labelsp) 1654{ 1655 struct pkcs11_provider *p = NULL; 1656 int nkeys; 1657 1658 nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp, 1659 &p, CKU_USER); 1660 1661 /* no keys found or some other error, de-register provider */ 1662 if (nkeys <= 0 && p != NULL) { 1663 TAILQ_REMOVE(&pkcs11_providers, p, next); 1664 pkcs11_provider_finalize(p); 1665 pkcs11_provider_unref(p); 1666 } 1667 if (nkeys == 0) 1668 debug_f("provider %s returned no keys", provider_id); 1669 1670 return (nkeys); 1671} 1672 1673#ifdef WITH_PKCS11_KEYGEN 1674struct sshkey * 1675pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label, 1676 unsigned int type, unsigned int bits, unsigned char keyid, u_int32_t *err) 1677{ 1678 struct pkcs11_provider *p = NULL; 1679 struct pkcs11_slotinfo *si; 1680 CK_FUNCTION_LIST *f; 1681 CK_SESSION_HANDLE session; 1682 struct sshkey *k = NULL; 1683 int ret = -1, reset_pin = 0, reset_provider = 0; 1684 CK_RV rv; 1685 1686 *err = 0; 1687 1688 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) 1689 debug_f("provider \"%s\" available", provider_id); 1690 else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, NULL, 1691 &p, CKU_SO)) < 0) { 1692 debug_f("could not register provider %s", provider_id); 1693 goto out; 1694 } else 1695 reset_provider = 1; 1696 1697 f = p->function_list; 1698 si = &p->slotinfo[slotidx]; 1699 session = si->session; 1700 1701 if ((rv = f->C_SetOperationState(session , pin, strlen(pin), 1702 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) { 1703 debug_f("could not supply SO pin: %lu", rv); 1704 reset_pin = 0; 1705 } else 1706 reset_pin = 1; 1707 1708 switch (type) { 1709 case KEY_RSA: 1710 if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label, 1711 bits, keyid, err)) == NULL) { 1712 debug_f("failed to generate RSA key"); 1713 goto out; 1714 } 1715 break; 1716 case KEY_ECDSA: 1717 if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label, 1718 bits, keyid, err)) == NULL) { 1719 debug_f("failed to generate ECDSA key"); 1720 goto out; 1721 } 1722 break; 1723 default: 1724 *err = SSH_PKCS11_ERR_GENERIC; 1725 debug_f("unknown type %d", type); 1726 goto out; 1727 } 1728 1729out: 1730 if (reset_pin) 1731 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE, 1732 CK_INVALID_HANDLE); 1733 1734 if (reset_provider) 1735 pkcs11_del_provider(provider_id); 1736 1737 return (k); 1738} 1739 1740struct sshkey * 1741pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx, 1742 unsigned char keyid, u_int32_t *err) 1743{ 1744 struct pkcs11_provider *p = NULL; 1745 struct pkcs11_slotinfo *si; 1746 struct sshkey *k = NULL; 1747 int reset_pin = 0, reset_provider = 0; 1748 CK_ULONG nattrs; 1749 CK_FUNCTION_LIST *f; 1750 CK_SESSION_HANDLE session; 1751 CK_ATTRIBUTE attrs[16]; 1752 CK_OBJECT_CLASS key_class; 1753 CK_KEY_TYPE key_type; 1754 CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; 1755 CK_RV rv; 1756 1757 *err = 0; 1758 1759 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) { 1760 debug_f("using provider \"%s\"", provider_id); 1761 } else if (pkcs11_register_provider(provider_id, pin, NULL, NULL, &p, 1762 CKU_SO) < 0) { 1763 debug_f("could not register provider %s", 1764 provider_id); 1765 goto out; 1766 } else 1767 reset_provider = 1; 1768 1769 f = p->function_list; 1770 si = &p->slotinfo[slotidx]; 1771 session = si->session; 1772 1773 if ((rv = f->C_SetOperationState(session , pin, strlen(pin), 1774 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) { 1775 debug_f("could not supply SO pin: %lu", rv); 1776 reset_pin = 0; 1777 } else 1778 reset_pin = 1; 1779 1780 /* private key */ 1781 nattrs = 0; 1782 key_class = CKO_PRIVATE_KEY; 1783 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class)); 1784 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid)); 1785 1786 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 && 1787 obj != CK_INVALID_HANDLE) { 1788 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) { 1789 debug_f("could not destroy private key 0x%hhx", 1790 keyid); 1791 *err = rv; 1792 goto out; 1793 } 1794 } 1795 1796 /* public key */ 1797 nattrs = 0; 1798 key_class = CKO_PUBLIC_KEY; 1799 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class)); 1800 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid)); 1801 1802 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 && 1803 obj != CK_INVALID_HANDLE) { 1804 1805 /* get key type */ 1806 nattrs = 0; 1807 FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type, 1808 sizeof(key_type)); 1809 rv = f->C_GetAttributeValue(session, obj, attrs, nattrs); 1810 if (rv != CKR_OK) { 1811 debug_f("could not get key type of public key 0x%hhx", 1812 keyid); 1813 *err = rv; 1814 key_type = -1; 1815 } 1816 if (key_type == CKK_RSA) 1817 k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj); 1818 else if (key_type == CKK_ECDSA) 1819 k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj); 1820 1821 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) { 1822 debug_f("could not destroy public key 0x%hhx", keyid); 1823 *err = rv; 1824 goto out; 1825 } 1826 } 1827 1828out: 1829 if (reset_pin) 1830 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE, 1831 CK_INVALID_HANDLE); 1832 1833 if (reset_provider) 1834 pkcs11_del_provider(provider_id); 1835 1836 return (k); 1837} 1838#endif /* WITH_PKCS11_KEYGEN */ 1839#else 1840int 1841pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp, 1842 char ***labelsp) 1843{ 1844 error("dlopen() not supported"); 1845 return (-1); 1846} 1847#endif /* HAVE_DLOPEN */ 1848