Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011-2016 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: * Copyright (C) 2016 EDF S.A.
! 20: *
! 21: * Permission is hereby granted, free of charge, to any person obtaining a copy
! 22: * of this software and associated documentation files (the "Software"), to deal
! 23: * in the Software without restriction, including without limitation the rights
! 24: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 25: * copies of the Software, and to permit persons to whom the Software is
! 26: * furnished to do so, subject to the following conditions:
! 27: *
! 28: * The above copyright notice and this permission notice shall be included in
! 29: * all copies or substantial portions of the Software.
! 30: *
! 31: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 32: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 33: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 34: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 35: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! 36: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! 37: * THE SOFTWARE.
! 38: */
! 39:
! 40: #include "pkcs11_private_key.h"
! 41:
! 42: #include "pkcs11_library.h"
! 43: #include "pkcs11_manager.h"
! 44: #include "pkcs11_public_key.h"
! 45:
! 46: #include <utils/debug.h>
! 47: #include <asn1/asn1.h>
! 48:
! 49: typedef struct private_pkcs11_private_key_t private_pkcs11_private_key_t;
! 50:
! 51: /**
! 52: * Private data of an pkcs11_private_key_t object.
! 53: */
! 54: struct private_pkcs11_private_key_t {
! 55:
! 56: /**
! 57: * Public pkcs11_private_key_t interface.
! 58: */
! 59: pkcs11_private_key_t public;
! 60:
! 61: /**
! 62: * PKCS#11 module
! 63: */
! 64: pkcs11_library_t *lib;
! 65:
! 66: /**
! 67: * Slot the token is in
! 68: */
! 69: CK_SLOT_ID slot;
! 70:
! 71: /**
! 72: * Token session
! 73: */
! 74: CK_SESSION_HANDLE session;
! 75:
! 76: /**
! 77: * Key object on the token
! 78: */
! 79: CK_OBJECT_HANDLE object;
! 80:
! 81: /**
! 82: * Key requires reauthentication for each signature/decryption
! 83: */
! 84: CK_BBOOL reauth;
! 85:
! 86: /**
! 87: * Keyid of the key we use
! 88: */
! 89: identification_t *keyid;
! 90:
! 91: /**
! 92: * Associated public key
! 93: */
! 94: public_key_t *pubkey;
! 95:
! 96: /**
! 97: * References to this key
! 98: */
! 99: refcount_t ref;
! 100:
! 101: /**
! 102: * Type of this private key
! 103: */
! 104: key_type_t type;
! 105: };
! 106:
! 107:
! 108: METHOD(private_key_t, get_type, key_type_t,
! 109: private_pkcs11_private_key_t *this)
! 110: {
! 111: return this->type;
! 112: }
! 113:
! 114: METHOD(private_key_t, get_keysize, int,
! 115: private_pkcs11_private_key_t *this)
! 116: {
! 117: return this->pubkey->get_keysize(this->pubkey);
! 118: }
! 119:
! 120: /**
! 121: * See header.
! 122: */
! 123: CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme,
! 124: key_type_t type, size_t keylen,
! 125: hash_algorithm_t *hash)
! 126: {
! 127: static struct {
! 128: signature_scheme_t scheme;
! 129: CK_MECHANISM mechanism;
! 130: key_type_t type;
! 131: size_t keylen;
! 132: hash_algorithm_t hash;
! 133: } mappings[] = {
! 134: {SIGN_RSA_EMSA_PKCS1_NULL, {CKM_RSA_PKCS, NULL, 0},
! 135: KEY_RSA, 0, HASH_UNKNOWN},
! 136: {SIGN_RSA_EMSA_PKCS1_SHA2_256, {CKM_SHA256_RSA_PKCS, NULL, 0},
! 137: KEY_RSA, 0, HASH_UNKNOWN},
! 138: {SIGN_RSA_EMSA_PKCS1_SHA2_384, {CKM_SHA384_RSA_PKCS, NULL, 0},
! 139: KEY_RSA, 0, HASH_UNKNOWN},
! 140: {SIGN_RSA_EMSA_PKCS1_SHA2_512, {CKM_SHA512_RSA_PKCS, NULL, 0},
! 141: KEY_RSA, 0, HASH_UNKNOWN},
! 142: {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_SHA1_RSA_PKCS, NULL, 0},
! 143: KEY_RSA, 0, HASH_UNKNOWN},
! 144: {SIGN_RSA_EMSA_PKCS1_MD5, {CKM_MD5_RSA_PKCS, NULL, 0},
! 145: KEY_RSA, 0, HASH_UNKNOWN},
! 146: {SIGN_ECDSA_WITH_NULL, {CKM_ECDSA, NULL, 0},
! 147: KEY_ECDSA, 0, HASH_UNKNOWN},
! 148: {SIGN_ECDSA_WITH_SHA1_DER, {CKM_ECDSA_SHA1, NULL, 0},
! 149: KEY_ECDSA, 0, HASH_UNKNOWN},
! 150: {SIGN_ECDSA_WITH_SHA256_DER, {CKM_ECDSA, NULL, 0},
! 151: KEY_ECDSA, 0, HASH_SHA256},
! 152: {SIGN_ECDSA_WITH_SHA384_DER, {CKM_ECDSA, NULL, 0},
! 153: KEY_ECDSA, 0, HASH_SHA384},
! 154: {SIGN_ECDSA_WITH_SHA512_DER, {CKM_ECDSA, NULL, 0},
! 155: KEY_ECDSA, 0, HASH_SHA512},
! 156: {SIGN_ECDSA_256, {CKM_ECDSA, NULL, 0},
! 157: KEY_ECDSA, 256, HASH_SHA256},
! 158: {SIGN_ECDSA_384, {CKM_ECDSA, NULL, 0},
! 159: KEY_ECDSA, 384, HASH_SHA384},
! 160: {SIGN_ECDSA_521, {CKM_ECDSA, NULL, 0},
! 161: KEY_ECDSA, 521, HASH_SHA512},
! 162: };
! 163: int i;
! 164:
! 165: for (i = 0; i < countof(mappings); i++)
! 166: {
! 167: if (mappings[i].scheme == scheme)
! 168: {
! 169: size_t len = mappings[i].keylen;
! 170: if (mappings[i].type != type || (len && keylen != len))
! 171: {
! 172: return NULL;
! 173: }
! 174: if (hash)
! 175: {
! 176: *hash = mappings[i].hash;
! 177: }
! 178: return &mappings[i].mechanism;
! 179: }
! 180: }
! 181: return NULL;
! 182: }
! 183:
! 184: /**
! 185: * See header.
! 186: */
! 187: CK_MECHANISM_PTR pkcs11_encryption_scheme_to_mech(encryption_scheme_t scheme)
! 188: {
! 189: static struct {
! 190: encryption_scheme_t scheme;
! 191: CK_MECHANISM mechanism;
! 192: } mappings[] = {
! 193: {ENCRYPT_RSA_PKCS1, {CKM_RSA_PKCS, NULL, 0}},
! 194: {ENCRYPT_RSA_OAEP_SHA1, {CKM_RSA_PKCS_OAEP, NULL, 0}},
! 195: };
! 196: int i;
! 197:
! 198: for (i = 0; i < countof(mappings); i++)
! 199: {
! 200: if (mappings[i].scheme == scheme)
! 201: {
! 202: return &mappings[i].mechanism;
! 203: }
! 204: }
! 205: return NULL;
! 206: }
! 207:
! 208: /**
! 209: * Reauthenticate to do a signature
! 210: */
! 211: static bool reauth(private_pkcs11_private_key_t *this,
! 212: CK_SESSION_HANDLE session)
! 213: {
! 214: enumerator_t *enumerator;
! 215: shared_key_t *shared;
! 216: chunk_t pin;
! 217: CK_RV rv;
! 218: bool found = FALSE, success = FALSE;
! 219:
! 220: enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
! 221: SHARED_PIN, this->keyid, NULL);
! 222: while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
! 223: {
! 224: found = TRUE;
! 225: pin = shared->get_key(shared);
! 226: rv = this->lib->f->C_Login(session, CKU_CONTEXT_SPECIFIC,
! 227: pin.ptr, pin.len);
! 228: if (rv == CKR_OK)
! 229: {
! 230: success = TRUE;
! 231: break;
! 232: }
! 233: DBG1(DBG_CFG, "reauthentication login failed: %N", ck_rv_names, rv);
! 234: }
! 235: enumerator->destroy(enumerator);
! 236:
! 237: if (!found)
! 238: {
! 239: DBG1(DBG_CFG, "private key requires reauthentication, but no PIN found");
! 240: return FALSE;
! 241: }
! 242: return success;
! 243: }
! 244:
! 245: METHOD(private_key_t, sign, bool,
! 246: private_pkcs11_private_key_t *this, signature_scheme_t scheme, void *params,
! 247: chunk_t data, chunk_t *signature)
! 248: {
! 249: CK_MECHANISM_PTR mechanism;
! 250: CK_SESSION_HANDLE session;
! 251: CK_BYTE_PTR buf;
! 252: CK_ULONG len;
! 253: CK_RV rv;
! 254: hash_algorithm_t hash_alg;
! 255: chunk_t hash = chunk_empty;
! 256:
! 257: mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type,
! 258: get_keysize(this), &hash_alg);
! 259: if (!mechanism)
! 260: {
! 261: DBG1(DBG_LIB, "signature scheme %N not supported",
! 262: signature_scheme_names, scheme);
! 263: return FALSE;
! 264: }
! 265: rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
! 266: &session);
! 267: if (rv != CKR_OK)
! 268: {
! 269: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
! 270: return FALSE;
! 271: }
! 272: rv = this->lib->f->C_SignInit(session, mechanism, this->object);
! 273: if (this->reauth && !reauth(this, session))
! 274: {
! 275: this->lib->f->C_CloseSession(session);
! 276: return FALSE;
! 277: }
! 278: if (rv != CKR_OK)
! 279: {
! 280: this->lib->f->C_CloseSession(session);
! 281: DBG1(DBG_LIB, "C_SignInit() failed: %N", ck_rv_names, rv);
! 282: return FALSE;
! 283: }
! 284: if (hash_alg != HASH_UNKNOWN)
! 285: {
! 286: hasher_t *hasher;
! 287:
! 288: hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
! 289: if (!hasher || !hasher->allocate_hash(hasher, data, &hash))
! 290: {
! 291: DESTROY_IF(hasher);
! 292: this->lib->f->C_CloseSession(session);
! 293: return FALSE;
! 294: }
! 295: hasher->destroy(hasher);
! 296: data = hash;
! 297: }
! 298: len = (get_keysize(this) + 7) / 8;
! 299: if (this->type == KEY_ECDSA)
! 300: { /* signature is twice the length of the base point order */
! 301: len *= 2;
! 302: }
! 303: buf = malloc(len);
! 304: rv = this->lib->f->C_Sign(session, data.ptr, data.len, buf, &len);
! 305: this->lib->f->C_CloseSession(session);
! 306: chunk_free(&hash);
! 307: if (rv != CKR_OK)
! 308: {
! 309: DBG1(DBG_LIB, "C_Sign() failed: %N", ck_rv_names, rv);
! 310: free(buf);
! 311: return FALSE;
! 312: }
! 313: switch (scheme)
! 314: {
! 315: case SIGN_ECDSA_WITH_SHA1_DER:
! 316: case SIGN_ECDSA_WITH_SHA256_DER:
! 317: case SIGN_ECDSA_WITH_SHA384_DER:
! 318: case SIGN_ECDSA_WITH_SHA512_DER:
! 319: {
! 320: chunk_t r, s;
! 321:
! 322: /* return an ASN.1 encoded sequence of integers r and s, removing
! 323: * any zero-padding */
! 324: len /= 2;
! 325: r = chunk_skip_zero(chunk_create(buf, len));
! 326: s = chunk_skip_zero(chunk_create(buf+len, len));
! 327: *signature = asn1_wrap(ASN1_SEQUENCE, "mm",
! 328: asn1_integer("c", r), asn1_integer("c", s));
! 329: free(buf);
! 330: break;
! 331: }
! 332: default:
! 333: *signature = chunk_create(buf, len);
! 334: break;
! 335: }
! 336: return TRUE;
! 337: }
! 338:
! 339: METHOD(private_key_t, decrypt, bool,
! 340: private_pkcs11_private_key_t *this, encryption_scheme_t scheme,
! 341: chunk_t crypt, chunk_t *plain)
! 342: {
! 343: CK_MECHANISM_PTR mechanism;
! 344: CK_SESSION_HANDLE session;
! 345: CK_BYTE_PTR buf;
! 346: CK_ULONG len;
! 347: CK_RV rv;
! 348:
! 349: mechanism = pkcs11_encryption_scheme_to_mech(scheme);
! 350: if (!mechanism)
! 351: {
! 352: DBG1(DBG_LIB, "encryption scheme %N not supported",
! 353: encryption_scheme_names, scheme);
! 354: return FALSE;
! 355: }
! 356: rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
! 357: &session);
! 358: if (rv != CKR_OK)
! 359: {
! 360: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
! 361: return FALSE;
! 362: }
! 363: rv = this->lib->f->C_DecryptInit(session, mechanism, this->object);
! 364: if (this->reauth && !reauth(this, session))
! 365: {
! 366: this->lib->f->C_CloseSession(session);
! 367: return FALSE;
! 368: }
! 369: if (rv != CKR_OK)
! 370: {
! 371: this->lib->f->C_CloseSession(session);
! 372: DBG1(DBG_LIB, "C_DecryptInit() failed: %N", ck_rv_names, rv);
! 373: return FALSE;
! 374: }
! 375: len = (get_keysize(this) + 7) / 8;
! 376: buf = malloc(len);
! 377: rv = this->lib->f->C_Decrypt(session, crypt.ptr, crypt.len, buf, &len);
! 378: this->lib->f->C_CloseSession(session);
! 379: if (rv != CKR_OK)
! 380: {
! 381: DBG1(DBG_LIB, "C_Decrypt() failed: %N", ck_rv_names, rv);
! 382: free(buf);
! 383: return FALSE;
! 384: }
! 385: *plain = chunk_create(buf, len);
! 386: return TRUE;
! 387: }
! 388:
! 389: METHOD(private_key_t, get_public_key, public_key_t*,
! 390: private_pkcs11_private_key_t *this)
! 391: {
! 392: return this->pubkey->get_ref(this->pubkey);
! 393: }
! 394:
! 395: METHOD(private_key_t, get_fingerprint, bool,
! 396: private_pkcs11_private_key_t *this, cred_encoding_type_t type,
! 397: chunk_t *fingerprint)
! 398: {
! 399: return this->pubkey->get_fingerprint(this->pubkey, type, fingerprint);
! 400: }
! 401:
! 402: METHOD(private_key_t, get_encoding, bool,
! 403: private_pkcs11_private_key_t *this, cred_encoding_type_t type,
! 404: chunk_t *encoding)
! 405: {
! 406: return FALSE;
! 407: }
! 408:
! 409: METHOD(private_key_t, get_ref, private_key_t*,
! 410: private_pkcs11_private_key_t *this)
! 411: {
! 412: ref_get(&this->ref);
! 413: return &this->public.key;
! 414: }
! 415:
! 416: METHOD(private_key_t, destroy, void,
! 417: private_pkcs11_private_key_t *this)
! 418: {
! 419: if (ref_put(&this->ref))
! 420: {
! 421: if (this->pubkey)
! 422: {
! 423: this->pubkey->destroy(this->pubkey);
! 424: }
! 425: this->keyid->destroy(this->keyid);
! 426: this->lib->f->C_CloseSession(this->session);
! 427: free(this);
! 428: }
! 429: }
! 430:
! 431: /**
! 432: * Find the PKCS#11 library by its friendly name
! 433: */
! 434: static pkcs11_library_t* find_lib(char *module)
! 435: {
! 436: pkcs11_manager_t *manager;
! 437: enumerator_t *enumerator;
! 438: pkcs11_library_t *p11, *found = NULL;
! 439: CK_SLOT_ID slot;
! 440:
! 441: manager = lib->get(lib, "pkcs11-manager");
! 442: if (!manager)
! 443: {
! 444: return NULL;
! 445: }
! 446: enumerator = manager->create_token_enumerator(manager);
! 447: while (enumerator->enumerate(enumerator, &p11, &slot))
! 448: {
! 449: if (streq(module, p11->get_name(p11)))
! 450: {
! 451: found = p11;
! 452: break;
! 453: }
! 454: }
! 455: enumerator->destroy(enumerator);
! 456: return found;
! 457: }
! 458:
! 459: /**
! 460: * Find the PKCS#11 lib having a keyid, and optionally a slot
! 461: */
! 462: static pkcs11_library_t* find_lib_by_keyid(chunk_t keyid, int *slot,
! 463: CK_OBJECT_CLASS class)
! 464: {
! 465: pkcs11_manager_t *manager;
! 466: enumerator_t *enumerator;
! 467: pkcs11_library_t *p11, *found = NULL;
! 468: CK_SLOT_ID current;
! 469:
! 470: manager = lib->get(lib, "pkcs11-manager");
! 471: if (!manager)
! 472: {
! 473: return NULL;
! 474: }
! 475: enumerator = manager->create_token_enumerator(manager);
! 476: while (enumerator->enumerate(enumerator, &p11, ¤t))
! 477: {
! 478: if (*slot == -1 || *slot == current)
! 479: {
! 480: /* look for a pubkey/cert, it is usually readable without login */
! 481: CK_ATTRIBUTE tmpl[] = {
! 482: {CKA_CLASS, &class, sizeof(class)},
! 483: {CKA_ID, keyid.ptr, keyid.len},
! 484: };
! 485: CK_OBJECT_HANDLE object;
! 486: CK_SESSION_HANDLE session;
! 487: CK_RV rv;
! 488: enumerator_t *keys;
! 489:
! 490: rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
! 491: &session);
! 492: if (rv != CKR_OK)
! 493: {
! 494: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
! 495: ck_rv_names, rv);
! 496: continue;
! 497: }
! 498: keys = p11->create_object_enumerator(p11, session,
! 499: tmpl, countof(tmpl), NULL, 0);
! 500: if (keys->enumerate(keys, &object))
! 501: {
! 502: DBG1(DBG_CFG, "found key on PKCS#11 token '%s':%d",
! 503: p11->get_name(p11), current);
! 504: found = p11;
! 505: *slot = current;
! 506: }
! 507: keys->destroy(keys);
! 508: p11->f->C_CloseSession(session);
! 509: if (found)
! 510: {
! 511: break;
! 512: }
! 513: }
! 514: }
! 515: enumerator->destroy(enumerator);
! 516: return found;
! 517: }
! 518:
! 519: /**
! 520: * Find the PKCS#11 lib and CKA_ID of the certificate object of a given
! 521: * subjectKeyIdentifier and optional slot
! 522: */
! 523: static pkcs11_library_t* find_lib_and_keyid_by_skid(chunk_t keyid_chunk,
! 524: chunk_t *ckaid, int *slot)
! 525: {
! 526: CK_OBJECT_CLASS class = CKO_CERTIFICATE;
! 527: CK_CERTIFICATE_TYPE type = CKC_X_509;
! 528: CK_ATTRIBUTE tmpl[] = {
! 529: {CKA_CLASS, &class, sizeof(class)},
! 530: {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
! 531: };
! 532: CK_ATTRIBUTE attr[] = {
! 533: {CKA_VALUE, NULL, 0},
! 534: {CKA_ID, NULL, 0},
! 535: };
! 536: CK_OBJECT_HANDLE object;
! 537: CK_SESSION_HANDLE session;
! 538: CK_RV rv;
! 539: pkcs11_manager_t *manager;
! 540: enumerator_t *enumerator, *certs;
! 541: identification_t *keyid;
! 542: pkcs11_library_t *p11, *found = NULL;
! 543: CK_SLOT_ID current;
! 544: linked_list_t *raw;
! 545: certificate_t *cert;
! 546: struct {
! 547: chunk_t value;
! 548: chunk_t ckaid;
! 549: } *entry;
! 550:
! 551: manager = lib->get(lib, "pkcs11-manager");
! 552: if (!manager)
! 553: {
! 554: return NULL;
! 555: }
! 556:
! 557: keyid = identification_create_from_encoding(ID_KEY_ID, keyid_chunk);
! 558: /* store result in a temporary list, avoid recursive operation */
! 559: raw = linked_list_create();
! 560:
! 561: enumerator = manager->create_token_enumerator(manager);
! 562: while (enumerator->enumerate(enumerator, &p11, ¤t))
! 563: {
! 564: if (*slot != -1 && *slot != current)
! 565: {
! 566: continue;
! 567: }
! 568: rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
! 569: &session);
! 570: if (rv != CKR_OK)
! 571: {
! 572: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
! 573: ck_rv_names, rv);
! 574: continue;
! 575: }
! 576: certs = p11->create_object_enumerator(p11, session, tmpl, countof(tmpl),
! 577: attr, countof(attr));
! 578: while (certs->enumerate(certs, &object))
! 579: {
! 580: INIT(entry,
! 581: .value = chunk_clone(
! 582: chunk_create(attr[0].pValue, attr[0].ulValueLen)),
! 583: .ckaid = chunk_clone(
! 584: chunk_create(attr[1].pValue, attr[1].ulValueLen)),
! 585: );
! 586: raw->insert_last(raw, entry);
! 587: }
! 588: certs->destroy(certs);
! 589:
! 590: while (raw->remove_first(raw, (void**)&entry) == SUCCESS)
! 591: {
! 592: if (!found)
! 593: {
! 594: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
! 595: CERT_X509, BUILD_BLOB_ASN1_DER,
! 596: entry->value, BUILD_END);
! 597: if (cert)
! 598: {
! 599: if (cert->has_subject(cert, keyid))
! 600: {
! 601: DBG1(DBG_CFG, "found cert with keyid '%#B' on PKCS#11 "
! 602: "token '%s':%d", &keyid_chunk, p11->get_name(p11),
! 603: current);
! 604: found = p11;
! 605: *ckaid = chunk_clone(entry->ckaid);
! 606: *slot = current;
! 607: }
! 608: cert->destroy(cert);
! 609: }
! 610: else
! 611: {
! 612: DBG1(DBG_CFG, "parsing cert with CKA_ID '%#B' on PKCS#11 "
! 613: "token '%s':%d failed", &entry->ckaid,
! 614: p11->get_name(p11), current);
! 615: }
! 616: }
! 617: chunk_free(&entry->value);
! 618: chunk_free(&entry->ckaid);
! 619: free(entry);
! 620: }
! 621: p11->f->C_CloseSession(session);
! 622: if (found)
! 623: {
! 624: break;
! 625: }
! 626: }
! 627: enumerator->destroy(enumerator);
! 628: keyid->destroy(keyid);
! 629: raw->destroy(raw);
! 630: return found;
! 631: }
! 632:
! 633: /**
! 634: * Find the key on the token
! 635: */
! 636: static bool find_key(private_pkcs11_private_key_t *this, chunk_t keyid)
! 637: {
! 638: CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
! 639: CK_ATTRIBUTE tmpl[] = {
! 640: {CKA_CLASS, &class, sizeof(class)},
! 641: {CKA_ID, keyid.ptr, keyid.len},
! 642: };
! 643: CK_OBJECT_HANDLE object;
! 644: CK_KEY_TYPE type;
! 645: CK_BBOOL reauth = FALSE;
! 646: CK_ATTRIBUTE attr[] = {
! 647: {CKA_KEY_TYPE, &type, sizeof(type)},
! 648: {CKA_ALWAYS_AUTHENTICATE, &reauth, sizeof(reauth)},
! 649: };
! 650: enumerator_t *enumerator;
! 651: int count = countof(attr);
! 652: bool found = FALSE;
! 653:
! 654: /* do not use CKA_ALWAYS_AUTHENTICATE if not supported */
! 655: if (!(this->lib->get_features(this->lib) & PKCS11_ALWAYS_AUTH_KEYS))
! 656: {
! 657: count--;
! 658: }
! 659: enumerator = this->lib->create_object_enumerator(this->lib,
! 660: this->session, tmpl, countof(tmpl), attr, count);
! 661: if (enumerator->enumerate(enumerator, &object))
! 662: {
! 663: this->type = KEY_RSA;
! 664: switch (type)
! 665: {
! 666: case CKK_ECDSA:
! 667: this->type = KEY_ECDSA;
! 668: /* fall-through */
! 669: case CKK_RSA:
! 670: this->reauth = reauth;
! 671: this->object = object;
! 672: found = TRUE;
! 673: break;
! 674: default:
! 675: DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
! 676: break;
! 677: }
! 678: }
! 679: enumerator->destroy(enumerator);
! 680: return found;
! 681: }
! 682:
! 683: /**
! 684: * Find a PIN and try to log in
! 685: */
! 686: static bool login(private_pkcs11_private_key_t *this, int slot)
! 687: {
! 688: enumerator_t *enumerator;
! 689: shared_key_t *shared;
! 690: chunk_t pin;
! 691: CK_RV rv;
! 692: CK_SESSION_INFO info;
! 693: bool found = FALSE, success = FALSE;
! 694:
! 695: rv = this->lib->f->C_GetSessionInfo(this->session, &info);
! 696: if (rv != CKR_OK)
! 697: {
! 698: DBG1(DBG_CFG, "C_GetSessionInfo failed: %N", ck_rv_names, rv);
! 699: return FALSE;
! 700: }
! 701: if (info.state != CKS_RO_PUBLIC_SESSION &&
! 702: info.state != CKS_RW_PUBLIC_SESSION)
! 703: { /* already logged in with another session, skip */
! 704: return TRUE;
! 705: }
! 706:
! 707: enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
! 708: SHARED_PIN, this->keyid, NULL);
! 709: while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
! 710: {
! 711: found = TRUE;
! 712: pin = shared->get_key(shared);
! 713: rv = this->lib->f->C_Login(this->session, CKU_USER, pin.ptr, pin.len);
! 714: if (rv == CKR_OK)
! 715: {
! 716: success = TRUE;
! 717: break;
! 718: }
! 719: DBG1(DBG_CFG, "login to '%s':%d failed: %N",
! 720: this->lib->get_name(this->lib), slot, ck_rv_names, rv);
! 721: }
! 722: enumerator->destroy(enumerator);
! 723:
! 724: if (!found)
! 725: {
! 726: DBG1(DBG_CFG, "no PIN found for PKCS#11 key %Y", this->keyid);
! 727: return FALSE;
! 728: }
! 729: return success;
! 730: }
! 731:
! 732: /**
! 733: * Get a public key from a certificate with a given key ID.
! 734: */
! 735: static public_key_t* find_pubkey_in_certs(private_pkcs11_private_key_t *this,
! 736: chunk_t keyid)
! 737: {
! 738: CK_OBJECT_CLASS class = CKO_CERTIFICATE;
! 739: CK_CERTIFICATE_TYPE type = CKC_X_509;
! 740: CK_ATTRIBUTE tmpl[] = {
! 741: {CKA_CLASS, &class, sizeof(class)},
! 742: {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
! 743: {CKA_ID, keyid.ptr, keyid.len},
! 744: };
! 745: CK_OBJECT_HANDLE object;
! 746: CK_ATTRIBUTE attr[] = {
! 747: {CKA_VALUE, NULL, 0},
! 748: };
! 749: enumerator_t *enumerator;
! 750: chunk_t data = chunk_empty;
! 751: public_key_t *key = NULL;
! 752: certificate_t *cert;
! 753:
! 754: enumerator = this->lib->create_object_enumerator(this->lib, this->session,
! 755: tmpl, countof(tmpl), attr, countof(attr));
! 756: if (enumerator->enumerate(enumerator, &object))
! 757: {
! 758: data = chunk_clone(chunk_create(attr[0].pValue, attr[0].ulValueLen));
! 759: }
! 760: enumerator->destroy(enumerator);
! 761:
! 762: if (data.ptr)
! 763: {
! 764: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
! 765: BUILD_BLOB_ASN1_DER, data, BUILD_END);
! 766: free(data.ptr);
! 767: if (cert)
! 768: {
! 769: key = cert->get_public_key(cert);
! 770: cert->destroy(cert);
! 771: }
! 772: }
! 773: return key;
! 774: }
! 775:
! 776: /**
! 777: * See header.
! 778: */
! 779: pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args)
! 780: {
! 781: private_pkcs11_private_key_t *this;
! 782: char *module = NULL;
! 783: chunk_t keyid = chunk_empty, ckaid = chunk_empty;
! 784: int slot = -1;
! 785: CK_RV rv;
! 786:
! 787: while (TRUE)
! 788: {
! 789: switch (va_arg(args, builder_part_t))
! 790: {
! 791: case BUILD_PKCS11_KEYID:
! 792: keyid = va_arg(args, chunk_t);
! 793: continue;
! 794: case BUILD_PKCS11_SLOT:
! 795: slot = va_arg(args, int);
! 796: continue;
! 797: case BUILD_PKCS11_MODULE:
! 798: module = va_arg(args, char*);
! 799: continue;
! 800: case BUILD_END:
! 801: break;
! 802: default:
! 803: return NULL;
! 804: }
! 805: break;
! 806: }
! 807: if (!keyid.len)
! 808: {
! 809: return NULL;
! 810: }
! 811:
! 812: INIT(this,
! 813: .public = {
! 814: .key = {
! 815: .get_type = _get_type,
! 816: .sign = _sign,
! 817: .decrypt = _decrypt,
! 818: .get_keysize = _get_keysize,
! 819: .get_public_key = _get_public_key,
! 820: .equals = private_key_equals,
! 821: .belongs_to = private_key_belongs_to,
! 822: .get_fingerprint = _get_fingerprint,
! 823: .has_fingerprint = private_key_has_fingerprint,
! 824: .get_encoding = _get_encoding,
! 825: .get_ref = _get_ref,
! 826: .destroy = _destroy,
! 827: },
! 828: },
! 829: .ref = 1,
! 830: );
! 831:
! 832: if (module && slot != -1)
! 833: {
! 834: this->lib = find_lib(module);
! 835: if (!this->lib)
! 836: {
! 837: DBG1(DBG_CFG, "PKCS#11 module '%s' not found", module);
! 838: free(this);
! 839: return NULL;
! 840: }
! 841: }
! 842: else
! 843: {
! 844: this->lib = find_lib_by_keyid(keyid, &slot, CKO_PUBLIC_KEY);
! 845: if (!this->lib)
! 846: {
! 847: this->lib = find_lib_by_keyid(keyid, &slot, CKO_CERTIFICATE);
! 848: }
! 849: if (!this->lib)
! 850: {
! 851: this->lib = find_lib_and_keyid_by_skid(keyid, &ckaid, &slot);
! 852: }
! 853: if (!this->lib)
! 854: {
! 855: DBG1(DBG_CFG, "no PKCS#11 module found having a keyid %#B", &keyid);
! 856: free(this);
! 857: return NULL;
! 858: }
! 859: }
! 860:
! 861: rv = this->lib->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
! 862: NULL, NULL, &this->session);
! 863: if (rv != CKR_OK)
! 864: {
! 865: DBG1(DBG_CFG, "opening private key session on '%s':%d failed: %N",
! 866: module, slot, ck_rv_names, rv);
! 867: free(this);
! 868: return NULL;
! 869: }
! 870:
! 871: this->slot = slot;
! 872: this->keyid = identification_create_from_encoding(ID_KEY_ID, keyid);
! 873:
! 874: if (!login(this, slot))
! 875: {
! 876: destroy(this);
! 877: return NULL;
! 878: }
! 879:
! 880: if (ckaid.ptr)
! 881: {
! 882: DBG1(DBG_CFG, "using CKA_ID '%#B' for key with keyid '%#B'",
! 883: &ckaid, &keyid);
! 884: keyid = ckaid;
! 885: }
! 886:
! 887: if (!find_key(this, keyid))
! 888: {
! 889: DBG1(DBG_CFG, "did not find the key with %s '%#B'",
! 890: ckaid.ptr ? "CKA_ID" : "keyid", &keyid);
! 891: destroy(this);
! 892: return NULL;
! 893: }
! 894:
! 895: this->pubkey = pkcs11_public_key_connect(this->lib, slot, this->type, keyid);
! 896: if (!this->pubkey)
! 897: {
! 898: this->pubkey = find_pubkey_in_certs(this, keyid);
! 899: if (!this->pubkey)
! 900: {
! 901: DBG1(DBG_CFG, "no public key or certificate found for private key "
! 902: "(%s '%#B') on '%s':%d", ckaid.ptr ? "CKA_ID" : "keyid",
! 903: &keyid, module, slot);
! 904: destroy(this);
! 905: return NULL;
! 906: }
! 907: }
! 908: return &this->public;
! 909: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>