diff options
Diffstat (limited to 'src/charon/plugins/eap_aka/eap_aka.c')
-rw-r--r-- | src/charon/plugins/eap_aka/eap_aka.c | 226 |
1 files changed, 113 insertions, 113 deletions
diff --git a/src/charon/plugins/eap_aka/eap_aka.c b/src/charon/plugins/eap_aka/eap_aka.c index ebef74404..0b85428f9 100644 --- a/src/charon/plugins/eap_aka/eap_aka.c +++ b/src/charon/plugins/eap_aka/eap_aka.c @@ -178,72 +178,72 @@ typedef struct private_eap_aka_t private_eap_aka_t; * Private data of an eap_aka_t object. */ struct private_eap_aka_t { - + /** * Public authenticator_t interface. */ eap_aka_t public; - + /** * ID of the server */ identification_t *server; - + /** * ID of the peer */ identification_t *peer; - + /** * SHA11 hasher */ hasher_t *sha1; - + /** * MAC function used in EAP-AKA */ signer_t *signer; - + /** * pseudo random function used in EAP-aka */ prf_t *prf; - + /** * Special keyed SHA1 hasher used in EAP-AKA, implemented as PRF */ prf_t *keyed_prf; - + /** * Key for EAP MAC */ chunk_t k_auth; - + /** * Key for EAP encryption */ chunk_t k_encr; - + /** * MSK */ chunk_t msk; - + /** * Extendend MSK */ chunk_t emsk; - + /** * Expected result from client XRES */ chunk_t xres; - + /** * Shared secret K from ipsec.conf (padded) */ chunk_t k; - + /** * random value RAND generated by server */ @@ -270,7 +270,7 @@ static chunk_t peer_sqn = chunk_from_buf(peer_sqn_buf); static void update_sqn(u_int8_t *sqn, time_t offset) { timeval_t time; - + time_monotonic(&time); /* set sqb_sqn to an integer containing seconds followed by most * significant useconds */ @@ -322,7 +322,7 @@ static void mpz_mul_poly(mpz_t r, mpz_t a, mpz_t b) { mpz_t bm, rm; int current = 0, shifted = 0, shift; - + mpz_init_set(bm, b); mpz_init_set_ui(rm, 0); /* scan through a, for each found bit: */ @@ -335,7 +335,7 @@ static void mpz_mul_poly(mpz_t r, mpz_t a, mpz_t b) mpz_xor(rm, rm, bm); current++; } - + mpz_swap(r, rm); mpz_clear(rm); mpz_clear(bm); @@ -361,13 +361,13 @@ static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b) */ int a_bit, b_bit, diff; mpz_t bm, am; - + mpz_init_set(am, a); mpz_init(bm); - + a_bit = mpz_sizeinbase(a, 2); b_bit = mpz_sizeinbase(b, 2); - + /* don't do anything if b > a */ if (a_bit >= b_bit) { @@ -397,7 +397,7 @@ static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b) * a = 00000010 * which is the polynomial modulo */ - + mpz_swap(r, am); mpz_clear(am); mpz_clear(bm); @@ -410,12 +410,12 @@ static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b) static void step4(private_eap_aka_t *this, u_int8_t x[]) { mpz_t xm, am, bm, gm; - + mpz_init(xm); mpz_init(am); mpz_init(bm); mpz_init(gm); - + mpz_import(xm, HASH_SIZE_SHA1, 1, 1, 1, 0, x); mpz_import(am, sizeof(a), 1, 1, 1, 0, a); mpz_import(bm, sizeof(b), 1, 1, 1, 0, b); @@ -424,9 +424,9 @@ static void step4(private_eap_aka_t *this, u_int8_t x[]) mpz_mul_poly(xm, am, xm); mpz_add_poly(xm, bm, xm); mpz_mod_poly(xm, xm, gm); - + mpz_export(x, NULL, 1, HASH_SIZE_SHA1, 1, 0, xm); - + mpz_clear(xm); mpz_clear(am); mpz_clear(bm); @@ -441,7 +441,7 @@ static void step3(private_eap_aka_t *this, chunk_t k, chunk_t payload, u_int8_t h[]) { u_int8_t buf[64]; - + if (payload.len < sizeof(buf)) { /* pad c with zeros */ @@ -455,7 +455,7 @@ static void step3(private_eap_aka_t *this, /* not more than 512 bits can be G()-ed */ payload.len = sizeof(buf); } - + /* use the keyed hasher to build the hash */ this->keyed_prf->set_key(this->keyed_prf, k); this->keyed_prf->get_bytes(this->keyed_prf, payload, h); @@ -470,19 +470,19 @@ static void fx(private_eap_aka_t *this, chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); u_int8_t h[HASH_SIZE_SHA1]; u_int8_t i; - + for (i = 0; i < 2; i++) { memset(payload.ptr, 0x5c, payload.len); payload.ptr[11] ^= f; memxor(payload.ptr + 12, fmk.ptr, fmk.len); memxor(payload.ptr + 24, rand.ptr, rand.len); - + payload.ptr[3] ^= i; payload.ptr[19] ^= i; payload.ptr[35] ^= i; payload.ptr[51] ^= i; - + step3(this, k, payload, h); step4(this, h); memcpy(out + i * 8, h, 8); @@ -502,14 +502,14 @@ static void f1x(private_eap_aka_t *this, */ chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); u_int8_t h[HASH_SIZE_SHA1]; - + memset(payload.ptr, 0x5c, PAYLOAD_LENGTH); payload.ptr[11] ^= f; memxor(payload.ptr + 12, fmk.ptr, fmk.len); memxor(payload.ptr + 16, rand.ptr, rand.len); memxor(payload.ptr + 34, sqn.ptr, sqn.len); memxor(payload.ptr + 42, amf.ptr, amf.len); - + step3(this, k, payload, h); step4(this, h); memcpy(mac, h, MAC_LENGTH); @@ -518,17 +518,17 @@ static void f1x(private_eap_aka_t *this, /** * Calculation function of f5() and f5star() */ -static void f5x(private_eap_aka_t *this, +static void f5x(private_eap_aka_t *this, u_int8_t f, chunk_t k, chunk_t rand, u_int8_t ak[]) { chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); u_int8_t h[HASH_SIZE_SHA1]; - + memset(payload.ptr, 0x5c, payload.len); payload.ptr[11] ^= f; memxor(payload.ptr + 12, fmk.ptr, fmk.len); memxor(payload.ptr + 16, rand.ptr, rand.len); - + step3(this, k, payload, h); step4(this, h); memcpy(ak, h, AK_LENGTH); @@ -605,12 +605,12 @@ static void f5star(private_eap_aka_t *this, chunk_t k, chunk_t rand, u_int8_t ak static bool derive_keys(private_eap_aka_t *this, identification_t *id) { chunk_t ck, ik, mk, identity, tmp; - + ck = chunk_alloca(CK_LENGTH); ik = chunk_alloca(IK_LENGTH); mk = chunk_alloca(MK_LENGTH); identity = id->get_encoding(id); - + /* MK = SHA1( Identity | IK | CK ) */ f3(this, this->k, this->rand, ck.ptr); f4(this, this->k, this->rand, ik.ptr); @@ -618,7 +618,7 @@ static bool derive_keys(private_eap_aka_t *this, identification_t *id) tmp = chunk_cata("ccc", identity, ik, ck); DBG3(DBG_IKE, "Identity|IK|CK %B", &tmp); this->sha1->get_hash(this->sha1, tmp, mk.ptr); - + /* K_encr | K_auth | MSK | EMSK = prf(0) | prf(0) * FIPS PRF has 320 bit block size, we need 160 byte for keys * => run prf four times */ @@ -694,9 +694,9 @@ static aka_attribute_t read_attribute(chunk_t *data, chunk_t *attr_data) { aka_attribute_t attribute; size_t length; - + DBG3(DBG_IKE, "reading attribute from %B", data); - + if (data->len < 2) { return AT_END; @@ -733,7 +733,7 @@ static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code va_list args; aka_attribute_t attr; u_int8_t *mac_pos = NULL; - + /* write EAP header, skip length bytes */ *pos.ptr++ = code; *pos.ptr++ = identifier; @@ -745,18 +745,18 @@ static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code *pos.ptr++ = 0; *pos.ptr++ = 0; pos.len -= 4; - + va_start(args, type); while ((attr = va_arg(args, aka_attribute_t)) != AT_END) { chunk_t data = va_arg(args, chunk_t); - + DBG3(DBG_IKE, "building %N %B", aka_attribute_names, attr, &data); - + /* write attribute header */ *pos.ptr++ = attr; pos.len--; - + switch (attr) { case AT_RES: @@ -804,11 +804,11 @@ static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code } } va_end(args); - + /* calculate message length, write into header */ message.len = pos.ptr - message.ptr; *(u_int16_t*)(message.ptr + 2) = htons(message.len); - + /* create MAC if AT_MAC attribte was included */ if (mac_pos) { @@ -818,10 +818,10 @@ static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code this->signer->get_signature(this->signer, message, mac_pos); DBG3(DBG_IKE, "is %b", mac_pos, AT_MAC_LENGTH); } - + /* payload constructor takes data with some bytes skipped */ payload = eap_payload_create_data(message); - + DBG3(DBG_IKE, "created EAP message %B", &message); return payload; } @@ -832,7 +832,7 @@ static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code static u_char get_identifier() { u_char id; - + do { id = random(); } while (!id); @@ -847,12 +847,12 @@ static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, { rng_t *rng; chunk_t mac, ak, autn; - + mac = chunk_alloca(MAC_LENGTH); ak = chunk_alloca(AK_LENGTH); chunk_free(&this->rand); chunk_free(&this->xres); - + /* generate RAND: * we use a registered RNG, not f0() proposed in S.S0055 */ @@ -864,16 +864,16 @@ static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, } rng->allocate_bytes(rng, RAND_LENGTH, &this->rand); rng->destroy(rng); - + # ifdef TEST_VECTORS /* Test vector for RAND */ u_int8_t test_rand[] = { 0x4b,0x05,0x2b,0x20,0xe2,0xa0,0x6c,0x8f, 0xf7,0x00,0xda,0x51,0x2b,0x4e,0x11,0x1e, }; - memcpy(this->rand.ptr, test_rand, this->rand.len); + memcpy(this->rand.ptr, test_rand, this->rand.len); # endif /* TEST_VECTORS */ - + /* Get the shared key K: */ if (load_key(this->server, this->peer, &this->k) != SUCCESS) { @@ -881,7 +881,7 @@ static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, "with EAP-AKA", this->server, this->peer); return FAILED; } - + # ifdef TEST_VECTORS /* Test vector for K */ u_int8_t test_k[] = { @@ -890,26 +890,26 @@ static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, }; memcpy(this->k.ptr, test_k, this->k.len); # endif /* TEST_VECTORS */ - + /* generate MAC */ f1(this, this->k, this->rand, sqn, amf, mac.ptr); - + /* generate AK */ f5(this, this->k, this->rand, ak.ptr); - + /* precalculate XRES as expected from client */ this->xres = chunk_alloc(RES_LENGTH); f2(this, this->k, this->rand, this->xres.ptr); - + /* calculate AUTN = (SQN xor AK) || AMF || MAC */ autn = chunk_cata("ccc", sqn, amf, mac); memxor(autn.ptr, ak.ptr, ak.len); DBG3(DBG_IKE, "AUTN %B", &autn); - - + + /* derive K_encr, K_auth, MSK, EMSK */ derive_keys(this, this->peer); - + /* build payload */ *out = build_aka_payload(this, EAP_REQUEST, get_identifier(), AKA_CHALLENGE, AT_RAND, this->rand, AT_AUTN, autn, AT_MAC, @@ -923,17 +923,17 @@ static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, static status_t server_initiate(private_eap_aka_t *this, eap_payload_t **out) { chunk_t sqn = chunk_alloca(SQN_LENGTH); - + /* we use an offset of 3 minutes to tolerate clock inaccuracy * without the need to synchronize sequence numbers */ update_sqn(sqn.ptr, 180); - + # ifdef TEST_VECTORS /* Test vector for SQN */ u_int8_t test_sqn[] = {0x00,0x00,0x00,0x00,0x00,0x01}; - memcpy(sqn.ptr, test_sqn, sqn.len); + memcpy(sqn.ptr, test_sqn, sqn.len); # endif /* TEST_VECTORS */ - + return server_initiate_challenge(this, sqn, out); } @@ -942,11 +942,11 @@ static status_t server_process_synchronize(private_eap_aka_t *this, { chunk_t attr, auts = chunk_empty, pos, message, macs, xmacs, sqn, aks, amf; u_int i; - + message = in->get_data(in); pos = message; read_header(&pos); - + /* iterate over attributes */ while (TRUE) { @@ -971,19 +971,19 @@ static status_t server_process_synchronize(private_eap_aka_t *this, } break; } - + if (auts.len != AUTS_LENGTH) { DBG1(DBG_IKE, "synchronization request didn't contain useable AUTS"); return FAILED; } - + chunk_split(auts, "mm", SQN_LENGTH, &sqn, MAC_LENGTH, &macs); aks = chunk_alloca(AK_LENGTH); f5star(this, this->k, this->rand, aks.ptr); /* decrypt serial number by XORing AKS */ memxor(sqn.ptr, aks.ptr, aks.len); - + /* verify MACS */ xmacs = chunk_alloca(MAC_LENGTH); amf = chunk_alloca(AMF_LENGTH); @@ -996,7 +996,7 @@ static status_t server_process_synchronize(private_eap_aka_t *this, DBG3(DBG_IKE, "MACS %B XMACS %B", &macs, &xmacs); return FAILED; } - + /* retry the challenge with the received SQN + 1*/ for (i = SQN_LENGTH - 1; i >= 0; i--) { @@ -1014,11 +1014,11 @@ static status_t server_process_synchronize(private_eap_aka_t *this, static status_t server_process_challenge(private_eap_aka_t *this, eap_payload_t *in) { chunk_t attr, res = chunk_empty, at_mac = chunk_empty, pos, message; - + message = in->get_data(in); pos = message; read_header(&pos); - + /* iterate over attributes */ while (TRUE) { @@ -1055,7 +1055,7 @@ static status_t server_process_challenge(private_eap_aka_t *this, eap_payload_t } break; } - + /* verify EAP message MAC AT_MAC */ { this->signer->set_key(this->signer, this->k_auth); @@ -1067,7 +1067,7 @@ static status_t server_process_challenge(private_eap_aka_t *this, eap_payload_t return FAILED; } } - + /* compare received RES against stored precalculated XRES */ if (!chunk_equals(res, this->xres)) { @@ -1086,12 +1086,12 @@ static status_t server_process(private_eap_aka_t *this, { chunk_t message; aka_subtype_t type; - + message = in->get_data(in); type = read_header(&message); - + DBG3(DBG_IKE, "received EAP message %B", &message); - + switch (type) { case AKA_CHALLENGE: @@ -1128,19 +1128,19 @@ static status_t peer_process_challenge(private_eap_aka_t *this, chunk_t autn = chunk_empty, at_mac = chunk_empty; chunk_t ak, sqn, sqn_ak, mac, xmac, res, amf, message, pos; u_int8_t identifier; - + ak = chunk_alloca(AK_LENGTH); xmac = chunk_alloca(MAC_LENGTH); res = chunk_alloca(RES_LENGTH); chunk_free(&this->rand); - + message = in->get_data(in); pos = message; read_header(&pos); identifier = in->get_identifier(in); - + DBG3(DBG_IKE, "reading attributes from %B", &pos); - + /* iterate over attributes */ while (TRUE) { @@ -1178,7 +1178,7 @@ static status_t peer_process_challenge(private_eap_aka_t *this, } break; } - + if (this->rand.len != RAND_LENGTH || autn.len != AUTN_LENGTH) { /* required attributes wrong/not found, abort */ @@ -1188,11 +1188,11 @@ static status_t peer_process_challenge(private_eap_aka_t *this, aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); return NEED_MORE; } - + DBG3(DBG_IKE, "using autn %B", &autn); /* split up AUTN = SQN xor AK | AMF | MAC */ chunk_split(autn, "mmm", SQN_LENGTH, &sqn_ak, AMF_LENGTH, &amf, MAC_LENGTH, &mac); - + /* Get the shared key K: */ chunk_free(&this->k); if (load_key(this->peer, this->server, &this->k) != SUCCESS) @@ -1213,19 +1213,19 @@ static status_t peer_process_challenge(private_eap_aka_t *this, }; memcpy(this->k.ptr, test_k, this->k.len); # endif /* TEST_VECTORS */ - + /* calculate anonymity key AK */ f5(this, this->k, this->rand, ak.ptr); DBG3(DBG_IKE, "using rand %B", &this->rand); DBG3(DBG_IKE, "using ak %B", &ak); /* XOR AK into SQN to decrypt it */ - + sqn = chunk_clonea(sqn_ak); - + DBG3(DBG_IKE, "using ak xor sqn %B", &sqn_ak); memxor(sqn.ptr, ak.ptr, sqn.len); DBG3(DBG_IKE, "using sqn %B", &sqn); - + /* calculate expected MAC and compare against received one */ f1(this, this->k, this->rand, sqn, amf, xmac.ptr); if (!chunk_equals(mac, xmac)) @@ -1243,13 +1243,13 @@ static status_t peer_process_challenge(private_eap_aka_t *this, { /* sequence number invalid. send AUTS */ chunk_t auts, macs, aks, amf; - + macs = chunk_alloca(MAC_LENGTH); aks = chunk_alloca(AK_LENGTH); amf = chunk_alloca(AMF_LENGTH); - + /* AMF is set to zero in AKA_SYNCHRONIZATION_FAILURE */ - memset(amf.ptr, 0, amf.len); + memset(amf.ptr, 0, amf.len); /* AKS = f5*(RAND) */ f5star(this, this->k, this->rand, aks.ptr); /* MACS = f1*(RAND) */ @@ -1257,7 +1257,7 @@ static status_t peer_process_challenge(private_eap_aka_t *this, /* AUTS = SQN xor AKS | MACS */ memxor(aks.ptr, peer_sqn.ptr, aks.len); auts = chunk_cata("cc", aks, macs); - + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_SYNCHRONIZATION_FAILURE, AT_AUTS, auts, AT_END); @@ -1270,7 +1270,7 @@ static status_t peer_process_challenge(private_eap_aka_t *this, /* derive K_encr, K_auth, MSK, EMSK */ derive_keys(this, this->peer); - + /* verify EAP message MAC AT_MAC */ DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message); DBG3(DBG_IKE, "using key %B", &this->k_auth); @@ -1284,13 +1284,13 @@ static status_t peer_process_challenge(private_eap_aka_t *this, AT_CLIENT_ERROR_CODE, 0); return NEED_MORE; } - + /* update stored SQN to the received one */ memcpy(peer_sqn.ptr, sqn.ptr, sqn.len); - + /* calculate RES */ f2(this, this->k, this->rand, res.ptr); - + /* build response */ *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CHALLENGE, AT_RES, res, AT_MAC, chunk_empty, AT_END); @@ -1305,14 +1305,14 @@ static status_t peer_process_notification(private_eap_aka_t *this, { chunk_t message, pos, attr; u_int8_t identifier; - + message = in->get_data(in); pos = message; read_header(&pos); identifier = in->get_identifier(in); - + DBG3(DBG_IKE, "reading attributes from %B", &pos); - + /* iterate over attributes */ while (TRUE) { @@ -1324,7 +1324,7 @@ static status_t peer_process_notification(private_eap_aka_t *this, case AT_NOTIFICATION: { u_int16_t code; - + if (attr.len != 2) { DBG1(DBG_IKE, "received invalid AKA notification, ignored"); @@ -1333,7 +1333,7 @@ static status_t peer_process_notification(private_eap_aka_t *this, code = ntohs(*(u_int16_t*)attr.ptr); switch (code) { - case 0: + case 0: DBG1(DBG_IKE, "received AKA notification 'general " "failure after authentication' (%d)", code); return FAILED; @@ -1387,13 +1387,13 @@ static status_t peer_process(private_eap_aka_t *this, aka_subtype_t type; chunk_t message; u_int8_t identifier; - + message = in->get_data(in); type = read_header(&message); identifier = in->get_identifier(in); - + DBG3(DBG_IKE, "received EAP message %B", &message); - + switch (type) { case AKA_CHALLENGE: @@ -1483,14 +1483,14 @@ static private_eap_aka_t *eap_aka_create_generic(identification_t *server, identification_t *peer) { private_eap_aka_t *this = malloc_thing(private_eap_aka_t); - + this->public.eap_method_interface.initiate = NULL; this->public.eap_method_interface.process = NULL; this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; - + /* private data */ this->server = server->clone(server); this->peer = peer->clone(peer); @@ -1501,7 +1501,7 @@ static private_eap_aka_t *eap_aka_create_generic(identification_t *server, this->xres = chunk_empty; this->k = chunk_empty; this->rand = chunk_empty; - + this->sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA1_128); this->prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160); @@ -1526,7 +1526,7 @@ static private_eap_aka_t *eap_aka_create_generic(identification_t *server, eap_aka_t *eap_aka_create_server(identification_t *server, identification_t *peer) { private_eap_aka_t *this = eap_aka_create_generic(server, peer); - + if (this) { this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate; @@ -1541,12 +1541,12 @@ eap_aka_t *eap_aka_create_server(identification_t *server, identification_t *pee eap_aka_t *eap_aka_create_peer(identification_t *server, identification_t *peer) { private_eap_aka_t *this = eap_aka_create_generic(server, peer); - + if (this) { this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate; this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process; } - return (eap_aka_t*)this; + return (eap_aka_t*)this; } |