Annotation of embedaddon/strongswan/src/libsimaka/simaka_crypto.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2009-2011 Martin Willi
                      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 "simaka_crypto.h"
                     17: 
                     18: #include "simaka_manager.h"
                     19: 
                     20: #include <utils/debug.h>
                     21: 
                     22: /** length of the k_encr key */
                     23: #define KENCR_LEN 16
                     24: /** length of the k_auth key */
                     25: #define KAUTH_LEN 16
                     26: /** length of the MSK */
                     27: #define MSK_LEN 64
                     28: /** length of the EMSK */
                     29: #define EMSK_LEN 64
                     30: 
                     31: typedef struct private_simaka_crypto_t private_simaka_crypto_t;
                     32: 
                     33: /**
                     34:  * Private data of an simaka_crypto_t object.
                     35:  */
                     36: struct private_simaka_crypto_t {
                     37: 
                     38:        /**
                     39:         * Public simaka_crypto_t interface.
                     40:         */
                     41:        simaka_crypto_t public;
                     42: 
                     43:        /**
                     44:         * EAP type this crypto is used, SIM or AKA
                     45:         */
                     46:        eap_type_t type;
                     47: 
                     48:        /**
                     49:         * signer to create/verify AT_MAC
                     50:         */
                     51:        signer_t *signer;
                     52: 
                     53:        /**
                     54:         * crypter to encrypt/decrypt AT_ENCR_DATA
                     55:         */
                     56:        crypter_t *crypter;
                     57: 
                     58:        /**
                     59:         * hasher used in key derivation
                     60:         */
                     61:        hasher_t *hasher;
                     62: 
                     63:        /**
                     64:         * PRF function used in key derivation
                     65:         */
                     66:        prf_t *prf;
                     67: 
                     68:        /**
                     69:         * Random number generator to generate nonces
                     70:         */
                     71:        rng_t *rng;
                     72: 
                     73:        /**
                     74:         * Have k_encr/k_auth been derived?
                     75:         */
                     76:        bool derived;
                     77: };
                     78: 
                     79: METHOD(simaka_crypto_t, get_signer, signer_t*,
                     80:        private_simaka_crypto_t *this)
                     81: {
                     82:        return this->derived ? this->signer : NULL;
                     83: }
                     84: 
                     85: METHOD(simaka_crypto_t, get_crypter, crypter_t*,
                     86:        private_simaka_crypto_t *this)
                     87: {
                     88:        return this->derived ? this->crypter : NULL;
                     89: }
                     90: 
                     91: METHOD(simaka_crypto_t, get_rng, rng_t*,
                     92:        private_simaka_crypto_t *this)
                     93: {
                     94:        return this->rng;
                     95: }
                     96: 
                     97: /**
                     98:  * Call SIM/AKA key hook
                     99:  */
                    100: static void call_hook(private_simaka_crypto_t *this, chunk_t encr, chunk_t auth)
                    101: {
                    102:        simaka_manager_t *mgr;
                    103: 
                    104:        switch (this->type)
                    105:        {
                    106:                case EAP_SIM:
                    107:                        mgr = lib->get(lib, "sim-manager");
                    108:                        break;
                    109:                case EAP_AKA:
                    110:                        mgr = lib->get(lib, "aka-manager");
                    111:                        break;
                    112:                default:
                    113:                        return;
                    114:        }
                    115:        mgr->key_hook(mgr, encr, auth);
                    116: }
                    117: 
                    118: METHOD(simaka_crypto_t, derive_keys_full, bool,
                    119:        private_simaka_crypto_t *this, identification_t *id,
                    120:        chunk_t data, chunk_t *mk, chunk_t *msk)
                    121: {
                    122:        chunk_t str, k_encr, k_auth;
                    123:        int i;
                    124: 
                    125:        /* For SIM: MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version)
                    126:         * For AKA: MK = SHA1(Identity|IK|CK) */
                    127:        if (!this->hasher->get_hash(this->hasher, id->get_encoding(id), NULL) ||
                    128:                !this->hasher->allocate_hash(this->hasher, data, mk))
                    129:        {
                    130:                return FALSE;
                    131:        }
                    132:        DBG3(DBG_LIB, "MK %B", mk);
                    133: 
                    134:        /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf() */
                    135:        if (!this->prf->set_key(this->prf, *mk))
                    136:        {
                    137:                chunk_clear(mk);
                    138:                return FALSE;
                    139:        }
                    140:        str = chunk_alloca(this->prf->get_block_size(this->prf) * 3);
                    141:        for (i = 0; i < 3; i++)
                    142:        {
                    143:                if (!this->prf->get_bytes(this->prf, chunk_empty,
                    144:                                                                  str.ptr + str.len / 3 * i))
                    145:                {
                    146:                        chunk_clear(mk);
                    147:                        return FALSE;
                    148:                }
                    149:        }
                    150: 
                    151:        k_encr = chunk_create(str.ptr, KENCR_LEN);
                    152:        k_auth = chunk_create(str.ptr + KENCR_LEN, KAUTH_LEN);
                    153: 
                    154:        if (!this->signer->set_key(this->signer, k_auth) ||
                    155:                !this->crypter->set_key(this->crypter, k_encr))
                    156:        {
                    157:                chunk_clear(mk);
                    158:                return FALSE;
                    159:        }
                    160: 
                    161:        *msk = chunk_clone(chunk_create(str.ptr + KENCR_LEN + KAUTH_LEN, MSK_LEN));
                    162:        DBG3(DBG_LIB, "K_encr %B\nK_auth %B\nMSK %B", &k_encr, &k_auth, msk);
                    163: 
                    164:        call_hook(this, k_encr, k_auth);
                    165: 
                    166:        this->derived = TRUE;
                    167:        return TRUE;
                    168: }
                    169: 
                    170: METHOD(simaka_crypto_t, derive_keys_reauth, bool,
                    171:        private_simaka_crypto_t *this, chunk_t mk)
                    172: {
                    173:        chunk_t str, k_encr, k_auth;
                    174:        int i;
                    175: 
                    176:        /* K_encr | K_auth = prf() | prf() */
                    177:        if (!this->prf->set_key(this->prf, mk))
                    178:        {
                    179:                return FALSE;
                    180:        }
                    181:        str = chunk_alloca(this->prf->get_block_size(this->prf) * 2);
                    182:        for (i = 0; i < 2; i++)
                    183:        {
                    184:                if (!this->prf->get_bytes(this->prf, chunk_empty,
                    185:                                                                  str.ptr + str.len / 2 * i))
                    186:                {
                    187:                        return FALSE;
                    188:                }
                    189:        }
                    190:        k_encr = chunk_create(str.ptr, KENCR_LEN);
                    191:        k_auth = chunk_create(str.ptr + KENCR_LEN, KAUTH_LEN);
                    192:        DBG3(DBG_LIB, "K_encr %B\nK_auth %B", &k_encr, &k_auth);
                    193: 
                    194:        if (!this->signer->set_key(this->signer, k_auth) ||
                    195:                !this->crypter->set_key(this->crypter, k_encr))
                    196:        {
                    197:                return FALSE;
                    198:        }
                    199: 
                    200:        call_hook(this, k_encr, k_auth);
                    201: 
                    202:        this->derived = TRUE;
                    203:        return TRUE;
                    204: }
                    205: 
                    206: METHOD(simaka_crypto_t, derive_keys_reauth_msk, bool,
                    207:        private_simaka_crypto_t *this, identification_t *id, chunk_t counter,
                    208:        chunk_t nonce_s, chunk_t mk, chunk_t *msk)
                    209: {
                    210:        char xkey[HASH_SIZE_SHA1];
                    211:        chunk_t str;
                    212:        int i;
                    213: 
                    214:        if (!this->hasher->get_hash(this->hasher, id->get_encoding(id), NULL) ||
                    215:                !this->hasher->get_hash(this->hasher, counter, NULL) ||
                    216:                !this->hasher->get_hash(this->hasher, nonce_s, NULL) ||
                    217:                !this->hasher->get_hash(this->hasher, mk, xkey))
                    218:        {
                    219:                return FALSE;
                    220:        }
                    221: 
                    222:        /* MSK | EMSK = prf() | prf() | prf() | prf() */
                    223:        if (!this->prf->set_key(this->prf, chunk_create(xkey, sizeof(xkey))))
                    224:        {
                    225:                return FALSE;
                    226:        }
                    227:        str = chunk_alloca(this->prf->get_block_size(this->prf) * 2);
                    228:        for (i = 0; i < 2; i++)
                    229:        {
                    230:                if (!this->prf->get_bytes(this->prf, chunk_empty,
                    231:                                                                  str.ptr + str.len / 2 * i))
                    232:                {
                    233:                        return FALSE;
                    234:                }
                    235:        }
                    236:        *msk = chunk_clone(chunk_create(str.ptr, MSK_LEN));
                    237:        DBG3(DBG_LIB, "MSK %B", msk);
                    238: 
                    239:        return TRUE;
                    240: }
                    241: 
                    242: METHOD(simaka_crypto_t, clear_keys, void,
                    243:        private_simaka_crypto_t *this)
                    244: {
                    245:        this->derived = FALSE;
                    246: }
                    247: 
                    248: METHOD(simaka_crypto_t, destroy, void,
                    249:        private_simaka_crypto_t *this)
                    250: {
                    251:        DESTROY_IF(this->rng);
                    252:        DESTROY_IF(this->hasher);
                    253:        DESTROY_IF(this->prf);
                    254:        DESTROY_IF(this->signer);
                    255:        DESTROY_IF(this->crypter);
                    256:        free(this);
                    257: }
                    258: 
                    259: /**
                    260:  * See header
                    261:  */
                    262: simaka_crypto_t *simaka_crypto_create(eap_type_t type)
                    263: {
                    264:        private_simaka_crypto_t *this;
                    265: 
                    266:        INIT(this,
                    267:                .public = {
                    268:                        .get_signer = _get_signer,
                    269:                        .get_crypter = _get_crypter,
                    270:                        .get_rng = _get_rng,
                    271:                        .derive_keys_full = _derive_keys_full,
                    272:                        .derive_keys_reauth = _derive_keys_reauth,
                    273:                        .derive_keys_reauth_msk = _derive_keys_reauth_msk,
                    274:                        .clear_keys = _clear_keys,
                    275:                        .destroy = _destroy,
                    276:                },
                    277:                .type = type,
                    278:                .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
                    279:                .hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1),
                    280:                .prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160),
                    281:                .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA1_128),
                    282:                .crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC, 16),
                    283:        );
                    284:        if (!this->rng || !this->hasher || !this->prf ||
                    285:                !this->signer || !this->crypter)
                    286:        {
                    287:                DBG1(DBG_LIB, "unable to use %N, missing algorithms",
                    288:                         eap_type_names, type);
                    289:                destroy(this);
                    290:                return NULL;
                    291:        }
                    292:        return &this->public;
                    293: }

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