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