16d49e1aeSJan Lentfer /*
23ff40c12SJohn Marino * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
33ff40c12SJohn Marino * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
76d49e1aeSJan Lentfer */
86d49e1aeSJan Lentfer
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer
116d49e1aeSJan Lentfer #include "common.h"
126d49e1aeSJan Lentfer #include "pcsc_funcs.h"
133ff40c12SJohn Marino #include "crypto/crypto.h"
143ff40c12SJohn Marino #include "crypto/sha1.h"
153ff40c12SJohn Marino #include "crypto/sha256.h"
163ff40c12SJohn Marino #include "crypto/milenage.h"
176d49e1aeSJan Lentfer #include "eap_common/eap_sim_common.h"
183ff40c12SJohn Marino #include "eap_config.h"
193ff40c12SJohn Marino #include "eap_i.h"
206d49e1aeSJan Lentfer
216d49e1aeSJan Lentfer
226d49e1aeSJan Lentfer struct eap_aka_data {
236d49e1aeSJan Lentfer u8 ik[EAP_AKA_IK_LEN], ck[EAP_AKA_CK_LEN], res[EAP_AKA_RES_MAX_LEN];
246d49e1aeSJan Lentfer size_t res_len;
256d49e1aeSJan Lentfer u8 nonce_s[EAP_SIM_NONCE_S_LEN];
266d49e1aeSJan Lentfer u8 mk[EAP_SIM_MK_LEN];
276d49e1aeSJan Lentfer u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
286d49e1aeSJan Lentfer u8 k_encr[EAP_SIM_K_ENCR_LEN];
296d49e1aeSJan Lentfer u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
306d49e1aeSJan Lentfer u8 msk[EAP_SIM_KEYING_DATA_LEN];
316d49e1aeSJan Lentfer u8 emsk[EAP_EMSK_LEN];
326d49e1aeSJan Lentfer u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN];
336d49e1aeSJan Lentfer u8 auts[EAP_AKA_AUTS_LEN];
34*a1157835SDaniel Fojt u8 reauth_mac[EAP_SIM_MAC_LEN];
356d49e1aeSJan Lentfer
366d49e1aeSJan Lentfer int num_id_req, num_notification;
376d49e1aeSJan Lentfer u8 *pseudonym;
386d49e1aeSJan Lentfer size_t pseudonym_len;
396d49e1aeSJan Lentfer u8 *reauth_id;
406d49e1aeSJan Lentfer size_t reauth_id_len;
416d49e1aeSJan Lentfer int reauth;
426d49e1aeSJan Lentfer unsigned int counter, counter_too_small;
436d49e1aeSJan Lentfer u8 *last_eap_identity;
446d49e1aeSJan Lentfer size_t last_eap_identity_len;
456d49e1aeSJan Lentfer enum {
46*a1157835SDaniel Fojt CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
476d49e1aeSJan Lentfer } state;
486d49e1aeSJan Lentfer
496d49e1aeSJan Lentfer struct wpabuf *id_msgs;
506d49e1aeSJan Lentfer int prev_id;
516d49e1aeSJan Lentfer int result_ind, use_result_ind;
52*a1157835SDaniel Fojt int use_pseudonym;
536d49e1aeSJan Lentfer u8 eap_method;
546d49e1aeSJan Lentfer u8 *network_name;
556d49e1aeSJan Lentfer size_t network_name_len;
566d49e1aeSJan Lentfer u16 kdf;
576d49e1aeSJan Lentfer int kdf_negotiation;
58*a1157835SDaniel Fojt u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX];
59*a1157835SDaniel Fojt size_t last_kdf_count;
60*a1157835SDaniel Fojt int error_code;
616d49e1aeSJan Lentfer };
626d49e1aeSJan Lentfer
636d49e1aeSJan Lentfer
646d49e1aeSJan Lentfer #ifndef CONFIG_NO_STDOUT_DEBUG
eap_aka_state_txt(int state)656d49e1aeSJan Lentfer static const char * eap_aka_state_txt(int state)
666d49e1aeSJan Lentfer {
676d49e1aeSJan Lentfer switch (state) {
686d49e1aeSJan Lentfer case CONTINUE:
696d49e1aeSJan Lentfer return "CONTINUE";
706d49e1aeSJan Lentfer case RESULT_SUCCESS:
716d49e1aeSJan Lentfer return "RESULT_SUCCESS";
726d49e1aeSJan Lentfer case SUCCESS:
736d49e1aeSJan Lentfer return "SUCCESS";
746d49e1aeSJan Lentfer case FAILURE:
756d49e1aeSJan Lentfer return "FAILURE";
766d49e1aeSJan Lentfer default:
776d49e1aeSJan Lentfer return "?";
786d49e1aeSJan Lentfer }
796d49e1aeSJan Lentfer }
806d49e1aeSJan Lentfer #endif /* CONFIG_NO_STDOUT_DEBUG */
816d49e1aeSJan Lentfer
826d49e1aeSJan Lentfer
eap_aka_state(struct eap_aka_data * data,int state)836d49e1aeSJan Lentfer static void eap_aka_state(struct eap_aka_data *data, int state)
846d49e1aeSJan Lentfer {
856d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
866d49e1aeSJan Lentfer eap_aka_state_txt(data->state),
876d49e1aeSJan Lentfer eap_aka_state_txt(state));
886d49e1aeSJan Lentfer data->state = state;
896d49e1aeSJan Lentfer }
906d49e1aeSJan Lentfer
916d49e1aeSJan Lentfer
eap_aka_init(struct eap_sm * sm)926d49e1aeSJan Lentfer static void * eap_aka_init(struct eap_sm *sm)
936d49e1aeSJan Lentfer {
946d49e1aeSJan Lentfer struct eap_aka_data *data;
956d49e1aeSJan Lentfer const char *phase1 = eap_get_config_phase1(sm);
963ff40c12SJohn Marino struct eap_peer_config *config = eap_get_config(sm);
976d49e1aeSJan Lentfer
986d49e1aeSJan Lentfer data = os_zalloc(sizeof(*data));
996d49e1aeSJan Lentfer if (data == NULL)
1006d49e1aeSJan Lentfer return NULL;
1016d49e1aeSJan Lentfer
1026d49e1aeSJan Lentfer data->eap_method = EAP_TYPE_AKA;
1036d49e1aeSJan Lentfer
104*a1157835SDaniel Fojt /* Zero is a valid error code, so we need to initialize */
105*a1157835SDaniel Fojt data->error_code = NO_EAP_METHOD_ERROR;
106*a1157835SDaniel Fojt
1076d49e1aeSJan Lentfer eap_aka_state(data, CONTINUE);
1086d49e1aeSJan Lentfer data->prev_id = -1;
1096d49e1aeSJan Lentfer
1106d49e1aeSJan Lentfer data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
1116d49e1aeSJan Lentfer
112*a1157835SDaniel Fojt data->use_pseudonym = !sm->init_phase2;
113*a1157835SDaniel Fojt if (config && config->anonymous_identity && data->use_pseudonym) {
1143ff40c12SJohn Marino data->pseudonym = os_malloc(config->anonymous_identity_len);
1153ff40c12SJohn Marino if (data->pseudonym) {
1163ff40c12SJohn Marino os_memcpy(data->pseudonym, config->anonymous_identity,
1173ff40c12SJohn Marino config->anonymous_identity_len);
1183ff40c12SJohn Marino data->pseudonym_len = config->anonymous_identity_len;
1193ff40c12SJohn Marino }
1203ff40c12SJohn Marino }
1213ff40c12SJohn Marino
1226d49e1aeSJan Lentfer return data;
1236d49e1aeSJan Lentfer }
1246d49e1aeSJan Lentfer
1256d49e1aeSJan Lentfer
1266d49e1aeSJan Lentfer #ifdef EAP_AKA_PRIME
eap_aka_prime_init(struct eap_sm * sm)1276d49e1aeSJan Lentfer static void * eap_aka_prime_init(struct eap_sm *sm)
1286d49e1aeSJan Lentfer {
1296d49e1aeSJan Lentfer struct eap_aka_data *data = eap_aka_init(sm);
1306d49e1aeSJan Lentfer if (data == NULL)
1316d49e1aeSJan Lentfer return NULL;
1326d49e1aeSJan Lentfer data->eap_method = EAP_TYPE_AKA_PRIME;
1336d49e1aeSJan Lentfer return data;
1346d49e1aeSJan Lentfer }
1356d49e1aeSJan Lentfer #endif /* EAP_AKA_PRIME */
1366d49e1aeSJan Lentfer
1376d49e1aeSJan Lentfer
eap_aka_clear_keys(struct eap_aka_data * data,int reauth)138*a1157835SDaniel Fojt static void eap_aka_clear_keys(struct eap_aka_data *data, int reauth)
139*a1157835SDaniel Fojt {
140*a1157835SDaniel Fojt if (!reauth) {
141*a1157835SDaniel Fojt os_memset(data->mk, 0, EAP_SIM_MK_LEN);
142*a1157835SDaniel Fojt os_memset(data->k_aut, 0, EAP_AKA_PRIME_K_AUT_LEN);
143*a1157835SDaniel Fojt os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN);
144*a1157835SDaniel Fojt os_memset(data->k_re, 0, EAP_AKA_PRIME_K_RE_LEN);
145*a1157835SDaniel Fojt }
146*a1157835SDaniel Fojt os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN);
147*a1157835SDaniel Fojt os_memset(data->emsk, 0, EAP_EMSK_LEN);
148*a1157835SDaniel Fojt os_memset(data->autn, 0, EAP_AKA_AUTN_LEN);
149*a1157835SDaniel Fojt os_memset(data->auts, 0, EAP_AKA_AUTS_LEN);
150*a1157835SDaniel Fojt }
151*a1157835SDaniel Fojt
152*a1157835SDaniel Fojt
eap_aka_deinit(struct eap_sm * sm,void * priv)1536d49e1aeSJan Lentfer static void eap_aka_deinit(struct eap_sm *sm, void *priv)
1546d49e1aeSJan Lentfer {
1556d49e1aeSJan Lentfer struct eap_aka_data *data = priv;
1566d49e1aeSJan Lentfer if (data) {
1576d49e1aeSJan Lentfer os_free(data->pseudonym);
1586d49e1aeSJan Lentfer os_free(data->reauth_id);
1596d49e1aeSJan Lentfer os_free(data->last_eap_identity);
1606d49e1aeSJan Lentfer wpabuf_free(data->id_msgs);
1616d49e1aeSJan Lentfer os_free(data->network_name);
162*a1157835SDaniel Fojt eap_aka_clear_keys(data, 0);
1636d49e1aeSJan Lentfer os_free(data);
1646d49e1aeSJan Lentfer }
1656d49e1aeSJan Lentfer }
1666d49e1aeSJan Lentfer
1676d49e1aeSJan Lentfer
eap_aka_ext_sim_req(struct eap_sm * sm,struct eap_aka_data * data)1683ff40c12SJohn Marino static int eap_aka_ext_sim_req(struct eap_sm *sm, struct eap_aka_data *data)
1693ff40c12SJohn Marino {
1703ff40c12SJohn Marino char req[200], *pos, *end;
1713ff40c12SJohn Marino
1723ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-AKA: Use external USIM processing");
1733ff40c12SJohn Marino pos = req;
1743ff40c12SJohn Marino end = pos + sizeof(req);
1753ff40c12SJohn Marino pos += os_snprintf(pos, end - pos, "UMTS-AUTH");
1763ff40c12SJohn Marino pos += os_snprintf(pos, end - pos, ":");
1773ff40c12SJohn Marino pos += wpa_snprintf_hex(pos, end - pos, data->rand, EAP_AKA_RAND_LEN);
1783ff40c12SJohn Marino pos += os_snprintf(pos, end - pos, ":");
179*a1157835SDaniel Fojt wpa_snprintf_hex(pos, end - pos, data->autn, EAP_AKA_AUTN_LEN);
1803ff40c12SJohn Marino
1813ff40c12SJohn Marino eap_sm_request_sim(sm, req);
1823ff40c12SJohn Marino return 1;
1833ff40c12SJohn Marino }
1843ff40c12SJohn Marino
1853ff40c12SJohn Marino
eap_aka_ext_sim_result(struct eap_sm * sm,struct eap_aka_data * data,struct eap_peer_config * conf)1863ff40c12SJohn Marino static int eap_aka_ext_sim_result(struct eap_sm *sm, struct eap_aka_data *data,
1873ff40c12SJohn Marino struct eap_peer_config *conf)
1883ff40c12SJohn Marino {
1893ff40c12SJohn Marino char *resp, *pos;
1903ff40c12SJohn Marino
1913ff40c12SJohn Marino wpa_printf(MSG_DEBUG,
1923ff40c12SJohn Marino "EAP-AKA: Use result from external USIM processing");
1933ff40c12SJohn Marino
1943ff40c12SJohn Marino resp = conf->external_sim_resp;
1953ff40c12SJohn Marino conf->external_sim_resp = NULL;
1963ff40c12SJohn Marino
1973ff40c12SJohn Marino if (os_strncmp(resp, "UMTS-AUTS:", 10) == 0) {
1983ff40c12SJohn Marino pos = resp + 10;
1993ff40c12SJohn Marino if (hexstr2bin(pos, data->auts, EAP_AKA_AUTS_LEN) < 0)
2003ff40c12SJohn Marino goto invalid;
2013ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: AUTS", data->auts,
2023ff40c12SJohn Marino EAP_AKA_AUTS_LEN);
2033ff40c12SJohn Marino os_free(resp);
2043ff40c12SJohn Marino return -2;
2053ff40c12SJohn Marino }
2063ff40c12SJohn Marino
2073ff40c12SJohn Marino if (os_strncmp(resp, "UMTS-AUTH:", 10) != 0) {
2083ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized external USIM processing response");
2093ff40c12SJohn Marino os_free(resp);
2103ff40c12SJohn Marino return -1;
2113ff40c12SJohn Marino }
2123ff40c12SJohn Marino
2133ff40c12SJohn Marino pos = resp + 10;
2143ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG, "EAP-AKA: RAND", data->rand, EAP_AKA_RAND_LEN);
2153ff40c12SJohn Marino
2163ff40c12SJohn Marino if (hexstr2bin(pos, data->ik, EAP_AKA_IK_LEN) < 0)
2173ff40c12SJohn Marino goto invalid;
2183ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", data->ik, EAP_AKA_IK_LEN);
2193ff40c12SJohn Marino pos += EAP_AKA_IK_LEN * 2;
2203ff40c12SJohn Marino if (*pos != ':')
2213ff40c12SJohn Marino goto invalid;
2223ff40c12SJohn Marino pos++;
2233ff40c12SJohn Marino
2243ff40c12SJohn Marino if (hexstr2bin(pos, data->ck, EAP_AKA_CK_LEN) < 0)
2253ff40c12SJohn Marino goto invalid;
2263ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", data->ck, EAP_AKA_CK_LEN);
2273ff40c12SJohn Marino pos += EAP_AKA_CK_LEN * 2;
2283ff40c12SJohn Marino if (*pos != ':')
2293ff40c12SJohn Marino goto invalid;
2303ff40c12SJohn Marino pos++;
2313ff40c12SJohn Marino
2323ff40c12SJohn Marino data->res_len = os_strlen(pos) / 2;
2333ff40c12SJohn Marino if (data->res_len > EAP_AKA_RES_MAX_LEN) {
2343ff40c12SJohn Marino data->res_len = 0;
2353ff40c12SJohn Marino goto invalid;
2363ff40c12SJohn Marino }
2373ff40c12SJohn Marino if (hexstr2bin(pos, data->res, data->res_len) < 0)
2383ff40c12SJohn Marino goto invalid;
2393ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: RES", data->res, data->res_len);
2403ff40c12SJohn Marino
2413ff40c12SJohn Marino os_free(resp);
2423ff40c12SJohn Marino return 0;
2433ff40c12SJohn Marino
2443ff40c12SJohn Marino invalid:
2453ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-AKA: Invalid external USIM processing UMTS-AUTH response");
2463ff40c12SJohn Marino os_free(resp);
2473ff40c12SJohn Marino return -1;
2483ff40c12SJohn Marino }
2493ff40c12SJohn Marino
2503ff40c12SJohn Marino
eap_aka_umts_auth(struct eap_sm * sm,struct eap_aka_data * data)2516d49e1aeSJan Lentfer static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
2526d49e1aeSJan Lentfer {
2536d49e1aeSJan Lentfer struct eap_peer_config *conf;
2546d49e1aeSJan Lentfer
2556d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: UMTS authentication algorithm");
2566d49e1aeSJan Lentfer
2576d49e1aeSJan Lentfer conf = eap_get_config(sm);
2586d49e1aeSJan Lentfer if (conf == NULL)
2596d49e1aeSJan Lentfer return -1;
2603ff40c12SJohn Marino
2613ff40c12SJohn Marino if (sm->external_sim) {
2623ff40c12SJohn Marino if (conf->external_sim_resp)
2633ff40c12SJohn Marino return eap_aka_ext_sim_result(sm, data, conf);
2643ff40c12SJohn Marino else
2653ff40c12SJohn Marino return eap_aka_ext_sim_req(sm, data);
2663ff40c12SJohn Marino }
2673ff40c12SJohn Marino
2686d49e1aeSJan Lentfer if (conf->pcsc) {
2696d49e1aeSJan Lentfer return scard_umts_auth(sm->scard_ctx, data->rand,
2706d49e1aeSJan Lentfer data->autn, data->res, &data->res_len,
2716d49e1aeSJan Lentfer data->ik, data->ck, data->auts);
2726d49e1aeSJan Lentfer }
2736d49e1aeSJan Lentfer
2746d49e1aeSJan Lentfer #ifdef CONFIG_USIM_SIMULATOR
2756d49e1aeSJan Lentfer if (conf->password) {
2766d49e1aeSJan Lentfer u8 opc[16], k[16], sqn[6];
2776d49e1aeSJan Lentfer const char *pos;
2786d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: Use internal Milenage "
2796d49e1aeSJan Lentfer "implementation for UMTS authentication");
2806d49e1aeSJan Lentfer if (conf->password_len < 78) {
2816d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: invalid Milenage "
2826d49e1aeSJan Lentfer "password");
2836d49e1aeSJan Lentfer return -1;
2846d49e1aeSJan Lentfer }
2856d49e1aeSJan Lentfer pos = (const char *) conf->password;
2866d49e1aeSJan Lentfer if (hexstr2bin(pos, k, 16))
2876d49e1aeSJan Lentfer return -1;
2886d49e1aeSJan Lentfer pos += 32;
2896d49e1aeSJan Lentfer if (*pos != ':')
2906d49e1aeSJan Lentfer return -1;
2916d49e1aeSJan Lentfer pos++;
2926d49e1aeSJan Lentfer
2936d49e1aeSJan Lentfer if (hexstr2bin(pos, opc, 16))
2946d49e1aeSJan Lentfer return -1;
2956d49e1aeSJan Lentfer pos += 32;
2966d49e1aeSJan Lentfer if (*pos != ':')
2976d49e1aeSJan Lentfer return -1;
2986d49e1aeSJan Lentfer pos++;
2996d49e1aeSJan Lentfer
3006d49e1aeSJan Lentfer if (hexstr2bin(pos, sqn, 6))
3016d49e1aeSJan Lentfer return -1;
3026d49e1aeSJan Lentfer
3036d49e1aeSJan Lentfer return milenage_check(opc, k, sqn, data->rand, data->autn,
3046d49e1aeSJan Lentfer data->ik, data->ck,
3056d49e1aeSJan Lentfer data->res, &data->res_len, data->auts);
3066d49e1aeSJan Lentfer }
3076d49e1aeSJan Lentfer #endif /* CONFIG_USIM_SIMULATOR */
3086d49e1aeSJan Lentfer
3096d49e1aeSJan Lentfer #ifdef CONFIG_USIM_HARDCODED
3106d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: Use hardcoded Kc and SRES values for "
3116d49e1aeSJan Lentfer "testing");
3126d49e1aeSJan Lentfer
3136d49e1aeSJan Lentfer /* These hardcoded Kc and SRES values are used for testing.
3146d49e1aeSJan Lentfer * Could consider making them configurable. */
3156d49e1aeSJan Lentfer os_memset(data->res, '2', EAP_AKA_RES_MAX_LEN);
3166d49e1aeSJan Lentfer data->res_len = EAP_AKA_RES_MAX_LEN;
3176d49e1aeSJan Lentfer os_memset(data->ik, '3', EAP_AKA_IK_LEN);
3186d49e1aeSJan Lentfer os_memset(data->ck, '4', EAP_AKA_CK_LEN);
3196d49e1aeSJan Lentfer {
3206d49e1aeSJan Lentfer u8 autn[EAP_AKA_AUTN_LEN];
3216d49e1aeSJan Lentfer os_memset(autn, '1', EAP_AKA_AUTN_LEN);
322*a1157835SDaniel Fojt if (os_memcmp_const(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
3236d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
3246d49e1aeSJan Lentfer "with expected value");
3256d49e1aeSJan Lentfer return -1;
3266d49e1aeSJan Lentfer }
3276d49e1aeSJan Lentfer }
3286d49e1aeSJan Lentfer #if 0
3296d49e1aeSJan Lentfer {
3306d49e1aeSJan Lentfer static int test_resync = 1;
3316d49e1aeSJan Lentfer if (test_resync) {
3326d49e1aeSJan Lentfer /* Test Resynchronization */
3336d49e1aeSJan Lentfer test_resync = 0;
3346d49e1aeSJan Lentfer return -2;
3356d49e1aeSJan Lentfer }
3366d49e1aeSJan Lentfer }
3376d49e1aeSJan Lentfer #endif
3386d49e1aeSJan Lentfer return 0;
3396d49e1aeSJan Lentfer
3406d49e1aeSJan Lentfer #else /* CONFIG_USIM_HARDCODED */
3416d49e1aeSJan Lentfer
342*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "EAP-AKA: No UMTS authentication algorithm "
3436d49e1aeSJan Lentfer "enabled");
3446d49e1aeSJan Lentfer return -1;
3456d49e1aeSJan Lentfer
3466d49e1aeSJan Lentfer #endif /* CONFIG_USIM_HARDCODED */
3476d49e1aeSJan Lentfer }
3486d49e1aeSJan Lentfer
3496d49e1aeSJan Lentfer
3506d49e1aeSJan Lentfer #define CLEAR_PSEUDONYM 0x01
3516d49e1aeSJan Lentfer #define CLEAR_REAUTH_ID 0x02
3526d49e1aeSJan Lentfer #define CLEAR_EAP_ID 0x04
3536d49e1aeSJan Lentfer
eap_aka_clear_identities(struct eap_sm * sm,struct eap_aka_data * data,int id)3543ff40c12SJohn Marino static void eap_aka_clear_identities(struct eap_sm *sm,
3553ff40c12SJohn Marino struct eap_aka_data *data, int id)
3566d49e1aeSJan Lentfer {
3573ff40c12SJohn Marino if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
3583ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
3596d49e1aeSJan Lentfer os_free(data->pseudonym);
3606d49e1aeSJan Lentfer data->pseudonym = NULL;
3616d49e1aeSJan Lentfer data->pseudonym_len = 0;
362*a1157835SDaniel Fojt if (data->use_pseudonym)
3633ff40c12SJohn Marino eap_set_anon_id(sm, NULL, 0);
3646d49e1aeSJan Lentfer }
3653ff40c12SJohn Marino if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
3663ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
3676d49e1aeSJan Lentfer os_free(data->reauth_id);
3686d49e1aeSJan Lentfer data->reauth_id = NULL;
3696d49e1aeSJan Lentfer data->reauth_id_len = 0;
3706d49e1aeSJan Lentfer }
3713ff40c12SJohn Marino if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
3723ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id");
3736d49e1aeSJan Lentfer os_free(data->last_eap_identity);
3746d49e1aeSJan Lentfer data->last_eap_identity = NULL;
3756d49e1aeSJan Lentfer data->last_eap_identity_len = 0;
3766d49e1aeSJan Lentfer }
3776d49e1aeSJan Lentfer }
3786d49e1aeSJan Lentfer
3796d49e1aeSJan Lentfer
eap_aka_learn_ids(struct eap_sm * sm,struct eap_aka_data * data,struct eap_sim_attrs * attr)3803ff40c12SJohn Marino static int eap_aka_learn_ids(struct eap_sm *sm, struct eap_aka_data *data,
3816d49e1aeSJan Lentfer struct eap_sim_attrs *attr)
3826d49e1aeSJan Lentfer {
3836d49e1aeSJan Lentfer if (attr->next_pseudonym) {
3843ff40c12SJohn Marino const u8 *identity = NULL;
3853ff40c12SJohn Marino size_t identity_len = 0;
3863ff40c12SJohn Marino const u8 *realm = NULL;
3873ff40c12SJohn Marino size_t realm_len = 0;
3883ff40c12SJohn Marino
3893ff40c12SJohn Marino wpa_hexdump_ascii(MSG_DEBUG,
3903ff40c12SJohn Marino "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
3913ff40c12SJohn Marino attr->next_pseudonym,
3923ff40c12SJohn Marino attr->next_pseudonym_len);
3936d49e1aeSJan Lentfer os_free(data->pseudonym);
3943ff40c12SJohn Marino /* Look for the realm of the permanent identity */
3953ff40c12SJohn Marino identity = eap_get_config_identity(sm, &identity_len);
3963ff40c12SJohn Marino if (identity) {
3973ff40c12SJohn Marino for (realm = identity, realm_len = identity_len;
3983ff40c12SJohn Marino realm_len > 0; realm_len--, realm++) {
3993ff40c12SJohn Marino if (*realm == '@')
4003ff40c12SJohn Marino break;
4013ff40c12SJohn Marino }
4023ff40c12SJohn Marino }
4033ff40c12SJohn Marino data->pseudonym = os_malloc(attr->next_pseudonym_len +
4043ff40c12SJohn Marino realm_len);
4056d49e1aeSJan Lentfer if (data->pseudonym == NULL) {
4066d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
4076d49e1aeSJan Lentfer "next pseudonym");
4083ff40c12SJohn Marino data->pseudonym_len = 0;
4096d49e1aeSJan Lentfer return -1;
4106d49e1aeSJan Lentfer }
4116d49e1aeSJan Lentfer os_memcpy(data->pseudonym, attr->next_pseudonym,
4126d49e1aeSJan Lentfer attr->next_pseudonym_len);
4133ff40c12SJohn Marino if (realm_len) {
4143ff40c12SJohn Marino os_memcpy(data->pseudonym + attr->next_pseudonym_len,
4153ff40c12SJohn Marino realm, realm_len);
4163ff40c12SJohn Marino }
4173ff40c12SJohn Marino data->pseudonym_len = attr->next_pseudonym_len + realm_len;
418*a1157835SDaniel Fojt if (data->use_pseudonym)
419*a1157835SDaniel Fojt eap_set_anon_id(sm, data->pseudonym,
420*a1157835SDaniel Fojt data->pseudonym_len);
4216d49e1aeSJan Lentfer }
4226d49e1aeSJan Lentfer
4236d49e1aeSJan Lentfer if (attr->next_reauth_id) {
4246d49e1aeSJan Lentfer os_free(data->reauth_id);
425*a1157835SDaniel Fojt data->reauth_id = os_memdup(attr->next_reauth_id,
426*a1157835SDaniel Fojt attr->next_reauth_id_len);
4276d49e1aeSJan Lentfer if (data->reauth_id == NULL) {
4286d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
4296d49e1aeSJan Lentfer "next reauth_id");
4303ff40c12SJohn Marino data->reauth_id_len = 0;
4316d49e1aeSJan Lentfer return -1;
4326d49e1aeSJan Lentfer }
4336d49e1aeSJan Lentfer data->reauth_id_len = attr->next_reauth_id_len;
4346d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG,
4356d49e1aeSJan Lentfer "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
4366d49e1aeSJan Lentfer data->reauth_id,
4376d49e1aeSJan Lentfer data->reauth_id_len);
4386d49e1aeSJan Lentfer }
4396d49e1aeSJan Lentfer
4406d49e1aeSJan Lentfer return 0;
4416d49e1aeSJan Lentfer }
4426d49e1aeSJan Lentfer
4436d49e1aeSJan Lentfer
eap_aka_add_id_msg(struct eap_aka_data * data,const struct wpabuf * msg)4446d49e1aeSJan Lentfer static int eap_aka_add_id_msg(struct eap_aka_data *data,
4456d49e1aeSJan Lentfer const struct wpabuf *msg)
4466d49e1aeSJan Lentfer {
4476d49e1aeSJan Lentfer if (msg == NULL)
4486d49e1aeSJan Lentfer return -1;
4496d49e1aeSJan Lentfer
4506d49e1aeSJan Lentfer if (data->id_msgs == NULL) {
4516d49e1aeSJan Lentfer data->id_msgs = wpabuf_dup(msg);
4526d49e1aeSJan Lentfer return data->id_msgs == NULL ? -1 : 0;
4536d49e1aeSJan Lentfer }
4546d49e1aeSJan Lentfer
4556d49e1aeSJan Lentfer if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
4566d49e1aeSJan Lentfer return -1;
4576d49e1aeSJan Lentfer wpabuf_put_buf(data->id_msgs, msg);
4586d49e1aeSJan Lentfer
4596d49e1aeSJan Lentfer return 0;
4606d49e1aeSJan Lentfer }
4616d49e1aeSJan Lentfer
4626d49e1aeSJan Lentfer
eap_aka_add_checkcode(struct eap_aka_data * data,struct eap_sim_msg * msg)4636d49e1aeSJan Lentfer static void eap_aka_add_checkcode(struct eap_aka_data *data,
4646d49e1aeSJan Lentfer struct eap_sim_msg *msg)
4656d49e1aeSJan Lentfer {
4666d49e1aeSJan Lentfer const u8 *addr;
4676d49e1aeSJan Lentfer size_t len;
4686d49e1aeSJan Lentfer u8 hash[SHA256_MAC_LEN];
4696d49e1aeSJan Lentfer
4706d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_CHECKCODE");
4716d49e1aeSJan Lentfer
4726d49e1aeSJan Lentfer if (data->id_msgs == NULL) {
4736d49e1aeSJan Lentfer /*
4746d49e1aeSJan Lentfer * No EAP-AKA/Identity packets were exchanged - send empty
4756d49e1aeSJan Lentfer * checkcode.
4766d49e1aeSJan Lentfer */
4776d49e1aeSJan Lentfer eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
4786d49e1aeSJan Lentfer return;
4796d49e1aeSJan Lentfer }
4806d49e1aeSJan Lentfer
4816d49e1aeSJan Lentfer /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
4826d49e1aeSJan Lentfer addr = wpabuf_head(data->id_msgs);
4836d49e1aeSJan Lentfer len = wpabuf_len(data->id_msgs);
4846d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
4856d49e1aeSJan Lentfer #ifdef EAP_AKA_PRIME
4866d49e1aeSJan Lentfer if (data->eap_method == EAP_TYPE_AKA_PRIME)
4876d49e1aeSJan Lentfer sha256_vector(1, &addr, &len, hash);
4886d49e1aeSJan Lentfer else
4896d49e1aeSJan Lentfer #endif /* EAP_AKA_PRIME */
4906d49e1aeSJan Lentfer sha1_vector(1, &addr, &len, hash);
4916d49e1aeSJan Lentfer
4926d49e1aeSJan Lentfer eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
4936d49e1aeSJan Lentfer data->eap_method == EAP_TYPE_AKA_PRIME ?
4946d49e1aeSJan Lentfer EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
4956d49e1aeSJan Lentfer }
4966d49e1aeSJan Lentfer
4976d49e1aeSJan Lentfer
eap_aka_verify_checkcode(struct eap_aka_data * data,const u8 * checkcode,size_t checkcode_len)4986d49e1aeSJan Lentfer static int eap_aka_verify_checkcode(struct eap_aka_data *data,
4996d49e1aeSJan Lentfer const u8 *checkcode, size_t checkcode_len)
5006d49e1aeSJan Lentfer {
5016d49e1aeSJan Lentfer const u8 *addr;
5026d49e1aeSJan Lentfer size_t len;
5036d49e1aeSJan Lentfer u8 hash[SHA256_MAC_LEN];
5046d49e1aeSJan Lentfer size_t hash_len;
5056d49e1aeSJan Lentfer
5066d49e1aeSJan Lentfer if (checkcode == NULL)
5076d49e1aeSJan Lentfer return -1;
5086d49e1aeSJan Lentfer
5096d49e1aeSJan Lentfer if (data->id_msgs == NULL) {
5106d49e1aeSJan Lentfer if (checkcode_len != 0) {
5116d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
5126d49e1aeSJan Lentfer "indicates that AKA/Identity messages were "
5136d49e1aeSJan Lentfer "used, but they were not");
5146d49e1aeSJan Lentfer return -1;
5156d49e1aeSJan Lentfer }
5166d49e1aeSJan Lentfer return 0;
5176d49e1aeSJan Lentfer }
5186d49e1aeSJan Lentfer
5196d49e1aeSJan Lentfer hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
5206d49e1aeSJan Lentfer EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
5216d49e1aeSJan Lentfer
5226d49e1aeSJan Lentfer if (checkcode_len != hash_len) {
5236d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
5246d49e1aeSJan Lentfer "indicates that AKA/Identity message were not "
5256d49e1aeSJan Lentfer "used, but they were");
5266d49e1aeSJan Lentfer return -1;
5276d49e1aeSJan Lentfer }
5286d49e1aeSJan Lentfer
5296d49e1aeSJan Lentfer /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
5306d49e1aeSJan Lentfer addr = wpabuf_head(data->id_msgs);
5316d49e1aeSJan Lentfer len = wpabuf_len(data->id_msgs);
5326d49e1aeSJan Lentfer #ifdef EAP_AKA_PRIME
5336d49e1aeSJan Lentfer if (data->eap_method == EAP_TYPE_AKA_PRIME)
5346d49e1aeSJan Lentfer sha256_vector(1, &addr, &len, hash);
5356d49e1aeSJan Lentfer else
5366d49e1aeSJan Lentfer #endif /* EAP_AKA_PRIME */
5376d49e1aeSJan Lentfer sha1_vector(1, &addr, &len, hash);
5386d49e1aeSJan Lentfer
539*a1157835SDaniel Fojt if (os_memcmp_const(hash, checkcode, hash_len) != 0) {
5406d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
5416d49e1aeSJan Lentfer return -1;
5426d49e1aeSJan Lentfer }
5436d49e1aeSJan Lentfer
5446d49e1aeSJan Lentfer return 0;
5456d49e1aeSJan Lentfer }
5466d49e1aeSJan Lentfer
5476d49e1aeSJan Lentfer
eap_aka_client_error(struct eap_aka_data * data,u8 id,int err)5486d49e1aeSJan Lentfer static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
5496d49e1aeSJan Lentfer int err)
5506d49e1aeSJan Lentfer {
5516d49e1aeSJan Lentfer struct eap_sim_msg *msg;
5526d49e1aeSJan Lentfer
5536d49e1aeSJan Lentfer eap_aka_state(data, FAILURE);
5546d49e1aeSJan Lentfer data->num_id_req = 0;
5556d49e1aeSJan Lentfer data->num_notification = 0;
5566d49e1aeSJan Lentfer
5573ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-AKA: Send Client-Error (error code %d)",
5583ff40c12SJohn Marino err);
5596d49e1aeSJan Lentfer msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
5606d49e1aeSJan Lentfer EAP_AKA_SUBTYPE_CLIENT_ERROR);
5616d49e1aeSJan Lentfer eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
562*a1157835SDaniel Fojt return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
5636d49e1aeSJan Lentfer }
5646d49e1aeSJan Lentfer
5656d49e1aeSJan Lentfer
eap_aka_authentication_reject(struct eap_aka_data * data,u8 id)5666d49e1aeSJan Lentfer static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data,
5676d49e1aeSJan Lentfer u8 id)
5686d49e1aeSJan Lentfer {
5696d49e1aeSJan Lentfer struct eap_sim_msg *msg;
5706d49e1aeSJan Lentfer
5716d49e1aeSJan Lentfer eap_aka_state(data, FAILURE);
5726d49e1aeSJan Lentfer data->num_id_req = 0;
5736d49e1aeSJan Lentfer data->num_notification = 0;
5746d49e1aeSJan Lentfer
5756d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject "
5766d49e1aeSJan Lentfer "(id=%d)", id);
5776d49e1aeSJan Lentfer msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
5786d49e1aeSJan Lentfer EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
579*a1157835SDaniel Fojt return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
5806d49e1aeSJan Lentfer }
5816d49e1aeSJan Lentfer
5826d49e1aeSJan Lentfer
eap_aka_synchronization_failure(struct eap_aka_data * data,u8 id,struct eap_sim_attrs * attr)5836d49e1aeSJan Lentfer static struct wpabuf * eap_aka_synchronization_failure(
584*a1157835SDaniel Fojt struct eap_aka_data *data, u8 id, struct eap_sim_attrs *attr)
5856d49e1aeSJan Lentfer {
5866d49e1aeSJan Lentfer struct eap_sim_msg *msg;
5876d49e1aeSJan Lentfer
5886d49e1aeSJan Lentfer data->num_id_req = 0;
5896d49e1aeSJan Lentfer data->num_notification = 0;
5906d49e1aeSJan Lentfer
5916d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure "
5926d49e1aeSJan Lentfer "(id=%d)", id);
5936d49e1aeSJan Lentfer msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
5946d49e1aeSJan Lentfer EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
5956d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_AUTS");
5966d49e1aeSJan Lentfer eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
5976d49e1aeSJan Lentfer EAP_AKA_AUTS_LEN);
598*a1157835SDaniel Fojt if (data->eap_method == EAP_TYPE_AKA_PRIME) {
599*a1157835SDaniel Fojt size_t i;
600*a1157835SDaniel Fojt
601*a1157835SDaniel Fojt for (i = 0; i < attr->kdf_count; i++) {
602*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, " AT_KDF");
603*a1157835SDaniel Fojt eap_sim_msg_add(msg, EAP_SIM_AT_KDF, attr->kdf[i],
604*a1157835SDaniel Fojt NULL, 0);
605*a1157835SDaniel Fojt }
606*a1157835SDaniel Fojt }
607*a1157835SDaniel Fojt return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
6086d49e1aeSJan Lentfer }
6096d49e1aeSJan Lentfer
6106d49e1aeSJan Lentfer
eap_aka_response_identity(struct eap_sm * sm,struct eap_aka_data * data,u8 id,enum eap_sim_id_req id_req)6116d49e1aeSJan Lentfer static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
6126d49e1aeSJan Lentfer struct eap_aka_data *data,
6136d49e1aeSJan Lentfer u8 id,
6146d49e1aeSJan Lentfer enum eap_sim_id_req id_req)
6156d49e1aeSJan Lentfer {
6166d49e1aeSJan Lentfer const u8 *identity = NULL;
6176d49e1aeSJan Lentfer size_t identity_len = 0;
6186d49e1aeSJan Lentfer struct eap_sim_msg *msg;
6196d49e1aeSJan Lentfer
6206d49e1aeSJan Lentfer data->reauth = 0;
6216d49e1aeSJan Lentfer if (id_req == ANY_ID && data->reauth_id) {
6226d49e1aeSJan Lentfer identity = data->reauth_id;
6236d49e1aeSJan Lentfer identity_len = data->reauth_id_len;
6246d49e1aeSJan Lentfer data->reauth = 1;
6256d49e1aeSJan Lentfer } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
626*a1157835SDaniel Fojt data->pseudonym &&
627*a1157835SDaniel Fojt !eap_sim_anonymous_username(data->pseudonym,
628*a1157835SDaniel Fojt data->pseudonym_len)) {
6296d49e1aeSJan Lentfer identity = data->pseudonym;
6306d49e1aeSJan Lentfer identity_len = data->pseudonym_len;
6313ff40c12SJohn Marino eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID);
6326d49e1aeSJan Lentfer } else if (id_req != NO_ID_REQ) {
6336d49e1aeSJan Lentfer identity = eap_get_config_identity(sm, &identity_len);
6346d49e1aeSJan Lentfer if (identity) {
635*a1157835SDaniel Fojt int ids = CLEAR_PSEUDONYM | CLEAR_REAUTH_ID;
636*a1157835SDaniel Fojt
637*a1157835SDaniel Fojt if (data->pseudonym &&
638*a1157835SDaniel Fojt eap_sim_anonymous_username(data->pseudonym,
639*a1157835SDaniel Fojt data->pseudonym_len))
640*a1157835SDaniel Fojt ids &= ~CLEAR_PSEUDONYM;
641*a1157835SDaniel Fojt eap_aka_clear_identities(sm, data, ids);
6426d49e1aeSJan Lentfer }
6436d49e1aeSJan Lentfer }
6446d49e1aeSJan Lentfer if (id_req != NO_ID_REQ)
6453ff40c12SJohn Marino eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
6466d49e1aeSJan Lentfer
6476d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
6486d49e1aeSJan Lentfer msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
6496d49e1aeSJan Lentfer EAP_AKA_SUBTYPE_IDENTITY);
6506d49e1aeSJan Lentfer
6516d49e1aeSJan Lentfer if (identity) {
6526d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY",
6536d49e1aeSJan Lentfer identity, identity_len);
6546d49e1aeSJan Lentfer eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
6556d49e1aeSJan Lentfer identity, identity_len);
6566d49e1aeSJan Lentfer }
6576d49e1aeSJan Lentfer
658*a1157835SDaniel Fojt return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
6596d49e1aeSJan Lentfer }
6606d49e1aeSJan Lentfer
6616d49e1aeSJan Lentfer
eap_aka_response_challenge(struct eap_aka_data * data,u8 id)6626d49e1aeSJan Lentfer static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data,
6636d49e1aeSJan Lentfer u8 id)
6646d49e1aeSJan Lentfer {
6656d49e1aeSJan Lentfer struct eap_sim_msg *msg;
6666d49e1aeSJan Lentfer
6676d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)", id);
6686d49e1aeSJan Lentfer msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
6696d49e1aeSJan Lentfer EAP_AKA_SUBTYPE_CHALLENGE);
6706d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_RES");
6716d49e1aeSJan Lentfer eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len * 8,
6726d49e1aeSJan Lentfer data->res, data->res_len);
6736d49e1aeSJan Lentfer eap_aka_add_checkcode(data, msg);
6746d49e1aeSJan Lentfer if (data->use_result_ind) {
6756d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
6766d49e1aeSJan Lentfer eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
6776d49e1aeSJan Lentfer }
6786d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_MAC");
6796d49e1aeSJan Lentfer eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
680*a1157835SDaniel Fojt return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, (u8 *) "",
681*a1157835SDaniel Fojt 0);
6826d49e1aeSJan Lentfer }
6836d49e1aeSJan Lentfer
6846d49e1aeSJan Lentfer
eap_aka_response_reauth(struct eap_aka_data * data,u8 id,int counter_too_small,const u8 * nonce_s)6856d49e1aeSJan Lentfer static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data,
6866d49e1aeSJan Lentfer u8 id, int counter_too_small,
6876d49e1aeSJan Lentfer const u8 *nonce_s)
6886d49e1aeSJan Lentfer {
6896d49e1aeSJan Lentfer struct eap_sim_msg *msg;
6906d49e1aeSJan Lentfer unsigned int counter;
6916d49e1aeSJan Lentfer
6926d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)",
6936d49e1aeSJan Lentfer id);
6946d49e1aeSJan Lentfer msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
6956d49e1aeSJan Lentfer EAP_AKA_SUBTYPE_REAUTHENTICATION);
6966d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_IV");
6976d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
6986d49e1aeSJan Lentfer eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
6996d49e1aeSJan Lentfer
7006d49e1aeSJan Lentfer if (counter_too_small) {
7016d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " *AT_COUNTER_TOO_SMALL");
7026d49e1aeSJan Lentfer eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
7036d49e1aeSJan Lentfer counter = data->counter_too_small;
7046d49e1aeSJan Lentfer } else
7056d49e1aeSJan Lentfer counter = data->counter;
7066d49e1aeSJan Lentfer
7076d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", counter);
7086d49e1aeSJan Lentfer eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
7096d49e1aeSJan Lentfer
7106d49e1aeSJan Lentfer if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
7116d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
7126d49e1aeSJan Lentfer "AT_ENCR_DATA");
7136d49e1aeSJan Lentfer eap_sim_msg_free(msg);
7146d49e1aeSJan Lentfer return NULL;
7156d49e1aeSJan Lentfer }
7166d49e1aeSJan Lentfer eap_aka_add_checkcode(data, msg);
7176d49e1aeSJan Lentfer if (data->use_result_ind) {
7186d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
7196d49e1aeSJan Lentfer eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
7206d49e1aeSJan Lentfer }
7216d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_MAC");
7226d49e1aeSJan Lentfer eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
723*a1157835SDaniel Fojt return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, nonce_s,
7246d49e1aeSJan Lentfer EAP_SIM_NONCE_S_LEN);
7256d49e1aeSJan Lentfer }
7266d49e1aeSJan Lentfer
7276d49e1aeSJan Lentfer
eap_aka_response_notification(struct eap_aka_data * data,u8 id,u16 notification)7286d49e1aeSJan Lentfer static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data,
7296d49e1aeSJan Lentfer u8 id, u16 notification)
7306d49e1aeSJan Lentfer {
7316d49e1aeSJan Lentfer struct eap_sim_msg *msg;
7326d49e1aeSJan Lentfer u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
7336d49e1aeSJan Lentfer
7346d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)", id);
7356d49e1aeSJan Lentfer msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
7366d49e1aeSJan Lentfer EAP_AKA_SUBTYPE_NOTIFICATION);
7376d49e1aeSJan Lentfer if (k_aut && data->reauth) {
7386d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_IV");
7396d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
7406d49e1aeSJan Lentfer eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
7416d49e1aeSJan Lentfer EAP_SIM_AT_ENCR_DATA);
7426d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", data->counter);
7436d49e1aeSJan Lentfer eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
7446d49e1aeSJan Lentfer NULL, 0);
7456d49e1aeSJan Lentfer if (eap_sim_msg_add_encr_end(msg, data->k_encr,
7466d49e1aeSJan Lentfer EAP_SIM_AT_PADDING)) {
7476d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
7486d49e1aeSJan Lentfer "AT_ENCR_DATA");
7496d49e1aeSJan Lentfer eap_sim_msg_free(msg);
7506d49e1aeSJan Lentfer return NULL;
7516d49e1aeSJan Lentfer }
7526d49e1aeSJan Lentfer }
7536d49e1aeSJan Lentfer if (k_aut) {
7546d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_MAC");
7556d49e1aeSJan Lentfer eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
7566d49e1aeSJan Lentfer }
757*a1157835SDaniel Fojt return eap_sim_msg_finish(msg, data->eap_method, k_aut, (u8 *) "", 0);
7586d49e1aeSJan Lentfer }
7596d49e1aeSJan Lentfer
7606d49e1aeSJan Lentfer
eap_aka_process_identity(struct eap_sm * sm,struct eap_aka_data * data,u8 id,const struct wpabuf * reqData,struct eap_sim_attrs * attr)7616d49e1aeSJan Lentfer static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm,
7626d49e1aeSJan Lentfer struct eap_aka_data *data,
7636d49e1aeSJan Lentfer u8 id,
7646d49e1aeSJan Lentfer const struct wpabuf *reqData,
7656d49e1aeSJan Lentfer struct eap_sim_attrs *attr)
7666d49e1aeSJan Lentfer {
7676d49e1aeSJan Lentfer int id_error;
7686d49e1aeSJan Lentfer struct wpabuf *buf;
7696d49e1aeSJan Lentfer
7706d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Identity");
7716d49e1aeSJan Lentfer
7726d49e1aeSJan Lentfer id_error = 0;
7736d49e1aeSJan Lentfer switch (attr->id_req) {
7746d49e1aeSJan Lentfer case NO_ID_REQ:
7756d49e1aeSJan Lentfer break;
7766d49e1aeSJan Lentfer case ANY_ID:
7776d49e1aeSJan Lentfer if (data->num_id_req > 0)
7786d49e1aeSJan Lentfer id_error++;
7796d49e1aeSJan Lentfer data->num_id_req++;
7806d49e1aeSJan Lentfer break;
7816d49e1aeSJan Lentfer case FULLAUTH_ID:
7826d49e1aeSJan Lentfer if (data->num_id_req > 1)
7836d49e1aeSJan Lentfer id_error++;
7846d49e1aeSJan Lentfer data->num_id_req++;
7856d49e1aeSJan Lentfer break;
7866d49e1aeSJan Lentfer case PERMANENT_ID:
7876d49e1aeSJan Lentfer if (data->num_id_req > 2)
7886d49e1aeSJan Lentfer id_error++;
7896d49e1aeSJan Lentfer data->num_id_req++;
7906d49e1aeSJan Lentfer break;
7916d49e1aeSJan Lentfer }
7926d49e1aeSJan Lentfer if (id_error) {
7936d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests "
7946d49e1aeSJan Lentfer "used within one authentication");
7956d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
7966d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
7976d49e1aeSJan Lentfer }
7986d49e1aeSJan Lentfer
7996d49e1aeSJan Lentfer buf = eap_aka_response_identity(sm, data, id, attr->id_req);
8006d49e1aeSJan Lentfer
8016d49e1aeSJan Lentfer if (data->prev_id != id) {
8026d49e1aeSJan Lentfer eap_aka_add_id_msg(data, reqData);
8036d49e1aeSJan Lentfer eap_aka_add_id_msg(data, buf);
8046d49e1aeSJan Lentfer data->prev_id = id;
8056d49e1aeSJan Lentfer }
8066d49e1aeSJan Lentfer
8076d49e1aeSJan Lentfer return buf;
8086d49e1aeSJan Lentfer }
8096d49e1aeSJan Lentfer
8106d49e1aeSJan Lentfer
eap_aka_verify_mac(struct eap_aka_data * data,const struct wpabuf * req,const u8 * mac,const u8 * extra,size_t extra_len)8116d49e1aeSJan Lentfer static int eap_aka_verify_mac(struct eap_aka_data *data,
8126d49e1aeSJan Lentfer const struct wpabuf *req,
8136d49e1aeSJan Lentfer const u8 *mac, const u8 *extra,
8146d49e1aeSJan Lentfer size_t extra_len)
8156d49e1aeSJan Lentfer {
8166d49e1aeSJan Lentfer if (data->eap_method == EAP_TYPE_AKA_PRIME)
8176d49e1aeSJan Lentfer return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
8186d49e1aeSJan Lentfer extra_len);
8196d49e1aeSJan Lentfer return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
8206d49e1aeSJan Lentfer }
8216d49e1aeSJan Lentfer
8226d49e1aeSJan Lentfer
8236d49e1aeSJan Lentfer #ifdef EAP_AKA_PRIME
eap_aka_prime_kdf_select(struct eap_aka_data * data,u8 id,u16 kdf)8246d49e1aeSJan Lentfer static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data,
8256d49e1aeSJan Lentfer u8 id, u16 kdf)
8266d49e1aeSJan Lentfer {
8276d49e1aeSJan Lentfer struct eap_sim_msg *msg;
8286d49e1aeSJan Lentfer
8296d49e1aeSJan Lentfer data->kdf_negotiation = 1;
8306d49e1aeSJan Lentfer data->kdf = kdf;
8316d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF "
8326d49e1aeSJan Lentfer "select)", id);
8336d49e1aeSJan Lentfer msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
8346d49e1aeSJan Lentfer EAP_AKA_SUBTYPE_CHALLENGE);
8356d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, " AT_KDF");
8366d49e1aeSJan Lentfer eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0);
837*a1157835SDaniel Fojt return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
8386d49e1aeSJan Lentfer }
8396d49e1aeSJan Lentfer
8406d49e1aeSJan Lentfer
eap_aka_prime_kdf_neg(struct eap_aka_data * data,u8 id,struct eap_sim_attrs * attr)8416d49e1aeSJan Lentfer static struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data,
8426d49e1aeSJan Lentfer u8 id, struct eap_sim_attrs *attr)
8436d49e1aeSJan Lentfer {
8446d49e1aeSJan Lentfer size_t i;
8456d49e1aeSJan Lentfer
8466d49e1aeSJan Lentfer for (i = 0; i < attr->kdf_count; i++) {
847*a1157835SDaniel Fojt if (attr->kdf[i] == EAP_AKA_PRIME_KDF) {
848*a1157835SDaniel Fojt os_memcpy(data->last_kdf_attrs, attr->kdf,
849*a1157835SDaniel Fojt sizeof(u16) * attr->kdf_count);
850*a1157835SDaniel Fojt data->last_kdf_count = attr->kdf_count;
8516d49e1aeSJan Lentfer return eap_aka_prime_kdf_select(data, id,
8526d49e1aeSJan Lentfer EAP_AKA_PRIME_KDF);
8536d49e1aeSJan Lentfer }
854*a1157835SDaniel Fojt }
8556d49e1aeSJan Lentfer
8566d49e1aeSJan Lentfer /* No matching KDF found - fail authentication as if AUTN had been
8576d49e1aeSJan Lentfer * incorrect */
8586d49e1aeSJan Lentfer return eap_aka_authentication_reject(data, id);
8596d49e1aeSJan Lentfer }
8606d49e1aeSJan Lentfer
8616d49e1aeSJan Lentfer
eap_aka_prime_kdf_valid(struct eap_aka_data * data,struct eap_sim_attrs * attr)8626d49e1aeSJan Lentfer static int eap_aka_prime_kdf_valid(struct eap_aka_data *data,
8636d49e1aeSJan Lentfer struct eap_sim_attrs *attr)
8646d49e1aeSJan Lentfer {
8656d49e1aeSJan Lentfer size_t i, j;
8666d49e1aeSJan Lentfer
8676d49e1aeSJan Lentfer if (attr->kdf_count == 0)
8686d49e1aeSJan Lentfer return 0;
8696d49e1aeSJan Lentfer
8706d49e1aeSJan Lentfer /* The only allowed (and required) duplication of a KDF is the addition
8716d49e1aeSJan Lentfer * of the selected KDF into the beginning of the list. */
8726d49e1aeSJan Lentfer
8736d49e1aeSJan Lentfer if (data->kdf_negotiation) {
874*a1157835SDaniel Fojt /* When the peer receives the new EAP-Request/AKA'-Challenge
875*a1157835SDaniel Fojt * message, must check only requested change occurred in the
876*a1157835SDaniel Fojt * list of AT_KDF attributes. If there are any other changes,
877*a1157835SDaniel Fojt * the peer must behave like the case that AT_MAC had been
878*a1157835SDaniel Fojt * incorrect and authentication is failed. These are defined in
879*a1157835SDaniel Fojt * EAP-AKA' specification RFC 5448, Section 3.2. */
8806d49e1aeSJan Lentfer if (attr->kdf[0] != data->kdf) {
8816d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
8826d49e1aeSJan Lentfer "accept the selected KDF");
883*a1157835SDaniel Fojt return -1;
884*a1157835SDaniel Fojt }
885*a1157835SDaniel Fojt
886*a1157835SDaniel Fojt if (attr->kdf_count > EAP_AKA_PRIME_KDF_MAX ||
887*a1157835SDaniel Fojt attr->kdf_count != data->last_kdf_count + 1) {
888*a1157835SDaniel Fojt wpa_printf(MSG_WARNING,
889*a1157835SDaniel Fojt "EAP-AKA': The length of KDF attributes is wrong");
890*a1157835SDaniel Fojt return -1;
8916d49e1aeSJan Lentfer }
8926d49e1aeSJan Lentfer
8936d49e1aeSJan Lentfer for (i = 1; i < attr->kdf_count; i++) {
894*a1157835SDaniel Fojt if (attr->kdf[i] != data->last_kdf_attrs[i - 1]) {
895*a1157835SDaniel Fojt wpa_printf(MSG_WARNING,
896*a1157835SDaniel Fojt "EAP-AKA': The KDF attributes except selected KDF are not same as original one");
897*a1157835SDaniel Fojt return -1;
8986d49e1aeSJan Lentfer }
8996d49e1aeSJan Lentfer }
9006d49e1aeSJan Lentfer }
9016d49e1aeSJan Lentfer
9026d49e1aeSJan Lentfer for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) {
9036d49e1aeSJan Lentfer for (j = i + 1; j < attr->kdf_count; j++) {
9046d49e1aeSJan Lentfer if (attr->kdf[i] == attr->kdf[j]) {
9056d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA': The server "
9066d49e1aeSJan Lentfer "included a duplicated KDF");
9076d49e1aeSJan Lentfer return 0;
9086d49e1aeSJan Lentfer }
9096d49e1aeSJan Lentfer }
9106d49e1aeSJan Lentfer }
9116d49e1aeSJan Lentfer
9126d49e1aeSJan Lentfer return 1;
9136d49e1aeSJan Lentfer }
9146d49e1aeSJan Lentfer #endif /* EAP_AKA_PRIME */
9156d49e1aeSJan Lentfer
9166d49e1aeSJan Lentfer
eap_aka_process_challenge(struct eap_sm * sm,struct eap_aka_data * data,u8 id,const struct wpabuf * reqData,struct eap_sim_attrs * attr)9176d49e1aeSJan Lentfer static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
9186d49e1aeSJan Lentfer struct eap_aka_data *data,
9196d49e1aeSJan Lentfer u8 id,
9206d49e1aeSJan Lentfer const struct wpabuf *reqData,
9216d49e1aeSJan Lentfer struct eap_sim_attrs *attr)
9226d49e1aeSJan Lentfer {
9236d49e1aeSJan Lentfer const u8 *identity;
9246d49e1aeSJan Lentfer size_t identity_len;
9256d49e1aeSJan Lentfer int res;
9266d49e1aeSJan Lentfer struct eap_sim_attrs eattr;
9276d49e1aeSJan Lentfer
9286d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge");
9296d49e1aeSJan Lentfer
9306d49e1aeSJan Lentfer if (attr->checkcode &&
9316d49e1aeSJan Lentfer eap_aka_verify_checkcode(data, attr->checkcode,
9326d49e1aeSJan Lentfer attr->checkcode_len)) {
9336d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
9346d49e1aeSJan Lentfer "message");
935*a1157835SDaniel Fojt #ifdef TEST_FUZZ
936*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
937*a1157835SDaniel Fojt "TEST: Ignore AT_CHECKCODE mismatch for fuzz testing");
938*a1157835SDaniel Fojt #else /* TEST_FUZZ */
9396d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
9406d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
941*a1157835SDaniel Fojt #endif /* TEST_FUZZ */
9426d49e1aeSJan Lentfer }
9436d49e1aeSJan Lentfer
9446d49e1aeSJan Lentfer #ifdef EAP_AKA_PRIME
9456d49e1aeSJan Lentfer if (data->eap_method == EAP_TYPE_AKA_PRIME) {
9466d49e1aeSJan Lentfer if (!attr->kdf_input || attr->kdf_input_len == 0) {
9476d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message "
9486d49e1aeSJan Lentfer "did not include non-empty AT_KDF_INPUT");
9496d49e1aeSJan Lentfer /* Fail authentication as if AUTN had been incorrect */
9506d49e1aeSJan Lentfer return eap_aka_authentication_reject(data, id);
9516d49e1aeSJan Lentfer }
9526d49e1aeSJan Lentfer os_free(data->network_name);
953*a1157835SDaniel Fojt data->network_name = os_memdup(attr->kdf_input,
954*a1157835SDaniel Fojt attr->kdf_input_len);
9556d49e1aeSJan Lentfer if (data->network_name == NULL) {
9566d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA': No memory for "
9576d49e1aeSJan Lentfer "storing Network Name");
9586d49e1aeSJan Lentfer return eap_aka_authentication_reject(data, id);
9596d49e1aeSJan Lentfer }
9606d49e1aeSJan Lentfer data->network_name_len = attr->kdf_input_len;
9616d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name "
9626d49e1aeSJan Lentfer "(AT_KDF_INPUT)",
9636d49e1aeSJan Lentfer data->network_name, data->network_name_len);
9646d49e1aeSJan Lentfer /* TODO: check Network Name per 3GPP.33.402 */
9656d49e1aeSJan Lentfer
966*a1157835SDaniel Fojt res = eap_aka_prime_kdf_valid(data, attr);
967*a1157835SDaniel Fojt if (res == 0)
9686d49e1aeSJan Lentfer return eap_aka_authentication_reject(data, id);
969*a1157835SDaniel Fojt else if (res == -1)
970*a1157835SDaniel Fojt return eap_aka_client_error(
971*a1157835SDaniel Fojt data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
9726d49e1aeSJan Lentfer
9736d49e1aeSJan Lentfer if (attr->kdf[0] != EAP_AKA_PRIME_KDF)
9746d49e1aeSJan Lentfer return eap_aka_prime_kdf_neg(data, id, attr);
9756d49e1aeSJan Lentfer
9766d49e1aeSJan Lentfer data->kdf = EAP_AKA_PRIME_KDF;
9776d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
9786d49e1aeSJan Lentfer }
9796d49e1aeSJan Lentfer
9806d49e1aeSJan Lentfer if (data->eap_method == EAP_TYPE_AKA && attr->bidding) {
9816d49e1aeSJan Lentfer u16 flags = WPA_GET_BE16(attr->bidding);
9826d49e1aeSJan Lentfer if ((flags & EAP_AKA_BIDDING_FLAG_D) &&
9836d49e1aeSJan Lentfer eap_allowed_method(sm, EAP_VENDOR_IETF,
9846d49e1aeSJan Lentfer EAP_TYPE_AKA_PRIME)) {
9856d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from "
9866d49e1aeSJan Lentfer "AKA' to AKA detected");
9876d49e1aeSJan Lentfer /* Fail authentication as if AUTN had been incorrect */
9886d49e1aeSJan Lentfer return eap_aka_authentication_reject(data, id);
9896d49e1aeSJan Lentfer }
9906d49e1aeSJan Lentfer }
9916d49e1aeSJan Lentfer #endif /* EAP_AKA_PRIME */
9926d49e1aeSJan Lentfer
9936d49e1aeSJan Lentfer data->reauth = 0;
9946d49e1aeSJan Lentfer if (!attr->mac || !attr->rand || !attr->autn) {
9956d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
9966d49e1aeSJan Lentfer "did not include%s%s%s",
9976d49e1aeSJan Lentfer !attr->mac ? " AT_MAC" : "",
9986d49e1aeSJan Lentfer !attr->rand ? " AT_RAND" : "",
9996d49e1aeSJan Lentfer !attr->autn ? " AT_AUTN" : "");
10006d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
10016d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
10026d49e1aeSJan Lentfer }
10036d49e1aeSJan Lentfer os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN);
10046d49e1aeSJan Lentfer os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN);
10056d49e1aeSJan Lentfer
10066d49e1aeSJan Lentfer res = eap_aka_umts_auth(sm, data);
10076d49e1aeSJan Lentfer if (res == -1) {
10086d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
10096d49e1aeSJan Lentfer "failed (AUTN)");
10106d49e1aeSJan Lentfer return eap_aka_authentication_reject(data, id);
10116d49e1aeSJan Lentfer } else if (res == -2) {
10126d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
10136d49e1aeSJan Lentfer "failed (AUTN seq# -> AUTS)");
1014*a1157835SDaniel Fojt return eap_aka_synchronization_failure(data, id, attr);
10153ff40c12SJohn Marino } else if (res > 0) {
10163ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-AKA: Wait for external USIM processing");
10173ff40c12SJohn Marino return NULL;
10186d49e1aeSJan Lentfer } else if (res) {
10196d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
10206d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
10216d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
10226d49e1aeSJan Lentfer }
10236d49e1aeSJan Lentfer #ifdef EAP_AKA_PRIME
10246d49e1aeSJan Lentfer if (data->eap_method == EAP_TYPE_AKA_PRIME) {
10256d49e1aeSJan Lentfer /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
10266d49e1aeSJan Lentfer * needed 6-octet SQN ^ AK for CK',IK' derivation */
10276d49e1aeSJan Lentfer u16 amf = WPA_GET_BE16(data->autn + 6);
10286d49e1aeSJan Lentfer if (!(amf & 0x8000)) {
10296d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA': AMF separation bit "
10306d49e1aeSJan Lentfer "not set (AMF=0x%4x)", amf);
10316d49e1aeSJan Lentfer return eap_aka_authentication_reject(data, id);
10326d49e1aeSJan Lentfer }
10336d49e1aeSJan Lentfer eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
10346d49e1aeSJan Lentfer data->autn,
10356d49e1aeSJan Lentfer data->network_name,
10366d49e1aeSJan Lentfer data->network_name_len);
10376d49e1aeSJan Lentfer }
10386d49e1aeSJan Lentfer #endif /* EAP_AKA_PRIME */
10396d49e1aeSJan Lentfer if (data->last_eap_identity) {
10406d49e1aeSJan Lentfer identity = data->last_eap_identity;
10416d49e1aeSJan Lentfer identity_len = data->last_eap_identity_len;
1042*a1157835SDaniel Fojt } else if (data->pseudonym &&
1043*a1157835SDaniel Fojt !eap_sim_anonymous_username(data->pseudonym,
1044*a1157835SDaniel Fojt data->pseudonym_len)) {
10456d49e1aeSJan Lentfer identity = data->pseudonym;
10466d49e1aeSJan Lentfer identity_len = data->pseudonym_len;
1047*a1157835SDaniel Fojt } else {
1048*a1157835SDaniel Fojt struct eap_peer_config *config;
1049*a1157835SDaniel Fojt
1050*a1157835SDaniel Fojt config = eap_get_config(sm);
1051*a1157835SDaniel Fojt if (config && config->imsi_identity) {
1052*a1157835SDaniel Fojt identity = config->imsi_identity;
1053*a1157835SDaniel Fojt identity_len = config->imsi_identity_len;
1054*a1157835SDaniel Fojt } else {
10556d49e1aeSJan Lentfer identity = eap_get_config_identity(sm, &identity_len);
1056*a1157835SDaniel Fojt }
1057*a1157835SDaniel Fojt }
10586d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
10596d49e1aeSJan Lentfer "derivation", identity, identity_len);
10606d49e1aeSJan Lentfer if (data->eap_method == EAP_TYPE_AKA_PRIME) {
10616d49e1aeSJan Lentfer eap_aka_prime_derive_keys(identity, identity_len, data->ik,
10626d49e1aeSJan Lentfer data->ck, data->k_encr, data->k_aut,
10636d49e1aeSJan Lentfer data->k_re, data->msk, data->emsk);
10646d49e1aeSJan Lentfer } else {
10656d49e1aeSJan Lentfer eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
10666d49e1aeSJan Lentfer data->mk);
10676d49e1aeSJan Lentfer eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
10686d49e1aeSJan Lentfer data->msk, data->emsk);
10696d49e1aeSJan Lentfer }
10706d49e1aeSJan Lentfer if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
10716d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
10726d49e1aeSJan Lentfer "used invalid AT_MAC");
1073*a1157835SDaniel Fojt #ifdef TEST_FUZZ
1074*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
1075*a1157835SDaniel Fojt "TEST: Ignore AT_MAC mismatch for fuzz testing");
1076*a1157835SDaniel Fojt #else /* TEST_FUZZ */
10776d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
10786d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1079*a1157835SDaniel Fojt #endif /* TEST_FUZZ */
10806d49e1aeSJan Lentfer }
10816d49e1aeSJan Lentfer
10823ff40c12SJohn Marino /* Old reauthentication identity must not be used anymore. In
10833ff40c12SJohn Marino * other words, if no new identities are received, full
10843ff40c12SJohn Marino * authentication will be used on next reauthentication (using
10853ff40c12SJohn Marino * pseudonym identity or permanent identity). */
10863ff40c12SJohn Marino eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
10876d49e1aeSJan Lentfer
10886d49e1aeSJan Lentfer if (attr->encr_data) {
10896d49e1aeSJan Lentfer u8 *decrypted;
10906d49e1aeSJan Lentfer decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
10916d49e1aeSJan Lentfer attr->encr_data_len, attr->iv,
10926d49e1aeSJan Lentfer &eattr, 0);
10936d49e1aeSJan Lentfer if (decrypted == NULL) {
10946d49e1aeSJan Lentfer return eap_aka_client_error(
10956d49e1aeSJan Lentfer data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
10966d49e1aeSJan Lentfer }
10973ff40c12SJohn Marino eap_aka_learn_ids(sm, data, &eattr);
10986d49e1aeSJan Lentfer os_free(decrypted);
10996d49e1aeSJan Lentfer }
11006d49e1aeSJan Lentfer
11016d49e1aeSJan Lentfer if (data->result_ind && attr->result_ind)
11026d49e1aeSJan Lentfer data->use_result_ind = 1;
11036d49e1aeSJan Lentfer
1104*a1157835SDaniel Fojt if (data->state != FAILURE) {
11056d49e1aeSJan Lentfer eap_aka_state(data, data->use_result_ind ?
11066d49e1aeSJan Lentfer RESULT_SUCCESS : SUCCESS);
11076d49e1aeSJan Lentfer }
11086d49e1aeSJan Lentfer
11096d49e1aeSJan Lentfer data->num_id_req = 0;
11106d49e1aeSJan Lentfer data->num_notification = 0;
11116d49e1aeSJan Lentfer /* RFC 4187 specifies that counter is initialized to one after
11126d49e1aeSJan Lentfer * fullauth, but initializing it to zero makes it easier to implement
11136d49e1aeSJan Lentfer * reauth verification. */
11146d49e1aeSJan Lentfer data->counter = 0;
11156d49e1aeSJan Lentfer return eap_aka_response_challenge(data, id);
11166d49e1aeSJan Lentfer }
11176d49e1aeSJan Lentfer
11186d49e1aeSJan Lentfer
eap_aka_process_notification_reauth(struct eap_aka_data * data,struct eap_sim_attrs * attr)11196d49e1aeSJan Lentfer static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
11206d49e1aeSJan Lentfer struct eap_sim_attrs *attr)
11216d49e1aeSJan Lentfer {
11226d49e1aeSJan Lentfer struct eap_sim_attrs eattr;
11236d49e1aeSJan Lentfer u8 *decrypted;
11246d49e1aeSJan Lentfer
11256d49e1aeSJan Lentfer if (attr->encr_data == NULL || attr->iv == NULL) {
11266d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after "
11276d49e1aeSJan Lentfer "reauth did not include encrypted data");
11286d49e1aeSJan Lentfer return -1;
11296d49e1aeSJan Lentfer }
11306d49e1aeSJan Lentfer
11316d49e1aeSJan Lentfer decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
11326d49e1aeSJan Lentfer attr->encr_data_len, attr->iv, &eattr,
11336d49e1aeSJan Lentfer 0);
11346d49e1aeSJan Lentfer if (decrypted == NULL) {
11356d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
11366d49e1aeSJan Lentfer "data from notification message");
11376d49e1aeSJan Lentfer return -1;
11386d49e1aeSJan Lentfer }
11396d49e1aeSJan Lentfer
11406d49e1aeSJan Lentfer if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
11416d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
11426d49e1aeSJan Lentfer "message does not match with counter in reauth "
11436d49e1aeSJan Lentfer "message");
11446d49e1aeSJan Lentfer os_free(decrypted);
11456d49e1aeSJan Lentfer return -1;
11466d49e1aeSJan Lentfer }
11476d49e1aeSJan Lentfer
11486d49e1aeSJan Lentfer os_free(decrypted);
11496d49e1aeSJan Lentfer return 0;
11506d49e1aeSJan Lentfer }
11516d49e1aeSJan Lentfer
11526d49e1aeSJan Lentfer
eap_aka_process_notification_auth(struct eap_aka_data * data,const struct wpabuf * reqData,struct eap_sim_attrs * attr)11536d49e1aeSJan Lentfer static int eap_aka_process_notification_auth(struct eap_aka_data *data,
11546d49e1aeSJan Lentfer const struct wpabuf *reqData,
11556d49e1aeSJan Lentfer struct eap_sim_attrs *attr)
11566d49e1aeSJan Lentfer {
11576d49e1aeSJan Lentfer if (attr->mac == NULL) {
11586d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-AKA: no AT_MAC in after_auth "
11596d49e1aeSJan Lentfer "Notification message");
11606d49e1aeSJan Lentfer return -1;
11616d49e1aeSJan Lentfer }
11626d49e1aeSJan Lentfer
11636d49e1aeSJan Lentfer if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
11646d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
11656d49e1aeSJan Lentfer "used invalid AT_MAC");
11666d49e1aeSJan Lentfer return -1;
11676d49e1aeSJan Lentfer }
11686d49e1aeSJan Lentfer
11696d49e1aeSJan Lentfer if (data->reauth &&
11706d49e1aeSJan Lentfer eap_aka_process_notification_reauth(data, attr)) {
11716d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification "
11726d49e1aeSJan Lentfer "message after reauth");
11736d49e1aeSJan Lentfer return -1;
11746d49e1aeSJan Lentfer }
11756d49e1aeSJan Lentfer
11766d49e1aeSJan Lentfer return 0;
11776d49e1aeSJan Lentfer }
11786d49e1aeSJan Lentfer
11796d49e1aeSJan Lentfer
eap_aka_process_notification(struct eap_sm * sm,struct eap_aka_data * data,u8 id,const struct wpabuf * reqData,struct eap_sim_attrs * attr)11806d49e1aeSJan Lentfer static struct wpabuf * eap_aka_process_notification(
11816d49e1aeSJan Lentfer struct eap_sm *sm, struct eap_aka_data *data, u8 id,
11826d49e1aeSJan Lentfer const struct wpabuf *reqData, struct eap_sim_attrs *attr)
11836d49e1aeSJan Lentfer {
11846d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Notification");
11856d49e1aeSJan Lentfer if (data->num_notification > 0) {
11866d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-AKA: too many notification "
11876d49e1aeSJan Lentfer "rounds (only one allowed)");
11886d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
11896d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
11906d49e1aeSJan Lentfer }
11916d49e1aeSJan Lentfer data->num_notification++;
11926d49e1aeSJan Lentfer if (attr->notification == -1) {
11936d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in "
11946d49e1aeSJan Lentfer "Notification message");
11956d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
11966d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
11976d49e1aeSJan Lentfer }
11986d49e1aeSJan Lentfer
11996d49e1aeSJan Lentfer if ((attr->notification & 0x4000) == 0 &&
12006d49e1aeSJan Lentfer eap_aka_process_notification_auth(data, reqData, attr)) {
12016d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
12026d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12036d49e1aeSJan Lentfer }
12046d49e1aeSJan Lentfer
12056d49e1aeSJan Lentfer eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
12066d49e1aeSJan Lentfer if (attr->notification >= 0 && attr->notification < 32768) {
1207*a1157835SDaniel Fojt data->error_code = attr->notification;
12086d49e1aeSJan Lentfer eap_aka_state(data, FAILURE);
12096d49e1aeSJan Lentfer } else if (attr->notification == EAP_SIM_SUCCESS &&
12106d49e1aeSJan Lentfer data->state == RESULT_SUCCESS)
12116d49e1aeSJan Lentfer eap_aka_state(data, SUCCESS);
12126d49e1aeSJan Lentfer return eap_aka_response_notification(data, id, attr->notification);
12136d49e1aeSJan Lentfer }
12146d49e1aeSJan Lentfer
12156d49e1aeSJan Lentfer
eap_aka_process_reauthentication(struct eap_sm * sm,struct eap_aka_data * data,u8 id,const struct wpabuf * reqData,struct eap_sim_attrs * attr)12166d49e1aeSJan Lentfer static struct wpabuf * eap_aka_process_reauthentication(
12176d49e1aeSJan Lentfer struct eap_sm *sm, struct eap_aka_data *data, u8 id,
12186d49e1aeSJan Lentfer const struct wpabuf *reqData, struct eap_sim_attrs *attr)
12196d49e1aeSJan Lentfer {
12206d49e1aeSJan Lentfer struct eap_sim_attrs eattr;
12216d49e1aeSJan Lentfer u8 *decrypted;
12226d49e1aeSJan Lentfer
12236d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication");
12246d49e1aeSJan Lentfer
12256d49e1aeSJan Lentfer if (attr->checkcode &&
12266d49e1aeSJan Lentfer eap_aka_verify_checkcode(data, attr->checkcode,
12276d49e1aeSJan Lentfer attr->checkcode_len)) {
1228*a1157835SDaniel Fojt #ifdef TEST_FUZZ
1229*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
1230*a1157835SDaniel Fojt "TEST: Ignore AT_CHECKCODE mismatch for fuzz testing");
1231*a1157835SDaniel Fojt #else /* TEST_FUZZ */
12326d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
12336d49e1aeSJan Lentfer "message");
1234*a1157835SDaniel Fojt #endif /* TEST_FUZZ */
12356d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
12366d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12376d49e1aeSJan Lentfer }
12386d49e1aeSJan Lentfer
12396d49e1aeSJan Lentfer if (data->reauth_id == NULL) {
12406d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying "
12416d49e1aeSJan Lentfer "reauthentication, but no reauth_id available");
12426d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
12436d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12446d49e1aeSJan Lentfer }
12456d49e1aeSJan Lentfer
12466d49e1aeSJan Lentfer data->reauth = 1;
12476d49e1aeSJan Lentfer if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
12486d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
12496d49e1aeSJan Lentfer "did not have valid AT_MAC");
12506d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
12516d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12526d49e1aeSJan Lentfer }
12536d49e1aeSJan Lentfer
1254*a1157835SDaniel Fojt /* At this stage the received MAC has been verified. Use this MAC for
1255*a1157835SDaniel Fojt * reauth Session-Id calculation if all other checks pass.
1256*a1157835SDaniel Fojt * The peer does not use the local MAC but the received MAC in deriving
1257*a1157835SDaniel Fojt * Session-Id. */
1258*a1157835SDaniel Fojt os_memcpy(data->reauth_mac, attr->mac, EAP_SIM_MAC_LEN);
1259*a1157835SDaniel Fojt wpa_hexdump(MSG_DEBUG, "EAP-AKA: Server MAC",
1260*a1157835SDaniel Fojt data->reauth_mac, EAP_SIM_MAC_LEN);
1261*a1157835SDaniel Fojt
12626d49e1aeSJan Lentfer if (attr->encr_data == NULL || attr->iv == NULL) {
12636d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
12646d49e1aeSJan Lentfer "message did not include encrypted data");
12656d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
12666d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12676d49e1aeSJan Lentfer }
12686d49e1aeSJan Lentfer
12696d49e1aeSJan Lentfer decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
12706d49e1aeSJan Lentfer attr->encr_data_len, attr->iv, &eattr,
12716d49e1aeSJan Lentfer 0);
12726d49e1aeSJan Lentfer if (decrypted == NULL) {
12736d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
12746d49e1aeSJan Lentfer "data from reauthentication message");
12756d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
12766d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12776d49e1aeSJan Lentfer }
12786d49e1aeSJan Lentfer
12796d49e1aeSJan Lentfer if (eattr.nonce_s == NULL || eattr.counter < 0) {
12806d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet",
12816d49e1aeSJan Lentfer !eattr.nonce_s ? " AT_NONCE_S" : "",
12826d49e1aeSJan Lentfer eattr.counter < 0 ? " AT_COUNTER" : "");
12836d49e1aeSJan Lentfer os_free(decrypted);
12846d49e1aeSJan Lentfer return eap_aka_client_error(data, id,
12856d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12866d49e1aeSJan Lentfer }
12876d49e1aeSJan Lentfer
12886d49e1aeSJan Lentfer if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
12896d49e1aeSJan Lentfer struct wpabuf *res;
12906d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter "
12916d49e1aeSJan Lentfer "(%d <= %d)", eattr.counter, data->counter);
12926d49e1aeSJan Lentfer data->counter_too_small = eattr.counter;
12936d49e1aeSJan Lentfer
12946d49e1aeSJan Lentfer /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
12956d49e1aeSJan Lentfer * reauth_id must not be used to start a new reauthentication.
12966d49e1aeSJan Lentfer * However, since it was used in the last EAP-Response-Identity
12976d49e1aeSJan Lentfer * packet, it has to saved for the following fullauth to be
12986d49e1aeSJan Lentfer * used in MK derivation. */
12996d49e1aeSJan Lentfer os_free(data->last_eap_identity);
13006d49e1aeSJan Lentfer data->last_eap_identity = data->reauth_id;
13016d49e1aeSJan Lentfer data->last_eap_identity_len = data->reauth_id_len;
13026d49e1aeSJan Lentfer data->reauth_id = NULL;
13036d49e1aeSJan Lentfer data->reauth_id_len = 0;
13046d49e1aeSJan Lentfer
13056d49e1aeSJan Lentfer res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s);
13066d49e1aeSJan Lentfer os_free(decrypted);
13076d49e1aeSJan Lentfer
13086d49e1aeSJan Lentfer return res;
13096d49e1aeSJan Lentfer }
13106d49e1aeSJan Lentfer data->counter = eattr.counter;
13116d49e1aeSJan Lentfer
13126d49e1aeSJan Lentfer os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
13136d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
13146d49e1aeSJan Lentfer data->nonce_s, EAP_SIM_NONCE_S_LEN);
13156d49e1aeSJan Lentfer
13166d49e1aeSJan Lentfer if (data->eap_method == EAP_TYPE_AKA_PRIME) {
13176d49e1aeSJan Lentfer eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
13186d49e1aeSJan Lentfer data->reauth_id,
13196d49e1aeSJan Lentfer data->reauth_id_len,
13206d49e1aeSJan Lentfer data->nonce_s,
13216d49e1aeSJan Lentfer data->msk, data->emsk);
13226d49e1aeSJan Lentfer } else {
13236d49e1aeSJan Lentfer eap_sim_derive_keys_reauth(data->counter, data->reauth_id,
13246d49e1aeSJan Lentfer data->reauth_id_len,
13256d49e1aeSJan Lentfer data->nonce_s, data->mk,
13266d49e1aeSJan Lentfer data->msk, data->emsk);
13276d49e1aeSJan Lentfer }
13283ff40c12SJohn Marino eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
13293ff40c12SJohn Marino eap_aka_learn_ids(sm, data, &eattr);
13306d49e1aeSJan Lentfer
13316d49e1aeSJan Lentfer if (data->result_ind && attr->result_ind)
13326d49e1aeSJan Lentfer data->use_result_ind = 1;
13336d49e1aeSJan Lentfer
1334*a1157835SDaniel Fojt if (data->state != FAILURE) {
13356d49e1aeSJan Lentfer eap_aka_state(data, data->use_result_ind ?
13366d49e1aeSJan Lentfer RESULT_SUCCESS : SUCCESS);
13376d49e1aeSJan Lentfer }
13386d49e1aeSJan Lentfer
13396d49e1aeSJan Lentfer data->num_id_req = 0;
13406d49e1aeSJan Lentfer data->num_notification = 0;
13416d49e1aeSJan Lentfer if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
13426d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
13436d49e1aeSJan Lentfer "fast reauths performed - force fullauth");
13443ff40c12SJohn Marino eap_aka_clear_identities(sm, data,
13453ff40c12SJohn Marino CLEAR_REAUTH_ID | CLEAR_EAP_ID);
13466d49e1aeSJan Lentfer }
13476d49e1aeSJan Lentfer os_free(decrypted);
13486d49e1aeSJan Lentfer return eap_aka_response_reauth(data, id, 0, data->nonce_s);
13496d49e1aeSJan Lentfer }
13506d49e1aeSJan Lentfer
13516d49e1aeSJan Lentfer
eap_aka_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)13526d49e1aeSJan Lentfer static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv,
13536d49e1aeSJan Lentfer struct eap_method_ret *ret,
13546d49e1aeSJan Lentfer const struct wpabuf *reqData)
13556d49e1aeSJan Lentfer {
13566d49e1aeSJan Lentfer struct eap_aka_data *data = priv;
13576d49e1aeSJan Lentfer const struct eap_hdr *req;
13586d49e1aeSJan Lentfer u8 subtype, id;
13596d49e1aeSJan Lentfer struct wpabuf *res;
13606d49e1aeSJan Lentfer const u8 *pos;
13616d49e1aeSJan Lentfer struct eap_sim_attrs attr;
13626d49e1aeSJan Lentfer size_t len;
13636d49e1aeSJan Lentfer
13646d49e1aeSJan Lentfer wpa_hexdump_buf(MSG_DEBUG, "EAP-AKA: EAP data", reqData);
13656d49e1aeSJan Lentfer if (eap_get_config_identity(sm, &len) == NULL) {
13666d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
13676d49e1aeSJan Lentfer eap_sm_request_identity(sm);
13686d49e1aeSJan Lentfer ret->ignore = TRUE;
13696d49e1aeSJan Lentfer return NULL;
13706d49e1aeSJan Lentfer }
13716d49e1aeSJan Lentfer
13726d49e1aeSJan Lentfer pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
13736d49e1aeSJan Lentfer &len);
1374*a1157835SDaniel Fojt if (pos == NULL || len < 3) {
13756d49e1aeSJan Lentfer ret->ignore = TRUE;
13766d49e1aeSJan Lentfer return NULL;
13776d49e1aeSJan Lentfer }
13786d49e1aeSJan Lentfer req = wpabuf_head(reqData);
13796d49e1aeSJan Lentfer id = req->identifier;
13806d49e1aeSJan Lentfer len = be_to_host16(req->length);
13816d49e1aeSJan Lentfer
13826d49e1aeSJan Lentfer ret->ignore = FALSE;
13836d49e1aeSJan Lentfer ret->methodState = METHOD_MAY_CONT;
13846d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
13856d49e1aeSJan Lentfer ret->allowNotifications = TRUE;
13866d49e1aeSJan Lentfer
13876d49e1aeSJan Lentfer subtype = *pos++;
13886d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
13896d49e1aeSJan Lentfer pos += 2; /* Reserved */
13906d49e1aeSJan Lentfer
13916d49e1aeSJan Lentfer if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr,
13926d49e1aeSJan Lentfer data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
13936d49e1aeSJan Lentfer 0)) {
13946d49e1aeSJan Lentfer res = eap_aka_client_error(data, id,
13956d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
13966d49e1aeSJan Lentfer goto done;
13976d49e1aeSJan Lentfer }
13986d49e1aeSJan Lentfer
13996d49e1aeSJan Lentfer switch (subtype) {
14006d49e1aeSJan Lentfer case EAP_AKA_SUBTYPE_IDENTITY:
14016d49e1aeSJan Lentfer res = eap_aka_process_identity(sm, data, id, reqData, &attr);
14026d49e1aeSJan Lentfer break;
14036d49e1aeSJan Lentfer case EAP_AKA_SUBTYPE_CHALLENGE:
14046d49e1aeSJan Lentfer res = eap_aka_process_challenge(sm, data, id, reqData, &attr);
14056d49e1aeSJan Lentfer break;
14066d49e1aeSJan Lentfer case EAP_AKA_SUBTYPE_NOTIFICATION:
14076d49e1aeSJan Lentfer res = eap_aka_process_notification(sm, data, id, reqData,
14086d49e1aeSJan Lentfer &attr);
14096d49e1aeSJan Lentfer break;
14106d49e1aeSJan Lentfer case EAP_AKA_SUBTYPE_REAUTHENTICATION:
14116d49e1aeSJan Lentfer res = eap_aka_process_reauthentication(sm, data, id, reqData,
14126d49e1aeSJan Lentfer &attr);
14136d49e1aeSJan Lentfer break;
14146d49e1aeSJan Lentfer case EAP_AKA_SUBTYPE_CLIENT_ERROR:
14156d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error");
14166d49e1aeSJan Lentfer res = eap_aka_client_error(data, id,
14176d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
14186d49e1aeSJan Lentfer break;
14196d49e1aeSJan Lentfer default:
14206d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype);
14216d49e1aeSJan Lentfer res = eap_aka_client_error(data, id,
14226d49e1aeSJan Lentfer EAP_AKA_UNABLE_TO_PROCESS_PACKET);
14236d49e1aeSJan Lentfer break;
14246d49e1aeSJan Lentfer }
14256d49e1aeSJan Lentfer
14266d49e1aeSJan Lentfer done:
14276d49e1aeSJan Lentfer if (data->state == FAILURE) {
14286d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
14296d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
14306d49e1aeSJan Lentfer } else if (data->state == SUCCESS) {
14316d49e1aeSJan Lentfer ret->decision = data->use_result_ind ?
14326d49e1aeSJan Lentfer DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
14336d49e1aeSJan Lentfer /*
14346d49e1aeSJan Lentfer * It is possible for the server to reply with AKA
14356d49e1aeSJan Lentfer * Notification, so we must allow the method to continue and
14366d49e1aeSJan Lentfer * not only accept EAP-Success at this point.
14376d49e1aeSJan Lentfer */
14386d49e1aeSJan Lentfer ret->methodState = data->use_result_ind ?
14396d49e1aeSJan Lentfer METHOD_DONE : METHOD_MAY_CONT;
1440*a1157835SDaniel Fojt } else if (data->state == RESULT_SUCCESS)
14416d49e1aeSJan Lentfer ret->methodState = METHOD_CONT;
14426d49e1aeSJan Lentfer
14436d49e1aeSJan Lentfer if (ret->methodState == METHOD_DONE) {
14446d49e1aeSJan Lentfer ret->allowNotifications = FALSE;
14456d49e1aeSJan Lentfer }
14466d49e1aeSJan Lentfer
14476d49e1aeSJan Lentfer return res;
14486d49e1aeSJan Lentfer }
14496d49e1aeSJan Lentfer
14506d49e1aeSJan Lentfer
eap_aka_has_reauth_data(struct eap_sm * sm,void * priv)14516d49e1aeSJan Lentfer static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
14526d49e1aeSJan Lentfer {
14536d49e1aeSJan Lentfer struct eap_aka_data *data = priv;
14546d49e1aeSJan Lentfer return data->pseudonym || data->reauth_id;
14556d49e1aeSJan Lentfer }
14566d49e1aeSJan Lentfer
14576d49e1aeSJan Lentfer
eap_aka_deinit_for_reauth(struct eap_sm * sm,void * priv)14586d49e1aeSJan Lentfer static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
14596d49e1aeSJan Lentfer {
14606d49e1aeSJan Lentfer struct eap_aka_data *data = priv;
14613ff40c12SJohn Marino eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
14626d49e1aeSJan Lentfer data->prev_id = -1;
14636d49e1aeSJan Lentfer wpabuf_free(data->id_msgs);
14646d49e1aeSJan Lentfer data->id_msgs = NULL;
14656d49e1aeSJan Lentfer data->use_result_ind = 0;
14666d49e1aeSJan Lentfer data->kdf_negotiation = 0;
1467*a1157835SDaniel Fojt eap_aka_clear_keys(data, 1);
14686d49e1aeSJan Lentfer }
14696d49e1aeSJan Lentfer
14706d49e1aeSJan Lentfer
eap_aka_init_for_reauth(struct eap_sm * sm,void * priv)14716d49e1aeSJan Lentfer static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv)
14726d49e1aeSJan Lentfer {
14736d49e1aeSJan Lentfer struct eap_aka_data *data = priv;
14746d49e1aeSJan Lentfer data->num_id_req = 0;
14756d49e1aeSJan Lentfer data->num_notification = 0;
14766d49e1aeSJan Lentfer eap_aka_state(data, CONTINUE);
14776d49e1aeSJan Lentfer return priv;
14786d49e1aeSJan Lentfer }
14796d49e1aeSJan Lentfer
14806d49e1aeSJan Lentfer
eap_aka_get_identity(struct eap_sm * sm,void * priv,size_t * len)14816d49e1aeSJan Lentfer static const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv,
14826d49e1aeSJan Lentfer size_t *len)
14836d49e1aeSJan Lentfer {
14846d49e1aeSJan Lentfer struct eap_aka_data *data = priv;
14856d49e1aeSJan Lentfer
14866d49e1aeSJan Lentfer if (data->reauth_id) {
14876d49e1aeSJan Lentfer *len = data->reauth_id_len;
14886d49e1aeSJan Lentfer return data->reauth_id;
14896d49e1aeSJan Lentfer }
14906d49e1aeSJan Lentfer
14916d49e1aeSJan Lentfer if (data->pseudonym) {
14926d49e1aeSJan Lentfer *len = data->pseudonym_len;
14936d49e1aeSJan Lentfer return data->pseudonym;
14946d49e1aeSJan Lentfer }
14956d49e1aeSJan Lentfer
14966d49e1aeSJan Lentfer return NULL;
14976d49e1aeSJan Lentfer }
14986d49e1aeSJan Lentfer
14996d49e1aeSJan Lentfer
eap_aka_isKeyAvailable(struct eap_sm * sm,void * priv)15006d49e1aeSJan Lentfer static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
15016d49e1aeSJan Lentfer {
15026d49e1aeSJan Lentfer struct eap_aka_data *data = priv;
15036d49e1aeSJan Lentfer return data->state == SUCCESS;
15046d49e1aeSJan Lentfer }
15056d49e1aeSJan Lentfer
15066d49e1aeSJan Lentfer
eap_aka_getKey(struct eap_sm * sm,void * priv,size_t * len)15076d49e1aeSJan Lentfer static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
15086d49e1aeSJan Lentfer {
15096d49e1aeSJan Lentfer struct eap_aka_data *data = priv;
15106d49e1aeSJan Lentfer u8 *key;
15116d49e1aeSJan Lentfer
15126d49e1aeSJan Lentfer if (data->state != SUCCESS)
15136d49e1aeSJan Lentfer return NULL;
15146d49e1aeSJan Lentfer
1515*a1157835SDaniel Fojt key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
15166d49e1aeSJan Lentfer if (key == NULL)
15176d49e1aeSJan Lentfer return NULL;
15186d49e1aeSJan Lentfer
15196d49e1aeSJan Lentfer *len = EAP_SIM_KEYING_DATA_LEN;
15206d49e1aeSJan Lentfer
15216d49e1aeSJan Lentfer return key;
15226d49e1aeSJan Lentfer }
15236d49e1aeSJan Lentfer
15246d49e1aeSJan Lentfer
eap_aka_get_session_id(struct eap_sm * sm,void * priv,size_t * len)15253ff40c12SJohn Marino static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
15263ff40c12SJohn Marino {
15273ff40c12SJohn Marino struct eap_aka_data *data = priv;
15283ff40c12SJohn Marino u8 *id;
15293ff40c12SJohn Marino
15303ff40c12SJohn Marino if (data->state != SUCCESS)
15313ff40c12SJohn Marino return NULL;
15323ff40c12SJohn Marino
1533*a1157835SDaniel Fojt if (!data->reauth)
15343ff40c12SJohn Marino *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
1535*a1157835SDaniel Fojt else
1536*a1157835SDaniel Fojt *len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
15373ff40c12SJohn Marino id = os_malloc(*len);
15383ff40c12SJohn Marino if (id == NULL)
15393ff40c12SJohn Marino return NULL;
15403ff40c12SJohn Marino
15413ff40c12SJohn Marino id[0] = data->eap_method;
1542*a1157835SDaniel Fojt if (!data->reauth) {
15433ff40c12SJohn Marino os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
1544*a1157835SDaniel Fojt os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn,
1545*a1157835SDaniel Fojt EAP_AKA_AUTN_LEN);
1546*a1157835SDaniel Fojt } else {
1547*a1157835SDaniel Fojt os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
1548*a1157835SDaniel Fojt os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
1549*a1157835SDaniel Fojt EAP_SIM_MAC_LEN);
1550*a1157835SDaniel Fojt }
15513ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
15523ff40c12SJohn Marino
15533ff40c12SJohn Marino return id;
15543ff40c12SJohn Marino }
15553ff40c12SJohn Marino
15563ff40c12SJohn Marino
eap_aka_get_emsk(struct eap_sm * sm,void * priv,size_t * len)15576d49e1aeSJan Lentfer static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
15586d49e1aeSJan Lentfer {
15596d49e1aeSJan Lentfer struct eap_aka_data *data = priv;
15606d49e1aeSJan Lentfer u8 *key;
15616d49e1aeSJan Lentfer
15626d49e1aeSJan Lentfer if (data->state != SUCCESS)
15636d49e1aeSJan Lentfer return NULL;
15646d49e1aeSJan Lentfer
1565*a1157835SDaniel Fojt key = os_memdup(data->emsk, EAP_EMSK_LEN);
15666d49e1aeSJan Lentfer if (key == NULL)
15676d49e1aeSJan Lentfer return NULL;
15686d49e1aeSJan Lentfer
15696d49e1aeSJan Lentfer *len = EAP_EMSK_LEN;
15706d49e1aeSJan Lentfer
15716d49e1aeSJan Lentfer return key;
15726d49e1aeSJan Lentfer }
15736d49e1aeSJan Lentfer
15746d49e1aeSJan Lentfer
eap_aka_get_error_code(void * priv)1575*a1157835SDaniel Fojt static int eap_aka_get_error_code(void *priv)
1576*a1157835SDaniel Fojt {
1577*a1157835SDaniel Fojt struct eap_aka_data *data = priv;
1578*a1157835SDaniel Fojt int current_data_error;
1579*a1157835SDaniel Fojt
1580*a1157835SDaniel Fojt if (!data)
1581*a1157835SDaniel Fojt return NO_EAP_METHOD_ERROR;
1582*a1157835SDaniel Fojt
1583*a1157835SDaniel Fojt current_data_error = data->error_code;
1584*a1157835SDaniel Fojt
1585*a1157835SDaniel Fojt /* Now reset for next transaction */
1586*a1157835SDaniel Fojt data->error_code = NO_EAP_METHOD_ERROR;
1587*a1157835SDaniel Fojt
1588*a1157835SDaniel Fojt return current_data_error;
1589*a1157835SDaniel Fojt }
1590*a1157835SDaniel Fojt
1591*a1157835SDaniel Fojt
eap_peer_aka_register(void)15926d49e1aeSJan Lentfer int eap_peer_aka_register(void)
15936d49e1aeSJan Lentfer {
15946d49e1aeSJan Lentfer struct eap_method *eap;
15956d49e1aeSJan Lentfer
15966d49e1aeSJan Lentfer eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
15976d49e1aeSJan Lentfer EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
15986d49e1aeSJan Lentfer if (eap == NULL)
15996d49e1aeSJan Lentfer return -1;
16006d49e1aeSJan Lentfer
16016d49e1aeSJan Lentfer eap->init = eap_aka_init;
16026d49e1aeSJan Lentfer eap->deinit = eap_aka_deinit;
16036d49e1aeSJan Lentfer eap->process = eap_aka_process;
16046d49e1aeSJan Lentfer eap->isKeyAvailable = eap_aka_isKeyAvailable;
16056d49e1aeSJan Lentfer eap->getKey = eap_aka_getKey;
16063ff40c12SJohn Marino eap->getSessionId = eap_aka_get_session_id;
16076d49e1aeSJan Lentfer eap->has_reauth_data = eap_aka_has_reauth_data;
16086d49e1aeSJan Lentfer eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
16096d49e1aeSJan Lentfer eap->init_for_reauth = eap_aka_init_for_reauth;
16106d49e1aeSJan Lentfer eap->get_identity = eap_aka_get_identity;
16116d49e1aeSJan Lentfer eap->get_emsk = eap_aka_get_emsk;
1612*a1157835SDaniel Fojt eap->get_error_code = eap_aka_get_error_code;
16136d49e1aeSJan Lentfer
1614*a1157835SDaniel Fojt return eap_peer_method_register(eap);
16156d49e1aeSJan Lentfer }
16166d49e1aeSJan Lentfer
16176d49e1aeSJan Lentfer
16186d49e1aeSJan Lentfer #ifdef EAP_AKA_PRIME
eap_peer_aka_prime_register(void)16196d49e1aeSJan Lentfer int eap_peer_aka_prime_register(void)
16206d49e1aeSJan Lentfer {
16216d49e1aeSJan Lentfer struct eap_method *eap;
16226d49e1aeSJan Lentfer
16236d49e1aeSJan Lentfer eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
16246d49e1aeSJan Lentfer EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
16256d49e1aeSJan Lentfer "AKA'");
16266d49e1aeSJan Lentfer if (eap == NULL)
16276d49e1aeSJan Lentfer return -1;
16286d49e1aeSJan Lentfer
16296d49e1aeSJan Lentfer eap->init = eap_aka_prime_init;
16306d49e1aeSJan Lentfer eap->deinit = eap_aka_deinit;
16316d49e1aeSJan Lentfer eap->process = eap_aka_process;
16326d49e1aeSJan Lentfer eap->isKeyAvailable = eap_aka_isKeyAvailable;
16336d49e1aeSJan Lentfer eap->getKey = eap_aka_getKey;
16343ff40c12SJohn Marino eap->getSessionId = eap_aka_get_session_id;
16356d49e1aeSJan Lentfer eap->has_reauth_data = eap_aka_has_reauth_data;
16366d49e1aeSJan Lentfer eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
16376d49e1aeSJan Lentfer eap->init_for_reauth = eap_aka_init_for_reauth;
16386d49e1aeSJan Lentfer eap->get_identity = eap_aka_get_identity;
16396d49e1aeSJan Lentfer eap->get_emsk = eap_aka_get_emsk;
1640*a1157835SDaniel Fojt eap->get_error_code = eap_aka_get_error_code;
16416d49e1aeSJan Lentfer
1642*a1157835SDaniel Fojt return eap_peer_method_register(eap);
16436d49e1aeSJan Lentfer }
16446d49e1aeSJan Lentfer #endif /* EAP_AKA_PRIME */
1645