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