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: value = chunk_from_thing(params); 143: break; 144: } 145: default: 146: break; 147: } 148: return derive_secret(this, value); 149: } 150: 151: METHOD(diffie_hellman_t, get_my_public_value, bool, 152: private_pkcs11_dh_t *this, chunk_t *value) 153: { 154: *value = chunk_clone(this->pub_key); 155: return TRUE; 156: } 157: 158: METHOD(diffie_hellman_t, get_shared_secret, bool, 159: private_pkcs11_dh_t *this, chunk_t *secret) 160: { 161: if (!this->secret.ptr) 162: { 163: return FALSE; 164: } 165: *secret = chunk_clone(this->secret); 166: return TRUE; 167: } 168: 169: METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t, 170: private_pkcs11_dh_t *this) 171: { 172: return this->group; 173: } 174: 175: METHOD(diffie_hellman_t, destroy, void, 176: private_pkcs11_dh_t *this) 177: { 178: this->lib->f->C_CloseSession(this->session); 179: chunk_clear(&this->pub_key); 180: chunk_clear(&this->secret); 181: free(this); 182: } 183: 184: /** 185: * Generate a DH/ECDH key pair. 186: * 187: * If this succeeds, this->pri_key has a handle to the private key and 188: * this->pub_key stores the public key. 189: */ 190: static bool generate_key_pair(private_pkcs11_dh_t *this, CK_ATTRIBUTE_PTR pub, 191: int pub_len, CK_ATTRIBUTE_PTR pri, int pri_len, 192: CK_ATTRIBUTE_TYPE attr) 193: { 194: CK_MECHANISM mech = { 195: this->mech_key, 196: NULL, 197: 0, 198: }; 199: CK_OBJECT_HANDLE pub_key; 200: CK_RV rv; 201: 202: rv = this->lib->f->C_GenerateKeyPair(this->session, &mech, pub, pub_len, 203: pri, pri_len, &pub_key, &this->pri_key); 204: if (rv != CKR_OK) 205: { 206: DBG1(DBG_CFG, "C_GenerateKeyPair() error: %N", ck_rv_names, rv); 207: return FALSE; 208: } 209: if (!this->lib->get_ck_attribute(this->lib, this->session, pub_key, 210: attr, &this->pub_key)) 211: { 212: chunk_free(&this->pub_key); 213: return FALSE; 214: } 215: return TRUE; 216: } 217: 218: /** 219: * Generate DH key pair. 220: */ 221: static bool generate_key_pair_modp(private_pkcs11_dh_t *this, size_t exp_len, 222: chunk_t g, chunk_t p) 223: { 224: CK_BBOOL ck_true = CK_TRUE; 225: CK_ATTRIBUTE pub_attr[] = { 226: { CKA_DERIVE, &ck_true, sizeof(ck_true) }, 227: { CKA_PRIME, p.ptr, p.len }, 228: { CKA_BASE, g.ptr, g.len }, 229: }; 230: CK_ULONG bits = exp_len * 8; 231: CK_ATTRIBUTE pri_attr[] = { 232: { CKA_DERIVE, &ck_true, sizeof(ck_true) }, 233: { CKA_VALUE_BITS, &bits, sizeof(bits) }, 234: }; 235: return generate_key_pair(this, pub_attr, countof(pub_attr), pri_attr, 236: countof(pri_attr), CKA_VALUE); 237: } 238: 239: /** 240: * Generate ECDH key pair. 241: */ 242: static bool generate_key_pair_ecp(private_pkcs11_dh_t *this, 243: chunk_t ecparams) 244: { 245: CK_BBOOL ck_true = CK_TRUE; 246: CK_ATTRIBUTE pub_attr[] = { 247: { CKA_DERIVE, &ck_true, sizeof(ck_true) }, 248: { CKA_EC_PARAMS, ecparams.ptr, ecparams.len }, 249: }; 250: CK_ATTRIBUTE pri_attr[] = { 251: { CKA_DERIVE, &ck_true, sizeof(ck_true) }, 252: }; 253: chunk_t pub_key; 254: if (!generate_key_pair(this, pub_attr, countof(pub_attr), pri_attr, 255: countof(pri_attr), CKA_EC_POINT)) 256: { 257: return FALSE; 258: } 259: if (this->pub_key.len <= 0 || this->pub_key.ptr[0] != 0x04) 260: { /* we currently only support the point in uncompressed form which 261: * looks like this: 0x04 || x || y */ 262: chunk_clear(&this->pub_key); 263: return FALSE; 264: } 265: pub_key = chunk_clone(chunk_skip(this->pub_key, 1)); 266: chunk_clear(&this->pub_key); 267: this->pub_key = pub_key; 268: return TRUE; 269: } 270: 271: /** 272: * Find a token we can use for DH/ECDH algorithm 273: */ 274: static pkcs11_library_t *find_token(private_pkcs11_dh_t *this, 275: CK_SESSION_HANDLE *session) 276: { 277: enumerator_t *tokens, *mechs; 278: pkcs11_manager_t *manager; 279: pkcs11_library_t *current, *found = NULL; 280: CK_MECHANISM_TYPE type; 281: CK_SLOT_ID slot; 282: 283: manager = lib->get(lib, "pkcs11-manager"); 284: if (!manager) 285: { 286: return NULL; 287: } 288: tokens = manager->create_token_enumerator(manager); 289: while (tokens->enumerate(tokens, ¤t, &slot)) 290: { 291: mechs = current->create_mechanism_enumerator(current, slot); 292: while (mechs->enumerate(mechs, &type, NULL)) 293: { /* we assume we can generate key pairs if the derive mechanism 294: * is supported */ 295: if (type == this->mech_derive) 296: { 297: if (current->f->C_OpenSession(slot, CKF_SERIAL_SESSION, 298: NULL, NULL, session) == CKR_OK) 299: { 300: found = current; 301: break; 302: } 303: } 304: } 305: mechs->destroy(mechs); 306: if (found) 307: { 308: break; 309: } 310: } 311: tokens->destroy(tokens); 312: return found; 313: } 314: 315: /** 316: * Generic internal constructor 317: */ 318: static private_pkcs11_dh_t *create_generic(diffie_hellman_group_t group, 319: CK_MECHANISM_TYPE key, 320: CK_MECHANISM_TYPE derive) 321: { 322: private_pkcs11_dh_t *this; 323: 324: INIT(this, 325: .public = { 326: .dh = { 327: .get_shared_secret = _get_shared_secret, 328: .set_other_public_value = _set_other_public_value, 329: .get_my_public_value = _get_my_public_value, 330: .get_dh_group = _get_dh_group, 331: .destroy = _destroy, 332: }, 333: }, 334: .group = group, 335: .mech_key = key, 336: .mech_derive = derive, 337: ); 338: 339: this->lib = find_token(this, &this->session); 340: if (!this->lib) 341: { 342: free(this); 343: return NULL; 344: } 345: return this; 346: } 347: 348: static pkcs11_dh_t *create_ecp(diffie_hellman_group_t group, chunk_t ecparam) 349: { 350: private_pkcs11_dh_t *this = create_generic(group, CKM_EC_KEY_PAIR_GEN, 351: CKM_ECDH1_DERIVE); 352: 353: if (this) 354: { 355: if (generate_key_pair_ecp(this, ecparam)) 356: { 357: chunk_free(&ecparam); 358: return &this->public; 359: } 360: chunk_free(&ecparam); 361: free(this); 362: } 363: return NULL; 364: } 365: 366: /** 367: * Constructor for MODP DH 368: */ 369: static pkcs11_dh_t *create_modp(diffie_hellman_group_t group, size_t exp_len, 370: chunk_t g, chunk_t p) 371: { 372: private_pkcs11_dh_t *this = create_generic(group, CKM_DH_PKCS_KEY_PAIR_GEN, 373: CKM_DH_PKCS_DERIVE); 374: 375: if (this) 376: { 377: if (generate_key_pair_modp(this, exp_len, g, p)) 378: { 379: return &this->public; 380: } 381: free(this); 382: } 383: return NULL; 384: } 385: 386: /** 387: * Lookup the EC params for the given group. 388: */ 389: static chunk_t ecparams_lookup(diffie_hellman_group_t group) 390: { 391: switch (group) 392: { 393: case ECP_192_BIT: 394: return asn1_build_known_oid(OID_PRIME192V1); 395: case ECP_224_BIT: 396: return asn1_build_known_oid(OID_SECT224R1); 397: case ECP_256_BIT: 398: return asn1_build_known_oid(OID_PRIME256V1); 399: case ECP_384_BIT: 400: return asn1_build_known_oid(OID_SECT384R1); 401: case ECP_521_BIT: 402: return asn1_build_known_oid(OID_SECT521R1); 403: default: 404: break; 405: } 406: return chunk_empty; 407: } 408: 409: /** 410: * Described in header. 411: */ 412: pkcs11_dh_t *pkcs11_dh_create(diffie_hellman_group_t group, ...) 413: { 414: switch (group) 415: { 416: case MODP_CUSTOM: 417: { 418: chunk_t g, p; 419: 420: VA_ARGS_GET(group, g, p); 421: return create_modp(group, p.len, g, p); 422: } 423: case ECP_192_BIT: 424: case ECP_224_BIT: 425: case ECP_256_BIT: 426: case ECP_384_BIT: 427: case ECP_521_BIT: 428: { 429: chunk_t params = ecparams_lookup(group); 430: if (params.ptr) 431: { 432: return create_ecp(group, params); 433: } 434: break; 435: } 436: default: 437: { 438: diffie_hellman_params_t *params = diffie_hellman_get_params(group); 439: if (params) 440: { 441: return create_modp(group, params->exp_len, params->generator, 442: params->prime); 443: } 444: break; 445: } 446: } 447: return NULL; 448: }