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