Return to pkcs11_dh.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / pkcs11 |
1.1 misho 1: /* 2: * Copyright (C) 2011 Tobias Brunner 3: * HSR Hochschule fuer Technik Rapperswil 4: * 5: * This program is free software; you can redistribute it and/or modify it 6: * under the terms of the GNU General Public License as published by the 7: * Free Software Foundation; either version 2 of the License, or (at your 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 9: * 10: * This program is distributed in the hope that it will be useful, but 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13: * for more details. 14: */ 15: 16: #include "pkcs11_dh.h" 17: 18: #include <utils/debug.h> 19: #include <library.h> 20: #include <asn1/asn1.h> 21: #include <asn1/oid.h> 22: 23: #include "pkcs11_manager.h" 24: 25: typedef struct private_pkcs11_dh_t private_pkcs11_dh_t; 26: 27: /** 28: * Private data of an pkcs11_dh_t object. 29: */ 30: struct private_pkcs11_dh_t { 31: 32: /** 33: * Public pkcs11_dh_t interface 34: */ 35: pkcs11_dh_t public; 36: 37: /** 38: * PKCS#11 library 39: */ 40: pkcs11_library_t *lib; 41: 42: /** 43: * Session handle for this object 44: */ 45: CK_SESSION_HANDLE session; 46: 47: /** 48: * Diffie Hellman group number. 49: */ 50: diffie_hellman_group_t group; 51: 52: /** 53: * Handle for own private value 54: */ 55: CK_OBJECT_HANDLE pri_key; 56: 57: /** 58: * Own public value 59: */ 60: chunk_t pub_key; 61: 62: /** 63: * Shared secret 64: */ 65: chunk_t secret; 66: 67: /** 68: * Mechanism to use to generate a key pair 69: */ 70: CK_MECHANISM_TYPE mech_key; 71: 72: /** 73: * Mechanism to use to derive a shared secret 74: */ 75: CK_MECHANISM_TYPE mech_derive; 76: 77: }; 78: 79: /** 80: * Derive a DH/ECDH shared secret. 81: * 82: * If this succeeds the shared secret is stored in this->secret. 83: */ 84: static bool derive_secret(private_pkcs11_dh_t *this, chunk_t other) 85: { 86: CK_OBJECT_CLASS klass = CKO_SECRET_KEY; 87: CK_KEY_TYPE type = CKK_GENERIC_SECRET; 88: CK_ATTRIBUTE attr[] = { 89: { CKA_CLASS, &klass, sizeof(klass) }, 90: { CKA_KEY_TYPE, &type, sizeof(type) }, 91: }; 92: CK_MECHANISM mech = { 93: this->mech_derive, 94: other.ptr, 95: other.len, 96: }; 97: CK_OBJECT_HANDLE secret; 98: CK_RV rv; 99: 100: rv = this->lib->f->C_DeriveKey(this->session, &mech, this->pri_key, 101: attr, countof(attr), &secret); 102: if (rv != CKR_OK) 103: { 104: DBG1(DBG_CFG, "C_DeriveKey() error: %N", ck_rv_names, rv); 105: return FALSE; 106: } 107: if (!this->lib->get_ck_attribute(this->lib, this->session, secret, 108: CKA_VALUE, &this->secret)) 109: { 110: chunk_free(&this->secret); 111: return FALSE; 112: } 113: return TRUE; 114: } 115: 116: METHOD(diffie_hellman_t, set_other_public_value, bool, 117: private_pkcs11_dh_t *this, chunk_t value) 118: { 119: if (!diffie_hellman_verify_value(this->group, value)) 120: { 121: return FALSE; 122: } 123: 124: switch (this->group) 125: { 126: case ECP_192_BIT: 127: case ECP_224_BIT: 128: case ECP_256_BIT: 129: case ECP_384_BIT: 130: case ECP_521_BIT: 131: { /* we expect the public value to just be the concatenated x and y 132: * coordinates, so we tag the value as an uncompressed ECPoint */ 133: chunk_t tag = chunk_from_chars(0x04); 134: chunk_t pubkey = chunk_cata("cc", tag, value); 135: CK_ECDH1_DERIVE_PARAMS params = { 136: CKD_NULL, 137: 0, 138: NULL, 139: pubkey.len, 140: pubkey.ptr, 141: }; 142: 143: if (!lib->settings->get_bool(lib->settings, 144: "%s.ecp_x_coordinate_only", TRUE, lib->ns)) 145: { /* we only get the x coordinate back */ 146: return FALSE; 147: } 148: value = chunk_from_thing(params); 149: break; 150: } 151: default: 152: break; 153: } 154: return derive_secret(this, value); 155: } 156: 157: METHOD(diffie_hellman_t, get_my_public_value, bool, 158: private_pkcs11_dh_t *this, chunk_t *value) 159: { 160: *value = chunk_clone(this->pub_key); 161: return TRUE; 162: } 163: 164: METHOD(diffie_hellman_t, get_shared_secret, bool, 165: private_pkcs11_dh_t *this, chunk_t *secret) 166: { 167: if (!this->secret.ptr) 168: { 169: return FALSE; 170: } 171: *secret = chunk_clone(this->secret); 172: return TRUE; 173: } 174: 175: METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t, 176: private_pkcs11_dh_t *this) 177: { 178: return this->group; 179: } 180: 181: METHOD(diffie_hellman_t, destroy, void, 182: private_pkcs11_dh_t *this) 183: { 184: this->lib->f->C_CloseSession(this->session); 185: chunk_clear(&this->pub_key); 186: chunk_clear(&this->secret); 187: free(this); 188: } 189: 190: /** 191: * Generate a DH/ECDH key pair. 192: * 193: * If this succeeds, this->pri_key has a handle to the private key and 194: * this->pub_key stores the public key. 195: */ 196: static bool generate_key_pair(private_pkcs11_dh_t *this, CK_ATTRIBUTE_PTR pub, 197: int pub_len, CK_ATTRIBUTE_PTR pri, int pri_len, 198: CK_ATTRIBUTE_TYPE attr) 199: { 200: CK_MECHANISM mech = { 201: this->mech_key, 202: NULL, 203: 0, 204: }; 205: CK_OBJECT_HANDLE pub_key; 206: CK_RV rv; 207: 208: rv = this->lib->f->C_GenerateKeyPair(this->session, &mech, pub, pub_len, 209: pri, pri_len, &pub_key, &this->pri_key); 210: if (rv != CKR_OK) 211: { 212: DBG1(DBG_CFG, "C_GenerateKeyPair() error: %N", ck_rv_names, rv); 213: return FALSE; 214: } 215: if (!this->lib->get_ck_attribute(this->lib, this->session, pub_key, 216: attr, &this->pub_key)) 217: { 218: chunk_free(&this->pub_key); 219: return FALSE; 220: } 221: return TRUE; 222: } 223: 224: /** 225: * Generate DH key pair. 226: */ 227: static bool generate_key_pair_modp(private_pkcs11_dh_t *this, size_t exp_len, 228: chunk_t g, chunk_t p) 229: { 230: CK_BBOOL ck_true = CK_TRUE; 231: CK_ATTRIBUTE pub_attr[] = { 232: { CKA_DERIVE, &ck_true, sizeof(ck_true) }, 233: { CKA_PRIME, p.ptr, p.len }, 234: { CKA_BASE, g.ptr, g.len }, 235: }; 236: CK_ULONG bits = exp_len * 8; 237: CK_ATTRIBUTE pri_attr[] = { 238: { CKA_DERIVE, &ck_true, sizeof(ck_true) }, 239: { CKA_VALUE_BITS, &bits, sizeof(bits) }, 240: }; 241: return generate_key_pair(this, pub_attr, countof(pub_attr), pri_attr, 242: countof(pri_attr), CKA_VALUE); 243: } 244: 245: /** 246: * Generate ECDH key pair. 247: */ 248: static bool generate_key_pair_ecp(private_pkcs11_dh_t *this, 249: chunk_t ecparams) 250: { 251: CK_BBOOL ck_true = CK_TRUE; 252: CK_ATTRIBUTE pub_attr[] = { 253: { CKA_DERIVE, &ck_true, sizeof(ck_true) }, 254: { CKA_EC_PARAMS, ecparams.ptr, ecparams.len }, 255: }; 256: CK_ATTRIBUTE pri_attr[] = { 257: { CKA_DERIVE, &ck_true, sizeof(ck_true) }, 258: }; 259: chunk_t pub_key; 260: if (!generate_key_pair(this, pub_attr, countof(pub_attr), pri_attr, 261: countof(pri_attr), CKA_EC_POINT)) 262: { 263: return FALSE; 264: } 265: if (this->pub_key.len <= 0 || this->pub_key.ptr[0] != 0x04) 266: { /* we currently only support the point in uncompressed form which 267: * looks like this: 0x04 || x || y */ 268: chunk_clear(&this->pub_key); 269: return FALSE; 270: } 271: pub_key = chunk_clone(chunk_skip(this->pub_key, 1)); 272: chunk_clear(&this->pub_key); 273: this->pub_key = pub_key; 274: return TRUE; 275: } 276: 277: /** 278: * Find a token we can use for DH/ECDH algorithm 279: */ 280: static pkcs11_library_t *find_token(private_pkcs11_dh_t *this, 281: CK_SESSION_HANDLE *session) 282: { 283: enumerator_t *tokens, *mechs; 284: pkcs11_manager_t *manager; 285: pkcs11_library_t *current, *found = NULL; 286: CK_MECHANISM_TYPE type; 287: CK_SLOT_ID slot; 288: 289: manager = lib->get(lib, "pkcs11-manager"); 290: if (!manager) 291: { 292: return NULL; 293: } 294: tokens = manager->create_token_enumerator(manager); 295: while (tokens->enumerate(tokens, ¤t, &slot)) 296: { 297: mechs = current->create_mechanism_enumerator(current, slot); 298: while (mechs->enumerate(mechs, &type, NULL)) 299: { /* we assume we can generate key pairs if the derive mechanism 300: * is supported */ 301: if (type == this->mech_derive) 302: { 303: if (current->f->C_OpenSession(slot, CKF_SERIAL_SESSION, 304: NULL, NULL, session) == CKR_OK) 305: { 306: found = current; 307: break; 308: } 309: } 310: } 311: mechs->destroy(mechs); 312: if (found) 313: { 314: break; 315: } 316: } 317: tokens->destroy(tokens); 318: return found; 319: } 320: 321: /** 322: * Generic internal constructor 323: */ 324: static private_pkcs11_dh_t *create_generic(diffie_hellman_group_t group, 325: CK_MECHANISM_TYPE key, 326: CK_MECHANISM_TYPE derive) 327: { 328: private_pkcs11_dh_t *this; 329: 330: INIT(this, 331: .public = { 332: .dh = { 333: .get_shared_secret = _get_shared_secret, 334: .set_other_public_value = _set_other_public_value, 335: .get_my_public_value = _get_my_public_value, 336: .get_dh_group = _get_dh_group, 337: .destroy = _destroy, 338: }, 339: }, 340: .group = group, 341: .mech_key = key, 342: .mech_derive = derive, 343: ); 344: 345: this->lib = find_token(this, &this->session); 346: if (!this->lib) 347: { 348: free(this); 349: return NULL; 350: } 351: return this; 352: } 353: 354: static pkcs11_dh_t *create_ecp(diffie_hellman_group_t group, chunk_t ecparam) 355: { 356: private_pkcs11_dh_t *this = create_generic(group, CKM_EC_KEY_PAIR_GEN, 357: CKM_ECDH1_DERIVE); 358: 359: if (this) 360: { 361: if (generate_key_pair_ecp(this, ecparam)) 362: { 363: chunk_free(&ecparam); 364: return &this->public; 365: } 366: chunk_free(&ecparam); 367: free(this); 368: } 369: return NULL; 370: } 371: 372: /** 373: * Constructor for MODP DH 374: */ 375: static pkcs11_dh_t *create_modp(diffie_hellman_group_t group, size_t exp_len, 376: chunk_t g, chunk_t p) 377: { 378: private_pkcs11_dh_t *this = create_generic(group, CKM_DH_PKCS_KEY_PAIR_GEN, 379: CKM_DH_PKCS_DERIVE); 380: 381: if (this) 382: { 383: if (generate_key_pair_modp(this, exp_len, g, p)) 384: { 385: return &this->public; 386: } 387: free(this); 388: } 389: return NULL; 390: } 391: 392: /** 393: * Lookup the EC params for the given group. 394: */ 395: static chunk_t ecparams_lookup(diffie_hellman_group_t group) 396: { 397: switch (group) 398: { 399: case ECP_192_BIT: 400: return asn1_build_known_oid(OID_PRIME192V1); 401: case ECP_224_BIT: 402: return asn1_build_known_oid(OID_SECT224R1); 403: case ECP_256_BIT: 404: return asn1_build_known_oid(OID_PRIME256V1); 405: case ECP_384_BIT: 406: return asn1_build_known_oid(OID_SECT384R1); 407: case ECP_521_BIT: 408: return asn1_build_known_oid(OID_SECT521R1); 409: default: 410: break; 411: } 412: return chunk_empty; 413: } 414: 415: /** 416: * Described in header. 417: */ 418: pkcs11_dh_t *pkcs11_dh_create(diffie_hellman_group_t group, ...) 419: { 420: switch (group) 421: { 422: case MODP_CUSTOM: 423: { 424: chunk_t g, p; 425: 426: VA_ARGS_GET(group, g, p); 427: return create_modp(group, p.len, g, p); 428: } 429: case ECP_192_BIT: 430: case ECP_224_BIT: 431: case ECP_256_BIT: 432: case ECP_384_BIT: 433: case ECP_521_BIT: 434: { 435: chunk_t params = ecparams_lookup(group); 436: if (params.ptr) 437: { 438: return create_ecp(group, params); 439: } 440: break; 441: } 442: default: 443: { 444: diffie_hellman_params_t *params = diffie_hellman_get_params(group); 445: if (params) 446: { 447: return create_modp(group, params->exp_len, params->generator, 448: params->prime); 449: } 450: break; 451: } 452: } 453: return NULL; 454: }