Annotation of embedaddon/strongswan/src/libsimaka/simaka_crypto.c, revision 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>