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