]> git.ipfire.org Git - people/ms/strongswan.git/blame - src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c
Merge branch 'rsa-oaep-encryption'
[people/ms/strongswan.git] / src / libstrongswan / plugins / pkcs11 / pkcs11_private_key.c
CommitLineData
5f1e4438 1/*
9a704963 2 * Copyright (C) 2011-2016 Tobias Brunner
1b671669 3 * HSR Hochschule fuer Technik Rapperswil
b0319fe8 4 *
5f1e4438
MW
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 */
9a704963
RG
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 */
5f1e4438
MW
39
40#include "pkcs11_private_key.h"
41
42#include "pkcs11_library.h"
43#include "pkcs11_manager.h"
44fdc62f 44#include "pkcs11_public_key.h"
5f1e4438 45
f05b4272 46#include <utils/debug.h>
b258ed01 47#include <asn1/asn1.h>
5f1e4438
MW
48
49typedef struct private_pkcs11_private_key_t private_pkcs11_private_key_t;
50
51/**
52 * Private data of an pkcs11_private_key_t object.
53 */
54struct 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 /**
b0319fe8 67 * Slot the token is in
5f1e4438 68 */
b0319fe8 69 CK_SLOT_ID slot;
5f1e4438
MW
70
71 /**
b0319fe8 72 * Token session
5f1e4438 73 */
b0319fe8 74 CK_SESSION_HANDLE session;
5f1e4438
MW
75
76 /**
77 * Key object on the token
78 */
79 CK_OBJECT_HANDLE object;
80
af007ed6
MW
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
5f1e4438
MW
91 /**
92 * Associated public key
93 */
94 public_key_t *pubkey;
95
96 /**
97 * References to this key
98 */
99 refcount_t ref;
5d2fccf4
TB
100
101 /**
102 * Type of this private key
103 */
104 key_type_t type;
5f1e4438
MW
105};
106
30a3ede8 107
5f1e4438
MW
108METHOD(private_key_t, get_type, key_type_t,
109 private_pkcs11_private_key_t *this)
110{
5d2fccf4 111 return this->type;
5f1e4438
MW
112}
113
a944d209 114METHOD(private_key_t, get_keysize, int,
5f1e4438
MW
115 private_pkcs11_private_key_t *this)
116{
117 return this->pubkey->get_keysize(this->pubkey);
118}
119
120/**
b6fcdc71
TB
121 * Check if a token supports the given mechanism.
122 */
123static 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
5f1e4438 144 */
b6fcdc71
TB
145CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(pkcs11_library_t *p11,
146 CK_SLOT_ID slot,
147 signature_scheme_t scheme,
5b85b94e 148 key_type_t type, size_t keylen,
fd48b220 149 hash_algorithm_t *hash)
5f1e4438
MW
150{
151 static struct {
152 signature_scheme_t scheme;
153 CK_MECHANISM mechanism;
5b85b94e
TB
154 key_type_t type;
155 size_t keylen;
fd48b220 156 hash_algorithm_t hash;
5f1e4438 157 } mappings[] = {
fd48b220 158 {SIGN_RSA_EMSA_PKCS1_NULL, {CKM_RSA_PKCS, NULL, 0},
5b85b94e 159 KEY_RSA, 0, HASH_UNKNOWN},
40f2589a 160 {SIGN_RSA_EMSA_PKCS1_SHA2_256, {CKM_SHA256_RSA_PKCS, NULL, 0},
5b85b94e 161 KEY_RSA, 0, HASH_UNKNOWN},
b6fcdc71
TB
162 {SIGN_RSA_EMSA_PKCS1_SHA2_256, {CKM_RSA_PKCS, NULL, 0},
163 KEY_RSA, 0, HASH_SHA256},
40f2589a 164 {SIGN_RSA_EMSA_PKCS1_SHA2_384, {CKM_SHA384_RSA_PKCS, NULL, 0},
5b85b94e 165 KEY_RSA, 0, HASH_UNKNOWN},
b6fcdc71
TB
166 {SIGN_RSA_EMSA_PKCS1_SHA2_384, {CKM_RSA_PKCS, NULL, 0},
167 KEY_RSA, 0, HASH_SHA384},
40f2589a 168 {SIGN_RSA_EMSA_PKCS1_SHA2_512, {CKM_SHA512_RSA_PKCS, NULL, 0},
5b85b94e 169 KEY_RSA, 0, HASH_UNKNOWN},
b6fcdc71
TB
170 {SIGN_RSA_EMSA_PKCS1_SHA2_512, {CKM_RSA_PKCS, NULL, 0},
171 KEY_RSA, 0, HASH_SHA512},
40f2589a 172 {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_SHA1_RSA_PKCS, NULL, 0},
5b85b94e 173 KEY_RSA, 0, HASH_UNKNOWN},
b6fcdc71
TB
174 {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_RSA_PKCS, NULL, 0},
175 KEY_RSA, 0, HASH_SHA1},
fd48b220 176 {SIGN_RSA_EMSA_PKCS1_MD5, {CKM_MD5_RSA_PKCS, NULL, 0},
5b85b94e 177 KEY_RSA, 0, HASH_UNKNOWN},
fd48b220 178 {SIGN_ECDSA_WITH_NULL, {CKM_ECDSA, NULL, 0},
5b85b94e 179 KEY_ECDSA, 0, HASH_UNKNOWN},
fd48b220 180 {SIGN_ECDSA_WITH_SHA1_DER, {CKM_ECDSA_SHA1, NULL, 0},
5b85b94e 181 KEY_ECDSA, 0, HASH_UNKNOWN},
fd48b220 182 {SIGN_ECDSA_WITH_SHA256_DER, {CKM_ECDSA, NULL, 0},
5b85b94e 183 KEY_ECDSA, 0, HASH_SHA256},
fd48b220 184 {SIGN_ECDSA_WITH_SHA384_DER, {CKM_ECDSA, NULL, 0},
5b85b94e 185 KEY_ECDSA, 0, HASH_SHA384},
fd48b220 186 {SIGN_ECDSA_WITH_SHA512_DER, {CKM_ECDSA, NULL, 0},
5b85b94e 187 KEY_ECDSA, 0, HASH_SHA512},
fd48b220 188 {SIGN_ECDSA_256, {CKM_ECDSA, NULL, 0},
5b85b94e 189 KEY_ECDSA, 256, HASH_SHA256},
fd48b220 190 {SIGN_ECDSA_384, {CKM_ECDSA, NULL, 0},
5b85b94e 191 KEY_ECDSA, 384, HASH_SHA384},
fd48b220 192 {SIGN_ECDSA_521, {CKM_ECDSA, NULL, 0},
5b85b94e 193 KEY_ECDSA, 521, HASH_SHA512},
5f1e4438
MW
194 };
195 int i;
196
197 for (i = 0; i < countof(mappings); i++)
198 {
199 if (mappings[i].scheme == scheme)
200 {
5b85b94e 201 size_t len = mappings[i].keylen;
b6fcdc71
TB
202
203 if (mappings[i].type != type || (len && keylen != len) ||
204 !is_mechanism_supported(p11, slot, &mappings[i].mechanism))
5b85b94e 205 {
b6fcdc71 206 continue;
5b85b94e 207 }
fd48b220
TB
208 if (hash)
209 {
210 *hash = mappings[i].hash;
211 }
5f1e4438
MW
212 return &mappings[i].mechanism;
213 }
214 }
215 return NULL;
216}
217
01e4f5f3
MW
218/**
219 * See header.
220 */
221CK_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
af007ed6
MW
242/**
243 * Reauthenticate to do a signature
244 */
b0319fe8
TB
245static bool reauth(private_pkcs11_private_key_t *this,
246 CK_SESSION_HANDLE session)
af007ed6
MW
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);
b0319fe8 260 rv = this->lib->f->C_Login(session, CKU_CONTEXT_SPECIFIC,
af007ed6
MW
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
5f1e4438 279METHOD(private_key_t, sign, bool,
de280c2e 280 private_pkcs11_private_key_t *this, signature_scheme_t scheme, void *params,
5f1e4438
MW
281 chunk_t data, chunk_t *signature)
282{
283 CK_MECHANISM_PTR mechanism;
b0319fe8 284 CK_SESSION_HANDLE session;
5f1e4438
MW
285 CK_BYTE_PTR buf;
286 CK_ULONG len;
287 CK_RV rv;
fd48b220
TB
288 hash_algorithm_t hash_alg;
289 chunk_t hash = chunk_empty;
5f1e4438 290
b6fcdc71
TB
291 mechanism = pkcs11_signature_scheme_to_mech(this->lib, this->slot, scheme,
292 this->type, get_keysize(this),
293 &hash_alg);
5f1e4438
MW
294 if (!mechanism)
295 {
296 DBG1(DBG_LIB, "signature scheme %N not supported",
297 signature_scheme_names, scheme);
298 return FALSE;
299 }
b0319fe8
TB
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))
af007ed6 309 {
b0319fe8 310 this->lib->f->C_CloseSession(session);
af007ed6
MW
311 return FALSE;
312 }
5f1e4438
MW
313 if (rv != CKR_OK)
314 {
b0319fe8 315 this->lib->f->C_CloseSession(session);
5f1e4438
MW
316 DBG1(DBG_LIB, "C_SignInit() failed: %N", ck_rv_names, rv);
317 return FALSE;
318 }
fd48b220
TB
319 if (hash_alg != HASH_UNKNOWN)
320 {
87dd205b
MW
321 hasher_t *hasher;
322
323 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
324 if (!hasher || !hasher->allocate_hash(hasher, data, &hash))
fd48b220 325 {
87dd205b 326 DESTROY_IF(hasher);
fd48b220
TB
327 this->lib->f->C_CloseSession(session);
328 return FALSE;
329 }
fd48b220 330 hasher->destroy(hasher);
b6fcdc71
TB
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 }
fd48b220
TB
346 data = hash;
347 }
a944d209 348 len = (get_keysize(this) + 7) / 8;
fd48b220
TB
349 if (this->type == KEY_ECDSA)
350 { /* signature is twice the length of the base point order */
351 len *= 2;
352 }
af007ed6 353 buf = malloc(len);
b0319fe8
TB
354 rv = this->lib->f->C_Sign(session, data.ptr, data.len, buf, &len);
355 this->lib->f->C_CloseSession(session);
fd48b220 356 chunk_free(&hash);
5f1e4438
MW
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 }
b258ed01
TB
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:
7316a13b
TB
369 {
370 chunk_t r, s;
371
372 /* return an ASN.1 encoded sequence of integers r and s, removing
373 * any zero-padding */
b258ed01 374 len /= 2;
7316a13b
TB
375 r = chunk_skip_zero(chunk_create(buf, len));
376 s = chunk_skip_zero(chunk_create(buf+len, len));
b258ed01 377 *signature = asn1_wrap(ASN1_SEQUENCE, "mm",
7316a13b 378 asn1_integer("c", r), asn1_integer("c", s));
b258ed01
TB
379 free(buf);
380 break;
7316a13b 381 }
b258ed01
TB
382 default:
383 *signature = chunk_create(buf, len);
384 break;
385 }
5f1e4438
MW
386 return TRUE;
387}
388
389METHOD(private_key_t, decrypt, bool,
33ddaaab 390 private_pkcs11_private_key_t *this, encryption_scheme_t scheme,
4abb29f6 391 void *params, chunk_t crypt, chunk_t *plain)
5f1e4438 392{
01e4f5f3 393 CK_MECHANISM_PTR mechanism;
b0319fe8 394 CK_SESSION_HANDLE session;
01e4f5f3
MW
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 }
b0319fe8
TB
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))
01e4f5f3 415 {
b0319fe8 416 this->lib->f->C_CloseSession(session);
01e4f5f3
MW
417 return FALSE;
418 }
419 if (rv != CKR_OK)
420 {
b0319fe8 421 this->lib->f->C_CloseSession(session);
01e4f5f3
MW
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);
b0319fe8
TB
427 rv = this->lib->f->C_Decrypt(session, crypt.ptr, crypt.len, buf, &len);
428 this->lib->f->C_CloseSession(session);
01e4f5f3
MW
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;
5f1e4438
MW
437}
438
439METHOD(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
445METHOD(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
452METHOD(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
459METHOD(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
466METHOD(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 }
af007ed6 475 this->keyid->destroy(this->keyid);
5f1e4438
MW
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 */
484static 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
07190323 491 manager = lib->get(lib, "pkcs11-manager");
5f1e4438
MW
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
7afc00d0
MW
509/**
510 * Find the PKCS#11 lib having a keyid, and optionally a slot
511 */
712e8130
MW
512static pkcs11_library_t* find_lib_by_keyid(chunk_t keyid, int *slot,
513 CK_OBJECT_CLASS class)
7afc00d0
MW
514{
515 pkcs11_manager_t *manager;
516 enumerator_t *enumerator;
517 pkcs11_library_t *p11, *found = NULL;
518 CK_SLOT_ID current;
519
07190323 520 manager = lib->get(lib, "pkcs11-manager");
7afc00d0
MW
521 if (!manager)
522 {
523 return NULL;
524 }
525 enumerator = manager->create_token_enumerator(manager);
526 while (enumerator->enumerate(enumerator, &p11, &current))
527 {
528 if (*slot == -1 || *slot == current)
529 {
712e8130 530 /* look for a pubkey/cert, it is usually readable without login */
7afc00d0
MW
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
9a704963
RG
569/**
570 * Find the PKCS#11 lib and CKA_ID of the certificate object of a given
571 * subjectKeyIdentifier and optional slot
572 */
573static 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, &current))
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 {
6537be9c
TB
630 if (attr[0].ulValueLen != CK_UNAVAILABLE_INFORMATION &&
631 attr[1].ulValueLen != CK_UNAVAILABLE_INFORMATION)
632 {
633 INIT(entry,
634 .value = chunk_clone(
635 chunk_create(attr[0].pValue, attr[0].ulValueLen)),
636 .ckaid = chunk_clone(
637 chunk_create(attr[1].pValue, attr[1].ulValueLen)),
638 );
639 raw->insert_last(raw, entry);
640 }
9a704963
RG
641 }
642 certs->destroy(certs);
643
644 while (raw->remove_first(raw, (void**)&entry) == SUCCESS)
645 {
646 if (!found)
647 {
648 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
649 CERT_X509, BUILD_BLOB_ASN1_DER,
650 entry->value, BUILD_END);
651 if (cert)
652 {
653 if (cert->has_subject(cert, keyid))
654 {
655 DBG1(DBG_CFG, "found cert with keyid '%#B' on PKCS#11 "
656 "token '%s':%d", &keyid_chunk, p11->get_name(p11),
657 current);
658 found = p11;
659 *ckaid = chunk_clone(entry->ckaid);
660 *slot = current;
661 }
662 cert->destroy(cert);
663 }
664 else
665 {
666 DBG1(DBG_CFG, "parsing cert with CKA_ID '%#B' on PKCS#11 "
667 "token '%s':%d failed", &entry->ckaid,
668 p11->get_name(p11), current);
669 }
670 }
671 chunk_free(&entry->value);
672 chunk_free(&entry->ckaid);
673 free(entry);
674 }
675 p11->f->C_CloseSession(session);
676 if (found)
677 {
678 break;
679 }
680 }
681 enumerator->destroy(enumerator);
682 keyid->destroy(keyid);
683 raw->destroy(raw);
684 return found;
685}
686
5f1e4438
MW
687/**
688 * Find the key on the token
689 */
690static bool find_key(private_pkcs11_private_key_t *this, chunk_t keyid)
691{
692 CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
693 CK_ATTRIBUTE tmpl[] = {
694 {CKA_CLASS, &class, sizeof(class)},
695 {CKA_ID, keyid.ptr, keyid.len},
696 };
697 CK_OBJECT_HANDLE object;
698 CK_KEY_TYPE type;
b78ca4b0 699 CK_BBOOL reauth = FALSE;
5f1e4438
MW
700 CK_ATTRIBUTE attr[] = {
701 {CKA_KEY_TYPE, &type, sizeof(type)},
b78ca4b0 702 {CKA_ALWAYS_AUTHENTICATE, &reauth, sizeof(reauth)},
5f1e4438
MW
703 };
704 enumerator_t *enumerator;
b78ca4b0 705 int count = countof(attr);
5d2fccf4 706 bool found = FALSE;
5f1e4438 707
b78ca4b0
MW
708 /* do not use CKA_ALWAYS_AUTHENTICATE if not supported */
709 if (!(this->lib->get_features(this->lib) & PKCS11_ALWAYS_AUTH_KEYS))
710 {
711 count--;
712 }
5f1e4438 713 enumerator = this->lib->create_object_enumerator(this->lib,
b78ca4b0 714 this->session, tmpl, countof(tmpl), attr, count);
6537be9c
TB
715 if (enumerator->enumerate(enumerator, &object) &&
716 attr[0].ulValueLen != CK_UNAVAILABLE_INFORMATION)
5f1e4438 717 {
5d2fccf4 718 this->type = KEY_RSA;
5f1e4438
MW
719 switch (type)
720 {
5d2fccf4
TB
721 case CKK_ECDSA:
722 this->type = KEY_ECDSA;
723 /* fall-through */
5f1e4438 724 case CKK_RSA:
6537be9c
TB
725 if (attr[1].ulValueLen != CK_UNAVAILABLE_INFORMATION)
726 {
727 this->reauth = reauth;
728 }
5f1e4438 729 this->object = object;
5d2fccf4 730 found = TRUE;
5f1e4438
MW
731 break;
732 default:
733 DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
734 break;
735 }
736 }
737 enumerator->destroy(enumerator);
5d2fccf4 738 return found;
5f1e4438
MW
739}
740
a0bdd5d6 741/**
62be9236 742 * Find a PIN and try to log in
a0bdd5d6 743 */
af007ed6 744static bool login(private_pkcs11_private_key_t *this, int slot)
a0bdd5d6 745{
0556667d 746 enumerator_t *enumerator;
62be9236
MW
747 shared_key_t *shared;
748 chunk_t pin;
a0bdd5d6 749 CK_RV rv;
199b1712 750 CK_SESSION_INFO info;
0556667d 751 bool found = FALSE, success = FALSE;
a0bdd5d6 752
199b1712
MW
753 rv = this->lib->f->C_GetSessionInfo(this->session, &info);
754 if (rv != CKR_OK)
755 {
756 DBG1(DBG_CFG, "C_GetSessionInfo failed: %N", ck_rv_names, rv);
757 return FALSE;
758 }
759 if (info.state != CKS_RO_PUBLIC_SESSION &&
760 info.state != CKS_RW_PUBLIC_SESSION)
761 { /* already logged in with another session, skip */
762 return TRUE;
763 }
764
0556667d 765 enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
af007ed6 766 SHARED_PIN, this->keyid, NULL);
0556667d 767 while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
a0bdd5d6 768 {
0556667d
MW
769 found = TRUE;
770 pin = shared->get_key(shared);
771 rv = this->lib->f->C_Login(this->session, CKU_USER, pin.ptr, pin.len);
772 if (rv == CKR_OK)
773 {
774 success = TRUE;
775 break;
776 }
a0bdd5d6
MW
777 DBG1(DBG_CFG, "login to '%s':%d failed: %N",
778 this->lib->get_name(this->lib), slot, ck_rv_names, rv);
0556667d
MW
779 }
780 enumerator->destroy(enumerator);
0556667d
MW
781
782 if (!found)
783 {
af007ed6 784 DBG1(DBG_CFG, "no PIN found for PKCS#11 key %Y", this->keyid);
a0bdd5d6
MW
785 return FALSE;
786 }
0556667d 787 return success;
a0bdd5d6
MW
788}
789
ffe42fa4
MW
790/**
791 * Get a public key from a certificate with a given key ID.
792 */
793static public_key_t* find_pubkey_in_certs(private_pkcs11_private_key_t *this,
794 chunk_t keyid)
795{
796 CK_OBJECT_CLASS class = CKO_CERTIFICATE;
797 CK_CERTIFICATE_TYPE type = CKC_X_509;
798 CK_ATTRIBUTE tmpl[] = {
799 {CKA_CLASS, &class, sizeof(class)},
800 {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
801 {CKA_ID, keyid.ptr, keyid.len},
802 };
803 CK_OBJECT_HANDLE object;
804 CK_ATTRIBUTE attr[] = {
805 {CKA_VALUE, NULL, 0},
806 };
807 enumerator_t *enumerator;
808 chunk_t data = chunk_empty;
809 public_key_t *key = NULL;
810 certificate_t *cert;
811
812 enumerator = this->lib->create_object_enumerator(this->lib, this->session,
813 tmpl, countof(tmpl), attr, countof(attr));
6537be9c
TB
814 if (enumerator->enumerate(enumerator, &object) &&
815 attr[0].ulValueLen != CK_UNAVAILABLE_INFORMATION)
ffe42fa4
MW
816 {
817 data = chunk_clone(chunk_create(attr[0].pValue, attr[0].ulValueLen));
818 }
819 enumerator->destroy(enumerator);
820
821 if (data.ptr)
822 {
823 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
824 BUILD_BLOB_ASN1_DER, data, BUILD_END);
825 free(data.ptr);
826 if (cert)
827 {
828 key = cert->get_public_key(cert);
829 cert->destroy(cert);
830 }
831 }
832 return key;
833}
834
5f1e4438
MW
835/**
836 * See header.
837 */
838pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args)
839{
840 private_pkcs11_private_key_t *this;
0b8b6640 841 char *module = NULL;
9a704963 842 chunk_t keyid = chunk_empty, ckaid = chunk_empty;
62be9236 843 int slot = -1;
5f1e4438 844 CK_RV rv;
5f1e4438
MW
845
846 while (TRUE)
847 {
848 switch (va_arg(args, builder_part_t))
849 {
850 case BUILD_PKCS11_KEYID:
0b8b6640 851 keyid = va_arg(args, chunk_t);
5f1e4438 852 continue;
5f1e4438
MW
853 case BUILD_PKCS11_SLOT:
854 slot = va_arg(args, int);
855 continue;
856 case BUILD_PKCS11_MODULE:
857 module = va_arg(args, char*);
858 continue;
859 case BUILD_END:
860 break;
861 default:
862 return NULL;
863 }
864 break;
865 }
62be9236 866 if (!keyid.len)
7afc00d0 867 {
5f1e4438
MW
868 return NULL;
869 }
870
871 INIT(this,
ba31fe1f
MW
872 .public = {
873 .key = {
874 .get_type = _get_type,
875 .sign = _sign,
876 .decrypt = _decrypt,
877 .get_keysize = _get_keysize,
878 .get_public_key = _get_public_key,
879 .equals = private_key_equals,
880 .belongs_to = private_key_belongs_to,
881 .get_fingerprint = _get_fingerprint,
882 .has_fingerprint = private_key_has_fingerprint,
883 .get_encoding = _get_encoding,
884 .get_ref = _get_ref,
885 .destroy = _destroy,
886 },
5f1e4438
MW
887 },
888 .ref = 1,
889 );
890
7afc00d0 891 if (module && slot != -1)
5f1e4438 892 {
7afc00d0
MW
893 this->lib = find_lib(module);
894 if (!this->lib)
895 {
896 DBG1(DBG_CFG, "PKCS#11 module '%s' not found", module);
897 free(this);
898 return NULL;
899 }
900 }
901 else
902 {
712e8130
MW
903 this->lib = find_lib_by_keyid(keyid, &slot, CKO_PUBLIC_KEY);
904 if (!this->lib)
905 {
906 this->lib = find_lib_by_keyid(keyid, &slot, CKO_CERTIFICATE);
907 }
7afc00d0 908 if (!this->lib)
9a704963
RG
909 {
910 this->lib = find_lib_and_keyid_by_skid(keyid, &ckaid, &slot);
911 }
912 if (!this->lib)
7afc00d0
MW
913 {
914 DBG1(DBG_CFG, "no PKCS#11 module found having a keyid %#B", &keyid);
915 free(this);
916 return NULL;
917 }
5f1e4438
MW
918 }
919
920 rv = this->lib->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
921 NULL, NULL, &this->session);
922 if (rv != CKR_OK)
923 {
924 DBG1(DBG_CFG, "opening private key session on '%s':%d failed: %N",
925 module, slot, ck_rv_names, rv);
926 free(this);
927 return NULL;
928 }
929
b0319fe8 930 this->slot = slot;
af007ed6 931 this->keyid = identification_create_from_encoding(ID_KEY_ID, keyid);
5f1e4438 932
af007ed6 933 if (!login(this, slot))
a0bdd5d6 934 {
62be9236
MW
935 destroy(this);
936 return NULL;
5f1e4438
MW
937 }
938
9a704963
RG
939 if (ckaid.ptr)
940 {
941 DBG1(DBG_CFG, "using CKA_ID '%#B' for key with keyid '%#B'",
942 &ckaid, &keyid);
943 keyid = ckaid;
944 }
945
0b8b6640 946 if (!find_key(this, keyid))
5f1e4438 947 {
9a704963
RG
948 DBG1(DBG_CFG, "did not find the key with %s '%#B'",
949 ckaid.ptr ? "CKA_ID" : "keyid", &keyid);
5f1e4438
MW
950 destroy(this);
951 return NULL;
952 }
5f1e4438 953
ffe42fa4 954 this->pubkey = pkcs11_public_key_connect(this->lib, slot, this->type, keyid);
5d2fccf4
TB
955 if (!this->pubkey)
956 {
ffe42fa4
MW
957 this->pubkey = find_pubkey_in_certs(this, keyid);
958 if (!this->pubkey)
959 {
960 DBG1(DBG_CFG, "no public key or certificate found for private key "
9a704963
RG
961 "(%s '%#B') on '%s':%d", ckaid.ptr ? "CKA_ID" : "keyid",
962 &keyid, module, slot);
ffe42fa4
MW
963 destroy(this);
964 return NULL;
965 }
5d2fccf4 966 }
5f1e4438
MW
967 return &this->public;
968}