blob: d7b3a65f0a53c8151eeb9709ea6495fa5e6c4e53 [file] [log] [blame]
djm@openbsd.orgf1185422019-01-20 23:08:24 +00001/* $OpenBSD: ssh-pkcs11.c,v 1.33 2019/01/20 23:08:24 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
djm@openbsd.orgf1185422019-01-20 23:08:24 +0000337 if ((k11 = RSA_get_ex_data(rsa, 0)) == NULL) {
338 error("RSA_get_ex_data failed for rsa %p", rsa);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000339 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
djm@openbsd.orgf1185422019-01-20 23:08:24 +0000368static RSA_METHOD *rsa_method;
369
370static int
371pkcs11_rsa_start_wrapper(void)
372{
373 if (rsa_method != NULL)
374 return (0);
375 rsa_method = RSA_meth_dup(RSA_get_default_method());
376 if (rsa_method == NULL)
377 return (-1);
378 if (!RSA_meth_set1_name(rsa_method, "pkcs11") ||
379 !RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt) ||
380 !RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt) ||
381 !RSA_meth_set_finish(rsa_method, pkcs11_rsa_finish)) {
382 error("%s: setup pkcs11 method failed", __func__);
383 return (-1);
384 }
385 return (0);
386}
387
Damien Miller7ea845e2010-02-12 09:21:02 +1100388/* redirect private key operations for rsa key to pkcs11 token */
389static int
390pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
391 CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
392{
393 struct pkcs11_key *k11;
djm@openbsd.orgf1185422019-01-20 23:08:24 +0000394
395 if (pkcs11_rsa_start_wrapper() == -1)
396 return (-1);
Damien Miller7ea845e2010-02-12 09:21:02 +1100397
398 k11 = xcalloc(1, sizeof(*k11));
399 k11->provider = provider;
400 provider->refcount++; /* provider referenced by RSA key */
401 k11->slotidx = slotidx;
402 /* identify key object on smartcard */
403 k11->keyid_len = keyid_attrib->ulValueLen;
djm@openbsd.orgd2d772f2016-02-12 00:20:30 +0000404 if (k11->keyid_len > 0) {
405 k11->keyid = xmalloc(k11->keyid_len);
406 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
407 }
djm@openbsd.orgf1185422019-01-20 23:08:24 +0000408
409 k11->rsa_method = rsa_method;
djm@openbsd.org482d23b2018-09-13 02:08:33 +0000410 RSA_set_method(rsa, k11->rsa_method);
djm@openbsd.orgf1185422019-01-20 23:08:24 +0000411 RSA_set_ex_data(rsa, 0, k11);
Damien Miller7ea845e2010-02-12 09:21:02 +1100412 return (0);
413}
414
djm@openbsd.org93f02102019-01-20 22:51:37 +0000415/* openssl callback doing the actual signing operation */
416static ECDSA_SIG *
417ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
418 const BIGNUM *rp, EC_KEY *ec)
419{
420 struct pkcs11_key *k11;
421 struct pkcs11_slotinfo *si;
422 CK_FUNCTION_LIST *f;
423 CK_ULONG siglen = 0, bnlen;
424 CK_RV rv;
425 ECDSA_SIG *ret = NULL;
426 u_char *sig;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000427
428 if ((k11 = EC_KEY_get_ex_data(ec, 0)) == NULL) {
429 ossl_error("EC_KEY_get_key_method_data failed for ec");
430 return (NULL);
431 }
432
433 if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
434 error("pkcs11_get_key failed");
435 return (NULL);
436 }
437
438 f = k11->provider->function_list;
439 si = &k11->provider->slotinfo[k11->slotidx];
440
441 siglen = ECDSA_size(ec);
442 sig = xmalloc(siglen);
443
444 /* XXX handle CKR_BUFFER_TOO_SMALL */
445 rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &siglen);
446 if (rv != CKR_OK) {
447 error("C_Sign failed: %lu", rv);
448 goto done;
449 }
djm@openbsd.org749aef32019-01-20 23:00:12 +0000450 if (siglen < 64 || siglen > 132 || siglen % 2) {
451 ossl_error("d2i_ECDSA_SIG failed");
452 goto done;
453 }
454 bnlen = siglen/2;
455 if ((ret = ECDSA_SIG_new()) == NULL) {
456 error("ECDSA_SIG_new failed");
457 goto done;
458 }
459 if (BN_bin2bn(sig, bnlen, ret->r) == NULL ||
460 BN_bin2bn(sig+bnlen, bnlen, ret->s) == NULL) {
461 ossl_error("d2i_ECDSA_SIG failed");
462 ECDSA_SIG_free(ret);
463 ret = NULL;
464 goto done;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000465 }
466 done:
467 free(sig);
468
469 return (ret);
470}
471
472static EC_KEY_METHOD *ec_key_method;
djm@openbsd.org445cfce2019-01-20 23:05:52 +0000473static int ec_key_idx = 0;
474
475static void
476pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
477 long argl, void *argp)
478{
479 struct pkcs11_key *k11 = ptr;
480
481 if (k11 == NULL)
482 return;
483 if (k11->provider)
484 pkcs11_provider_unref(k11->provider);
485 free(k11->keyid);
486 free(k11);
487}
djm@openbsd.org93f02102019-01-20 22:51:37 +0000488
489static int
490pkcs11_ecdsa_start_wrapper(void)
491{
492 int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
493 unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
494
495 if (ec_key_method != NULL)
496 return (0);
djm@openbsd.org445cfce2019-01-20 23:05:52 +0000497 ec_key_idx = EC_KEY_get_ex_new_index(0, "ssh-pkcs11-ecdsa",
498 NULL, NULL, pkcs11_k11_free);
499 if (ec_key_idx == -1)
500 return (-1);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000501 ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
502 if (ec_key_method == NULL)
503 return (-1);
504 EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
505 EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
506 return (0);
507}
508
509static int
510pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
511 CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
512{
513 struct pkcs11_key *k11;
514
515 if (pkcs11_ecdsa_start_wrapper() == -1)
516 return (-1);
517
518 k11 = xcalloc(1, sizeof(*k11));
519 k11->provider = provider;
520 provider->refcount++; /* provider referenced by ECDSA key */
521 k11->slotidx = slotidx;
522 /* identify key object on smartcard */
523 k11->keyid_len = keyid_attrib->ulValueLen;
524 k11->keyid = xmalloc(k11->keyid_len);
525 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
526 k11->ec_key_method = ec_key_method;
527
528 EC_KEY_set_method(ec, k11->ec_key_method);
djm@openbsd.org445cfce2019-01-20 23:05:52 +0000529 EC_KEY_set_ex_data(ec, ec_key_idx, k11);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000530
531 return (0);
532}
533
Damien Miller7ea845e2010-02-12 09:21:02 +1100534/* remove trailing spaces */
535static void
Damien Miller746d1a62013-07-18 16:13:02 +1000536rmspace(u_char *buf, size_t len)
Damien Miller7ea845e2010-02-12 09:21:02 +1100537{
538 size_t i;
539
540 if (!len)
541 return;
542 for (i = len - 1; i > 0; i--)
543 if (i == len - 1 || buf[i] == ' ')
544 buf[i] = '\0';
545 else
546 break;
547}
548
549/*
550 * open a pkcs11 session and login if required.
551 * if pin == NULL we delay login until key use
552 */
553static int
djm@openbsd.org93f02102019-01-20 22:51:37 +0000554pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin,
555 CK_ULONG user)
Damien Miller7ea845e2010-02-12 09:21:02 +1100556{
557 CK_RV rv;
558 CK_FUNCTION_LIST *f;
559 CK_SESSION_HANDLE session;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000560 int login_required, ret;
Damien Miller7ea845e2010-02-12 09:21:02 +1100561
562 f = p->function_list;
563 login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED;
564 if (pin && login_required && !strlen(pin)) {
565 error("pin required");
djm@openbsd.org93f02102019-01-20 22:51:37 +0000566 return (-SSH_PKCS11_ERR_PIN_REQUIRED);
Damien Miller7ea845e2010-02-12 09:21:02 +1100567 }
568 if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
569 CKF_SERIAL_SESSION, NULL, NULL, &session))
570 != CKR_OK) {
571 error("C_OpenSession failed: %lu", rv);
572 return (-1);
573 }
574 if (login_required && pin) {
djm@openbsd.org93f02102019-01-20 22:51:37 +0000575 rv = f->C_Login(session, user,
deraadt@openbsd.orgce4f59b2015-02-03 08:07:20 +0000576 (u_char *)pin, strlen(pin));
djm@openbsd.orgcb3bde32015-02-02 22:48:53 +0000577 if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
Damien Miller7ea845e2010-02-12 09:21:02 +1100578 error("C_Login failed: %lu", rv);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000579 ret = (rv == CKR_PIN_LOCKED) ?
580 -SSH_PKCS11_ERR_PIN_LOCKED :
581 -SSH_PKCS11_ERR_LOGIN_FAIL;
Damien Miller7ea845e2010-02-12 09:21:02 +1100582 if ((rv = f->C_CloseSession(session)) != CKR_OK)
583 error("C_CloseSession failed: %lu", rv);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000584 return (ret);
Damien Miller7ea845e2010-02-12 09:21:02 +1100585 }
586 p->slotinfo[slotidx].logged_in = 1;
587 }
588 p->slotinfo[slotidx].session = session;
589 return (0);
590}
591
Damien Millerd2252c72013-11-04 07:41:48 +1100592static int
djm@openbsd.org1129dcf2015-01-15 09:40:00 +0000593pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
Damien Millerd2252c72013-11-04 07:41:48 +1100594{
595 int i;
596
597 for (i = 0; i < *nkeys; i++)
djm@openbsd.org1129dcf2015-01-15 09:40:00 +0000598 if (sshkey_equal(key, (*keysp)[i]))
Damien Millerd2252c72013-11-04 07:41:48 +1100599 return (1);
600 return (0);
601}
602
djm@openbsd.org93f02102019-01-20 22:51:37 +0000603static struct sshkey *
604pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
605 CK_OBJECT_HANDLE *obj)
606{
607 CK_ATTRIBUTE key_attr[3];
608 CK_SESSION_HANDLE session;
609 CK_FUNCTION_LIST *f = NULL;
610 CK_RV rv;
djm@openbsd.org24757c12019-01-20 23:01:59 +0000611 ASN1_OCTET_STRING *octet = NULL;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000612 EC_KEY *ec = NULL;
613 EC_GROUP *group = NULL;
614 struct sshkey *key = NULL;
615 const unsigned char *attrp = NULL;
616 int i;
617 int nid;
618
619 memset(&key_attr, 0, sizeof(key_attr));
620 key_attr[0].type = CKA_ID;
621 key_attr[1].type = CKA_EC_POINT;
622 key_attr[2].type = CKA_EC_PARAMS;
623
624 session = p->slotinfo[slotidx].session;
625 f = p->function_list;
626
627 /* figure out size of the attributes */
628 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
629 if (rv != CKR_OK) {
630 error("C_GetAttributeValue failed: %lu", rv);
631 return (NULL);
632 }
633
634 /*
635 * Allow CKA_ID (always first attribute) to be empty, but
636 * ensure that none of the others are zero length.
637 * XXX assumes CKA_ID is always first.
638 */
639 if (key_attr[1].ulValueLen == 0 ||
640 key_attr[2].ulValueLen == 0) {
641 error("invalid attribute length");
642 return (NULL);
643 }
644
645 /* allocate buffers for attributes */
646 for (i = 0; i < 3; i++)
647 if (key_attr[i].ulValueLen > 0)
648 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
649
650 /* retrieve ID, public point and curve parameters of EC key */
651 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
652 if (rv != CKR_OK) {
653 error("C_GetAttributeValue failed: %lu", rv);
654 goto fail;
655 }
656
657 ec = EC_KEY_new();
658 if (ec == NULL) {
659 error("EC_KEY_new failed");
660 goto fail;
661 }
662
663 attrp = key_attr[2].pValue;
664 group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
665 if (group == NULL) {
666 ossl_error("d2i_ECPKParameters failed");
667 goto fail;
668 }
669
670 if (EC_KEY_set_group(ec, group) == 0) {
671 ossl_error("EC_KEY_set_group failed");
672 goto fail;
673 }
674
675 if (key_attr[1].ulValueLen <= 2) {
676 error("CKA_EC_POINT too small");
677 goto fail;
678 }
679
djm@openbsd.org24757c12019-01-20 23:01:59 +0000680 attrp = key_attr[1].pValue;
681 octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen);
682 if (octet == NULL) {
683 ossl_error("d2i_ASN1_OCTET_STRING failed");
684 goto fail;
685 }
686 attrp = octet->data;
687 if (o2i_ECPublicKey(&ec, &attrp, octet->length) == NULL) {
688 ossl_error("o2i_ECPublicKey failed");
689 goto fail;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000690 }
691
692 nid = sshkey_ecdsa_key_to_nid(ec);
693 if (nid < 0) {
694 error("couldn't get curve nid");
695 goto fail;
696 }
697
698 if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
699 goto fail;
700
701 key = sshkey_new(KEY_UNSPEC);
702 if (key == NULL) {
703 error("sshkey_new failed");
704 goto fail;
705 }
706
707 key->ecdsa = ec;
708 key->ecdsa_nid = nid;
709 key->type = KEY_ECDSA;
710 key->flags |= SSHKEY_FLAG_EXT;
711 ec = NULL; /* now owned by key */
712
713fail:
714 for (i = 0; i < 3; i++)
715 free(key_attr[i].pValue);
716 if (ec)
717 EC_KEY_free(ec);
718 if (group)
719 EC_GROUP_free(group);
djm@openbsd.org24757c12019-01-20 23:01:59 +0000720 if (octet)
721 ASN1_OCTET_STRING_free(octet);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000722
723 return (key);
724}
725
726static struct sshkey *
727pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
728 CK_OBJECT_HANDLE *obj)
729{
730 CK_ATTRIBUTE key_attr[3];
731 CK_SESSION_HANDLE session;
732 CK_FUNCTION_LIST *f = NULL;
733 CK_RV rv;
734 RSA *rsa = NULL;
735 BIGNUM *rsa_n, *rsa_e;
736 struct sshkey *key = NULL;
737 int i;
738
739 memset(&key_attr, 0, sizeof(key_attr));
740 key_attr[0].type = CKA_ID;
741 key_attr[1].type = CKA_MODULUS;
742 key_attr[2].type = CKA_PUBLIC_EXPONENT;
743
744 session = p->slotinfo[slotidx].session;
745 f = p->function_list;
746
747 /* figure out size of the attributes */
748 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
749 if (rv != CKR_OK) {
750 error("C_GetAttributeValue failed: %lu", rv);
751 return (NULL);
752 }
753
754 /*
755 * Allow CKA_ID (always first attribute) to be empty, but
756 * ensure that none of the others are zero length.
757 * XXX assumes CKA_ID is always first.
758 */
759 if (key_attr[1].ulValueLen == 0 ||
760 key_attr[2].ulValueLen == 0) {
761 error("invalid attribute length");
762 return (NULL);
763 }
764
765 /* allocate buffers for attributes */
766 for (i = 0; i < 3; i++)
767 if (key_attr[i].ulValueLen > 0)
768 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
769
770 /* retrieve ID, modulus and public exponent of RSA key */
771 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
772 if (rv != CKR_OK) {
773 error("C_GetAttributeValue failed: %lu", rv);
774 goto fail;
775 }
776
777 rsa = RSA_new();
778 if (rsa == NULL) {
779 error("RSA_new failed");
780 goto fail;
781 }
782
783 rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
784 rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
785 if (rsa_n == NULL || rsa_e == NULL) {
786 error("BN_bin2bn failed");
787 goto fail;
788 }
789 if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
790 fatal("%s: set key", __func__);
791 rsa_n = rsa_e = NULL; /* transferred */
792
793 if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
794 goto fail;
795
796 key = sshkey_new(KEY_UNSPEC);
797 if (key == NULL) {
798 error("sshkey_new failed");
799 goto fail;
800 }
801
802 key->rsa = rsa;
803 key->type = KEY_RSA;
804 key->flags |= SSHKEY_FLAG_EXT;
805 rsa = NULL; /* now owned by key */
806
807fail:
808 for (i = 0; i < 3; i++)
809 free(key_attr[i].pValue);
810 RSA_free(rsa);
811
812 return (key);
813}
814
815static struct sshkey *
816pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
817 CK_OBJECT_HANDLE *obj)
818{
819 CK_ATTRIBUTE cert_attr[3];
820 CK_SESSION_HANDLE session;
821 CK_FUNCTION_LIST *f = NULL;
822 CK_RV rv;
823 X509 *x509 = NULL;
824 EVP_PKEY *evp;
825 RSA *rsa = NULL;
826 EC_KEY *ec = NULL;
827 struct sshkey *key = NULL;
828 int i;
829 int nid;
830 const u_char *cp;
831
832 memset(&cert_attr, 0, sizeof(cert_attr));
833 cert_attr[0].type = CKA_ID;
834 cert_attr[1].type = CKA_SUBJECT;
835 cert_attr[2].type = CKA_VALUE;
836
837 session = p->slotinfo[slotidx].session;
838 f = p->function_list;
839
840 /* figure out size of the attributes */
841 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
842 if (rv != CKR_OK) {
843 error("C_GetAttributeValue failed: %lu", rv);
844 return (NULL);
845 }
846
847 /*
848 * Allow CKA_ID (always first attribute) to be empty, but
849 * ensure that none of the others are zero length.
850 * XXX assumes CKA_ID is always first.
851 */
852 if (cert_attr[1].ulValueLen == 0 ||
853 cert_attr[2].ulValueLen == 0) {
854 error("invalid attribute length");
855 return (NULL);
856 }
857
858 /* allocate buffers for attributes */
859 for (i = 0; i < 3; i++)
860 if (cert_attr[i].ulValueLen > 0)
861 cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
862
863 /* retrieve ID, subject and value of certificate */
864 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
865 if (rv != CKR_OK) {
866 error("C_GetAttributeValue failed: %lu", rv);
867 goto fail;
868 }
869
870 x509 = X509_new();
871 if (x509 == NULL) {
872 error("x509_new failed");
873 goto fail;
874 }
875
876 cp = cert_attr[2].pValue;
877 if (d2i_X509(&x509, &cp, cert_attr[2].ulValueLen) == NULL) {
878 error("d2i_x509 failed");
879 goto fail;
880 }
881
882 evp = X509_get_pubkey(x509);
883 if (evp == NULL) {
884 error("X509_get_pubkey failed");
885 goto fail;
886 }
887
888 if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
889 if (EVP_PKEY_get0_RSA(evp) == NULL) {
890 error("invalid x509; no rsa key");
891 goto fail;
892 }
893 if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
894 error("RSAPublicKey_dup failed");
895 goto fail;
896 }
897
898 if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
899 goto fail;
900
901 key = sshkey_new(KEY_UNSPEC);
902 if (key == NULL) {
903 error("sshkey_new failed");
904 goto fail;
905 }
906
907 key->rsa = rsa;
908 key->type = KEY_RSA;
909 key->flags |= SSHKEY_FLAG_EXT;
910 rsa = NULL; /* now owned by key */
911 } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
djm@openbsd.org8a246752019-01-20 23:03:26 +0000912 if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
djm@openbsd.org93f02102019-01-20 22:51:37 +0000913 error("invalid x509; no ec key");
914 goto fail;
915 }
djm@openbsd.org8a246752019-01-20 23:03:26 +0000916 if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
djm@openbsd.org93f02102019-01-20 22:51:37 +0000917 error("EC_KEY_dup failed");
918 goto fail;
919 }
920
921 nid = sshkey_ecdsa_key_to_nid(ec);
922 if (nid < 0) {
923 error("couldn't get curve nid");
924 goto fail;
925 }
926
927 if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
928 goto fail;
929
930 key = sshkey_new(KEY_UNSPEC);
931 if (key == NULL) {
932 error("sshkey_new failed");
933 goto fail;
934 }
935
936 key->ecdsa = ec;
937 key->ecdsa_nid = nid;
938 key->type = KEY_ECDSA;
939 key->flags |= SSHKEY_FLAG_EXT;
940 ec = NULL; /* now owned by key */
941 } else
942 error("unknown certificate key type");
943
944fail:
945 for (i = 0; i < 3; i++)
946 free(cert_attr[i].pValue);
947 X509_free(x509);
948 RSA_free(rsa);
949 EC_KEY_free(ec);
950
951 return (key);
952}
953
954#if 0
Damien Millerd2252c72013-11-04 07:41:48 +1100955static int
djm@openbsd.org482d23b2018-09-13 02:08:33 +0000956have_rsa_key(const RSA *rsa)
957{
958 const BIGNUM *rsa_n, *rsa_e;
959
960 RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
961 return rsa_n != NULL && rsa_e != NULL;
962}
djm@openbsd.org93f02102019-01-20 22:51:37 +0000963#endif
djm@openbsd.org482d23b2018-09-13 02:08:33 +0000964
djm@openbsd.org93f02102019-01-20 22:51:37 +0000965/*
966 * lookup certificates for token in slot identified by slotidx,
967 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
968 * keysp points to an (possibly empty) array with *nkeys keys.
969 */
djm@openbsd.org482d23b2018-09-13 02:08:33 +0000970static int
djm@openbsd.org93f02102019-01-20 22:51:37 +0000971pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
djm@openbsd.org1129dcf2015-01-15 09:40:00 +0000972 struct sshkey ***keysp, int *nkeys)
Damien Miller7ea845e2010-02-12 09:21:02 +1100973{
djm@openbsd.org93f02102019-01-20 22:51:37 +0000974 struct sshkey *key = NULL;
975 CK_OBJECT_CLASS key_class;
976 CK_ATTRIBUTE key_attr[1];
977 CK_SESSION_HANDLE session;
978 CK_FUNCTION_LIST *f = NULL;
979 CK_RV rv;
980 CK_OBJECT_HANDLE obj;
981 CK_ULONG n = 0;
982 int ret = -1;
Tim Rice179eee02010-03-04 12:48:05 -0800983
djm@openbsd.org93f02102019-01-20 22:51:37 +0000984 memset(&key_attr, 0, sizeof(key_attr));
985 memset(&obj, 0, sizeof(obj));
986
987 key_class = CKO_CERTIFICATE;
988 key_attr[0].type = CKA_CLASS;
989 key_attr[0].pValue = &key_class;
990 key_attr[0].ulValueLen = sizeof(key_class);
991
Damien Miller7ea845e2010-02-12 09:21:02 +1100992 session = p->slotinfo[slotidx].session;
djm@openbsd.org93f02102019-01-20 22:51:37 +0000993 f = p->function_list;
994
995 rv = f->C_FindObjectsInit(session, key_attr, 1);
996 if (rv != CKR_OK) {
Damien Miller7ea845e2010-02-12 09:21:02 +1100997 error("C_FindObjectsInit failed: %lu", rv);
djm@openbsd.org93f02102019-01-20 22:51:37 +0000998 goto fail;
Damien Miller7ea845e2010-02-12 09:21:02 +1100999 }
djm@openbsd.org93f02102019-01-20 22:51:37 +00001000
Damien Miller7ea845e2010-02-12 09:21:02 +11001001 while (1) {
djm@openbsd.org93f02102019-01-20 22:51:37 +00001002 CK_CERTIFICATE_TYPE ck_cert_type;
1003
1004 rv = f->C_FindObjects(session, &obj, 1, &n);
1005 if (rv != CKR_OK) {
1006 error("C_FindObjects failed: %lu", rv);
1007 goto fail;
Damien Miller7ea845e2010-02-12 09:21:02 +11001008 }
djm@openbsd.org93f02102019-01-20 22:51:37 +00001009 if (n == 0)
Damien Miller7ea845e2010-02-12 09:21:02 +11001010 break;
djm@openbsd.org93f02102019-01-20 22:51:37 +00001011
1012 memset(&ck_cert_type, 0, sizeof(ck_cert_type));
1013 memset(&key_attr, 0, sizeof(key_attr));
1014 key_attr[0].type = CKA_CERTIFICATE_TYPE;
1015 key_attr[0].pValue = &ck_cert_type;
1016 key_attr[0].ulValueLen = sizeof(ck_cert_type);
1017
1018 rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
1019 if (rv != CKR_OK) {
Damien Miller7ea845e2010-02-12 09:21:02 +11001020 error("C_GetAttributeValue failed: %lu", rv);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001021 goto fail;
djm@openbsd.org63ebcd02015-07-18 08:02:17 +00001022 }
1023
djm@openbsd.org93f02102019-01-20 22:51:37 +00001024 switch (ck_cert_type) {
1025 case CKC_X_509:
1026 key = pkcs11_fetch_x509_pubkey(p, slotidx, &obj);
1027 break;
1028 default:
1029 /* XXX print key type? */
1030 error("skipping unsupported certificate type");
1031 }
djm@openbsd.org482d23b2018-09-13 02:08:33 +00001032
djm@openbsd.org93f02102019-01-20 22:51:37 +00001033 if (key == NULL) {
1034 error("failed to fetch key");
1035 continue;
1036 }
1037
1038 if (pkcs11_key_included(keysp, nkeys, key)) {
1039 sshkey_free(key);
Damien Miller7ea845e2010-02-12 09:21:02 +11001040 } else {
djm@openbsd.org93f02102019-01-20 22:51:37 +00001041 /* expand key array and add key */
1042 *keysp = xrecallocarray(*keysp, *nkeys,
1043 *nkeys + 1, sizeof(struct sshkey *));
1044 (*keysp)[*nkeys] = key;
1045 *nkeys = *nkeys + 1;
1046 debug("have %d keys", *nkeys);
Damien Millerd2252c72013-11-04 07:41:48 +11001047 }
Damien Miller7ea845e2010-02-12 09:21:02 +11001048 }
djm@openbsd.org93f02102019-01-20 22:51:37 +00001049
1050 ret = 0;
1051fail:
1052 rv = f->C_FindObjectsFinal(session);
1053 if (rv != CKR_OK) {
Damien Miller7ea845e2010-02-12 09:21:02 +11001054 error("C_FindObjectsFinal failed: %lu", rv);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001055 ret = -1;
1056 }
1057
1058 return (ret);
Damien Miller7ea845e2010-02-12 09:21:02 +11001059}
1060
djm@openbsd.org93f02102019-01-20 22:51:37 +00001061/*
1062 * lookup public keys for token in slot identified by slotidx,
1063 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1064 * keysp points to an (possibly empty) array with *nkeys keys.
1065 */
1066static int
1067pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
1068 struct sshkey ***keysp, int *nkeys)
1069{
1070 struct sshkey *key = NULL;
1071 CK_OBJECT_CLASS key_class;
1072 CK_ATTRIBUTE key_attr[1];
1073 CK_SESSION_HANDLE session;
1074 CK_FUNCTION_LIST *f = NULL;
1075 CK_RV rv;
1076 CK_OBJECT_HANDLE obj;
1077 CK_ULONG n = 0;
1078 int ret = -1;
1079
1080 memset(&key_attr, 0, sizeof(key_attr));
1081 memset(&obj, 0, sizeof(obj));
1082
1083 key_class = CKO_PUBLIC_KEY;
1084 key_attr[0].type = CKA_CLASS;
1085 key_attr[0].pValue = &key_class;
1086 key_attr[0].ulValueLen = sizeof(key_class);
1087
1088 session = p->slotinfo[slotidx].session;
1089 f = p->function_list;
1090
1091 rv = f->C_FindObjectsInit(session, key_attr, 1);
1092 if (rv != CKR_OK) {
1093 error("C_FindObjectsInit failed: %lu", rv);
1094 goto fail;
1095 }
1096
1097 while (1) {
1098 CK_KEY_TYPE ck_key_type;
1099
1100 rv = f->C_FindObjects(session, &obj, 1, &n);
1101 if (rv != CKR_OK) {
1102 error("C_FindObjects failed: %lu", rv);
1103 goto fail;
1104 }
1105 if (n == 0)
1106 break;
1107
1108 memset(&ck_key_type, 0, sizeof(ck_key_type));
1109 memset(&key_attr, 0, sizeof(key_attr));
1110 key_attr[0].type = CKA_KEY_TYPE;
1111 key_attr[0].pValue = &ck_key_type;
1112 key_attr[0].ulValueLen = sizeof(ck_key_type);
1113
1114 rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
1115 if (rv != CKR_OK) {
1116 error("C_GetAttributeValue failed: %lu", rv);
1117 goto fail;
1118 }
1119
1120 switch (ck_key_type) {
1121 case CKK_RSA:
1122 key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1123 break;
1124 case CKK_ECDSA:
1125 key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1126 break;
1127 default:
1128 /* XXX print key type? */
1129 error("skipping unsupported key type");
1130 }
1131
1132 if (key == NULL) {
1133 error("failed to fetch key");
1134 continue;
1135 }
1136
1137 if (pkcs11_key_included(keysp, nkeys, key)) {
1138 sshkey_free(key);
1139 } else {
1140 /* expand key array and add key */
1141 *keysp = xrecallocarray(*keysp, *nkeys,
1142 *nkeys + 1, sizeof(struct sshkey *));
1143 (*keysp)[*nkeys] = key;
1144 *nkeys = *nkeys + 1;
1145 debug("have %d keys", *nkeys);
1146 }
1147 }
1148
1149 ret = 0;
1150fail:
1151 rv = f->C_FindObjectsFinal(session);
1152 if (rv != CKR_OK) {
1153 error("C_FindObjectsFinal failed: %lu", rv);
1154 ret = -1;
1155 }
1156
1157 return (ret);
1158}
1159
1160#ifdef WITH_PKCS11_KEYGEN
1161#define FILL_ATTR(attr, idx, typ, val, len) \
1162 { (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; }
1163
1164static struct sshkey *
1165pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1166 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1167{
1168 struct pkcs11_slotinfo *si;
1169 char *plabel = label ? label : "";
1170 int npub = 0, npriv = 0;
1171 CK_RV rv;
1172 CK_FUNCTION_LIST *f;
1173 CK_SESSION_HANDLE session;
1174 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1175 CK_OBJECT_HANDLE pubKey, privKey;
1176 CK_ATTRIBUTE tpub[16], tpriv[16];
1177 CK_MECHANISM mech = {
1178 CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
1179 };
1180 CK_BYTE pubExponent[] = {
1181 0x01, 0x00, 0x01 /* RSA_F4 in bytes */
1182 };
1183 pubkey_filter[0].pValue = &pubkey_class;
1184 cert_filter[0].pValue = &cert_class;
1185
1186 *err = 0;
1187
1188 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1189 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1190 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1191 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1192 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1193 sizeof(false_val));
1194 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1195 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1196 FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits));
1197 FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent,
1198 sizeof(pubExponent));
1199 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1200
1201 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1202 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1203 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1204 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1205 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1206 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1207 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1208 sizeof(false_val));
1209 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1210 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1211 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1212
1213 f = p->function_list;
1214 si = &p->slotinfo[slotidx];
1215 session = si->session;
1216
1217 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1218 &pubKey, &privKey)) != CKR_OK) {
1219 error("%s: key generation failed: error 0x%lx", __func__, rv);
1220 *err = rv;
1221 return NULL;
1222 }
1223
1224 return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey);
1225}
1226
1227static int
1228pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen)
1229{
1230 size_t i, len;
1231 char ptr[3];
1232
1233 if (dest)
1234 *dest = NULL;
1235 if (rlen)
1236 *rlen = 0;
1237
1238 if ((len = strlen(hex)) % 2)
1239 return -1;
1240 len /= 2;
1241
1242 *dest = xmalloc(len);
1243
1244 ptr[2] = '\0';
1245 for (i = 0; i < len; i++) {
1246 ptr[0] = hex[2 * i];
1247 ptr[1] = hex[(2 * i) + 1];
1248 if (!isxdigit(ptr[0]) || !isxdigit(ptr[1]))
1249 return -1;
1250 (*dest)[i] = (unsigned char)strtoul(ptr, NULL, 16);
1251 }
1252
1253 if (rlen)
1254 *rlen = len;
1255
1256 return 0;
1257}
1258
1259static struct ec_curve_info {
1260 const char *name;
1261 const char *oid;
1262 const char *oid_encoded;
1263 size_t size;
1264} ec_curve_infos[] = {
1265 {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
1266 {"secp384r1", "1.3.132.0.34", "06052B81040022", 384},
1267 {"secp521r1", "1.3.132.0.35", "06052B81040023", 521},
1268 {NULL, NULL, NULL, 0},
1269};
1270
1271static struct sshkey *
1272pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1273 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1274{
1275 struct pkcs11_slotinfo *si;
1276 char *plabel = label ? label : "";
1277 int i;
1278 size_t ecparams_size;
1279 unsigned char *ecparams = NULL;
1280 int npub = 0, npriv = 0;
1281 CK_RV rv;
1282 CK_FUNCTION_LIST *f;
1283 CK_SESSION_HANDLE session;
1284 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1285 CK_OBJECT_HANDLE pubKey, privKey;
1286 CK_MECHANISM mech = {
1287 CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
1288 };
1289 CK_ATTRIBUTE tpub[16], tpriv[16];
1290
1291 *err = 0;
1292
1293 for (i = 0; ec_curve_infos[i].name; i++) {
1294 if (ec_curve_infos[i].size == bits)
1295 break;
1296 }
1297 if (!ec_curve_infos[i].name) {
1298 error("%s: invalid key size %lu", __func__, bits);
1299 return NULL;
1300 }
1301 if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams,
1302 &ecparams_size) == -1) {
1303 error("%s: invalid oid", __func__);
1304 return NULL;
1305 }
1306
1307 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1308 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1309 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1310 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1311 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1312 sizeof(false_val));
1313 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1314 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1315 FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size);
1316 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1317
1318 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1319 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1320 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1321 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1322 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1323 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1324 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1325 sizeof(false_val));
1326 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1327 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1328 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1329
1330 f = p->function_list;
1331 si = &p->slotinfo[slotidx];
1332 session = si->session;
1333
1334 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1335 &pubKey, &privKey)) != CKR_OK) {
1336 error("%s: key generation failed: error 0x%lx", __func__, rv);
1337 *err = rv;
1338 return NULL;
1339 }
1340
1341 return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey);
1342}
1343#endif /* WITH_PKCS11_KEYGEN */
1344
1345/*
1346 * register a new provider, fails if provider already exists. if
1347 * keyp is provided, fetch keys.
1348 */
1349static int
1350pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1351 struct pkcs11_provider **providerp, CK_ULONG user)
Damien Miller7ea845e2010-02-12 09:21:02 +11001352{
1353 int nkeys, need_finalize = 0;
djm@openbsd.org93f02102019-01-20 22:51:37 +00001354 int ret = -1;
Damien Miller7ea845e2010-02-12 09:21:02 +11001355 struct pkcs11_provider *p = NULL;
1356 void *handle = NULL;
1357 CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
1358 CK_RV rv;
1359 CK_FUNCTION_LIST *f = NULL;
1360 CK_TOKEN_INFO *token;
1361 CK_ULONG i;
1362
djm@openbsd.org93f02102019-01-20 22:51:37 +00001363 if (providerp == NULL)
1364 goto fail;
1365 *providerp = NULL;
1366
1367 if (keyp != NULL)
1368 *keyp = NULL;
1369
Damien Miller7ea845e2010-02-12 09:21:02 +11001370 if (pkcs11_provider_lookup(provider_id) != NULL) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001371 debug("%s: provider already registered: %s",
1372 __func__, provider_id);
Damien Miller7ea845e2010-02-12 09:21:02 +11001373 goto fail;
1374 }
djm@openbsd.org93f02102019-01-20 22:51:37 +00001375 /* open shared pkcs11-library */
Damien Miller7ea845e2010-02-12 09:21:02 +11001376 if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
1377 error("dlopen %s failed: %s", provider_id, dlerror());
1378 goto fail;
1379 }
1380 if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
1381 error("dlsym(C_GetFunctionList) failed: %s", dlerror());
1382 goto fail;
1383 }
1384 p = xcalloc(1, sizeof(*p));
1385 p->name = xstrdup(provider_id);
1386 p->handle = handle;
1387 /* setup the pkcs11 callbacks */
1388 if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001389 error("C_GetFunctionList for provider %s failed: %lu",
1390 provider_id, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001391 goto fail;
1392 }
1393 p->function_list = f;
1394 if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001395 error("C_Initialize for provider %s failed: %lu",
1396 provider_id, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001397 goto fail;
1398 }
1399 need_finalize = 1;
1400 if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001401 error("C_GetInfo for provider %s failed: %lu",
1402 provider_id, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001403 goto fail;
1404 }
1405 rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
1406 rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001407 debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d"
Damien Miller7ea845e2010-02-12 09:21:02 +11001408 " libraryDescription <%s> libraryVersion %d.%d",
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001409 provider_id,
Damien Miller7ea845e2010-02-12 09:21:02 +11001410 p->info.manufacturerID,
1411 p->info.cryptokiVersion.major,
1412 p->info.cryptokiVersion.minor,
1413 p->info.libraryDescription,
1414 p->info.libraryVersion.major,
1415 p->info.libraryVersion.minor);
1416 if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
1417 error("C_GetSlotList failed: %lu", rv);
1418 goto fail;
1419 }
1420 if (p->nslots == 0) {
djm@openbsd.org93f02102019-01-20 22:51:37 +00001421 error("%s: provider %s returned no slots", __func__,
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001422 provider_id);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001423 ret = -SSH_PKCS11_ERR_NO_SLOTS;
Damien Miller7ea845e2010-02-12 09:21:02 +11001424 goto fail;
1425 }
1426 p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
1427 if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
1428 != CKR_OK) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001429 error("C_GetSlotList for provider %s failed: %lu",
1430 provider_id, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001431 goto fail;
1432 }
1433 p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
1434 p->valid = 1;
1435 nkeys = 0;
1436 for (i = 0; i < p->nslots; i++) {
1437 token = &p->slotinfo[i].token;
1438 if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
1439 != CKR_OK) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001440 error("C_GetTokenInfo for provider %s slot %lu "
1441 "failed: %lu", provider_id, (unsigned long)i, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001442 continue;
1443 }
djm@openbsd.orgb15fd982015-07-18 08:00:21 +00001444 if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001445 debug2("%s: ignoring uninitialised token in "
1446 "provider %s slot %lu", __func__,
1447 provider_id, (unsigned long)i);
djm@openbsd.orgb15fd982015-07-18 08:00:21 +00001448 continue;
1449 }
Damien Miller7ea845e2010-02-12 09:21:02 +11001450 rmspace(token->label, sizeof(token->label));
1451 rmspace(token->manufacturerID, sizeof(token->manufacturerID));
1452 rmspace(token->model, sizeof(token->model));
1453 rmspace(token->serialNumber, sizeof(token->serialNumber));
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001454 debug("provider %s slot %lu: label <%s> manufacturerID <%s> "
1455 "model <%s> serial <%s> flags 0x%lx",
1456 provider_id, (unsigned long)i,
Damien Miller7ea845e2010-02-12 09:21:02 +11001457 token->label, token->manufacturerID, token->model,
1458 token->serialNumber, token->flags);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001459 /*
1460 * open session, login with pin and retrieve public
1461 * keys (if keyp is provided)
1462 */
1463 if ((ret = pkcs11_open_session(p, i, pin, user)) == 0) {
1464 if (keyp == NULL)
1465 continue;
Damien Miller7ea845e2010-02-12 09:21:02 +11001466 pkcs11_fetch_keys(p, i, keyp, &nkeys);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001467 pkcs11_fetch_certs(p, i, keyp, &nkeys);
1468 }
Damien Miller7ea845e2010-02-12 09:21:02 +11001469 }
djm@openbsd.org93f02102019-01-20 22:51:37 +00001470
1471 /* now owned by caller */
1472 *providerp = p;
1473
1474 TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
1475 p->refcount++; /* add to provider list */
1476
1477 return (nkeys);
Damien Miller7ea845e2010-02-12 09:21:02 +11001478fail:
1479 if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
djm@openbsd.orgefb494e2016-10-28 03:33:52 +00001480 error("C_Finalize for provider %s failed: %lu",
1481 provider_id, rv);
Damien Miller7ea845e2010-02-12 09:21:02 +11001482 if (p) {
djm@openbsd.org93f02102019-01-20 22:51:37 +00001483 free(p->name);
Darren Tuckera627d422013-06-02 07:31:17 +10001484 free(p->slotlist);
1485 free(p->slotinfo);
1486 free(p);
Damien Miller7ea845e2010-02-12 09:21:02 +11001487 }
1488 if (handle)
1489 dlclose(handle);
djm@openbsd.org93f02102019-01-20 22:51:37 +00001490 return (ret);
Damien Miller7ea845e2010-02-12 09:21:02 +11001491}
Damien Millerdfa41562010-02-12 10:06:28 +11001492
djm@openbsd.org93f02102019-01-20 22:51:37 +00001493/*
1494 * register a new provider and get number of keys hold by the token,
1495 * fails if provider already exists
1496 */
1497int
1498pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
1499{
1500 struct pkcs11_provider *p = NULL;
1501 int nkeys;
Darren Tucker0dd24e02011-09-04 19:59:26 +10001502
djm@openbsd.org93f02102019-01-20 22:51:37 +00001503 nkeys = pkcs11_register_provider(provider_id, pin, keyp, &p, CKU_USER);
1504
1505 /* no keys found or some other error, de-register provider */
1506 if (nkeys <= 0 && p != NULL) {
1507 TAILQ_REMOVE(&pkcs11_providers, p, next);
1508 pkcs11_provider_finalize(p);
1509 pkcs11_provider_unref(p);
1510 }
1511 if (nkeys == 0)
1512 debug("%s: provider %s returned no keys", __func__,
1513 provider_id);
1514
1515 return (nkeys);
1516}
1517
1518#ifdef WITH_PKCS11_KEYGEN
1519struct sshkey *
1520pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
1521 unsigned int type, unsigned int bits, unsigned char keyid, u_int32_t *err)
1522{
1523 struct pkcs11_provider *p = NULL;
1524 struct pkcs11_slotinfo *si;
1525 CK_FUNCTION_LIST *f;
1526 CK_SESSION_HANDLE session;
1527 struct sshkey *k = NULL;
1528 int ret = -1, reset_pin = 0, reset_provider = 0;
1529 CK_RV rv;
1530
1531 *err = 0;
1532
1533 if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
1534 debug("%s: provider \"%s\" available", __func__, provider_id);
1535 else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, &p,
1536 CKU_SO)) < 0) {
1537 debug("%s: could not register provider %s", __func__,
1538 provider_id);
1539 goto out;
1540 } else
1541 reset_provider = 1;
1542
1543 f = p->function_list;
1544 si = &p->slotinfo[slotidx];
1545 session = si->session;
1546
1547 if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1548 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1549 debug("%s: could not supply SO pin: %lu", __func__, rv);
1550 reset_pin = 0;
1551 } else
1552 reset_pin = 1;
1553
1554 switch (type) {
1555 case KEY_RSA:
1556 if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label,
1557 bits, keyid, err)) == NULL) {
1558 debug("%s: failed to generate RSA key", __func__);
1559 goto out;
1560 }
1561 break;
1562 case KEY_ECDSA:
1563 if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label,
1564 bits, keyid, err)) == NULL) {
1565 debug("%s: failed to generate ECDSA key", __func__);
1566 goto out;
1567 }
1568 break;
1569 default:
1570 *err = SSH_PKCS11_ERR_GENERIC;
1571 debug("%s: unknown type %d", __func__, type);
1572 goto out;
1573 }
1574
1575out:
1576 if (reset_pin)
1577 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1578 CK_INVALID_HANDLE);
1579
1580 if (reset_provider)
1581 pkcs11_del_provider(provider_id);
1582
1583 return (k);
1584}
1585
1586struct sshkey *
1587pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
1588 unsigned char keyid, u_int32_t *err)
1589{
1590 struct pkcs11_provider *p = NULL;
1591 struct pkcs11_slotinfo *si;
1592 struct sshkey *k = NULL;
1593 int reset_pin = 0, reset_provider = 0;
1594 CK_ULONG nattrs;
1595 CK_FUNCTION_LIST *f;
1596 CK_SESSION_HANDLE session;
1597 CK_ATTRIBUTE attrs[16];
1598 CK_OBJECT_CLASS key_class;
1599 CK_KEY_TYPE key_type;
1600 CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE;
1601 CK_RV rv;
1602
1603 *err = 0;
1604
1605 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
1606 debug("%s: using provider \"%s\"", __func__, provider_id);
1607 } else if (pkcs11_register_provider(provider_id, pin, NULL, &p,
1608 CKU_SO) < 0) {
1609 debug("%s: could not register provider %s", __func__,
1610 provider_id);
1611 goto out;
1612 } else
1613 reset_provider = 1;
1614
1615 f = p->function_list;
1616 si = &p->slotinfo[slotidx];
1617 session = si->session;
1618
1619 if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1620 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1621 debug("%s: could not supply SO pin: %lu", __func__, rv);
1622 reset_pin = 0;
1623 } else
1624 reset_pin = 1;
1625
1626 /* private key */
1627 nattrs = 0;
1628 key_class = CKO_PRIVATE_KEY;
1629 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1630 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1631
1632 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1633 obj != CK_INVALID_HANDLE) {
1634 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1635 debug("%s: could not destroy private key 0x%hhx",
1636 __func__, keyid);
1637 *err = rv;
1638 goto out;
1639 }
1640 }
1641
1642 /* public key */
1643 nattrs = 0;
1644 key_class = CKO_PUBLIC_KEY;
1645 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1646 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1647
1648 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1649 obj != CK_INVALID_HANDLE) {
1650
1651 /* get key type */
1652 nattrs = 0;
1653 FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type,
1654 sizeof(key_type));
1655 rv = f->C_GetAttributeValue(session, obj, attrs, nattrs);
1656 if (rv != CKR_OK) {
1657 debug("%s: could not get key type of public key 0x%hhx",
1658 __func__, keyid);
1659 *err = rv;
1660 key_type = -1;
1661 }
1662 if (key_type == CKK_RSA)
1663 k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1664 else if (key_type == CKK_ECDSA)
1665 k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1666
1667 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1668 debug("%s: could not destroy public key 0x%hhx",
1669 __func__, keyid);
1670 *err = rv;
1671 goto out;
1672 }
1673 }
1674
1675out:
1676 if (reset_pin)
1677 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1678 CK_INVALID_HANDLE);
1679
1680 if (reset_provider)
1681 pkcs11_del_provider(provider_id);
1682
1683 return (k);
1684}
1685#endif /* WITH_PKCS11_KEYGEN */
1686#else /* HAVE_DLOPEN */
Darren Tucker0dd24e02011-09-04 19:59:26 +10001687int
1688pkcs11_init(int interactive)
1689{
djm@openbsd.org93f02102019-01-20 22:51:37 +00001690 error("%s: dlopen() not supported", __func__);
1691 return (-1);
1692}
1693
1694int
1695pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
1696{
1697 error("%s: dlopen() not supported", __func__);
1698 return (-1);
Darren Tucker0dd24e02011-09-04 19:59:26 +10001699}
1700
1701void
1702pkcs11_terminate(void)
1703{
djm@openbsd.org93f02102019-01-20 22:51:37 +00001704 error("%s: dlopen() not supported", __func__);
Darren Tucker0dd24e02011-09-04 19:59:26 +10001705}
djm@openbsd.org93f02102019-01-20 22:51:37 +00001706#endif /* HAVE_DLOPEN */