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

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

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