1 /* $NetBSD: ssh-pkcs11.c,v 1.15 2018/04/06 18:59:00 christos Exp $ */ 2 /* $OpenBSD: ssh-pkcs11.c,v 1.26 2018/02/07 02:06:51 jsing Exp $ */ 3 /* 4 * Copyright (c) 2010 Markus Friedl. All rights reserved. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 #include "includes.h" 19 __RCSID("$NetBSD: ssh-pkcs11.c,v 1.15 2018/04/06 18:59:00 christos Exp $"); 20 21 #include <sys/types.h> 22 #include <sys/queue.h> 23 #include <sys/time.h> 24 #include <stdarg.h> 25 #include <stdio.h> 26 27 #include <string.h> 28 #include <dlfcn.h> 29 30 #include <openssl/x509.h> 31 32 #define CRYPTOKI_COMPAT 33 #include "pkcs11.h" 34 35 #include "log.h" 36 #include "misc.h" 37 #include "sshkey.h" 38 #include "ssh-pkcs11.h" 39 #include "xmalloc.h" 40 41 struct pkcs11_slotinfo { 42 CK_TOKEN_INFO token; 43 CK_SESSION_HANDLE session; 44 int logged_in; 45 }; 46 47 struct pkcs11_provider { 48 char *name; 49 void *handle; 50 CK_FUNCTION_LIST *function_list; 51 CK_INFO info; 52 CK_ULONG nslots; 53 CK_SLOT_ID *slotlist; 54 struct pkcs11_slotinfo *slotinfo; 55 int valid; 56 int refcount; 57 TAILQ_ENTRY(pkcs11_provider) next; 58 }; 59 60 TAILQ_HEAD(, pkcs11_provider) pkcs11_providers; 61 62 struct pkcs11_key { 63 struct pkcs11_provider *provider; 64 CK_ULONG slotidx; 65 int (*orig_finish)(RSA *rsa); 66 RSA_METHOD *rsa_method; 67 char *keyid; 68 int keyid_len; 69 }; 70 71 int pkcs11_interactive = 0; 72 73 int 74 pkcs11_init(int interactive) 75 { 76 pkcs11_interactive = interactive; 77 TAILQ_INIT(&pkcs11_providers); 78 return (0); 79 } 80 81 /* 82 * finalize a provider shared libarary, it's no longer usable. 83 * however, there might still be keys referencing this provider, 84 * so the actuall freeing of memory is handled by pkcs11_provider_unref(). 85 * this is called when a provider gets unregistered. 86 */ 87 static void 88 pkcs11_provider_finalize(struct pkcs11_provider *p) 89 { 90 CK_RV rv; 91 CK_ULONG i; 92 93 debug("pkcs11_provider_finalize: %p refcount %d valid %d", 94 p, p->refcount, p->valid); 95 if (!p->valid) 96 return; 97 for (i = 0; i < p->nslots; i++) { 98 if (p->slotinfo[i].session && 99 (rv = p->function_list->C_CloseSession( 100 p->slotinfo[i].session)) != CKR_OK) 101 error("C_CloseSession failed: %lu", rv); 102 } 103 if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK) 104 error("C_Finalize failed: %lu", rv); 105 p->valid = 0; 106 p->function_list = NULL; 107 #ifdef HAVE_DLOPEN 108 dlclose(p->handle); 109 #endif 110 } 111 112 /* 113 * remove a reference to the provider. 114 * called when a key gets destroyed or when the provider is unregistered. 115 */ 116 static void 117 pkcs11_provider_unref(struct pkcs11_provider *p) 118 { 119 debug("pkcs11_provider_unref: %p refcount %d", p, p->refcount); 120 if (--p->refcount <= 0) { 121 if (p->valid) 122 error("pkcs11_provider_unref: %p still valid", p); 123 free(p->slotlist); 124 free(p->slotinfo); 125 free(p); 126 } 127 } 128 129 /* unregister all providers, keys might still point to the providers */ 130 void 131 pkcs11_terminate(void) 132 { 133 struct pkcs11_provider *p; 134 135 while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) { 136 TAILQ_REMOVE(&pkcs11_providers, p, next); 137 pkcs11_provider_finalize(p); 138 pkcs11_provider_unref(p); 139 } 140 } 141 142 /* lookup provider by name */ 143 static struct pkcs11_provider * 144 pkcs11_provider_lookup(char *provider_id) 145 { 146 struct pkcs11_provider *p; 147 148 TAILQ_FOREACH(p, &pkcs11_providers, next) { 149 debug("check %p %s", p, p->name); 150 if (!strcmp(provider_id, p->name)) 151 return (p); 152 } 153 return (NULL); 154 } 155 156 /* unregister provider by name */ 157 int 158 pkcs11_del_provider(char *provider_id) 159 { 160 struct pkcs11_provider *p; 161 162 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) { 163 TAILQ_REMOVE(&pkcs11_providers, p, next); 164 pkcs11_provider_finalize(p); 165 pkcs11_provider_unref(p); 166 return (0); 167 } 168 return (-1); 169 } 170 171 #ifdef HAVE_DLOPEN 172 /* openssl callback for freeing an RSA key */ 173 static int 174 pkcs11_rsa_finish(RSA *rsa) 175 { 176 struct pkcs11_key *k11; 177 int rv = -1; 178 179 if ((k11 = RSA_get_app_data(rsa)) != NULL) { 180 if (k11->orig_finish) 181 rv = k11->orig_finish(rsa); 182 if (k11->provider) 183 pkcs11_provider_unref(k11->provider); 184 free(k11->keyid); 185 free(k11); 186 } 187 return (rv); 188 } 189 190 /* find a single 'obj' for given attributes */ 191 static int 192 pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr, 193 CK_ULONG nattr, CK_OBJECT_HANDLE *obj) 194 { 195 CK_FUNCTION_LIST *f; 196 CK_SESSION_HANDLE session; 197 CK_ULONG nfound = 0; 198 CK_RV rv; 199 int ret = -1; 200 201 f = p->function_list; 202 session = p->slotinfo[slotidx].session; 203 if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) { 204 error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv); 205 return (-1); 206 } 207 if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK || 208 nfound != 1) { 209 debug("C_FindObjects failed (nfound %lu nattr %lu): %lu", 210 nfound, nattr, rv); 211 } else 212 ret = 0; 213 if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK) 214 error("C_FindObjectsFinal failed: %lu", rv); 215 return (ret); 216 } 217 218 /* openssl callback doing the actual signing operation */ 219 static int 220 pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, 221 int padding) 222 { 223 struct pkcs11_key *k11; 224 struct pkcs11_slotinfo *si; 225 CK_FUNCTION_LIST *f; 226 CK_OBJECT_HANDLE obj; 227 CK_ULONG tlen = 0; 228 CK_RV rv; 229 CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY; 230 CK_BBOOL true_val = CK_TRUE; 231 CK_MECHANISM mech = { 232 CKM_RSA_PKCS, NULL_PTR, 0 233 }; 234 CK_ATTRIBUTE key_filter[] = { 235 {CKA_CLASS, &private_key_class, sizeof(private_key_class) }, 236 {CKA_ID, NULL, 0}, 237 {CKA_SIGN, &true_val, sizeof(true_val) } 238 }; 239 char *pin = NULL, prompt[1024]; 240 int rval = -1; 241 242 if ((k11 = RSA_get_app_data(rsa)) == NULL) { 243 error("RSA_get_app_data failed for rsa %p", rsa); 244 return (-1); 245 } 246 if (!k11->provider || !k11->provider->valid) { 247 error("no pkcs11 (valid) provider for rsa %p", rsa); 248 return (-1); 249 } 250 f = k11->provider->function_list; 251 si = &k11->provider->slotinfo[k11->slotidx]; 252 if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { 253 if (!pkcs11_interactive) { 254 error("need pin entry%s", (si->token.flags & 255 CKF_PROTECTED_AUTHENTICATION_PATH) ? 256 " on reader keypad" : ""); 257 return (-1); 258 } 259 if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) 260 verbose("Deferring PIN entry to reader keypad."); 261 else { 262 snprintf(prompt, sizeof(prompt), 263 "Enter PIN for '%s': ", si->token.label); 264 pin = read_passphrase(prompt, RP_ALLOW_EOF); 265 if (pin == NULL) 266 return (-1); /* bail out */ 267 } 268 rv = f->C_Login(si->session, CKU_USER, (u_char *)pin, 269 (pin != NULL) ? strlen(pin) : 0); 270 if (pin != NULL) { 271 explicit_bzero(pin, strlen(pin)); 272 free(pin); 273 } 274 if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) { 275 error("C_Login failed: %lu", rv); 276 return (-1); 277 } 278 si->logged_in = 1; 279 } 280 key_filter[1].pValue = k11->keyid; 281 key_filter[1].ulValueLen = k11->keyid_len; 282 /* try to find object w/CKA_SIGN first, retry w/o */ 283 if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 && 284 pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) { 285 error("cannot find private key"); 286 } else if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) { 287 error("C_SignInit failed: %lu", rv); 288 } else { 289 /* XXX handle CKR_BUFFER_TOO_SMALL */ 290 tlen = RSA_size(rsa); 291 rv = f->C_Sign(si->session, __UNCONST(from), flen, to, &tlen); 292 if (rv == CKR_OK) 293 rval = tlen; 294 else 295 error("C_Sign failed: %lu", rv); 296 } 297 return (rval); 298 } 299 300 static int 301 pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa, 302 int padding) 303 { 304 return (-1); 305 } 306 307 /* redirect private key operations for rsa key to pkcs11 token */ 308 static int 309 pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, 310 CK_ATTRIBUTE *keyid_attrib, RSA *rsa) 311 { 312 struct pkcs11_key *k11; 313 const RSA_METHOD *def = RSA_get_default_method(); 314 315 k11 = xcalloc(1, sizeof(*k11)); 316 k11->provider = provider; 317 provider->refcount++; /* provider referenced by RSA key */ 318 k11->slotidx = slotidx; 319 /* identify key object on smartcard */ 320 k11->keyid_len = keyid_attrib->ulValueLen; 321 if (k11->keyid_len > 0) { 322 k11->keyid = xmalloc(k11->keyid_len); 323 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); 324 } 325 k11->orig_finish = RSA_meth_get_finish(def); 326 327 if ((k11->rsa_method = RSA_meth_new("pkcs11", RSA_meth_get_flags(__UNCONST(def)))) == NULL) 328 return -1; 329 RSA_meth_set_priv_enc(k11->rsa_method, pkcs11_rsa_private_encrypt); 330 RSA_meth_set_priv_dec(k11->rsa_method, pkcs11_rsa_private_decrypt); 331 RSA_meth_set_finish(k11->rsa_method, pkcs11_rsa_finish); 332 333 RSA_set_method(rsa, k11->rsa_method); 334 RSA_set_app_data(rsa, k11); 335 return (0); 336 } 337 338 /* remove trailing spaces */ 339 static void 340 rmspace(u_char *buf, size_t len) 341 { 342 size_t i; 343 344 if (!len) 345 return; 346 for (i = len - 1; i > 0; i--) 347 if (i == len - 1 || buf[i] == ' ') 348 buf[i] = '\0'; 349 else 350 break; 351 } 352 353 /* 354 * open a pkcs11 session and login if required. 355 * if pin == NULL we delay login until key use 356 */ 357 static int 358 pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin) 359 { 360 CK_RV rv; 361 CK_FUNCTION_LIST *f; 362 CK_SESSION_HANDLE session; 363 int login_required; 364 365 f = p->function_list; 366 login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED; 367 if (pin && login_required && !strlen(pin)) { 368 error("pin required"); 369 return (-1); 370 } 371 if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION| 372 CKF_SERIAL_SESSION, NULL, NULL, &session)) 373 != CKR_OK) { 374 error("C_OpenSession failed: %lu", rv); 375 return (-1); 376 } 377 if (login_required && pin) { 378 rv = f->C_Login(session, CKU_USER, 379 (u_char *)pin, strlen(pin)); 380 if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) { 381 error("C_Login failed: %lu", rv); 382 if ((rv = f->C_CloseSession(session)) != CKR_OK) 383 error("C_CloseSession failed: %lu", rv); 384 return (-1); 385 } 386 p->slotinfo[slotidx].logged_in = 1; 387 } 388 p->slotinfo[slotidx].session = session; 389 return (0); 390 } 391 392 /* 393 * lookup public keys for token in slot identified by slotidx, 394 * add 'wrapped' public keys to the 'keysp' array and increment nkeys. 395 * keysp points to an (possibly empty) array with *nkeys keys. 396 */ 397 static int pkcs11_fetch_keys_filter(struct pkcs11_provider *, CK_ULONG, 398 CK_ATTRIBUTE [], CK_ATTRIBUTE [3], struct sshkey ***, int *) 399 __attribute__((__bounded__(__minbytes__,4, 3 * sizeof(CK_ATTRIBUTE)))); 400 401 static int 402 pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, 403 struct sshkey ***keysp, int *nkeys) 404 { 405 CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY; 406 CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE; 407 CK_ATTRIBUTE pubkey_filter[] = { 408 { CKA_CLASS, &pubkey_class, sizeof(pubkey_class) } 409 }; 410 CK_ATTRIBUTE cert_filter[] = { 411 { CKA_CLASS, &cert_class, sizeof(cert_class) } 412 }; 413 CK_ATTRIBUTE pubkey_attribs[] = { 414 { CKA_ID, NULL, 0 }, 415 { CKA_MODULUS, NULL, 0 }, 416 { CKA_PUBLIC_EXPONENT, NULL, 0 } 417 }; 418 CK_ATTRIBUTE cert_attribs[] = { 419 { CKA_ID, NULL, 0 }, 420 { CKA_SUBJECT, NULL, 0 }, 421 { CKA_VALUE, NULL, 0 } 422 }; 423 424 if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, pubkey_attribs, 425 keysp, nkeys) < 0 || 426 pkcs11_fetch_keys_filter(p, slotidx, cert_filter, cert_attribs, 427 keysp, nkeys) < 0) 428 return (-1); 429 return (0); 430 } 431 432 static int 433 pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key) 434 { 435 int i; 436 437 for (i = 0; i < *nkeys; i++) 438 if (sshkey_equal(key, (*keysp)[i])) 439 return (1); 440 return (0); 441 } 442 443 static int 444 pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, 445 CK_ATTRIBUTE filter[], CK_ATTRIBUTE attribs[3], 446 struct sshkey ***keysp, int *nkeys) 447 { 448 struct sshkey *key; 449 RSA *rsa; 450 X509 *x509; 451 EVP_PKEY *evp; 452 int i; 453 const u_char *cp; 454 CK_RV rv; 455 CK_OBJECT_HANDLE obj; 456 CK_ULONG nfound; 457 CK_SESSION_HANDLE session; 458 CK_FUNCTION_LIST *f; 459 460 f = p->function_list; 461 session = p->slotinfo[slotidx].session; 462 /* setup a filter the looks for public keys */ 463 if ((rv = f->C_FindObjectsInit(session, filter, 1)) != CKR_OK) { 464 error("C_FindObjectsInit failed: %lu", rv); 465 return (-1); 466 } 467 while (1) { 468 /* XXX 3 attributes in attribs[] */ 469 for (i = 0; i < 3; i++) { 470 attribs[i].pValue = NULL; 471 attribs[i].ulValueLen = 0; 472 } 473 if ((rv = f->C_FindObjects(session, &obj, 1, &nfound)) != CKR_OK 474 || nfound == 0) 475 break; 476 /* found a key, so figure out size of the attributes */ 477 if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) 478 != CKR_OK) { 479 error("C_GetAttributeValue failed: %lu", rv); 480 continue; 481 } 482 /* 483 * Allow CKA_ID (always first attribute) to be empty, but 484 * ensure that none of the others are zero length. 485 * XXX assumes CKA_ID is always first. 486 */ 487 if (attribs[1].ulValueLen == 0 || 488 attribs[2].ulValueLen == 0) { 489 continue; 490 } 491 /* allocate buffers for attributes */ 492 for (i = 0; i < 3; i++) { 493 if (attribs[i].ulValueLen > 0) { 494 attribs[i].pValue = xmalloc( 495 attribs[i].ulValueLen); 496 } 497 } 498 499 /* 500 * retrieve ID, modulus and public exponent of RSA key, 501 * or ID, subject and value for certificates. 502 */ 503 rsa = NULL; 504 if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) 505 != CKR_OK) { 506 error("C_GetAttributeValue failed: %lu", rv); 507 } else if (attribs[1].type == CKA_MODULUS ) { 508 if ((rsa = RSA_new()) == NULL) { 509 error("RSA_new failed"); 510 } else { 511 BIGNUM *n=NULL, *e=NULL; 512 n = BN_new(); 513 e = BN_new(); 514 if (n == NULL || e == NULL) 515 error("BN_new alloc failed"); 516 if (BN_bin2bn(attribs[1].pValue, 517 attribs[1].ulValueLen, n) == NULL || 518 BN_bin2bn(attribs[2].pValue, 519 attribs[2].ulValueLen, e) == NULL) 520 error("BN_bin2bn failed"); 521 if (RSA_set0_key(rsa, n, e, NULL) == 0) 522 error("RSA_set0_key failed"); 523 n = e = NULL; 524 } 525 } else { 526 cp = attribs[2].pValue; 527 if ((x509 = X509_new()) == NULL) { 528 error("X509_new failed"); 529 } else if (d2i_X509(&x509, &cp, attribs[2].ulValueLen) 530 == NULL) { 531 error("d2i_X509 failed"); 532 } else if ((evp = X509_get_pubkey(x509)) == NULL || 533 EVP_PKEY_id(evp) != EVP_PKEY_RSA || 534 EVP_PKEY_get0_RSA(evp) == NULL) { 535 debug("X509_get_pubkey failed or no rsa"); 536 } else if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) 537 == NULL) { 538 error("RSAPublicKey_dup"); 539 } 540 X509_free(x509); 541 } 542 { 543 const BIGNUM *n, *e; 544 RSA_get0_key(rsa, &n, &e, NULL); 545 if (rsa && n && e && 546 pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) { 547 if ((key = sshkey_new(KEY_UNSPEC)) == NULL) 548 fatal("sshkey_new failed"); 549 key->rsa = rsa; 550 key->type = KEY_RSA; 551 key->flags |= SSHKEY_FLAG_EXT; 552 if (pkcs11_key_included(keysp, nkeys, key)) { 553 sshkey_free(key); 554 } else { 555 /* expand key array and add key */ 556 *keysp = xrecallocarray(*keysp, *nkeys, 557 *nkeys + 1, sizeof(struct sshkey *)); 558 (*keysp)[*nkeys] = key; 559 *nkeys = *nkeys + 1; 560 debug("have %d keys", *nkeys); 561 } 562 } else if (rsa) { 563 RSA_free(rsa); 564 } 565 } 566 for (i = 0; i < 3; i++) 567 free(attribs[i].pValue); 568 } 569 if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK) 570 error("C_FindObjectsFinal failed: %lu", rv); 571 return (0); 572 } 573 574 /* register a new provider, fails if provider already exists */ 575 int 576 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp) 577 { 578 int nkeys, need_finalize = 0; 579 struct pkcs11_provider *p = NULL; 580 void *handle = NULL; 581 CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **); 582 CK_RV rv; 583 CK_FUNCTION_LIST *f = NULL; 584 CK_TOKEN_INFO *token; 585 CK_ULONG i; 586 587 *keyp = NULL; 588 if (pkcs11_provider_lookup(provider_id) != NULL) { 589 debug("%s: provider already registered: %s", 590 __func__, provider_id); 591 goto fail; 592 } 593 /* open shared pkcs11-libarary */ 594 if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) { 595 error("dlopen %s failed: %s", provider_id, dlerror()); 596 goto fail; 597 } 598 if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) { 599 error("dlsym(C_GetFunctionList) failed: %s", dlerror()); 600 goto fail; 601 } 602 p = xcalloc(1, sizeof(*p)); 603 p->name = xstrdup(provider_id); 604 p->handle = handle; 605 /* setup the pkcs11 callbacks */ 606 if ((rv = (*getfunctionlist)(&f)) != CKR_OK) { 607 error("C_GetFunctionList for provider %s failed: %lu", 608 provider_id, rv); 609 goto fail; 610 } 611 p->function_list = f; 612 if ((rv = f->C_Initialize(NULL)) != CKR_OK) { 613 error("C_Initialize for provider %s failed: %lu", 614 provider_id, rv); 615 goto fail; 616 } 617 need_finalize = 1; 618 if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) { 619 error("C_GetInfo for provider %s failed: %lu", 620 provider_id, rv); 621 goto fail; 622 } 623 rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID)); 624 rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription)); 625 debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d" 626 " libraryDescription <%s> libraryVersion %d.%d", 627 provider_id, 628 p->info.manufacturerID, 629 p->info.cryptokiVersion.major, 630 p->info.cryptokiVersion.minor, 631 p->info.libraryDescription, 632 p->info.libraryVersion.major, 633 p->info.libraryVersion.minor); 634 if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) { 635 error("C_GetSlotList failed: %lu", rv); 636 goto fail; 637 } 638 if (p->nslots == 0) { 639 debug("%s: provider %s returned no slots", __func__, 640 provider_id); 641 goto fail; 642 } 643 p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID)); 644 if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots)) 645 != CKR_OK) { 646 error("C_GetSlotList for provider %s failed: %lu", 647 provider_id, rv); 648 goto fail; 649 } 650 p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo)); 651 p->valid = 1; 652 nkeys = 0; 653 for (i = 0; i < p->nslots; i++) { 654 token = &p->slotinfo[i].token; 655 if ((rv = f->C_GetTokenInfo(p->slotlist[i], token)) 656 != CKR_OK) { 657 error("C_GetTokenInfo for provider %s slot %lu " 658 "failed: %lu", provider_id, (unsigned long)i, rv); 659 continue; 660 } 661 if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { 662 debug2("%s: ignoring uninitialised token in " 663 "provider %s slot %lu", __func__, 664 provider_id, (unsigned long)i); 665 continue; 666 } 667 rmspace(token->label, sizeof(token->label)); 668 rmspace(token->manufacturerID, sizeof(token->manufacturerID)); 669 rmspace(token->model, sizeof(token->model)); 670 rmspace(token->serialNumber, sizeof(token->serialNumber)); 671 debug("provider %s slot %lu: label <%s> manufacturerID <%s> " 672 "model <%s> serial <%s> flags 0x%lx", 673 provider_id, (unsigned long)i, 674 token->label, token->manufacturerID, token->model, 675 token->serialNumber, token->flags); 676 /* open session, login with pin and retrieve public keys */ 677 if (pkcs11_open_session(p, i, pin) == 0) 678 pkcs11_fetch_keys(p, i, keyp, &nkeys); 679 } 680 if (nkeys > 0) { 681 TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); 682 p->refcount++; /* add to provider list */ 683 return (nkeys); 684 } 685 debug("%s: provider %s returned no keys", __func__, provider_id); 686 /* don't add the provider, since it does not have any keys */ 687 fail: 688 if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) 689 error("C_Finalize for provider %s failed: %lu", 690 provider_id, rv); 691 if (p) { 692 free(p->slotlist); 693 free(p->slotinfo); 694 free(p); 695 } 696 if (handle) 697 dlclose(handle); 698 return (-1); 699 } 700 #else 701 int 702 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp) 703 { 704 error("dlopen() not supported"); 705 return (-1); 706 } 707 #endif 708