Annotation of src/usr.bin/ssh/ssh-pkcs11.c, Revision 1.47
1.47 ! djm 1: /* $OpenBSD: ssh-pkcs11.c,v 1.46 2019/10/01 10:22:53 djm Exp $ */
1.1 markus 2: /*
3: * Copyright (c) 2010 Markus Friedl. All rights reserved.
1.28 djm 4: * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
1.1 markus 5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20: #include <sys/queue.h>
21: #include <stdarg.h>
22: #include <stdio.h>
23:
1.28 djm 24: #include <ctype.h>
1.1 markus 25: #include <string.h>
26: #include <dlfcn.h>
27:
1.28 djm 28: #include <openssl/ecdsa.h>
1.9 markus 29: #include <openssl/x509.h>
1.28 djm 30: #include <openssl/err.h>
1.9 markus 31:
1.1 markus 32: #define CRYPTOKI_COMPAT
33: #include "pkcs11.h"
34:
35: #include "log.h"
36: #include "misc.h"
1.15 djm 37: #include "sshkey.h"
1.1 markus 38: #include "ssh-pkcs11.h"
39: #include "xmalloc.h"
40:
41: struct pkcs11_slotinfo {
42: CK_TOKEN_INFO token;
43: CK_SESSION_HANDLE session;
44: int logged_in;
45: };
46:
47: struct pkcs11_provider {
48: char *name;
49: void *handle;
50: CK_FUNCTION_LIST *function_list;
51: CK_INFO info;
52: CK_ULONG nslots;
53: CK_SLOT_ID *slotlist;
54: struct pkcs11_slotinfo *slotinfo;
55: int valid;
56: int refcount;
57: TAILQ_ENTRY(pkcs11_provider) next;
58: };
59:
60: TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
61:
62: struct pkcs11_key {
63: struct pkcs11_provider *provider;
64: CK_ULONG slotidx;
65: char *keyid;
66: int keyid_len;
67: };
68:
69: int pkcs11_interactive = 0;
70:
1.28 djm 71: #ifdef HAVE_DLOPEN
72: static void
73: ossl_error(const char *msg)
74: {
1.35 djm 75: unsigned long e;
1.28 djm 76:
1.39 djm 77: error("%s: %s", __func__, msg);
1.35 djm 78: while ((e = ERR_get_error()) != 0)
1.39 djm 79: error("%s: libcrypto error: %.100s", __func__,
1.35 djm 80: ERR_error_string(e, NULL));
1.28 djm 81: }
82: #endif
83:
1.1 markus 84: int
85: pkcs11_init(int interactive)
86: {
87: pkcs11_interactive = interactive;
88: TAILQ_INIT(&pkcs11_providers);
89: return (0);
90: }
91:
92: /*
1.28 djm 93: * finalize a provider shared library, it's no longer usable.
1.1 markus 94: * however, there might still be keys referencing this provider,
1.28 djm 95: * so the actual freeing of memory is handled by pkcs11_provider_unref().
1.1 markus 96: * this is called when a provider gets unregistered.
97: */
98: static void
99: pkcs11_provider_finalize(struct pkcs11_provider *p)
100: {
101: CK_RV rv;
102: CK_ULONG i;
103:
104: debug("pkcs11_provider_finalize: %p refcount %d valid %d",
105: p, p->refcount, p->valid);
106: if (!p->valid)
107: return;
108: for (i = 0; i < p->nslots; i++) {
109: if (p->slotinfo[i].session &&
110: (rv = p->function_list->C_CloseSession(
111: p->slotinfo[i].session)) != CKR_OK)
112: error("C_CloseSession failed: %lu", rv);
113: }
114: if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
115: error("C_Finalize failed: %lu", rv);
116: p->valid = 0;
117: p->function_list = NULL;
1.3 deraadt 118: #ifdef HAVE_DLOPEN
1.1 markus 119: dlclose(p->handle);
1.3 deraadt 120: #endif
1.1 markus 121: }
122:
123: /*
124: * remove a reference to the provider.
125: * called when a key gets destroyed or when the provider is unregistered.
126: */
127: static void
128: pkcs11_provider_unref(struct pkcs11_provider *p)
129: {
130: debug("pkcs11_provider_unref: %p refcount %d", p, p->refcount);
131: if (--p->refcount <= 0) {
132: if (p->valid)
133: error("pkcs11_provider_unref: %p still valid", p);
1.28 djm 134: free(p->name);
1.7 djm 135: free(p->slotlist);
136: free(p->slotinfo);
137: free(p);
1.1 markus 138: }
139: }
140:
141: /* unregister all providers, keys might still point to the providers */
142: void
143: pkcs11_terminate(void)
144: {
145: struct pkcs11_provider *p;
146:
147: while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
148: TAILQ_REMOVE(&pkcs11_providers, p, next);
149: pkcs11_provider_finalize(p);
150: pkcs11_provider_unref(p);
151: }
152: }
153:
154: /* lookup provider by name */
155: static struct pkcs11_provider *
156: pkcs11_provider_lookup(char *provider_id)
157: {
158: struct pkcs11_provider *p;
159:
160: TAILQ_FOREACH(p, &pkcs11_providers, next) {
161: debug("check %p %s", p, p->name);
162: if (!strcmp(provider_id, p->name))
163: return (p);
164: }
165: return (NULL);
166: }
167:
168: /* unregister provider by name */
169: int
170: pkcs11_del_provider(char *provider_id)
171: {
172: struct pkcs11_provider *p;
173:
174: if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
175: TAILQ_REMOVE(&pkcs11_providers, p, next);
176: pkcs11_provider_finalize(p);
177: pkcs11_provider_unref(p);
178: return (0);
179: }
180: return (-1);
181: }
182:
1.28 djm 183: #ifdef HAVE_DLOPEN
1.38 djm 184: static RSA_METHOD *rsa_method;
185: static int rsa_idx = 0;
186: static EC_KEY_METHOD *ec_key_method;
187: static int ec_key_idx = 0;
188:
1.34 djm 189: /* release a wrapped object */
190: static void
191: pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
192: long argl, void *argp)
1.1 markus 193: {
1.34 djm 194: struct pkcs11_key *k11 = ptr;
1.1 markus 195:
1.34 djm 196: debug("%s: parent %p ptr %p idx %d", __func__, parent, ptr, idx);
197: if (k11 == NULL)
198: return;
199: if (k11->provider)
200: pkcs11_provider_unref(k11->provider);
201: free(k11->keyid);
202: free(k11);
1.1 markus 203: }
204:
1.5 markus 205: /* find a single 'obj' for given attributes */
206: static int
207: pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
208: CK_ULONG nattr, CK_OBJECT_HANDLE *obj)
209: {
210: CK_FUNCTION_LIST *f;
211: CK_SESSION_HANDLE session;
212: CK_ULONG nfound = 0;
213: CK_RV rv;
214: int ret = -1;
215:
216: f = p->function_list;
217: session = p->slotinfo[slotidx].session;
218: if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) {
219: error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv);
220: return (-1);
221: }
222: if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK ||
223: nfound != 1) {
224: debug("C_FindObjects failed (nfound %lu nattr %lu): %lu",
225: nfound, nattr, rv);
226: } else
227: ret = 0;
228: if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
229: error("C_FindObjectsFinal failed: %lu", rv);
230: return (ret);
231: }
232:
1.1 markus 233: static int
1.45 djm 234: pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si,
235: CK_USER_TYPE type)
1.40 djm 236: {
237: char *pin = NULL, prompt[1024];
238: CK_RV rv;
239:
1.45 djm 240: if (provider == NULL || si == NULL || !provider->valid) {
1.40 djm 241: error("no pkcs11 (valid) provider found");
242: return (-1);
243: }
244:
245: if (!pkcs11_interactive) {
246: error("need pin entry%s",
247: (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ?
248: " on reader keypad" : "");
249: return (-1);
250: }
251: if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
252: verbose("Deferring PIN entry to reader keypad.");
253: else {
254: snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ",
255: si->token.label);
256: if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) {
257: debug("%s: no pin specified", __func__);
258: return (-1); /* bail out */
259: }
260: }
1.45 djm 261: rv = provider->function_list->C_Login(si->session, type, (u_char *)pin,
1.40 djm 262: (pin != NULL) ? strlen(pin) : 0);
263: if (pin != NULL)
264: freezero(pin, strlen(pin));
265: if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
266: error("C_Login failed: %lu", rv);
267: return (-1);
268: }
269: si->logged_in = 1;
270: return (0);
271: }
272:
273: static int
1.45 djm 274: pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type)
275: {
276: if (k11 == NULL || k11->provider == NULL || !k11->provider->valid) {
277: error("no pkcs11 (valid) provider found");
278: return (-1);
279: }
280:
281: return pkcs11_login_slot(k11->provider,
282: &k11->provider->slotinfo[k11->slotidx], type);
283: }
284:
285:
286: static int
1.40 djm 287: pkcs11_check_obj_bool_attrib(struct pkcs11_key *k11, CK_OBJECT_HANDLE obj,
288: CK_ATTRIBUTE_TYPE type, int *val)
289: {
290: struct pkcs11_slotinfo *si;
291: CK_FUNCTION_LIST *f;
292: CK_BBOOL flag = 0;
293: CK_ATTRIBUTE attr;
294: CK_RV rv;
295:
296: *val = 0;
297:
298: if (!k11->provider || !k11->provider->valid) {
299: error("no pkcs11 (valid) provider found");
300: return (-1);
301: }
302:
303: f = k11->provider->function_list;
304: si = &k11->provider->slotinfo[k11->slotidx];
305:
306: attr.type = type;
307: attr.pValue = &flag;
308: attr.ulValueLen = sizeof(flag);
309:
310: rv = f->C_GetAttributeValue(si->session, obj, &attr, 1);
311: if (rv != CKR_OK) {
312: error("C_GetAttributeValue failed: %lu", rv);
313: return (-1);
314: }
315: *val = flag != 0;
316: debug("%s: provider %p slot %lu object %lu: attrib %lu = %d",
317: __func__, k11->provider, k11->slotidx, obj, type, *val);
318: return (0);
319: }
320:
321: static int
1.28 djm 322: pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type)
1.1 markus 323: {
324: struct pkcs11_slotinfo *si;
325: CK_FUNCTION_LIST *f;
1.28 djm 326: CK_OBJECT_HANDLE obj;
327: CK_RV rv;
328: CK_OBJECT_CLASS private_key_class;
329: CK_BBOOL true_val;
330: CK_MECHANISM mech;
331: CK_ATTRIBUTE key_filter[3];
1.40 djm 332: int always_auth = 0;
333: int did_login = 0;
1.1 markus 334:
335: if (!k11->provider || !k11->provider->valid) {
1.28 djm 336: error("no pkcs11 (valid) provider found");
1.1 markus 337: return (-1);
338: }
1.28 djm 339:
1.1 markus 340: f = k11->provider->function_list;
341: si = &k11->provider->slotinfo[k11->slotidx];
1.28 djm 342:
1.1 markus 343: if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
1.40 djm 344: if (pkcs11_login(k11, CKU_USER) < 0) {
345: error("login failed");
1.1 markus 346: return (-1);
347: }
1.40 djm 348: did_login = 1;
1.1 markus 349: }
1.28 djm 350:
351: memset(&key_filter, 0, sizeof(key_filter));
352: private_key_class = CKO_PRIVATE_KEY;
353: key_filter[0].type = CKA_CLASS;
354: key_filter[0].pValue = &private_key_class;
355: key_filter[0].ulValueLen = sizeof(private_key_class);
356:
357: key_filter[1].type = CKA_ID;
1.1 markus 358: key_filter[1].pValue = k11->keyid;
359: key_filter[1].ulValueLen = k11->keyid_len;
1.28 djm 360:
361: true_val = CK_TRUE;
362: key_filter[2].type = CKA_SIGN;
363: key_filter[2].pValue = &true_val;
364: key_filter[2].ulValueLen = sizeof(true_val);
365:
1.5 markus 366: /* try to find object w/CKA_SIGN first, retry w/o */
367: if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
368: pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
369: error("cannot find private key");
1.28 djm 370: return (-1);
371: }
372:
373: memset(&mech, 0, sizeof(mech));
374: mech.mechanism = mech_type;
375: mech.pParameter = NULL_PTR;
376: mech.ulParameterLen = 0;
377:
378: if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
1.1 markus 379: error("C_SignInit failed: %lu", rv);
1.28 djm 380: return (-1);
1.40 djm 381: }
382:
383: pkcs11_check_obj_bool_attrib(k11, obj, CKA_ALWAYS_AUTHENTICATE,
384: &always_auth); /* ignore errors here */
385: if (always_auth && !did_login) {
386: debug("%s: always-auth key", __func__);
387: if (pkcs11_login(k11, CKU_CONTEXT_SPECIFIC) < 0) {
388: error("login failed for always-auth key");
389: return (-1);
390: }
1.1 markus 391: }
1.28 djm 392:
393: return (0);
394: }
395:
396: /* openssl callback doing the actual signing operation */
397: static int
398: pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
399: int padding)
400: {
401: struct pkcs11_key *k11;
402: struct pkcs11_slotinfo *si;
403: CK_FUNCTION_LIST *f;
404: CK_ULONG tlen = 0;
405: CK_RV rv;
406: int rval = -1;
407:
1.38 djm 408: if ((k11 = RSA_get_ex_data(rsa, rsa_idx)) == NULL) {
1.33 djm 409: error("RSA_get_ex_data failed for rsa %p", rsa);
1.28 djm 410: return (-1);
411: }
412:
413: if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
414: error("pkcs11_get_key failed");
415: return (-1);
416: }
417:
418: f = k11->provider->function_list;
419: si = &k11->provider->slotinfo[k11->slotidx];
420: tlen = RSA_size(rsa);
421:
422: /* XXX handle CKR_BUFFER_TOO_SMALL */
423: rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
424: if (rv == CKR_OK)
425: rval = tlen;
426: else
427: error("C_Sign failed: %lu", rv);
428:
1.1 markus 429: return (rval);
430: }
431:
432: static int
433: pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
434: int padding)
435: {
436: return (-1);
437: }
438:
1.33 djm 439: static int
440: pkcs11_rsa_start_wrapper(void)
441: {
442: if (rsa_method != NULL)
443: return (0);
444: rsa_method = RSA_meth_dup(RSA_get_default_method());
445: if (rsa_method == NULL)
446: return (-1);
1.34 djm 447: rsa_idx = RSA_get_ex_new_index(0, "ssh-pkcs11-rsa",
448: NULL, NULL, pkcs11_k11_free);
449: if (rsa_idx == -1)
450: return (-1);
1.33 djm 451: if (!RSA_meth_set1_name(rsa_method, "pkcs11") ||
452: !RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt) ||
1.34 djm 453: !RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt)) {
1.33 djm 454: error("%s: setup pkcs11 method failed", __func__);
455: return (-1);
456: }
457: return (0);
458: }
459:
1.1 markus 460: /* redirect private key operations for rsa key to pkcs11 token */
461: static int
462: pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
463: CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
464: {
465: struct pkcs11_key *k11;
1.33 djm 466:
467: if (pkcs11_rsa_start_wrapper() == -1)
468: return (-1);
1.1 markus 469:
470: k11 = xcalloc(1, sizeof(*k11));
471: k11->provider = provider;
472: provider->refcount++; /* provider referenced by RSA key */
473: k11->slotidx = slotidx;
474: /* identify key object on smartcard */
475: k11->keyid_len = keyid_attrib->ulValueLen;
1.22 djm 476: if (k11->keyid_len > 0) {
477: k11->keyid = xmalloc(k11->keyid_len);
478: memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
479: }
1.33 djm 480:
1.36 djm 481: RSA_set_method(rsa, rsa_method);
1.34 djm 482: RSA_set_ex_data(rsa, rsa_idx, k11);
1.1 markus 483: return (0);
484: }
485:
1.28 djm 486: /* openssl callback doing the actual signing operation */
487: static ECDSA_SIG *
488: ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
489: const BIGNUM *rp, EC_KEY *ec)
490: {
491: struct pkcs11_key *k11;
492: struct pkcs11_slotinfo *si;
493: CK_FUNCTION_LIST *f;
494: CK_ULONG siglen = 0, bnlen;
495: CK_RV rv;
496: ECDSA_SIG *ret = NULL;
497: u_char *sig;
1.37 djm 498: BIGNUM *r = NULL, *s = NULL;
1.28 djm 499:
1.38 djm 500: if ((k11 = EC_KEY_get_ex_data(ec, ec_key_idx)) == NULL) {
1.28 djm 501: ossl_error("EC_KEY_get_key_method_data failed for ec");
502: return (NULL);
503: }
504:
505: if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
506: error("pkcs11_get_key failed");
507: return (NULL);
508: }
509:
510: f = k11->provider->function_list;
511: si = &k11->provider->slotinfo[k11->slotidx];
512:
513: siglen = ECDSA_size(ec);
514: sig = xmalloc(siglen);
515:
516: /* XXX handle CKR_BUFFER_TOO_SMALL */
517: rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &siglen);
518: if (rv != CKR_OK) {
519: error("C_Sign failed: %lu", rv);
520: goto done;
521: }
1.29 djm 522: if (siglen < 64 || siglen > 132 || siglen % 2) {
523: ossl_error("d2i_ECDSA_SIG failed");
524: goto done;
525: }
526: bnlen = siglen/2;
527: if ((ret = ECDSA_SIG_new()) == NULL) {
528: error("ECDSA_SIG_new failed");
529: goto done;
530: }
1.37 djm 531: if ((r = BN_bin2bn(sig, bnlen, NULL)) == NULL ||
532: (s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) {
1.29 djm 533: ossl_error("d2i_ECDSA_SIG failed");
534: ECDSA_SIG_free(ret);
535: ret = NULL;
536: goto done;
1.28 djm 537: }
1.37 djm 538: if (!ECDSA_SIG_set0(ret, r, s)) {
539: error("%s: ECDSA_SIG_set0 failed", __func__);
540: ECDSA_SIG_free(ret);
541: ret = NULL;
542: goto done;
543: }
544: r = s = NULL; /* now owned by ret */
545: /* success */
1.28 djm 546: done:
1.37 djm 547: BN_free(r);
548: BN_free(s);
1.28 djm 549: free(sig);
550:
551: return (ret);
552: }
553:
554: static int
555: pkcs11_ecdsa_start_wrapper(void)
556: {
557: int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
558: unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
559:
560: if (ec_key_method != NULL)
561: return (0);
1.32 djm 562: ec_key_idx = EC_KEY_get_ex_new_index(0, "ssh-pkcs11-ecdsa",
563: NULL, NULL, pkcs11_k11_free);
564: if (ec_key_idx == -1)
565: return (-1);
1.28 djm 566: ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
567: if (ec_key_method == NULL)
568: return (-1);
569: EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
570: EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
571: return (0);
572: }
573:
574: static int
575: pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
576: CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
577: {
578: struct pkcs11_key *k11;
579:
580: if (pkcs11_ecdsa_start_wrapper() == -1)
581: return (-1);
582:
583: k11 = xcalloc(1, sizeof(*k11));
584: k11->provider = provider;
585: provider->refcount++; /* provider referenced by ECDSA key */
586: k11->slotidx = slotidx;
587: /* identify key object on smartcard */
588: k11->keyid_len = keyid_attrib->ulValueLen;
589: k11->keyid = xmalloc(k11->keyid_len);
590: memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
591:
1.36 djm 592: EC_KEY_set_method(ec, ec_key_method);
1.32 djm 593: EC_KEY_set_ex_data(ec, ec_key_idx, k11);
1.28 djm 594:
595: return (0);
596: }
597:
1.1 markus 598: /* remove trailing spaces */
599: static void
1.8 djm 600: rmspace(u_char *buf, size_t len)
1.1 markus 601: {
602: size_t i;
603:
604: if (!len)
605: return;
606: for (i = len - 1; i > 0; i--)
607: if (i == len - 1 || buf[i] == ' ')
608: buf[i] = '\0';
609: else
610: break;
611: }
612:
613: /*
614: * open a pkcs11 session and login if required.
615: * if pin == NULL we delay login until key use
616: */
617: static int
1.28 djm 618: pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin,
619: CK_ULONG user)
1.1 markus 620: {
1.41 djm 621: struct pkcs11_slotinfo *si;
622: CK_FUNCTION_LIST *f;
1.1 markus 623: CK_RV rv;
624: CK_SESSION_HANDLE session;
1.46 djm 625: int login_required, ret;
1.1 markus 626:
627: f = p->function_list;
1.41 djm 628: si = &p->slotinfo[slotidx];
629:
630: login_required = si->token.flags & CKF_LOGIN_REQUIRED;
631:
632: /* fail early before opening session */
1.46 djm 633: if (login_required && !pkcs11_interactive &&
1.42 djm 634: (pin == NULL || strlen(pin) == 0)) {
1.1 markus 635: error("pin required");
1.28 djm 636: return (-SSH_PKCS11_ERR_PIN_REQUIRED);
1.1 markus 637: }
638: if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
1.41 djm 639: CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) {
1.1 markus 640: error("C_OpenSession failed: %lu", rv);
641: return (-1);
642: }
1.46 djm 643: if (login_required && pin != NULL && strlen(pin) != 0) {
644: rv = f->C_Login(session, user, (u_char *)pin, strlen(pin));
1.16 djm 645: if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
1.1 markus 646: error("C_Login failed: %lu", rv);
1.28 djm 647: ret = (rv == CKR_PIN_LOCKED) ?
648: -SSH_PKCS11_ERR_PIN_LOCKED :
649: -SSH_PKCS11_ERR_LOGIN_FAIL;
1.1 markus 650: if ((rv = f->C_CloseSession(session)) != CKR_OK)
651: error("C_CloseSession failed: %lu", rv);
1.28 djm 652: return (ret);
1.1 markus 653: }
1.41 djm 654: si->logged_in = 1;
1.1 markus 655: }
1.41 djm 656: si->session = session;
1.1 markus 657: return (0);
658: }
659:
660: static int
1.15 djm 661: pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
1.9 markus 662: {
663: int i;
664:
665: for (i = 0; i < *nkeys; i++)
1.15 djm 666: if (sshkey_equal(key, (*keysp)[i]))
1.9 markus 667: return (1);
668: return (0);
669: }
670:
1.28 djm 671: static struct sshkey *
672: pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
673: CK_OBJECT_HANDLE *obj)
674: {
675: CK_ATTRIBUTE key_attr[3];
676: CK_SESSION_HANDLE session;
677: CK_FUNCTION_LIST *f = NULL;
678: CK_RV rv;
1.30 djm 679: ASN1_OCTET_STRING *octet = NULL;
1.28 djm 680: EC_KEY *ec = NULL;
681: EC_GROUP *group = NULL;
682: struct sshkey *key = NULL;
683: const unsigned char *attrp = NULL;
684: int i;
685: int nid;
686:
687: memset(&key_attr, 0, sizeof(key_attr));
688: key_attr[0].type = CKA_ID;
689: key_attr[1].type = CKA_EC_POINT;
690: key_attr[2].type = CKA_EC_PARAMS;
691:
692: session = p->slotinfo[slotidx].session;
693: f = p->function_list;
694:
695: /* figure out size of the attributes */
696: rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
697: if (rv != CKR_OK) {
698: error("C_GetAttributeValue failed: %lu", rv);
699: return (NULL);
700: }
701:
702: /*
703: * Allow CKA_ID (always first attribute) to be empty, but
704: * ensure that none of the others are zero length.
705: * XXX assumes CKA_ID is always first.
706: */
707: if (key_attr[1].ulValueLen == 0 ||
708: key_attr[2].ulValueLen == 0) {
709: error("invalid attribute length");
710: return (NULL);
711: }
712:
713: /* allocate buffers for attributes */
714: for (i = 0; i < 3; i++)
715: if (key_attr[i].ulValueLen > 0)
716: key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
717:
718: /* retrieve ID, public point and curve parameters of EC key */
719: rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
720: if (rv != CKR_OK) {
721: error("C_GetAttributeValue failed: %lu", rv);
722: goto fail;
723: }
724:
725: ec = EC_KEY_new();
726: if (ec == NULL) {
727: error("EC_KEY_new failed");
728: goto fail;
729: }
730:
731: attrp = key_attr[2].pValue;
732: group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
733: if (group == NULL) {
734: ossl_error("d2i_ECPKParameters failed");
735: goto fail;
736: }
737:
738: if (EC_KEY_set_group(ec, group) == 0) {
739: ossl_error("EC_KEY_set_group failed");
740: goto fail;
741: }
742:
743: if (key_attr[1].ulValueLen <= 2) {
744: error("CKA_EC_POINT too small");
745: goto fail;
746: }
747:
1.30 djm 748: attrp = key_attr[1].pValue;
749: octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen);
750: if (octet == NULL) {
751: ossl_error("d2i_ASN1_OCTET_STRING failed");
752: goto fail;
753: }
754: attrp = octet->data;
755: if (o2i_ECPublicKey(&ec, &attrp, octet->length) == NULL) {
756: ossl_error("o2i_ECPublicKey failed");
757: goto fail;
1.28 djm 758: }
759:
760: nid = sshkey_ecdsa_key_to_nid(ec);
761: if (nid < 0) {
762: error("couldn't get curve nid");
763: goto fail;
764: }
765:
766: if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
767: goto fail;
768:
769: key = sshkey_new(KEY_UNSPEC);
770: if (key == NULL) {
771: error("sshkey_new failed");
772: goto fail;
773: }
774:
775: key->ecdsa = ec;
776: key->ecdsa_nid = nid;
777: key->type = KEY_ECDSA;
778: key->flags |= SSHKEY_FLAG_EXT;
779: ec = NULL; /* now owned by key */
780:
781: fail:
782: for (i = 0; i < 3; i++)
783: free(key_attr[i].pValue);
784: if (ec)
785: EC_KEY_free(ec);
786: if (group)
787: EC_GROUP_free(group);
1.30 djm 788: if (octet)
789: ASN1_OCTET_STRING_free(octet);
1.28 djm 790:
791: return (key);
792: }
793:
794: static struct sshkey *
795: pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
796: CK_OBJECT_HANDLE *obj)
797: {
798: CK_ATTRIBUTE key_attr[3];
799: CK_SESSION_HANDLE session;
800: CK_FUNCTION_LIST *f = NULL;
801: CK_RV rv;
802: RSA *rsa = NULL;
803: BIGNUM *rsa_n, *rsa_e;
804: struct sshkey *key = NULL;
805: int i;
806:
807: memset(&key_attr, 0, sizeof(key_attr));
808: key_attr[0].type = CKA_ID;
809: key_attr[1].type = CKA_MODULUS;
810: key_attr[2].type = CKA_PUBLIC_EXPONENT;
811:
812: session = p->slotinfo[slotidx].session;
813: f = p->function_list;
814:
815: /* figure out size of the attributes */
816: rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
817: if (rv != CKR_OK) {
818: error("C_GetAttributeValue failed: %lu", rv);
819: return (NULL);
820: }
821:
822: /*
823: * Allow CKA_ID (always first attribute) to be empty, but
824: * ensure that none of the others are zero length.
825: * XXX assumes CKA_ID is always first.
826: */
827: if (key_attr[1].ulValueLen == 0 ||
828: key_attr[2].ulValueLen == 0) {
829: error("invalid attribute length");
830: return (NULL);
831: }
832:
833: /* allocate buffers for attributes */
834: for (i = 0; i < 3; i++)
835: if (key_attr[i].ulValueLen > 0)
836: key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
837:
838: /* retrieve ID, modulus and public exponent of RSA key */
839: rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
840: if (rv != CKR_OK) {
841: error("C_GetAttributeValue failed: %lu", rv);
842: goto fail;
843: }
844:
845: rsa = RSA_new();
846: if (rsa == NULL) {
847: error("RSA_new failed");
848: goto fail;
849: }
850:
851: rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
852: rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
853: if (rsa_n == NULL || rsa_e == NULL) {
854: error("BN_bin2bn failed");
855: goto fail;
856: }
857: if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
858: fatal("%s: set key", __func__);
859: rsa_n = rsa_e = NULL; /* transferred */
860:
861: if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
862: goto fail;
863:
864: key = sshkey_new(KEY_UNSPEC);
865: if (key == NULL) {
866: error("sshkey_new failed");
867: goto fail;
868: }
869:
870: key->rsa = rsa;
871: key->type = KEY_RSA;
872: key->flags |= SSHKEY_FLAG_EXT;
873: rsa = NULL; /* now owned by key */
874:
875: fail:
876: for (i = 0; i < 3; i++)
877: free(key_attr[i].pValue);
878: RSA_free(rsa);
879:
880: return (key);
881: }
882:
1.47 ! djm 883: static int
1.28 djm 884: pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
1.47 ! djm 885: CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp)
1.28 djm 886: {
887: CK_ATTRIBUTE cert_attr[3];
888: CK_SESSION_HANDLE session;
889: CK_FUNCTION_LIST *f = NULL;
890: CK_RV rv;
891: X509 *x509 = NULL;
1.47 ! djm 892: X509_NAME *x509_name = NULL;
1.28 djm 893: EVP_PKEY *evp;
894: RSA *rsa = NULL;
895: EC_KEY *ec = NULL;
896: struct sshkey *key = NULL;
897: int i;
898: int nid;
1.47 ! djm 899: const u_char *cp;
! 900: char *subject = NULL;
! 901:
! 902: *keyp = NULL;
! 903: *labelp = NULL;
1.28 djm 904:
905: memset(&cert_attr, 0, sizeof(cert_attr));
906: cert_attr[0].type = CKA_ID;
907: cert_attr[1].type = CKA_SUBJECT;
908: cert_attr[2].type = CKA_VALUE;
909:
910: session = p->slotinfo[slotidx].session;
911: f = p->function_list;
912:
913: /* figure out size of the attributes */
914: rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
915: if (rv != CKR_OK) {
916: error("C_GetAttributeValue failed: %lu", rv);
1.47 ! djm 917: return -1;
1.28 djm 918: }
919:
920: /*
921: * Allow CKA_ID (always first attribute) to be empty, but
922: * ensure that none of the others are zero length.
923: * XXX assumes CKA_ID is always first.
924: */
925: if (cert_attr[1].ulValueLen == 0 ||
926: cert_attr[2].ulValueLen == 0) {
927: error("invalid attribute length");
1.47 ! djm 928: return -1;
1.28 djm 929: }
930:
931: /* allocate buffers for attributes */
932: for (i = 0; i < 3; i++)
933: if (cert_attr[i].ulValueLen > 0)
934: cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
935:
936: /* retrieve ID, subject and value of certificate */
937: rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
938: if (rv != CKR_OK) {
939: error("C_GetAttributeValue failed: %lu", rv);
1.47 ! djm 940: goto out;
1.28 djm 941: }
942:
1.47 ! djm 943: /* Decode DER-encoded cert subject */
! 944: cp = cert_attr[2].pValue;
! 945: if ((x509_name = d2i_X509_NAME(NULL, &cp,
! 946: cert_attr[1].ulValueLen)) == NULL ||
! 947: (subject = X509_NAME_oneline(x509_name, NULL, 0)) == NULL)
! 948: subject = xstrdup("invalid subject");
! 949: X509_NAME_free(x509_name);
1.28 djm 950:
951: cp = cert_attr[2].pValue;
1.47 ! djm 952: if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) {
1.28 djm 953: error("d2i_x509 failed");
1.47 ! djm 954: goto out;
1.28 djm 955: }
956:
1.47 ! djm 957: if ((evp = X509_get_pubkey(x509)) == NULL) {
1.28 djm 958: error("X509_get_pubkey failed");
1.47 ! djm 959: goto out;
1.28 djm 960: }
961:
962: if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
963: if (EVP_PKEY_get0_RSA(evp) == NULL) {
964: error("invalid x509; no rsa key");
1.47 ! djm 965: goto out;
1.28 djm 966: }
967: if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
968: error("RSAPublicKey_dup failed");
1.47 ! djm 969: goto out;
1.28 djm 970: }
971:
972: if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
1.47 ! djm 973: goto out;
1.28 djm 974:
975: key = sshkey_new(KEY_UNSPEC);
976: if (key == NULL) {
977: error("sshkey_new failed");
1.47 ! djm 978: goto out;
1.28 djm 979: }
980:
981: key->rsa = rsa;
982: key->type = KEY_RSA;
983: key->flags |= SSHKEY_FLAG_EXT;
984: rsa = NULL; /* now owned by key */
985: } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
1.31 djm 986: if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
1.28 djm 987: error("invalid x509; no ec key");
1.47 ! djm 988: goto out;
1.28 djm 989: }
1.31 djm 990: if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
1.28 djm 991: error("EC_KEY_dup failed");
1.47 ! djm 992: goto out;
1.28 djm 993: }
994:
995: nid = sshkey_ecdsa_key_to_nid(ec);
996: if (nid < 0) {
997: error("couldn't get curve nid");
1.47 ! djm 998: goto out;
1.28 djm 999: }
1000:
1001: if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
1.47 ! djm 1002: goto out;
1.28 djm 1003:
1004: key = sshkey_new(KEY_UNSPEC);
1005: if (key == NULL) {
1006: error("sshkey_new failed");
1.47 ! djm 1007: goto out;
1.28 djm 1008: }
1009:
1010: key->ecdsa = ec;
1011: key->ecdsa_nid = nid;
1012: key->type = KEY_ECDSA;
1013: key->flags |= SSHKEY_FLAG_EXT;
1014: ec = NULL; /* now owned by key */
1.47 ! djm 1015: } else {
1.28 djm 1016: error("unknown certificate key type");
1.47 ! djm 1017: goto out;
! 1018: }
! 1019: out:
1.28 djm 1020: for (i = 0; i < 3; i++)
1021: free(cert_attr[i].pValue);
1022: X509_free(x509);
1023: RSA_free(rsa);
1024: EC_KEY_free(ec);
1.47 ! djm 1025: if (key == NULL) {
! 1026: free(subject);
! 1027: return -1;
! 1028: }
! 1029: /* success */
! 1030: *keyp = key;
! 1031: *labelp = subject;
! 1032: return 0;
1.28 djm 1033: }
1034:
1035: #if 0
1.9 markus 1036: static int
1.27 djm 1037: have_rsa_key(const RSA *rsa)
1038: {
1039: const BIGNUM *rsa_n, *rsa_e;
1040:
1041: RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
1042: return rsa_n != NULL && rsa_e != NULL;
1043: }
1.28 djm 1044: #endif
1.27 djm 1045:
1.28 djm 1046: /*
1047: * lookup certificates for token in slot identified by slotidx,
1048: * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1049: * keysp points to an (possibly empty) array with *nkeys keys.
1050: */
1.27 djm 1051: static int
1.28 djm 1052: pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
1.47 ! djm 1053: struct sshkey ***keysp, char ***labelsp, int *nkeys)
1.1 markus 1054: {
1.28 djm 1055: struct sshkey *key = NULL;
1056: CK_OBJECT_CLASS key_class;
1057: CK_ATTRIBUTE key_attr[1];
1058: CK_SESSION_HANDLE session;
1059: CK_FUNCTION_LIST *f = NULL;
1060: CK_RV rv;
1061: CK_OBJECT_HANDLE obj;
1062: CK_ULONG n = 0;
1063: int ret = -1;
1.47 ! djm 1064: char *label;
1.28 djm 1065:
1066: memset(&key_attr, 0, sizeof(key_attr));
1067: memset(&obj, 0, sizeof(obj));
1068:
1069: key_class = CKO_CERTIFICATE;
1070: key_attr[0].type = CKA_CLASS;
1071: key_attr[0].pValue = &key_class;
1072: key_attr[0].ulValueLen = sizeof(key_class);
1.1 markus 1073:
1.28 djm 1074: session = p->slotinfo[slotidx].session;
1.1 markus 1075: f = p->function_list;
1.28 djm 1076:
1077: rv = f->C_FindObjectsInit(session, key_attr, 1);
1078: if (rv != CKR_OK) {
1.1 markus 1079: error("C_FindObjectsInit failed: %lu", rv);
1.28 djm 1080: goto fail;
1.1 markus 1081: }
1.28 djm 1082:
1.1 markus 1083: while (1) {
1.28 djm 1084: CK_CERTIFICATE_TYPE ck_cert_type;
1085:
1086: rv = f->C_FindObjects(session, &obj, 1, &n);
1087: if (rv != CKR_OK) {
1088: error("C_FindObjects failed: %lu", rv);
1089: goto fail;
1.1 markus 1090: }
1.28 djm 1091: if (n == 0)
1.1 markus 1092: break;
1.28 djm 1093:
1094: memset(&ck_cert_type, 0, sizeof(ck_cert_type));
1095: memset(&key_attr, 0, sizeof(key_attr));
1096: key_attr[0].type = CKA_CERTIFICATE_TYPE;
1097: key_attr[0].pValue = &ck_cert_type;
1098: key_attr[0].ulValueLen = sizeof(ck_cert_type);
1099:
1100: rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
1101: if (rv != CKR_OK) {
1.1 markus 1102: error("C_GetAttributeValue failed: %lu", rv);
1.28 djm 1103: goto fail;
1104: }
1105:
1.47 ! djm 1106: key = NULL;
! 1107: label = NULL;
1.28 djm 1108: switch (ck_cert_type) {
1109: case CKC_X_509:
1.47 ! djm 1110: if (pkcs11_fetch_x509_pubkey(p, slotidx, &obj,
! 1111: &key, &label) != 0) {
! 1112: error("failed to fetch key");
! 1113: continue;
! 1114: }
1.28 djm 1115: break;
1116: default:
1.47 ! djm 1117: error("skipping unsupported certificate type %lu",
! 1118: ck_cert_type);
1.6 markus 1119: continue;
1120: }
1.28 djm 1121:
1122: if (pkcs11_key_included(keysp, nkeys, key)) {
1123: sshkey_free(key);
1124: } else {
1125: /* expand key array and add key */
1126: *keysp = xrecallocarray(*keysp, *nkeys,
1127: *nkeys + 1, sizeof(struct sshkey *));
1128: (*keysp)[*nkeys] = key;
1.47 ! djm 1129: if (labelsp != NULL) {
! 1130: *labelsp = xrecallocarray(*labelsp, *nkeys,
! 1131: *nkeys + 1, sizeof(char *));
! 1132: (*labelsp)[*nkeys] = xstrdup((char *)label);
! 1133: }
1.28 djm 1134: *nkeys = *nkeys + 1;
1135: debug("have %d keys", *nkeys);
1.21 djm 1136: }
1.28 djm 1137: }
1138:
1139: ret = 0;
1140: fail:
1141: rv = f->C_FindObjectsFinal(session);
1142: if (rv != CKR_OK) {
1143: error("C_FindObjectsFinal failed: %lu", rv);
1144: ret = -1;
1145: }
1146:
1147: return (ret);
1148: }
1.21 djm 1149:
1.28 djm 1150: /*
1151: * lookup public keys for token in slot identified by slotidx,
1152: * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1153: * keysp points to an (possibly empty) array with *nkeys keys.
1154: */
1155: static int
1156: pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
1.47 ! djm 1157: struct sshkey ***keysp, char ***labelsp, int *nkeys)
1.28 djm 1158: {
1159: struct sshkey *key = NULL;
1160: CK_OBJECT_CLASS key_class;
1.47 ! djm 1161: CK_ATTRIBUTE key_attr[2];
1.28 djm 1162: CK_SESSION_HANDLE session;
1163: CK_FUNCTION_LIST *f = NULL;
1164: CK_RV rv;
1165: CK_OBJECT_HANDLE obj;
1166: CK_ULONG n = 0;
1167: int ret = -1;
1168:
1169: memset(&key_attr, 0, sizeof(key_attr));
1170: memset(&obj, 0, sizeof(obj));
1171:
1172: key_class = CKO_PUBLIC_KEY;
1173: key_attr[0].type = CKA_CLASS;
1174: key_attr[0].pValue = &key_class;
1175: key_attr[0].ulValueLen = sizeof(key_class);
1176:
1177: session = p->slotinfo[slotidx].session;
1178: f = p->function_list;
1179:
1180: rv = f->C_FindObjectsInit(session, key_attr, 1);
1181: if (rv != CKR_OK) {
1182: error("C_FindObjectsInit failed: %lu", rv);
1183: goto fail;
1184: }
1185:
1186: while (1) {
1187: CK_KEY_TYPE ck_key_type;
1.47 ! djm 1188: CK_UTF8CHAR label[256];
1.28 djm 1189:
1190: rv = f->C_FindObjects(session, &obj, 1, &n);
1191: if (rv != CKR_OK) {
1192: error("C_FindObjects failed: %lu", rv);
1193: goto fail;
1194: }
1195: if (n == 0)
1196: break;
1197:
1198: memset(&ck_key_type, 0, sizeof(ck_key_type));
1199: memset(&key_attr, 0, sizeof(key_attr));
1200: key_attr[0].type = CKA_KEY_TYPE;
1201: key_attr[0].pValue = &ck_key_type;
1202: key_attr[0].ulValueLen = sizeof(ck_key_type);
1.47 ! djm 1203: key_attr[1].type = CKA_LABEL;
! 1204: key_attr[1].pValue = &label;
! 1205: key_attr[1].ulValueLen = sizeof(label) - 1;
1.28 djm 1206:
1.47 ! djm 1207: rv = f->C_GetAttributeValue(session, obj, key_attr, 2);
1.28 djm 1208: if (rv != CKR_OK) {
1.1 markus 1209: error("C_GetAttributeValue failed: %lu", rv);
1.28 djm 1210: goto fail;
1211: }
1212:
1.47 ! djm 1213: label[key_attr[1].ulValueLen] = '\0';
! 1214:
1.28 djm 1215: switch (ck_key_type) {
1216: case CKK_RSA:
1217: key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1218: break;
1219: case CKK_ECDSA:
1220: key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1221: break;
1222: default:
1223: /* XXX print key type? */
1.43 markus 1224: key = NULL;
1.28 djm 1225: error("skipping unsupported key type");
1226: }
1227:
1228: if (key == NULL) {
1229: error("failed to fetch key");
1230: continue;
1231: }
1232:
1233: if (pkcs11_key_included(keysp, nkeys, key)) {
1234: sshkey_free(key);
1.1 markus 1235: } else {
1.28 djm 1236: /* expand key array and add key */
1237: *keysp = xrecallocarray(*keysp, *nkeys,
1238: *nkeys + 1, sizeof(struct sshkey *));
1239: (*keysp)[*nkeys] = key;
1.47 ! djm 1240: if (labelsp != NULL) {
! 1241: *labelsp = xrecallocarray(*labelsp, *nkeys,
! 1242: *nkeys + 1, sizeof(char *));
! 1243: (*labelsp)[*nkeys] = xstrdup((char *)label);
! 1244: }
1.28 djm 1245: *nkeys = *nkeys + 1;
1246: debug("have %d keys", *nkeys);
1.1 markus 1247: }
1248: }
1.28 djm 1249:
1250: ret = 0;
1251: fail:
1252: rv = f->C_FindObjectsFinal(session);
1253: if (rv != CKR_OK) {
1.1 markus 1254: error("C_FindObjectsFinal failed: %lu", rv);
1.28 djm 1255: ret = -1;
1256: }
1257:
1258: return (ret);
1259: }
1260:
1261: #ifdef WITH_PKCS11_KEYGEN
1262: #define FILL_ATTR(attr, idx, typ, val, len) \
1263: { (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; }
1264:
1265: static struct sshkey *
1266: pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1267: char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1268: {
1269: struct pkcs11_slotinfo *si;
1270: char *plabel = label ? label : "";
1271: int npub = 0, npriv = 0;
1272: CK_RV rv;
1273: CK_FUNCTION_LIST *f;
1274: CK_SESSION_HANDLE session;
1275: CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1276: CK_OBJECT_HANDLE pubKey, privKey;
1277: CK_ATTRIBUTE tpub[16], tpriv[16];
1278: CK_MECHANISM mech = {
1279: CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
1280: };
1281: CK_BYTE pubExponent[] = {
1282: 0x01, 0x00, 0x01 /* RSA_F4 in bytes */
1283: };
1284:
1285: *err = 0;
1286:
1287: FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1288: FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1289: FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1290: FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1291: FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1292: sizeof(false_val));
1293: FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1294: FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1295: FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits));
1296: FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent,
1297: sizeof(pubExponent));
1298: FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1299:
1300: FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1301: FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1302: FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1303: FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1304: FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1305: FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1306: FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1307: sizeof(false_val));
1308: FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1309: FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1310: FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1311:
1312: f = p->function_list;
1313: si = &p->slotinfo[slotidx];
1314: session = si->session;
1315:
1316: if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1317: &pubKey, &privKey)) != CKR_OK) {
1318: error("%s: key generation failed: error 0x%lx", __func__, rv);
1319: *err = rv;
1320: return NULL;
1321: }
1322:
1323: return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey);
1324: }
1325:
1326: static int
1327: pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen)
1328: {
1329: size_t i, len;
1330: char ptr[3];
1331:
1332: if (dest)
1333: *dest = NULL;
1334: if (rlen)
1335: *rlen = 0;
1336:
1337: if ((len = strlen(hex)) % 2)
1338: return -1;
1339: len /= 2;
1340:
1341: *dest = xmalloc(len);
1342:
1343: ptr[2] = '\0';
1344: for (i = 0; i < len; i++) {
1345: ptr[0] = hex[2 * i];
1346: ptr[1] = hex[(2 * i) + 1];
1347: if (!isxdigit(ptr[0]) || !isxdigit(ptr[1]))
1348: return -1;
1349: (*dest)[i] = (unsigned char)strtoul(ptr, NULL, 16);
1350: }
1351:
1352: if (rlen)
1353: *rlen = len;
1354:
1355: return 0;
1356: }
1357:
1358: static struct ec_curve_info {
1359: const char *name;
1360: const char *oid;
1361: const char *oid_encoded;
1362: size_t size;
1363: } ec_curve_infos[] = {
1364: {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
1365: {"secp384r1", "1.3.132.0.34", "06052B81040022", 384},
1366: {"secp521r1", "1.3.132.0.35", "06052B81040023", 521},
1.35 djm 1367: {NULL, NULL, NULL, 0},
1.28 djm 1368: };
1369:
1370: static struct sshkey *
1371: pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1372: char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1373: {
1374: struct pkcs11_slotinfo *si;
1375: char *plabel = label ? label : "";
1376: int i;
1377: size_t ecparams_size;
1378: unsigned char *ecparams = NULL;
1379: int npub = 0, npriv = 0;
1380: CK_RV rv;
1381: CK_FUNCTION_LIST *f;
1382: CK_SESSION_HANDLE session;
1383: CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1384: CK_OBJECT_HANDLE pubKey, privKey;
1385: CK_MECHANISM mech = {
1386: CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
1387: };
1388: CK_ATTRIBUTE tpub[16], tpriv[16];
1389:
1390: *err = 0;
1391:
1392: for (i = 0; ec_curve_infos[i].name; i++) {
1393: if (ec_curve_infos[i].size == bits)
1394: break;
1395: }
1396: if (!ec_curve_infos[i].name) {
1397: error("%s: invalid key size %lu", __func__, bits);
1398: return NULL;
1399: }
1400: if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams,
1401: &ecparams_size) == -1) {
1402: error("%s: invalid oid", __func__);
1403: return NULL;
1404: }
1405:
1406: FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1407: FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1408: FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1409: FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1410: FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1411: sizeof(false_val));
1412: FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1413: FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1414: FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size);
1415: FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1416:
1417: FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1418: FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1419: FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1420: FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1421: FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1422: FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1423: FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1424: sizeof(false_val));
1425: FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1426: FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1427: FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1428:
1429: f = p->function_list;
1430: si = &p->slotinfo[slotidx];
1431: session = si->session;
1432:
1433: if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1434: &pubKey, &privKey)) != CKR_OK) {
1435: error("%s: key generation failed: error 0x%lx", __func__, rv);
1436: *err = rv;
1437: return NULL;
1438: }
1439:
1440: return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey);
1.1 markus 1441: }
1.28 djm 1442: #endif /* WITH_PKCS11_KEYGEN */
1.1 markus 1443:
1.28 djm 1444: /*
1445: * register a new provider, fails if provider already exists. if
1446: * keyp is provided, fetch keys.
1447: */
1448: static int
1.47 ! djm 1449: pkcs11_register_provider(char *provider_id, char *pin,
! 1450: struct sshkey ***keyp, char ***labelsp,
1.28 djm 1451: struct pkcs11_provider **providerp, CK_ULONG user)
1.1 markus 1452: {
1453: int nkeys, need_finalize = 0;
1.28 djm 1454: int ret = -1;
1.1 markus 1455: struct pkcs11_provider *p = NULL;
1456: void *handle = NULL;
1457: CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
1458: CK_RV rv;
1459: CK_FUNCTION_LIST *f = NULL;
1460: CK_TOKEN_INFO *token;
1461: CK_ULONG i;
1462:
1.28 djm 1463: if (providerp == NULL)
1464: goto fail;
1465: *providerp = NULL;
1466:
1467: if (keyp != NULL)
1468: *keyp = NULL;
1.47 ! djm 1469: if (labelsp != NULL)
! 1470: *labelsp = NULL;
1.28 djm 1471:
1.1 markus 1472: if (pkcs11_provider_lookup(provider_id) != NULL) {
1.23 djm 1473: debug("%s: provider already registered: %s",
1474: __func__, provider_id);
1.1 markus 1475: goto fail;
1476: }
1.28 djm 1477: /* open shared pkcs11-library */
1.1 markus 1478: if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
1479: error("dlopen %s failed: %s", provider_id, dlerror());
1480: goto fail;
1481: }
1482: if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
1483: error("dlsym(C_GetFunctionList) failed: %s", dlerror());
1484: goto fail;
1485: }
1486: p = xcalloc(1, sizeof(*p));
1487: p->name = xstrdup(provider_id);
1488: p->handle = handle;
1489: /* setup the pkcs11 callbacks */
1490: if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
1.23 djm 1491: error("C_GetFunctionList for provider %s failed: %lu",
1492: provider_id, rv);
1.1 markus 1493: goto fail;
1494: }
1495: p->function_list = f;
1496: if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
1.23 djm 1497: error("C_Initialize for provider %s failed: %lu",
1498: provider_id, rv);
1.1 markus 1499: goto fail;
1500: }
1501: need_finalize = 1;
1502: if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
1.23 djm 1503: error("C_GetInfo for provider %s failed: %lu",
1504: provider_id, rv);
1.1 markus 1505: goto fail;
1506: }
1507: rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
1508: rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
1.23 djm 1509: debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d"
1.1 markus 1510: " libraryDescription <%s> libraryVersion %d.%d",
1.23 djm 1511: provider_id,
1.1 markus 1512: p->info.manufacturerID,
1513: p->info.cryptokiVersion.major,
1514: p->info.cryptokiVersion.minor,
1515: p->info.libraryDescription,
1516: p->info.libraryVersion.major,
1517: p->info.libraryVersion.minor);
1518: if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
1519: error("C_GetSlotList failed: %lu", rv);
1520: goto fail;
1521: }
1522: if (p->nslots == 0) {
1.44 djm 1523: debug("%s: provider %s returned no slots", __func__,
1.23 djm 1524: provider_id);
1.28 djm 1525: ret = -SSH_PKCS11_ERR_NO_SLOTS;
1.1 markus 1526: goto fail;
1527: }
1528: p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
1529: if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
1530: != CKR_OK) {
1.23 djm 1531: error("C_GetSlotList for provider %s failed: %lu",
1532: provider_id, rv);
1.1 markus 1533: goto fail;
1534: }
1535: p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
1536: p->valid = 1;
1537: nkeys = 0;
1538: for (i = 0; i < p->nslots; i++) {
1539: token = &p->slotinfo[i].token;
1540: if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
1541: != CKR_OK) {
1.23 djm 1542: error("C_GetTokenInfo for provider %s slot %lu "
1543: "failed: %lu", provider_id, (unsigned long)i, rv);
1.20 djm 1544: continue;
1545: }
1546: if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
1.23 djm 1547: debug2("%s: ignoring uninitialised token in "
1548: "provider %s slot %lu", __func__,
1549: provider_id, (unsigned long)i);
1.1 markus 1550: continue;
1551: }
1552: rmspace(token->label, sizeof(token->label));
1553: rmspace(token->manufacturerID, sizeof(token->manufacturerID));
1554: rmspace(token->model, sizeof(token->model));
1555: rmspace(token->serialNumber, sizeof(token->serialNumber));
1.23 djm 1556: debug("provider %s slot %lu: label <%s> manufacturerID <%s> "
1557: "model <%s> serial <%s> flags 0x%lx",
1558: provider_id, (unsigned long)i,
1.1 markus 1559: token->label, token->manufacturerID, token->model,
1560: token->serialNumber, token->flags);
1.28 djm 1561: /*
1562: * open session, login with pin and retrieve public
1563: * keys (if keyp is provided)
1564: */
1.45 djm 1565: if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 ||
1566: keyp == NULL)
1567: continue;
1.47 ! djm 1568: pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
! 1569: pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
1.45 djm 1570: if (nkeys == 0 && !p->slotinfo[i].logged_in &&
1571: pkcs11_interactive) {
1572: /*
1573: * Some tokens require login before they will
1574: * expose keys.
1575: */
1576: if (pkcs11_login_slot(p, &p->slotinfo[i],
1577: CKU_USER) < 0) {
1578: error("login failed");
1.28 djm 1579: continue;
1.45 djm 1580: }
1.47 ! djm 1581: pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
! 1582: pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
1.28 djm 1583: }
1.1 markus 1584: }
1.28 djm 1585:
1586: /* now owned by caller */
1587: *providerp = p;
1588:
1589: TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
1590: p->refcount++; /* add to provider list */
1591:
1592: return (nkeys);
1.1 markus 1593: fail:
1594: if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
1.23 djm 1595: error("C_Finalize for provider %s failed: %lu",
1596: provider_id, rv);
1.1 markus 1597: if (p) {
1.28 djm 1598: free(p->name);
1.7 djm 1599: free(p->slotlist);
1600: free(p->slotinfo);
1601: free(p);
1.1 markus 1602: }
1603: if (handle)
1604: dlclose(handle);
1.28 djm 1605: return (ret);
1606: }
1607:
1608: /*
1609: * register a new provider and get number of keys hold by the token,
1610: * fails if provider already exists
1611: */
1612: int
1.47 ! djm 1613: pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
! 1614: char ***labelsp)
1.28 djm 1615: {
1616: struct pkcs11_provider *p = NULL;
1617: int nkeys;
1618:
1.47 ! djm 1619: nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp,
! 1620: &p, CKU_USER);
1.28 djm 1621:
1622: /* no keys found or some other error, de-register provider */
1623: if (nkeys <= 0 && p != NULL) {
1624: TAILQ_REMOVE(&pkcs11_providers, p, next);
1625: pkcs11_provider_finalize(p);
1626: pkcs11_provider_unref(p);
1627: }
1628: if (nkeys == 0)
1629: debug("%s: provider %s returned no keys", __func__,
1630: provider_id);
1631:
1632: return (nkeys);
1633: }
1634:
1635: #ifdef WITH_PKCS11_KEYGEN
1636: struct sshkey *
1637: pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
1638: unsigned int type, unsigned int bits, unsigned char keyid, u_int32_t *err)
1639: {
1640: struct pkcs11_provider *p = NULL;
1641: struct pkcs11_slotinfo *si;
1642: CK_FUNCTION_LIST *f;
1643: CK_SESSION_HANDLE session;
1644: struct sshkey *k = NULL;
1645: int ret = -1, reset_pin = 0, reset_provider = 0;
1646: CK_RV rv;
1647:
1648: *err = 0;
1649:
1650: if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
1651: debug("%s: provider \"%s\" available", __func__, provider_id);
1.47 ! djm 1652: else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, NULL,
! 1653: &p, CKU_SO)) < 0) {
1.28 djm 1654: debug("%s: could not register provider %s", __func__,
1655: provider_id);
1656: goto out;
1657: } else
1658: reset_provider = 1;
1659:
1660: f = p->function_list;
1661: si = &p->slotinfo[slotidx];
1662: session = si->session;
1663:
1664: if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1665: CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1666: debug("%s: could not supply SO pin: %lu", __func__, rv);
1667: reset_pin = 0;
1668: } else
1669: reset_pin = 1;
1670:
1671: switch (type) {
1672: case KEY_RSA:
1673: if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label,
1674: bits, keyid, err)) == NULL) {
1675: debug("%s: failed to generate RSA key", __func__);
1676: goto out;
1677: }
1678: break;
1679: case KEY_ECDSA:
1680: if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label,
1681: bits, keyid, err)) == NULL) {
1682: debug("%s: failed to generate ECDSA key", __func__);
1683: goto out;
1684: }
1685: break;
1686: default:
1687: *err = SSH_PKCS11_ERR_GENERIC;
1688: debug("%s: unknown type %d", __func__, type);
1689: goto out;
1690: }
1691:
1692: out:
1693: if (reset_pin)
1694: f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1695: CK_INVALID_HANDLE);
1696:
1697: if (reset_provider)
1698: pkcs11_del_provider(provider_id);
1699:
1700: return (k);
1701: }
1702:
1703: struct sshkey *
1704: pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
1705: unsigned char keyid, u_int32_t *err)
1706: {
1707: struct pkcs11_provider *p = NULL;
1708: struct pkcs11_slotinfo *si;
1709: struct sshkey *k = NULL;
1710: int reset_pin = 0, reset_provider = 0;
1711: CK_ULONG nattrs;
1712: CK_FUNCTION_LIST *f;
1713: CK_SESSION_HANDLE session;
1714: CK_ATTRIBUTE attrs[16];
1715: CK_OBJECT_CLASS key_class;
1716: CK_KEY_TYPE key_type;
1717: CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE;
1718: CK_RV rv;
1719:
1720: *err = 0;
1721:
1722: if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
1723: debug("%s: using provider \"%s\"", __func__, provider_id);
1.47 ! djm 1724: } else if (pkcs11_register_provider(provider_id, pin, NULL, NULL, &p,
1.28 djm 1725: CKU_SO) < 0) {
1726: debug("%s: could not register provider %s", __func__,
1727: provider_id);
1728: goto out;
1729: } else
1730: reset_provider = 1;
1731:
1732: f = p->function_list;
1733: si = &p->slotinfo[slotidx];
1734: session = si->session;
1735:
1736: if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1737: CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1738: debug("%s: could not supply SO pin: %lu", __func__, rv);
1739: reset_pin = 0;
1740: } else
1741: reset_pin = 1;
1742:
1743: /* private key */
1744: nattrs = 0;
1745: key_class = CKO_PRIVATE_KEY;
1746: FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1747: FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1748:
1749: if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1750: obj != CK_INVALID_HANDLE) {
1751: if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1752: debug("%s: could not destroy private key 0x%hhx",
1753: __func__, keyid);
1754: *err = rv;
1755: goto out;
1756: }
1757: }
1758:
1759: /* public key */
1760: nattrs = 0;
1761: key_class = CKO_PUBLIC_KEY;
1762: FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1763: FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1764:
1765: if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1766: obj != CK_INVALID_HANDLE) {
1767:
1768: /* get key type */
1769: nattrs = 0;
1770: FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type,
1771: sizeof(key_type));
1772: rv = f->C_GetAttributeValue(session, obj, attrs, nattrs);
1773: if (rv != CKR_OK) {
1774: debug("%s: could not get key type of public key 0x%hhx",
1775: __func__, keyid);
1776: *err = rv;
1777: key_type = -1;
1778: }
1779: if (key_type == CKK_RSA)
1780: k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1781: else if (key_type == CKK_ECDSA)
1782: k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1783:
1784: if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1785: debug("%s: could not destroy public key 0x%hhx",
1786: __func__, keyid);
1787: *err = rv;
1788: goto out;
1789: }
1790: }
1791:
1792: out:
1793: if (reset_pin)
1794: f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1795: CK_INVALID_HANDLE);
1796:
1797: if (reset_provider)
1798: pkcs11_del_provider(provider_id);
1799:
1800: return (k);
1.1 markus 1801: }
1.28 djm 1802: #endif /* WITH_PKCS11_KEYGEN */
1.2 markus 1803: #else
1804: int
1.15 djm 1805: pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
1.2 markus 1806: {
1807: error("dlopen() not supported");
1808: return (-1);
1809: }
1.28 djm 1810: #endif /* HAVE_DLOPEN */