Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c, revision 1.1.1.1
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: /**
121: * See header.
122: */
123: CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme,
124: key_type_t type, size_t keylen,
125: hash_algorithm_t *hash)
126: {
127: static struct {
128: signature_scheme_t scheme;
129: CK_MECHANISM mechanism;
130: key_type_t type;
131: size_t keylen;
132: hash_algorithm_t hash;
133: } mappings[] = {
134: {SIGN_RSA_EMSA_PKCS1_NULL, {CKM_RSA_PKCS, NULL, 0},
135: KEY_RSA, 0, HASH_UNKNOWN},
136: {SIGN_RSA_EMSA_PKCS1_SHA2_256, {CKM_SHA256_RSA_PKCS, NULL, 0},
137: KEY_RSA, 0, HASH_UNKNOWN},
138: {SIGN_RSA_EMSA_PKCS1_SHA2_384, {CKM_SHA384_RSA_PKCS, NULL, 0},
139: KEY_RSA, 0, HASH_UNKNOWN},
140: {SIGN_RSA_EMSA_PKCS1_SHA2_512, {CKM_SHA512_RSA_PKCS, NULL, 0},
141: KEY_RSA, 0, HASH_UNKNOWN},
142: {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_SHA1_RSA_PKCS, NULL, 0},
143: KEY_RSA, 0, HASH_UNKNOWN},
144: {SIGN_RSA_EMSA_PKCS1_MD5, {CKM_MD5_RSA_PKCS, NULL, 0},
145: KEY_RSA, 0, HASH_UNKNOWN},
146: {SIGN_ECDSA_WITH_NULL, {CKM_ECDSA, NULL, 0},
147: KEY_ECDSA, 0, HASH_UNKNOWN},
148: {SIGN_ECDSA_WITH_SHA1_DER, {CKM_ECDSA_SHA1, NULL, 0},
149: KEY_ECDSA, 0, HASH_UNKNOWN},
150: {SIGN_ECDSA_WITH_SHA256_DER, {CKM_ECDSA, NULL, 0},
151: KEY_ECDSA, 0, HASH_SHA256},
152: {SIGN_ECDSA_WITH_SHA384_DER, {CKM_ECDSA, NULL, 0},
153: KEY_ECDSA, 0, HASH_SHA384},
154: {SIGN_ECDSA_WITH_SHA512_DER, {CKM_ECDSA, NULL, 0},
155: KEY_ECDSA, 0, HASH_SHA512},
156: {SIGN_ECDSA_256, {CKM_ECDSA, NULL, 0},
157: KEY_ECDSA, 256, HASH_SHA256},
158: {SIGN_ECDSA_384, {CKM_ECDSA, NULL, 0},
159: KEY_ECDSA, 384, HASH_SHA384},
160: {SIGN_ECDSA_521, {CKM_ECDSA, NULL, 0},
161: KEY_ECDSA, 521, HASH_SHA512},
162: };
163: int i;
164:
165: for (i = 0; i < countof(mappings); i++)
166: {
167: if (mappings[i].scheme == scheme)
168: {
169: size_t len = mappings[i].keylen;
170: if (mappings[i].type != type || (len && keylen != len))
171: {
172: return NULL;
173: }
174: if (hash)
175: {
176: *hash = mappings[i].hash;
177: }
178: return &mappings[i].mechanism;
179: }
180: }
181: return NULL;
182: }
183:
184: /**
185: * See header.
186: */
187: CK_MECHANISM_PTR pkcs11_encryption_scheme_to_mech(encryption_scheme_t scheme)
188: {
189: static struct {
190: encryption_scheme_t scheme;
191: CK_MECHANISM mechanism;
192: } mappings[] = {
193: {ENCRYPT_RSA_PKCS1, {CKM_RSA_PKCS, NULL, 0}},
194: {ENCRYPT_RSA_OAEP_SHA1, {CKM_RSA_PKCS_OAEP, NULL, 0}},
195: };
196: int i;
197:
198: for (i = 0; i < countof(mappings); i++)
199: {
200: if (mappings[i].scheme == scheme)
201: {
202: return &mappings[i].mechanism;
203: }
204: }
205: return NULL;
206: }
207:
208: /**
209: * Reauthenticate to do a signature
210: */
211: static bool reauth(private_pkcs11_private_key_t *this,
212: CK_SESSION_HANDLE session)
213: {
214: enumerator_t *enumerator;
215: shared_key_t *shared;
216: chunk_t pin;
217: CK_RV rv;
218: bool found = FALSE, success = FALSE;
219:
220: enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
221: SHARED_PIN, this->keyid, NULL);
222: while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
223: {
224: found = TRUE;
225: pin = shared->get_key(shared);
226: rv = this->lib->f->C_Login(session, CKU_CONTEXT_SPECIFIC,
227: pin.ptr, pin.len);
228: if (rv == CKR_OK)
229: {
230: success = TRUE;
231: break;
232: }
233: DBG1(DBG_CFG, "reauthentication login failed: %N", ck_rv_names, rv);
234: }
235: enumerator->destroy(enumerator);
236:
237: if (!found)
238: {
239: DBG1(DBG_CFG, "private key requires reauthentication, but no PIN found");
240: return FALSE;
241: }
242: return success;
243: }
244:
245: METHOD(private_key_t, sign, bool,
246: private_pkcs11_private_key_t *this, signature_scheme_t scheme, void *params,
247: chunk_t data, chunk_t *signature)
248: {
249: CK_MECHANISM_PTR mechanism;
250: CK_SESSION_HANDLE session;
251: CK_BYTE_PTR buf;
252: CK_ULONG len;
253: CK_RV rv;
254: hash_algorithm_t hash_alg;
255: chunk_t hash = chunk_empty;
256:
257: mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type,
258: get_keysize(this), &hash_alg);
259: if (!mechanism)
260: {
261: DBG1(DBG_LIB, "signature scheme %N not supported",
262: signature_scheme_names, scheme);
263: return FALSE;
264: }
265: rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
266: &session);
267: if (rv != CKR_OK)
268: {
269: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
270: return FALSE;
271: }
272: rv = this->lib->f->C_SignInit(session, mechanism, this->object);
273: if (this->reauth && !reauth(this, session))
274: {
275: this->lib->f->C_CloseSession(session);
276: return FALSE;
277: }
278: if (rv != CKR_OK)
279: {
280: this->lib->f->C_CloseSession(session);
281: DBG1(DBG_LIB, "C_SignInit() failed: %N", ck_rv_names, rv);
282: return FALSE;
283: }
284: if (hash_alg != HASH_UNKNOWN)
285: {
286: hasher_t *hasher;
287:
288: hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
289: if (!hasher || !hasher->allocate_hash(hasher, data, &hash))
290: {
291: DESTROY_IF(hasher);
292: this->lib->f->C_CloseSession(session);
293: return FALSE;
294: }
295: hasher->destroy(hasher);
296: data = hash;
297: }
298: len = (get_keysize(this) + 7) / 8;
299: if (this->type == KEY_ECDSA)
300: { /* signature is twice the length of the base point order */
301: len *= 2;
302: }
303: buf = malloc(len);
304: rv = this->lib->f->C_Sign(session, data.ptr, data.len, buf, &len);
305: this->lib->f->C_CloseSession(session);
306: chunk_free(&hash);
307: if (rv != CKR_OK)
308: {
309: DBG1(DBG_LIB, "C_Sign() failed: %N", ck_rv_names, rv);
310: free(buf);
311: return FALSE;
312: }
313: switch (scheme)
314: {
315: case SIGN_ECDSA_WITH_SHA1_DER:
316: case SIGN_ECDSA_WITH_SHA256_DER:
317: case SIGN_ECDSA_WITH_SHA384_DER:
318: case SIGN_ECDSA_WITH_SHA512_DER:
319: {
320: chunk_t r, s;
321:
322: /* return an ASN.1 encoded sequence of integers r and s, removing
323: * any zero-padding */
324: len /= 2;
325: r = chunk_skip_zero(chunk_create(buf, len));
326: s = chunk_skip_zero(chunk_create(buf+len, len));
327: *signature = asn1_wrap(ASN1_SEQUENCE, "mm",
328: asn1_integer("c", r), asn1_integer("c", s));
329: free(buf);
330: break;
331: }
332: default:
333: *signature = chunk_create(buf, len);
334: break;
335: }
336: return TRUE;
337: }
338:
339: METHOD(private_key_t, decrypt, bool,
340: private_pkcs11_private_key_t *this, encryption_scheme_t scheme,
341: chunk_t crypt, chunk_t *plain)
342: {
343: CK_MECHANISM_PTR mechanism;
344: CK_SESSION_HANDLE session;
345: CK_BYTE_PTR buf;
346: CK_ULONG len;
347: CK_RV rv;
348:
349: mechanism = pkcs11_encryption_scheme_to_mech(scheme);
350: if (!mechanism)
351: {
352: DBG1(DBG_LIB, "encryption scheme %N not supported",
353: encryption_scheme_names, scheme);
354: return FALSE;
355: }
356: rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
357: &session);
358: if (rv != CKR_OK)
359: {
360: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
361: return FALSE;
362: }
363: rv = this->lib->f->C_DecryptInit(session, mechanism, this->object);
364: if (this->reauth && !reauth(this, session))
365: {
366: this->lib->f->C_CloseSession(session);
367: return FALSE;
368: }
369: if (rv != CKR_OK)
370: {
371: this->lib->f->C_CloseSession(session);
372: DBG1(DBG_LIB, "C_DecryptInit() failed: %N", ck_rv_names, rv);
373: return FALSE;
374: }
375: len = (get_keysize(this) + 7) / 8;
376: buf = malloc(len);
377: rv = this->lib->f->C_Decrypt(session, crypt.ptr, crypt.len, buf, &len);
378: this->lib->f->C_CloseSession(session);
379: if (rv != CKR_OK)
380: {
381: DBG1(DBG_LIB, "C_Decrypt() failed: %N", ck_rv_names, rv);
382: free(buf);
383: return FALSE;
384: }
385: *plain = chunk_create(buf, len);
386: return TRUE;
387: }
388:
389: METHOD(private_key_t, get_public_key, public_key_t*,
390: private_pkcs11_private_key_t *this)
391: {
392: return this->pubkey->get_ref(this->pubkey);
393: }
394:
395: METHOD(private_key_t, get_fingerprint, bool,
396: private_pkcs11_private_key_t *this, cred_encoding_type_t type,
397: chunk_t *fingerprint)
398: {
399: return this->pubkey->get_fingerprint(this->pubkey, type, fingerprint);
400: }
401:
402: METHOD(private_key_t, get_encoding, bool,
403: private_pkcs11_private_key_t *this, cred_encoding_type_t type,
404: chunk_t *encoding)
405: {
406: return FALSE;
407: }
408:
409: METHOD(private_key_t, get_ref, private_key_t*,
410: private_pkcs11_private_key_t *this)
411: {
412: ref_get(&this->ref);
413: return &this->public.key;
414: }
415:
416: METHOD(private_key_t, destroy, void,
417: private_pkcs11_private_key_t *this)
418: {
419: if (ref_put(&this->ref))
420: {
421: if (this->pubkey)
422: {
423: this->pubkey->destroy(this->pubkey);
424: }
425: this->keyid->destroy(this->keyid);
426: this->lib->f->C_CloseSession(this->session);
427: free(this);
428: }
429: }
430:
431: /**
432: * Find the PKCS#11 library by its friendly name
433: */
434: static pkcs11_library_t* find_lib(char *module)
435: {
436: pkcs11_manager_t *manager;
437: enumerator_t *enumerator;
438: pkcs11_library_t *p11, *found = NULL;
439: CK_SLOT_ID slot;
440:
441: manager = lib->get(lib, "pkcs11-manager");
442: if (!manager)
443: {
444: return NULL;
445: }
446: enumerator = manager->create_token_enumerator(manager);
447: while (enumerator->enumerate(enumerator, &p11, &slot))
448: {
449: if (streq(module, p11->get_name(p11)))
450: {
451: found = p11;
452: break;
453: }
454: }
455: enumerator->destroy(enumerator);
456: return found;
457: }
458:
459: /**
460: * Find the PKCS#11 lib having a keyid, and optionally a slot
461: */
462: static pkcs11_library_t* find_lib_by_keyid(chunk_t keyid, int *slot,
463: CK_OBJECT_CLASS class)
464: {
465: pkcs11_manager_t *manager;
466: enumerator_t *enumerator;
467: pkcs11_library_t *p11, *found = NULL;
468: CK_SLOT_ID current;
469:
470: manager = lib->get(lib, "pkcs11-manager");
471: if (!manager)
472: {
473: return NULL;
474: }
475: enumerator = manager->create_token_enumerator(manager);
476: while (enumerator->enumerate(enumerator, &p11, ¤t))
477: {
478: if (*slot == -1 || *slot == current)
479: {
480: /* look for a pubkey/cert, it is usually readable without login */
481: CK_ATTRIBUTE tmpl[] = {
482: {CKA_CLASS, &class, sizeof(class)},
483: {CKA_ID, keyid.ptr, keyid.len},
484: };
485: CK_OBJECT_HANDLE object;
486: CK_SESSION_HANDLE session;
487: CK_RV rv;
488: enumerator_t *keys;
489:
490: rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
491: &session);
492: if (rv != CKR_OK)
493: {
494: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
495: ck_rv_names, rv);
496: continue;
497: }
498: keys = p11->create_object_enumerator(p11, session,
499: tmpl, countof(tmpl), NULL, 0);
500: if (keys->enumerate(keys, &object))
501: {
502: DBG1(DBG_CFG, "found key on PKCS#11 token '%s':%d",
503: p11->get_name(p11), current);
504: found = p11;
505: *slot = current;
506: }
507: keys->destroy(keys);
508: p11->f->C_CloseSession(session);
509: if (found)
510: {
511: break;
512: }
513: }
514: }
515: enumerator->destroy(enumerator);
516: return found;
517: }
518:
519: /**
520: * Find the PKCS#11 lib and CKA_ID of the certificate object of a given
521: * subjectKeyIdentifier and optional slot
522: */
523: static pkcs11_library_t* find_lib_and_keyid_by_skid(chunk_t keyid_chunk,
524: chunk_t *ckaid, int *slot)
525: {
526: CK_OBJECT_CLASS class = CKO_CERTIFICATE;
527: CK_CERTIFICATE_TYPE type = CKC_X_509;
528: CK_ATTRIBUTE tmpl[] = {
529: {CKA_CLASS, &class, sizeof(class)},
530: {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
531: };
532: CK_ATTRIBUTE attr[] = {
533: {CKA_VALUE, NULL, 0},
534: {CKA_ID, NULL, 0},
535: };
536: CK_OBJECT_HANDLE object;
537: CK_SESSION_HANDLE session;
538: CK_RV rv;
539: pkcs11_manager_t *manager;
540: enumerator_t *enumerator, *certs;
541: identification_t *keyid;
542: pkcs11_library_t *p11, *found = NULL;
543: CK_SLOT_ID current;
544: linked_list_t *raw;
545: certificate_t *cert;
546: struct {
547: chunk_t value;
548: chunk_t ckaid;
549: } *entry;
550:
551: manager = lib->get(lib, "pkcs11-manager");
552: if (!manager)
553: {
554: return NULL;
555: }
556:
557: keyid = identification_create_from_encoding(ID_KEY_ID, keyid_chunk);
558: /* store result in a temporary list, avoid recursive operation */
559: raw = linked_list_create();
560:
561: enumerator = manager->create_token_enumerator(manager);
562: while (enumerator->enumerate(enumerator, &p11, ¤t))
563: {
564: if (*slot != -1 && *slot != current)
565: {
566: continue;
567: }
568: rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
569: &session);
570: if (rv != CKR_OK)
571: {
572: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
573: ck_rv_names, rv);
574: continue;
575: }
576: certs = p11->create_object_enumerator(p11, session, tmpl, countof(tmpl),
577: attr, countof(attr));
578: while (certs->enumerate(certs, &object))
579: {
580: INIT(entry,
581: .value = chunk_clone(
582: chunk_create(attr[0].pValue, attr[0].ulValueLen)),
583: .ckaid = chunk_clone(
584: chunk_create(attr[1].pValue, attr[1].ulValueLen)),
585: );
586: raw->insert_last(raw, entry);
587: }
588: certs->destroy(certs);
589:
590: while (raw->remove_first(raw, (void**)&entry) == SUCCESS)
591: {
592: if (!found)
593: {
594: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
595: CERT_X509, BUILD_BLOB_ASN1_DER,
596: entry->value, BUILD_END);
597: if (cert)
598: {
599: if (cert->has_subject(cert, keyid))
600: {
601: DBG1(DBG_CFG, "found cert with keyid '%#B' on PKCS#11 "
602: "token '%s':%d", &keyid_chunk, p11->get_name(p11),
603: current);
604: found = p11;
605: *ckaid = chunk_clone(entry->ckaid);
606: *slot = current;
607: }
608: cert->destroy(cert);
609: }
610: else
611: {
612: DBG1(DBG_CFG, "parsing cert with CKA_ID '%#B' on PKCS#11 "
613: "token '%s':%d failed", &entry->ckaid,
614: p11->get_name(p11), current);
615: }
616: }
617: chunk_free(&entry->value);
618: chunk_free(&entry->ckaid);
619: free(entry);
620: }
621: p11->f->C_CloseSession(session);
622: if (found)
623: {
624: break;
625: }
626: }
627: enumerator->destroy(enumerator);
628: keyid->destroy(keyid);
629: raw->destroy(raw);
630: return found;
631: }
632:
633: /**
634: * Find the key on the token
635: */
636: static bool find_key(private_pkcs11_private_key_t *this, chunk_t keyid)
637: {
638: CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
639: CK_ATTRIBUTE tmpl[] = {
640: {CKA_CLASS, &class, sizeof(class)},
641: {CKA_ID, keyid.ptr, keyid.len},
642: };
643: CK_OBJECT_HANDLE object;
644: CK_KEY_TYPE type;
645: CK_BBOOL reauth = FALSE;
646: CK_ATTRIBUTE attr[] = {
647: {CKA_KEY_TYPE, &type, sizeof(type)},
648: {CKA_ALWAYS_AUTHENTICATE, &reauth, sizeof(reauth)},
649: };
650: enumerator_t *enumerator;
651: int count = countof(attr);
652: bool found = FALSE;
653:
654: /* do not use CKA_ALWAYS_AUTHENTICATE if not supported */
655: if (!(this->lib->get_features(this->lib) & PKCS11_ALWAYS_AUTH_KEYS))
656: {
657: count--;
658: }
659: enumerator = this->lib->create_object_enumerator(this->lib,
660: this->session, tmpl, countof(tmpl), attr, count);
661: if (enumerator->enumerate(enumerator, &object))
662: {
663: this->type = KEY_RSA;
664: switch (type)
665: {
666: case CKK_ECDSA:
667: this->type = KEY_ECDSA;
668: /* fall-through */
669: case CKK_RSA:
670: this->reauth = reauth;
671: this->object = object;
672: found = TRUE;
673: break;
674: default:
675: DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
676: break;
677: }
678: }
679: enumerator->destroy(enumerator);
680: return found;
681: }
682:
683: /**
684: * Find a PIN and try to log in
685: */
686: static bool login(private_pkcs11_private_key_t *this, int slot)
687: {
688: enumerator_t *enumerator;
689: shared_key_t *shared;
690: chunk_t pin;
691: CK_RV rv;
692: CK_SESSION_INFO info;
693: bool found = FALSE, success = FALSE;
694:
695: rv = this->lib->f->C_GetSessionInfo(this->session, &info);
696: if (rv != CKR_OK)
697: {
698: DBG1(DBG_CFG, "C_GetSessionInfo failed: %N", ck_rv_names, rv);
699: return FALSE;
700: }
701: if (info.state != CKS_RO_PUBLIC_SESSION &&
702: info.state != CKS_RW_PUBLIC_SESSION)
703: { /* already logged in with another session, skip */
704: return TRUE;
705: }
706:
707: enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
708: SHARED_PIN, this->keyid, NULL);
709: while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
710: {
711: found = TRUE;
712: pin = shared->get_key(shared);
713: rv = this->lib->f->C_Login(this->session, CKU_USER, pin.ptr, pin.len);
714: if (rv == CKR_OK)
715: {
716: success = TRUE;
717: break;
718: }
719: DBG1(DBG_CFG, "login to '%s':%d failed: %N",
720: this->lib->get_name(this->lib), slot, ck_rv_names, rv);
721: }
722: enumerator->destroy(enumerator);
723:
724: if (!found)
725: {
726: DBG1(DBG_CFG, "no PIN found for PKCS#11 key %Y", this->keyid);
727: return FALSE;
728: }
729: return success;
730: }
731:
732: /**
733: * Get a public key from a certificate with a given key ID.
734: */
735: static public_key_t* find_pubkey_in_certs(private_pkcs11_private_key_t *this,
736: chunk_t keyid)
737: {
738: CK_OBJECT_CLASS class = CKO_CERTIFICATE;
739: CK_CERTIFICATE_TYPE type = CKC_X_509;
740: CK_ATTRIBUTE tmpl[] = {
741: {CKA_CLASS, &class, sizeof(class)},
742: {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
743: {CKA_ID, keyid.ptr, keyid.len},
744: };
745: CK_OBJECT_HANDLE object;
746: CK_ATTRIBUTE attr[] = {
747: {CKA_VALUE, NULL, 0},
748: };
749: enumerator_t *enumerator;
750: chunk_t data = chunk_empty;
751: public_key_t *key = NULL;
752: certificate_t *cert;
753:
754: enumerator = this->lib->create_object_enumerator(this->lib, this->session,
755: tmpl, countof(tmpl), attr, countof(attr));
756: if (enumerator->enumerate(enumerator, &object))
757: {
758: data = chunk_clone(chunk_create(attr[0].pValue, attr[0].ulValueLen));
759: }
760: enumerator->destroy(enumerator);
761:
762: if (data.ptr)
763: {
764: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
765: BUILD_BLOB_ASN1_DER, data, BUILD_END);
766: free(data.ptr);
767: if (cert)
768: {
769: key = cert->get_public_key(cert);
770: cert->destroy(cert);
771: }
772: }
773: return key;
774: }
775:
776: /**
777: * See header.
778: */
779: pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args)
780: {
781: private_pkcs11_private_key_t *this;
782: char *module = NULL;
783: chunk_t keyid = chunk_empty, ckaid = chunk_empty;
784: int slot = -1;
785: CK_RV rv;
786:
787: while (TRUE)
788: {
789: switch (va_arg(args, builder_part_t))
790: {
791: case BUILD_PKCS11_KEYID:
792: keyid = va_arg(args, chunk_t);
793: continue;
794: case BUILD_PKCS11_SLOT:
795: slot = va_arg(args, int);
796: continue;
797: case BUILD_PKCS11_MODULE:
798: module = va_arg(args, char*);
799: continue;
800: case BUILD_END:
801: break;
802: default:
803: return NULL;
804: }
805: break;
806: }
807: if (!keyid.len)
808: {
809: return NULL;
810: }
811:
812: INIT(this,
813: .public = {
814: .key = {
815: .get_type = _get_type,
816: .sign = _sign,
817: .decrypt = _decrypt,
818: .get_keysize = _get_keysize,
819: .get_public_key = _get_public_key,
820: .equals = private_key_equals,
821: .belongs_to = private_key_belongs_to,
822: .get_fingerprint = _get_fingerprint,
823: .has_fingerprint = private_key_has_fingerprint,
824: .get_encoding = _get_encoding,
825: .get_ref = _get_ref,
826: .destroy = _destroy,
827: },
828: },
829: .ref = 1,
830: );
831:
832: if (module && slot != -1)
833: {
834: this->lib = find_lib(module);
835: if (!this->lib)
836: {
837: DBG1(DBG_CFG, "PKCS#11 module '%s' not found", module);
838: free(this);
839: return NULL;
840: }
841: }
842: else
843: {
844: this->lib = find_lib_by_keyid(keyid, &slot, CKO_PUBLIC_KEY);
845: if (!this->lib)
846: {
847: this->lib = find_lib_by_keyid(keyid, &slot, CKO_CERTIFICATE);
848: }
849: if (!this->lib)
850: {
851: this->lib = find_lib_and_keyid_by_skid(keyid, &ckaid, &slot);
852: }
853: if (!this->lib)
854: {
855: DBG1(DBG_CFG, "no PKCS#11 module found having a keyid %#B", &keyid);
856: free(this);
857: return NULL;
858: }
859: }
860:
861: rv = this->lib->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
862: NULL, NULL, &this->session);
863: if (rv != CKR_OK)
864: {
865: DBG1(DBG_CFG, "opening private key session on '%s':%d failed: %N",
866: module, slot, ck_rv_names, rv);
867: free(this);
868: return NULL;
869: }
870:
871: this->slot = slot;
872: this->keyid = identification_create_from_encoding(ID_KEY_ID, keyid);
873:
874: if (!login(this, slot))
875: {
876: destroy(this);
877: return NULL;
878: }
879:
880: if (ckaid.ptr)
881: {
882: DBG1(DBG_CFG, "using CKA_ID '%#B' for key with keyid '%#B'",
883: &ckaid, &keyid);
884: keyid = ckaid;
885: }
886:
887: if (!find_key(this, keyid))
888: {
889: DBG1(DBG_CFG, "did not find the key with %s '%#B'",
890: ckaid.ptr ? "CKA_ID" : "keyid", &keyid);
891: destroy(this);
892: return NULL;
893: }
894:
895: this->pubkey = pkcs11_public_key_connect(this->lib, slot, this->type, keyid);
896: if (!this->pubkey)
897: {
898: this->pubkey = find_pubkey_in_certs(this, keyid);
899: if (!this->pubkey)
900: {
901: DBG1(DBG_CFG, "no public key or certificate found for private key "
902: "(%s '%#B') on '%s':%d", ckaid.ptr ? "CKA_ID" : "keyid",
903: &keyid, module, slot);
904: destroy(this);
905: return NULL;
906: }
907: }
908: return &this->public;
909: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>