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