Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2008-2009 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 "eap_aka_3gpp2_provider.h"
                     17: 
                     18: #include <daemon.h>
                     19: #include <credentials/keys/shared_key.h>
                     20: 
                     21: typedef struct private_eap_aka_3gpp2_provider_t private_eap_aka_3gpp2_provider_t;
                     22: 
                     23: /**
                     24:  * Private data of an eap_aka_3gpp2_provider_t object.
                     25:  */
                     26: struct private_eap_aka_3gpp2_provider_t {
                     27: 
                     28:        /**
                     29:         * Public eap_aka_3gpp2_provider_t interface.
                     30:         */
                     31:        eap_aka_3gpp2_provider_t public;
                     32: 
                     33:        /**
                     34:         * AKA functions
                     35:         */
                     36:        eap_aka_3gpp2_functions_t *f;
                     37: 
                     38:        /**
                     39:         * time based SQN, we use the same for all peers
                     40:         */
                     41:        char sqn[AKA_SQN_LEN];
                     42: };
                     43: 
                     44: /** Authentication management field */
                     45: static char amf_def[AKA_AMF_LEN] = {0x00, 0x01};
                     46: 
                     47: /**
                     48:  * Get a shared key K from the credential database
                     49:  */
                     50: bool eap_aka_3gpp2_get_k(identification_t *id, char k[AKA_K_LEN])
                     51: {
                     52:        shared_key_t *shared;
                     53:        chunk_t key;
                     54: 
                     55:        shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, id, NULL);
                     56:        if (shared == NULL)
                     57:        {
                     58:                return FALSE;
                     59:        }
                     60:        key = shared->get_key(shared);
                     61:        memset(k, '\0', AKA_K_LEN);
                     62:        memcpy(k, key.ptr, min(key.len, AKA_K_LEN));
                     63:        shared->destroy(shared);
                     64:        return TRUE;
                     65: }
                     66: 
                     67: /**
                     68:  * get SQN using current time
                     69:  */
                     70: void eap_aka_3gpp2_get_sqn(char sqn[AKA_SQN_LEN], int offset)
                     71: {
                     72:        timeval_t time;
                     73: 
                     74:        gettimeofday(&time, NULL);
                     75:        /* set sqn to an integer containing 4 bytes seconds + 2 bytes usecs */
                     76:        time.tv_sec = htonl(time.tv_sec + offset);
                     77:        /* usec's are never larger than 0x000f423f, so we shift the 12 first bits */
                     78:        time.tv_usec = htonl(time.tv_usec << 12);
                     79:        memcpy(sqn, (char*)&time.tv_sec + sizeof(time_t) - 4, 4);
                     80:        memcpy(sqn + 4, &time.tv_usec, 2);
                     81: }
                     82: 
                     83: METHOD(simaka_provider_t, get_quintuplet, bool,
                     84:        private_eap_aka_3gpp2_provider_t *this, identification_t *id,
                     85:        char rand[AKA_RAND_LEN], char xres[AKA_RES_MAX], int *xres_len,
                     86:        char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN])
                     87: {
                     88:        rng_t *rng;
                     89:        char mac[AKA_MAC_LEN], ak[AKA_AK_LEN], k[AKA_K_LEN];
                     90: 
                     91:        /* generate RAND: we use a registered RNG, not f0() proposed in S.S0055 */
                     92:        rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
                     93:        if (!rng || !rng->get_bytes(rng, AKA_RAND_LEN, rand))
                     94:        {
                     95:                DBG1(DBG_IKE, "generating RAND for AKA failed");
                     96:                DESTROY_IF(rng);
                     97:                return FALSE;
                     98:        }
                     99:        rng->destroy(rng);
                    100: 
                    101:        if (!eap_aka_3gpp2_get_k(id, k))
                    102:        {
                    103:                DBG1(DBG_IKE, "no EAP key found for %Y to authenticate with AKA", id);
                    104:                return FALSE;
                    105:        }
                    106: 
                    107:        DBG3(DBG_IKE, "generated rand %b", rand, AKA_RAND_LEN);
                    108:        DBG3(DBG_IKE, "using K %b", k, AKA_K_LEN);
                    109: 
                    110:        /* MAC, AK, XRES as expected from client */
                    111:        if (!this->f->f1(this->f, k, rand, this->sqn, amf_def, mac) ||
                    112:                !this->f->f5(this->f, k, rand, ak) ||
                    113:                !this->f->f2(this->f, k, rand, xres))
                    114:        {
                    115:                return FALSE;
                    116:        }
                    117:        *xres_len = AKA_RES_MAX;
                    118:        /* AUTN = (SQN xor AK) || AMF || MAC */
                    119:        memcpy(autn, this->sqn, AKA_SQN_LEN);
                    120:        memxor(autn, ak, AKA_AK_LEN);
                    121:        memcpy(autn + AKA_SQN_LEN, amf_def, AKA_AMF_LEN);
                    122:        memcpy(autn + AKA_SQN_LEN + AKA_AMF_LEN, mac, AKA_MAC_LEN);
                    123:        DBG3(DBG_IKE, "AUTN %b", autn, AKA_AUTN_LEN);
                    124:        /* CK/IK */
                    125:        if (!this->f->f3(this->f, k, rand, ck) ||
                    126:                !this->f->f4(this->f, k, rand, ik))
                    127:        {
                    128:                return FALSE;
                    129:        }
                    130:        chunk_increment(chunk_create(this->sqn, AKA_SQN_LEN));
                    131:        return TRUE;
                    132: }
                    133: 
                    134: METHOD(simaka_provider_t, resync, bool,
                    135:        private_eap_aka_3gpp2_provider_t *this, identification_t *id,
                    136:        char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
                    137: {
                    138:        char *sqn, *macs;
                    139:        char aks[AKA_AK_LEN], k[AKA_K_LEN], amf[AKA_AMF_LEN], xmacs[AKA_MAC_LEN];
                    140: 
                    141:        if (!eap_aka_3gpp2_get_k(id, k))
                    142:        {
                    143:                DBG1(DBG_IKE, "no EAP key found for %Y to authenticate with AKA", id);
                    144:                return FALSE;
                    145:        }
                    146: 
                    147:        /* AUTHS = (AK xor SQN) | MAC */
                    148:        sqn = auts;
                    149:        macs = auts + AKA_SQN_LEN;
                    150:        if (!this->f->f5star(this->f, k, rand, aks))
                    151:        {
                    152:                return FALSE;
                    153:        }
                    154:        memxor(sqn, aks, AKA_AK_LEN);
                    155: 
                    156:        /* verify XMACS, AMF of zero is used in resynchronization */
                    157:        memset(amf, 0, AKA_AMF_LEN);
                    158:        if (!this->f->f1star(this->f, k, rand, sqn, amf, xmacs))
                    159:        {
                    160:                return FALSE;
                    161:        }
                    162:        if (!memeq_const(macs, xmacs, AKA_MAC_LEN))
                    163:        {
                    164:                DBG1(DBG_IKE, "received MACS does not match XMACS");
                    165:                DBG3(DBG_IKE, "MACS %b XMACS %b",
                    166:                         macs, AKA_MAC_LEN, xmacs, AKA_MAC_LEN);
                    167:                return FALSE;
                    168:        }
                    169:        /* update stored SQN to received SQN + 1 */
                    170:        memcpy(this->sqn, sqn, AKA_SQN_LEN);
                    171:        chunk_increment(chunk_create(this->sqn, AKA_SQN_LEN));
                    172:        return TRUE;
                    173: }
                    174: 
                    175: METHOD(eap_aka_3gpp2_provider_t, destroy, void,
                    176:        private_eap_aka_3gpp2_provider_t *this)
                    177: {
                    178:        free(this);
                    179: }
                    180: 
                    181: /**
                    182:  * See header
                    183:  */
                    184: eap_aka_3gpp2_provider_t *eap_aka_3gpp2_provider_create(
                    185:                                                                                                eap_aka_3gpp2_functions_t *f)
                    186: {
                    187:        private_eap_aka_3gpp2_provider_t *this;
                    188: 
                    189:        INIT(this,
                    190:                .public = {
                    191:                        .provider = {
                    192:                                .get_triplet = (void*)return_false,
                    193:                                .get_quintuplet = _get_quintuplet,
                    194:                                .resync = _resync,
                    195:                                .is_pseudonym = (void*)return_null,
                    196:                                .gen_pseudonym = (void*)return_null,
                    197:                                .is_reauth = (void*)return_null,
                    198:                                .gen_reauth = (void*)return_null,
                    199:                        },
                    200:                        .destroy = _destroy,
                    201:                },
                    202:                .f = f,
                    203:        );
                    204:        /* use an offset to accept clock skew between client/server without resync */
                    205:        eap_aka_3gpp2_get_sqn(this->sqn, 180);
                    206: 
                    207:        return &this->public;
                    208: }

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