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