Return to eap_aka_3gpp2_provider.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / eap_aka_3gpp2 |
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: }