Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c, revision 1.1.1.1

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, &current, &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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>