blob: c36d31604bbbd6b394fedd4211bc395d5c373f7f [file] [log] [blame]
djm@openbsd.org445cfce2019-01-20 23:05:52 +00001/* $OpenBSD: ssh-pkcs11.c,v 1.32 2019/01/20 23:05:52 djm Exp $ */
Damien Miller7ea845e2010-02-12 09:21:02 +11002/*
3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
djm@openbsd.org93f02102019-01-20 22:51:37 +00004 * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
Damien Miller7ea845e2010-02-12 09:21:02 +11005 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
Damien Miller8ad0fbd2010-02-12 09:49:06 +110019#include "includes.h"
20
Damien Millerdfa41562010-02-12 10:06:28 +110021#ifdef ENABLE_PKCS11
22
Damien Miller8ad0fbd2010-02-12 09:49:06 +110023#ifdef HAVE_SYS_TIME_H
24# include <sys/time.h>
25#endif
djm@openbsd.org93f02102019-01-20 22:51:37 +000026
27#include <sys/types.h>
Damien Miller7ea845e2010-02-12 09:21:02 +110028#include <stdarg.h>
29#include <stdio.h>
30
djm@openbsd.org93f02102019-01-20 22:51:37 +000031#include <ctype.h>
Damien Miller7ea845e2010-02-12 09:21:02 +110032#include <string.h>
33#include <dlfcn.h>
34
Damien Miller8ad0fbd2010-02-12 09:49:06 +110035#include "openbsd-compat/sys-queue.h"
Damien Miller48f54b92018-09-13 12:13:50 +100036#include "openbsd-compat/openssl-compat.h"
Damien Miller8ad0fbd2010-02-12 09:49:06 +110037
djm@openbsd.org93f02102019-01-20 22:51:37 +000038#include <openssl/ecdsa.h>
Damien Millerd2252c72013-11-04 07:41:48 +110039#include <openssl/x509.h>
djm@openbsd.org93f02102019-01-20 22:51:37 +000040#include <openssl/err.h>
Damien Millerd2252c72013-11-04 07:41:48 +110041
Damien Miller7ea845e2010-02-12 09:21:02 +110042#define CRYPTOKI_COMPAT
43#include "pkcs11.h"
44
45#include "log.h"
46#include "misc.h"
djm@openbsd.org1129dcf2015-01-15 09:40:00 +000047#include "sshkey.h"
Damien Miller7ea845e2010-02-12 09:21:02 +110048#include "ssh-pkcs11.h"
49#include "xmalloc.h"
50
51struct pkcs11_slotinfo {
52 CK_TOKEN_INFO token;
53 CK_SESSION_HANDLE session;
54 int logged_in;
55};
56
57struct pkcs11_provider {
58 char *name;
59 void *handle;
60 CK_FUNCTION_LIST *function_list;
61 CK_INFO info;
62 CK_ULONG nslots;
63 CK_SLOT_ID *slotlist;
64 struct pkcs11_slotinfo *slotinfo;
65 int valid;
66 int refcount;
67 TAILQ_ENTRY(pkcs11_provider) next;
68};
69
70TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
71
72struct pkcs11_key {
73 struct pkcs11_provider *provider;
74 CK_ULONG slotidx;
75 int (*orig_finish)(RSA *rsa);
djm@openbsd.org482d23b2018-09-13 02:08:33 +000076 RSA_METHOD *rsa_method;
djm@openbsd.org93f02102019-01-20 22:51:37 +000077 EC_KEY_METHOD *ec_key_method;
Damien Miller7ea845e2010-02-12 09:21:02 +110078 char *keyid;
79 int keyid_len;
80};
81
82int pkcs11_interactive = 0;
83
djm@openbsd.org93f02102019-01-20 22:51:37 +000084#ifdef HAVE_DLOPEN
85static void
86ossl_error(const char *msg)
87{
88 unsigned long e;
89
90 while ((e = ERR_get_error()) != 0)
91 error("%s: %s: %.100s", __func__, msg,
92 ERR_error_string(e, NULL));
93}
94#endif
95
Damien Miller7ea845e2010-02-12 09:21:02 +110096int
97pkcs11_init(int interactive)
98{
99 pkcs11_interactive = interactive;
100 TAILQ_INIT(&pkcs11_providers);
101 return (0);
102}
103
104/*
djm@openbsd.org93f02102019-01-20 22:51:37 +0000105 * finalize a provider shared library, it's no longer usable.
Damien Miller7ea845e2010-02-12 09:21:02 +1100106 * however, there might still be keys referencing this provider,
djm@openbsd.org93f02102019-01-20 22:51:37 +0000107 * so the actual freeing of memory is handled by pkcs11_provider_unref().
Damien Miller7ea845e2010-02-12 09:21:02 +1100108 * this is called when a provider gets unregistered.
109 */
110static void
111pkcs11_provider_finalize(struct pkcs11_provider *p)
112{
113 CK_RV rv;
114 CK_ULONG i;
115
116 debug("pkcs11_provider_finalize: %p refcount %d valid %d",
117 p, p->refcount, p->valid);
118 if (!p->valid)
119 return;
120 for (i = 0; i < p->nslots; i++) {
121 if (p->slotinfo[i].session &&
122 (rv = p->function_list->C_CloseSession(
123 p->slotinfo[i].session)) != CKR_OK)
124 error("C_CloseSession failed: %lu", rv);
125 }
126 if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
127 error("C_Finalize failed: %lu", rv);
128 p->valid = 0;
129 p->function_list = NULL;
130 dlclose(p->handle);
131}
132
133/*
134 * remove a reference to the provider.
135 * called when a key gets destroyed or when the provider is unregistered.
136 */
137static void
138pkcs11_provider_unref(struct pkcs11_provider *p)
139{
140 debug("pkcs11_provider_unref: %p refcount %d", p, p->refcount);
141 if (--p->refcount <= 0) {
142 if (p->valid)
143 error("pkcs11_provider_unref: %p still valid", p);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000144 free(p->name);
Darren Tuckera627d422013-06-02 07:31:17 +1000145 free(p->slotlist);
146 free(p->slotinfo);
147 free(p);
Damien Miller7ea845e2010-02-12 09:21:02 +1100148 }
149}
150
151/* unregister all providers, keys might still point to the providers */
152void
153pkcs11_terminate(void)
154{
155 struct pkcs11_provider *p;
156
157 while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
158 TAILQ_REMOVE(&pkcs11_providers, p, next);
159 pkcs11_provider_finalize(p);
160 pkcs11_provider_unref(p);
161 }
162}
163
164/* lookup provider by name */
165static struct pkcs11_provider *
166pkcs11_provider_lookup(char *provider_id)
167{
168 struct pkcs11_provider *p;
169
170 TAILQ_FOREACH(p, &pkcs11_providers, next) {
171 debug("check %p %s", p, p->name);
172 if (!strcmp(provider_id, p->name))
173 return (p);
174 }
175 return (NULL);
176}
177
178/* unregister provider by name */
179int
180pkcs11_del_provider(char *provider_id)
181{
182 struct pkcs11_provider *p;
183
184 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
185 TAILQ_REMOVE(&pkcs11_providers, p, next);
186 pkcs11_provider_finalize(p);
187 pkcs11_provider_unref(p);
188 return (0);
189 }
190 return (-1);
191}
192
193/* openssl callback for freeing an RSA key */
194static int
195pkcs11_rsa_finish(RSA *rsa)
196{
197 struct pkcs11_key *k11;
198 int rv = -1;
199
200 if ((k11 = RSA_get_app_data(rsa)) != NULL) {
201 if (k11->orig_finish)
202 rv = k11->orig_finish(rsa);
203 if (k11->provider)
204 pkcs11_provider_unref(k11->provider);
djm@openbsd.org482d23b2018-09-13 02:08:33 +0000205 RSA_meth_free(k11->rsa_method);
Darren Tuckera627d422013-06-02 07:31:17 +1000206 free(k11->keyid);
207 free(k11);
Damien Miller7ea845e2010-02-12 09:21:02 +1100208 }
209 return (rv);
210}
211
Damien Miller031c9102010-04-16 15:54:44 +1000212/* find a single 'obj' for given attributes */
213static int
214pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
215 CK_ULONG nattr, CK_OBJECT_HANDLE *obj)
216{
217 CK_FUNCTION_LIST *f;
218 CK_SESSION_HANDLE session;
219 CK_ULONG nfound = 0;
220 CK_RV rv;
221 int ret = -1;
222
223 f = p->function_list;
224 session = p->slotinfo[slotidx].session;
225 if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) {
226 error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv);
227 return (-1);
228 }
229 if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK ||
230 nfound != 1) {
231 debug("C_FindObjects failed (nfound %lu nattr %lu): %lu",
232 nfound, nattr, rv);
233 } else
234 ret = 0;
235 if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
236 error("C_FindObjectsFinal failed: %lu", rv);
237 return (ret);
238}
239
Damien Miller7ea845e2010-02-12 09:21:02 +1100240static int
djm@openbsd.org93f02102019-01-20 22:51:37 +0000241pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type)
Damien Miller7ea845e2010-02-12 09:21:02 +1100242{
Damien Miller7ea845e2010-02-12 09:21:02 +1100243 struct pkcs11_slotinfo *si;
244 CK_FUNCTION_LIST *f;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000245 CK_OBJECT_HANDLE obj;
246 CK_RV rv;
247 CK_OBJECT_CLASS private_key_class;
248 CK_BBOOL true_val;
249 CK_MECHANISM mech;
250 CK_ATTRIBUTE key_filter[3];
djm@openbsd.orga71ba582015-05-27 05:15:02 +0000251 char *pin = NULL, prompt[1024];
Damien Miller7ea845e2010-02-12 09:21:02 +1100252
Damien Miller7ea845e2010-02-12 09:21:02 +1100253 if (!k11->provider || !k11->provider->valid) {
djm@openbsd.org93f02102019-01-20 22:51:37 +0000254 error("no pkcs11 (valid) provider found");
Damien Miller7ea845e2010-02-12 09:21:02 +1100255 return (-1);
256 }
djm@openbsd.org93f02102019-01-20 22:51:37 +0000257
Damien Miller7ea845e2010-02-12 09:21:02 +1100258 f = k11->provider->function_list;
259 si = &k11->provider->slotinfo[k11->slotidx];
djm@openbsd.org93f02102019-01-20 22:51:37 +0000260
Damien Miller7ea845e2010-02-12 09:21:02 +1100261 if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
262 if (!pkcs11_interactive) {
djm@openbsd.orga71ba582015-05-27 05:15:02 +0000263 error("need pin entry%s", (si->token.flags &
264 CKF_PROTECTED_AUTHENTICATION_PATH) ?
265 " on reader keypad" : "");
Damien Miller7ea845e2010-02-12 09:21:02 +1100266 return (-1);
267 }
djm@openbsd.orga71ba582015-05-27 05:15:02 +0000268 if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
269 verbose("Deferring PIN entry to reader keypad.");
270 else {
271 snprintf(prompt, sizeof(prompt),
272 "Enter PIN for '%s': ", si->token.label);
273 pin = read_passphrase(prompt, RP_ALLOW_EOF);
274 if (pin == NULL)
275 return (-1); /* bail out */
276 }
277 rv = f->C_Login(si->session, CKU_USER, (u_char *)pin,
278 (pin != NULL) ? strlen(pin) : 0);
279 if (pin != NULL) {
280 explicit_bzero(pin, strlen(pin));
Darren Tuckera627d422013-06-02 07:31:17 +1000281 free(pin);
djm@openbsd.orga71ba582015-05-27 05:15:02 +0000282 }
283 if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
Damien Miller7ea845e2010-02-12 09:21:02 +1100284 error("C_Login failed: %lu", rv);
285 return (-1);
286 }
Damien Miller7ea845e2010-02-12 09:21:02 +1100287 si->logged_in = 1;
288 }
djm@openbsd.org93f02102019-01-20 22:51:37 +0000289
290 memset(&key_filter, 0, sizeof(key_filter));
291 private_key_class = CKO_PRIVATE_KEY;
292 key_filter[0].type = CKA_CLASS;
293 key_filter[0].pValue = &private_key_class;
294 key_filter[0].ulValueLen = sizeof(private_key_class);
295
296 key_filter[1].type = CKA_ID;
Damien Miller7ea845e2010-02-12 09:21:02 +1100297 key_filter[1].pValue = k11->keyid;
298 key_filter[1].ulValueLen = k11->keyid_len;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000299
300 true_val = CK_TRUE;
301 key_filter[2].type = CKA_SIGN;
302 key_filter[2].pValue = &true_val;
303 key_filter[2].ulValueLen = sizeof(true_val);
304
Damien Miller031c9102010-04-16 15:54:44 +1000305 /* try to find object w/CKA_SIGN first, retry w/o */
306 if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
307 pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
308 error("cannot find private key");
djm@openbsd.org93f02102019-01-20 22:51:37 +0000309 return (-1);
Damien Miller7ea845e2010-02-12 09:21:02 +1100310 }
djm@openbsd.org93f02102019-01-20 22:51:37 +0000311
312 memset(&mech, 0, sizeof(mech));
313 mech.mechanism = mech_type;
314 mech.pParameter = NULL_PTR;
315 mech.ulParameterLen = 0;
316
317 if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
318 error("C_SignInit failed: %lu", rv);
319 return (-1);
320 }
321
322 return (0);
323}
324
325/* openssl callback doing the actual signing operation */
326static int
327pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
328 int padding)
329{
330 struct pkcs11_key *k11;
331 struct pkcs11_slotinfo *si;
332 CK_FUNCTION_LIST *f;
333 CK_ULONG tlen = 0;
334 CK_RV rv;
335 int rval = -1;
336
337 if ((k11 = RSA_get_app_data(rsa)) == NULL) {
338 error("RSA_get_app_data failed for rsa %p", rsa);
339 return (-1);
340 }
341
342 if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
343 error("pkcs11_get_key failed");
344 return (-1);
345 }
346
347 f = k11->provider->function_list;
348 si = &k11->provider->slotinfo[k11->slotidx];
349 tlen = RSA_size(rsa);
350
351 /* XXX handle CKR_BUFFER_TOO_SMALL */
352 rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
353 if (rv == CKR_OK)
354 rval = tlen;
355 else
356 error("C_Sign failed: %lu", rv);
357
Damien Miller7ea845e2010-02-12 09:21:02 +1100358 return (rval);
359}
360
361static int
362pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
363 int padding)
364{
365 return (-1);
366}
367
368/* redirect private key operations for rsa key to pkcs11 token */
369static int
370pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
371 CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
372{
373 struct pkcs11_key *k11;
374 const RSA_METHOD *def = RSA_get_default_method();
375
376 k11 = xcalloc(1, sizeof(*k11));
377 k11->provider = provider;
378 provider->refcount++; /* provider referenced by RSA key */
379 k11->slotidx = slotidx;
380 /* identify key object on smartcard */
381 k11->keyid_len = keyid_attrib->ulValueLen;
djm@openbsd.orgd2d772f2016-02-12 00:20:30 +0000382 if (k11->keyid_len > 0) {
383 k11->keyid = xmalloc(k11->keyid_len);
384 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
385 }
djm@openbsd.org482d23b2018-09-13 02:08:33 +0000386 k11->rsa_method = RSA_meth_dup(def);
387 if (k11->rsa_method == NULL)
388 fatal("%s: RSA_meth_dup failed", __func__);
389 k11->orig_finish = RSA_meth_get_finish(def);
390 if (!RSA_meth_set1_name(k11->rsa_method, "pkcs11") ||
391 !RSA_meth_set_priv_enc(k11->rsa_method,
392 pkcs11_rsa_private_encrypt) ||
393 !RSA_meth_set_priv_dec(k11->rsa_method,
394 pkcs11_rsa_private_decrypt) ||
395 !RSA_meth_set_finish(k11->rsa_method, pkcs11_rsa_finish))
396 fatal("%s: setup pkcs11 method failed", __func__);
397 RSA_set_method(rsa, k11->rsa_method);
Damien Miller7ea845e2010-02-12 09:21:02 +1100398 RSA_set_app_data(rsa, k11);
399 return (0);
400}
401
djm@openbsd.org93f02102019-01-20 22:51:37 +0000402/* openssl callback doing the actual signing operation */
403static ECDSA_SIG *
404ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
405 const BIGNUM *rp, EC_KEY *ec)
406{
407 struct pkcs11_key *k11;
408 struct pkcs11_slotinfo *si;
409 CK_FUNCTION_LIST *f;
410 CK_ULONG siglen = 0, bnlen;
411 CK_RV rv;
412 ECDSA_SIG *ret = NULL;
413 u_char *sig;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000414
415 if ((k11 = EC_KEY_get_ex_data(ec, 0)) == NULL) {
416 ossl_error("EC_KEY_get_key_method_data failed for ec");
417 return (NULL);
418 }
419
420 if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
421 error("pkcs11_get_key failed");
422 return (NULL);
423 }
424
425 f = k11->provider->function_list;
426 si = &k11->provider->slotinfo[k11->slotidx];
427
428 siglen = ECDSA_size(ec);
429 sig = xmalloc(siglen);
430
431 /* XXX handle CKR_BUFFER_TOO_SMALL */
432 rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &siglen);
433 if (rv != CKR_OK) {
434 error("C_Sign failed: %lu", rv);
435 goto done;
436 }
djm@openbsd.org749aef32019-01-20 23:00:12 +0000437 if (siglen < 64 || siglen > 132 || siglen % 2) {
438 ossl_error("d2i_ECDSA_SIG failed");
439 goto done;
440 }
441 bnlen = siglen/2;
442 if ((ret = ECDSA_SIG_new()) == NULL) {
443 error("ECDSA_SIG_new failed");
444 goto done;
445 }
446 if (BN_bin2bn(sig, bnlen, ret->r) == NULL ||
447 BN_bin2bn(sig+bnlen, bnlen, ret->s) == NULL) {
448 ossl_error("d2i_ECDSA_SIG failed");
449 ECDSA_SIG_free(ret);
450 ret = NULL;
451 goto done;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000452 }
453 done:
454 free(sig);
455
456 return (ret);
457}
458
459static EC_KEY_METHOD *ec_key_method;
djm@openbsd.org445cfce2019-01-20 23:05:52 +0000460static int ec_key_idx = 0;
461
462static void
463pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
464 long argl, void *argp)
465{
466 struct pkcs11_key *k11 = ptr;
467
468 if (k11 == NULL)
469 return;
470 if (k11->provider)
471 pkcs11_provider_unref(k11->provider);
472 free(k11->keyid);
473 free(k11);
474}
djm@openbsd.org93f02102019-01-20 22:51:37 +0000475
476static int
477pkcs11_ecdsa_start_wrapper(void)
478{
479 int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
480 unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
481
482 if (ec_key_method != NULL)
483 return (0);
djm@openbsd.org445cfce2019-01-20 23:05:52 +0000484 ec_key_idx = EC_KEY_get_ex_new_index(0, "ssh-pkcs11-ecdsa",
485 NULL, NULL, pkcs11_k11_free);
486 if (ec_key_idx == -1)
487 return (-1);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000488 ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
489 if (ec_key_method == NULL)
490 return (-1);
491 EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
492 EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
493 return (0);
494}
495
496static int
497pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
498 CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
499{
500 struct pkcs11_key *k11;
501
502 if (pkcs11_ecdsa_start_wrapper() == -1)
503 return (-1);
504
505 k11 = xcalloc(1, sizeof(*k11));
506 k11->provider = provider;
507 provider->refcount++; /* provider referenced by ECDSA key */
508 k11->slotidx = slotidx;
509 /* identify key object on smartcard */
510 k11->keyid_len = keyid_attrib->ulValueLen;
511 k11->keyid = xmalloc(k11->keyid_len);
512 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
513 k11->ec_key_method = ec_key_method;
514
515 EC_KEY_set_method(ec, k11->ec_key_method);
djm@openbsd.org445cfce2019-01-20 23:05:52 +0000516 EC_KEY_set_ex_data(ec, ec_key_idx, k11);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000517
518 return (0);
519}
520
Damien Miller7ea845e2010-02-12 09:21:02 +1100521/* remove trailing spaces */
522static void
Damien Miller746d1a62013-07-18 16:13:02 +1000523rmspace(u_char *buf, size_t len)
Damien Miller7ea845e2010-02-12 09:21:02 +1100524{
525 size_t i;
526
527 if (!len)
528 return;
529 for (i = len - 1; i > 0; i--)
530 if (i == len - 1 || buf[i] == ' ')
531 buf[i] = '\0';
532 else
533 break;
534}
535
536/*
537 * open a pkcs11 session and login if required.
538 * if pin == NULL we delay login until key use
539 */
540static int
djm@openbsd.org93f02102019-01-20 22:51:37 +0000541pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin,
542 CK_ULONG user)
Damien Miller7ea845e2010-02-12 09:21:02 +1100543{
544 CK_RV rv;
545 CK_FUNCTION_LIST *f;
546 CK_SESSION_HANDLE session;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000547 int login_required, ret;
Damien Miller7ea845e2010-02-12 09:21:02 +1100548
549 f = p->function_list;
550 login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED;
551 if (pin && login_required && !strlen(pin)) {
552 error("pin required");
djm@openbsd.org93f02102019-01-20 22:51:37 +0000553 return (-SSH_PKCS11_ERR_PIN_REQUIRED);
Damien Miller7ea845e2010-02-12 09:21:02 +1100554 }
555 if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
556 CKF_SERIAL_SESSION, NULL, NULL, &session))
557 != CKR_OK) {
558 error("C_OpenSession failed: %lu", rv);
559 return (-1);
560 }
561 if (login_required && pin) {
djm@openbsd.org93f02102019-01-20 22:51:37 +0000562 rv = f->C_Login(session, user,
deraadt@openbsd.orgce4f59b2015-02-03 08:07:20 +0000563 (u_char *)pin, strlen(pin));
djm@openbsd.orgcb3bde32015-02-02 22:48:53 +0000564 if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
Damien Miller7ea845e2010-02-12 09:21:02 +1100565 error("C_Login failed: %lu", rv);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000566 ret = (rv == CKR_PIN_LOCKED) ?
567 -SSH_PKCS11_ERR_PIN_LOCKED :
568 -SSH_PKCS11_ERR_LOGIN_FAIL;
Damien Miller7ea845e2010-02-12 09:21:02 +1100569 if ((rv = f->C_CloseSession(session)) != CKR_OK)
570 error("C_CloseSession failed: %lu", rv);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000571 return (ret);
Damien Miller7ea845e2010-02-12 09:21:02 +1100572 }
573 p->slotinfo[slotidx].logged_in = 1;
574 }
575 p->slotinfo[slotidx].session = session;
576 return (0);
577}
578
Damien Millerd2252c72013-11-04 07:41:48 +1100579static int
djm@openbsd.org1129dcf2015-01-15 09:40:00 +0000580pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
Damien Millerd2252c72013-11-04 07:41:48 +1100581{
582 int i;
583
584 for (i = 0; i < *nkeys; i++)
djm@openbsd.org1129dcf2015-01-15 09:40:00 +0000585 if (sshkey_equal(key, (*keysp)[i]))
Damien Millerd2252c72013-11-04 07:41:48 +1100586 return (1);
587 return (0);
588}
589
djm@openbsd.org93f02102019-01-20 22:51:37 +0000590static struct sshkey *
591pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
592 CK_OBJECT_HANDLE *obj)
593{
594 CK_ATTRIBUTE key_attr[3];
595 CK_SESSION_HANDLE session;
596 CK_FUNCTION_LIST *f = NULL;
597 CK_RV rv;
djm@openbsd.org24757c12019-01-20 23:01:59 +0000598 ASN1_OCTET_STRING *octet = NULL;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000599 EC_KEY *ec = NULL;
600 EC_GROUP *group = NULL;
601 struct sshkey *key = NULL;
602 const unsigned char *attrp = NULL;
603 int i;
604 int nid;
605
606 memset(&key_attr, 0, sizeof(key_attr));
607 key_attr[0].type = CKA_ID;
608 key_attr[1].type = CKA_EC_POINT;
609 key_attr[2].type = CKA_EC_PARAMS;
610
611 session = p->slotinfo[slotidx].session;
612 f = p->function_list;
613
614 /* figure out size of the attributes */
615 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
616 if (rv != CKR_OK) {
617 error("C_GetAttributeValue failed: %lu", rv);
618 return (NULL);
619 }
620
621 /*
622 * Allow CKA_ID (always first attribute) to be empty, but
623 * ensure that none of the others are zero length.
624 * XXX assumes CKA_ID is always first.
625 */
626 if (key_attr[1].ulValueLen == 0 ||
627 key_attr[2].ulValueLen == 0) {
628 error("invalid attribute length");
629 return (NULL);
630 }
631
632 /* allocate buffers for attributes */
633 for (i = 0; i < 3; i++)
634 if (key_attr[i].ulValueLen > 0)
635 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
636
637 /* retrieve ID, public point and curve parameters of EC key */
638 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
639 if (rv != CKR_OK) {
640 error("C_GetAttributeValue failed: %lu", rv);
641 goto fail;
642 }
643
644 ec = EC_KEY_new();
645 if (ec == NULL) {
646 error("EC_KEY_new failed");
647 goto fail;
648 }
649
650 attrp = key_attr[2].pValue;
651 group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
652 if (group == NULL) {
653 ossl_error("d2i_ECPKParameters failed");
654 goto fail;
655 }
656
657 if (EC_KEY_set_group(ec, group) == 0) {
658 ossl_error("EC_KEY_set_group failed");
659 goto fail;
660 }
661
662 if (key_attr[1].ulValueLen <= 2) {
663 error("CKA_EC_POINT too small");
664 goto fail;
665 }
666
djm@openbsd.org24757c12019-01-20 23:01:59 +0000667 attrp = key_attr[1].pValue;
668 octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen);
669 if (octet == NULL) {
670 ossl_error("d2i_ASN1_OCTET_STRING failed");
671 goto fail;
672 }
673 attrp = octet->data;
674 if (o2i_ECPublicKey(&ec, &attrp, octet->length) == NULL) {
675 ossl_error("o2i_ECPublicKey failed");
676 goto fail;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000677 }
678
679 nid = sshkey_ecdsa_key_to_nid(ec);
680 if (nid < 0) {
681 error("couldn't get curve nid");
682 goto fail;
683 }
684
685 if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
686 goto fail;
687
688 key = sshkey_new(KEY_UNSPEC);
689 if (key == NULL) {
690 error("sshkey_new failed");
691 goto fail;
692 }
693
694 key->ecdsa = ec;
695 key->ecdsa_nid = nid;
696 key->type = KEY_ECDSA;
697 key->flags |= SSHKEY_FLAG_EXT;
698 ec = NULL; /* now owned by key */
699
700fail:
701 for (i = 0; i < 3; i++)
702 free(key_attr[i].pValue);
703 if (ec)
704 EC_KEY_free(ec);
705 if (group)
706 EC_GROUP_free(group);
djm@openbsd.org24757c12019-01-20 23:01:59 +0000707 if (octet)
708 ASN1_OCTET_STRING_free(octet);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000709
710 return (key);
711}
712
713static struct sshkey *
714pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
715 CK_OBJECT_HANDLE *obj)
716{
717 CK_ATTRIBUTE key_attr[3];
718 CK_SESSION_HANDLE session;
719 CK_FUNCTION_LIST *f = NULL;
720 CK_RV rv;
721 RSA *rsa = NULL;
722 BIGNUM *rsa_n, *rsa_e;
723 struct sshkey *key = NULL;
724 int i;
725
726 memset(&key_attr, 0, sizeof(key_attr));
727 key_attr[0].type = CKA_ID;
728 key_attr[1].type = CKA_MODULUS;
729 key_attr[2].type = CKA_PUBLIC_EXPONENT;
730
731 session = p->slotinfo[slotidx].session;
732 f = p->function_list;
733
734 /* figure out size of the attributes */
735 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
736 if (rv != CKR_OK) {
737 error("C_GetAttributeValue failed: %lu", rv);
738 return (NULL);
739 }
740
741 /*
742 * Allow CKA_ID (always first attribute) to be empty, but
743 * ensure that none of the others are zero length.
744 * XXX assumes CKA_ID is always first.
745 */
746 if (key_attr[1].ulValueLen == 0 ||
747 key_attr[2].ulValueLen == 0) {
748 error("invalid attribute length");
749 return (NULL);
750 }
751
752 /* allocate buffers for attributes */
753 for (i = 0; i < 3; i++)
754 if (key_attr[i].ulValueLen > 0)
755 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
756
757 /* retrieve ID, modulus and public exponent of RSA key */
758 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
759 if (rv != CKR_OK) {
760 error("C_GetAttributeValue failed: %lu", rv);
761 goto fail;
762 }
763
764 rsa = RSA_new();
765 if (rsa == NULL) {
766 error("RSA_new failed");
767 goto fail;
768 }
769
770 rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
771 rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
772 if (rsa_n == NULL || rsa_e == NULL) {
773 error("BN_bin2bn failed");
774 goto fail;
775 }
776 if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
777 fatal("%s: set key", __func__);
778 rsa_n = rsa_e = NULL; /* transferred */
779
780 if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
781 goto fail;
782
783 key = sshkey_new(KEY_UNSPEC);
784 if (key == NULL) {
785 error("sshkey_new failed");
786 goto fail;
787 }
788
789 key->rsa = rsa;
790 key->type = KEY_RSA;
791 key->flags |= SSHKEY_FLAG_EXT;
792 rsa = NULL; /* now owned by key */
793
794fail:
795 for (i = 0; i < 3; i++)
796 free(key_attr[i].pValue);
797 RSA_free(rsa);
798
799 return (key);
800}
801
802static struct sshkey *
803pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
804 CK_OBJECT_HANDLE *obj)
805{
806 CK_ATTRIBUTE cert_attr[3];
807 CK_SESSION_HANDLE session;
808 CK_FUNCTION_LIST *f = NULL;
809 CK_RV rv;
810 X509 *x509 = NULL;
811 EVP_PKEY *evp;
812 RSA *rsa = NULL;
813 EC_KEY *ec = NULL;
814 struct sshkey *key = NULL;
815 int i;
816 int nid;
817 const u_char *cp;
818
819 memset(&cert_attr, 0, sizeof(cert_attr));
820 cert_attr[0].type = CKA_ID;
821 cert_attr[1].type = CKA_SUBJECT;
822 cert_attr[2].type = CKA_VALUE;
823
824 session = p->slotinfo[slotidx].session;
825 f = p->function_list;
826
827 /* figure out size of the attributes */
828 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
829 if (rv != CKR_OK) {
830 error("C_GetAttributeValue failed: %lu", rv);
831 return (NULL);
832 }
833
834 /*
835 * Allow CKA_ID (always first attribute) to be empty, but
836 * ensure that none of the others are zero length.
837 * XXX assumes CKA_ID is always first.
838 */
839 if (cert_attr[1].ulValueLen == 0 ||
840 cert_attr[2].ulValueLen == 0) {
841 error("invalid attribute length");
842 return (NULL);
843 }
844
845 /* allocate buffers for attributes */
846 for (i = 0; i < 3; i++)
847 if (cert_attr[i].ulValueLen > 0)
848 cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
849
850 /* retrieve ID, subject and value of certificate */
851 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
852 if (rv != CKR_OK) {
853 error("C_GetAttributeValue failed: %lu", rv);
854 goto fail;
855 }
856
857 x509 = X509_new();
858 if (x509 == NULL) {
859 error("x509_new failed");
860 goto fail;
861 }
862
863 cp = cert_attr[2].pValue;
864 if (d2i_X509(&x509, &cp, cert_attr[2].ulValueLen) == NULL) {
865 error("d2i_x509 failed");
866 goto fail;
867 }
868
869 evp = X509_get_pubkey(x509);
870 if (evp == NULL) {
871 error("X509_get_pubkey failed");
872 goto fail;
873 }
874
875 if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
876 if (EVP_PKEY_get0_RSA(evp) == NULL) {
877 error("invalid x509; no rsa key");
878 goto fail;
879 }
880 if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
881 error("RSAPublicKey_dup failed");
882 goto fail;
883 }
884
885 if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
886 goto fail;
887
888 key = sshkey_new(KEY_UNSPEC);
889 if (key == NULL) {
890 error("sshkey_new failed");
891 goto fail;
892 }
893
894 key->rsa = rsa;
895 key->type = KEY_RSA;
896 key->flags |= SSHKEY_FLAG_EXT;
897 rsa = NULL; /* now owned by key */
898 } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
djm@openbsd.org8a246752019-01-20 23:03:26 +0000899 if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
djm@openbsd.org93f02102019-01-20 22:51:37 +0000900 error("invalid x509; no ec key");
901 goto fail;
902 }
djm@openbsd.org8a246752019-01-20 23:03:26 +0000903 if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
djm@openbsd.org93f02102019-01-20 22:51:37 +0000904 error("EC_KEY_dup failed");
905 goto fail;
906 }
907
908 nid = sshkey_ecdsa_key_to_nid(ec);
909 if (nid < 0) {
910 error("couldn't get curve nid");
911 goto fail;
912 }
913
914 if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
915 goto fail;
916
917 key = sshkey_new(KEY_UNSPEC);
918 if (key == NULL) {
919 error("sshkey_new failed");
920 goto fail;
921 }
922
923 key->ecdsa = ec;
924 key->ecdsa_nid = nid;
925 key->type = KEY_ECDSA;
926 key->flags |= SSHKEY_FLAG_EXT;
927 ec = NULL; /* now owned by key */
928 } else
929 error("unknown certificate key type");
930
931fail:
932 for (i = 0; i < 3; i++)
933 free(cert_attr[i].pValue);
934 X509_free(x509);
935 RSA_free(rsa);
936 EC_KEY_free(ec);
937
938 return (key);
939}
940
941#if 0
Damien Millerd2252c72013-11-04 07:41:48 +1100942static int
djm@openbsd.org482d23b2018-09-13 02:08:33 +0000943have_rsa_key(const RSA *rsa)
944{
945 const BIGNUM *rsa_n, *rsa_e;
946
947 RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
948 return rsa_n != NULL && rsa_e != NULL;
949}
djm@openbsd.org93f02102019-01-20 22:51:37 +0000950#endif
djm@openbsd.org482d23b2018-09-13 02:08:33 +0000951
djm@openbsd.org93f02102019-01-20 22:51:37 +0000952/*
953 * lookup certificates for token in slot identified by slotidx,
954 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
955 * keysp points to an (possibly empty) array with *nkeys keys.
956 */
djm@openbsd.org482d23b2018-09-13 02:08:33 +0000957static int
djm@openbsd.org93f02102019-01-20 22:51:37 +0000958pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
djm@openbsd.org1129dcf2015-01-15 09:40:00 +0000959 struct sshkey ***keysp, int *nkeys)
Damien Miller7ea845e2010-02-12 09:21:02 +1100960{
djm@openbsd.org93f02102019-01-20 22:51:37 +0000961 struct sshkey *key = NULL;
962 CK_OBJECT_CLASS key_class;
963 CK_ATTRIBUTE key_attr[1];
964 CK_SESSION_HANDLE session;
965 CK_FUNCTION_LIST *f = NULL;
966 CK_RV rv;
967 CK_OBJECT_HANDLE obj;
968 CK_ULONG n = 0;
969 int ret = -1;
Tim Rice179eee02010-03-04 12:48:05 -0800970
djm@openbsd.org93f02102019-01-20 22:51:37 +0000971 memset(&key_attr, 0, sizeof(key_attr));
972 memset(&obj, 0, sizeof(obj));
973
974 key_class = CKO_CERTIFICATE;
975 key_attr[0].type = CKA_CLASS;
976 key_attr[0].pValue = &key_class;
977 key_attr[0].ulValueLen = sizeof(key_class);
978
Damien Miller7ea845e2010-02-12 09:21:02 +1100979 session = p->slotinfo[slotidx].session;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000980 f = p->function_list;
981
982 rv = f->C_FindObjectsInit(session, key_attr, 1);
983 if (rv != CKR_OK) {
Damien Miller7ea845e2010-02-12 09:21:02 +1100984 error("C_FindObjectsInit failed: %lu", rv);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000985 goto fail;
Damien Miller7ea845e2010-02-12 09:21:02 +1100986 }
djm@openbsd.org93f02102019-01-20 22:51:37 +0000987
Damien Miller7ea845e2010-02-12 09:21:02 +1100988 while (1) {
djm@openbsd.org93f02102019-01-20 22:51:37 +0000989 CK_CERTIFICATE_TYPE ck_cert_type;
990
991 rv = f->C_FindObjects(session, &obj, 1, &n);
992 if (rv != CKR_OK) {
993 error("C_FindObjects failed: %lu", rv);
994 goto fail;
Damien Miller7ea845e2010-02-12 09:21:02 +1100995 }
djm@openbsd.org93f02102019-01-20 22:51:37 +0000996 if (n == 0)
Damien Miller7ea845e2010-02-12 09:21:02 +1100997 break;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000998
999 memset(&ck_cert_type, 0, sizeof(ck_cert_type));
1000 memset(&key_attr, 0, sizeof(key_attr));
1001 key_attr[0].type = CKA_CERTIFICATE_TYPE;
1002 key_attr[0].pValue = &ck_cert_type;
1003 key_attr[0].ulValueLen = sizeof(ck_cert_type);
1004
1005 rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
1006 if (rv != CKR_OK) {
Damien Miller7ea845e2010-02-12 09:21:02 +11001007 error("C_GetAttributeValue failed: %lu", rv);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001008 goto fail;
djm@openbsd.org63ebcd02015-07-18 08:02:17 +00001009 }
1010
djm@openbsd.org93f02102019-01-20 22:51:37 +00001011 switch (ck_cert_type) {
1012 case CKC_X_509:
1013 key = pkcs11_fetch_x509_pubkey(p, slotidx, &obj);
1014 break;
1015 default:
1016 /* XXX print key type? */
1017 error("skipping unsupported certificate type");
1018 }
djm@openbsd.org482d23b2018-09-13 02:08:33 +00001019
djm@openbsd.org93f02102019-01-20 22:51:37 +00001020 if (key == NULL) {
1021 error("failed to fetch key");
1022 continue;
1023 }
1024
1025 if (pkcs11_key_included(keysp, nkeys, key)) {
1026 sshkey_free(key);
Damien Miller7ea845e2010-02-12 09:21:02 +11001027 } else {
djm@openbsd.org93f02102019-01-20 22:51:37 +00001028 /* expand key array and add key */
1029 *keysp = xrecallocarray(*keysp, *nkeys,
1030 *nkeys + 1, sizeof(struct sshkey *));
1031 (*keysp)[*nkeys] = key;
1032 *nkeys = *nkeys + 1;
1033 debug("have %d keys", *nkeys);
Damien Millerd2252c72013-11-04 07:41:48 +11001034 }
Damien Miller7ea845e2010-02-12 09:21:02 +11001035 }
djm@openbsd.org93f02102019-01-20 22:51:37 +00001036
1037 ret = 0;
1038fail:
1039 rv = f->C_FindObjectsFinal(session);
1040 if (rv != CKR_OK) {
Damien Miller7ea845e2010-02-12 09:21:02 +11001041 error("C_FindObjectsFinal failed: %lu", rv);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001042 ret = -1;
1043 }
1044
1045 return (ret);
Damien Miller7ea845e2010-02-12 09:21:02 +11001046}
1047
djm@openbsd.org93f02102019-01-20 22:51:37 +00001048/*
1049 * lookup public keys for token in slot identified by slotidx,
1050 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1051 * keysp points to an (possibly empty) array with *nkeys keys.
1052 */
1053static int
1054pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
1055 struct sshkey ***keysp, int *nkeys)
1056{
1057 struct sshkey *key = NULL;
1058 CK_OBJECT_CLASS key_class;
1059 CK_ATTRIBUTE key_attr[1];
1060 CK_SESSION_HANDLE session;
1061 CK_FUNCTION_LIST *f = NULL;
1062 CK_RV rv;
1063 CK_OBJECT_HANDLE obj;
1064 CK_ULONG n = 0;
1065 int ret = -1;
1066
1067 memset(&key_attr, 0, sizeof(key_attr));
1068 memset(&obj, 0, sizeof(obj));
1069
1070 key_class = CKO_PUBLIC_KEY;
1071 key_attr[0].type = CKA_CLASS;
1072 key_attr[0].pValue = &key_class;
1073 key_attr[0].ulValueLen = sizeof(key_class);
1074
1075 session = p->slotinfo[slotidx].session;
1076 f = p->function_list;
1077
1078 rv = f->C_FindObjectsInit(session, key_attr, 1);
1079 if (rv != CKR_OK) {
1080 error("C_FindObjectsInit failed: %lu", rv);
1081 goto fail;
1082 }
1083
1084 while (1) {
1085 CK_KEY_TYPE ck_key_type;
1086
1087 rv = f->C_FindObjects(session, &obj, 1, &n);
1088 if (rv != CKR_OK) {
1089 error("C_FindObjects failed: %lu", rv);
1090 goto fail;
1091 }
1092 if (n == 0)
1093 break;
1094
1095 memset(&ck_key_type, 0, sizeof(ck_key_type));
1096 memset(&key_attr, 0, sizeof(key_attr));
1097 key_attr[0].type = CKA_KEY_TYPE;
1098 key_attr[0].pValue = &ck_key_type;
1099 key_attr[0].ulValueLen = sizeof(ck_key_type);
1100
1101 rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
1102 if (rv != CKR_OK) {
1103 error("C_GetAttributeValue failed: %lu", rv);
1104 goto fail;
1105 }
1106
1107 switch (ck_key_type) {
1108 case CKK_RSA:
1109 key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1110 break;
1111 case CKK_ECDSA:
1112 key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1113 break;
1114 default:
1115 /* XXX print key type? */
1116 error("skipping unsupported key type");
1117 }
1118
1119 if (key == NULL) {
1120 error("failed to fetch key");
1121 continue;
1122 }
1123
1124 if (pkcs11_key_included(keysp, nkeys, key)) {
1125 sshkey_free(key);
1126 } else {
1127 /* expand key array and add key */
1128 *keysp = xrecallocarray(*keysp, *nkeys,
1129 *nkeys + 1, sizeof(struct sshkey *));
1130 (*keysp)[*nkeys] = key;
1131 *nkeys = *nkeys + 1;
1132 debug("have %d keys", *nkeys);
1133 }
1134 }
1135
1136 ret = 0;
1137fail:
1138 rv = f->C_FindObjectsFinal(session);
1139 if (rv != CKR_OK) {
1140 error("C_FindObjectsFinal failed: %lu", rv);
1141 ret = -1;
1142 }
1143
1144 return (ret);
1145}
1146
1147#ifdef WITH_PKCS11_KEYGEN
1148#define FILL_ATTR(attr, idx, typ, val, len) \
1149 { (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; }
1150
1151static struct sshkey *
1152pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1153 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1154{
1155 struct pkcs11_slotinfo *si;
1156 char *plabel = label ? label : "";
1157 int npub = 0, npriv = 0;
1158 CK_RV rv;
1159 CK_FUNCTION_LIST *f;
1160 CK_SESSION_HANDLE session;
1161 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1162 CK_OBJECT_HANDLE pubKey, privKey;
1163 CK_ATTRIBUTE tpub[16], tpriv[16];
1164 CK_MECHANISM mech = {
1165 CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
1166 };
1167 CK_BYTE pubExponent[] = {
1168 0x01, 0x00, 0x01 /* RSA_F4 in bytes */
1169 };
1170 pubkey_filter[0].pValue = &pubkey_class;
1171 cert_filter[0].pValue = &cert_class;
1172
1173 *err = 0;
1174
1175 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1176 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1177 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1178 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1179 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1180 sizeof(false_val));
1181 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1182 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1183 FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits));
1184 FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent,
1185 sizeof(pubExponent));
1186 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1187
1188 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1189 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1190 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1191 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1192 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1193 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1194 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1195 sizeof(false_val));
1196 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1197 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1198 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1199
1200 f = p->function_list;
1201 si = &p->slotinfo[slotidx];
1202 session = si->session;
1203
1204 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1205 &pubKey, &privKey)) != CKR_OK) {
1206 error("%s: key generation failed: error 0x%lx", __func__, rv);
1207 *err = rv;
1208 return NULL;
1209 }
1210
1211 return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey);
1212}
1213
1214static int
1215pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen)
1216{
1217 size_t i, len;
1218 char ptr[3];
1219
1220 if (dest)
1221 *dest = NULL;
1222 if (rlen)
1223 *rlen = 0;
1224
1225 if ((len = strlen(hex)) % 2)
1226 return -1;
1227 len /= 2;
1228
1229 *dest = xmalloc(len);
1230
1231 ptr[2] = '\0';
1232 for (i = 0; i < len; i++) {
1233 ptr[0] = hex[2 * i];
1234 ptr[1] = hex[(2 * i) + 1];
1235 if (!isxdigit(ptr[0]) || !isxdigit(ptr[1]))
1236 return -1;
1237 (*dest)[i] = (unsigned char)strtoul(ptr, NULL, 16);
1238 }
1239
1240 if (rlen)
1241 *rlen = len;
1242
1243 return 0;
1244}
1245
1246static struct ec_curve_info {
1247 const char *name;
1248 const char *oid;
1249 const char *oid_encoded;
1250 size_t size;
1251} ec_curve_infos[] = {
1252 {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
1253 {"secp384r1", "1.3.132.0.34", "06052B81040022", 384},
1254 {"secp521r1", "1.3.132.0.35", "06052B81040023", 521},
1255 {NULL, NULL, NULL, 0},
1256};
1257
1258static struct sshkey *
1259pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1260 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1261{
1262 struct pkcs11_slotinfo *si;
1263 char *plabel = label ? label : "";
1264 int i;
1265 size_t ecparams_size;
1266 unsigned char *ecparams = NULL;
1267 int npub = 0, npriv = 0;
1268 CK_RV rv;
1269 CK_FUNCTION_LIST *f;
1270 CK_SESSION_HANDLE session;
1271 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1272 CK_OBJECT_HANDLE pubKey, privKey;
1273 CK_MECHANISM mech = {
1274 CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
1275 };
1276 CK_ATTRIBUTE tpub[16], tpriv[16];
1277
1278 *err = 0;
1279
1280 for (i = 0; ec_curve_infos[i].name; i++) {
1281 if (ec_curve_infos[i].size == bits)
1282 break;
1283 }
1284 if (!ec_curve_infos[i].name) {
1285 error("%s: invalid key size %lu", __func__, bits);
1286 return NULL;
1287 }
1288 if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams,
1289 &ecparams_size) == -1) {
1290 error("%s: invalid oid", __func__);
1291 return NULL;
1292 }
1293
1294 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1295 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1296 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1297 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1298 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1299 sizeof(false_val));
1300 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1301 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1302 FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size);
1303 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1304
1305 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1306 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1307 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1308 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1309 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1310 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1311 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1312 sizeof(false_val));
1313 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1314 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1315 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1316
1317 f = p->function_list;
1318 si = &p->slotinfo[slotidx];
1319 session = si->session;
1320
1321 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1322 &pubKey, &privKey)) != CKR_OK) {
1323 error("%s: key generation failed: error 0x%lx", __func__, rv);
1324 *err = rv;
1325 return NULL;
1326 }
1327
1328 return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey);
1329}
1330#endif /* WITH_PKCS11_KEYGEN */
1331
1332/*
1333 * register a new provider, fails if provider already exists. if
1334 * keyp is provided, fetch keys.
1335 */
1336static int
1337pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1338 struct pkcs11_provider **providerp, CK_ULONG user)
Damien Miller7ea845e2010-02-12 09:21:02 +11001339{
1340 int nkeys, need_finalize = 0;
djm@openbsd.org93f02102019-01-20 22:51:37 +00001341 int ret = -1;
Damien Miller7ea845e2010-02-12 09:21:02 +11001342 struct pkcs11_provider *p = NULL;
1343 void *handle = NULL;
1344 CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
1345 CK_RV rv;
1346 CK_FUNCTION_LIST *f = NULL;
1347 CK_TOKEN_INFO *token;
1348 CK_ULONG i;
1349
djm@openbsd.org93f02102019-01-20 22:51:37 +00001350 if (providerp == NULL)
1351 goto fail;
1352 *providerp = NULL;
1353
1354 if (keyp != NULL)
1355 *keyp = NULL;
1356
Damien Miller7ea845e2010-02-12 09:21:02 +11001357 if (pkcs11_provider_lookup(provider_id) != NULL) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001358 debug("%s: provider already registered: %s",
1359 __func__, provider_id);
Damien Miller7ea845e2010-02-12 09:21:02 +11001360 goto fail;
1361 }
djm@openbsd.org93f02102019-01-20 22:51:37 +00001362 /* open shared pkcs11-library */
Damien Miller7ea845e2010-02-12 09:21:02 +11001363 if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
1364 error("dlopen %s failed: %s", provider_id, dlerror());
1365 goto fail;
1366 }
1367 if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
1368 error("dlsym(C_GetFunctionList) failed: %s", dlerror());
1369 goto fail;
1370 }
1371 p = xcalloc(1, sizeof(*p));
1372 p->name = xstrdup(provider_id);
1373 p->handle = handle;
1374 /* setup the pkcs11 callbacks */
1375 if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001376 error("C_GetFunctionList for provider %s failed: %lu",
1377 provider_id, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001378 goto fail;
1379 }
1380 p->function_list = f;
1381 if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001382 error("C_Initialize for provider %s failed: %lu",
1383 provider_id, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001384 goto fail;
1385 }
1386 need_finalize = 1;
1387 if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001388 error("C_GetInfo for provider %s failed: %lu",
1389 provider_id, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001390 goto fail;
1391 }
1392 rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
1393 rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001394 debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d"
Damien Miller7ea845e2010-02-12 09:21:02 +11001395 " libraryDescription <%s> libraryVersion %d.%d",
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001396 provider_id,
Damien Miller7ea845e2010-02-12 09:21:02 +11001397 p->info.manufacturerID,
1398 p->info.cryptokiVersion.major,
1399 p->info.cryptokiVersion.minor,
1400 p->info.libraryDescription,
1401 p->info.libraryVersion.major,
1402 p->info.libraryVersion.minor);
1403 if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
1404 error("C_GetSlotList failed: %lu", rv);
1405 goto fail;
1406 }
1407 if (p->nslots == 0) {
djm@openbsd.org93f02102019-01-20 22:51:37 +00001408 error("%s: provider %s returned no slots", __func__,
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001409 provider_id);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001410 ret = -SSH_PKCS11_ERR_NO_SLOTS;
Damien Miller7ea845e2010-02-12 09:21:02 +11001411 goto fail;
1412 }
1413 p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
1414 if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
1415 != CKR_OK) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001416 error("C_GetSlotList for provider %s failed: %lu",
1417 provider_id, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001418 goto fail;
1419 }
1420 p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
1421 p->valid = 1;
1422 nkeys = 0;
1423 for (i = 0; i < p->nslots; i++) {
1424 token = &p->slotinfo[i].token;
1425 if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
1426 != CKR_OK) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001427 error("C_GetTokenInfo for provider %s slot %lu "
1428 "failed: %lu", provider_id, (unsigned long)i, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001429 continue;
1430 }
djm@openbsd.orgb15fd982015-07-18 08:00:21 +00001431 if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001432 debug2("%s: ignoring uninitialised token in "
1433 "provider %s slot %lu", __func__,
1434 provider_id, (unsigned long)i);
djm@openbsd.orgb15fd982015-07-18 08:00:21 +00001435 continue;
1436 }
Damien Miller7ea845e2010-02-12 09:21:02 +11001437 rmspace(token->label, sizeof(token->label));
1438 rmspace(token->manufacturerID, sizeof(token->manufacturerID));
1439 rmspace(token->model, sizeof(token->model));
1440 rmspace(token->serialNumber, sizeof(token->serialNumber));
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001441 debug("provider %s slot %lu: label <%s> manufacturerID <%s> "
1442 "model <%s> serial <%s> flags 0x%lx",
1443 provider_id, (unsigned long)i,
Damien Miller7ea845e2010-02-12 09:21:02 +11001444 token->label, token->manufacturerID, token->model,
1445 token->serialNumber, token->flags);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001446 /*
1447 * open session, login with pin and retrieve public
1448 * keys (if keyp is provided)
1449 */
1450 if ((ret = pkcs11_open_session(p, i, pin, user)) == 0) {
1451 if (keyp == NULL)
1452 continue;
Damien Miller7ea845e2010-02-12 09:21:02 +11001453 pkcs11_fetch_keys(p, i, keyp, &nkeys);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001454 pkcs11_fetch_certs(p, i, keyp, &nkeys);
1455 }
Damien Miller7ea845e2010-02-12 09:21:02 +11001456 }
djm@openbsd.org93f02102019-01-20 22:51:37 +00001457
1458 /* now owned by caller */
1459 *providerp = p;
1460
1461 TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
1462 p->refcount++; /* add to provider list */
1463
1464 return (nkeys);
Damien Miller7ea845e2010-02-12 09:21:02 +11001465fail:
1466 if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001467 error("C_Finalize for provider %s failed: %lu",
1468 provider_id, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001469 if (p) {
djm@openbsd.org93f02102019-01-20 22:51:37 +00001470 free(p->name);
Darren Tuckera627d422013-06-02 07:31:17 +10001471 free(p->slotlist);
1472 free(p->slotinfo);
1473 free(p);
Damien Miller7ea845e2010-02-12 09:21:02 +11001474 }
1475 if (handle)
1476 dlclose(handle);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001477 return (ret);
Damien Miller7ea845e2010-02-12 09:21:02 +11001478}
Damien Millerdfa41562010-02-12 10:06:28 +11001479
djm@openbsd.org93f02102019-01-20 22:51:37 +00001480/*
1481 * register a new provider and get number of keys hold by the token,
1482 * fails if provider already exists
1483 */
1484int
1485pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
1486{
1487 struct pkcs11_provider *p = NULL;
1488 int nkeys;
Darren Tucker0dd24e02011-09-04 19:59:26 +10001489
djm@openbsd.org93f02102019-01-20 22:51:37 +00001490 nkeys = pkcs11_register_provider(provider_id, pin, keyp, &p, CKU_USER);
1491
1492 /* no keys found or some other error, de-register provider */
1493 if (nkeys <= 0 && p != NULL) {
1494 TAILQ_REMOVE(&pkcs11_providers, p, next);
1495 pkcs11_provider_finalize(p);
1496 pkcs11_provider_unref(p);
1497 }
1498 if (nkeys == 0)
1499 debug("%s: provider %s returned no keys", __func__,
1500 provider_id);
1501
1502 return (nkeys);
1503}
1504
1505#ifdef WITH_PKCS11_KEYGEN
1506struct sshkey *
1507pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
1508 unsigned int type, unsigned int bits, unsigned char keyid, u_int32_t *err)
1509{
1510 struct pkcs11_provider *p = NULL;
1511 struct pkcs11_slotinfo *si;
1512 CK_FUNCTION_LIST *f;
1513 CK_SESSION_HANDLE session;
1514 struct sshkey *k = NULL;
1515 int ret = -1, reset_pin = 0, reset_provider = 0;
1516 CK_RV rv;
1517
1518 *err = 0;
1519
1520 if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
1521 debug("%s: provider \"%s\" available", __func__, provider_id);
1522 else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, &p,
1523 CKU_SO)) < 0) {
1524 debug("%s: could not register provider %s", __func__,
1525 provider_id);
1526 goto out;
1527 } else
1528 reset_provider = 1;
1529
1530 f = p->function_list;
1531 si = &p->slotinfo[slotidx];
1532 session = si->session;
1533
1534 if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1535 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1536 debug("%s: could not supply SO pin: %lu", __func__, rv);
1537 reset_pin = 0;
1538 } else
1539 reset_pin = 1;
1540
1541 switch (type) {
1542 case KEY_RSA:
1543 if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label,
1544 bits, keyid, err)) == NULL) {
1545 debug("%s: failed to generate RSA key", __func__);
1546 goto out;
1547 }
1548 break;
1549 case KEY_ECDSA:
1550 if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label,
1551 bits, keyid, err)) == NULL) {
1552 debug("%s: failed to generate ECDSA key", __func__);
1553 goto out;
1554 }
1555 break;
1556 default:
1557 *err = SSH_PKCS11_ERR_GENERIC;
1558 debug("%s: unknown type %d", __func__, type);
1559 goto out;
1560 }
1561
1562out:
1563 if (reset_pin)
1564 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1565 CK_INVALID_HANDLE);
1566
1567 if (reset_provider)
1568 pkcs11_del_provider(provider_id);
1569
1570 return (k);
1571}
1572
1573struct sshkey *
1574pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
1575 unsigned char keyid, u_int32_t *err)
1576{
1577 struct pkcs11_provider *p = NULL;
1578 struct pkcs11_slotinfo *si;
1579 struct sshkey *k = NULL;
1580 int reset_pin = 0, reset_provider = 0;
1581 CK_ULONG nattrs;
1582 CK_FUNCTION_LIST *f;
1583 CK_SESSION_HANDLE session;
1584 CK_ATTRIBUTE attrs[16];
1585 CK_OBJECT_CLASS key_class;
1586 CK_KEY_TYPE key_type;
1587 CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE;
1588 CK_RV rv;
1589
1590 *err = 0;
1591
1592 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
1593 debug("%s: using provider \"%s\"", __func__, provider_id);
1594 } else if (pkcs11_register_provider(provider_id, pin, NULL, &p,
1595 CKU_SO) < 0) {
1596 debug("%s: could not register provider %s", __func__,
1597 provider_id);
1598 goto out;
1599 } else
1600 reset_provider = 1;
1601
1602 f = p->function_list;
1603 si = &p->slotinfo[slotidx];
1604 session = si->session;
1605
1606 if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1607 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1608 debug("%s: could not supply SO pin: %lu", __func__, rv);
1609 reset_pin = 0;
1610 } else
1611 reset_pin = 1;
1612
1613 /* private key */
1614 nattrs = 0;
1615 key_class = CKO_PRIVATE_KEY;
1616 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1617 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1618
1619 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1620 obj != CK_INVALID_HANDLE) {
1621 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1622 debug("%s: could not destroy private key 0x%hhx",
1623 __func__, keyid);
1624 *err = rv;
1625 goto out;
1626 }
1627 }
1628
1629 /* public key */
1630 nattrs = 0;
1631 key_class = CKO_PUBLIC_KEY;
1632 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1633 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1634
1635 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1636 obj != CK_INVALID_HANDLE) {
1637
1638 /* get key type */
1639 nattrs = 0;
1640 FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type,
1641 sizeof(key_type));
1642 rv = f->C_GetAttributeValue(session, obj, attrs, nattrs);
1643 if (rv != CKR_OK) {
1644 debug("%s: could not get key type of public key 0x%hhx",
1645 __func__, keyid);
1646 *err = rv;
1647 key_type = -1;
1648 }
1649 if (key_type == CKK_RSA)
1650 k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1651 else if (key_type == CKK_ECDSA)
1652 k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1653
1654 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1655 debug("%s: could not destroy public key 0x%hhx",
1656 __func__, keyid);
1657 *err = rv;
1658 goto out;
1659 }
1660 }
1661
1662out:
1663 if (reset_pin)
1664 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1665 CK_INVALID_HANDLE);
1666
1667 if (reset_provider)
1668 pkcs11_del_provider(provider_id);
1669
1670 return (k);
1671}
1672#endif /* WITH_PKCS11_KEYGEN */
1673#else /* HAVE_DLOPEN */
Darren Tucker0dd24e02011-09-04 19:59:26 +10001674int
1675pkcs11_init(int interactive)
1676{
djm@openbsd.org93f02102019-01-20 22:51:37 +00001677 error("%s: dlopen() not supported", __func__);
1678 return (-1);
1679}
1680
1681int
1682pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
1683{
1684 error("%s: dlopen() not supported", __func__);
1685 return (-1);
Darren Tucker0dd24e02011-09-04 19:59:26 +10001686}
1687
1688void
1689pkcs11_terminate(void)
1690{
djm@openbsd.org93f02102019-01-20 22:51:37 +00001691 error("%s: dlopen() not supported", __func__);
Darren Tucker0dd24e02011-09-04 19:59:26 +10001692}
djm@openbsd.org93f02102019-01-20 22:51:37 +00001693#endif /* HAVE_DLOPEN */