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