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