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