]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c
Add a return value to hasher_t.allocate_hash()
[thirdparty/strongswan.git] / src / libstrongswan / plugins / pkcs11 / pkcs11_public_key.c
CommitLineData
fed9407b 1/*
b0319fe8
TB
2 * Copyright (C) 2011 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
fed9407b
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 */
18
19#include "pkcs11_public_key.h"
20
21#include "pkcs11.h"
22#include "pkcs11_private_key.h"
23#include "pkcs11_manager.h"
24
36d1627f
TB
25#include <asn1/oid.h>
26#include <asn1/asn1.h>
27#include <asn1/asn1_parser.h>
fed9407b 28#include <debug.h>
fed9407b
MW
29
30typedef struct private_pkcs11_public_key_t private_pkcs11_public_key_t;
31
32/**
33 * Private data of an pkcs11_public_key_t object.
34 */
35struct 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 /**
a8084ee0 48 * Key size in bits
fed9407b
MW
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
fed9407b
MW
72 /**
73 * References to this key
74 */
75 refcount_t ref;
76};
77
36d1627f
TB
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 */
87static 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 */
109static 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 */
123static 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 */
139static 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);
182end:
183 parser->destroy(parser);
184 return success;
185}
186
187
fed9407b
MW
188METHOD(public_key_t, get_type, key_type_t,
189 private_pkcs11_public_key_t *this)
190{
191 return this->type;
192}
193
01e4f5f3
MW
194METHOD(public_key_t, get_keysize, int,
195 private_pkcs11_public_key_t *this)
196{
a8084ee0 197 return this->k;
01e4f5f3
MW
198}
199
fed9407b
MW
200METHOD(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;
b0319fe8 205 CK_SESSION_HANDLE session;
fed9407b 206 CK_RV rv;
fd48b220
TB
207 hash_algorithm_t hash_alg;
208 chunk_t hash = chunk_empty;
fed9407b 209
5b85b94e
TB
210 mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, this->k,
211 &hash_alg);
fed9407b
MW
212 if (!mechanism)
213 {
214 DBG1(DBG_LIB, "signature scheme %N not supported",
215 signature_scheme_names, scheme);
216 return FALSE;
217 }
7c03d707
MW
218 if (sig.len && sig.ptr[0] == 0)
219 { /* trim leading zero byte in sig */
220 sig = chunk_skip(sig, 1);
221 }
b0319fe8
TB
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);
fed9407b
MW
230 if (rv != CKR_OK)
231 {
b0319fe8 232 this->lib->f->C_CloseSession(session);
fed9407b
MW
233 DBG1(DBG_LIB, "C_VerifyInit() failed: %N", ck_rv_names, rv);
234 return FALSE;
235 }
fd48b220
TB
236 if (hash_alg != HASH_UNKNOWN)
237 {
87dd205b
MW
238 hasher_t *hasher;
239
240 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
241 if (!hasher || !hasher->allocate_hash(hasher, data, &hash))
fd48b220 242 {
87dd205b 243 DESTROY_IF(hasher);
fd48b220
TB
244 this->lib->f->C_CloseSession(session);
245 return FALSE;
246 }
fd48b220
TB
247 hasher->destroy(hasher);
248 data = hash;
249 }
b0319fe8
TB
250 rv = this->lib->f->C_Verify(session, data.ptr, data.len, sig.ptr, sig.len);
251 this->lib->f->C_CloseSession(session);
fd48b220 252 chunk_free(&hash);
fed9407b
MW
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
261METHOD(public_key_t, encrypt, bool,
33ddaaab 262 private_pkcs11_public_key_t *this, encryption_scheme_t scheme,
01e4f5f3 263 chunk_t plain, chunk_t *crypt)
fed9407b 264{
01e4f5f3 265 CK_MECHANISM_PTR mechanism;
b0319fe8 266 CK_SESSION_HANDLE session;
01e4f5f3
MW
267 CK_BYTE_PTR buf;
268 CK_ULONG len;
269 CK_RV rv;
fed9407b 270
01e4f5f3
MW
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 }
b0319fe8
TB
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);
01e4f5f3
MW
286 if (rv != CKR_OK)
287 {
b0319fe8 288 this->lib->f->C_CloseSession(session);
01e4f5f3
MW
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);
b0319fe8
TB
294 rv = this->lib->f->C_Encrypt(session, plain.ptr, plain.len, buf, &len);
295 this->lib->f->C_CloseSession(session);
01e4f5f3
MW
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;
fed9407b
MW
304}
305
9e3b1e14
TB
306/**
307 * Encode ECDSA key using a given encoding type
308 */
309static 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 */
354static 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);
87dd205b 379 if (!hasher || !hasher->allocate_hash(hasher, asn1, fp))
9e3b1e14 380 {
87dd205b 381 DESTROY_IF(hasher);
9e3b1e14
TB
382 chunk_clear(&asn1);
383 return FALSE;
384 }
9e3b1e14
TB
385 hasher->destroy(hasher);
386 chunk_clear(&asn1);
387 lib->encoding->cache(lib->encoding, type, this, *fp);
388 return TRUE;
389}
390
fed9407b
MW
391/**
392 * Encode RSA key using a given encoding type
393 */
394static bool encode_rsa(private_pkcs11_public_key_t *this,
395 cred_encoding_type_t type, void *cache, chunk_t *encoding)
396{
dae19d44 397 enumerator_t *enumerator;
fed9407b 398 bool success = FALSE;
fed9407b
MW
399 CK_ATTRIBUTE attr[] = {
400 {CKA_MODULUS, NULL, 0},
401 {CKA_PUBLIC_EXPONENT, NULL, 0},
402 };
403
dae19d44
TB
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)
fed9407b 408 {
dae19d44 409 chunk_t n, e;
fed9407b 410 n = chunk_create(attr[0].pValue, attr[0].ulValueLen);
8859c1f2
TB
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 }
fed9407b
MW
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 }
dae19d44 419 DESTROY_IF(enumerator);
fed9407b
MW
420 return success;
421}
422
423METHOD(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);
9e3b1e14
TB
431 case KEY_ECDSA:
432 return encode_ecdsa(this, type, encoding);
fed9407b
MW
433 default:
434 return FALSE;
435 }
436}
437
438METHOD(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);
9e3b1e14
TB
449 case KEY_ECDSA:
450 return fingerprint_ecdsa(this, type, fp);
fed9407b
MW
451 default:
452 return FALSE;
453 }
454}
455
456METHOD(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
463METHOD(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);
fed9407b
MW
470 free(this);
471 }
472}
473
474/**
475 * Create an empty PKCS#11 public key
476 */
477static 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,
57426116 499 .k = k,
fed9407b
MW
500 .lib = p11,
501 .slot = slot,
502 .session = session,
503 .object = object,
7c03d707 504 .ref = 1,
fed9407b
MW
505 );
506
507 return this;
508}
509
510/**
511 * Find a key object, including PKCS11 library and slot
512 */
57426116
TB
513static private_pkcs11_public_key_t* find_key(key_type_t type, size_t keylen,
514 CK_ATTRIBUTE_PTR tmpl, int count)
fed9407b
MW
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
07190323 522 manager = lib->get(lib, "pkcs11-manager");
fed9407b
MW
523 if (!manager)
524 {
525 return NULL;
526 }
527
fed9407b
MW
528 enumerator = manager->create_token_enumerator(manager);
529 while (enumerator->enumerate(enumerator, &p11, &slot))
530 {
fed9407b
MW
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 }
57426116
TB
542 keys = p11->create_object_enumerator(p11, session, tmpl, count,
543 NULL, 0);
fed9407b
MW
544 if (keys->enumerate(keys, &object))
545 {
57426116 546 this = create(type, keylen, p11, slot, session, object);
fed9407b
MW
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
57426116
TB
557/**
558 * Find an RSA key object
559 */
560static 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
36d1627f
TB
574/**
575 * Find an ECDSA key object
576 */
577static 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
7c03d707
MW
592/**
593 * Create a key object in a suitable token session
594 */
57426116
TB
595static 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)
7c03d707
MW
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
07190323 605 manager = lib->get(lib, "pkcs11-manager");
7c03d707
MW
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;
7c03d707
MW
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 {
57426116
TB
623 bool found = FALSE;
624 int i;
7c03d707
MW
625 if (!(info.flags & CKF_VERIFY))
626 {
627 continue;
628 }
57426116 629 for (i = 0; i < mcount; i++)
7c03d707 630 {
57426116
TB
631 if (mechanisms[i] == mech)
632 {
633 found = TRUE;
7c03d707 634 break;
57426116
TB
635 }
636 }
637 if (!found)
638 {
639 continue;
7c03d707
MW
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 }
57426116 649 rv = p11->f->C_CreateObject(session, tmpl, count, &object);
7c03d707
MW
650 if (rv == CKR_OK)
651 {
57426116
TB
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);
7c03d707
MW
655 }
656 else
657 {
57426116
TB
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);
7c03d707
MW
661 p11->f->C_CloseSession(session);
662 }
57426116 663 break;
7c03d707
MW
664 }
665 mechs->destroy(mechs);
666 if (this)
667 {
668 break;
669 }
670 }
671 enumerator->destroy(enumerator);
672 return this;
673}
674
57426116
TB
675/**
676 * Create an RSA key object in a suitable token session
677 */
678static 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
36d1627f
TB
701/**
702 * Create an ECDSA key object in a suitable token session
703 */
704static 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
fed9407b
MW
724/**
725 * See header
726 */
727pkcs11_public_key_t *pkcs11_public_key_load(key_type_t type, va_list args)
728{
729 private_pkcs11_public_key_t *this;
36d1627f 730 chunk_t n, e, blob;
a190ec0a 731 size_t keylen = 0;
fed9407b 732
36d1627f 733 n = e = blob = chunk_empty;
fed9407b
MW
734 while (TRUE)
735 {
736 switch (va_arg(args, builder_part_t))
737 {
36d1627f
TB
738 case BUILD_BLOB_ASN1_DER:
739 blob = va_arg(args, chunk_t);
740 continue;
fed9407b
MW
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 {
7c03d707
MW
756 if (n.len && n.ptr[0] == 0)
757 { /* trim leading zero byte in modulus */
758 n = chunk_skip(n, 1);
759 }
57426116
TB
760 keylen = n.len * 8;
761 this = find_rsa_key(n, e, keylen);
fed9407b
MW
762 if (this)
763 {
764 return &this->public;
765 }
57426116 766 this = create_rsa_key(n, e, keylen);
7c03d707
MW
767 if (this)
768 {
769 return &this->public;
770 }
fed9407b 771 }
36d1627f
TB
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 }
fed9407b
MW
790 return NULL;
791}
792
30a3ede8
TB
793static 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
4de8f280 815 switch (key_type)
30a3ede8
TB
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 */
897pkcs11_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}