Return to pkcs11_public_key.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / pkcs11 |
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: }