Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Copyright (C) 2011-2016 Tobias Brunner
3: * HSR Hochschule fuer Technik Rapperswil
4: *
5: * Copyright (C) 2010 Martin Willi
6: * Copyright (C) 2010 revosec AG
7: *
8: * This program is free software; you can redistribute it and/or modify it
9: * under the terms of the GNU General Public License as published by the
10: * Free Software Foundation; either version 2 of the License, or (at your
11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12: *
13: * This program is distributed in the hope that it will be useful, but
14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16: * for more details.
17: */
18: /*
19: * Copyright (C) 2016 EDF S.A.
20: *
21: * Permission is hereby granted, free of charge, to any person obtaining a copy
22: * of this software and associated documentation files (the "Software"), to deal
23: * in the Software without restriction, including without limitation the rights
24: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25: * copies of the Software, and to permit persons to whom the Software is
26: * furnished to do so, subject to the following conditions:
27: *
28: * The above copyright notice and this permission notice shall be included in
29: * all copies or substantial portions of the Software.
30: *
31: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37: * THE SOFTWARE.
38: */
39:
40: #include "pkcs11_private_key.h"
41:
42: #include "pkcs11_library.h"
43: #include "pkcs11_manager.h"
44: #include "pkcs11_public_key.h"
45:
46: #include <utils/debug.h>
47: #include <asn1/asn1.h>
48:
49: typedef struct private_pkcs11_private_key_t private_pkcs11_private_key_t;
50:
51: /**
52: * Private data of an pkcs11_private_key_t object.
53: */
54: struct private_pkcs11_private_key_t {
55:
56: /**
57: * Public pkcs11_private_key_t interface.
58: */
59: pkcs11_private_key_t public;
60:
61: /**
62: * PKCS#11 module
63: */
64: pkcs11_library_t *lib;
65:
66: /**
67: * Slot the token is in
68: */
69: CK_SLOT_ID slot;
70:
71: /**
72: * Token session
73: */
74: CK_SESSION_HANDLE session;
75:
76: /**
77: * Key object on the token
78: */
79: CK_OBJECT_HANDLE object;
80:
81: /**
82: * Key requires reauthentication for each signature/decryption
83: */
84: CK_BBOOL reauth;
85:
86: /**
87: * Keyid of the key we use
88: */
89: identification_t *keyid;
90:
91: /**
92: * Associated public key
93: */
94: public_key_t *pubkey;
95:
96: /**
97: * References to this key
98: */
99: refcount_t ref;
100:
101: /**
102: * Type of this private key
103: */
104: key_type_t type;
105: };
106:
107:
108: METHOD(private_key_t, get_type, key_type_t,
109: private_pkcs11_private_key_t *this)
110: {
111: return this->type;
112: }
113:
114: METHOD(private_key_t, get_keysize, int,
115: private_pkcs11_private_key_t *this)
116: {
117: return this->pubkey->get_keysize(this->pubkey);
118: }
119:
120: /**
1.1.1.2 ! misho 121: * Check if a token supports the given mechanism.
1.1 misho 122: */
1.1.1.2 ! misho 123: static bool is_mechanism_supported(pkcs11_library_t *p11, CK_SLOT_ID slot,
! 124: const CK_MECHANISM_PTR mech)
! 125: {
! 126: enumerator_t *mechs;
! 127: CK_MECHANISM_TYPE type;
! 128:
! 129: mechs = p11->create_mechanism_enumerator(p11, slot);
! 130: while (mechs->enumerate(mechs, &type, NULL))
! 131: {
! 132: if (type == mech->mechanism)
! 133: {
! 134: mechs->destroy(mechs);
! 135: return TRUE;
! 136: }
! 137: }
! 138: mechs->destroy(mechs);
! 139: return FALSE;
! 140: }
! 141:
! 142: /*
! 143: * Described in header
! 144: */
! 145: CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(pkcs11_library_t *p11,
! 146: CK_SLOT_ID slot,
! 147: signature_scheme_t scheme,
1.1 misho 148: key_type_t type, size_t keylen,
149: hash_algorithm_t *hash)
150: {
151: static struct {
152: signature_scheme_t scheme;
153: CK_MECHANISM mechanism;
154: key_type_t type;
155: size_t keylen;
156: hash_algorithm_t hash;
157: } mappings[] = {
158: {SIGN_RSA_EMSA_PKCS1_NULL, {CKM_RSA_PKCS, NULL, 0},
159: KEY_RSA, 0, HASH_UNKNOWN},
160: {SIGN_RSA_EMSA_PKCS1_SHA2_256, {CKM_SHA256_RSA_PKCS, NULL, 0},
161: KEY_RSA, 0, HASH_UNKNOWN},
1.1.1.2 ! misho 162: {SIGN_RSA_EMSA_PKCS1_SHA2_256, {CKM_RSA_PKCS, NULL, 0},
! 163: KEY_RSA, 0, HASH_SHA256},
1.1 misho 164: {SIGN_RSA_EMSA_PKCS1_SHA2_384, {CKM_SHA384_RSA_PKCS, NULL, 0},
165: KEY_RSA, 0, HASH_UNKNOWN},
1.1.1.2 ! misho 166: {SIGN_RSA_EMSA_PKCS1_SHA2_384, {CKM_RSA_PKCS, NULL, 0},
! 167: KEY_RSA, 0, HASH_SHA384},
1.1 misho 168: {SIGN_RSA_EMSA_PKCS1_SHA2_512, {CKM_SHA512_RSA_PKCS, NULL, 0},
169: KEY_RSA, 0, HASH_UNKNOWN},
1.1.1.2 ! misho 170: {SIGN_RSA_EMSA_PKCS1_SHA2_512, {CKM_RSA_PKCS, NULL, 0},
! 171: KEY_RSA, 0, HASH_SHA512},
1.1 misho 172: {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_SHA1_RSA_PKCS, NULL, 0},
173: KEY_RSA, 0, HASH_UNKNOWN},
1.1.1.2 ! misho 174: {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_RSA_PKCS, NULL, 0},
! 175: KEY_RSA, 0, HASH_SHA1},
1.1 misho 176: {SIGN_RSA_EMSA_PKCS1_MD5, {CKM_MD5_RSA_PKCS, NULL, 0},
177: KEY_RSA, 0, HASH_UNKNOWN},
178: {SIGN_ECDSA_WITH_NULL, {CKM_ECDSA, NULL, 0},
179: KEY_ECDSA, 0, HASH_UNKNOWN},
180: {SIGN_ECDSA_WITH_SHA1_DER, {CKM_ECDSA_SHA1, NULL, 0},
181: KEY_ECDSA, 0, HASH_UNKNOWN},
182: {SIGN_ECDSA_WITH_SHA256_DER, {CKM_ECDSA, NULL, 0},
183: KEY_ECDSA, 0, HASH_SHA256},
184: {SIGN_ECDSA_WITH_SHA384_DER, {CKM_ECDSA, NULL, 0},
185: KEY_ECDSA, 0, HASH_SHA384},
186: {SIGN_ECDSA_WITH_SHA512_DER, {CKM_ECDSA, NULL, 0},
187: KEY_ECDSA, 0, HASH_SHA512},
188: {SIGN_ECDSA_256, {CKM_ECDSA, NULL, 0},
189: KEY_ECDSA, 256, HASH_SHA256},
190: {SIGN_ECDSA_384, {CKM_ECDSA, NULL, 0},
191: KEY_ECDSA, 384, HASH_SHA384},
192: {SIGN_ECDSA_521, {CKM_ECDSA, NULL, 0},
193: KEY_ECDSA, 521, HASH_SHA512},
194: };
195: int i;
196:
197: for (i = 0; i < countof(mappings); i++)
198: {
199: if (mappings[i].scheme == scheme)
200: {
201: size_t len = mappings[i].keylen;
1.1.1.2 ! misho 202:
! 203: if (mappings[i].type != type || (len && keylen != len) ||
! 204: !is_mechanism_supported(p11, slot, &mappings[i].mechanism))
1.1 misho 205: {
1.1.1.2 ! misho 206: continue;
1.1 misho 207: }
208: if (hash)
209: {
210: *hash = mappings[i].hash;
211: }
212: return &mappings[i].mechanism;
213: }
214: }
215: return NULL;
216: }
217:
218: /**
219: * See header.
220: */
221: CK_MECHANISM_PTR pkcs11_encryption_scheme_to_mech(encryption_scheme_t scheme)
222: {
223: static struct {
224: encryption_scheme_t scheme;
225: CK_MECHANISM mechanism;
226: } mappings[] = {
227: {ENCRYPT_RSA_PKCS1, {CKM_RSA_PKCS, NULL, 0}},
228: {ENCRYPT_RSA_OAEP_SHA1, {CKM_RSA_PKCS_OAEP, NULL, 0}},
229: };
230: int i;
231:
232: for (i = 0; i < countof(mappings); i++)
233: {
234: if (mappings[i].scheme == scheme)
235: {
236: return &mappings[i].mechanism;
237: }
238: }
239: return NULL;
240: }
241:
242: /**
243: * Reauthenticate to do a signature
244: */
245: static bool reauth(private_pkcs11_private_key_t *this,
246: CK_SESSION_HANDLE session)
247: {
248: enumerator_t *enumerator;
249: shared_key_t *shared;
250: chunk_t pin;
251: CK_RV rv;
252: bool found = FALSE, success = FALSE;
253:
254: enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
255: SHARED_PIN, this->keyid, NULL);
256: while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
257: {
258: found = TRUE;
259: pin = shared->get_key(shared);
260: rv = this->lib->f->C_Login(session, CKU_CONTEXT_SPECIFIC,
261: pin.ptr, pin.len);
262: if (rv == CKR_OK)
263: {
264: success = TRUE;
265: break;
266: }
267: DBG1(DBG_CFG, "reauthentication login failed: %N", ck_rv_names, rv);
268: }
269: enumerator->destroy(enumerator);
270:
271: if (!found)
272: {
273: DBG1(DBG_CFG, "private key requires reauthentication, but no PIN found");
274: return FALSE;
275: }
276: return success;
277: }
278:
279: METHOD(private_key_t, sign, bool,
280: private_pkcs11_private_key_t *this, signature_scheme_t scheme, void *params,
281: chunk_t data, chunk_t *signature)
282: {
283: CK_MECHANISM_PTR mechanism;
284: CK_SESSION_HANDLE session;
285: CK_BYTE_PTR buf;
286: CK_ULONG len;
287: CK_RV rv;
288: hash_algorithm_t hash_alg;
289: chunk_t hash = chunk_empty;
290:
1.1.1.2 ! misho 291: mechanism = pkcs11_signature_scheme_to_mech(this->lib, this->slot, scheme,
! 292: this->type, get_keysize(this),
! 293: &hash_alg);
1.1 misho 294: if (!mechanism)
295: {
296: DBG1(DBG_LIB, "signature scheme %N not supported",
297: signature_scheme_names, scheme);
298: return FALSE;
299: }
300: rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
301: &session);
302: if (rv != CKR_OK)
303: {
304: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
305: return FALSE;
306: }
307: rv = this->lib->f->C_SignInit(session, mechanism, this->object);
308: if (this->reauth && !reauth(this, session))
309: {
310: this->lib->f->C_CloseSession(session);
311: return FALSE;
312: }
313: if (rv != CKR_OK)
314: {
315: this->lib->f->C_CloseSession(session);
316: DBG1(DBG_LIB, "C_SignInit() failed: %N", ck_rv_names, rv);
317: return FALSE;
318: }
319: if (hash_alg != HASH_UNKNOWN)
320: {
321: hasher_t *hasher;
322:
323: hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
324: if (!hasher || !hasher->allocate_hash(hasher, data, &hash))
325: {
326: DESTROY_IF(hasher);
327: this->lib->f->C_CloseSession(session);
328: return FALSE;
329: }
330: hasher->destroy(hasher);
1.1.1.2 ! misho 331: switch (scheme)
! 332: {
! 333: case SIGN_RSA_EMSA_PKCS1_SHA1:
! 334: case SIGN_RSA_EMSA_PKCS1_SHA2_256:
! 335: case SIGN_RSA_EMSA_PKCS1_SHA2_384:
! 336: case SIGN_RSA_EMSA_PKCS1_SHA2_512:
! 337: /* encode PKCS#1 digestInfo if the token does not support it */
! 338: hash = asn1_wrap(ASN1_SEQUENCE, "mm",
! 339: asn1_algorithmIdentifier(
! 340: hasher_algorithm_to_oid(hash_alg)),
! 341: asn1_wrap(ASN1_OCTET_STRING, "m", hash));
! 342: break;
! 343: default:
! 344: break;
! 345: }
1.1 misho 346: data = hash;
347: }
348: len = (get_keysize(this) + 7) / 8;
349: if (this->type == KEY_ECDSA)
350: { /* signature is twice the length of the base point order */
351: len *= 2;
352: }
353: buf = malloc(len);
354: rv = this->lib->f->C_Sign(session, data.ptr, data.len, buf, &len);
355: this->lib->f->C_CloseSession(session);
356: chunk_free(&hash);
357: if (rv != CKR_OK)
358: {
359: DBG1(DBG_LIB, "C_Sign() failed: %N", ck_rv_names, rv);
360: free(buf);
361: return FALSE;
362: }
363: switch (scheme)
364: {
365: case SIGN_ECDSA_WITH_SHA1_DER:
366: case SIGN_ECDSA_WITH_SHA256_DER:
367: case SIGN_ECDSA_WITH_SHA384_DER:
368: case SIGN_ECDSA_WITH_SHA512_DER:
369: {
370: chunk_t r, s;
371:
372: /* return an ASN.1 encoded sequence of integers r and s, removing
373: * any zero-padding */
374: len /= 2;
375: r = chunk_skip_zero(chunk_create(buf, len));
376: s = chunk_skip_zero(chunk_create(buf+len, len));
377: *signature = asn1_wrap(ASN1_SEQUENCE, "mm",
378: asn1_integer("c", r), asn1_integer("c", s));
379: free(buf);
380: break;
381: }
382: default:
383: *signature = chunk_create(buf, len);
384: break;
385: }
386: return TRUE;
387: }
388:
389: METHOD(private_key_t, decrypt, bool,
390: private_pkcs11_private_key_t *this, encryption_scheme_t scheme,
391: chunk_t crypt, chunk_t *plain)
392: {
393: CK_MECHANISM_PTR mechanism;
394: CK_SESSION_HANDLE session;
395: CK_BYTE_PTR buf;
396: CK_ULONG len;
397: CK_RV rv;
398:
399: mechanism = pkcs11_encryption_scheme_to_mech(scheme);
400: if (!mechanism)
401: {
402: DBG1(DBG_LIB, "encryption scheme %N not supported",
403: encryption_scheme_names, scheme);
404: return FALSE;
405: }
406: rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
407: &session);
408: if (rv != CKR_OK)
409: {
410: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
411: return FALSE;
412: }
413: rv = this->lib->f->C_DecryptInit(session, mechanism, this->object);
414: if (this->reauth && !reauth(this, session))
415: {
416: this->lib->f->C_CloseSession(session);
417: return FALSE;
418: }
419: if (rv != CKR_OK)
420: {
421: this->lib->f->C_CloseSession(session);
422: DBG1(DBG_LIB, "C_DecryptInit() failed: %N", ck_rv_names, rv);
423: return FALSE;
424: }
425: len = (get_keysize(this) + 7) / 8;
426: buf = malloc(len);
427: rv = this->lib->f->C_Decrypt(session, crypt.ptr, crypt.len, buf, &len);
428: this->lib->f->C_CloseSession(session);
429: if (rv != CKR_OK)
430: {
431: DBG1(DBG_LIB, "C_Decrypt() failed: %N", ck_rv_names, rv);
432: free(buf);
433: return FALSE;
434: }
435: *plain = chunk_create(buf, len);
436: return TRUE;
437: }
438:
439: METHOD(private_key_t, get_public_key, public_key_t*,
440: private_pkcs11_private_key_t *this)
441: {
442: return this->pubkey->get_ref(this->pubkey);
443: }
444:
445: METHOD(private_key_t, get_fingerprint, bool,
446: private_pkcs11_private_key_t *this, cred_encoding_type_t type,
447: chunk_t *fingerprint)
448: {
449: return this->pubkey->get_fingerprint(this->pubkey, type, fingerprint);
450: }
451:
452: METHOD(private_key_t, get_encoding, bool,
453: private_pkcs11_private_key_t *this, cred_encoding_type_t type,
454: chunk_t *encoding)
455: {
456: return FALSE;
457: }
458:
459: METHOD(private_key_t, get_ref, private_key_t*,
460: private_pkcs11_private_key_t *this)
461: {
462: ref_get(&this->ref);
463: return &this->public.key;
464: }
465:
466: METHOD(private_key_t, destroy, void,
467: private_pkcs11_private_key_t *this)
468: {
469: if (ref_put(&this->ref))
470: {
471: if (this->pubkey)
472: {
473: this->pubkey->destroy(this->pubkey);
474: }
475: this->keyid->destroy(this->keyid);
476: this->lib->f->C_CloseSession(this->session);
477: free(this);
478: }
479: }
480:
481: /**
482: * Find the PKCS#11 library by its friendly name
483: */
484: static pkcs11_library_t* find_lib(char *module)
485: {
486: pkcs11_manager_t *manager;
487: enumerator_t *enumerator;
488: pkcs11_library_t *p11, *found = NULL;
489: CK_SLOT_ID slot;
490:
491: manager = lib->get(lib, "pkcs11-manager");
492: if (!manager)
493: {
494: return NULL;
495: }
496: enumerator = manager->create_token_enumerator(manager);
497: while (enumerator->enumerate(enumerator, &p11, &slot))
498: {
499: if (streq(module, p11->get_name(p11)))
500: {
501: found = p11;
502: break;
503: }
504: }
505: enumerator->destroy(enumerator);
506: return found;
507: }
508:
509: /**
510: * Find the PKCS#11 lib having a keyid, and optionally a slot
511: */
512: static pkcs11_library_t* find_lib_by_keyid(chunk_t keyid, int *slot,
513: CK_OBJECT_CLASS class)
514: {
515: pkcs11_manager_t *manager;
516: enumerator_t *enumerator;
517: pkcs11_library_t *p11, *found = NULL;
518: CK_SLOT_ID current;
519:
520: manager = lib->get(lib, "pkcs11-manager");
521: if (!manager)
522: {
523: return NULL;
524: }
525: enumerator = manager->create_token_enumerator(manager);
526: while (enumerator->enumerate(enumerator, &p11, ¤t))
527: {
528: if (*slot == -1 || *slot == current)
529: {
530: /* look for a pubkey/cert, it is usually readable without login */
531: CK_ATTRIBUTE tmpl[] = {
532: {CKA_CLASS, &class, sizeof(class)},
533: {CKA_ID, keyid.ptr, keyid.len},
534: };
535: CK_OBJECT_HANDLE object;
536: CK_SESSION_HANDLE session;
537: CK_RV rv;
538: enumerator_t *keys;
539:
540: rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
541: &session);
542: if (rv != CKR_OK)
543: {
544: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
545: ck_rv_names, rv);
546: continue;
547: }
548: keys = p11->create_object_enumerator(p11, session,
549: tmpl, countof(tmpl), NULL, 0);
550: if (keys->enumerate(keys, &object))
551: {
552: DBG1(DBG_CFG, "found key on PKCS#11 token '%s':%d",
553: p11->get_name(p11), current);
554: found = p11;
555: *slot = current;
556: }
557: keys->destroy(keys);
558: p11->f->C_CloseSession(session);
559: if (found)
560: {
561: break;
562: }
563: }
564: }
565: enumerator->destroy(enumerator);
566: return found;
567: }
568:
569: /**
570: * Find the PKCS#11 lib and CKA_ID of the certificate object of a given
571: * subjectKeyIdentifier and optional slot
572: */
573: static pkcs11_library_t* find_lib_and_keyid_by_skid(chunk_t keyid_chunk,
574: chunk_t *ckaid, int *slot)
575: {
576: CK_OBJECT_CLASS class = CKO_CERTIFICATE;
577: CK_CERTIFICATE_TYPE type = CKC_X_509;
578: CK_ATTRIBUTE tmpl[] = {
579: {CKA_CLASS, &class, sizeof(class)},
580: {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
581: };
582: CK_ATTRIBUTE attr[] = {
583: {CKA_VALUE, NULL, 0},
584: {CKA_ID, NULL, 0},
585: };
586: CK_OBJECT_HANDLE object;
587: CK_SESSION_HANDLE session;
588: CK_RV rv;
589: pkcs11_manager_t *manager;
590: enumerator_t *enumerator, *certs;
591: identification_t *keyid;
592: pkcs11_library_t *p11, *found = NULL;
593: CK_SLOT_ID current;
594: linked_list_t *raw;
595: certificate_t *cert;
596: struct {
597: chunk_t value;
598: chunk_t ckaid;
599: } *entry;
600:
601: manager = lib->get(lib, "pkcs11-manager");
602: if (!manager)
603: {
604: return NULL;
605: }
606:
607: keyid = identification_create_from_encoding(ID_KEY_ID, keyid_chunk);
608: /* store result in a temporary list, avoid recursive operation */
609: raw = linked_list_create();
610:
611: enumerator = manager->create_token_enumerator(manager);
612: while (enumerator->enumerate(enumerator, &p11, ¤t))
613: {
614: if (*slot != -1 && *slot != current)
615: {
616: continue;
617: }
618: rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
619: &session);
620: if (rv != CKR_OK)
621: {
622: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
623: ck_rv_names, rv);
624: continue;
625: }
626: certs = p11->create_object_enumerator(p11, session, tmpl, countof(tmpl),
627: attr, countof(attr));
628: while (certs->enumerate(certs, &object))
629: {
630: INIT(entry,
631: .value = chunk_clone(
632: chunk_create(attr[0].pValue, attr[0].ulValueLen)),
633: .ckaid = chunk_clone(
634: chunk_create(attr[1].pValue, attr[1].ulValueLen)),
635: );
636: raw->insert_last(raw, entry);
637: }
638: certs->destroy(certs);
639:
640: while (raw->remove_first(raw, (void**)&entry) == SUCCESS)
641: {
642: if (!found)
643: {
644: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
645: CERT_X509, BUILD_BLOB_ASN1_DER,
646: entry->value, BUILD_END);
647: if (cert)
648: {
649: if (cert->has_subject(cert, keyid))
650: {
651: DBG1(DBG_CFG, "found cert with keyid '%#B' on PKCS#11 "
652: "token '%s':%d", &keyid_chunk, p11->get_name(p11),
653: current);
654: found = p11;
655: *ckaid = chunk_clone(entry->ckaid);
656: *slot = current;
657: }
658: cert->destroy(cert);
659: }
660: else
661: {
662: DBG1(DBG_CFG, "parsing cert with CKA_ID '%#B' on PKCS#11 "
663: "token '%s':%d failed", &entry->ckaid,
664: p11->get_name(p11), current);
665: }
666: }
667: chunk_free(&entry->value);
668: chunk_free(&entry->ckaid);
669: free(entry);
670: }
671: p11->f->C_CloseSession(session);
672: if (found)
673: {
674: break;
675: }
676: }
677: enumerator->destroy(enumerator);
678: keyid->destroy(keyid);
679: raw->destroy(raw);
680: return found;
681: }
682:
683: /**
684: * Find the key on the token
685: */
686: static bool find_key(private_pkcs11_private_key_t *this, chunk_t keyid)
687: {
688: CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
689: CK_ATTRIBUTE tmpl[] = {
690: {CKA_CLASS, &class, sizeof(class)},
691: {CKA_ID, keyid.ptr, keyid.len},
692: };
693: CK_OBJECT_HANDLE object;
694: CK_KEY_TYPE type;
695: CK_BBOOL reauth = FALSE;
696: CK_ATTRIBUTE attr[] = {
697: {CKA_KEY_TYPE, &type, sizeof(type)},
698: {CKA_ALWAYS_AUTHENTICATE, &reauth, sizeof(reauth)},
699: };
700: enumerator_t *enumerator;
701: int count = countof(attr);
702: bool found = FALSE;
703:
704: /* do not use CKA_ALWAYS_AUTHENTICATE if not supported */
705: if (!(this->lib->get_features(this->lib) & PKCS11_ALWAYS_AUTH_KEYS))
706: {
707: count--;
708: }
709: enumerator = this->lib->create_object_enumerator(this->lib,
710: this->session, tmpl, countof(tmpl), attr, count);
711: if (enumerator->enumerate(enumerator, &object))
712: {
713: this->type = KEY_RSA;
714: switch (type)
715: {
716: case CKK_ECDSA:
717: this->type = KEY_ECDSA;
718: /* fall-through */
719: case CKK_RSA:
720: this->reauth = reauth;
721: this->object = object;
722: found = TRUE;
723: break;
724: default:
725: DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
726: break;
727: }
728: }
729: enumerator->destroy(enumerator);
730: return found;
731: }
732:
733: /**
734: * Find a PIN and try to log in
735: */
736: static bool login(private_pkcs11_private_key_t *this, int slot)
737: {
738: enumerator_t *enumerator;
739: shared_key_t *shared;
740: chunk_t pin;
741: CK_RV rv;
742: CK_SESSION_INFO info;
743: bool found = FALSE, success = FALSE;
744:
745: rv = this->lib->f->C_GetSessionInfo(this->session, &info);
746: if (rv != CKR_OK)
747: {
748: DBG1(DBG_CFG, "C_GetSessionInfo failed: %N", ck_rv_names, rv);
749: return FALSE;
750: }
751: if (info.state != CKS_RO_PUBLIC_SESSION &&
752: info.state != CKS_RW_PUBLIC_SESSION)
753: { /* already logged in with another session, skip */
754: return TRUE;
755: }
756:
757: enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
758: SHARED_PIN, this->keyid, NULL);
759: while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
760: {
761: found = TRUE;
762: pin = shared->get_key(shared);
763: rv = this->lib->f->C_Login(this->session, CKU_USER, pin.ptr, pin.len);
764: if (rv == CKR_OK)
765: {
766: success = TRUE;
767: break;
768: }
769: DBG1(DBG_CFG, "login to '%s':%d failed: %N",
770: this->lib->get_name(this->lib), slot, ck_rv_names, rv);
771: }
772: enumerator->destroy(enumerator);
773:
774: if (!found)
775: {
776: DBG1(DBG_CFG, "no PIN found for PKCS#11 key %Y", this->keyid);
777: return FALSE;
778: }
779: return success;
780: }
781:
782: /**
783: * Get a public key from a certificate with a given key ID.
784: */
785: static public_key_t* find_pubkey_in_certs(private_pkcs11_private_key_t *this,
786: chunk_t keyid)
787: {
788: CK_OBJECT_CLASS class = CKO_CERTIFICATE;
789: CK_CERTIFICATE_TYPE type = CKC_X_509;
790: CK_ATTRIBUTE tmpl[] = {
791: {CKA_CLASS, &class, sizeof(class)},
792: {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
793: {CKA_ID, keyid.ptr, keyid.len},
794: };
795: CK_OBJECT_HANDLE object;
796: CK_ATTRIBUTE attr[] = {
797: {CKA_VALUE, NULL, 0},
798: };
799: enumerator_t *enumerator;
800: chunk_t data = chunk_empty;
801: public_key_t *key = NULL;
802: certificate_t *cert;
803:
804: enumerator = this->lib->create_object_enumerator(this->lib, this->session,
805: tmpl, countof(tmpl), attr, countof(attr));
806: if (enumerator->enumerate(enumerator, &object))
807: {
808: data = chunk_clone(chunk_create(attr[0].pValue, attr[0].ulValueLen));
809: }
810: enumerator->destroy(enumerator);
811:
812: if (data.ptr)
813: {
814: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
815: BUILD_BLOB_ASN1_DER, data, BUILD_END);
816: free(data.ptr);
817: if (cert)
818: {
819: key = cert->get_public_key(cert);
820: cert->destroy(cert);
821: }
822: }
823: return key;
824: }
825:
826: /**
827: * See header.
828: */
829: pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args)
830: {
831: private_pkcs11_private_key_t *this;
832: char *module = NULL;
833: chunk_t keyid = chunk_empty, ckaid = chunk_empty;
834: int slot = -1;
835: CK_RV rv;
836:
837: while (TRUE)
838: {
839: switch (va_arg(args, builder_part_t))
840: {
841: case BUILD_PKCS11_KEYID:
842: keyid = va_arg(args, chunk_t);
843: continue;
844: case BUILD_PKCS11_SLOT:
845: slot = va_arg(args, int);
846: continue;
847: case BUILD_PKCS11_MODULE:
848: module = va_arg(args, char*);
849: continue;
850: case BUILD_END:
851: break;
852: default:
853: return NULL;
854: }
855: break;
856: }
857: if (!keyid.len)
858: {
859: return NULL;
860: }
861:
862: INIT(this,
863: .public = {
864: .key = {
865: .get_type = _get_type,
866: .sign = _sign,
867: .decrypt = _decrypt,
868: .get_keysize = _get_keysize,
869: .get_public_key = _get_public_key,
870: .equals = private_key_equals,
871: .belongs_to = private_key_belongs_to,
872: .get_fingerprint = _get_fingerprint,
873: .has_fingerprint = private_key_has_fingerprint,
874: .get_encoding = _get_encoding,
875: .get_ref = _get_ref,
876: .destroy = _destroy,
877: },
878: },
879: .ref = 1,
880: );
881:
882: if (module && slot != -1)
883: {
884: this->lib = find_lib(module);
885: if (!this->lib)
886: {
887: DBG1(DBG_CFG, "PKCS#11 module '%s' not found", module);
888: free(this);
889: return NULL;
890: }
891: }
892: else
893: {
894: this->lib = find_lib_by_keyid(keyid, &slot, CKO_PUBLIC_KEY);
895: if (!this->lib)
896: {
897: this->lib = find_lib_by_keyid(keyid, &slot, CKO_CERTIFICATE);
898: }
899: if (!this->lib)
900: {
901: this->lib = find_lib_and_keyid_by_skid(keyid, &ckaid, &slot);
902: }
903: if (!this->lib)
904: {
905: DBG1(DBG_CFG, "no PKCS#11 module found having a keyid %#B", &keyid);
906: free(this);
907: return NULL;
908: }
909: }
910:
911: rv = this->lib->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
912: NULL, NULL, &this->session);
913: if (rv != CKR_OK)
914: {
915: DBG1(DBG_CFG, "opening private key session on '%s':%d failed: %N",
916: module, slot, ck_rv_names, rv);
917: free(this);
918: return NULL;
919: }
920:
921: this->slot = slot;
922: this->keyid = identification_create_from_encoding(ID_KEY_ID, keyid);
923:
924: if (!login(this, slot))
925: {
926: destroy(this);
927: return NULL;
928: }
929:
930: if (ckaid.ptr)
931: {
932: DBG1(DBG_CFG, "using CKA_ID '%#B' for key with keyid '%#B'",
933: &ckaid, &keyid);
934: keyid = ckaid;
935: }
936:
937: if (!find_key(this, keyid))
938: {
939: DBG1(DBG_CFG, "did not find the key with %s '%#B'",
940: ckaid.ptr ? "CKA_ID" : "keyid", &keyid);
941: destroy(this);
942: return NULL;
943: }
944:
945: this->pubkey = pkcs11_public_key_connect(this->lib, slot, this->type, keyid);
946: if (!this->pubkey)
947: {
948: this->pubkey = find_pubkey_in_certs(this, keyid);
949: if (!this->pubkey)
950: {
951: DBG1(DBG_CFG, "no public key or certificate found for private key "
952: "(%s '%#B') on '%s':%d", ckaid.ptr ? "CKA_ID" : "keyid",
953: &keyid, module, slot);
954: destroy(this);
955: return NULL;
956: }
957: }
958: return &this->public;
959: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>