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