Annotation of src/usr.bin/ssh/ssh-pkcs11.c, Revision 1.32
1.32 ! djm 1: /* $OpenBSD: ssh-pkcs11.c,v 1.31 2019/01/20 23:03:26 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;
1.32 ! djm 453: static int ec_key_idx = 0;
! 454:
! 455: static void
! 456: pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
! 457: long argl, void *argp)
! 458: {
! 459: struct pkcs11_key *k11 = ptr;
! 460:
! 461: if (k11 == NULL)
! 462: return;
! 463: if (k11->provider)
! 464: pkcs11_provider_unref(k11->provider);
! 465: free(k11->keyid);
! 466: free(k11);
! 467: }
1.28 djm 468:
469: static int
470: pkcs11_ecdsa_start_wrapper(void)
471: {
472: int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
473: unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
474:
475: if (ec_key_method != NULL)
476: return (0);
1.32 ! djm 477: ec_key_idx = EC_KEY_get_ex_new_index(0, "ssh-pkcs11-ecdsa",
! 478: NULL, NULL, pkcs11_k11_free);
! 479: if (ec_key_idx == -1)
! 480: return (-1);
1.28 djm 481: ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
482: if (ec_key_method == NULL)
483: return (-1);
484: EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
485: EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
486: return (0);
487: }
488:
489: static int
490: pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
491: CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
492: {
493: struct pkcs11_key *k11;
494:
495: if (pkcs11_ecdsa_start_wrapper() == -1)
496: return (-1);
497:
498: k11 = xcalloc(1, sizeof(*k11));
499: k11->provider = provider;
500: provider->refcount++; /* provider referenced by ECDSA key */
501: k11->slotidx = slotidx;
502: /* identify key object on smartcard */
503: k11->keyid_len = keyid_attrib->ulValueLen;
504: k11->keyid = xmalloc(k11->keyid_len);
505: memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
506: k11->ec_key_method = ec_key_method;
507:
508: EC_KEY_set_method(ec, k11->ec_key_method);
1.32 ! djm 509: EC_KEY_set_ex_data(ec, ec_key_idx, k11);
1.28 djm 510:
511: return (0);
512: }
513:
1.1 markus 514: /* remove trailing spaces */
515: static void
1.8 djm 516: rmspace(u_char *buf, size_t len)
1.1 markus 517: {
518: size_t i;
519:
520: if (!len)
521: return;
522: for (i = len - 1; i > 0; i--)
523: if (i == len - 1 || buf[i] == ' ')
524: buf[i] = '\0';
525: else
526: break;
527: }
528:
529: /*
530: * open a pkcs11 session and login if required.
531: * if pin == NULL we delay login until key use
532: */
533: static int
1.28 djm 534: pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin,
535: CK_ULONG user)
1.1 markus 536: {
537: CK_RV rv;
538: CK_FUNCTION_LIST *f;
539: CK_SESSION_HANDLE session;
1.28 djm 540: int login_required, ret;
1.1 markus 541:
542: f = p->function_list;
543: login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED;
544: if (pin && login_required && !strlen(pin)) {
545: error("pin required");
1.28 djm 546: return (-SSH_PKCS11_ERR_PIN_REQUIRED);
1.1 markus 547: }
548: if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
549: CKF_SERIAL_SESSION, NULL, NULL, &session))
550: != CKR_OK) {
551: error("C_OpenSession failed: %lu", rv);
552: return (-1);
553: }
554: if (login_required && pin) {
1.28 djm 555: rv = f->C_Login(session, user,
1.17 deraadt 556: (u_char *)pin, strlen(pin));
1.16 djm 557: if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
1.1 markus 558: error("C_Login failed: %lu", rv);
1.28 djm 559: ret = (rv == CKR_PIN_LOCKED) ?
560: -SSH_PKCS11_ERR_PIN_LOCKED :
561: -SSH_PKCS11_ERR_LOGIN_FAIL;
1.1 markus 562: if ((rv = f->C_CloseSession(session)) != CKR_OK)
563: error("C_CloseSession failed: %lu", rv);
1.28 djm 564: return (ret);
1.1 markus 565: }
566: p->slotinfo[slotidx].logged_in = 1;
567: }
568: p->slotinfo[slotidx].session = session;
569: return (0);
570: }
571:
572: static int
1.15 djm 573: pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
1.9 markus 574: {
575: int i;
576:
577: for (i = 0; i < *nkeys; i++)
1.15 djm 578: if (sshkey_equal(key, (*keysp)[i]))
1.9 markus 579: return (1);
580: return (0);
581: }
582:
1.28 djm 583: static struct sshkey *
584: pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
585: CK_OBJECT_HANDLE *obj)
586: {
587: CK_ATTRIBUTE key_attr[3];
588: CK_SESSION_HANDLE session;
589: CK_FUNCTION_LIST *f = NULL;
590: CK_RV rv;
1.30 djm 591: ASN1_OCTET_STRING *octet = NULL;
1.28 djm 592: EC_KEY *ec = NULL;
593: EC_GROUP *group = NULL;
594: struct sshkey *key = NULL;
595: const unsigned char *attrp = NULL;
596: int i;
597: int nid;
598:
599: memset(&key_attr, 0, sizeof(key_attr));
600: key_attr[0].type = CKA_ID;
601: key_attr[1].type = CKA_EC_POINT;
602: key_attr[2].type = CKA_EC_PARAMS;
603:
604: session = p->slotinfo[slotidx].session;
605: f = p->function_list;
606:
607: /* figure out size of the attributes */
608: rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
609: if (rv != CKR_OK) {
610: error("C_GetAttributeValue failed: %lu", rv);
611: return (NULL);
612: }
613:
614: /*
615: * Allow CKA_ID (always first attribute) to be empty, but
616: * ensure that none of the others are zero length.
617: * XXX assumes CKA_ID is always first.
618: */
619: if (key_attr[1].ulValueLen == 0 ||
620: key_attr[2].ulValueLen == 0) {
621: error("invalid attribute length");
622: return (NULL);
623: }
624:
625: /* allocate buffers for attributes */
626: for (i = 0; i < 3; i++)
627: if (key_attr[i].ulValueLen > 0)
628: key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
629:
630: /* retrieve ID, public point and curve parameters of EC key */
631: rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
632: if (rv != CKR_OK) {
633: error("C_GetAttributeValue failed: %lu", rv);
634: goto fail;
635: }
636:
637: ec = EC_KEY_new();
638: if (ec == NULL) {
639: error("EC_KEY_new failed");
640: goto fail;
641: }
642:
643: attrp = key_attr[2].pValue;
644: group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
645: if (group == NULL) {
646: ossl_error("d2i_ECPKParameters failed");
647: goto fail;
648: }
649:
650: if (EC_KEY_set_group(ec, group) == 0) {
651: ossl_error("EC_KEY_set_group failed");
652: goto fail;
653: }
654:
655: if (key_attr[1].ulValueLen <= 2) {
656: error("CKA_EC_POINT too small");
657: goto fail;
658: }
659:
1.30 djm 660: attrp = key_attr[1].pValue;
661: octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen);
662: if (octet == NULL) {
663: ossl_error("d2i_ASN1_OCTET_STRING failed");
664: goto fail;
665: }
666: attrp = octet->data;
667: if (o2i_ECPublicKey(&ec, &attrp, octet->length) == NULL) {
668: ossl_error("o2i_ECPublicKey failed");
669: goto fail;
1.28 djm 670: }
671:
672: nid = sshkey_ecdsa_key_to_nid(ec);
673: if (nid < 0) {
674: error("couldn't get curve nid");
675: goto fail;
676: }
677:
678: if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
679: goto fail;
680:
681: key = sshkey_new(KEY_UNSPEC);
682: if (key == NULL) {
683: error("sshkey_new failed");
684: goto fail;
685: }
686:
687: key->ecdsa = ec;
688: key->ecdsa_nid = nid;
689: key->type = KEY_ECDSA;
690: key->flags |= SSHKEY_FLAG_EXT;
691: ec = NULL; /* now owned by key */
692:
693: fail:
694: for (i = 0; i < 3; i++)
695: free(key_attr[i].pValue);
696: if (ec)
697: EC_KEY_free(ec);
698: if (group)
699: EC_GROUP_free(group);
1.30 djm 700: if (octet)
701: ASN1_OCTET_STRING_free(octet);
1.28 djm 702:
703: return (key);
704: }
705:
706: static struct sshkey *
707: pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
708: CK_OBJECT_HANDLE *obj)
709: {
710: CK_ATTRIBUTE key_attr[3];
711: CK_SESSION_HANDLE session;
712: CK_FUNCTION_LIST *f = NULL;
713: CK_RV rv;
714: RSA *rsa = NULL;
715: BIGNUM *rsa_n, *rsa_e;
716: struct sshkey *key = NULL;
717: int i;
718:
719: memset(&key_attr, 0, sizeof(key_attr));
720: key_attr[0].type = CKA_ID;
721: key_attr[1].type = CKA_MODULUS;
722: key_attr[2].type = CKA_PUBLIC_EXPONENT;
723:
724: session = p->slotinfo[slotidx].session;
725: f = p->function_list;
726:
727: /* figure out size of the attributes */
728: rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
729: if (rv != CKR_OK) {
730: error("C_GetAttributeValue failed: %lu", rv);
731: return (NULL);
732: }
733:
734: /*
735: * Allow CKA_ID (always first attribute) to be empty, but
736: * ensure that none of the others are zero length.
737: * XXX assumes CKA_ID is always first.
738: */
739: if (key_attr[1].ulValueLen == 0 ||
740: key_attr[2].ulValueLen == 0) {
741: error("invalid attribute length");
742: return (NULL);
743: }
744:
745: /* allocate buffers for attributes */
746: for (i = 0; i < 3; i++)
747: if (key_attr[i].ulValueLen > 0)
748: key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
749:
750: /* retrieve ID, modulus and public exponent of RSA key */
751: rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
752: if (rv != CKR_OK) {
753: error("C_GetAttributeValue failed: %lu", rv);
754: goto fail;
755: }
756:
757: rsa = RSA_new();
758: if (rsa == NULL) {
759: error("RSA_new failed");
760: goto fail;
761: }
762:
763: rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
764: rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
765: if (rsa_n == NULL || rsa_e == NULL) {
766: error("BN_bin2bn failed");
767: goto fail;
768: }
769: if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
770: fatal("%s: set key", __func__);
771: rsa_n = rsa_e = NULL; /* transferred */
772:
773: if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
774: goto fail;
775:
776: key = sshkey_new(KEY_UNSPEC);
777: if (key == NULL) {
778: error("sshkey_new failed");
779: goto fail;
780: }
781:
782: key->rsa = rsa;
783: key->type = KEY_RSA;
784: key->flags |= SSHKEY_FLAG_EXT;
785: rsa = NULL; /* now owned by key */
786:
787: fail:
788: for (i = 0; i < 3; i++)
789: free(key_attr[i].pValue);
790: RSA_free(rsa);
791:
792: return (key);
793: }
794:
795: static struct sshkey *
796: pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
797: CK_OBJECT_HANDLE *obj)
798: {
799: CK_ATTRIBUTE cert_attr[3];
800: CK_SESSION_HANDLE session;
801: CK_FUNCTION_LIST *f = NULL;
802: CK_RV rv;
803: X509 *x509 = NULL;
804: EVP_PKEY *evp;
805: RSA *rsa = NULL;
806: EC_KEY *ec = NULL;
807: struct sshkey *key = NULL;
808: int i;
809: int nid;
810: const u_char *cp;
811:
812: memset(&cert_attr, 0, sizeof(cert_attr));
813: cert_attr[0].type = CKA_ID;
814: cert_attr[1].type = CKA_SUBJECT;
815: cert_attr[2].type = CKA_VALUE;
816:
817: session = p->slotinfo[slotidx].session;
818: f = p->function_list;
819:
820: /* figure out size of the attributes */
821: rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
822: if (rv != CKR_OK) {
823: error("C_GetAttributeValue failed: %lu", rv);
824: return (NULL);
825: }
826:
827: /*
828: * Allow CKA_ID (always first attribute) to be empty, but
829: * ensure that none of the others are zero length.
830: * XXX assumes CKA_ID is always first.
831: */
832: if (cert_attr[1].ulValueLen == 0 ||
833: cert_attr[2].ulValueLen == 0) {
834: error("invalid attribute length");
835: return (NULL);
836: }
837:
838: /* allocate buffers for attributes */
839: for (i = 0; i < 3; i++)
840: if (cert_attr[i].ulValueLen > 0)
841: cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
842:
843: /* retrieve ID, subject and value of certificate */
844: rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
845: if (rv != CKR_OK) {
846: error("C_GetAttributeValue failed: %lu", rv);
847: goto fail;
848: }
849:
850: x509 = X509_new();
851: if (x509 == NULL) {
852: error("x509_new failed");
853: goto fail;
854: }
855:
856: cp = cert_attr[2].pValue;
857: if (d2i_X509(&x509, &cp, cert_attr[2].ulValueLen) == NULL) {
858: error("d2i_x509 failed");
859: goto fail;
860: }
861:
862: evp = X509_get_pubkey(x509);
863: if (evp == NULL) {
864: error("X509_get_pubkey failed");
865: goto fail;
866: }
867:
868: if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
869: if (EVP_PKEY_get0_RSA(evp) == NULL) {
870: error("invalid x509; no rsa key");
871: goto fail;
872: }
873: if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
874: error("RSAPublicKey_dup failed");
875: goto fail;
876: }
877:
878: if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
879: goto fail;
880:
881: key = sshkey_new(KEY_UNSPEC);
882: if (key == NULL) {
883: error("sshkey_new failed");
884: goto fail;
885: }
886:
887: key->rsa = rsa;
888: key->type = KEY_RSA;
889: key->flags |= SSHKEY_FLAG_EXT;
890: rsa = NULL; /* now owned by key */
891: } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
1.31 djm 892: if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
1.28 djm 893: error("invalid x509; no ec key");
894: goto fail;
895: }
1.31 djm 896: if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
1.28 djm 897: error("EC_KEY_dup failed");
898: goto fail;
899: }
900:
901: nid = sshkey_ecdsa_key_to_nid(ec);
902: if (nid < 0) {
903: error("couldn't get curve nid");
904: goto fail;
905: }
906:
907: if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
908: goto fail;
909:
910: key = sshkey_new(KEY_UNSPEC);
911: if (key == NULL) {
912: error("sshkey_new failed");
913: goto fail;
914: }
915:
916: key->ecdsa = ec;
917: key->ecdsa_nid = nid;
918: key->type = KEY_ECDSA;
919: key->flags |= SSHKEY_FLAG_EXT;
920: ec = NULL; /* now owned by key */
921: } else
922: error("unknown certificate key type");
923:
924: fail:
925: for (i = 0; i < 3; i++)
926: free(cert_attr[i].pValue);
927: X509_free(x509);
928: RSA_free(rsa);
929: EC_KEY_free(ec);
930:
931: return (key);
932: }
933:
934: #if 0
1.9 markus 935: static int
1.27 djm 936: have_rsa_key(const RSA *rsa)
937: {
938: const BIGNUM *rsa_n, *rsa_e;
939:
940: RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
941: return rsa_n != NULL && rsa_e != NULL;
942: }
1.28 djm 943: #endif
1.27 djm 944:
1.28 djm 945: /*
946: * lookup certificates for token in slot identified by slotidx,
947: * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
948: * keysp points to an (possibly empty) array with *nkeys keys.
949: */
1.27 djm 950: static int
1.28 djm 951: pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
1.15 djm 952: struct sshkey ***keysp, int *nkeys)
1.1 markus 953: {
1.28 djm 954: struct sshkey *key = NULL;
955: CK_OBJECT_CLASS key_class;
956: CK_ATTRIBUTE key_attr[1];
957: CK_SESSION_HANDLE session;
958: CK_FUNCTION_LIST *f = NULL;
959: CK_RV rv;
960: CK_OBJECT_HANDLE obj;
961: CK_ULONG n = 0;
962: int ret = -1;
963:
964: memset(&key_attr, 0, sizeof(key_attr));
965: memset(&obj, 0, sizeof(obj));
966:
967: key_class = CKO_CERTIFICATE;
968: key_attr[0].type = CKA_CLASS;
969: key_attr[0].pValue = &key_class;
970: key_attr[0].ulValueLen = sizeof(key_class);
1.1 markus 971:
1.28 djm 972: session = p->slotinfo[slotidx].session;
1.1 markus 973: f = p->function_list;
1.28 djm 974:
975: rv = f->C_FindObjectsInit(session, key_attr, 1);
976: if (rv != CKR_OK) {
1.1 markus 977: error("C_FindObjectsInit failed: %lu", rv);
1.28 djm 978: goto fail;
1.1 markus 979: }
1.28 djm 980:
1.1 markus 981: while (1) {
1.28 djm 982: CK_CERTIFICATE_TYPE ck_cert_type;
983:
984: rv = f->C_FindObjects(session, &obj, 1, &n);
985: if (rv != CKR_OK) {
986: error("C_FindObjects failed: %lu", rv);
987: goto fail;
1.1 markus 988: }
1.28 djm 989: if (n == 0)
1.1 markus 990: break;
1.28 djm 991:
992: memset(&ck_cert_type, 0, sizeof(ck_cert_type));
993: memset(&key_attr, 0, sizeof(key_attr));
994: key_attr[0].type = CKA_CERTIFICATE_TYPE;
995: key_attr[0].pValue = &ck_cert_type;
996: key_attr[0].ulValueLen = sizeof(ck_cert_type);
997:
998: rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
999: if (rv != CKR_OK) {
1.1 markus 1000: error("C_GetAttributeValue failed: %lu", rv);
1.28 djm 1001: goto fail;
1002: }
1003:
1004: switch (ck_cert_type) {
1005: case CKC_X_509:
1006: key = pkcs11_fetch_x509_pubkey(p, slotidx, &obj);
1007: break;
1008: default:
1009: /* XXX print key type? */
1010: error("skipping unsupported certificate type");
1.1 markus 1011: }
1.28 djm 1012:
1013: if (key == NULL) {
1014: error("failed to fetch key");
1.6 markus 1015: continue;
1016: }
1.28 djm 1017:
1018: if (pkcs11_key_included(keysp, nkeys, key)) {
1019: sshkey_free(key);
1020: } else {
1021: /* expand key array and add key */
1022: *keysp = xrecallocarray(*keysp, *nkeys,
1023: *nkeys + 1, sizeof(struct sshkey *));
1024: (*keysp)[*nkeys] = key;
1025: *nkeys = *nkeys + 1;
1026: debug("have %d keys", *nkeys);
1.21 djm 1027: }
1.28 djm 1028: }
1029:
1030: ret = 0;
1031: fail:
1032: rv = f->C_FindObjectsFinal(session);
1033: if (rv != CKR_OK) {
1034: error("C_FindObjectsFinal failed: %lu", rv);
1035: ret = -1;
1036: }
1037:
1038: return (ret);
1039: }
1.21 djm 1040:
1.28 djm 1041: /*
1042: * lookup public keys for token in slot identified by slotidx,
1043: * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1044: * keysp points to an (possibly empty) array with *nkeys keys.
1045: */
1046: static int
1047: pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
1048: struct sshkey ***keysp, int *nkeys)
1049: {
1050: struct sshkey *key = NULL;
1051: CK_OBJECT_CLASS key_class;
1052: CK_ATTRIBUTE key_attr[1];
1053: CK_SESSION_HANDLE session;
1054: CK_FUNCTION_LIST *f = NULL;
1055: CK_RV rv;
1056: CK_OBJECT_HANDLE obj;
1057: CK_ULONG n = 0;
1058: int ret = -1;
1059:
1060: memset(&key_attr, 0, sizeof(key_attr));
1061: memset(&obj, 0, sizeof(obj));
1062:
1063: key_class = CKO_PUBLIC_KEY;
1064: key_attr[0].type = CKA_CLASS;
1065: key_attr[0].pValue = &key_class;
1066: key_attr[0].ulValueLen = sizeof(key_class);
1067:
1068: session = p->slotinfo[slotidx].session;
1069: f = p->function_list;
1070:
1071: rv = f->C_FindObjectsInit(session, key_attr, 1);
1072: if (rv != CKR_OK) {
1073: error("C_FindObjectsInit failed: %lu", rv);
1074: goto fail;
1075: }
1076:
1077: while (1) {
1078: CK_KEY_TYPE ck_key_type;
1079:
1080: rv = f->C_FindObjects(session, &obj, 1, &n);
1081: if (rv != CKR_OK) {
1082: error("C_FindObjects failed: %lu", rv);
1083: goto fail;
1084: }
1085: if (n == 0)
1086: break;
1087:
1088: memset(&ck_key_type, 0, sizeof(ck_key_type));
1089: memset(&key_attr, 0, sizeof(key_attr));
1090: key_attr[0].type = CKA_KEY_TYPE;
1091: key_attr[0].pValue = &ck_key_type;
1092: key_attr[0].ulValueLen = sizeof(ck_key_type);
1093:
1094: rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
1095: if (rv != CKR_OK) {
1.1 markus 1096: error("C_GetAttributeValue failed: %lu", rv);
1.28 djm 1097: goto fail;
1098: }
1099:
1100: switch (ck_key_type) {
1101: case CKK_RSA:
1102: key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1103: break;
1104: case CKK_ECDSA:
1105: key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1106: break;
1107: default:
1108: /* XXX print key type? */
1109: error("skipping unsupported key type");
1110: }
1111:
1112: if (key == NULL) {
1113: error("failed to fetch key");
1114: continue;
1115: }
1116:
1117: if (pkcs11_key_included(keysp, nkeys, key)) {
1118: sshkey_free(key);
1.1 markus 1119: } else {
1.28 djm 1120: /* expand key array and add key */
1121: *keysp = xrecallocarray(*keysp, *nkeys,
1122: *nkeys + 1, sizeof(struct sshkey *));
1123: (*keysp)[*nkeys] = key;
1124: *nkeys = *nkeys + 1;
1125: debug("have %d keys", *nkeys);
1.1 markus 1126: }
1127: }
1.28 djm 1128:
1129: ret = 0;
1130: fail:
1131: rv = f->C_FindObjectsFinal(session);
1132: if (rv != CKR_OK) {
1.1 markus 1133: error("C_FindObjectsFinal failed: %lu", rv);
1.28 djm 1134: ret = -1;
1135: }
1136:
1137: return (ret);
1138: }
1139:
1140: #ifdef WITH_PKCS11_KEYGEN
1141: #define FILL_ATTR(attr, idx, typ, val, len) \
1142: { (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; }
1143:
1144: static struct sshkey *
1145: pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1146: char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1147: {
1148: struct pkcs11_slotinfo *si;
1149: char *plabel = label ? label : "";
1150: int npub = 0, npriv = 0;
1151: CK_RV rv;
1152: CK_FUNCTION_LIST *f;
1153: CK_SESSION_HANDLE session;
1154: CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1155: CK_OBJECT_HANDLE pubKey, privKey;
1156: CK_ATTRIBUTE tpub[16], tpriv[16];
1157: CK_MECHANISM mech = {
1158: CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
1159: };
1160: CK_BYTE pubExponent[] = {
1161: 0x01, 0x00, 0x01 /* RSA_F4 in bytes */
1162: };
1163:
1164: *err = 0;
1165:
1166: FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1167: FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1168: FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1169: FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1170: FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1171: sizeof(false_val));
1172: FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1173: FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1174: FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits));
1175: FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent,
1176: sizeof(pubExponent));
1177: FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1178:
1179: FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1180: FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1181: FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1182: FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1183: FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1184: FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1185: FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1186: sizeof(false_val));
1187: FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1188: FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1189: FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1190:
1191: f = p->function_list;
1192: si = &p->slotinfo[slotidx];
1193: session = si->session;
1194:
1195: if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1196: &pubKey, &privKey)) != CKR_OK) {
1197: error("%s: key generation failed: error 0x%lx", __func__, rv);
1198: *err = rv;
1199: return NULL;
1200: }
1201:
1202: return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey);
1203: }
1204:
1205: static int
1206: pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen)
1207: {
1208: size_t i, len;
1209: char ptr[3];
1210:
1211: if (dest)
1212: *dest = NULL;
1213: if (rlen)
1214: *rlen = 0;
1215:
1216: if ((len = strlen(hex)) % 2)
1217: return -1;
1218: len /= 2;
1219:
1220: *dest = xmalloc(len);
1221:
1222: ptr[2] = '\0';
1223: for (i = 0; i < len; i++) {
1224: ptr[0] = hex[2 * i];
1225: ptr[1] = hex[(2 * i) + 1];
1226: if (!isxdigit(ptr[0]) || !isxdigit(ptr[1]))
1227: return -1;
1228: (*dest)[i] = (unsigned char)strtoul(ptr, NULL, 16);
1229: }
1230:
1231: if (rlen)
1232: *rlen = len;
1233:
1234: return 0;
1235: }
1236:
1237: static struct ec_curve_info {
1238: const char *name;
1239: const char *oid;
1240: const char *oid_encoded;
1241: size_t size;
1242: } ec_curve_infos[] = {
1243: {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
1244: {"secp384r1", "1.3.132.0.34", "06052B81040022", 384},
1245: {"secp521r1", "1.3.132.0.35", "06052B81040023", 521},
1246: {NULL, NULL, NULL, 0},
1247: };
1248:
1249: static struct sshkey *
1250: pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1251: char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1252: {
1253: struct pkcs11_slotinfo *si;
1254: char *plabel = label ? label : "";
1255: int i;
1256: size_t ecparams_size;
1257: unsigned char *ecparams = NULL;
1258: int npub = 0, npriv = 0;
1259: CK_RV rv;
1260: CK_FUNCTION_LIST *f;
1261: CK_SESSION_HANDLE session;
1262: CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1263: CK_OBJECT_HANDLE pubKey, privKey;
1264: CK_MECHANISM mech = {
1265: CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
1266: };
1267: CK_ATTRIBUTE tpub[16], tpriv[16];
1268:
1269: *err = 0;
1270:
1271: for (i = 0; ec_curve_infos[i].name; i++) {
1272: if (ec_curve_infos[i].size == bits)
1273: break;
1274: }
1275: if (!ec_curve_infos[i].name) {
1276: error("%s: invalid key size %lu", __func__, bits);
1277: return NULL;
1278: }
1279: if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams,
1280: &ecparams_size) == -1) {
1281: error("%s: invalid oid", __func__);
1282: return NULL;
1283: }
1284:
1285: FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1286: FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1287: FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1288: FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1289: FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1290: sizeof(false_val));
1291: FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1292: FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1293: FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size);
1294: FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1295:
1296: FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1297: FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1298: FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1299: FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1300: FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1301: FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1302: FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1303: sizeof(false_val));
1304: FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1305: FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1306: FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1307:
1308: f = p->function_list;
1309: si = &p->slotinfo[slotidx];
1310: session = si->session;
1311:
1312: if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1313: &pubKey, &privKey)) != CKR_OK) {
1314: error("%s: key generation failed: error 0x%lx", __func__, rv);
1315: *err = rv;
1316: return NULL;
1317: }
1318:
1319: return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey);
1.1 markus 1320: }
1.28 djm 1321: #endif /* WITH_PKCS11_KEYGEN */
1.1 markus 1322:
1.28 djm 1323: /*
1324: * register a new provider, fails if provider already exists. if
1325: * keyp is provided, fetch keys.
1326: */
1327: static int
1328: pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1329: struct pkcs11_provider **providerp, CK_ULONG user)
1.1 markus 1330: {
1331: int nkeys, need_finalize = 0;
1.28 djm 1332: int ret = -1;
1.1 markus 1333: struct pkcs11_provider *p = NULL;
1334: void *handle = NULL;
1335: CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
1336: CK_RV rv;
1337: CK_FUNCTION_LIST *f = NULL;
1338: CK_TOKEN_INFO *token;
1339: CK_ULONG i;
1340:
1.28 djm 1341: if (providerp == NULL)
1342: goto fail;
1343: *providerp = NULL;
1344:
1345: if (keyp != NULL)
1346: *keyp = NULL;
1347:
1.1 markus 1348: if (pkcs11_provider_lookup(provider_id) != NULL) {
1.23 djm 1349: debug("%s: provider already registered: %s",
1350: __func__, provider_id);
1.1 markus 1351: goto fail;
1352: }
1.28 djm 1353: /* open shared pkcs11-library */
1.1 markus 1354: if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
1355: error("dlopen %s failed: %s", provider_id, dlerror());
1356: goto fail;
1357: }
1358: if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
1359: error("dlsym(C_GetFunctionList) failed: %s", dlerror());
1360: goto fail;
1361: }
1362: p = xcalloc(1, sizeof(*p));
1363: p->name = xstrdup(provider_id);
1364: p->handle = handle;
1365: /* setup the pkcs11 callbacks */
1366: if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
1.23 djm 1367: error("C_GetFunctionList for provider %s failed: %lu",
1368: provider_id, rv);
1.1 markus 1369: goto fail;
1370: }
1371: p->function_list = f;
1372: if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
1.23 djm 1373: error("C_Initialize for provider %s failed: %lu",
1374: provider_id, rv);
1.1 markus 1375: goto fail;
1376: }
1377: need_finalize = 1;
1378: if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
1.23 djm 1379: error("C_GetInfo for provider %s failed: %lu",
1380: provider_id, rv);
1.1 markus 1381: goto fail;
1382: }
1383: rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
1384: rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
1.23 djm 1385: debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d"
1.1 markus 1386: " libraryDescription <%s> libraryVersion %d.%d",
1.23 djm 1387: provider_id,
1.1 markus 1388: p->info.manufacturerID,
1389: p->info.cryptokiVersion.major,
1390: p->info.cryptokiVersion.minor,
1391: p->info.libraryDescription,
1392: p->info.libraryVersion.major,
1393: p->info.libraryVersion.minor);
1394: if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
1395: error("C_GetSlotList failed: %lu", rv);
1396: goto fail;
1397: }
1398: if (p->nslots == 0) {
1.28 djm 1399: error("%s: provider %s returned no slots", __func__,
1.23 djm 1400: provider_id);
1.28 djm 1401: ret = -SSH_PKCS11_ERR_NO_SLOTS;
1.1 markus 1402: goto fail;
1403: }
1404: p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
1405: if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
1406: != CKR_OK) {
1.23 djm 1407: error("C_GetSlotList for provider %s failed: %lu",
1408: provider_id, rv);
1.1 markus 1409: goto fail;
1410: }
1411: p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
1412: p->valid = 1;
1413: nkeys = 0;
1414: for (i = 0; i < p->nslots; i++) {
1415: token = &p->slotinfo[i].token;
1416: if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
1417: != CKR_OK) {
1.23 djm 1418: error("C_GetTokenInfo for provider %s slot %lu "
1419: "failed: %lu", provider_id, (unsigned long)i, rv);
1.20 djm 1420: continue;
1421: }
1422: if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
1.23 djm 1423: debug2("%s: ignoring uninitialised token in "
1424: "provider %s slot %lu", __func__,
1425: provider_id, (unsigned long)i);
1.1 markus 1426: continue;
1427: }
1428: rmspace(token->label, sizeof(token->label));
1429: rmspace(token->manufacturerID, sizeof(token->manufacturerID));
1430: rmspace(token->model, sizeof(token->model));
1431: rmspace(token->serialNumber, sizeof(token->serialNumber));
1.23 djm 1432: debug("provider %s slot %lu: label <%s> manufacturerID <%s> "
1433: "model <%s> serial <%s> flags 0x%lx",
1434: provider_id, (unsigned long)i,
1.1 markus 1435: token->label, token->manufacturerID, token->model,
1436: token->serialNumber, token->flags);
1.28 djm 1437: /*
1438: * open session, login with pin and retrieve public
1439: * keys (if keyp is provided)
1440: */
1441: if ((ret = pkcs11_open_session(p, i, pin, user)) == 0) {
1442: if (keyp == NULL)
1443: continue;
1.1 markus 1444: pkcs11_fetch_keys(p, i, keyp, &nkeys);
1.28 djm 1445: pkcs11_fetch_certs(p, i, keyp, &nkeys);
1446: }
1.1 markus 1447: }
1.28 djm 1448:
1449: /* now owned by caller */
1450: *providerp = p;
1451:
1452: TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
1453: p->refcount++; /* add to provider list */
1454:
1455: return (nkeys);
1.1 markus 1456: fail:
1457: if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
1.23 djm 1458: error("C_Finalize for provider %s failed: %lu",
1459: provider_id, rv);
1.1 markus 1460: if (p) {
1.28 djm 1461: free(p->name);
1.7 djm 1462: free(p->slotlist);
1463: free(p->slotinfo);
1464: free(p);
1.1 markus 1465: }
1466: if (handle)
1467: dlclose(handle);
1.28 djm 1468: return (ret);
1469: }
1470:
1471: /*
1472: * register a new provider and get number of keys hold by the token,
1473: * fails if provider already exists
1474: */
1475: int
1476: pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
1477: {
1478: struct pkcs11_provider *p = NULL;
1479: int nkeys;
1480:
1481: nkeys = pkcs11_register_provider(provider_id, pin, keyp, &p, CKU_USER);
1482:
1483: /* no keys found or some other error, de-register provider */
1484: if (nkeys <= 0 && p != NULL) {
1485: TAILQ_REMOVE(&pkcs11_providers, p, next);
1486: pkcs11_provider_finalize(p);
1487: pkcs11_provider_unref(p);
1488: }
1489: if (nkeys == 0)
1490: debug("%s: provider %s returned no keys", __func__,
1491: provider_id);
1492:
1493: return (nkeys);
1494: }
1495:
1496: #ifdef WITH_PKCS11_KEYGEN
1497: struct sshkey *
1498: pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
1499: unsigned int type, unsigned int bits, unsigned char keyid, u_int32_t *err)
1500: {
1501: struct pkcs11_provider *p = NULL;
1502: struct pkcs11_slotinfo *si;
1503: CK_FUNCTION_LIST *f;
1504: CK_SESSION_HANDLE session;
1505: struct sshkey *k = NULL;
1506: int ret = -1, reset_pin = 0, reset_provider = 0;
1507: CK_RV rv;
1508:
1509: *err = 0;
1510:
1511: if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
1512: debug("%s: provider \"%s\" available", __func__, provider_id);
1513: else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, &p,
1514: CKU_SO)) < 0) {
1515: debug("%s: could not register provider %s", __func__,
1516: provider_id);
1517: goto out;
1518: } else
1519: reset_provider = 1;
1520:
1521: f = p->function_list;
1522: si = &p->slotinfo[slotidx];
1523: session = si->session;
1524:
1525: if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1526: CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1527: debug("%s: could not supply SO pin: %lu", __func__, rv);
1528: reset_pin = 0;
1529: } else
1530: reset_pin = 1;
1531:
1532: switch (type) {
1533: case KEY_RSA:
1534: if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label,
1535: bits, keyid, err)) == NULL) {
1536: debug("%s: failed to generate RSA key", __func__);
1537: goto out;
1538: }
1539: break;
1540: case KEY_ECDSA:
1541: if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label,
1542: bits, keyid, err)) == NULL) {
1543: debug("%s: failed to generate ECDSA key", __func__);
1544: goto out;
1545: }
1546: break;
1547: default:
1548: *err = SSH_PKCS11_ERR_GENERIC;
1549: debug("%s: unknown type %d", __func__, type);
1550: goto out;
1551: }
1552:
1553: out:
1554: if (reset_pin)
1555: f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1556: CK_INVALID_HANDLE);
1557:
1558: if (reset_provider)
1559: pkcs11_del_provider(provider_id);
1560:
1561: return (k);
1562: }
1563:
1564: struct sshkey *
1565: pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
1566: unsigned char keyid, u_int32_t *err)
1567: {
1568: struct pkcs11_provider *p = NULL;
1569: struct pkcs11_slotinfo *si;
1570: struct sshkey *k = NULL;
1571: int reset_pin = 0, reset_provider = 0;
1572: CK_ULONG nattrs;
1573: CK_FUNCTION_LIST *f;
1574: CK_SESSION_HANDLE session;
1575: CK_ATTRIBUTE attrs[16];
1576: CK_OBJECT_CLASS key_class;
1577: CK_KEY_TYPE key_type;
1578: CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE;
1579: CK_RV rv;
1580:
1581: *err = 0;
1582:
1583: if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
1584: debug("%s: using provider \"%s\"", __func__, provider_id);
1585: } else if (pkcs11_register_provider(provider_id, pin, NULL, &p,
1586: CKU_SO) < 0) {
1587: debug("%s: could not register provider %s", __func__,
1588: provider_id);
1589: goto out;
1590: } else
1591: reset_provider = 1;
1592:
1593: f = p->function_list;
1594: si = &p->slotinfo[slotidx];
1595: session = si->session;
1596:
1597: if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1598: CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1599: debug("%s: could not supply SO pin: %lu", __func__, rv);
1600: reset_pin = 0;
1601: } else
1602: reset_pin = 1;
1603:
1604: /* private key */
1605: nattrs = 0;
1606: key_class = CKO_PRIVATE_KEY;
1607: FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1608: FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1609:
1610: if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1611: obj != CK_INVALID_HANDLE) {
1612: if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1613: debug("%s: could not destroy private key 0x%hhx",
1614: __func__, keyid);
1615: *err = rv;
1616: goto out;
1617: }
1618: }
1619:
1620: /* public key */
1621: nattrs = 0;
1622: key_class = CKO_PUBLIC_KEY;
1623: FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1624: FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1625:
1626: if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1627: obj != CK_INVALID_HANDLE) {
1628:
1629: /* get key type */
1630: nattrs = 0;
1631: FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type,
1632: sizeof(key_type));
1633: rv = f->C_GetAttributeValue(session, obj, attrs, nattrs);
1634: if (rv != CKR_OK) {
1635: debug("%s: could not get key type of public key 0x%hhx",
1636: __func__, keyid);
1637: *err = rv;
1638: key_type = -1;
1639: }
1640: if (key_type == CKK_RSA)
1641: k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1642: else if (key_type == CKK_ECDSA)
1643: k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1644:
1645: if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1646: debug("%s: could not destroy public key 0x%hhx",
1647: __func__, keyid);
1648: *err = rv;
1649: goto out;
1650: }
1651: }
1652:
1653: out:
1654: if (reset_pin)
1655: f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1656: CK_INVALID_HANDLE);
1657:
1658: if (reset_provider)
1659: pkcs11_del_provider(provider_id);
1660:
1661: return (k);
1.1 markus 1662: }
1.28 djm 1663: #endif /* WITH_PKCS11_KEYGEN */
1.2 markus 1664: #else
1665: int
1.15 djm 1666: pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
1.2 markus 1667: {
1668: error("dlopen() not supported");
1669: return (-1);
1670: }
1.28 djm 1671: #endif /* HAVE_DLOPEN */