0be7b0509114fd584b4cba30284eadb0d42a11d9
[strongswan.git] / src / libstrongswan / plugins / pkcs11 / pkcs11_public_key.c
1 /*
2 * Copyright (C) 2011 Tobias Brunner
3 * 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 #include "pkcs11_public_key.h"
20
21 #include "pkcs11.h"
22 #include "pkcs11_private_key.h"
23 #include "pkcs11_manager.h"
24
25 #include <asn1/oid.h>
26 #include <asn1/asn1.h>
27 #include <asn1/asn1_parser.h>
28 #include <debug.h>
29
30 typedef struct private_pkcs11_public_key_t private_pkcs11_public_key_t;
31
32 /**
33 * Private data of an pkcs11_public_key_t object.
34 */
35 struct private_pkcs11_public_key_t {
36
37 /**
38 * Public pkcs11_public_key_t interface.
39 */
40 pkcs11_public_key_t public;
41
42 /**
43 * Type of the key
44 */
45 key_type_t type;
46
47 /**
48 * Key size in bits
49 */
50 size_t k;
51
52 /**
53 * PKCS#11 library this key uses
54 */
55 pkcs11_library_t *lib;
56
57 /**
58 * Slot the token is in
59 */
60 CK_SLOT_ID slot;
61
62 /**
63 * Session we use
64 */
65 CK_SESSION_HANDLE session;
66
67 /**
68 * Object handle to the key
69 */
70 CK_OBJECT_HANDLE object;
71
72 /**
73 * References to this key
74 */
75 refcount_t ref;
76 };
77
78 /**
79 * Helper function that returns the base point order length in bits of the
80 * given named curve.
81 *
82 * Currently only a subset of defined curves is supported (namely the 5 curves
83 * over Fp recommended by NIST). IKEv2 only supports 3 out of these.
84 *
85 * 0 is returned if the given curve is not supported.
86 */
87 static size_t basepoint_order_len(int oid)
88 {
89 switch (oid)
90 {
91 case OID_PRIME192V1:
92 return 192;
93 case OID_SECT224R1:
94 return 224;
95 case OID_PRIME256V1:
96 return 256;
97 case OID_SECT384R1:
98 return 384;
99 case OID_SECT521R1:
100 return 521;
101 default:
102 return 0;
103 }
104 }
105
106 /**
107 * Parses the given ecParameters (ASN.1) and returns the key length.
108 */
109 static bool keylen_from_ecparams(chunk_t ecparams, size_t *keylen)
110 {
111 if (!asn1_parse_simple_object(&ecparams, ASN1_OID, 0, "named curve"))
112 {
113 return FALSE;
114 }
115 *keylen = basepoint_order_len(asn1_known_oid(ecparams));
116 return *keylen > 0;
117 }
118
119 /**
120 * ASN.1 definition of a subjectPublicKeyInfo structure when used with ECDSA
121 * we currently only support named curves.
122 */
123 static const asn1Object_t pkinfoObjects[] = {
124 { 0, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
125 { 1, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
126 { 2, "algorithm", ASN1_OID, ASN1_BODY }, /* 2 */
127 { 2, "namedCurve", ASN1_OID, ASN1_RAW }, /* 3 */
128 { 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_BODY }, /* 4 */
129 { 0, "exit", ASN1_EOC, ASN1_EXIT }
130 };
131 #define PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM 2
132 #define PKINFO_SUBJECT_PUBLIC_KEY_NAMEDCURVE 3
133 #define PKINFO_SUBJECT_PUBLIC_KEY 4
134
135 /**
136 * Extract the DER encoded Parameters and ECPoint from the given DER encoded
137 * subjectPublicKeyInfo.
138 */
139 static bool parse_ecdsa_public_key(chunk_t blob, chunk_t *ecparams,
140 chunk_t *ecpoint, size_t *keylen)
141 {
142 asn1_parser_t *parser;
143 chunk_t object;
144 int objectID;
145 bool success = FALSE;
146
147 parser = asn1_parser_create(pkinfoObjects, blob);
148
149 while (parser->iterate(parser, &objectID, &object))
150 {
151 switch (objectID)
152 {
153 case PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM:
154 {
155 if (asn1_known_oid(object) != OID_EC_PUBLICKEY)
156 {
157 goto end;
158 }
159 break;
160 }
161 case PKINFO_SUBJECT_PUBLIC_KEY_NAMEDCURVE:
162 {
163 *ecparams = object;
164 if (!keylen_from_ecparams(object, keylen))
165 {
166 goto end;
167 }
168 break;
169 }
170 case PKINFO_SUBJECT_PUBLIC_KEY:
171 {
172 if (object.len > 0 && *object.ptr == 0x00)
173 { /* skip initial bit string octet defining 0 unused bits */
174 object = chunk_skip(object, 1);
175 }
176 *ecpoint = object;
177 break;
178 }
179 }
180 }
181 success = parser->success(parser);
182 end:
183 parser->destroy(parser);
184 return success;
185 }
186
187
188 METHOD(public_key_t, get_type, key_type_t,
189 private_pkcs11_public_key_t *this)
190 {
191 return this->type;
192 }
193
194 METHOD(public_key_t, get_keysize, int,
195 private_pkcs11_public_key_t *this)
196 {
197 return this->k;
198 }
199
200 METHOD(public_key_t, verify, bool,
201 private_pkcs11_public_key_t *this, signature_scheme_t scheme,
202 chunk_t data, chunk_t sig)
203 {
204 CK_MECHANISM_PTR mechanism;
205 CK_SESSION_HANDLE session;
206 CK_RV rv;
207
208 mechanism = pkcs11_signature_scheme_to_mech(scheme);
209 if (!mechanism)
210 {
211 DBG1(DBG_LIB, "signature scheme %N not supported",
212 signature_scheme_names, scheme);
213 return FALSE;
214 }
215 if (sig.len && sig.ptr[0] == 0)
216 { /* trim leading zero byte in sig */
217 sig = chunk_skip(sig, 1);
218 }
219 rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
220 &session);
221 if (rv != CKR_OK)
222 {
223 DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
224 return FALSE;
225 }
226 rv = this->lib->f->C_VerifyInit(session, mechanism, this->object);
227 if (rv != CKR_OK)
228 {
229 this->lib->f->C_CloseSession(session);
230 DBG1(DBG_LIB, "C_VerifyInit() failed: %N", ck_rv_names, rv);
231 return FALSE;
232 }
233 rv = this->lib->f->C_Verify(session, data.ptr, data.len, sig.ptr, sig.len);
234 this->lib->f->C_CloseSession(session);
235 if (rv != CKR_OK)
236 {
237 DBG1(DBG_LIB, "C_Verify() failed: %N", ck_rv_names, rv);
238 return FALSE;
239 }
240 return TRUE;
241 }
242
243 METHOD(public_key_t, encrypt, bool,
244 private_pkcs11_public_key_t *this, encryption_scheme_t scheme,
245 chunk_t plain, chunk_t *crypt)
246 {
247 CK_MECHANISM_PTR mechanism;
248 CK_SESSION_HANDLE session;
249 CK_BYTE_PTR buf;
250 CK_ULONG len;
251 CK_RV rv;
252
253 mechanism = pkcs11_encryption_scheme_to_mech(scheme);
254 if (!mechanism)
255 {
256 DBG1(DBG_LIB, "encryption scheme %N not supported",
257 encryption_scheme_names, scheme);
258 return FALSE;
259 }
260 rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
261 &session);
262 if (rv != CKR_OK)
263 {
264 DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
265 return FALSE;
266 }
267 rv = this->lib->f->C_EncryptInit(session, mechanism, this->object);
268 if (rv != CKR_OK)
269 {
270 this->lib->f->C_CloseSession(session);
271 DBG1(DBG_LIB, "C_EncryptInit() failed: %N", ck_rv_names, rv);
272 return FALSE;
273 }
274 len = (get_keysize(this) + 7) / 8;
275 buf = malloc(len);
276 rv = this->lib->f->C_Encrypt(session, plain.ptr, plain.len, buf, &len);
277 this->lib->f->C_CloseSession(session);
278 if (rv != CKR_OK)
279 {
280 DBG1(DBG_LIB, "C_Encrypt() failed: %N", ck_rv_names, rv);
281 free(buf);
282 return FALSE;
283 }
284 *crypt = chunk_create(buf, len);
285 return TRUE;
286 }
287
288 /**
289 * Encode ECDSA key using a given encoding type
290 */
291 static bool encode_ecdsa(private_pkcs11_public_key_t *this,
292 cred_encoding_type_t type, chunk_t *encoding)
293 {
294 enumerator_t *enumerator;
295 bool success = FALSE;
296 CK_ATTRIBUTE attr[] = {
297 {CKA_EC_PARAMS, NULL, 0},
298 {CKA_EC_POINT, NULL, 0},
299 };
300
301 if (type != PUBKEY_SPKI_ASN1_DER && type != PUBKEY_PEM)
302 {
303 return FALSE;
304 }
305
306 enumerator = this->lib->create_object_attr_enumerator(this->lib,
307 this->session, this->object, attr, countof(attr));
308 if (enumerator && enumerator->enumerate(enumerator, NULL) &&
309 attr[0].ulValueLen > 0 && attr[1].ulValueLen > 0)
310 {
311 chunk_t ecparams, ecpoint;
312 ecparams = chunk_create(attr[0].pValue, attr[0].ulValueLen);
313 ecpoint = chunk_create(attr[1].pValue, attr[1].ulValueLen);
314 /* encode as subjectPublicKeyInfo */
315 *encoding = asn1_wrap(ASN1_SEQUENCE, "mm",
316 asn1_wrap(ASN1_SEQUENCE, "mc",
317 asn1_build_known_oid(OID_EC_PUBLICKEY), ecparams),
318 asn1_bitstring("c", ecpoint));
319 success = TRUE;
320 if (type == PUBKEY_PEM)
321 {
322 chunk_t asn1 = *encoding;
323 success = lib->encoding->encode(lib->encoding, PUBKEY_PEM,
324 NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
325 asn1, CRED_PART_END);
326 chunk_clear(&asn1);
327 }
328 }
329 DESTROY_IF(enumerator);
330 return success;
331 }
332
333 /**
334 * Compute fingerprint of an ECDSA key
335 */
336 static bool fingerprint_ecdsa(private_pkcs11_public_key_t *this,
337 cred_encoding_type_t type, chunk_t *fp)
338 {
339 hasher_t *hasher;
340 chunk_t asn1;
341
342 switch (type)
343 {
344 case KEYID_PUBKEY_SHA1:
345 if (!this->lib->get_ck_attribute(this->lib, this->session,
346 this->object, CKA_EC_POINT, &asn1))
347 {
348 return FALSE;
349 }
350 break;
351 case KEYID_PUBKEY_INFO_SHA1:
352 if (!encode_ecdsa(this, PUBKEY_SPKI_ASN1_DER, &asn1))
353 {
354 return FALSE;
355 }
356 break;
357 default:
358 return FALSE;
359 }
360 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
361 if (!hasher)
362 {
363 chunk_clear(&asn1);
364 return FALSE;
365 }
366 hasher->allocate_hash(hasher, asn1, fp);
367 hasher->destroy(hasher);
368 chunk_clear(&asn1);
369 lib->encoding->cache(lib->encoding, type, this, *fp);
370 return TRUE;
371 }
372
373 /**
374 * Encode RSA key using a given encoding type
375 */
376 static bool encode_rsa(private_pkcs11_public_key_t *this,
377 cred_encoding_type_t type, void *cache, chunk_t *encoding)
378 {
379 enumerator_t *enumerator;
380 bool success = FALSE;
381 CK_ATTRIBUTE attr[] = {
382 {CKA_MODULUS, NULL, 0},
383 {CKA_PUBLIC_EXPONENT, NULL, 0},
384 };
385
386 enumerator = this->lib->create_object_attr_enumerator(this->lib,
387 this->session, this->object, attr, countof(attr));
388 if (enumerator && enumerator->enumerate(enumerator, NULL) &&
389 attr[0].ulValueLen > 0 && attr[1].ulValueLen > 0)
390 {
391 chunk_t n, e;
392 n = chunk_create(attr[0].pValue, attr[0].ulValueLen);
393 if (n.ptr[0] & 0x80)
394 { /* add leading 0x00, encoders expect it already like this */
395 n = chunk_cata("cc", chunk_from_chars(0x00), n);
396 }
397 e = chunk_create(attr[1].pValue, attr[1].ulValueLen);
398 success = lib->encoding->encode(lib->encoding, type, cache, encoding,
399 CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
400 }
401 DESTROY_IF(enumerator);
402 return success;
403 }
404
405 METHOD(public_key_t, get_encoding, bool,
406 private_pkcs11_public_key_t *this, cred_encoding_type_t type,
407 chunk_t *encoding)
408 {
409 switch (this->type)
410 {
411 case KEY_RSA:
412 return encode_rsa(this, type, NULL, encoding);
413 case KEY_ECDSA:
414 return encode_ecdsa(this, type, encoding);
415 default:
416 return FALSE;
417 }
418 }
419
420 METHOD(public_key_t, get_fingerprint, bool,
421 private_pkcs11_public_key_t *this, cred_encoding_type_t type, chunk_t *fp)
422 {
423 if (lib->encoding->get_cache(lib->encoding, type, this, fp))
424 {
425 return TRUE;
426 }
427 switch (this->type)
428 {
429 case KEY_RSA:
430 return encode_rsa(this, type, this, fp);
431 case KEY_ECDSA:
432 return fingerprint_ecdsa(this, type, fp);
433 default:
434 return FALSE;
435 }
436 }
437
438 METHOD(public_key_t, get_ref, public_key_t*,
439 private_pkcs11_public_key_t *this)
440 {
441 ref_get(&this->ref);
442 return &this->public.key;
443 }
444
445 METHOD(public_key_t, destroy, void,
446 private_pkcs11_public_key_t *this)
447 {
448 if (ref_put(&this->ref))
449 {
450 lib->encoding->clear_cache(lib->encoding, this);
451 this->lib->f->C_CloseSession(this->session);
452 free(this);
453 }
454 }
455
456 /**
457 * Create an empty PKCS#11 public key
458 */
459 static private_pkcs11_public_key_t *create(key_type_t type, size_t k,
460 pkcs11_library_t *p11, CK_SLOT_ID slot,
461 CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object)
462 {
463 private_pkcs11_public_key_t *this;
464
465 INIT(this,
466 .public = {
467 .key = {
468 .get_type = _get_type,
469 .verify = _verify,
470 .encrypt = _encrypt,
471 .equals = public_key_equals,
472 .get_keysize = _get_keysize,
473 .get_fingerprint = _get_fingerprint,
474 .has_fingerprint = public_key_has_fingerprint,
475 .get_encoding = _get_encoding,
476 .get_ref = _get_ref,
477 .destroy = _destroy,
478 },
479 },
480 .type = type,
481 .k = k,
482 .lib = p11,
483 .slot = slot,
484 .session = session,
485 .object = object,
486 .ref = 1,
487 );
488
489 return this;
490 }
491
492 /**
493 * Find a key object, including PKCS11 library and slot
494 */
495 static private_pkcs11_public_key_t* find_key(key_type_t type, size_t keylen,
496 CK_ATTRIBUTE_PTR tmpl, int count)
497 {
498 private_pkcs11_public_key_t *this = NULL;
499 pkcs11_manager_t *manager;
500 enumerator_t *enumerator, *keys;
501 pkcs11_library_t *p11;
502 CK_SLOT_ID slot;
503
504 manager = lib->get(lib, "pkcs11-manager");
505 if (!manager)
506 {
507 return NULL;
508 }
509
510 enumerator = manager->create_token_enumerator(manager);
511 while (enumerator->enumerate(enumerator, &p11, &slot))
512 {
513 CK_OBJECT_HANDLE object;
514 CK_SESSION_HANDLE session;
515 CK_RV rv;
516
517 rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL,
518 &session);
519 if (rv != CKR_OK)
520 {
521 DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
522 continue;
523 }
524 keys = p11->create_object_enumerator(p11, session, tmpl, count,
525 NULL, 0);
526 if (keys->enumerate(keys, &object))
527 {
528 this = create(type, keylen, p11, slot, session, object);
529 keys->destroy(keys);
530 break;
531 }
532 keys->destroy(keys);
533 p11->f->C_CloseSession(session);
534 }
535 enumerator->destroy(enumerator);
536 return this;
537 }
538
539 /**
540 * Find an RSA key object
541 */
542 static private_pkcs11_public_key_t* find_rsa_key(chunk_t n, chunk_t e,
543 size_t keylen)
544 {
545 CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
546 CK_KEY_TYPE type = CKK_RSA;
547 CK_ATTRIBUTE tmpl[] = {
548 {CKA_CLASS, &class, sizeof(class)},
549 {CKA_KEY_TYPE, &type, sizeof(type)},
550 {CKA_MODULUS, n.ptr, n.len},
551 {CKA_PUBLIC_EXPONENT, e.ptr, e.len},
552 };
553 return find_key(KEY_RSA, keylen, tmpl, countof(tmpl));
554 }
555
556 /**
557 * Find an ECDSA key object
558 */
559 static private_pkcs11_public_key_t* find_ecdsa_key(chunk_t ecparams,
560 chunk_t ecpoint,
561 size_t keylen)
562 {
563 CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
564 CK_KEY_TYPE type = CKK_ECDSA;
565 CK_ATTRIBUTE tmpl[] = {
566 {CKA_CLASS, &class, sizeof(class)},
567 {CKA_KEY_TYPE, &type, sizeof(type)},
568 {CKA_EC_PARAMS, ecparams.ptr, ecparams.len},
569 {CKA_EC_POINT, ecpoint.ptr, ecpoint.len},
570 };
571 return find_key(KEY_ECDSA, keylen, tmpl, countof(tmpl));
572 }
573
574 /**
575 * Create a key object in a suitable token session
576 */
577 static private_pkcs11_public_key_t* create_key(key_type_t type, size_t keylen,
578 CK_MECHANISM_TYPE_PTR mechanisms, int mcount,
579 CK_ATTRIBUTE_PTR tmpl, int count)
580 {
581 private_pkcs11_public_key_t *this = NULL;
582 pkcs11_manager_t *manager;
583 enumerator_t *enumerator, *mechs;
584 pkcs11_library_t *p11;
585 CK_SLOT_ID slot;
586
587 manager = lib->get(lib, "pkcs11-manager");
588 if (!manager)
589 {
590 return NULL;
591 }
592
593 enumerator = manager->create_token_enumerator(manager);
594 while (enumerator->enumerate(enumerator, &p11, &slot))
595 {
596 CK_MECHANISM_TYPE mech;
597 CK_MECHANISM_INFO info;
598 CK_OBJECT_HANDLE object;
599 CK_SESSION_HANDLE session;
600 CK_RV rv;
601
602 mechs = p11->create_mechanism_enumerator(p11, slot);
603 while (mechs->enumerate(mechs, &mech, &info))
604 {
605 bool found = FALSE;
606 int i;
607 if (!(info.flags & CKF_VERIFY))
608 {
609 continue;
610 }
611 for (i = 0; i < mcount; i++)
612 {
613 if (mechanisms[i] == mech)
614 {
615 found = TRUE;
616 break;
617 }
618 }
619 if (!found)
620 {
621 continue;
622 }
623 rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL,
624 &session);
625 if (rv != CKR_OK)
626 {
627 DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
628 ck_rv_names, rv);
629 continue;
630 }
631 rv = p11->f->C_CreateObject(session, tmpl, count, &object);
632 if (rv == CKR_OK)
633 {
634 this = create(type, keylen, p11, slot, session, object);
635 DBG2(DBG_CFG, "created %N public key on token '%s':%d ",
636 key_type_names, type, p11->get_name(p11), slot);
637 }
638 else
639 {
640 DBG1(DBG_CFG, "creating %N public key on token '%s':%d "
641 "failed: %N", key_type_names, type, p11->get_name(p11),
642 slot, ck_rv_names, rv);
643 p11->f->C_CloseSession(session);
644 }
645 break;
646 }
647 mechs->destroy(mechs);
648 if (this)
649 {
650 break;
651 }
652 }
653 enumerator->destroy(enumerator);
654 return this;
655 }
656
657 /**
658 * Create an RSA key object in a suitable token session
659 */
660 static private_pkcs11_public_key_t* create_rsa_key(chunk_t n, chunk_t e,
661 size_t keylen)
662 {
663 CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
664 CK_KEY_TYPE type = CKK_RSA;
665 CK_ATTRIBUTE tmpl[] = {
666 {CKA_CLASS, &class, sizeof(class)},
667 {CKA_KEY_TYPE, &type, sizeof(type)},
668 {CKA_MODULUS, n.ptr, n.len},
669 {CKA_PUBLIC_EXPONENT, e.ptr, e.len},
670 };
671 CK_MECHANISM_TYPE mechs[] = {
672 CKM_RSA_PKCS,
673 CKM_SHA1_RSA_PKCS,
674 CKM_SHA256_RSA_PKCS,
675 CKM_SHA384_RSA_PKCS,
676 CKM_SHA512_RSA_PKCS,
677 CKM_MD5_RSA_PKCS,
678 };
679 return create_key(KEY_RSA, keylen, mechs, countof(mechs), tmpl,
680 countof(tmpl));
681 }
682
683 /**
684 * Create an ECDSA key object in a suitable token session
685 */
686 static private_pkcs11_public_key_t* create_ecdsa_key(chunk_t ecparams,
687 chunk_t ecpoint,
688 size_t keylen)
689 {
690 CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
691 CK_KEY_TYPE type = CKK_ECDSA;
692 CK_ATTRIBUTE tmpl[] = {
693 {CKA_CLASS, &class, sizeof(class)},
694 {CKA_KEY_TYPE, &type, sizeof(type)},
695 {CKA_EC_PARAMS, ecparams.ptr, ecparams.len},
696 {CKA_EC_POINT, ecpoint.ptr, ecpoint.len},
697 };
698 CK_MECHANISM_TYPE mechs[] = {
699 CKM_ECDSA,
700 CKM_ECDSA_SHA1,
701 };
702 return create_key(KEY_ECDSA, keylen, mechs,
703 countof(mechs), tmpl, countof(tmpl));
704 }
705
706 /**
707 * See header
708 */
709 pkcs11_public_key_t *pkcs11_public_key_load(key_type_t type, va_list args)
710 {
711 private_pkcs11_public_key_t *this;
712 chunk_t n, e, blob;
713 size_t keylen;
714
715 n = e = blob = chunk_empty;
716 while (TRUE)
717 {
718 switch (va_arg(args, builder_part_t))
719 {
720 case BUILD_BLOB_ASN1_DER:
721 blob = va_arg(args, chunk_t);
722 continue;
723 case BUILD_RSA_MODULUS:
724 n = va_arg(args, chunk_t);
725 continue;
726 case BUILD_RSA_PUB_EXP:
727 e = va_arg(args, chunk_t);
728 continue;
729 case BUILD_END:
730 break;
731 default:
732 return NULL;
733 }
734 break;
735 }
736 if (type == KEY_RSA && e.ptr && n.ptr)
737 {
738 if (n.len && n.ptr[0] == 0)
739 { /* trim leading zero byte in modulus */
740 n = chunk_skip(n, 1);
741 }
742 keylen = n.len * 8;
743 this = find_rsa_key(n, e, keylen);
744 if (this)
745 {
746 return &this->public;
747 }
748 this = create_rsa_key(n, e, keylen);
749 if (this)
750 {
751 return &this->public;
752 }
753 }
754 else if (type == KEY_ECDSA && blob.ptr)
755 {
756 chunk_t ecparams, ecpoint;
757 ecparams = ecpoint = chunk_empty;
758 if (parse_ecdsa_public_key(blob, &ecparams, &ecpoint, &keylen))
759 {
760 this = find_ecdsa_key(ecparams, ecpoint, keylen);
761 if (this)
762 {
763 return &this->public;
764 }
765 this = create_ecdsa_key(ecparams, ecpoint, keylen);
766 if (this)
767 {
768 return &this->public;
769 }
770 }
771 }
772 return NULL;
773 }
774
775 static private_pkcs11_public_key_t *find_key_by_keyid(pkcs11_library_t *p11,
776 int slot, key_type_t key_type,
777 chunk_t keyid)
778 {
779 CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
780 CK_KEY_TYPE type;
781 CK_ATTRIBUTE tmpl[] = {
782 {CKA_CLASS, &class, sizeof(class)},
783 {CKA_ID, keyid.ptr, keyid.len},
784 {CKA_KEY_TYPE, &type, sizeof(type)},
785 };
786 CK_OBJECT_HANDLE object;
787 CK_ATTRIBUTE attr[] = {
788 {CKA_KEY_TYPE, &type, sizeof(type)},
789 };
790 CK_SESSION_HANDLE session;
791 CK_RV rv;
792 enumerator_t *enumerator;
793 int count = countof(tmpl);
794 bool found = FALSE;
795 size_t keylen;
796
797 switch (type)
798 {
799 case KEY_RSA:
800 type = CKK_RSA;
801 break;
802 case KEY_ECDSA:
803 type = CKK_ECDSA;
804 break;
805 default:
806 /* don't specify key type on KEY_ANY */
807 count--;
808 break;
809 }
810
811 rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, &session);
812 if (rv != CKR_OK)
813 {
814 DBG1(DBG_CFG, "opening public key session on '%s':%d failed: %N",
815 p11->get_name(p11), slot, ck_rv_names, rv);
816 return NULL;
817 }
818
819 enumerator = p11->create_object_enumerator(p11, session, tmpl, count, attr,
820 countof(attr));
821 if (enumerator->enumerate(enumerator, &object))
822 {
823 switch (type)
824 {
825 case CKK_ECDSA:
826 {
827 chunk_t ecparams;
828 if (p11->get_ck_attribute(p11, session, object, CKA_EC_PARAMS,
829 &ecparams) &&
830 keylen_from_ecparams(ecparams, &keylen))
831 {
832 chunk_free(&ecparams);
833 key_type = KEY_ECDSA;
834 found = TRUE;
835 }
836 break;
837 }
838 case CKK_RSA:
839 {
840 chunk_t n;
841 if (p11->get_ck_attribute(p11, session, object, CKA_MODULUS,
842 &n) && n.len > 0)
843 {
844 keylen = n.len * 8;
845 chunk_free(&n);
846 key_type = KEY_RSA;
847 found = TRUE;
848 }
849 break;
850 }
851 default:
852 DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
853 break;
854 }
855 }
856 enumerator->destroy(enumerator);
857
858 if (found)
859 {
860 return create(key_type, keylen, p11, slot, session, object);
861 }
862 p11->f->C_CloseSession(session);
863 return NULL;
864 }
865
866 /**
867 * Find a public key on the given token with a specific keyid.
868 *
869 * Used by pkcs11_private_key_t.
870 *
871 * TODO: if no public key is found, we should perhaps search for a certificate
872 * with the given keyid and extract the key from there
873 *
874 * @param p11 PKCS#11 module
875 * @param slot slot id
876 * @param type type of the key
877 * @param keyid key id
878 */
879 pkcs11_public_key_t *pkcs11_public_key_connect(pkcs11_library_t *p11,
880 int slot, key_type_t type, chunk_t keyid)
881 {
882 private_pkcs11_public_key_t *this;
883
884 this = find_key_by_keyid(p11, slot, type, keyid);
885 if (!this)
886 {
887 return NULL;
888 }
889 return &this->public;
890 }