f0d7093dbd8459c3598ec42955c5102324388b91
[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 hash_algorithm_t hash_alg;
208 chunk_t hash = chunk_empty;
209
210 mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, this->k,
211 &hash_alg);
212 if (!mechanism)
213 {
214 DBG1(DBG_LIB, "signature scheme %N not supported",
215 signature_scheme_names, scheme);
216 return FALSE;
217 }
218 if (sig.len && sig.ptr[0] == 0)
219 { /* trim leading zero byte in sig */
220 sig = chunk_skip(sig, 1);
221 }
222 rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
223 &session);
224 if (rv != CKR_OK)
225 {
226 DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
227 return FALSE;
228 }
229 rv = this->lib->f->C_VerifyInit(session, mechanism, this->object);
230 if (rv != CKR_OK)
231 {
232 this->lib->f->C_CloseSession(session);
233 DBG1(DBG_LIB, "C_VerifyInit() failed: %N", ck_rv_names, rv);
234 return FALSE;
235 }
236 if (hash_alg != HASH_UNKNOWN)
237 {
238 hasher_t *hasher;
239
240 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
241 if (!hasher || !hasher->allocate_hash(hasher, data, &hash))
242 {
243 DESTROY_IF(hasher);
244 this->lib->f->C_CloseSession(session);
245 return FALSE;
246 }
247 hasher->destroy(hasher);
248 data = hash;
249 }
250 rv = this->lib->f->C_Verify(session, data.ptr, data.len, sig.ptr, sig.len);
251 this->lib->f->C_CloseSession(session);
252 chunk_free(&hash);
253 if (rv != CKR_OK)
254 {
255 DBG1(DBG_LIB, "C_Verify() failed: %N", ck_rv_names, rv);
256 return FALSE;
257 }
258 return TRUE;
259 }
260
261 METHOD(public_key_t, encrypt, bool,
262 private_pkcs11_public_key_t *this, encryption_scheme_t scheme,
263 chunk_t plain, chunk_t *crypt)
264 {
265 CK_MECHANISM_PTR mechanism;
266 CK_SESSION_HANDLE session;
267 CK_BYTE_PTR buf;
268 CK_ULONG len;
269 CK_RV rv;
270
271 mechanism = pkcs11_encryption_scheme_to_mech(scheme);
272 if (!mechanism)
273 {
274 DBG1(DBG_LIB, "encryption scheme %N not supported",
275 encryption_scheme_names, scheme);
276 return FALSE;
277 }
278 rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
279 &session);
280 if (rv != CKR_OK)
281 {
282 DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
283 return FALSE;
284 }
285 rv = this->lib->f->C_EncryptInit(session, mechanism, this->object);
286 if (rv != CKR_OK)
287 {
288 this->lib->f->C_CloseSession(session);
289 DBG1(DBG_LIB, "C_EncryptInit() failed: %N", ck_rv_names, rv);
290 return FALSE;
291 }
292 len = (get_keysize(this) + 7) / 8;
293 buf = malloc(len);
294 rv = this->lib->f->C_Encrypt(session, plain.ptr, plain.len, buf, &len);
295 this->lib->f->C_CloseSession(session);
296 if (rv != CKR_OK)
297 {
298 DBG1(DBG_LIB, "C_Encrypt() failed: %N", ck_rv_names, rv);
299 free(buf);
300 return FALSE;
301 }
302 *crypt = chunk_create(buf, len);
303 return TRUE;
304 }
305
306 /**
307 * Encode ECDSA key using a given encoding type
308 */
309 static bool encode_ecdsa(private_pkcs11_public_key_t *this,
310 cred_encoding_type_t type, chunk_t *encoding)
311 {
312 enumerator_t *enumerator;
313 bool success = FALSE;
314 CK_ATTRIBUTE attr[] = {
315 {CKA_EC_PARAMS, NULL, 0},
316 {CKA_EC_POINT, NULL, 0},
317 };
318
319 if (type != PUBKEY_SPKI_ASN1_DER && type != PUBKEY_PEM)
320 {
321 return FALSE;
322 }
323
324 enumerator = this->lib->create_object_attr_enumerator(this->lib,
325 this->session, this->object, attr, countof(attr));
326 if (enumerator && enumerator->enumerate(enumerator, NULL) &&
327 attr[0].ulValueLen > 0 && attr[1].ulValueLen > 0)
328 {
329 chunk_t ecparams, ecpoint;
330 ecparams = chunk_create(attr[0].pValue, attr[0].ulValueLen);
331 ecpoint = chunk_create(attr[1].pValue, attr[1].ulValueLen);
332 /* encode as subjectPublicKeyInfo */
333 *encoding = asn1_wrap(ASN1_SEQUENCE, "mm",
334 asn1_wrap(ASN1_SEQUENCE, "mc",
335 asn1_build_known_oid(OID_EC_PUBLICKEY), ecparams),
336 asn1_bitstring("c", ecpoint));
337 success = TRUE;
338 if (type == PUBKEY_PEM)
339 {
340 chunk_t asn1 = *encoding;
341 success = lib->encoding->encode(lib->encoding, PUBKEY_PEM,
342 NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
343 asn1, CRED_PART_END);
344 chunk_clear(&asn1);
345 }
346 }
347 DESTROY_IF(enumerator);
348 return success;
349 }
350
351 /**
352 * Compute fingerprint of an ECDSA key
353 */
354 static bool fingerprint_ecdsa(private_pkcs11_public_key_t *this,
355 cred_encoding_type_t type, chunk_t *fp)
356 {
357 hasher_t *hasher;
358 chunk_t asn1;
359
360 switch (type)
361 {
362 case KEYID_PUBKEY_SHA1:
363 if (!this->lib->get_ck_attribute(this->lib, this->session,
364 this->object, CKA_EC_POINT, &asn1))
365 {
366 return FALSE;
367 }
368 break;
369 case KEYID_PUBKEY_INFO_SHA1:
370 if (!encode_ecdsa(this, PUBKEY_SPKI_ASN1_DER, &asn1))
371 {
372 return FALSE;
373 }
374 break;
375 default:
376 return FALSE;
377 }
378 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
379 if (!hasher || !hasher->allocate_hash(hasher, asn1, fp))
380 {
381 DESTROY_IF(hasher);
382 chunk_clear(&asn1);
383 return FALSE;
384 }
385 hasher->destroy(hasher);
386 chunk_clear(&asn1);
387 lib->encoding->cache(lib->encoding, type, this, *fp);
388 return TRUE;
389 }
390
391 /**
392 * Encode RSA key using a given encoding type
393 */
394 static bool encode_rsa(private_pkcs11_public_key_t *this,
395 cred_encoding_type_t type, void *cache, chunk_t *encoding)
396 {
397 enumerator_t *enumerator;
398 bool success = FALSE;
399 CK_ATTRIBUTE attr[] = {
400 {CKA_MODULUS, NULL, 0},
401 {CKA_PUBLIC_EXPONENT, NULL, 0},
402 };
403
404 enumerator = this->lib->create_object_attr_enumerator(this->lib,
405 this->session, this->object, attr, countof(attr));
406 if (enumerator && enumerator->enumerate(enumerator, NULL) &&
407 attr[0].ulValueLen > 0 && attr[1].ulValueLen > 0)
408 {
409 chunk_t n, e;
410 n = chunk_create(attr[0].pValue, attr[0].ulValueLen);
411 if (n.ptr[0] & 0x80)
412 { /* add leading 0x00, encoders expect it already like this */
413 n = chunk_cata("cc", chunk_from_chars(0x00), n);
414 }
415 e = chunk_create(attr[1].pValue, attr[1].ulValueLen);
416 success = lib->encoding->encode(lib->encoding, type, cache, encoding,
417 CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
418 }
419 DESTROY_IF(enumerator);
420 return success;
421 }
422
423 METHOD(public_key_t, get_encoding, bool,
424 private_pkcs11_public_key_t *this, cred_encoding_type_t type,
425 chunk_t *encoding)
426 {
427 switch (this->type)
428 {
429 case KEY_RSA:
430 return encode_rsa(this, type, NULL, encoding);
431 case KEY_ECDSA:
432 return encode_ecdsa(this, type, encoding);
433 default:
434 return FALSE;
435 }
436 }
437
438 METHOD(public_key_t, get_fingerprint, bool,
439 private_pkcs11_public_key_t *this, cred_encoding_type_t type, chunk_t *fp)
440 {
441 if (lib->encoding->get_cache(lib->encoding, type, this, fp))
442 {
443 return TRUE;
444 }
445 switch (this->type)
446 {
447 case KEY_RSA:
448 return encode_rsa(this, type, this, fp);
449 case KEY_ECDSA:
450 return fingerprint_ecdsa(this, type, fp);
451 default:
452 return FALSE;
453 }
454 }
455
456 METHOD(public_key_t, get_ref, public_key_t*,
457 private_pkcs11_public_key_t *this)
458 {
459 ref_get(&this->ref);
460 return &this->public.key;
461 }
462
463 METHOD(public_key_t, destroy, void,
464 private_pkcs11_public_key_t *this)
465 {
466 if (ref_put(&this->ref))
467 {
468 lib->encoding->clear_cache(lib->encoding, this);
469 this->lib->f->C_CloseSession(this->session);
470 free(this);
471 }
472 }
473
474 /**
475 * Create an empty PKCS#11 public key
476 */
477 static private_pkcs11_public_key_t *create(key_type_t type, size_t k,
478 pkcs11_library_t *p11, CK_SLOT_ID slot,
479 CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object)
480 {
481 private_pkcs11_public_key_t *this;
482
483 INIT(this,
484 .public = {
485 .key = {
486 .get_type = _get_type,
487 .verify = _verify,
488 .encrypt = _encrypt,
489 .equals = public_key_equals,
490 .get_keysize = _get_keysize,
491 .get_fingerprint = _get_fingerprint,
492 .has_fingerprint = public_key_has_fingerprint,
493 .get_encoding = _get_encoding,
494 .get_ref = _get_ref,
495 .destroy = _destroy,
496 },
497 },
498 .type = type,
499 .k = k,
500 .lib = p11,
501 .slot = slot,
502 .session = session,
503 .object = object,
504 .ref = 1,
505 );
506
507 return this;
508 }
509
510 /**
511 * Find a key object, including PKCS11 library and slot
512 */
513 static private_pkcs11_public_key_t* find_key(key_type_t type, size_t keylen,
514 CK_ATTRIBUTE_PTR tmpl, int count)
515 {
516 private_pkcs11_public_key_t *this = NULL;
517 pkcs11_manager_t *manager;
518 enumerator_t *enumerator, *keys;
519 pkcs11_library_t *p11;
520 CK_SLOT_ID slot;
521
522 manager = lib->get(lib, "pkcs11-manager");
523 if (!manager)
524 {
525 return NULL;
526 }
527
528 enumerator = manager->create_token_enumerator(manager);
529 while (enumerator->enumerate(enumerator, &p11, &slot))
530 {
531 CK_OBJECT_HANDLE object;
532 CK_SESSION_HANDLE session;
533 CK_RV rv;
534
535 rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL,
536 &session);
537 if (rv != CKR_OK)
538 {
539 DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
540 continue;
541 }
542 keys = p11->create_object_enumerator(p11, session, tmpl, count,
543 NULL, 0);
544 if (keys->enumerate(keys, &object))
545 {
546 this = create(type, keylen, p11, slot, session, object);
547 keys->destroy(keys);
548 break;
549 }
550 keys->destroy(keys);
551 p11->f->C_CloseSession(session);
552 }
553 enumerator->destroy(enumerator);
554 return this;
555 }
556
557 /**
558 * Find an RSA key object
559 */
560 static private_pkcs11_public_key_t* find_rsa_key(chunk_t n, chunk_t e,
561 size_t keylen)
562 {
563 CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
564 CK_KEY_TYPE type = CKK_RSA;
565 CK_ATTRIBUTE tmpl[] = {
566 {CKA_CLASS, &class, sizeof(class)},
567 {CKA_KEY_TYPE, &type, sizeof(type)},
568 {CKA_MODULUS, n.ptr, n.len},
569 {CKA_PUBLIC_EXPONENT, e.ptr, e.len},
570 };
571 return find_key(KEY_RSA, keylen, tmpl, countof(tmpl));
572 }
573
574 /**
575 * Find an ECDSA key object
576 */
577 static private_pkcs11_public_key_t* find_ecdsa_key(chunk_t ecparams,
578 chunk_t ecpoint,
579 size_t keylen)
580 {
581 CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
582 CK_KEY_TYPE type = CKK_ECDSA;
583 CK_ATTRIBUTE tmpl[] = {
584 {CKA_CLASS, &class, sizeof(class)},
585 {CKA_KEY_TYPE, &type, sizeof(type)},
586 {CKA_EC_PARAMS, ecparams.ptr, ecparams.len},
587 {CKA_EC_POINT, ecpoint.ptr, ecpoint.len},
588 };
589 return find_key(KEY_ECDSA, keylen, tmpl, countof(tmpl));
590 }
591
592 /**
593 * Create a key object in a suitable token session
594 */
595 static private_pkcs11_public_key_t* create_key(key_type_t type, size_t keylen,
596 CK_MECHANISM_TYPE_PTR mechanisms, int mcount,
597 CK_ATTRIBUTE_PTR tmpl, int count)
598 {
599 private_pkcs11_public_key_t *this = NULL;
600 pkcs11_manager_t *manager;
601 enumerator_t *enumerator, *mechs;
602 pkcs11_library_t *p11;
603 CK_SLOT_ID slot;
604
605 manager = lib->get(lib, "pkcs11-manager");
606 if (!manager)
607 {
608 return NULL;
609 }
610
611 enumerator = manager->create_token_enumerator(manager);
612 while (enumerator->enumerate(enumerator, &p11, &slot))
613 {
614 CK_MECHANISM_TYPE mech;
615 CK_MECHANISM_INFO info;
616 CK_OBJECT_HANDLE object;
617 CK_SESSION_HANDLE session;
618 CK_RV rv;
619
620 mechs = p11->create_mechanism_enumerator(p11, slot);
621 while (mechs->enumerate(mechs, &mech, &info))
622 {
623 bool found = FALSE;
624 int i;
625 if (!(info.flags & CKF_VERIFY))
626 {
627 continue;
628 }
629 for (i = 0; i < mcount; i++)
630 {
631 if (mechanisms[i] == mech)
632 {
633 found = TRUE;
634 break;
635 }
636 }
637 if (!found)
638 {
639 continue;
640 }
641 rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL,
642 &session);
643 if (rv != CKR_OK)
644 {
645 DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
646 ck_rv_names, rv);
647 continue;
648 }
649 rv = p11->f->C_CreateObject(session, tmpl, count, &object);
650 if (rv == CKR_OK)
651 {
652 this = create(type, keylen, p11, slot, session, object);
653 DBG2(DBG_CFG, "created %N public key on token '%s':%d ",
654 key_type_names, type, p11->get_name(p11), slot);
655 }
656 else
657 {
658 DBG1(DBG_CFG, "creating %N public key on token '%s':%d "
659 "failed: %N", key_type_names, type, p11->get_name(p11),
660 slot, ck_rv_names, rv);
661 p11->f->C_CloseSession(session);
662 }
663 break;
664 }
665 mechs->destroy(mechs);
666 if (this)
667 {
668 break;
669 }
670 }
671 enumerator->destroy(enumerator);
672 return this;
673 }
674
675 /**
676 * Create an RSA key object in a suitable token session
677 */
678 static private_pkcs11_public_key_t* create_rsa_key(chunk_t n, chunk_t e,
679 size_t keylen)
680 {
681 CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
682 CK_KEY_TYPE type = CKK_RSA;
683 CK_ATTRIBUTE tmpl[] = {
684 {CKA_CLASS, &class, sizeof(class)},
685 {CKA_KEY_TYPE, &type, sizeof(type)},
686 {CKA_MODULUS, n.ptr, n.len},
687 {CKA_PUBLIC_EXPONENT, e.ptr, e.len},
688 };
689 CK_MECHANISM_TYPE mechs[] = {
690 CKM_RSA_PKCS,
691 CKM_SHA1_RSA_PKCS,
692 CKM_SHA256_RSA_PKCS,
693 CKM_SHA384_RSA_PKCS,
694 CKM_SHA512_RSA_PKCS,
695 CKM_MD5_RSA_PKCS,
696 };
697 return create_key(KEY_RSA, keylen, mechs, countof(mechs), tmpl,
698 countof(tmpl));
699 }
700
701 /**
702 * Create an ECDSA key object in a suitable token session
703 */
704 static private_pkcs11_public_key_t* create_ecdsa_key(chunk_t ecparams,
705 chunk_t ecpoint,
706 size_t keylen)
707 {
708 CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
709 CK_KEY_TYPE type = CKK_ECDSA;
710 CK_ATTRIBUTE tmpl[] = {
711 {CKA_CLASS, &class, sizeof(class)},
712 {CKA_KEY_TYPE, &type, sizeof(type)},
713 {CKA_EC_PARAMS, ecparams.ptr, ecparams.len},
714 {CKA_EC_POINT, ecpoint.ptr, ecpoint.len},
715 };
716 CK_MECHANISM_TYPE mechs[] = {
717 CKM_ECDSA,
718 CKM_ECDSA_SHA1,
719 };
720 return create_key(KEY_ECDSA, keylen, mechs,
721 countof(mechs), tmpl, countof(tmpl));
722 }
723
724 /**
725 * See header
726 */
727 pkcs11_public_key_t *pkcs11_public_key_load(key_type_t type, va_list args)
728 {
729 private_pkcs11_public_key_t *this;
730 chunk_t n, e, blob;
731 size_t keylen = 0;
732
733 n = e = blob = chunk_empty;
734 while (TRUE)
735 {
736 switch (va_arg(args, builder_part_t))
737 {
738 case BUILD_BLOB_ASN1_DER:
739 blob = va_arg(args, chunk_t);
740 continue;
741 case BUILD_RSA_MODULUS:
742 n = va_arg(args, chunk_t);
743 continue;
744 case BUILD_RSA_PUB_EXP:
745 e = va_arg(args, chunk_t);
746 continue;
747 case BUILD_END:
748 break;
749 default:
750 return NULL;
751 }
752 break;
753 }
754 if (type == KEY_RSA && e.ptr && n.ptr)
755 {
756 if (n.len && n.ptr[0] == 0)
757 { /* trim leading zero byte in modulus */
758 n = chunk_skip(n, 1);
759 }
760 keylen = n.len * 8;
761 this = find_rsa_key(n, e, keylen);
762 if (this)
763 {
764 return &this->public;
765 }
766 this = create_rsa_key(n, e, keylen);
767 if (this)
768 {
769 return &this->public;
770 }
771 }
772 else if (type == KEY_ECDSA && blob.ptr)
773 {
774 chunk_t ecparams, ecpoint;
775 ecparams = ecpoint = chunk_empty;
776 if (parse_ecdsa_public_key(blob, &ecparams, &ecpoint, &keylen))
777 {
778 this = find_ecdsa_key(ecparams, ecpoint, keylen);
779 if (this)
780 {
781 return &this->public;
782 }
783 this = create_ecdsa_key(ecparams, ecpoint, keylen);
784 if (this)
785 {
786 return &this->public;
787 }
788 }
789 }
790 return NULL;
791 }
792
793 static private_pkcs11_public_key_t *find_key_by_keyid(pkcs11_library_t *p11,
794 int slot, key_type_t key_type,
795 chunk_t keyid)
796 {
797 CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
798 CK_KEY_TYPE type;
799 CK_ATTRIBUTE tmpl[] = {
800 {CKA_CLASS, &class, sizeof(class)},
801 {CKA_ID, keyid.ptr, keyid.len},
802 {CKA_KEY_TYPE, &type, sizeof(type)},
803 };
804 CK_OBJECT_HANDLE object;
805 CK_ATTRIBUTE attr[] = {
806 {CKA_KEY_TYPE, &type, sizeof(type)},
807 };
808 CK_SESSION_HANDLE session;
809 CK_RV rv;
810 enumerator_t *enumerator;
811 int count = countof(tmpl);
812 bool found = FALSE;
813 size_t keylen;
814
815 switch (key_type)
816 {
817 case KEY_RSA:
818 type = CKK_RSA;
819 break;
820 case KEY_ECDSA:
821 type = CKK_ECDSA;
822 break;
823 default:
824 /* don't specify key type on KEY_ANY */
825 count--;
826 break;
827 }
828
829 rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, &session);
830 if (rv != CKR_OK)
831 {
832 DBG1(DBG_CFG, "opening public key session on '%s':%d failed: %N",
833 p11->get_name(p11), slot, ck_rv_names, rv);
834 return NULL;
835 }
836
837 enumerator = p11->create_object_enumerator(p11, session, tmpl, count, attr,
838 countof(attr));
839 if (enumerator->enumerate(enumerator, &object))
840 {
841 switch (type)
842 {
843 case CKK_ECDSA:
844 {
845 chunk_t ecparams;
846 if (p11->get_ck_attribute(p11, session, object, CKA_EC_PARAMS,
847 &ecparams) &&
848 keylen_from_ecparams(ecparams, &keylen))
849 {
850 chunk_free(&ecparams);
851 key_type = KEY_ECDSA;
852 found = TRUE;
853 }
854 break;
855 }
856 case CKK_RSA:
857 {
858 chunk_t n;
859 if (p11->get_ck_attribute(p11, session, object, CKA_MODULUS,
860 &n) && n.len > 0)
861 {
862 keylen = n.len * 8;
863 chunk_free(&n);
864 key_type = KEY_RSA;
865 found = TRUE;
866 }
867 break;
868 }
869 default:
870 DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
871 break;
872 }
873 }
874 enumerator->destroy(enumerator);
875
876 if (found)
877 {
878 return create(key_type, keylen, p11, slot, session, object);
879 }
880 p11->f->C_CloseSession(session);
881 return NULL;
882 }
883
884 /**
885 * Find a public key on the given token with a specific keyid.
886 *
887 * Used by pkcs11_private_key_t.
888 *
889 * TODO: if no public key is found, we should perhaps search for a certificate
890 * with the given keyid and extract the key from there
891 *
892 * @param p11 PKCS#11 module
893 * @param slot slot id
894 * @param type type of the key
895 * @param keyid key id
896 */
897 pkcs11_public_key_t *pkcs11_public_key_connect(pkcs11_library_t *p11,
898 int slot, key_type_t type, chunk_t keyid)
899 {
900 private_pkcs11_public_key_t *this;
901
902 this = find_key_by_keyid(p11, slot, type, keyid);
903 if (!this)
904 {
905 return NULL;
906 }
907 return &this->public;
908 }