fix old typo (s/SYSVINITSTOPT/SYSVINITSTOP/)
[openssh.git] / ssh-pkcs11.c
blob31b9360f0adbc620296610307dbedea27b7426f4
1 /* $OpenBSD: ssh-pkcs11.c,v 1.64 2024/09/20 02:00:46 jsg Exp $ */
2 /*
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.
19 #include "includes.h"
21 #ifdef ENABLE_PKCS11
23 #ifdef HAVE_SYS_TIME_H
24 # include <sys/time.h>
25 #endif
27 #include <sys/types.h>
28 #include <stdarg.h>
29 #include <stdio.h>
31 #include <ctype.h>
32 #include <string.h>
33 #include <dlfcn.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
43 #include "pkcs11.h"
45 #include "log.h"
46 #include "misc.h"
47 #include "sshkey.h"
48 #include "ssh-pkcs11.h"
49 #include "digest.h"
50 #include "xmalloc.h"
52 struct pkcs11_slotinfo {
53 CK_TOKEN_INFO token;
54 CK_SESSION_HANDLE session;
55 int logged_in;
58 struct pkcs11_provider {
59 char *name;
60 void *handle;
61 CK_FUNCTION_LIST *function_list;
62 CK_INFO info;
63 CK_ULONG nslots;
64 CK_SLOT_ID *slotlist;
65 struct pkcs11_slotinfo *slotinfo;
66 int valid;
67 int refcount;
68 TAILQ_ENTRY(pkcs11_provider) next;
71 TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
73 struct pkcs11_key {
74 struct pkcs11_provider *provider;
75 CK_ULONG slotidx;
76 char *keyid;
77 int keyid_len;
80 int pkcs11_interactive = 0;
82 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
83 static void
84 ossl_error(const char *msg)
86 unsigned long e;
88 error_f("%s", 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 */
94 int
95 pkcs11_init(int interactive)
97 pkcs11_interactive = interactive;
98 TAILQ_INIT(&pkcs11_providers);
99 return (0);
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.
108 static void
109 pkcs11_provider_finalize(struct pkcs11_provider *p)
111 CK_RV rv;
112 CK_ULONG i;
114 debug_f("provider \"%s\" refcount %d valid %d",
115 p->name, p->refcount, p->valid);
116 if (!p->valid)
117 return;
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);
126 p->valid = 0;
127 p->function_list = NULL;
128 dlclose(p->handle);
132 * remove a reference to the provider.
133 * called when a key gets destroyed or when the provider is unregistered.
135 static void
136 pkcs11_provider_unref(struct pkcs11_provider *p)
138 debug_f("provider \"%s\" refcount %d", p->name, p->refcount);
139 if (--p->refcount <= 0) {
140 if (p->valid)
141 error_f("provider \"%s\" still valid", p->name);
142 free(p->name);
143 free(p->slotlist);
144 free(p->slotinfo);
145 free(p);
149 /* unregister all providers, keys might still point to the providers */
150 void
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))
171 return (p);
173 return (NULL);
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);
186 return (0);
188 return (-1);
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 */
199 static void
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);
206 if (k11 == NULL)
207 return;
208 if (k11->provider)
209 pkcs11_provider_unref(k11->provider);
210 free(k11->keyid);
211 free(k11);
214 /* find a single 'obj' for given attributes */
215 static int
216 pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
217 CK_ULONG nattr, CK_OBJECT_HANDLE *obj)
219 CK_FUNCTION_LIST *f;
220 CK_SESSION_HANDLE session;
221 CK_ULONG nfound = 0;
222 CK_RV rv;
223 int ret = -1;
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);
229 return (-1);
231 if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK ||
232 nfound != 1) {
233 debug("C_FindObjects failed (nfound %lu nattr %lu): %lu",
234 nfound, nattr, rv);
235 } else
236 ret = 0;
237 if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
238 error("C_FindObjectsFinal failed: %lu", rv);
239 return (ret);
242 static int
243 pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si,
244 CK_USER_TYPE type)
246 char *pin = NULL, prompt[1024];
247 CK_RV rv;
249 if (provider == NULL || si == NULL || !provider->valid) {
250 error("no pkcs11 (valid) provider found");
251 return (-1);
254 if (!pkcs11_interactive) {
255 error("need pin entry%s",
256 (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ?
257 " on reader keypad" : "");
258 return (-1);
260 if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
261 verbose("Deferring PIN entry to reader keypad.");
262 else {
263 snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ",
264 si->token.label);
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);
272 if (pin != NULL)
273 freezero(pin, strlen(pin));
275 switch (rv) {
276 case CKR_OK:
277 case CKR_USER_ALREADY_LOGGED_IN:
278 /* success */
279 break;
280 case CKR_PIN_LEN_RANGE:
281 error("PKCS#11 login failed: PIN length out of range");
282 return -1;
283 case CKR_PIN_INCORRECT:
284 error("PKCS#11 login failed: PIN incorrect");
285 return -1;
286 case CKR_PIN_LOCKED:
287 error("PKCS#11 login failed: PIN locked");
288 return -1;
289 default:
290 error("PKCS#11 login failed: error %lu", rv);
291 return -1;
293 si->logged_in = 1;
294 return (0);
297 static int
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");
302 return (-1);
305 return pkcs11_login_slot(k11->provider,
306 &k11->provider->slotinfo[k11->slotidx], type);
310 static int
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;
315 CK_FUNCTION_LIST *f;
316 CK_BBOOL flag = 0;
317 CK_ATTRIBUTE attr;
318 CK_RV rv;
320 *val = 0;
322 if (!k11->provider || !k11->provider->valid) {
323 error("no pkcs11 (valid) provider found");
324 return (-1);
327 f = k11->provider->function_list;
328 si = &k11->provider->slotinfo[k11->slotidx];
330 attr.type = type;
331 attr.pValue = &flag;
332 attr.ulValueLen = sizeof(flag);
334 rv = f->C_GetAttributeValue(si->session, obj, &attr, 1);
335 if (rv != CKR_OK) {
336 error("C_GetAttributeValue failed: %lu", rv);
337 return (-1);
339 *val = flag != 0;
340 debug_f("provider \"%s\" slot %lu object %lu: attrib %lu = %d",
341 k11->provider->name, k11->slotidx, obj, type, *val);
342 return (0);
345 static int
346 pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type)
348 struct pkcs11_slotinfo *si;
349 CK_FUNCTION_LIST *f;
350 CK_OBJECT_HANDLE obj;
351 CK_RV rv;
352 CK_OBJECT_CLASS private_key_class;
353 CK_BBOOL true_val;
354 CK_MECHANISM mech;
355 CK_ATTRIBUTE key_filter[3];
356 int always_auth = 0;
357 int did_login = 0;
359 if (!k11->provider || !k11->provider->valid) {
360 error("no pkcs11 (valid) provider found");
361 return (-1);
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");
370 return (-1);
372 did_login = 1;
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;
385 true_val = CK_TRUE;
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");
394 return (-1);
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);
404 return (-1);
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");
413 return (-1);
417 return (0);
420 /* openssl callback doing the actual signing operation */
421 static int
422 pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
423 int padding)
425 struct pkcs11_key *k11;
426 struct pkcs11_slotinfo *si;
427 CK_FUNCTION_LIST *f;
428 CK_ULONG tlen = 0;
429 CK_RV rv;
430 int rval = -1;
432 if ((k11 = RSA_get_ex_data(rsa, rsa_idx)) == NULL) {
433 error("RSA_get_ex_data failed");
434 return (-1);
437 if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
438 error("pkcs11_get_key failed");
439 return (-1);
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);
448 if (rv == CKR_OK)
449 rval = tlen;
450 else
451 error("C_Sign failed: %lu", rv);
453 return (rval);
456 static int
457 pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
458 int padding)
460 return (-1);
463 static int
464 pkcs11_rsa_start_wrapper(void)
466 if (rsa_method != NULL)
467 return (0);
468 rsa_method = RSA_meth_dup(RSA_get_default_method());
469 if (rsa_method == NULL)
470 return (-1);
471 rsa_idx = RSA_get_ex_new_index(0, "ssh-pkcs11-rsa",
472 NULL, NULL, pkcs11_k11_free);
473 if (rsa_idx == -1)
474 return (-1);
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");
479 return (-1);
481 return (0);
484 /* redirect private key operations for rsa key to pkcs11 token */
485 static int
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)
492 return (-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 if (RSA_set_method(rsa, rsa_method) != 1)
506 fatal_f("RSA_set_method failed");
507 if (RSA_set_ex_data(rsa, rsa_idx, k11) != 1)
508 fatal_f("RSA_set_ex_data failed");
509 return (0);
512 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
513 /* openssl callback doing the actual signing operation */
514 static ECDSA_SIG *
515 ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
516 const BIGNUM *rp, EC_KEY *ec)
518 struct pkcs11_key *k11;
519 struct pkcs11_slotinfo *si;
520 CK_FUNCTION_LIST *f;
521 CK_ULONG siglen = 0, bnlen;
522 CK_RV rv;
523 ECDSA_SIG *ret = NULL;
524 u_char *sig;
525 BIGNUM *r = NULL, *s = NULL;
527 if ((k11 = EC_KEY_get_ex_data(ec, ec_key_idx)) == NULL) {
528 ossl_error("EC_KEY_get_ex_data failed for ec");
529 return (NULL);
532 if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
533 error("pkcs11_get_key failed");
534 return (NULL);
537 f = k11->provider->function_list;
538 si = &k11->provider->slotinfo[k11->slotidx];
540 siglen = ECDSA_size(ec);
541 sig = xmalloc(siglen);
543 /* XXX handle CKR_BUFFER_TOO_SMALL */
544 rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &siglen);
545 if (rv != CKR_OK) {
546 error("C_Sign failed: %lu", rv);
547 goto done;
549 if (siglen < 64 || siglen > 132 || siglen % 2) {
550 error_f("bad signature length: %lu", (u_long)siglen);
551 goto done;
553 bnlen = siglen/2;
554 if ((ret = ECDSA_SIG_new()) == NULL) {
555 error("ECDSA_SIG_new failed");
556 goto done;
558 if ((r = BN_bin2bn(sig, bnlen, NULL)) == NULL ||
559 (s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) {
560 ossl_error("BN_bin2bn failed");
561 ECDSA_SIG_free(ret);
562 ret = NULL;
563 goto done;
565 if (!ECDSA_SIG_set0(ret, r, s)) {
566 error_f("ECDSA_SIG_set0 failed");
567 ECDSA_SIG_free(ret);
568 ret = NULL;
569 goto done;
571 r = s = NULL; /* now owned by ret */
572 /* success */
573 done:
574 BN_free(r);
575 BN_free(s);
576 free(sig);
578 return (ret);
581 static int
582 pkcs11_ecdsa_start_wrapper(void)
584 int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
585 unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
587 if (ec_key_method != NULL)
588 return (0);
589 ec_key_idx = EC_KEY_get_ex_new_index(0, "ssh-pkcs11-ecdsa",
590 NULL, NULL, pkcs11_k11_free);
591 if (ec_key_idx == -1)
592 return (-1);
593 ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
594 if (ec_key_method == NULL)
595 return (-1);
596 EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
597 EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
598 return (0);
601 static int
602 pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
603 CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
605 struct pkcs11_key *k11;
607 if (pkcs11_ecdsa_start_wrapper() == -1)
608 return (-1);
610 k11 = xcalloc(1, sizeof(*k11));
611 k11->provider = provider;
612 provider->refcount++; /* provider referenced by ECDSA key */
613 k11->slotidx = slotidx;
614 /* identify key object on smartcard */
615 k11->keyid_len = keyid_attrib->ulValueLen;
616 if (k11->keyid_len > 0) {
617 k11->keyid = xmalloc(k11->keyid_len);
618 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
620 if (EC_KEY_set_method(ec, ec_key_method) != 1)
621 fatal_f("EC_KEY_set_method failed");
622 if (EC_KEY_set_ex_data(ec, ec_key_idx, k11) != 1)
623 fatal_f("EC_KEY_set_ex_data failed");
625 return (0);
627 #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
629 /* remove trailing spaces */
630 static char *
631 rmspace(u_char *buf, size_t len)
633 size_t i;
635 if (len == 0)
636 return buf;
637 for (i = len - 1; i > 0; i--)
638 if (buf[i] == ' ')
639 buf[i] = '\0';
640 else
641 break;
642 return buf;
644 /* Used to printf fixed-width, space-padded, unterminated strings using %.*s */
645 #define RMSPACE(s) (int)sizeof(s), rmspace(s, sizeof(s))
648 * open a pkcs11 session and login if required.
649 * if pin == NULL we delay login until key use
651 static int
652 pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin,
653 CK_ULONG user)
655 struct pkcs11_slotinfo *si;
656 CK_FUNCTION_LIST *f;
657 CK_RV rv;
658 CK_SESSION_HANDLE session;
659 int login_required, ret;
661 f = p->function_list;
662 si = &p->slotinfo[slotidx];
664 login_required = si->token.flags & CKF_LOGIN_REQUIRED;
666 /* fail early before opening session */
667 if (login_required && !pkcs11_interactive &&
668 (pin == NULL || strlen(pin) == 0)) {
669 error("pin required");
670 return (-SSH_PKCS11_ERR_PIN_REQUIRED);
672 if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
673 CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) {
674 error("C_OpenSession failed: %lu", rv);
675 return (-1);
677 if (login_required && pin != NULL && strlen(pin) != 0) {
678 rv = f->C_Login(session, user, (u_char *)pin, strlen(pin));
679 if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
680 error("C_Login failed: %lu", rv);
681 ret = (rv == CKR_PIN_LOCKED) ?
682 -SSH_PKCS11_ERR_PIN_LOCKED :
683 -SSH_PKCS11_ERR_LOGIN_FAIL;
684 if ((rv = f->C_CloseSession(session)) != CKR_OK)
685 error("C_CloseSession failed: %lu", rv);
686 return (ret);
688 si->logged_in = 1;
690 si->session = session;
691 return (0);
694 static int
695 pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
697 int i;
699 for (i = 0; i < *nkeys; i++)
700 if (sshkey_equal(key, (*keysp)[i]))
701 return (1);
702 return (0);
705 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
706 static struct sshkey *
707 pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
708 CK_OBJECT_HANDLE *obj)
710 CK_ATTRIBUTE key_attr[3];
711 CK_SESSION_HANDLE session;
712 CK_FUNCTION_LIST *f = NULL;
713 CK_RV rv;
714 ASN1_OCTET_STRING *octet = NULL;
715 EC_KEY *ec = NULL;
716 EC_GROUP *group = NULL;
717 struct sshkey *key = NULL;
718 const unsigned char *attrp = NULL;
719 int i;
720 int nid;
722 memset(&key_attr, 0, sizeof(key_attr));
723 key_attr[0].type = CKA_ID;
724 key_attr[1].type = CKA_EC_POINT;
725 key_attr[2].type = CKA_EC_PARAMS;
727 session = p->slotinfo[slotidx].session;
728 f = p->function_list;
730 /* figure out size of the attributes */
731 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
732 if (rv != CKR_OK) {
733 error("C_GetAttributeValue failed: %lu", rv);
734 return (NULL);
738 * Allow CKA_ID (always first attribute) to be empty, but
739 * ensure that none of the others are zero length.
740 * XXX assumes CKA_ID is always first.
742 if (key_attr[1].ulValueLen == 0 ||
743 key_attr[2].ulValueLen == 0) {
744 error("invalid attribute length");
745 return (NULL);
748 /* allocate buffers for attributes */
749 for (i = 0; i < 3; i++)
750 if (key_attr[i].ulValueLen > 0)
751 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
753 /* retrieve ID, public point and curve parameters of EC key */
754 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
755 if (rv != CKR_OK) {
756 error("C_GetAttributeValue failed: %lu", rv);
757 goto fail;
760 ec = EC_KEY_new();
761 if (ec == NULL) {
762 error("EC_KEY_new failed");
763 goto fail;
766 attrp = key_attr[2].pValue;
767 group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
768 if (group == NULL) {
769 ossl_error("d2i_ECPKParameters failed");
770 goto fail;
773 if (EC_KEY_set_group(ec, group) == 0) {
774 ossl_error("EC_KEY_set_group failed");
775 goto fail;
778 if (key_attr[1].ulValueLen <= 2) {
779 error("CKA_EC_POINT too small");
780 goto fail;
783 attrp = key_attr[1].pValue;
784 octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen);
785 if (octet == NULL) {
786 ossl_error("d2i_ASN1_OCTET_STRING failed");
787 goto fail;
789 attrp = octet->data;
790 if (o2i_ECPublicKey(&ec, &attrp, octet->length) == NULL) {
791 ossl_error("o2i_ECPublicKey failed");
792 goto fail;
795 nid = sshkey_ecdsa_key_to_nid(ec);
796 if (nid < 0) {
797 error("couldn't get curve nid");
798 goto fail;
801 if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
802 goto fail;
804 key = sshkey_new(KEY_UNSPEC);
805 if (key == NULL) {
806 error("sshkey_new failed");
807 goto fail;
810 EVP_PKEY_free(key->pkey);
811 if ((key->pkey = EVP_PKEY_new()) == NULL)
812 fatal("EVP_PKEY_new failed");
813 if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1)
814 fatal("EVP_PKEY_set1_EC_KEY failed");
815 key->ecdsa_nid = nid;
816 key->type = KEY_ECDSA;
817 key->flags |= SSHKEY_FLAG_EXT;
819 fail:
820 for (i = 0; i < 3; i++)
821 free(key_attr[i].pValue);
822 if (ec)
823 EC_KEY_free(ec);
824 if (group)
825 EC_GROUP_free(group);
826 if (octet)
827 ASN1_OCTET_STRING_free(octet);
829 return (key);
831 #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
833 static struct sshkey *
834 pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
835 CK_OBJECT_HANDLE *obj)
837 CK_ATTRIBUTE key_attr[3];
838 CK_SESSION_HANDLE session;
839 CK_FUNCTION_LIST *f = NULL;
840 CK_RV rv;
841 RSA *rsa = NULL;
842 BIGNUM *rsa_n, *rsa_e;
843 struct sshkey *key = NULL;
844 int i;
846 memset(&key_attr, 0, sizeof(key_attr));
847 key_attr[0].type = CKA_ID;
848 key_attr[1].type = CKA_MODULUS;
849 key_attr[2].type = CKA_PUBLIC_EXPONENT;
851 session = p->slotinfo[slotidx].session;
852 f = p->function_list;
854 /* figure out size of the attributes */
855 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
856 if (rv != CKR_OK) {
857 error("C_GetAttributeValue failed: %lu", rv);
858 return (NULL);
862 * Allow CKA_ID (always first attribute) to be empty, but
863 * ensure that none of the others are zero length.
864 * XXX assumes CKA_ID is always first.
866 if (key_attr[1].ulValueLen == 0 ||
867 key_attr[2].ulValueLen == 0) {
868 error("invalid attribute length");
869 return (NULL);
872 /* allocate buffers for attributes */
873 for (i = 0; i < 3; i++)
874 if (key_attr[i].ulValueLen > 0)
875 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
877 /* retrieve ID, modulus and public exponent of RSA key */
878 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
879 if (rv != CKR_OK) {
880 error("C_GetAttributeValue failed: %lu", rv);
881 goto fail;
884 rsa = RSA_new();
885 if (rsa == NULL) {
886 error("RSA_new failed");
887 goto fail;
890 rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
891 rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
892 if (rsa_n == NULL || rsa_e == NULL) {
893 error("BN_bin2bn failed");
894 goto fail;
896 if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
897 fatal_f("set key");
898 rsa_n = rsa_e = NULL; /* transferred */
900 if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
901 goto fail;
903 key = sshkey_new(KEY_UNSPEC);
904 if (key == NULL) {
905 error("sshkey_new failed");
906 goto fail;
909 EVP_PKEY_free(key->pkey);
910 if ((key->pkey = EVP_PKEY_new()) == NULL)
911 fatal("EVP_PKEY_new failed");
912 if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1)
913 fatal("EVP_PKEY_set1_RSA failed");
914 key->type = KEY_RSA;
915 key->flags |= SSHKEY_FLAG_EXT;
917 fail:
918 for (i = 0; i < 3; i++)
919 free(key_attr[i].pValue);
920 RSA_free(rsa);
922 return (key);
925 static int
926 pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
927 CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp)
929 CK_ATTRIBUTE cert_attr[3];
930 CK_SESSION_HANDLE session;
931 CK_FUNCTION_LIST *f = NULL;
932 CK_RV rv;
933 X509 *x509 = NULL;
934 X509_NAME *x509_name = NULL;
935 EVP_PKEY *evp;
936 RSA *rsa = NULL;
937 #ifdef OPENSSL_HAS_ECC
938 EC_KEY *ec = NULL;
939 #endif
940 struct sshkey *key = NULL;
941 int i;
942 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
943 int nid;
944 #endif
945 const u_char *cp;
946 char *subject = NULL;
948 *keyp = NULL;
949 *labelp = NULL;
951 memset(&cert_attr, 0, sizeof(cert_attr));
952 cert_attr[0].type = CKA_ID;
953 cert_attr[1].type = CKA_SUBJECT;
954 cert_attr[2].type = CKA_VALUE;
956 session = p->slotinfo[slotidx].session;
957 f = p->function_list;
959 /* figure out size of the attributes */
960 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
961 if (rv != CKR_OK) {
962 error("C_GetAttributeValue failed: %lu", rv);
963 return -1;
967 * Allow CKA_ID (always first attribute) to be empty, but
968 * ensure that none of the others are zero length.
969 * XXX assumes CKA_ID is always first.
971 if (cert_attr[1].ulValueLen == 0 ||
972 cert_attr[2].ulValueLen == 0) {
973 error("invalid attribute length");
974 return -1;
977 /* allocate buffers for attributes */
978 for (i = 0; i < 3; i++)
979 if (cert_attr[i].ulValueLen > 0)
980 cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
982 /* retrieve ID, subject and value of certificate */
983 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
984 if (rv != CKR_OK) {
985 error("C_GetAttributeValue failed: %lu", rv);
986 goto out;
989 /* Decode DER-encoded cert subject */
990 cp = cert_attr[1].pValue;
991 if ((x509_name = d2i_X509_NAME(NULL, &cp,
992 cert_attr[1].ulValueLen)) == NULL ||
993 (subject = X509_NAME_oneline(x509_name, NULL, 0)) == NULL)
994 subject = xstrdup("invalid subject");
995 X509_NAME_free(x509_name);
997 cp = cert_attr[2].pValue;
998 if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) {
999 error("d2i_x509 failed");
1000 goto out;
1003 if ((evp = X509_get_pubkey(x509)) == NULL) {
1004 error("X509_get_pubkey failed");
1005 goto out;
1008 if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
1009 if (EVP_PKEY_get0_RSA(evp) == NULL) {
1010 error("invalid x509; no rsa key");
1011 goto out;
1013 if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
1014 error("RSAPublicKey_dup failed");
1015 goto out;
1018 if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
1019 goto out;
1021 key = sshkey_new(KEY_UNSPEC);
1022 if (key == NULL) {
1023 error("sshkey_new failed");
1024 goto out;
1027 EVP_PKEY_free(key->pkey);
1028 if ((key->pkey = EVP_PKEY_new()) == NULL)
1029 fatal("EVP_PKEY_new failed");
1030 if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1)
1031 fatal("EVP_PKEY_set1_RSA failed");
1032 key->type = KEY_RSA;
1033 key->flags |= SSHKEY_FLAG_EXT;
1034 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
1035 } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
1036 if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
1037 error("invalid x509; no ec key");
1038 goto out;
1040 if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
1041 error("EC_KEY_dup failed");
1042 goto out;
1045 nid = sshkey_ecdsa_key_to_nid(ec);
1046 if (nid < 0) {
1047 error("couldn't get curve nid");
1048 goto out;
1051 if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
1052 goto out;
1054 key = sshkey_new(KEY_UNSPEC);
1055 if (key == NULL) {
1056 error("sshkey_new failed");
1057 goto out;
1060 EVP_PKEY_free(key->pkey);
1061 if ((key->pkey = EVP_PKEY_new()) == NULL)
1062 fatal("EVP_PKEY_new failed");
1063 if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1)
1064 fatal("EVP_PKEY_set1_EC_KEY failed");
1065 key->ecdsa_nid = nid;
1066 key->type = KEY_ECDSA;
1067 key->flags |= SSHKEY_FLAG_EXT;
1068 #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
1069 } else {
1070 error("unknown certificate key type");
1071 goto out;
1073 out:
1074 for (i = 0; i < 3; i++)
1075 free(cert_attr[i].pValue);
1076 X509_free(x509);
1077 RSA_free(rsa);
1078 #ifdef OPENSSL_HAS_ECC
1079 EC_KEY_free(ec);
1080 #endif
1081 if (key == NULL) {
1082 free(subject);
1083 return -1;
1085 /* success */
1086 *keyp = key;
1087 *labelp = subject;
1088 return 0;
1091 #if 0
1092 static int
1093 have_rsa_key(const RSA *rsa)
1095 const BIGNUM *rsa_n, *rsa_e;
1097 RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
1098 return rsa_n != NULL && rsa_e != NULL;
1100 #endif
1102 static void
1103 note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context,
1104 struct sshkey *key)
1106 char *fp;
1108 if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
1109 SSH_FP_DEFAULT)) == NULL) {
1110 error_f("sshkey_fingerprint failed");
1111 return;
1113 debug2("%s: provider %s slot %lu: %s %s", context, p->name,
1114 (u_long)slotidx, sshkey_type(key), fp);
1115 free(fp);
1119 * lookup certificates for token in slot identified by slotidx,
1120 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1121 * keysp points to an (possibly empty) array with *nkeys keys.
1123 static int
1124 pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
1125 struct sshkey ***keysp, char ***labelsp, int *nkeys)
1127 struct sshkey *key = NULL;
1128 CK_OBJECT_CLASS key_class;
1129 CK_ATTRIBUTE key_attr[1];
1130 CK_SESSION_HANDLE session;
1131 CK_FUNCTION_LIST *f = NULL;
1132 CK_RV rv;
1133 CK_OBJECT_HANDLE obj;
1134 CK_ULONG n = 0;
1135 int ret = -1;
1136 char *label;
1138 memset(&key_attr, 0, sizeof(key_attr));
1139 memset(&obj, 0, sizeof(obj));
1141 key_class = CKO_CERTIFICATE;
1142 key_attr[0].type = CKA_CLASS;
1143 key_attr[0].pValue = &key_class;
1144 key_attr[0].ulValueLen = sizeof(key_class);
1146 session = p->slotinfo[slotidx].session;
1147 f = p->function_list;
1149 rv = f->C_FindObjectsInit(session, key_attr, 1);
1150 if (rv != CKR_OK) {
1151 error("C_FindObjectsInit failed: %lu", rv);
1152 goto fail;
1155 while (1) {
1156 CK_CERTIFICATE_TYPE ck_cert_type;
1158 rv = f->C_FindObjects(session, &obj, 1, &n);
1159 if (rv != CKR_OK) {
1160 error("C_FindObjects failed: %lu", rv);
1161 goto fail;
1163 if (n == 0)
1164 break;
1166 memset(&ck_cert_type, 0, sizeof(ck_cert_type));
1167 memset(&key_attr, 0, sizeof(key_attr));
1168 key_attr[0].type = CKA_CERTIFICATE_TYPE;
1169 key_attr[0].pValue = &ck_cert_type;
1170 key_attr[0].ulValueLen = sizeof(ck_cert_type);
1172 rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
1173 if (rv != CKR_OK) {
1174 error("C_GetAttributeValue failed: %lu", rv);
1175 goto fail;
1178 key = NULL;
1179 label = NULL;
1180 switch (ck_cert_type) {
1181 case CKC_X_509:
1182 if (pkcs11_fetch_x509_pubkey(p, slotidx, &obj,
1183 &key, &label) != 0) {
1184 error("failed to fetch key");
1185 continue;
1187 break;
1188 default:
1189 error("skipping unsupported certificate type %lu",
1190 ck_cert_type);
1191 continue;
1193 note_key(p, slotidx, __func__, key);
1194 if (pkcs11_key_included(keysp, nkeys, key)) {
1195 debug2_f("key already included");
1196 sshkey_free(key);
1197 } else {
1198 /* expand key array and add key */
1199 *keysp = xrecallocarray(*keysp, *nkeys,
1200 *nkeys + 1, sizeof(struct sshkey *));
1201 (*keysp)[*nkeys] = key;
1202 if (labelsp != NULL) {
1203 *labelsp = xrecallocarray(*labelsp, *nkeys,
1204 *nkeys + 1, sizeof(char *));
1205 (*labelsp)[*nkeys] = xstrdup((char *)label);
1207 *nkeys = *nkeys + 1;
1208 debug("have %d keys", *nkeys);
1212 ret = 0;
1213 fail:
1214 rv = f->C_FindObjectsFinal(session);
1215 if (rv != CKR_OK) {
1216 error("C_FindObjectsFinal failed: %lu", rv);
1217 ret = -1;
1220 return (ret);
1224 * lookup public keys for token in slot identified by slotidx,
1225 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1226 * keysp points to an (possibly empty) array with *nkeys keys.
1228 static int
1229 pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
1230 struct sshkey ***keysp, char ***labelsp, int *nkeys)
1232 struct sshkey *key = NULL;
1233 CK_OBJECT_CLASS key_class;
1234 CK_ATTRIBUTE key_attr[2];
1235 CK_SESSION_HANDLE session;
1236 CK_FUNCTION_LIST *f = NULL;
1237 CK_RV rv;
1238 CK_OBJECT_HANDLE obj;
1239 CK_ULONG n = 0;
1240 int ret = -1;
1242 memset(&key_attr, 0, sizeof(key_attr));
1243 memset(&obj, 0, sizeof(obj));
1245 key_class = CKO_PUBLIC_KEY;
1246 key_attr[0].type = CKA_CLASS;
1247 key_attr[0].pValue = &key_class;
1248 key_attr[0].ulValueLen = sizeof(key_class);
1250 session = p->slotinfo[slotidx].session;
1251 f = p->function_list;
1253 rv = f->C_FindObjectsInit(session, key_attr, 1);
1254 if (rv != CKR_OK) {
1255 error("C_FindObjectsInit failed: %lu", rv);
1256 goto fail;
1259 while (1) {
1260 CK_KEY_TYPE ck_key_type;
1261 CK_UTF8CHAR label[256];
1263 rv = f->C_FindObjects(session, &obj, 1, &n);
1264 if (rv != CKR_OK) {
1265 error("C_FindObjects failed: %lu", rv);
1266 goto fail;
1268 if (n == 0)
1269 break;
1271 memset(&ck_key_type, 0, sizeof(ck_key_type));
1272 memset(&key_attr, 0, sizeof(key_attr));
1273 key_attr[0].type = CKA_KEY_TYPE;
1274 key_attr[0].pValue = &ck_key_type;
1275 key_attr[0].ulValueLen = sizeof(ck_key_type);
1276 key_attr[1].type = CKA_LABEL;
1277 key_attr[1].pValue = &label;
1278 key_attr[1].ulValueLen = sizeof(label) - 1;
1280 rv = f->C_GetAttributeValue(session, obj, key_attr, 2);
1281 if (rv != CKR_OK) {
1282 error("C_GetAttributeValue failed: %lu", rv);
1283 goto fail;
1286 label[key_attr[1].ulValueLen] = '\0';
1288 switch (ck_key_type) {
1289 case CKK_RSA:
1290 key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1291 break;
1292 #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
1293 case CKK_ECDSA:
1294 key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1295 break;
1296 #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
1297 default:
1298 /* XXX print key type? */
1299 key = NULL;
1300 error("skipping unsupported key type");
1303 if (key == NULL) {
1304 error("failed to fetch key");
1305 continue;
1307 note_key(p, slotidx, __func__, key);
1308 if (pkcs11_key_included(keysp, nkeys, key)) {
1309 debug2_f("key already included");
1310 sshkey_free(key);
1311 } else {
1312 /* expand key array and add key */
1313 *keysp = xrecallocarray(*keysp, *nkeys,
1314 *nkeys + 1, sizeof(struct sshkey *));
1315 (*keysp)[*nkeys] = key;
1316 if (labelsp != NULL) {
1317 *labelsp = xrecallocarray(*labelsp, *nkeys,
1318 *nkeys + 1, sizeof(char *));
1319 (*labelsp)[*nkeys] = xstrdup((char *)label);
1321 *nkeys = *nkeys + 1;
1322 debug("have %d keys", *nkeys);
1326 ret = 0;
1327 fail:
1328 rv = f->C_FindObjectsFinal(session);
1329 if (rv != CKR_OK) {
1330 error("C_FindObjectsFinal failed: %lu", rv);
1331 ret = -1;
1334 return (ret);
1337 #ifdef WITH_PKCS11_KEYGEN
1338 #define FILL_ATTR(attr, idx, typ, val, len) \
1339 { (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; }
1341 static struct sshkey *
1342 pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1343 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1345 struct pkcs11_slotinfo *si;
1346 char *plabel = label ? label : "";
1347 int npub = 0, npriv = 0;
1348 CK_RV rv;
1349 CK_FUNCTION_LIST *f;
1350 CK_SESSION_HANDLE session;
1351 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1352 CK_OBJECT_HANDLE pubKey, privKey;
1353 CK_ATTRIBUTE tpub[16], tpriv[16];
1354 CK_MECHANISM mech = {
1355 CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
1357 CK_BYTE pubExponent[] = {
1358 0x01, 0x00, 0x01 /* RSA_F4 in bytes */
1360 pubkey_filter[0].pValue = &pubkey_class;
1361 cert_filter[0].pValue = &cert_class;
1363 *err = 0;
1365 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1366 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1367 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1368 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1369 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1370 sizeof(false_val));
1371 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1372 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1373 FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits));
1374 FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent,
1375 sizeof(pubExponent));
1376 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1378 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1379 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1380 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1381 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1382 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1383 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1384 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1385 sizeof(false_val));
1386 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1387 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1388 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1390 f = p->function_list;
1391 si = &p->slotinfo[slotidx];
1392 session = si->session;
1394 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1395 &pubKey, &privKey)) != CKR_OK) {
1396 error_f("key generation failed: error 0x%lx", rv);
1397 *err = rv;
1398 return NULL;
1401 return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey);
1404 static int
1405 h2i(char c)
1407 if (c >= '0' && c <= '9')
1408 return c - '0';
1409 else if (c >= 'a' && c <= 'f')
1410 return c - 'a' + 10;
1411 else if (c >= 'A' && c <= 'F')
1412 return c - 'A' + 10;
1413 else
1414 return -1;
1417 static int
1418 pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen)
1420 size_t i, len;
1422 if (dest)
1423 *dest = NULL;
1424 if (rlen)
1425 *rlen = 0;
1427 if ((len = strlen(hex)) % 2)
1428 return -1;
1429 len /= 2;
1431 *dest = xmalloc(len);
1433 for (i = 0; i < len; i++) {
1434 int hi, low;
1436 hi = h2i(hex[2 * i]);
1437 lo = h2i(hex[(2 * i) + 1]);
1438 if (hi == -1 || lo == -1)
1439 return -1;
1440 (*dest)[i] = (hi << 4) | lo;
1443 if (rlen)
1444 *rlen = len;
1446 return 0;
1449 static struct ec_curve_info {
1450 const char *name;
1451 const char *oid;
1452 const char *oid_encoded;
1453 size_t size;
1454 } ec_curve_infos[] = {
1455 {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
1456 {"secp384r1", "1.3.132.0.34", "06052B81040022", 384},
1457 {"secp521r1", "1.3.132.0.35", "06052B81040023", 521},
1458 {NULL, NULL, NULL, 0},
1461 static struct sshkey *
1462 pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1463 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1465 struct pkcs11_slotinfo *si;
1466 char *plabel = label ? label : "";
1467 int i;
1468 size_t ecparams_size;
1469 unsigned char *ecparams = NULL;
1470 int npub = 0, npriv = 0;
1471 CK_RV rv;
1472 CK_FUNCTION_LIST *f;
1473 CK_SESSION_HANDLE session;
1474 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1475 CK_OBJECT_HANDLE pubKey, privKey;
1476 CK_MECHANISM mech = {
1477 CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
1479 CK_ATTRIBUTE tpub[16], tpriv[16];
1481 *err = 0;
1483 for (i = 0; ec_curve_infos[i].name; i++) {
1484 if (ec_curve_infos[i].size == bits)
1485 break;
1487 if (!ec_curve_infos[i].name) {
1488 error_f("invalid key size %lu", bits);
1489 return NULL;
1491 if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams,
1492 &ecparams_size) == -1) {
1493 error_f("invalid oid");
1494 return NULL;
1497 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1498 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1499 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1500 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1501 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1502 sizeof(false_val));
1503 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1504 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1505 FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size);
1506 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1508 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1509 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1510 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1511 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1512 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1513 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1514 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1515 sizeof(false_val));
1516 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1517 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1518 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1520 f = p->function_list;
1521 si = &p->slotinfo[slotidx];
1522 session = si->session;
1524 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1525 &pubKey, &privKey)) != CKR_OK) {
1526 error_f("key generation failed: error 0x%lx", rv);
1527 *err = rv;
1528 return NULL;
1531 return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey);
1533 #endif /* WITH_PKCS11_KEYGEN */
1536 * register a new provider, fails if provider already exists. if
1537 * keyp is provided, fetch keys.
1539 static int
1540 pkcs11_register_provider(char *provider_id, char *pin,
1541 struct sshkey ***keyp, char ***labelsp,
1542 struct pkcs11_provider **providerp, CK_ULONG user)
1544 int nkeys, need_finalize = 0;
1545 int ret = -1;
1546 struct pkcs11_provider *p = NULL;
1547 void *handle = NULL;
1548 CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
1549 CK_RV rv;
1550 CK_FUNCTION_LIST *f = NULL;
1551 CK_TOKEN_INFO *token;
1552 CK_ULONG i;
1554 if (providerp == NULL)
1555 goto fail;
1556 *providerp = NULL;
1558 if (keyp != NULL)
1559 *keyp = NULL;
1560 if (labelsp != NULL)
1561 *labelsp = NULL;
1563 if (pkcs11_provider_lookup(provider_id) != NULL) {
1564 debug_f("provider already registered: %s", provider_id);
1565 goto fail;
1567 if (lib_contains_symbol(provider_id, "C_GetFunctionList") != 0) {
1568 error("provider %s is not a PKCS11 library", provider_id);
1569 goto fail;
1571 /* open shared pkcs11-library */
1572 if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
1573 error("dlopen %s failed: %s", provider_id, dlerror());
1574 goto fail;
1576 if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL)
1577 fatal("dlsym(C_GetFunctionList) failed: %s", dlerror());
1578 p = xcalloc(1, sizeof(*p));
1579 p->name = xstrdup(provider_id);
1580 p->handle = handle;
1581 /* setup the pkcs11 callbacks */
1582 if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
1583 error("C_GetFunctionList for provider %s failed: %lu",
1584 provider_id, rv);
1585 goto fail;
1587 p->function_list = f;
1588 if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
1589 error("C_Initialize for provider %s failed: %lu",
1590 provider_id, rv);
1591 goto fail;
1593 need_finalize = 1;
1594 if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
1595 error("C_GetInfo for provider %s failed: %lu",
1596 provider_id, rv);
1597 goto fail;
1599 debug("provider %s: manufacturerID <%.*s> cryptokiVersion %d.%d"
1600 " libraryDescription <%.*s> libraryVersion %d.%d",
1601 provider_id,
1602 RMSPACE(p->info.manufacturerID),
1603 p->info.cryptokiVersion.major,
1604 p->info.cryptokiVersion.minor,
1605 RMSPACE(p->info.libraryDescription),
1606 p->info.libraryVersion.major,
1607 p->info.libraryVersion.minor);
1608 if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
1609 error("C_GetSlotList failed: %lu", rv);
1610 goto fail;
1612 if (p->nslots == 0) {
1613 debug_f("provider %s returned no slots", provider_id);
1614 ret = -SSH_PKCS11_ERR_NO_SLOTS;
1615 goto fail;
1617 p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
1618 if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
1619 != CKR_OK) {
1620 error("C_GetSlotList for provider %s failed: %lu",
1621 provider_id, rv);
1622 goto fail;
1624 p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
1625 p->valid = 1;
1626 nkeys = 0;
1627 for (i = 0; i < p->nslots; i++) {
1628 token = &p->slotinfo[i].token;
1629 if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
1630 != CKR_OK) {
1631 error("C_GetTokenInfo for provider %s slot %lu "
1632 "failed: %lu", provider_id, (u_long)i, rv);
1633 continue;
1635 if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
1636 debug2_f("ignoring uninitialised token in "
1637 "provider %s slot %lu", provider_id, (u_long)i);
1638 continue;
1640 debug("provider %s slot %lu: label <%.*s> "
1641 "manufacturerID <%.*s> model <%.*s> serial <%.*s> "
1642 "flags 0x%lx",
1643 provider_id, (unsigned long)i,
1644 RMSPACE(token->label), RMSPACE(token->manufacturerID),
1645 RMSPACE(token->model), RMSPACE(token->serialNumber),
1646 token->flags);
1648 * open session, login with pin and retrieve public
1649 * keys (if keyp is provided)
1651 if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 ||
1652 keyp == NULL)
1653 continue;
1654 pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
1655 pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
1656 if (nkeys == 0 && !p->slotinfo[i].logged_in &&
1657 pkcs11_interactive) {
1659 * Some tokens require login before they will
1660 * expose keys.
1662 if (pkcs11_login_slot(p, &p->slotinfo[i],
1663 CKU_USER) < 0) {
1664 error("login failed");
1665 continue;
1667 pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
1668 pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
1672 /* now owned by caller */
1673 *providerp = p;
1675 TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
1676 p->refcount++; /* add to provider list */
1678 return (nkeys);
1679 fail:
1680 if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
1681 error("C_Finalize for provider %s failed: %lu",
1682 provider_id, rv);
1683 if (p) {
1684 free(p->name);
1685 free(p->slotlist);
1686 free(p->slotinfo);
1687 free(p);
1689 if (handle)
1690 dlclose(handle);
1691 if (ret > 0)
1692 ret = -1;
1693 return (ret);
1697 * register a new provider and get number of keys hold by the token,
1698 * fails if provider already exists
1701 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1702 char ***labelsp)
1704 struct pkcs11_provider *p = NULL;
1705 int nkeys;
1707 nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp,
1708 &p, CKU_USER);
1710 /* no keys found or some other error, de-register provider */
1711 if (nkeys <= 0 && p != NULL) {
1712 TAILQ_REMOVE(&pkcs11_providers, p, next);
1713 pkcs11_provider_finalize(p);
1714 pkcs11_provider_unref(p);
1716 if (nkeys == 0)
1717 debug_f("provider %s returned no keys", provider_id);
1719 return (nkeys);
1722 #ifdef WITH_PKCS11_KEYGEN
1723 struct sshkey *
1724 pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
1725 unsigned int type, unsigned int bits, unsigned char keyid, u_int32_t *err)
1727 struct pkcs11_provider *p = NULL;
1728 struct pkcs11_slotinfo *si;
1729 CK_FUNCTION_LIST *f;
1730 CK_SESSION_HANDLE session;
1731 struct sshkey *k = NULL;
1732 int ret = -1, reset_pin = 0, reset_provider = 0;
1733 CK_RV rv;
1735 *err = 0;
1737 if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
1738 debug_f("provider \"%s\" available", provider_id);
1739 else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, NULL,
1740 &p, CKU_SO)) < 0) {
1741 debug_f("could not register provider %s", provider_id);
1742 goto out;
1743 } else
1744 reset_provider = 1;
1746 f = p->function_list;
1747 si = &p->slotinfo[slotidx];
1748 session = si->session;
1750 if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1751 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1752 debug_f("could not supply SO pin: %lu", rv);
1753 reset_pin = 0;
1754 } else
1755 reset_pin = 1;
1757 switch (type) {
1758 case KEY_RSA:
1759 if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label,
1760 bits, keyid, err)) == NULL) {
1761 debug_f("failed to generate RSA key");
1762 goto out;
1764 break;
1765 case KEY_ECDSA:
1766 if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label,
1767 bits, keyid, err)) == NULL) {
1768 debug_f("failed to generate ECDSA key");
1769 goto out;
1771 break;
1772 default:
1773 *err = SSH_PKCS11_ERR_GENERIC;
1774 debug_f("unknown type %d", type);
1775 goto out;
1778 out:
1779 if (reset_pin)
1780 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1781 CK_INVALID_HANDLE);
1783 if (reset_provider)
1784 pkcs11_del_provider(provider_id);
1786 return (k);
1789 struct sshkey *
1790 pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
1791 unsigned char keyid, u_int32_t *err)
1793 struct pkcs11_provider *p = NULL;
1794 struct pkcs11_slotinfo *si;
1795 struct sshkey *k = NULL;
1796 int reset_pin = 0, reset_provider = 0;
1797 CK_ULONG nattrs;
1798 CK_FUNCTION_LIST *f;
1799 CK_SESSION_HANDLE session;
1800 CK_ATTRIBUTE attrs[16];
1801 CK_OBJECT_CLASS key_class;
1802 CK_KEY_TYPE key_type;
1803 CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE;
1804 CK_RV rv;
1806 *err = 0;
1808 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
1809 debug_f("using provider \"%s\"", provider_id);
1810 } else if (pkcs11_register_provider(provider_id, pin, NULL, NULL, &p,
1811 CKU_SO) < 0) {
1812 debug_f("could not register provider %s",
1813 provider_id);
1814 goto out;
1815 } else
1816 reset_provider = 1;
1818 f = p->function_list;
1819 si = &p->slotinfo[slotidx];
1820 session = si->session;
1822 if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1823 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1824 debug_f("could not supply SO pin: %lu", rv);
1825 reset_pin = 0;
1826 } else
1827 reset_pin = 1;
1829 /* private key */
1830 nattrs = 0;
1831 key_class = CKO_PRIVATE_KEY;
1832 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1833 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1835 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1836 obj != CK_INVALID_HANDLE) {
1837 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1838 debug_f("could not destroy private key 0x%hhx",
1839 keyid);
1840 *err = rv;
1841 goto out;
1845 /* public key */
1846 nattrs = 0;
1847 key_class = CKO_PUBLIC_KEY;
1848 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1849 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1851 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1852 obj != CK_INVALID_HANDLE) {
1854 /* get key type */
1855 nattrs = 0;
1856 FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type,
1857 sizeof(key_type));
1858 rv = f->C_GetAttributeValue(session, obj, attrs, nattrs);
1859 if (rv != CKR_OK) {
1860 debug_f("could not get key type of public key 0x%hhx",
1861 keyid);
1862 *err = rv;
1863 key_type = -1;
1865 if (key_type == CKK_RSA)
1866 k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1867 else if (key_type == CKK_ECDSA)
1868 k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1870 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1871 debug_f("could not destroy public key 0x%hhx", keyid);
1872 *err = rv;
1873 goto out;
1877 out:
1878 if (reset_pin)
1879 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1880 CK_INVALID_HANDLE);
1882 if (reset_provider)
1883 pkcs11_del_provider(provider_id);
1885 return (k);
1887 #endif /* WITH_PKCS11_KEYGEN */
1888 #else /* ENABLE_PKCS11 */
1890 #include <sys/types.h>
1891 #include <stdarg.h>
1892 #include <stdio.h>
1894 #include "log.h"
1895 #include "sshkey.h"
1898 pkcs11_init(int interactive)
1900 error("%s: dlopen() not supported", __func__);
1901 return (-1);
1905 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1906 char ***labelsp)
1908 error("%s: dlopen() not supported", __func__);
1909 return (-1);
1912 void
1913 pkcs11_terminate(void)
1915 error("%s: dlopen() not supported", __func__);
1917 #endif /* ENABLE_PKCS11 */