diff options
Diffstat (limited to 'contrib/wpa_supplicant/eap_aka.c')
-rw-r--r-- | contrib/wpa_supplicant/eap_aka.c | 342 |
1 files changed, 173 insertions, 169 deletions
diff --git a/contrib/wpa_supplicant/eap_aka.c b/contrib/wpa_supplicant/eap_aka.c index b05cc72..a8b56ca 100644 --- a/contrib/wpa_supplicant/eap_aka.c +++ b/contrib/wpa_supplicant/eap_aka.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / EAP-AKA (draft-arkko-pppext-eap-aka-12.txt) - * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * EAP peer method: EAP-AKA (RFC 4187) + * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,46 +12,26 @@ * See README and COPYING for more details. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> +#include "includes.h" #include "common.h" #include "eap_i.h" -#include "wpa_supplicant.h" -#include "config_ssid.h" #include "crypto.h" #include "pcsc_funcs.h" #include "eap_sim_common.h" -/* EAP-AKA Subtypes */ -#define EAP_AKA_SUBTYPE_CHALLENGE 1 -#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2 -#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4 -#define EAP_AKA_SUBTYPE_IDENTITY 5 -#define EAP_AKA_SUBTYPE_NOTIFICATION 12 -#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13 -#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14 - -/* AT_CLIENT_ERROR_CODE error codes */ -#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0 - -#define AKA_AUTS_LEN 14 -#define RES_MAX_LEN 16 -#define IK_LEN 16 -#define CK_LEN 16 -#define EAP_AKA_MAX_FAST_REAUTHS 1000 struct eap_aka_data { - u8 ik[IK_LEN], ck[CK_LEN], res[RES_MAX_LEN]; + u8 ik[EAP_AKA_IK_LEN], ck[EAP_AKA_CK_LEN], res[EAP_AKA_RES_MAX_LEN]; size_t res_len; u8 nonce_s[EAP_SIM_NONCE_S_LEN]; u8 mk[EAP_SIM_MK_LEN]; u8 k_aut[EAP_SIM_K_AUT_LEN]; u8 k_encr[EAP_SIM_K_ENCR_LEN]; u8 msk[EAP_SIM_KEYING_DATA_LEN]; - u8 rand[AKA_RAND_LEN], autn[AKA_AUTN_LEN]; - u8 auts[AKA_AUTS_LEN]; + u8 emsk[EAP_EMSK_LEN]; + u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN]; + u8 auts[EAP_AKA_AUTS_LEN]; int num_id_req, num_notification; u8 *pseudonym; @@ -69,10 +49,9 @@ struct eap_aka_data { static void * eap_aka_init(struct eap_sm *sm) { struct eap_aka_data *data; - data = malloc(sizeof(*data)); + data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; - memset(data, 0, sizeof(*data)); data->state = CONTINUE; @@ -84,10 +63,10 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv) { struct eap_aka_data *data = priv; if (data) { - free(data->pseudonym); - free(data->reauth_id); - free(data->last_eap_identity); - free(data); + os_free(data->pseudonym); + os_free(data->reauth_id); + os_free(data->last_eap_identity); + os_free(data); } } @@ -102,45 +81,34 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data) #else /* PCSC_FUNCS */ /* These hardcoded Kc and SRES values are used for testing. * Could consider making them configurable. */ - memset(data->res, '2', RES_MAX_LEN); - data->res_len = 16; - memset(data->ik, '3', IK_LEN); - memset(data->ck, '4', CK_LEN); + os_memset(data->res, '2', EAP_AKA_RES_MAX_LEN); + data->res_len = EAP_AKA_RES_MAX_LEN; + os_memset(data->ik, '3', EAP_AKA_IK_LEN); + os_memset(data->ck, '4', EAP_AKA_CK_LEN); { - u8 autn[AKA_AUTN_LEN]; - memset(autn, '1', AKA_AUTN_LEN); - if (memcmp(autn, data->autn, AKA_AUTN_LEN) != 0) { + u8 autn[EAP_AKA_AUTN_LEN]; + os_memset(autn, '1', EAP_AKA_AUTN_LEN); + if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) { wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match " "with expected value"); return -1; } } +#if 0 + { + static int test_resync = 1; + if (test_resync) { + /* Test Resynchronization */ + test_resync = 0; + return -2; + } + } +#endif return 0; #endif /* PCSC_FUNCS */ } -static void eap_aka_derive_mk(struct eap_aka_data *data, - const u8 *identity, size_t identity_len) -{ - const u8 *addr[3]; - size_t len[3]; - - addr[0] = identity; - len[0] = identity_len; - addr[1] = data->ik; - len[1] = IK_LEN; - addr[2] = data->ck; - len[2] = CK_LEN; - - /* MK = SHA1(Identity|IK|CK) */ - sha1_vector(3, addr, len, data->mk); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", data->ik, IK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", data->ck, CK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", data->mk, EAP_SIM_MK_LEN); -} - - #define CLEAR_PSEUDONYM 0x01 #define CLEAR_REAUTH_ID 0x02 #define CLEAR_EAP_ID 0x04 @@ -152,17 +120,17 @@ static void eap_aka_clear_identities(struct eap_aka_data *data, int id) id & CLEAR_REAUTH_ID ? " reauth_id" : "", id & CLEAR_EAP_ID ? " eap_id" : ""); if (id & CLEAR_PSEUDONYM) { - free(data->pseudonym); + os_free(data->pseudonym); data->pseudonym = NULL; data->pseudonym_len = 0; } if (id & CLEAR_REAUTH_ID) { - free(data->reauth_id); + os_free(data->reauth_id); data->reauth_id = NULL; data->reauth_id_len = 0; } if (id & CLEAR_EAP_ID) { - free(data->last_eap_identity); + os_free(data->last_eap_identity); data->last_eap_identity = NULL; data->last_eap_identity_len = 0; } @@ -173,15 +141,15 @@ static int eap_aka_learn_ids(struct eap_aka_data *data, struct eap_sim_attrs *attr) { if (attr->next_pseudonym) { - free(data->pseudonym); - data->pseudonym = malloc(attr->next_pseudonym_len); + os_free(data->pseudonym); + data->pseudonym = os_malloc(attr->next_pseudonym_len); if (data->pseudonym == NULL) { wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for " "next pseudonym"); return -1; } - memcpy(data->pseudonym, attr->next_pseudonym, - attr->next_pseudonym_len); + os_memcpy(data->pseudonym, attr->next_pseudonym, + attr->next_pseudonym_len); data->pseudonym_len = attr->next_pseudonym_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: (encr) AT_NEXT_PSEUDONYM", @@ -190,15 +158,15 @@ static int eap_aka_learn_ids(struct eap_aka_data *data, } if (attr->next_reauth_id) { - free(data->reauth_id); - data->reauth_id = malloc(attr->next_reauth_id_len); + os_free(data->reauth_id); + data->reauth_id = os_malloc(attr->next_reauth_id_len); if (data->reauth_id == NULL) { wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for " "next reauth_id"); return -1; } - memcpy(data->reauth_id, attr->next_reauth_id, - attr->next_reauth_id_len); + os_memcpy(data->reauth_id, attr->next_reauth_id, + attr->next_reauth_id_len); data->reauth_id_len = attr->next_reauth_id_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: (encr) AT_NEXT_REAUTH_ID", @@ -210,7 +178,7 @@ static int eap_aka_learn_ids(struct eap_aka_data *data, } -static u8 * eap_aka_client_error(struct eap_sm *sm, struct eap_aka_data *data, +static u8 * eap_aka_client_error(struct eap_aka_data *data, const struct eap_hdr *req, size_t *respDataLen, int err) { @@ -227,8 +195,7 @@ static u8 * eap_aka_client_error(struct eap_sm *sm, struct eap_aka_data *data, } -static u8 * eap_aka_authentication_reject(struct eap_sm *sm, - struct eap_aka_data *data, +static u8 * eap_aka_authentication_reject(struct eap_aka_data *data, const struct eap_hdr *req, size_t *respDataLen) { @@ -247,14 +214,12 @@ static u8 * eap_aka_authentication_reject(struct eap_sm *sm, } -static u8 * eap_aka_synchronization_failure(struct eap_sm *sm, - struct eap_aka_data *data, +static u8 * eap_aka_synchronization_failure(struct eap_aka_data *data, const struct eap_hdr *req, size_t *respDataLen) { struct eap_sim_msg *msg; - data->state = FAILURE; data->num_id_req = 0; data->num_notification = 0; @@ -264,7 +229,8 @@ static u8 * eap_aka_synchronization_failure(struct eap_sm *sm, EAP_TYPE_AKA, EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE); wpa_printf(MSG_DEBUG, " AT_AUTS"); - eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts, AKA_AUTS_LEN); + eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts, + EAP_AKA_AUTS_LEN); return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0); } @@ -275,8 +241,7 @@ static u8 * eap_aka_response_identity(struct eap_sm *sm, size_t *respDataLen, enum eap_sim_id_req id_req) { - struct wpa_ssid *config = eap_get_config(sm); - u8 *identity = NULL; + const u8 *identity = NULL; size_t identity_len = 0; struct eap_sim_msg *msg; @@ -290,11 +255,12 @@ static u8 * eap_aka_response_identity(struct eap_sm *sm, identity = data->pseudonym; identity_len = data->pseudonym_len; eap_aka_clear_identities(data, CLEAR_REAUTH_ID); - } else if (id_req != NO_ID_REQ && config && config->identity) { - identity = config->identity; - identity_len = config->identity_len; - eap_aka_clear_identities(data, - CLEAR_PSEUDONYM | CLEAR_REAUTH_ID); + } else if (id_req != NO_ID_REQ) { + identity = eap_get_config_identity(sm, &identity_len); + if (identity) { + eap_aka_clear_identities(data, CLEAR_PSEUDONYM | + CLEAR_REAUTH_ID); + } } if (id_req != NO_ID_REQ) eap_aka_clear_identities(data, CLEAR_EAP_ID); @@ -315,8 +281,7 @@ static u8 * eap_aka_response_identity(struct eap_sm *sm, } -static u8 * eap_aka_response_challenge(struct eap_sm *sm, - struct eap_aka_data *data, +static u8 * eap_aka_response_challenge(struct eap_aka_data *data, const struct eap_hdr *req, size_t *respDataLen) { @@ -335,10 +300,10 @@ static u8 * eap_aka_response_challenge(struct eap_sm *sm, } -static u8 * eap_aka_response_reauth(struct eap_sm *sm, - struct eap_aka_data *data, +static u8 * eap_aka_response_reauth(struct eap_aka_data *data, const struct eap_hdr *req, - size_t *respDataLen, int counter_too_small) + size_t *respDataLen, int counter_too_small, + const u8 *nonce_s) { struct eap_sim_msg *msg; unsigned int counter; @@ -370,13 +335,12 @@ static u8 * eap_aka_response_reauth(struct eap_sm *sm, } wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, respDataLen, data->k_aut, data->nonce_s, + return eap_sim_msg_finish(msg, respDataLen, data->k_aut, nonce_s, EAP_SIM_NONCE_S_LEN); } -static u8 * eap_aka_response_notification(struct eap_sm *sm, - struct eap_aka_data *data, +static u8 * eap_aka_response_notification(struct eap_aka_data *data, const struct eap_hdr *req, size_t *respDataLen, u16 notification) @@ -388,8 +352,6 @@ static u8 * eap_aka_response_notification(struct eap_sm *sm, req->identifier); msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier, EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION); - wpa_printf(MSG_DEBUG, " AT_NOTIFICATION"); - eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, notification, NULL, 0); if (k_aut && data->reauth) { wpa_printf(MSG_DEBUG, " AT_IV"); wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); @@ -417,7 +379,6 @@ static u8 * eap_aka_response_notification(struct eap_sm *sm, static u8 * eap_aka_process_identity(struct eap_sm *sm, struct eap_aka_data *data, const struct eap_hdr *req, - size_t reqDataLen, size_t *respDataLen, struct eap_sim_attrs *attr) { @@ -448,7 +409,7 @@ static u8 * eap_aka_process_identity(struct eap_sm *sm, if (id_error) { wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests " "used within one authentication"); - return eap_aka_client_error(sm, data, req, respDataLen, + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } @@ -464,8 +425,7 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm, size_t *respDataLen, struct eap_sim_attrs *attr) { - struct wpa_ssid *config = eap_get_config(sm); - u8 *identity; + const u8 *identity; size_t identity_len; int res; struct eap_sim_attrs eattr; @@ -478,26 +438,24 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm, !attr->mac ? " AT_MAC" : "", !attr->rand ? " AT_RAND" : "", !attr->autn ? " AT_AUTN" : ""); - return eap_aka_client_error(sm, data, req, respDataLen, + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } - memcpy(data->rand, attr->rand, AKA_RAND_LEN); - memcpy(data->autn, attr->autn, AKA_AUTN_LEN); + os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN); + os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN); res = eap_aka_umts_auth(sm, data); if (res == -1) { wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication " "failed (AUTN)"); - return eap_aka_authentication_reject(sm, data, req, - respDataLen); + return eap_aka_authentication_reject(data, req, respDataLen); } else if (res == -2) { wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication " "failed (AUTN seq# -> AUTS)"); - return eap_aka_synchronization_failure(sm, data, req, - respDataLen); + return eap_aka_synchronization_failure(data, req, respDataLen); } else if (res) { wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed"); - return eap_aka_client_error(sm, data, req, respDataLen, + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } if (data->last_eap_identity) { @@ -506,19 +464,19 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm, } else if (data->pseudonym) { identity = data->pseudonym; identity_len = data->pseudonym_len; - } else { - identity = config->identity; - identity_len = config->identity_len; - } + } else + identity = eap_get_config_identity(sm, &identity_len); wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK " "derivation", identity, identity_len); - eap_aka_derive_mk(data, identity, identity_len); - eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk); + eap_aka_derive_mk(identity, identity_len, data->ik, data->ck, + data->mk); + eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, + data->emsk); if (eap_sim_verify_mac(data->k_aut, (const u8 *) req, reqDataLen, attr->mac, (u8 *) "", 0)) { wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " "used invalid AT_MAC"); - return eap_aka_client_error(sm, data, req, respDataLen, + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } @@ -535,11 +493,11 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm, &eattr, 0); if (decrypted == NULL) { return eap_aka_client_error( - sm, data, req, respDataLen, + data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } eap_aka_learn_ids(data, &eattr); - free(decrypted); + os_free(decrypted); } if (data->state != FAILURE) @@ -547,17 +505,15 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm, data->num_id_req = 0; data->num_notification = 0; - /* draft-arkko-pppext-eap-aka-12.txt specifies that counter - * is initialized to one after fullauth, but initializing it to - * zero makes it easier to implement reauth verification. */ + /* RFC 4187 specifies that counter is initialized to one after + * fullauth, but initializing it to zero makes it easier to implement + * reauth verification. */ data->counter = 0; - return eap_aka_response_challenge(sm, data, req, respDataLen); + return eap_aka_response_challenge(data, req, respDataLen); } static int eap_aka_process_notification_reauth(struct eap_aka_data *data, - const struct eap_hdr *req, - size_t reqDataLen, struct eap_sim_attrs *attr) { struct eap_sim_attrs eattr; @@ -578,15 +534,15 @@ static int eap_aka_process_notification_reauth(struct eap_aka_data *data, return -1; } - if (eattr.counter != data->counter) { + if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) { wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification " "message does not match with counter in reauth " "message"); - free(decrypted); + os_free(decrypted); return -1; } - free(decrypted); + os_free(decrypted); return 0; } @@ -610,7 +566,7 @@ static int eap_aka_process_notification_auth(struct eap_aka_data *data, } if (data->reauth && - eap_aka_process_notification_reauth(data, req, reqDataLen, attr)) { + eap_aka_process_notification_reauth(data, attr)) { wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification " "message after reauth"); return -1; @@ -631,20 +587,20 @@ static u8 * eap_aka_process_notification(struct eap_sm *sm, if (data->num_notification > 0) { wpa_printf(MSG_INFO, "EAP-AKA: too many notification " "rounds (only one allowed)"); - return eap_aka_client_error(sm, data, req, respDataLen, + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } data->num_notification++; if (attr->notification == -1) { wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in " "Notification message"); - return eap_aka_client_error(sm, data, req, respDataLen, + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } if ((attr->notification & 0x4000) == 0 && eap_aka_process_notification_auth(data, req, reqDataLen, attr)) { - return eap_aka_client_error(sm, data, req, respDataLen, + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } @@ -652,7 +608,7 @@ static u8 * eap_aka_process_notification(struct eap_sm *sm, if (attr->notification >= 0 && attr->notification < 32768) { data->state = FAILURE; } - return eap_aka_response_notification(sm, data, req, respDataLen, + return eap_aka_response_notification(data, req, respDataLen, attr->notification); } @@ -672,7 +628,7 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm, if (data->reauth_id == NULL) { wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying " "reauthentication, but no reauth_id available"); - return eap_aka_client_error(sm, data, req, respDataLen, + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } @@ -681,14 +637,14 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm, attr->mac, (u8 *) "", 0)) { wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " "did not have valid AT_MAC"); - return eap_aka_client_error(sm, data, req, respDataLen, + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } if (attr->encr_data == NULL || attr->iv == NULL) { wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " "message did not include encrypted data"); - return eap_aka_client_error(sm, data, req, respDataLen, + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } @@ -698,7 +654,7 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm, if (decrypted == NULL) { wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " "data from reauthentication message"); - return eap_aka_client_error(sm, data, req, respDataLen, + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } @@ -706,37 +662,48 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm, wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet", !eattr.nonce_s ? " AT_NONCE_S" : "", eattr.counter < 0 ? " AT_COUNTER" : ""); - free(decrypted); - return eap_aka_client_error(sm, data, req, respDataLen, + os_free(decrypted); + return eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } - if (eattr.counter <= data->counter) { + if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) { + u8 *res; wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter " "(%d <= %d)", eattr.counter, data->counter); data->counter_too_small = eattr.counter; + + eap_sim_derive_keys_reauth(eattr.counter, data->reauth_id, + data->reauth_id_len, eattr.nonce_s, + data->mk, NULL, NULL); + /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current * reauth_id must not be used to start a new reauthentication. * However, since it was used in the last EAP-Response-Identity * packet, it has to saved for the following fullauth to be * used in MK derivation. */ - free(data->last_eap_identity); + os_free(data->last_eap_identity); data->last_eap_identity = data->reauth_id; data->last_eap_identity_len = data->reauth_id_len; data->reauth_id = NULL; data->reauth_id_len = 0; - free(decrypted); - return eap_aka_response_reauth(sm, data, req, respDataLen, 1); + + res = eap_aka_response_reauth(data, req, respDataLen, 1, + eattr.nonce_s); + os_free(decrypted); + + return res; } data->counter = eattr.counter; - memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN); + os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN); wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S", data->nonce_s, EAP_SIM_NONCE_S_LEN); eap_sim_derive_keys_reauth(data->counter, data->reauth_id, data->reauth_id_len, - data->nonce_s, data->mk, data->msk); + data->nonce_s, data->mk, data->msk, + data->emsk); eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); eap_aka_learn_ids(data, &eattr); @@ -750,8 +717,9 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm, "fast reauths performed - force fullauth"); eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); } - free(decrypted); - return eap_aka_response_reauth(sm, data, req, respDataLen, 0); + os_free(decrypted); + return eap_aka_response_reauth(data, req, respDataLen, 0, + data->nonce_s); } @@ -761,7 +729,6 @@ static u8 * eap_aka_process(struct eap_sm *sm, void *priv, size_t *respDataLen) { struct eap_aka_data *data = priv; - struct wpa_ssid *config = eap_get_config(sm); const struct eap_hdr *req; u8 subtype, *res; const u8 *pos; @@ -769,14 +736,15 @@ static u8 * eap_aka_process(struct eap_sm *sm, void *priv, size_t len; wpa_hexdump(MSG_DEBUG, "EAP-AKA: EAP data", reqData, reqDataLen); - if (config == NULL || config->identity == NULL) { + if (eap_get_config_identity(sm, &len) == NULL) { wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured"); - eap_sm_request_identity(sm, config); + eap_sm_request_identity(sm); ret->ignore = TRUE; return NULL; } - pos = eap_hdr_validate(EAP_TYPE_AKA, reqData, reqDataLen, &len); + pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_AKA, + reqData, reqDataLen, &len); if (pos == NULL || len < 1) { ret->ignore = TRUE; return NULL; @@ -794,14 +762,14 @@ static u8 * eap_aka_process(struct eap_sm *sm, void *priv, pos += 2; /* Reserved */ if (eap_sim_parse_attr(pos, reqData + len, &attr, 1, 0)) { - res = eap_aka_client_error(sm, data, req, respDataLen, + res = eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); goto done; } switch (subtype) { case EAP_AKA_SUBTYPE_IDENTITY: - res = eap_aka_process_identity(sm, data, req, len, + res = eap_aka_process_identity(sm, data, req, respDataLen, &attr); break; case EAP_AKA_SUBTYPE_CHALLENGE: @@ -818,12 +786,12 @@ static u8 * eap_aka_process(struct eap_sm *sm, void *priv, break; case EAP_AKA_SUBTYPE_CLIENT_ERROR: wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error"); - res = eap_aka_client_error(sm, data, req, respDataLen, + res = eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); break; default: wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype); - res = eap_aka_client_error(sm, data, req, respDataLen, + res = eap_aka_client_error(data, req, respDataLen, EAP_AKA_UNABLE_TO_PROCESS_PACKET); break; } @@ -834,7 +802,12 @@ done: ret->methodState = METHOD_DONE; } else if (data->state == SUCCESS) { ret->decision = DECISION_COND_SUCC; - ret->methodState = METHOD_DONE; + /* + * It is possible for the server to reply with AKA + * Notification, so we must allow the method to continue and + * not only accept EAP-Success at this point. + */ + ret->methodState = METHOD_MAY_CONT; } if (ret->methodState == METHOD_DONE) { @@ -903,28 +876,59 @@ static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len) if (data->state != SUCCESS) return NULL; - key = malloc(EAP_SIM_KEYING_DATA_LEN); + key = os_malloc(EAP_SIM_KEYING_DATA_LEN); if (key == NULL) return NULL; *len = EAP_SIM_KEYING_DATA_LEN; - memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); + os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); return key; } -const struct eap_method eap_method_aka = +static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len) { - .method = EAP_TYPE_AKA, - .name = "AKA", - .init = eap_aka_init, - .deinit = eap_aka_deinit, - .process = eap_aka_process, - .isKeyAvailable = eap_aka_isKeyAvailable, - .getKey = eap_aka_getKey, - .has_reauth_data = eap_aka_has_reauth_data, - .deinit_for_reauth = eap_aka_deinit_for_reauth, - .init_for_reauth = eap_aka_init_for_reauth, - .get_identity = eap_aka_get_identity, -}; + struct eap_aka_data *data = priv; + u8 *key; + + if (data->state != SUCCESS) + return NULL; + + key = os_malloc(EAP_EMSK_LEN); + if (key == NULL) + return NULL; + + *len = EAP_EMSK_LEN; + os_memcpy(key, data->emsk, EAP_EMSK_LEN); + + return key; +} + + +int eap_peer_aka_register(void) +{ + struct eap_method *eap; + int ret; + + eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, + EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA"); + if (eap == NULL) + return -1; + + eap->init = eap_aka_init; + eap->deinit = eap_aka_deinit; + eap->process = eap_aka_process; + eap->isKeyAvailable = eap_aka_isKeyAvailable; + eap->getKey = eap_aka_getKey; + eap->has_reauth_data = eap_aka_has_reauth_data; + eap->deinit_for_reauth = eap_aka_deinit_for_reauth; + eap->init_for_reauth = eap_aka_init_for_reauth; + eap->get_identity = eap_aka_get_identity; + eap->get_emsk = eap_aka_get_emsk; + + ret = eap_peer_method_register(eap); + if (ret) + eap_peer_method_free(eap); + return ret; +} |