1 /* $OpenBSD: ssh-pkcs11.c,v 1.56 2023/03/08 05:33:53 tb Exp $ */
3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
4 * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
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.
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.
23 #ifdef HAVE_SYS_TIME_H
24 # include <sys/time.h>
27 #include <sys/types.h>
35 #include "openbsd-compat/sys-queue.h"
36 #include "openbsd-compat/openssl-compat.h"
38 #include <openssl/ecdsa.h>
39 #include <openssl/x509.h>
40 #include <openssl/err.h>
42 #define CRYPTOKI_COMPAT
48 #include "ssh-pkcs11.h"
52 struct pkcs11_slotinfo {
54 CK_SESSION_HANDLE session;
58 struct pkcs11_provider {
61 CK_FUNCTION_LIST *function_list;
65 struct pkcs11_slotinfo *slotinfo;
68 TAILQ_ENTRY(pkcs11_provider) next;
71 TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
74 struct pkcs11_provider *provider;
80 int pkcs11_interactive = 0;
82 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
84 ossl_error(const char *msg)
89 while ((e = ERR_get_error()) != 0)
90 error_f("libcrypto error: %s", ERR_error_string(e, NULL));
92 #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
95 pkcs11_init(int interactive)
97 pkcs11_interactive = interactive;
98 TAILQ_INIT(&pkcs11_providers);
103 * finalize a provider shared library, it's no longer usable.
104 * however, there might still be keys referencing this provider,
105 * so the actual freeing of memory is handled by pkcs11_provider_unref().
106 * this is called when a provider gets unregistered.
109 pkcs11_provider_finalize(struct pkcs11_provider *p)
114 debug_f("provider \"%s\" refcount %d valid %d",
115 p->name, p->refcount, p->valid);
118 for (i = 0; i < p->nslots; i++) {
119 if (p->slotinfo[i].session &&
120 (rv = p->function_list->C_CloseSession(
121 p->slotinfo[i].session)) != CKR_OK)
122 error("C_CloseSession failed: %lu", rv);
124 if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
125 error("C_Finalize failed: %lu", rv);
127 p->function_list = NULL;
132 * remove a reference to the provider.
133 * called when a key gets destroyed or when the provider is unregistered.
136 pkcs11_provider_unref(struct pkcs11_provider *p)
138 debug_f("provider \"%s\" refcount %d", p->name, p->refcount);
139 if (--p->refcount <= 0) {
141 error_f("provider \"%s\" still valid", p->name);
149 /* unregister all providers, keys might still point to the providers */
151 pkcs11_terminate(void)
153 struct pkcs11_provider *p;
155 while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
156 TAILQ_REMOVE(&pkcs11_providers, p, next);
157 pkcs11_provider_finalize(p);
158 pkcs11_provider_unref(p);
162 /* lookup provider by name */
163 static struct pkcs11_provider *
164 pkcs11_provider_lookup(char *provider_id)
166 struct pkcs11_provider *p;
168 TAILQ_FOREACH(p, &pkcs11_providers, next) {
169 debug("check provider \"%s\"", p->name);
170 if (!strcmp(provider_id, p->name))
176 /* unregister provider by name */
178 pkcs11_del_provider(char *provider_id)
180 struct pkcs11_provider *p;
182 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
183 TAILQ_REMOVE(&pkcs11_providers, p, next);
184 pkcs11_provider_finalize(p);
185 pkcs11_provider_unref(p);
191 static RSA_METHOD *rsa_method;
192 static int rsa_idx = 0;
193 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
194 static EC_KEY_METHOD *ec_key_method;
195 static int ec_key_idx = 0;
196 #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
198 /* release a wrapped object */
200 pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
201 long argl, void *argp)
203 struct pkcs11_key *k11 = ptr;
205 debug_f("parent %p ptr %p idx %d", parent, ptr, idx);
209 pkcs11_provider_unref(k11->provider);
214 /* find a single 'obj' for given attributes */
216 pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
217 CK_ULONG nattr, CK_OBJECT_HANDLE *obj)
220 CK_SESSION_HANDLE session;
225 f = p->function_list;
226 session = p->slotinfo[slotidx].session;
227 if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) {
228 error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv);
231 if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK ||
233 debug("C_FindObjects failed (nfound %lu nattr %lu): %lu",
237 if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
238 error("C_FindObjectsFinal failed: %lu", rv);
243 pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si,
246 char *pin = NULL, prompt[1024];
249 if (provider == NULL || si == NULL || !provider->valid) {
250 error("no pkcs11 (valid) provider found");
254 if (!pkcs11_interactive) {
255 error("need pin entry%s",
256 (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ?
257 " on reader keypad" : "");
260 if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
261 verbose("Deferring PIN entry to reader keypad.");
263 snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ",
265 if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) {
266 debug_f("no pin specified");
267 return (-1); /* bail out */
270 rv = provider->function_list->C_Login(si->session, type, (u_char *)pin,
271 (pin != NULL) ? strlen(pin) : 0);
273 freezero(pin, strlen(pin));
277 case CKR_USER_ALREADY_LOGGED_IN:
280 case CKR_PIN_LEN_RANGE:
281 error("PKCS#11 login failed: PIN length out of range");
283 case CKR_PIN_INCORRECT:
284 error("PKCS#11 login failed: PIN incorrect");
287 error("PKCS#11 login failed: PIN locked");
290 error("PKCS#11 login failed: error %lu", rv);
298 pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type)
300 if (k11 == NULL || k11->provider == NULL || !k11->provider->valid) {
301 error("no pkcs11 (valid) provider found");
305 return pkcs11_login_slot(k11->provider,
306 &k11->provider->slotinfo[k11->slotidx], type);
311 pkcs11_check_obj_bool_attrib(struct pkcs11_key *k11, CK_OBJECT_HANDLE obj,
312 CK_ATTRIBUTE_TYPE type, int *val)
314 struct pkcs11_slotinfo *si;
322 if (!k11->provider || !k11->provider->valid) {
323 error("no pkcs11 (valid) provider found");
327 f = k11->provider->function_list;
328 si = &k11->provider->slotinfo[k11->slotidx];
332 attr.ulValueLen = sizeof(flag);
334 rv = f->C_GetAttributeValue(si->session, obj, &attr, 1);
336 error("C_GetAttributeValue failed: %lu", rv);
340 debug_f("provider \"%s\" slot %lu object %lu: attrib %lu = %d",
341 k11->provider->name, k11->slotidx, obj, type, *val);
346 pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type)
348 struct pkcs11_slotinfo *si;
350 CK_OBJECT_HANDLE obj;
352 CK_OBJECT_CLASS private_key_class;
355 CK_ATTRIBUTE key_filter[3];
359 if (!k11->provider || !k11->provider->valid) {
360 error("no pkcs11 (valid) provider found");
364 f = k11->provider->function_list;
365 si = &k11->provider->slotinfo[k11->slotidx];
367 if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
368 if (pkcs11_login(k11, CKU_USER) < 0) {
369 error("login failed");
375 memset(&key_filter, 0, sizeof(key_filter));
376 private_key_class = CKO_PRIVATE_KEY;
377 key_filter[0].type = CKA_CLASS;
378 key_filter[0].pValue = &private_key_class;
379 key_filter[0].ulValueLen = sizeof(private_key_class);
381 key_filter[1].type = CKA_ID;
382 key_filter[1].pValue = k11->keyid;
383 key_filter[1].ulValueLen = k11->keyid_len;
386 key_filter[2].type = CKA_SIGN;
387 key_filter[2].pValue = &true_val;
388 key_filter[2].ulValueLen = sizeof(true_val);
390 /* try to find object w/CKA_SIGN first, retry w/o */
391 if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
392 pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
393 error("cannot find private key");
397 memset(&mech, 0, sizeof(mech));
398 mech.mechanism = mech_type;
399 mech.pParameter = NULL_PTR;
400 mech.ulParameterLen = 0;
402 if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
403 error("C_SignInit failed: %lu", rv);
407 pkcs11_check_obj_bool_attrib(k11, obj, CKA_ALWAYS_AUTHENTICATE,
408 &always_auth); /* ignore errors here */
409 if (always_auth && !did_login) {
410 debug_f("always-auth key");
411 if (pkcs11_login(k11, CKU_CONTEXT_SPECIFIC) < 0) {
412 error("login failed for always-auth key");
420 /* openssl callback doing the actual signing operation */
422 pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
425 struct pkcs11_key *k11;
426 struct pkcs11_slotinfo *si;
432 if ((k11 = RSA_get_ex_data(rsa, rsa_idx)) == NULL) {
433 error("RSA_get_ex_data failed");
437 if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
438 error("pkcs11_get_key failed");
442 f = k11->provider->function_list;
443 si = &k11->provider->slotinfo[k11->slotidx];
444 tlen = RSA_size(rsa);
446 /* XXX handle CKR_BUFFER_TOO_SMALL */
447 rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
451 error("C_Sign failed: %lu", rv);
457 pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
464 pkcs11_rsa_start_wrapper(void)
466 if (rsa_method != NULL)
468 rsa_method = RSA_meth_dup(RSA_get_default_method());
469 if (rsa_method == NULL)
471 rsa_idx = RSA_get_ex_new_index(0, "ssh-pkcs11-rsa",
472 NULL, NULL, pkcs11_k11_free);
475 if (!RSA_meth_set1_name(rsa_method, "pkcs11") ||
476 !RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt) ||
477 !RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt)) {
478 error_f("setup pkcs11 method failed");
484 /* redirect private key operations for rsa key to pkcs11 token */
486 pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
487 CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
489 struct pkcs11_key *k11;
491 if (pkcs11_rsa_start_wrapper() == -1)
494 k11 = xcalloc(1, sizeof(*k11));
495 k11->provider = provider;
496 provider->refcount++; /* provider referenced by RSA key */
497 k11->slotidx = slotidx;
498 /* identify key object on smartcard */
499 k11->keyid_len = keyid_attrib->ulValueLen;
500 if (k11->keyid_len > 0) {
501 k11->keyid = xmalloc(k11->keyid_len);
502 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
505 RSA_set_method(rsa, rsa_method);
506 RSA_set_ex_data(rsa, rsa_idx, k11);
510 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
511 /* openssl callback doing the actual signing operation */
513 ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
514 const BIGNUM *rp, EC_KEY *ec)
516 struct pkcs11_key *k11;
517 struct pkcs11_slotinfo *si;
519 CK_ULONG siglen = 0, bnlen;
521 ECDSA_SIG *ret = NULL;
523 BIGNUM *r = NULL, *s = NULL;
525 if ((k11 = EC_KEY_get_ex_data(ec, ec_key_idx)) == NULL) {
526 ossl_error("EC_KEY_get_ex_data failed for ec");
530 if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
531 error("pkcs11_get_key failed");
535 f = k11->provider->function_list;
536 si = &k11->provider->slotinfo[k11->slotidx];
538 siglen = ECDSA_size(ec);
539 sig = xmalloc(siglen);
541 /* XXX handle CKR_BUFFER_TOO_SMALL */
542 rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &siglen);
544 error("C_Sign failed: %lu", rv);
547 if (siglen < 64 || siglen > 132 || siglen % 2) {
548 error_f("bad signature length: %lu", (u_long)siglen);
552 if ((ret = ECDSA_SIG_new()) == NULL) {
553 error("ECDSA_SIG_new failed");
556 if ((r = BN_bin2bn(sig, bnlen, NULL)) == NULL ||
557 (s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) {
558 ossl_error("BN_bin2bn failed");
563 if (!ECDSA_SIG_set0(ret, r, s)) {
564 error_f("ECDSA_SIG_set0 failed");
569 r = s = NULL; /* now owned by ret */
580 pkcs11_ecdsa_start_wrapper(void)
582 int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
583 unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
585 if (ec_key_method != NULL)
587 ec_key_idx = EC_KEY_get_ex_new_index(0, "ssh-pkcs11-ecdsa",
588 NULL, NULL, pkcs11_k11_free);
589 if (ec_key_idx == -1)
591 ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
592 if (ec_key_method == NULL)
594 EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
595 EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
600 pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
601 CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
603 struct pkcs11_key *k11;
605 if (pkcs11_ecdsa_start_wrapper() == -1)
608 k11 = xcalloc(1, sizeof(*k11));
609 k11->provider = provider;
610 provider->refcount++; /* provider referenced by ECDSA key */
611 k11->slotidx = slotidx;
612 /* identify key object on smartcard */
613 k11->keyid_len = keyid_attrib->ulValueLen;
614 if (k11->keyid_len > 0) {
615 k11->keyid = xmalloc(k11->keyid_len);
616 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
618 EC_KEY_set_method(ec, ec_key_method);
619 EC_KEY_set_ex_data(ec, ec_key_idx, k11);
623 #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
625 /* remove trailing spaces */
627 rmspace(u_char *buf, size_t len)
633 for (i = len - 1; i > 0; i--)
634 if (i == len - 1 || buf[i] == ' ')
641 * open a pkcs11 session and login if required.
642 * if pin == NULL we delay login until key use
645 pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin,
648 struct pkcs11_slotinfo *si;
651 CK_SESSION_HANDLE session;
652 int login_required, ret;
654 f = p->function_list;
655 si = &p->slotinfo[slotidx];
657 login_required = si->token.flags & CKF_LOGIN_REQUIRED;
659 /* fail early before opening session */
660 if (login_required && !pkcs11_interactive &&
661 (pin == NULL || strlen(pin) == 0)) {
662 error("pin required");
663 return (-SSH_PKCS11_ERR_PIN_REQUIRED);
665 if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
666 CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) {
667 error("C_OpenSession failed: %lu", rv);
670 if (login_required && pin != NULL && strlen(pin) != 0) {
671 rv = f->C_Login(session, user, (u_char *)pin, strlen(pin));
672 if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
673 error("C_Login failed: %lu", rv);
674 ret = (rv == CKR_PIN_LOCKED) ?
675 -SSH_PKCS11_ERR_PIN_LOCKED :
676 -SSH_PKCS11_ERR_LOGIN_FAIL;
677 if ((rv = f->C_CloseSession(session)) != CKR_OK)
678 error("C_CloseSession failed: %lu", rv);
683 si->session = session;
688 pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
692 for (i = 0; i < *nkeys; i++)
693 if (sshkey_equal(key, (*keysp)[i]))
698 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
699 static struct sshkey *
700 pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
701 CK_OBJECT_HANDLE *obj)
703 CK_ATTRIBUTE key_attr[3];
704 CK_SESSION_HANDLE session;
705 CK_FUNCTION_LIST *f = NULL;
707 ASN1_OCTET_STRING *octet = NULL;
709 EC_GROUP *group = NULL;
710 struct sshkey *key = NULL;
711 const unsigned char *attrp = NULL;
715 memset(&key_attr, 0, sizeof(key_attr));
716 key_attr[0].type = CKA_ID;
717 key_attr[1].type = CKA_EC_POINT;
718 key_attr[2].type = CKA_EC_PARAMS;
720 session = p->slotinfo[slotidx].session;
721 f = p->function_list;
723 /* figure out size of the attributes */
724 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
726 error("C_GetAttributeValue failed: %lu", rv);
731 * Allow CKA_ID (always first attribute) to be empty, but
732 * ensure that none of the others are zero length.
733 * XXX assumes CKA_ID is always first.
735 if (key_attr[1].ulValueLen == 0 ||
736 key_attr[2].ulValueLen == 0) {
737 error("invalid attribute length");
741 /* allocate buffers for attributes */
742 for (i = 0; i < 3; i++)
743 if (key_attr[i].ulValueLen > 0)
744 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
746 /* retrieve ID, public point and curve parameters of EC key */
747 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
749 error("C_GetAttributeValue failed: %lu", rv);
755 error("EC_KEY_new failed");
759 attrp = key_attr[2].pValue;
760 group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
762 ossl_error("d2i_ECPKParameters failed");
766 if (EC_KEY_set_group(ec, group) == 0) {
767 ossl_error("EC_KEY_set_group failed");
771 if (key_attr[1].ulValueLen <= 2) {
772 error("CKA_EC_POINT too small");
776 attrp = key_attr[1].pValue;
777 octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen);
779 ossl_error("d2i_ASN1_OCTET_STRING failed");
783 if (o2i_ECPublicKey(&ec, &attrp, octet->length) == NULL) {
784 ossl_error("o2i_ECPublicKey failed");
788 nid = sshkey_ecdsa_key_to_nid(ec);
790 error("couldn't get curve nid");
794 if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
797 key = sshkey_new(KEY_UNSPEC);
799 error("sshkey_new failed");
804 key->ecdsa_nid = nid;
805 key->type = KEY_ECDSA;
806 key->flags |= SSHKEY_FLAG_EXT;
807 ec = NULL; /* now owned by key */
810 for (i = 0; i < 3; i++)
811 free(key_attr[i].pValue);
815 EC_GROUP_free(group);
817 ASN1_OCTET_STRING_free(octet);
821 #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
823 static struct sshkey *
824 pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
825 CK_OBJECT_HANDLE *obj)
827 CK_ATTRIBUTE key_attr[3];
828 CK_SESSION_HANDLE session;
829 CK_FUNCTION_LIST *f = NULL;
832 BIGNUM *rsa_n, *rsa_e;
833 struct sshkey *key = NULL;
836 memset(&key_attr, 0, sizeof(key_attr));
837 key_attr[0].type = CKA_ID;
838 key_attr[1].type = CKA_MODULUS;
839 key_attr[2].type = CKA_PUBLIC_EXPONENT;
841 session = p->slotinfo[slotidx].session;
842 f = p->function_list;
844 /* figure out size of the attributes */
845 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
847 error("C_GetAttributeValue failed: %lu", rv);
852 * Allow CKA_ID (always first attribute) to be empty, but
853 * ensure that none of the others are zero length.
854 * XXX assumes CKA_ID is always first.
856 if (key_attr[1].ulValueLen == 0 ||
857 key_attr[2].ulValueLen == 0) {
858 error("invalid attribute length");
862 /* allocate buffers for attributes */
863 for (i = 0; i < 3; i++)
864 if (key_attr[i].ulValueLen > 0)
865 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
867 /* retrieve ID, modulus and public exponent of RSA key */
868 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
870 error("C_GetAttributeValue failed: %lu", rv);
876 error("RSA_new failed");
880 rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
881 rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
882 if (rsa_n == NULL || rsa_e == NULL) {
883 error("BN_bin2bn failed");
886 if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
888 rsa_n = rsa_e = NULL; /* transferred */
890 if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
893 key = sshkey_new(KEY_UNSPEC);
895 error("sshkey_new failed");
901 key->flags |= SSHKEY_FLAG_EXT;
902 rsa = NULL; /* now owned by key */
905 for (i = 0; i < 3; i++)
906 free(key_attr[i].pValue);
913 pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
914 CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp)
916 CK_ATTRIBUTE cert_attr[3];
917 CK_SESSION_HANDLE session;
918 CK_FUNCTION_LIST *f = NULL;
921 X509_NAME *x509_name = NULL;
924 #ifdef OPENSSL_HAS_ECC
927 struct sshkey *key = NULL;
929 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
933 char *subject = NULL;
938 memset(&cert_attr, 0, sizeof(cert_attr));
939 cert_attr[0].type = CKA_ID;
940 cert_attr[1].type = CKA_SUBJECT;
941 cert_attr[2].type = CKA_VALUE;
943 session = p->slotinfo[slotidx].session;
944 f = p->function_list;
946 /* figure out size of the attributes */
947 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
949 error("C_GetAttributeValue failed: %lu", rv);
954 * Allow CKA_ID (always first attribute) to be empty, but
955 * ensure that none of the others are zero length.
956 * XXX assumes CKA_ID is always first.
958 if (cert_attr[1].ulValueLen == 0 ||
959 cert_attr[2].ulValueLen == 0) {
960 error("invalid attribute length");
964 /* allocate buffers for attributes */
965 for (i = 0; i < 3; i++)
966 if (cert_attr[i].ulValueLen > 0)
967 cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
969 /* retrieve ID, subject and value of certificate */
970 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
972 error("C_GetAttributeValue failed: %lu", rv);
976 /* Decode DER-encoded cert subject */
977 cp = cert_attr[1].pValue;
978 if ((x509_name = d2i_X509_NAME(NULL, &cp,
979 cert_attr[1].ulValueLen)) == NULL ||
980 (subject = X509_NAME_oneline(x509_name, NULL, 0)) == NULL)
981 subject = xstrdup("invalid subject");
982 X509_NAME_free(x509_name);
984 cp = cert_attr[2].pValue;
985 if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) {
986 error("d2i_x509 failed");
990 if ((evp = X509_get_pubkey(x509)) == NULL) {
991 error("X509_get_pubkey failed");
995 if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
996 if (EVP_PKEY_get0_RSA(evp) == NULL) {
997 error("invalid x509; no rsa key");
1000 if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
1001 error("RSAPublicKey_dup failed");
1005 if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
1008 key = sshkey_new(KEY_UNSPEC);
1010 error("sshkey_new failed");
1015 key->type = KEY_RSA;
1016 key->flags |= SSHKEY_FLAG_EXT;
1017 rsa = NULL; /* now owned by key */
1018 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
1019 } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
1020 if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
1021 error("invalid x509; no ec key");
1024 if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
1025 error("EC_KEY_dup failed");
1029 nid = sshkey_ecdsa_key_to_nid(ec);
1031 error("couldn't get curve nid");
1035 if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
1038 key = sshkey_new(KEY_UNSPEC);
1040 error("sshkey_new failed");
1045 key->ecdsa_nid = nid;
1046 key->type = KEY_ECDSA;
1047 key->flags |= SSHKEY_FLAG_EXT;
1048 ec = NULL; /* now owned by key */
1049 #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
1051 error("unknown certificate key type");
1055 for (i = 0; i < 3; i++)
1056 free(cert_attr[i].pValue);
1059 #ifdef OPENSSL_HAS_ECC
1074 have_rsa_key(const RSA *rsa)
1076 const BIGNUM *rsa_n, *rsa_e;
1078 RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
1079 return rsa_n != NULL && rsa_e != NULL;
1084 note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context,
1089 if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
1090 SSH_FP_DEFAULT)) == NULL) {
1091 error_f("sshkey_fingerprint failed");
1094 debug2("%s: provider %s slot %lu: %s %s", context, p->name,
1095 (u_long)slotidx, sshkey_type(key), fp);
1100 * lookup certificates for token in slot identified by slotidx,
1101 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1102 * keysp points to an (possibly empty) array with *nkeys keys.
1105 pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
1106 struct sshkey ***keysp, char ***labelsp, int *nkeys)
1108 struct sshkey *key = NULL;
1109 CK_OBJECT_CLASS key_class;
1110 CK_ATTRIBUTE key_attr[1];
1111 CK_SESSION_HANDLE session;
1112 CK_FUNCTION_LIST *f = NULL;
1114 CK_OBJECT_HANDLE obj;
1119 memset(&key_attr, 0, sizeof(key_attr));
1120 memset(&obj, 0, sizeof(obj));
1122 key_class = CKO_CERTIFICATE;
1123 key_attr[0].type = CKA_CLASS;
1124 key_attr[0].pValue = &key_class;
1125 key_attr[0].ulValueLen = sizeof(key_class);
1127 session = p->slotinfo[slotidx].session;
1128 f = p->function_list;
1130 rv = f->C_FindObjectsInit(session, key_attr, 1);
1132 error("C_FindObjectsInit failed: %lu", rv);
1137 CK_CERTIFICATE_TYPE ck_cert_type;
1139 rv = f->C_FindObjects(session, &obj, 1, &n);
1141 error("C_FindObjects failed: %lu", rv);
1147 memset(&ck_cert_type, 0, sizeof(ck_cert_type));
1148 memset(&key_attr, 0, sizeof(key_attr));
1149 key_attr[0].type = CKA_CERTIFICATE_TYPE;
1150 key_attr[0].pValue = &ck_cert_type;
1151 key_attr[0].ulValueLen = sizeof(ck_cert_type);
1153 rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
1155 error("C_GetAttributeValue failed: %lu", rv);
1161 switch (ck_cert_type) {
1163 if (pkcs11_fetch_x509_pubkey(p, slotidx, &obj,
1164 &key, &label) != 0) {
1165 error("failed to fetch key");
1170 error("skipping unsupported certificate type %lu",
1174 note_key(p, slotidx, __func__, key);
1175 if (pkcs11_key_included(keysp, nkeys, key)) {
1176 debug2_f("key already included");;
1179 /* expand key array and add key */
1180 *keysp = xrecallocarray(*keysp, *nkeys,
1181 *nkeys + 1, sizeof(struct sshkey *));
1182 (*keysp)[*nkeys] = key;
1183 if (labelsp != NULL) {
1184 *labelsp = xrecallocarray(*labelsp, *nkeys,
1185 *nkeys + 1, sizeof(char *));
1186 (*labelsp)[*nkeys] = xstrdup((char *)label);
1188 *nkeys = *nkeys + 1;
1189 debug("have %d keys", *nkeys);
1195 rv = f->C_FindObjectsFinal(session);
1197 error("C_FindObjectsFinal failed: %lu", rv);
1205 * lookup public keys for token in slot identified by slotidx,
1206 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1207 * keysp points to an (possibly empty) array with *nkeys keys.
1210 pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
1211 struct sshkey ***keysp, char ***labelsp, int *nkeys)
1213 struct sshkey *key = NULL;
1214 CK_OBJECT_CLASS key_class;
1215 CK_ATTRIBUTE key_attr[2];
1216 CK_SESSION_HANDLE session;
1217 CK_FUNCTION_LIST *f = NULL;
1219 CK_OBJECT_HANDLE obj;
1223 memset(&key_attr, 0, sizeof(key_attr));
1224 memset(&obj, 0, sizeof(obj));
1226 key_class = CKO_PUBLIC_KEY;
1227 key_attr[0].type = CKA_CLASS;
1228 key_attr[0].pValue = &key_class;
1229 key_attr[0].ulValueLen = sizeof(key_class);
1231 session = p->slotinfo[slotidx].session;
1232 f = p->function_list;
1234 rv = f->C_FindObjectsInit(session, key_attr, 1);
1236 error("C_FindObjectsInit failed: %lu", rv);
1241 CK_KEY_TYPE ck_key_type;
1242 CK_UTF8CHAR label[256];
1244 rv = f->C_FindObjects(session, &obj, 1, &n);
1246 error("C_FindObjects failed: %lu", rv);
1252 memset(&ck_key_type, 0, sizeof(ck_key_type));
1253 memset(&key_attr, 0, sizeof(key_attr));
1254 key_attr[0].type = CKA_KEY_TYPE;
1255 key_attr[0].pValue = &ck_key_type;
1256 key_attr[0].ulValueLen = sizeof(ck_key_type);
1257 key_attr[1].type = CKA_LABEL;
1258 key_attr[1].pValue = &label;
1259 key_attr[1].ulValueLen = sizeof(label) - 1;
1261 rv = f->C_GetAttributeValue(session, obj, key_attr, 2);
1263 error("C_GetAttributeValue failed: %lu", rv);
1267 label[key_attr[1].ulValueLen] = '\0';
1269 switch (ck_key_type) {
1271 key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1273 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
1275 key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1277 #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
1279 /* XXX print key type? */
1281 error("skipping unsupported key type");
1285 error("failed to fetch key");
1288 note_key(p, slotidx, __func__, key);
1289 if (pkcs11_key_included(keysp, nkeys, key)) {
1290 debug2_f("key already included");;
1293 /* expand key array and add key */
1294 *keysp = xrecallocarray(*keysp, *nkeys,
1295 *nkeys + 1, sizeof(struct sshkey *));
1296 (*keysp)[*nkeys] = key;
1297 if (labelsp != NULL) {
1298 *labelsp = xrecallocarray(*labelsp, *nkeys,
1299 *nkeys + 1, sizeof(char *));
1300 (*labelsp)[*nkeys] = xstrdup((char *)label);
1302 *nkeys = *nkeys + 1;
1303 debug("have %d keys", *nkeys);
1309 rv = f->C_FindObjectsFinal(session);
1311 error("C_FindObjectsFinal failed: %lu", rv);
1318 #ifdef WITH_PKCS11_KEYGEN
1319 #define FILL_ATTR(attr, idx, typ, val, len) \
1320 { (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; }
1322 static struct sshkey *
1323 pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1324 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1326 struct pkcs11_slotinfo *si;
1327 char *plabel = label ? label : "";
1328 int npub = 0, npriv = 0;
1330 CK_FUNCTION_LIST *f;
1331 CK_SESSION_HANDLE session;
1332 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1333 CK_OBJECT_HANDLE pubKey, privKey;
1334 CK_ATTRIBUTE tpub[16], tpriv[16];
1335 CK_MECHANISM mech = {
1336 CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
1338 CK_BYTE pubExponent[] = {
1339 0x01, 0x00, 0x01 /* RSA_F4 in bytes */
1341 pubkey_filter[0].pValue = &pubkey_class;
1342 cert_filter[0].pValue = &cert_class;
1346 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1347 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1348 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1349 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1350 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1352 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1353 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1354 FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits));
1355 FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent,
1356 sizeof(pubExponent));
1357 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1359 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1360 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1361 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1362 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1363 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1364 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1365 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1367 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1368 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1369 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1371 f = p->function_list;
1372 si = &p->slotinfo[slotidx];
1373 session = si->session;
1375 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1376 &pubKey, &privKey)) != CKR_OK) {
1377 error_f("key generation failed: error 0x%lx", rv);
1382 return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey);
1386 pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen)
1396 if ((len = strlen(hex)) % 2)
1400 *dest = xmalloc(len);
1403 for (i = 0; i < len; i++) {
1404 ptr[0] = hex[2 * i];
1405 ptr[1] = hex[(2 * i) + 1];
1406 if (!isxdigit(ptr[0]) || !isxdigit(ptr[1]))
1408 (*dest)[i] = (unsigned char)strtoul(ptr, NULL, 16);
1417 static struct ec_curve_info {
1420 const char *oid_encoded;
1422 } ec_curve_infos[] = {
1423 {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
1424 {"secp384r1", "1.3.132.0.34", "06052B81040022", 384},
1425 {"secp521r1", "1.3.132.0.35", "06052B81040023", 521},
1426 {NULL, NULL, NULL, 0},
1429 static struct sshkey *
1430 pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1431 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1433 struct pkcs11_slotinfo *si;
1434 char *plabel = label ? label : "";
1436 size_t ecparams_size;
1437 unsigned char *ecparams = NULL;
1438 int npub = 0, npriv = 0;
1440 CK_FUNCTION_LIST *f;
1441 CK_SESSION_HANDLE session;
1442 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1443 CK_OBJECT_HANDLE pubKey, privKey;
1444 CK_MECHANISM mech = {
1445 CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
1447 CK_ATTRIBUTE tpub[16], tpriv[16];
1451 for (i = 0; ec_curve_infos[i].name; i++) {
1452 if (ec_curve_infos[i].size == bits)
1455 if (!ec_curve_infos[i].name) {
1456 error_f("invalid key size %lu", bits);
1459 if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams,
1460 &ecparams_size) == -1) {
1461 error_f("invalid oid");
1465 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1466 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1467 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1468 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1469 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1471 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1472 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1473 FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size);
1474 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1476 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1477 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1478 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1479 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1480 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1481 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1482 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1484 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1485 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1486 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1488 f = p->function_list;
1489 si = &p->slotinfo[slotidx];
1490 session = si->session;
1492 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1493 &pubKey, &privKey)) != CKR_OK) {
1494 error_f("key generation failed: error 0x%lx", rv);
1499 return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey);
1501 #endif /* WITH_PKCS11_KEYGEN */
1504 * register a new provider, fails if provider already exists. if
1505 * keyp is provided, fetch keys.
1508 pkcs11_register_provider(char *provider_id, char *pin,
1509 struct sshkey ***keyp, char ***labelsp,
1510 struct pkcs11_provider **providerp, CK_ULONG user)
1512 int nkeys, need_finalize = 0;
1514 struct pkcs11_provider *p = NULL;
1515 void *handle = NULL;
1516 CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
1518 CK_FUNCTION_LIST *f = NULL;
1519 CK_TOKEN_INFO *token;
1522 if (providerp == NULL)
1528 if (labelsp != NULL)
1531 if (pkcs11_provider_lookup(provider_id) != NULL) {
1532 debug_f("provider already registered: %s", provider_id);
1535 /* open shared pkcs11-library */
1536 if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
1537 error("dlopen %s failed: %s", provider_id, dlerror());
1540 if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL)
1541 fatal("dlsym(C_GetFunctionList) failed: %s", dlerror());
1542 p = xcalloc(1, sizeof(*p));
1543 p->name = xstrdup(provider_id);
1545 /* setup the pkcs11 callbacks */
1546 if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
1547 error("C_GetFunctionList for provider %s failed: %lu",
1551 p->function_list = f;
1552 if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
1553 error("C_Initialize for provider %s failed: %lu",
1558 if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
1559 error("C_GetInfo for provider %s failed: %lu",
1563 rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
1564 rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
1565 debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d"
1566 " libraryDescription <%s> libraryVersion %d.%d",
1568 p->info.manufacturerID,
1569 p->info.cryptokiVersion.major,
1570 p->info.cryptokiVersion.minor,
1571 p->info.libraryDescription,
1572 p->info.libraryVersion.major,
1573 p->info.libraryVersion.minor);
1574 if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
1575 error("C_GetSlotList failed: %lu", rv);
1578 if (p->nslots == 0) {
1579 debug_f("provider %s returned no slots", provider_id);
1580 ret = -SSH_PKCS11_ERR_NO_SLOTS;
1583 p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
1584 if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
1586 error("C_GetSlotList for provider %s failed: %lu",
1590 p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
1593 for (i = 0; i < p->nslots; i++) {
1594 token = &p->slotinfo[i].token;
1595 if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
1597 error("C_GetTokenInfo for provider %s slot %lu "
1598 "failed: %lu", provider_id, (u_long)i, rv);
1601 if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
1602 debug2_f("ignoring uninitialised token in "
1603 "provider %s slot %lu", provider_id, (u_long)i);
1606 rmspace(token->label, sizeof(token->label));
1607 rmspace(token->manufacturerID, sizeof(token->manufacturerID));
1608 rmspace(token->model, sizeof(token->model));
1609 rmspace(token->serialNumber, sizeof(token->serialNumber));
1610 debug("provider %s slot %lu: label <%s> manufacturerID <%s> "
1611 "model <%s> serial <%s> flags 0x%lx",
1612 provider_id, (unsigned long)i,
1613 token->label, token->manufacturerID, token->model,
1614 token->serialNumber, token->flags);
1616 * open session, login with pin and retrieve public
1617 * keys (if keyp is provided)
1619 if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 ||
1622 pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
1623 pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
1624 if (nkeys == 0 && !p->slotinfo[i].logged_in &&
1625 pkcs11_interactive) {
1627 * Some tokens require login before they will
1630 if (pkcs11_login_slot(p, &p->slotinfo[i],
1632 error("login failed");
1635 pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
1636 pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
1640 /* now owned by caller */
1643 TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
1644 p->refcount++; /* add to provider list */
1648 if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
1649 error("C_Finalize for provider %s failed: %lu",
1665 * register a new provider and get number of keys hold by the token,
1666 * fails if provider already exists
1669 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1672 struct pkcs11_provider *p = NULL;
1675 nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp,
1678 /* no keys found or some other error, de-register provider */
1679 if (nkeys <= 0 && p != NULL) {
1680 TAILQ_REMOVE(&pkcs11_providers, p, next);
1681 pkcs11_provider_finalize(p);
1682 pkcs11_provider_unref(p);
1685 debug_f("provider %s returned no keys", provider_id);
1690 #ifdef WITH_PKCS11_KEYGEN
1692 pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
1693 unsigned int type, unsigned int bits, unsigned char keyid, u_int32_t *err)
1695 struct pkcs11_provider *p = NULL;
1696 struct pkcs11_slotinfo *si;
1697 CK_FUNCTION_LIST *f;
1698 CK_SESSION_HANDLE session;
1699 struct sshkey *k = NULL;
1700 int ret = -1, reset_pin = 0, reset_provider = 0;
1705 if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
1706 debug_f("provider \"%s\" available", provider_id);
1707 else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, NULL,
1709 debug_f("could not register provider %s", provider_id);
1714 f = p->function_list;
1715 si = &p->slotinfo[slotidx];
1716 session = si->session;
1718 if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1719 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1720 debug_f("could not supply SO pin: %lu", rv);
1727 if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label,
1728 bits, keyid, err)) == NULL) {
1729 debug_f("failed to generate RSA key");
1734 if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label,
1735 bits, keyid, err)) == NULL) {
1736 debug_f("failed to generate ECDSA key");
1741 *err = SSH_PKCS11_ERR_GENERIC;
1742 debug_f("unknown type %d", type);
1748 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1752 pkcs11_del_provider(provider_id);
1758 pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
1759 unsigned char keyid, u_int32_t *err)
1761 struct pkcs11_provider *p = NULL;
1762 struct pkcs11_slotinfo *si;
1763 struct sshkey *k = NULL;
1764 int reset_pin = 0, reset_provider = 0;
1766 CK_FUNCTION_LIST *f;
1767 CK_SESSION_HANDLE session;
1768 CK_ATTRIBUTE attrs[16];
1769 CK_OBJECT_CLASS key_class;
1770 CK_KEY_TYPE key_type;
1771 CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE;
1776 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
1777 debug_f("using provider \"%s\"", provider_id);
1778 } else if (pkcs11_register_provider(provider_id, pin, NULL, NULL, &p,
1780 debug_f("could not register provider %s",
1786 f = p->function_list;
1787 si = &p->slotinfo[slotidx];
1788 session = si->session;
1790 if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1791 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1792 debug_f("could not supply SO pin: %lu", rv);
1799 key_class = CKO_PRIVATE_KEY;
1800 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1801 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1803 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1804 obj != CK_INVALID_HANDLE) {
1805 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1806 debug_f("could not destroy private key 0x%hhx",
1815 key_class = CKO_PUBLIC_KEY;
1816 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1817 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1819 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1820 obj != CK_INVALID_HANDLE) {
1824 FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type,
1826 rv = f->C_GetAttributeValue(session, obj, attrs, nattrs);
1828 debug_f("could not get key type of public key 0x%hhx",
1833 if (key_type == CKK_RSA)
1834 k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1835 else if (key_type == CKK_ECDSA)
1836 k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1838 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1839 debug_f("could not destroy public key 0x%hhx", keyid);
1847 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1851 pkcs11_del_provider(provider_id);
1855 #endif /* WITH_PKCS11_KEYGEN */
1856 #else /* ENABLE_PKCS11 */
1858 #include <sys/types.h>
1866 pkcs11_init(int interactive)
1868 error("%s: dlopen() not supported", __func__);
1873 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1876 error("%s: dlopen() not supported", __func__);
1881 pkcs11_terminate(void)
1883 error("%s: dlopen() not supported", __func__);
1885 #endif /* ENABLE_PKCS11 */