xref: /dflybsd-src/contrib/wpa_supplicant/src/eap_server/eap_server_aka.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
33ff40c12SJohn Marino  * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "includes.h"
103ff40c12SJohn Marino 
113ff40c12SJohn Marino #include "common.h"
123ff40c12SJohn Marino #include "crypto/sha256.h"
133ff40c12SJohn Marino #include "crypto/crypto.h"
143ff40c12SJohn Marino #include "crypto/random.h"
153ff40c12SJohn Marino #include "eap_common/eap_sim_common.h"
163ff40c12SJohn Marino #include "eap_server/eap_i.h"
173ff40c12SJohn Marino #include "eap_server/eap_sim_db.h"
183ff40c12SJohn Marino 
193ff40c12SJohn Marino 
203ff40c12SJohn Marino struct eap_aka_data {
213ff40c12SJohn Marino 	u8 mk[EAP_SIM_MK_LEN];
223ff40c12SJohn Marino 	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
233ff40c12SJohn Marino 	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
243ff40c12SJohn Marino 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
253ff40c12SJohn Marino 	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
263ff40c12SJohn Marino 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
273ff40c12SJohn Marino 	u8 emsk[EAP_EMSK_LEN];
283ff40c12SJohn Marino 	u8 rand[EAP_AKA_RAND_LEN];
293ff40c12SJohn Marino 	u8 autn[EAP_AKA_AUTN_LEN];
303ff40c12SJohn Marino 	u8 ck[EAP_AKA_CK_LEN];
313ff40c12SJohn Marino 	u8 ik[EAP_AKA_IK_LEN];
323ff40c12SJohn Marino 	u8 res[EAP_AKA_RES_MAX_LEN];
33*a1157835SDaniel Fojt 	u8 reauth_mac[EAP_SIM_MAC_LEN];
343ff40c12SJohn Marino 	size_t res_len;
353ff40c12SJohn Marino 	enum {
363ff40c12SJohn Marino 		IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
373ff40c12SJohn Marino 	} state;
383ff40c12SJohn Marino 	char *next_pseudonym;
393ff40c12SJohn Marino 	char *next_reauth_id;
403ff40c12SJohn Marino 	u16 counter;
413ff40c12SJohn Marino 	struct eap_sim_reauth *reauth;
423ff40c12SJohn Marino 	int auts_reported; /* whether the current AUTS has been reported to the
433ff40c12SJohn Marino 			    * eap_sim_db */
443ff40c12SJohn Marino 	u16 notification;
453ff40c12SJohn Marino 	int use_result_ind;
463ff40c12SJohn Marino 
473ff40c12SJohn Marino 	struct wpabuf *id_msgs;
483ff40c12SJohn Marino 	int pending_id;
493ff40c12SJohn Marino 	u8 eap_method;
503ff40c12SJohn Marino 	u8 *network_name;
513ff40c12SJohn Marino 	size_t network_name_len;
523ff40c12SJohn Marino 	u16 kdf;
533ff40c12SJohn Marino 	int identity_round;
543ff40c12SJohn Marino 	char permanent[20]; /* Permanent username */
553ff40c12SJohn Marino };
563ff40c12SJohn Marino 
573ff40c12SJohn Marino 
583ff40c12SJohn Marino static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data);
593ff40c12SJohn Marino 
603ff40c12SJohn Marino 
eap_aka_state_txt(int state)613ff40c12SJohn Marino static const char * eap_aka_state_txt(int state)
623ff40c12SJohn Marino {
633ff40c12SJohn Marino 	switch (state) {
643ff40c12SJohn Marino 	case IDENTITY:
653ff40c12SJohn Marino 		return "IDENTITY";
663ff40c12SJohn Marino 	case CHALLENGE:
673ff40c12SJohn Marino 		return "CHALLENGE";
683ff40c12SJohn Marino 	case REAUTH:
693ff40c12SJohn Marino 		return "REAUTH";
703ff40c12SJohn Marino 	case SUCCESS:
713ff40c12SJohn Marino 		return "SUCCESS";
723ff40c12SJohn Marino 	case FAILURE:
733ff40c12SJohn Marino 		return "FAILURE";
743ff40c12SJohn Marino 	case NOTIFICATION:
753ff40c12SJohn Marino 		return "NOTIFICATION";
763ff40c12SJohn Marino 	default:
773ff40c12SJohn Marino 		return "Unknown?!";
783ff40c12SJohn Marino 	}
793ff40c12SJohn Marino }
803ff40c12SJohn Marino 
813ff40c12SJohn Marino 
eap_aka_state(struct eap_aka_data * data,int state)823ff40c12SJohn Marino static void eap_aka_state(struct eap_aka_data *data, int state)
833ff40c12SJohn Marino {
843ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
853ff40c12SJohn Marino 		   eap_aka_state_txt(data->state),
863ff40c12SJohn Marino 		   eap_aka_state_txt(state));
873ff40c12SJohn Marino 	data->state = state;
883ff40c12SJohn Marino }
893ff40c12SJohn Marino 
903ff40c12SJohn Marino 
eap_aka_check_identity_reauth(struct eap_sm * sm,struct eap_aka_data * data,const char * username)913ff40c12SJohn Marino static int eap_aka_check_identity_reauth(struct eap_sm *sm,
923ff40c12SJohn Marino 					 struct eap_aka_data *data,
933ff40c12SJohn Marino 					 const char *username)
943ff40c12SJohn Marino {
953ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
963ff40c12SJohn Marino 	    username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)
973ff40c12SJohn Marino 		return 0;
983ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA &&
993ff40c12SJohn Marino 	    username[0] != EAP_AKA_REAUTH_ID_PREFIX)
1003ff40c12SJohn Marino 		return 0;
1013ff40c12SJohn Marino 
1023ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
1033ff40c12SJohn Marino 	data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv,
1043ff40c12SJohn Marino 						   username);
1053ff40c12SJohn Marino 	if (data->reauth == NULL) {
1063ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - "
1073ff40c12SJohn Marino 			   "request full auth identity");
1083ff40c12SJohn Marino 		/* Remain in IDENTITY state for another round */
1093ff40c12SJohn Marino 		return 0;
1103ff40c12SJohn Marino 	}
1113ff40c12SJohn Marino 
1123ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication");
1133ff40c12SJohn Marino 	os_strlcpy(data->permanent, data->reauth->permanent,
1143ff40c12SJohn Marino 		   sizeof(data->permanent));
1153ff40c12SJohn Marino 	data->counter = data->reauth->counter;
1163ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
1173ff40c12SJohn Marino 		os_memcpy(data->k_encr, data->reauth->k_encr,
1183ff40c12SJohn Marino 			  EAP_SIM_K_ENCR_LEN);
1193ff40c12SJohn Marino 		os_memcpy(data->k_aut, data->reauth->k_aut,
1203ff40c12SJohn Marino 			  EAP_AKA_PRIME_K_AUT_LEN);
1213ff40c12SJohn Marino 		os_memcpy(data->k_re, data->reauth->k_re,
1223ff40c12SJohn Marino 			  EAP_AKA_PRIME_K_RE_LEN);
1233ff40c12SJohn Marino 	} else {
1243ff40c12SJohn Marino 		os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
1253ff40c12SJohn Marino 	}
1263ff40c12SJohn Marino 
1273ff40c12SJohn Marino 	eap_aka_state(data, REAUTH);
1283ff40c12SJohn Marino 	return 1;
1293ff40c12SJohn Marino }
1303ff40c12SJohn Marino 
1313ff40c12SJohn Marino 
eap_aka_check_identity(struct eap_sm * sm,struct eap_aka_data * data)1323ff40c12SJohn Marino static void eap_aka_check_identity(struct eap_sm *sm,
1333ff40c12SJohn Marino 				   struct eap_aka_data *data)
1343ff40c12SJohn Marino {
1353ff40c12SJohn Marino 	char *username;
1363ff40c12SJohn Marino 
1373ff40c12SJohn Marino 	/* Check if we already know the identity from EAP-Response/Identity */
1383ff40c12SJohn Marino 
1393ff40c12SJohn Marino 	username = sim_get_username(sm->identity, sm->identity_len);
1403ff40c12SJohn Marino 	if (username == NULL)
1413ff40c12SJohn Marino 		return;
1423ff40c12SJohn Marino 
1433ff40c12SJohn Marino 	if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
1443ff40c12SJohn Marino 		os_free(username);
1453ff40c12SJohn Marino 		/*
1463ff40c12SJohn Marino 		 * Since re-auth username was recognized, skip AKA/Identity
1473ff40c12SJohn Marino 		 * exchange.
1483ff40c12SJohn Marino 		 */
1493ff40c12SJohn Marino 		return;
1503ff40c12SJohn Marino 	}
1513ff40c12SJohn Marino 
1523ff40c12SJohn Marino 	if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
1533ff40c12SJohn Marino 	     username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
1543ff40c12SJohn Marino 	    (data->eap_method == EAP_TYPE_AKA &&
1553ff40c12SJohn Marino 	     username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
1563ff40c12SJohn Marino 		const char *permanent;
1573ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
1583ff40c12SJohn Marino 			   username);
1593ff40c12SJohn Marino 		permanent = eap_sim_db_get_permanent(
1603ff40c12SJohn Marino 			sm->eap_sim_db_priv, username);
1613ff40c12SJohn Marino 		if (permanent == NULL) {
1623ff40c12SJohn Marino 			os_free(username);
1633ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
1643ff40c12SJohn Marino 				   "identity - request permanent identity");
1653ff40c12SJohn Marino 			/* Remain in IDENTITY state for another round */
1663ff40c12SJohn Marino 			return;
1673ff40c12SJohn Marino 		}
1683ff40c12SJohn Marino 		os_strlcpy(data->permanent, permanent,
1693ff40c12SJohn Marino 			   sizeof(data->permanent));
1703ff40c12SJohn Marino 		/*
1713ff40c12SJohn Marino 		 * Since pseudonym username was recognized, skip AKA/Identity
1723ff40c12SJohn Marino 		 * exchange.
1733ff40c12SJohn Marino 		 */
1743ff40c12SJohn Marino 		eap_aka_fullauth(sm, data);
1753ff40c12SJohn Marino 	}
1763ff40c12SJohn Marino 
1773ff40c12SJohn Marino 	os_free(username);
1783ff40c12SJohn Marino }
1793ff40c12SJohn Marino 
1803ff40c12SJohn Marino 
eap_aka_init(struct eap_sm * sm)1813ff40c12SJohn Marino static void * eap_aka_init(struct eap_sm *sm)
1823ff40c12SJohn Marino {
1833ff40c12SJohn Marino 	struct eap_aka_data *data;
1843ff40c12SJohn Marino 
1853ff40c12SJohn Marino 	if (sm->eap_sim_db_priv == NULL) {
1863ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
1873ff40c12SJohn Marino 		return NULL;
1883ff40c12SJohn Marino 	}
1893ff40c12SJohn Marino 
1903ff40c12SJohn Marino 	data = os_zalloc(sizeof(*data));
1913ff40c12SJohn Marino 	if (data == NULL)
1923ff40c12SJohn Marino 		return NULL;
1933ff40c12SJohn Marino 
1943ff40c12SJohn Marino 	data->eap_method = EAP_TYPE_AKA;
1953ff40c12SJohn Marino 
1963ff40c12SJohn Marino 	data->state = IDENTITY;
1973ff40c12SJohn Marino 	data->pending_id = -1;
1983ff40c12SJohn Marino 	eap_aka_check_identity(sm, data);
1993ff40c12SJohn Marino 
2003ff40c12SJohn Marino 	return data;
2013ff40c12SJohn Marino }
2023ff40c12SJohn Marino 
2033ff40c12SJohn Marino 
2043ff40c12SJohn Marino #ifdef EAP_SERVER_AKA_PRIME
eap_aka_prime_init(struct eap_sm * sm)2053ff40c12SJohn Marino static void * eap_aka_prime_init(struct eap_sm *sm)
2063ff40c12SJohn Marino {
2073ff40c12SJohn Marino 	struct eap_aka_data *data;
2083ff40c12SJohn Marino 	/* TODO: make ANID configurable; see 3GPP TS 24.302 */
2093ff40c12SJohn Marino 	char *network_name = "WLAN";
2103ff40c12SJohn Marino 
2113ff40c12SJohn Marino 	if (sm->eap_sim_db_priv == NULL) {
2123ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
2133ff40c12SJohn Marino 		return NULL;
2143ff40c12SJohn Marino 	}
2153ff40c12SJohn Marino 
2163ff40c12SJohn Marino 	data = os_zalloc(sizeof(*data));
2173ff40c12SJohn Marino 	if (data == NULL)
2183ff40c12SJohn Marino 		return NULL;
2193ff40c12SJohn Marino 
2203ff40c12SJohn Marino 	data->eap_method = EAP_TYPE_AKA_PRIME;
2213ff40c12SJohn Marino 	data->network_name = (u8 *) os_strdup(network_name);
2223ff40c12SJohn Marino 	if (data->network_name == NULL) {
2233ff40c12SJohn Marino 		os_free(data);
2243ff40c12SJohn Marino 		return NULL;
2253ff40c12SJohn Marino 	}
2263ff40c12SJohn Marino 
2273ff40c12SJohn Marino 	data->network_name_len = os_strlen(network_name);
2283ff40c12SJohn Marino 
2293ff40c12SJohn Marino 	data->state = IDENTITY;
2303ff40c12SJohn Marino 	data->pending_id = -1;
2313ff40c12SJohn Marino 	eap_aka_check_identity(sm, data);
2323ff40c12SJohn Marino 
2333ff40c12SJohn Marino 	return data;
2343ff40c12SJohn Marino }
2353ff40c12SJohn Marino #endif /* EAP_SERVER_AKA_PRIME */
2363ff40c12SJohn Marino 
2373ff40c12SJohn Marino 
eap_aka_reset(struct eap_sm * sm,void * priv)2383ff40c12SJohn Marino static void eap_aka_reset(struct eap_sm *sm, void *priv)
2393ff40c12SJohn Marino {
2403ff40c12SJohn Marino 	struct eap_aka_data *data = priv;
2413ff40c12SJohn Marino 	os_free(data->next_pseudonym);
2423ff40c12SJohn Marino 	os_free(data->next_reauth_id);
2433ff40c12SJohn Marino 	wpabuf_free(data->id_msgs);
2443ff40c12SJohn Marino 	os_free(data->network_name);
245*a1157835SDaniel Fojt 	bin_clear_free(data, sizeof(*data));
2463ff40c12SJohn Marino }
2473ff40c12SJohn Marino 
2483ff40c12SJohn Marino 
eap_aka_add_id_msg(struct eap_aka_data * data,const struct wpabuf * msg)2493ff40c12SJohn Marino static int eap_aka_add_id_msg(struct eap_aka_data *data,
2503ff40c12SJohn Marino 			      const struct wpabuf *msg)
2513ff40c12SJohn Marino {
2523ff40c12SJohn Marino 	if (msg == NULL)
2533ff40c12SJohn Marino 		return -1;
2543ff40c12SJohn Marino 
2553ff40c12SJohn Marino 	if (data->id_msgs == NULL) {
2563ff40c12SJohn Marino 		data->id_msgs = wpabuf_dup(msg);
2573ff40c12SJohn Marino 		return data->id_msgs == NULL ? -1 : 0;
2583ff40c12SJohn Marino 	}
2593ff40c12SJohn Marino 
2603ff40c12SJohn Marino 	if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
2613ff40c12SJohn Marino 		return -1;
2623ff40c12SJohn Marino 	wpabuf_put_buf(data->id_msgs, msg);
2633ff40c12SJohn Marino 
2643ff40c12SJohn Marino 	return 0;
2653ff40c12SJohn Marino }
2663ff40c12SJohn Marino 
2673ff40c12SJohn Marino 
eap_aka_add_checkcode(struct eap_aka_data * data,struct eap_sim_msg * msg)2683ff40c12SJohn Marino static void eap_aka_add_checkcode(struct eap_aka_data *data,
2693ff40c12SJohn Marino 				  struct eap_sim_msg *msg)
2703ff40c12SJohn Marino {
2713ff40c12SJohn Marino 	const u8 *addr;
2723ff40c12SJohn Marino 	size_t len;
2733ff40c12SJohn Marino 	u8 hash[SHA256_MAC_LEN];
2743ff40c12SJohn Marino 
2753ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
2763ff40c12SJohn Marino 
2773ff40c12SJohn Marino 	if (data->id_msgs == NULL) {
2783ff40c12SJohn Marino 		/*
2793ff40c12SJohn Marino 		 * No EAP-AKA/Identity packets were exchanged - send empty
2803ff40c12SJohn Marino 		 * checkcode.
2813ff40c12SJohn Marino 		 */
2823ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
2833ff40c12SJohn Marino 		return;
2843ff40c12SJohn Marino 	}
2853ff40c12SJohn Marino 
2863ff40c12SJohn Marino 	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
2873ff40c12SJohn Marino 	addr = wpabuf_head(data->id_msgs);
2883ff40c12SJohn Marino 	len = wpabuf_len(data->id_msgs);
2893ff40c12SJohn Marino 	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
2903ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
2913ff40c12SJohn Marino 		sha256_vector(1, &addr, &len, hash);
2923ff40c12SJohn Marino 	else
2933ff40c12SJohn Marino 		sha1_vector(1, &addr, &len, hash);
2943ff40c12SJohn Marino 
2953ff40c12SJohn Marino 	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
2963ff40c12SJohn Marino 			data->eap_method == EAP_TYPE_AKA_PRIME ?
2973ff40c12SJohn Marino 			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
2983ff40c12SJohn Marino }
2993ff40c12SJohn Marino 
3003ff40c12SJohn Marino 
eap_aka_verify_checkcode(struct eap_aka_data * data,const u8 * checkcode,size_t checkcode_len)3013ff40c12SJohn Marino static int eap_aka_verify_checkcode(struct eap_aka_data *data,
3023ff40c12SJohn Marino 				    const u8 *checkcode, size_t checkcode_len)
3033ff40c12SJohn Marino {
3043ff40c12SJohn Marino 	const u8 *addr;
3053ff40c12SJohn Marino 	size_t len;
3063ff40c12SJohn Marino 	u8 hash[SHA256_MAC_LEN];
3073ff40c12SJohn Marino 	size_t hash_len;
3083ff40c12SJohn Marino 
3093ff40c12SJohn Marino 	if (checkcode == NULL)
3103ff40c12SJohn Marino 		return -1;
3113ff40c12SJohn Marino 
3123ff40c12SJohn Marino 	if (data->id_msgs == NULL) {
3133ff40c12SJohn Marino 		if (checkcode_len != 0) {
3143ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
3153ff40c12SJohn Marino 				   "indicates that AKA/Identity messages were "
3163ff40c12SJohn Marino 				   "used, but they were not");
3173ff40c12SJohn Marino 			return -1;
3183ff40c12SJohn Marino 		}
3193ff40c12SJohn Marino 		return 0;
3203ff40c12SJohn Marino 	}
3213ff40c12SJohn Marino 
3223ff40c12SJohn Marino 	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
3233ff40c12SJohn Marino 		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
3243ff40c12SJohn Marino 
3253ff40c12SJohn Marino 	if (checkcode_len != hash_len) {
3263ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
3273ff40c12SJohn Marino 			   "that AKA/Identity message were not used, but they "
3283ff40c12SJohn Marino 			   "were");
3293ff40c12SJohn Marino 		return -1;
3303ff40c12SJohn Marino 	}
3313ff40c12SJohn Marino 
3323ff40c12SJohn Marino 	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
3333ff40c12SJohn Marino 	addr = wpabuf_head(data->id_msgs);
3343ff40c12SJohn Marino 	len = wpabuf_len(data->id_msgs);
3353ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
3363ff40c12SJohn Marino 		sha256_vector(1, &addr, &len, hash);
3373ff40c12SJohn Marino 	else
3383ff40c12SJohn Marino 		sha1_vector(1, &addr, &len, hash);
3393ff40c12SJohn Marino 
340*a1157835SDaniel Fojt 	if (os_memcmp_const(hash, checkcode, hash_len) != 0) {
3413ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
3423ff40c12SJohn Marino 		return -1;
3433ff40c12SJohn Marino 	}
3443ff40c12SJohn Marino 
3453ff40c12SJohn Marino 	return 0;
3463ff40c12SJohn Marino }
3473ff40c12SJohn Marino 
3483ff40c12SJohn Marino 
eap_aka_build_identity(struct eap_sm * sm,struct eap_aka_data * data,u8 id)3493ff40c12SJohn Marino static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
3503ff40c12SJohn Marino 					      struct eap_aka_data *data, u8 id)
3513ff40c12SJohn Marino {
3523ff40c12SJohn Marino 	struct eap_sim_msg *msg;
3533ff40c12SJohn Marino 	struct wpabuf *buf;
3543ff40c12SJohn Marino 
3553ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
3563ff40c12SJohn Marino 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
3573ff40c12SJohn Marino 			       EAP_AKA_SUBTYPE_IDENTITY);
3583ff40c12SJohn Marino 	data->identity_round++;
3593ff40c12SJohn Marino 	if (data->identity_round == 1) {
3603ff40c12SJohn Marino 		/*
3613ff40c12SJohn Marino 		 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
3623ff40c12SJohn Marino 		 * ignored and the AKA/Identity is used to request the
3633ff40c12SJohn Marino 		 * identity.
3643ff40c12SJohn Marino 		 */
3653ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
3663ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
3673ff40c12SJohn Marino 	} else if (data->identity_round > 3) {
3683ff40c12SJohn Marino 		/* Cannot use more than three rounds of Identity messages */
3693ff40c12SJohn Marino 		eap_sim_msg_free(msg);
3703ff40c12SJohn Marino 		return NULL;
3713ff40c12SJohn Marino 	} else if (sm->identity && sm->identity_len > 0 &&
3723ff40c12SJohn Marino 		   (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
3733ff40c12SJohn Marino 		    sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) {
3743ff40c12SJohn Marino 		/* Reauth id may have expired - try fullauth */
3753ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
3763ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
3773ff40c12SJohn Marino 	} else {
3783ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
3793ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
3803ff40c12SJohn Marino 	}
381*a1157835SDaniel Fojt 	buf = eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
3823ff40c12SJohn Marino 	if (eap_aka_add_id_msg(data, buf) < 0) {
3833ff40c12SJohn Marino 		wpabuf_free(buf);
3843ff40c12SJohn Marino 		return NULL;
3853ff40c12SJohn Marino 	}
3863ff40c12SJohn Marino 	data->pending_id = id;
3873ff40c12SJohn Marino 	return buf;
3883ff40c12SJohn Marino }
3893ff40c12SJohn Marino 
3903ff40c12SJohn Marino 
eap_aka_build_encr(struct eap_sm * sm,struct eap_aka_data * data,struct eap_sim_msg * msg,u16 counter,const u8 * nonce_s)3913ff40c12SJohn Marino static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
3923ff40c12SJohn Marino 			      struct eap_sim_msg *msg, u16 counter,
3933ff40c12SJohn Marino 			      const u8 *nonce_s)
3943ff40c12SJohn Marino {
3953ff40c12SJohn Marino 	os_free(data->next_pseudonym);
396*a1157835SDaniel Fojt 	if (!(sm->eap_sim_id & 0x01)) {
397*a1157835SDaniel Fojt 		/* Use of pseudonyms disabled in configuration */
398*a1157835SDaniel Fojt 		data->next_pseudonym = NULL;
399*a1157835SDaniel Fojt 	} else if (!nonce_s) {
4003ff40c12SJohn Marino 		data->next_pseudonym =
4013ff40c12SJohn Marino 			eap_sim_db_get_next_pseudonym(
4023ff40c12SJohn Marino 				sm->eap_sim_db_priv,
4033ff40c12SJohn Marino 				data->eap_method == EAP_TYPE_AKA_PRIME ?
4043ff40c12SJohn Marino 				EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
4053ff40c12SJohn Marino 	} else {
4063ff40c12SJohn Marino 		/* Do not update pseudonym during re-authentication */
4073ff40c12SJohn Marino 		data->next_pseudonym = NULL;
4083ff40c12SJohn Marino 	}
4093ff40c12SJohn Marino 	os_free(data->next_reauth_id);
410*a1157835SDaniel Fojt 	if (!(sm->eap_sim_id & 0x02)) {
411*a1157835SDaniel Fojt 		/* Use of fast reauth disabled in configuration */
412*a1157835SDaniel Fojt 		data->next_reauth_id = NULL;
413*a1157835SDaniel Fojt 	} else if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
4143ff40c12SJohn Marino 		data->next_reauth_id =
4153ff40c12SJohn Marino 			eap_sim_db_get_next_reauth_id(
4163ff40c12SJohn Marino 				sm->eap_sim_db_priv,
4173ff40c12SJohn Marino 				data->eap_method == EAP_TYPE_AKA_PRIME ?
4183ff40c12SJohn Marino 				EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
4193ff40c12SJohn Marino 	} else {
4203ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
4213ff40c12SJohn Marino 			   "count exceeded - force full authentication");
4223ff40c12SJohn Marino 		data->next_reauth_id = NULL;
4233ff40c12SJohn Marino 	}
4243ff40c12SJohn Marino 
4253ff40c12SJohn Marino 	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
4263ff40c12SJohn Marino 	    counter == 0 && nonce_s == NULL)
4273ff40c12SJohn Marino 		return 0;
4283ff40c12SJohn Marino 
4293ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "   AT_IV");
4303ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
4313ff40c12SJohn Marino 	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
4323ff40c12SJohn Marino 
4333ff40c12SJohn Marino 	if (counter > 0) {
4343ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
4353ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
4363ff40c12SJohn Marino 	}
4373ff40c12SJohn Marino 
4383ff40c12SJohn Marino 	if (nonce_s) {
4393ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
4403ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
4413ff40c12SJohn Marino 				EAP_SIM_NONCE_S_LEN);
4423ff40c12SJohn Marino 	}
4433ff40c12SJohn Marino 
4443ff40c12SJohn Marino 	if (data->next_pseudonym) {
4453ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
4463ff40c12SJohn Marino 			   data->next_pseudonym);
4473ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
4483ff40c12SJohn Marino 				os_strlen(data->next_pseudonym),
4493ff40c12SJohn Marino 				(u8 *) data->next_pseudonym,
4503ff40c12SJohn Marino 				os_strlen(data->next_pseudonym));
4513ff40c12SJohn Marino 	}
4523ff40c12SJohn Marino 
4533ff40c12SJohn Marino 	if (data->next_reauth_id) {
4543ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
4553ff40c12SJohn Marino 			   data->next_reauth_id);
4563ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
4573ff40c12SJohn Marino 				os_strlen(data->next_reauth_id),
4583ff40c12SJohn Marino 				(u8 *) data->next_reauth_id,
4593ff40c12SJohn Marino 				os_strlen(data->next_reauth_id));
4603ff40c12SJohn Marino 	}
4613ff40c12SJohn Marino 
4623ff40c12SJohn Marino 	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
4633ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
4643ff40c12SJohn Marino 			   "AT_ENCR_DATA");
4653ff40c12SJohn Marino 		return -1;
4663ff40c12SJohn Marino 	}
4673ff40c12SJohn Marino 
4683ff40c12SJohn Marino 	return 0;
4693ff40c12SJohn Marino }
4703ff40c12SJohn Marino 
4713ff40c12SJohn Marino 
eap_aka_build_challenge(struct eap_sm * sm,struct eap_aka_data * data,u8 id)4723ff40c12SJohn Marino static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
4733ff40c12SJohn Marino 					       struct eap_aka_data *data,
4743ff40c12SJohn Marino 					       u8 id)
4753ff40c12SJohn Marino {
4763ff40c12SJohn Marino 	struct eap_sim_msg *msg;
4773ff40c12SJohn Marino 
4783ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
4793ff40c12SJohn Marino 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
4803ff40c12SJohn Marino 			       EAP_AKA_SUBTYPE_CHALLENGE);
4813ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "   AT_RAND");
4823ff40c12SJohn Marino 	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
4833ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "   AT_AUTN");
4843ff40c12SJohn Marino 	eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
4853ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
4863ff40c12SJohn Marino 		if (data->kdf) {
4873ff40c12SJohn Marino 			/* Add the selected KDF into the beginning */
4883ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "   AT_KDF");
4893ff40c12SJohn Marino 			eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
4903ff40c12SJohn Marino 					NULL, 0);
4913ff40c12SJohn Marino 		}
4923ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   AT_KDF");
4933ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
4943ff40c12SJohn Marino 				NULL, 0);
4953ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
4963ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
4973ff40c12SJohn Marino 				data->network_name_len,
4983ff40c12SJohn Marino 				data->network_name, data->network_name_len);
4993ff40c12SJohn Marino 	}
5003ff40c12SJohn Marino 
5013ff40c12SJohn Marino 	if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
5023ff40c12SJohn Marino 		eap_sim_msg_free(msg);
5033ff40c12SJohn Marino 		return NULL;
5043ff40c12SJohn Marino 	}
5053ff40c12SJohn Marino 
5063ff40c12SJohn Marino 	eap_aka_add_checkcode(data, msg);
5073ff40c12SJohn Marino 
5083ff40c12SJohn Marino 	if (sm->eap_sim_aka_result_ind) {
5093ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
5103ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
5113ff40c12SJohn Marino 	}
5123ff40c12SJohn Marino 
5133ff40c12SJohn Marino #ifdef EAP_SERVER_AKA_PRIME
5143ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA) {
5153ff40c12SJohn Marino 		u16 flags = 0;
5163ff40c12SJohn Marino 		int i;
5173ff40c12SJohn Marino 		int aka_prime_preferred = 0;
5183ff40c12SJohn Marino 
5193ff40c12SJohn Marino 		i = 0;
5203ff40c12SJohn Marino 		while (sm->user && i < EAP_MAX_METHODS &&
5213ff40c12SJohn Marino 		       (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
5223ff40c12SJohn Marino 			sm->user->methods[i].method != EAP_TYPE_NONE)) {
5233ff40c12SJohn Marino 			if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
5243ff40c12SJohn Marino 				if (sm->user->methods[i].method ==
5253ff40c12SJohn Marino 				    EAP_TYPE_AKA)
5263ff40c12SJohn Marino 					break;
5273ff40c12SJohn Marino 				if (sm->user->methods[i].method ==
5283ff40c12SJohn Marino 				    EAP_TYPE_AKA_PRIME) {
5293ff40c12SJohn Marino 					aka_prime_preferred = 1;
5303ff40c12SJohn Marino 					break;
5313ff40c12SJohn Marino 				}
5323ff40c12SJohn Marino 			}
5333ff40c12SJohn Marino 			i++;
5343ff40c12SJohn Marino 		}
5353ff40c12SJohn Marino 
5363ff40c12SJohn Marino 		if (aka_prime_preferred)
5373ff40c12SJohn Marino 			flags |= EAP_AKA_BIDDING_FLAG_D;
5383ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
5393ff40c12SJohn Marino 	}
5403ff40c12SJohn Marino #endif /* EAP_SERVER_AKA_PRIME */
5413ff40c12SJohn Marino 
5423ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "   AT_MAC");
5433ff40c12SJohn Marino 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
544*a1157835SDaniel Fojt 	return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
5453ff40c12SJohn Marino }
5463ff40c12SJohn Marino 
5473ff40c12SJohn Marino 
eap_aka_build_reauth(struct eap_sm * sm,struct eap_aka_data * data,u8 id)5483ff40c12SJohn Marino static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
5493ff40c12SJohn Marino 					    struct eap_aka_data *data, u8 id)
5503ff40c12SJohn Marino {
5513ff40c12SJohn Marino 	struct eap_sim_msg *msg;
552*a1157835SDaniel Fojt 	struct wpabuf *buf;
5533ff40c12SJohn Marino 
5543ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
5553ff40c12SJohn Marino 
5563ff40c12SJohn Marino 	if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
5573ff40c12SJohn Marino 		return NULL;
5583ff40c12SJohn Marino 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
5593ff40c12SJohn Marino 			data->nonce_s, EAP_SIM_NONCE_S_LEN);
5603ff40c12SJohn Marino 
5613ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
5623ff40c12SJohn Marino 		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
5633ff40c12SJohn Marino 						 sm->identity,
5643ff40c12SJohn Marino 						 sm->identity_len,
5653ff40c12SJohn Marino 						 data->nonce_s,
5663ff40c12SJohn Marino 						 data->msk, data->emsk);
5673ff40c12SJohn Marino 	} else {
5683ff40c12SJohn Marino 		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
5693ff40c12SJohn Marino 				    data->msk, data->emsk);
5703ff40c12SJohn Marino 		eap_sim_derive_keys_reauth(data->counter, sm->identity,
5713ff40c12SJohn Marino 					   sm->identity_len, data->nonce_s,
5723ff40c12SJohn Marino 					   data->mk, data->msk, data->emsk);
5733ff40c12SJohn Marino 	}
5743ff40c12SJohn Marino 
5753ff40c12SJohn Marino 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
5763ff40c12SJohn Marino 			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
5773ff40c12SJohn Marino 
5783ff40c12SJohn Marino 	if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
5793ff40c12SJohn Marino 		eap_sim_msg_free(msg);
5803ff40c12SJohn Marino 		return NULL;
5813ff40c12SJohn Marino 	}
5823ff40c12SJohn Marino 
5833ff40c12SJohn Marino 	eap_aka_add_checkcode(data, msg);
5843ff40c12SJohn Marino 
5853ff40c12SJohn Marino 	if (sm->eap_sim_aka_result_ind) {
5863ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
5873ff40c12SJohn Marino 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
5883ff40c12SJohn Marino 	}
5893ff40c12SJohn Marino 
5903ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "   AT_MAC");
5913ff40c12SJohn Marino 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
592*a1157835SDaniel Fojt 	buf = eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
593*a1157835SDaniel Fojt 
594*a1157835SDaniel Fojt 	/* Remember this MAC before sending it to the peer. This MAC is used for
595*a1157835SDaniel Fojt 	 * Session-Id calculation after receiving response from the peer and
596*a1157835SDaniel Fojt 	 * after all other checks pass. */
597*a1157835SDaniel Fojt 	os_memcpy(data->reauth_mac,
598*a1157835SDaniel Fojt 		  wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN,
599*a1157835SDaniel Fojt 		  EAP_SIM_MAC_LEN);
600*a1157835SDaniel Fojt 
601*a1157835SDaniel Fojt 	return buf;
6023ff40c12SJohn Marino }
6033ff40c12SJohn Marino 
6043ff40c12SJohn Marino 
eap_aka_build_notification(struct eap_sm * sm,struct eap_aka_data * data,u8 id)6053ff40c12SJohn Marino static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
6063ff40c12SJohn Marino 						  struct eap_aka_data *data,
6073ff40c12SJohn Marino 						  u8 id)
6083ff40c12SJohn Marino {
6093ff40c12SJohn Marino 	struct eap_sim_msg *msg;
6103ff40c12SJohn Marino 
6113ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
6123ff40c12SJohn Marino 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
6133ff40c12SJohn Marino 			       EAP_AKA_SUBTYPE_NOTIFICATION);
6143ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
6153ff40c12SJohn Marino 	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
6163ff40c12SJohn Marino 			NULL, 0);
6173ff40c12SJohn Marino 	if (data->use_result_ind) {
6183ff40c12SJohn Marino 		if (data->reauth) {
6193ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "   AT_IV");
6203ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
6213ff40c12SJohn Marino 			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
6223ff40c12SJohn Marino 						   EAP_SIM_AT_ENCR_DATA);
6233ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
6243ff40c12SJohn Marino 				   data->counter);
6253ff40c12SJohn Marino 			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
6263ff40c12SJohn Marino 					NULL, 0);
6273ff40c12SJohn Marino 
6283ff40c12SJohn Marino 			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
6293ff40c12SJohn Marino 						     EAP_SIM_AT_PADDING)) {
6303ff40c12SJohn Marino 				wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
6313ff40c12SJohn Marino 					   "encrypt AT_ENCR_DATA");
6323ff40c12SJohn Marino 				eap_sim_msg_free(msg);
6333ff40c12SJohn Marino 				return NULL;
6343ff40c12SJohn Marino 			}
6353ff40c12SJohn Marino 		}
6363ff40c12SJohn Marino 
6373ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   AT_MAC");
6383ff40c12SJohn Marino 		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
6393ff40c12SJohn Marino 	}
640*a1157835SDaniel Fojt 	return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
6413ff40c12SJohn Marino }
6423ff40c12SJohn Marino 
6433ff40c12SJohn Marino 
eap_aka_buildReq(struct eap_sm * sm,void * priv,u8 id)6443ff40c12SJohn Marino static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
6453ff40c12SJohn Marino {
6463ff40c12SJohn Marino 	struct eap_aka_data *data = priv;
6473ff40c12SJohn Marino 
6483ff40c12SJohn Marino 	data->auts_reported = 0;
6493ff40c12SJohn Marino 	switch (data->state) {
6503ff40c12SJohn Marino 	case IDENTITY:
6513ff40c12SJohn Marino 		return eap_aka_build_identity(sm, data, id);
6523ff40c12SJohn Marino 	case CHALLENGE:
6533ff40c12SJohn Marino 		return eap_aka_build_challenge(sm, data, id);
6543ff40c12SJohn Marino 	case REAUTH:
6553ff40c12SJohn Marino 		return eap_aka_build_reauth(sm, data, id);
6563ff40c12SJohn Marino 	case NOTIFICATION:
6573ff40c12SJohn Marino 		return eap_aka_build_notification(sm, data, id);
6583ff40c12SJohn Marino 	default:
6593ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
6603ff40c12SJohn Marino 			   "buildReq", data->state);
6613ff40c12SJohn Marino 		break;
6623ff40c12SJohn Marino 	}
6633ff40c12SJohn Marino 	return NULL;
6643ff40c12SJohn Marino }
6653ff40c12SJohn Marino 
6663ff40c12SJohn Marino 
eap_aka_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)6673ff40c12SJohn Marino static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
6683ff40c12SJohn Marino 			     struct wpabuf *respData)
6693ff40c12SJohn Marino {
6703ff40c12SJohn Marino 	struct eap_aka_data *data = priv;
6713ff40c12SJohn Marino 	const u8 *pos;
6723ff40c12SJohn Marino 	size_t len;
6733ff40c12SJohn Marino 
6743ff40c12SJohn Marino 	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
6753ff40c12SJohn Marino 			       &len);
6763ff40c12SJohn Marino 	if (pos == NULL || len < 3) {
6773ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
6783ff40c12SJohn Marino 		return TRUE;
6793ff40c12SJohn Marino 	}
6803ff40c12SJohn Marino 
6813ff40c12SJohn Marino 	return FALSE;
6823ff40c12SJohn Marino }
6833ff40c12SJohn Marino 
6843ff40c12SJohn Marino 
eap_aka_subtype_ok(struct eap_aka_data * data,u8 subtype)6853ff40c12SJohn Marino static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
6863ff40c12SJohn Marino {
6873ff40c12SJohn Marino 	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
6883ff40c12SJohn Marino 	    subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
6893ff40c12SJohn Marino 		return FALSE;
6903ff40c12SJohn Marino 
6913ff40c12SJohn Marino 	switch (data->state) {
6923ff40c12SJohn Marino 	case IDENTITY:
6933ff40c12SJohn Marino 		if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
6943ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
6953ff40c12SJohn Marino 				   "subtype %d", subtype);
6963ff40c12SJohn Marino 			return TRUE;
6973ff40c12SJohn Marino 		}
6983ff40c12SJohn Marino 		break;
6993ff40c12SJohn Marino 	case CHALLENGE:
7003ff40c12SJohn Marino 		if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
7013ff40c12SJohn Marino 		    subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
7023ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
7033ff40c12SJohn Marino 				   "subtype %d", subtype);
7043ff40c12SJohn Marino 			return TRUE;
7053ff40c12SJohn Marino 		}
7063ff40c12SJohn Marino 		break;
7073ff40c12SJohn Marino 	case REAUTH:
7083ff40c12SJohn Marino 		if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
7093ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
7103ff40c12SJohn Marino 				   "subtype %d", subtype);
7113ff40c12SJohn Marino 			return TRUE;
7123ff40c12SJohn Marino 		}
7133ff40c12SJohn Marino 		break;
7143ff40c12SJohn Marino 	case NOTIFICATION:
7153ff40c12SJohn Marino 		if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
7163ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
7173ff40c12SJohn Marino 				   "subtype %d", subtype);
7183ff40c12SJohn Marino 			return TRUE;
7193ff40c12SJohn Marino 		}
7203ff40c12SJohn Marino 		break;
7213ff40c12SJohn Marino 	default:
7223ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
7233ff40c12SJohn Marino 			   "processing a response", data->state);
7243ff40c12SJohn Marino 		return TRUE;
7253ff40c12SJohn Marino 	}
7263ff40c12SJohn Marino 
7273ff40c12SJohn Marino 	return FALSE;
7283ff40c12SJohn Marino }
7293ff40c12SJohn Marino 
7303ff40c12SJohn Marino 
eap_aka_determine_identity(struct eap_sm * sm,struct eap_aka_data * data)7313ff40c12SJohn Marino static void eap_aka_determine_identity(struct eap_sm *sm,
7323ff40c12SJohn Marino 				       struct eap_aka_data *data)
7333ff40c12SJohn Marino {
7343ff40c12SJohn Marino 	char *username;
7353ff40c12SJohn Marino 
7363ff40c12SJohn Marino 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
7373ff40c12SJohn Marino 			  sm->identity, sm->identity_len);
7383ff40c12SJohn Marino 
7393ff40c12SJohn Marino 	username = sim_get_username(sm->identity, sm->identity_len);
7403ff40c12SJohn Marino 	if (username == NULL) {
7413ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
7423ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
7433ff40c12SJohn Marino 		return;
7443ff40c12SJohn Marino 	}
7453ff40c12SJohn Marino 
7463ff40c12SJohn Marino 	if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
7473ff40c12SJohn Marino 		os_free(username);
7483ff40c12SJohn Marino 		return;
7493ff40c12SJohn Marino 	}
7503ff40c12SJohn Marino 
7513ff40c12SJohn Marino 	if (((data->eap_method == EAP_TYPE_AKA_PRIME &&
7523ff40c12SJohn Marino 	      username[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) ||
7533ff40c12SJohn Marino 	     (data->eap_method == EAP_TYPE_AKA &&
7543ff40c12SJohn Marino 	      username[0] == EAP_AKA_REAUTH_ID_PREFIX)) &&
7553ff40c12SJohn Marino 	    data->identity_round == 1) {
7563ff40c12SJohn Marino 		/* Remain in IDENTITY state for another round to request full
7573ff40c12SJohn Marino 		 * auth identity since we did not recognize reauth id */
7583ff40c12SJohn Marino 		os_free(username);
7593ff40c12SJohn Marino 		return;
7603ff40c12SJohn Marino 	}
7613ff40c12SJohn Marino 
7623ff40c12SJohn Marino 	if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
7633ff40c12SJohn Marino 	     username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
7643ff40c12SJohn Marino 	    (data->eap_method == EAP_TYPE_AKA &&
7653ff40c12SJohn Marino 	     username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
7663ff40c12SJohn Marino 		const char *permanent;
7673ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
7683ff40c12SJohn Marino 			   username);
7693ff40c12SJohn Marino 		permanent = eap_sim_db_get_permanent(
7703ff40c12SJohn Marino 			sm->eap_sim_db_priv, username);
7713ff40c12SJohn Marino 		os_free(username);
7723ff40c12SJohn Marino 		if (permanent == NULL) {
7733ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
7743ff40c12SJohn Marino 				   "identity - request permanent identity");
7753ff40c12SJohn Marino 			/* Remain in IDENTITY state for another round */
7763ff40c12SJohn Marino 			return;
7773ff40c12SJohn Marino 		}
7783ff40c12SJohn Marino 		os_strlcpy(data->permanent, permanent,
7793ff40c12SJohn Marino 			   sizeof(data->permanent));
7803ff40c12SJohn Marino 	} else if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
7813ff40c12SJohn Marino 		    username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) ||
7823ff40c12SJohn Marino 		   (data->eap_method == EAP_TYPE_AKA &&
7833ff40c12SJohn Marino 		    username[0] == EAP_AKA_PERMANENT_PREFIX)) {
7843ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'",
7853ff40c12SJohn Marino 			   username);
7863ff40c12SJohn Marino 		os_strlcpy(data->permanent, username, sizeof(data->permanent));
7873ff40c12SJohn Marino 		os_free(username);
7883ff40c12SJohn Marino 	} else {
7893ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'",
7903ff40c12SJohn Marino 			   username);
7913ff40c12SJohn Marino 		os_free(username);
7923ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
7933ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
7943ff40c12SJohn Marino 		return;
7953ff40c12SJohn Marino 	}
7963ff40c12SJohn Marino 
7973ff40c12SJohn Marino 	eap_aka_fullauth(sm, data);
7983ff40c12SJohn Marino }
7993ff40c12SJohn Marino 
8003ff40c12SJohn Marino 
eap_aka_fullauth(struct eap_sm * sm,struct eap_aka_data * data)8013ff40c12SJohn Marino static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data)
8023ff40c12SJohn Marino {
8033ff40c12SJohn Marino 	size_t identity_len;
8043ff40c12SJohn Marino 	int res;
8053ff40c12SJohn Marino 
8063ff40c12SJohn Marino 	res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
8073ff40c12SJohn Marino 				      data->rand, data->autn, data->ik,
8083ff40c12SJohn Marino 				      data->ck, data->res, &data->res_len, sm);
8093ff40c12SJohn Marino 	if (res == EAP_SIM_DB_PENDING) {
8103ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
8113ff40c12SJohn Marino 			   "not yet available - pending request");
8123ff40c12SJohn Marino 		sm->method_pending = METHOD_PENDING_WAIT;
8133ff40c12SJohn Marino 		return;
8143ff40c12SJohn Marino 	}
8153ff40c12SJohn Marino 
816*a1157835SDaniel Fojt 	if (data->permanent[0] == EAP_AKA_PERMANENT_PREFIX ||
817*a1157835SDaniel Fojt 	    data->permanent[0] == EAP_AKA_PRIME_PERMANENT_PREFIX)
818*a1157835SDaniel Fojt 		os_strlcpy(sm->imsi, &data->permanent[1], sizeof(sm->imsi));
819*a1157835SDaniel Fojt 
8203ff40c12SJohn Marino #ifdef EAP_SERVER_AKA_PRIME
8213ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
8223ff40c12SJohn Marino 		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
8233ff40c12SJohn Marino 		 * needed 6-octet SQN ^AK for CK',IK' derivation */
8243ff40c12SJohn Marino 		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
8253ff40c12SJohn Marino 						 data->autn,
8263ff40c12SJohn Marino 						 data->network_name,
8273ff40c12SJohn Marino 						 data->network_name_len);
8283ff40c12SJohn Marino 	}
8293ff40c12SJohn Marino #endif /* EAP_SERVER_AKA_PRIME */
8303ff40c12SJohn Marino 
8313ff40c12SJohn Marino 	data->reauth = NULL;
8323ff40c12SJohn Marino 	data->counter = 0; /* reset re-auth counter since this is full auth */
8333ff40c12SJohn Marino 
8343ff40c12SJohn Marino 	if (res != 0) {
8353ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
8363ff40c12SJohn Marino 			   "authentication data for the peer");
8373ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
8383ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
8393ff40c12SJohn Marino 		return;
8403ff40c12SJohn Marino 	}
8413ff40c12SJohn Marino 	if (sm->method_pending == METHOD_PENDING_WAIT) {
8423ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
8433ff40c12SJohn Marino 			   "available - abort pending wait");
8443ff40c12SJohn Marino 		sm->method_pending = METHOD_PENDING_NONE;
8453ff40c12SJohn Marino 	}
8463ff40c12SJohn Marino 
8473ff40c12SJohn Marino 	identity_len = sm->identity_len;
8483ff40c12SJohn Marino 	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
8493ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
8503ff40c12SJohn Marino 			   "character from identity");
8513ff40c12SJohn Marino 		identity_len--;
8523ff40c12SJohn Marino 	}
8533ff40c12SJohn Marino 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
8543ff40c12SJohn Marino 			  sm->identity, identity_len);
8553ff40c12SJohn Marino 
8563ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
8573ff40c12SJohn Marino 		eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik,
8583ff40c12SJohn Marino 					  data->ck, data->k_encr, data->k_aut,
8593ff40c12SJohn Marino 					  data->k_re, data->msk, data->emsk);
8603ff40c12SJohn Marino 	} else {
8613ff40c12SJohn Marino 		eap_aka_derive_mk(sm->identity, identity_len, data->ik,
8623ff40c12SJohn Marino 				  data->ck, data->mk);
8633ff40c12SJohn Marino 		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
8643ff40c12SJohn Marino 				    data->msk, data->emsk);
8653ff40c12SJohn Marino 	}
8663ff40c12SJohn Marino 
8673ff40c12SJohn Marino 	eap_aka_state(data, CHALLENGE);
8683ff40c12SJohn Marino }
8693ff40c12SJohn Marino 
8703ff40c12SJohn Marino 
eap_aka_process_identity(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)8713ff40c12SJohn Marino static void eap_aka_process_identity(struct eap_sm *sm,
8723ff40c12SJohn Marino 				     struct eap_aka_data *data,
8733ff40c12SJohn Marino 				     struct wpabuf *respData,
8743ff40c12SJohn Marino 				     struct eap_sim_attrs *attr)
8753ff40c12SJohn Marino {
8763ff40c12SJohn Marino 	u8 *new_identity;
8773ff40c12SJohn Marino 
8783ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
8793ff40c12SJohn Marino 
8803ff40c12SJohn Marino 	if (attr->mac || attr->iv || attr->encr_data) {
8813ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
8823ff40c12SJohn Marino 			   "received in EAP-Response/AKA-Identity");
8833ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
8843ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
8853ff40c12SJohn Marino 		return;
8863ff40c12SJohn Marino 	}
8873ff40c12SJohn Marino 
8883ff40c12SJohn Marino 	/*
8893ff40c12SJohn Marino 	 * We always request identity with AKA/Identity, so the peer is
8903ff40c12SJohn Marino 	 * required to have replied with one.
8913ff40c12SJohn Marino 	 */
8923ff40c12SJohn Marino 	if (!attr->identity || attr->identity_len == 0) {
8933ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Peer did not provide any "
8943ff40c12SJohn Marino 			   "identity");
8953ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
8963ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
8973ff40c12SJohn Marino 		return;
8983ff40c12SJohn Marino 	}
8993ff40c12SJohn Marino 
9003ff40c12SJohn Marino 	new_identity = os_malloc(attr->identity_len);
9013ff40c12SJohn Marino 	if (new_identity == NULL) {
9023ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
9033ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
9043ff40c12SJohn Marino 		return;
9053ff40c12SJohn Marino 	}
9063ff40c12SJohn Marino 	os_free(sm->identity);
9073ff40c12SJohn Marino 	sm->identity = new_identity;
9083ff40c12SJohn Marino 	os_memcpy(sm->identity, attr->identity, attr->identity_len);
9093ff40c12SJohn Marino 	sm->identity_len = attr->identity_len;
9103ff40c12SJohn Marino 
9113ff40c12SJohn Marino 	eap_aka_determine_identity(sm, data);
9123ff40c12SJohn Marino 	if (eap_get_id(respData) == data->pending_id) {
9133ff40c12SJohn Marino 		data->pending_id = -1;
9143ff40c12SJohn Marino 		eap_aka_add_id_msg(data, respData);
9153ff40c12SJohn Marino 	}
9163ff40c12SJohn Marino }
9173ff40c12SJohn Marino 
9183ff40c12SJohn Marino 
eap_aka_verify_mac(struct eap_aka_data * data,const struct wpabuf * req,const u8 * mac,const u8 * extra,size_t extra_len)9193ff40c12SJohn Marino static int eap_aka_verify_mac(struct eap_aka_data *data,
9203ff40c12SJohn Marino 			      const struct wpabuf *req,
9213ff40c12SJohn Marino 			      const u8 *mac, const u8 *extra,
9223ff40c12SJohn Marino 			      size_t extra_len)
9233ff40c12SJohn Marino {
9243ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
9253ff40c12SJohn Marino 		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
9263ff40c12SJohn Marino 						 extra_len);
9273ff40c12SJohn Marino 	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
9283ff40c12SJohn Marino }
9293ff40c12SJohn Marino 
9303ff40c12SJohn Marino 
eap_aka_process_challenge(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)9313ff40c12SJohn Marino static void eap_aka_process_challenge(struct eap_sm *sm,
9323ff40c12SJohn Marino 				      struct eap_aka_data *data,
9333ff40c12SJohn Marino 				      struct wpabuf *respData,
9343ff40c12SJohn Marino 				      struct eap_sim_attrs *attr)
9353ff40c12SJohn Marino {
9363ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
9373ff40c12SJohn Marino 
9383ff40c12SJohn Marino #ifdef EAP_SERVER_AKA_PRIME
9393ff40c12SJohn Marino #if 0
9403ff40c12SJohn Marino 	/* KDF negotiation; to be enabled only after more than one KDF is
9413ff40c12SJohn Marino 	 * supported */
9423ff40c12SJohn Marino 	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
9433ff40c12SJohn Marino 	    attr->kdf_count == 1 && attr->mac == NULL) {
9443ff40c12SJohn Marino 		if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
9453ff40c12SJohn Marino 			wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
9463ff40c12SJohn Marino 				   "unknown KDF");
9473ff40c12SJohn Marino 			data->notification =
9483ff40c12SJohn Marino 				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
9493ff40c12SJohn Marino 			eap_aka_state(data, NOTIFICATION);
9503ff40c12SJohn Marino 			return;
9513ff40c12SJohn Marino 		}
9523ff40c12SJohn Marino 
9533ff40c12SJohn Marino 		data->kdf = attr->kdf[0];
9543ff40c12SJohn Marino 
9553ff40c12SJohn Marino 		/* Allow negotiation to continue with the selected KDF by
9563ff40c12SJohn Marino 		 * sending another Challenge message */
9573ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
9583ff40c12SJohn Marino 		return;
9593ff40c12SJohn Marino 	}
9603ff40c12SJohn Marino #endif
9613ff40c12SJohn Marino #endif /* EAP_SERVER_AKA_PRIME */
9623ff40c12SJohn Marino 
9633ff40c12SJohn Marino 	if (attr->checkcode &&
9643ff40c12SJohn Marino 	    eap_aka_verify_checkcode(data, attr->checkcode,
9653ff40c12SJohn Marino 				     attr->checkcode_len)) {
9663ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
9673ff40c12SJohn Marino 			   "message");
9683ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
9693ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
9703ff40c12SJohn Marino 		return;
9713ff40c12SJohn Marino 	}
9723ff40c12SJohn Marino 	if (attr->mac == NULL ||
9733ff40c12SJohn Marino 	    eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
9743ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
9753ff40c12SJohn Marino 			   "did not include valid AT_MAC");
9763ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
9773ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
9783ff40c12SJohn Marino 		return;
9793ff40c12SJohn Marino 	}
9803ff40c12SJohn Marino 
9813ff40c12SJohn Marino 	/*
9823ff40c12SJohn Marino 	 * AT_RES is padded, so verify that there is enough room for RES and
9833ff40c12SJohn Marino 	 * that the RES length in bits matches with the expected RES.
9843ff40c12SJohn Marino 	 */
9853ff40c12SJohn Marino 	if (attr->res == NULL || attr->res_len < data->res_len ||
9863ff40c12SJohn Marino 	    attr->res_len_bits != data->res_len * 8 ||
987*a1157835SDaniel Fojt 	    os_memcmp_const(attr->res, data->res, data->res_len) != 0) {
9883ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
9893ff40c12SJohn Marino 			   "include valid AT_RES (attr len=%lu, res len=%lu "
9903ff40c12SJohn Marino 			   "bits, expected %lu bits)",
9913ff40c12SJohn Marino 			   (unsigned long) attr->res_len,
9923ff40c12SJohn Marino 			   (unsigned long) attr->res_len_bits,
9933ff40c12SJohn Marino 			   (unsigned long) data->res_len * 8);
9943ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
9953ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
9963ff40c12SJohn Marino 		return;
9973ff40c12SJohn Marino 	}
9983ff40c12SJohn Marino 
9993ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
10003ff40c12SJohn Marino 		   "correct AT_MAC");
10013ff40c12SJohn Marino 	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
10023ff40c12SJohn Marino 		data->use_result_ind = 1;
10033ff40c12SJohn Marino 		data->notification = EAP_SIM_SUCCESS;
10043ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
10053ff40c12SJohn Marino 	} else
10063ff40c12SJohn Marino 		eap_aka_state(data, SUCCESS);
10073ff40c12SJohn Marino 
10083ff40c12SJohn Marino 	if (data->next_pseudonym) {
10093ff40c12SJohn Marino 		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
10103ff40c12SJohn Marino 					 data->next_pseudonym);
10113ff40c12SJohn Marino 		data->next_pseudonym = NULL;
10123ff40c12SJohn Marino 	}
10133ff40c12SJohn Marino 	if (data->next_reauth_id) {
10143ff40c12SJohn Marino 		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
10153ff40c12SJohn Marino #ifdef EAP_SERVER_AKA_PRIME
10163ff40c12SJohn Marino 			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
10173ff40c12SJohn Marino 						    data->permanent,
10183ff40c12SJohn Marino 						    data->next_reauth_id,
10193ff40c12SJohn Marino 						    data->counter + 1,
10203ff40c12SJohn Marino 						    data->k_encr, data->k_aut,
10213ff40c12SJohn Marino 						    data->k_re);
10223ff40c12SJohn Marino #endif /* EAP_SERVER_AKA_PRIME */
10233ff40c12SJohn Marino 		} else {
10243ff40c12SJohn Marino 			eap_sim_db_add_reauth(sm->eap_sim_db_priv,
10253ff40c12SJohn Marino 					      data->permanent,
10263ff40c12SJohn Marino 					      data->next_reauth_id,
10273ff40c12SJohn Marino 					      data->counter + 1,
10283ff40c12SJohn Marino 					      data->mk);
10293ff40c12SJohn Marino 		}
10303ff40c12SJohn Marino 		data->next_reauth_id = NULL;
10313ff40c12SJohn Marino 	}
10323ff40c12SJohn Marino }
10333ff40c12SJohn Marino 
10343ff40c12SJohn Marino 
eap_aka_process_sync_failure(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)10353ff40c12SJohn Marino static void eap_aka_process_sync_failure(struct eap_sm *sm,
10363ff40c12SJohn Marino 					 struct eap_aka_data *data,
10373ff40c12SJohn Marino 					 struct wpabuf *respData,
10383ff40c12SJohn Marino 					 struct eap_sim_attrs *attr)
10393ff40c12SJohn Marino {
10403ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
10413ff40c12SJohn Marino 
10423ff40c12SJohn Marino 	if (attr->auts == NULL) {
10433ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
10443ff40c12SJohn Marino 			   "message did not include valid AT_AUTS");
10453ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
10463ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
10473ff40c12SJohn Marino 		return;
10483ff40c12SJohn Marino 	}
10493ff40c12SJohn Marino 
10503ff40c12SJohn Marino 	/* Avoid re-reporting AUTS when processing pending EAP packet by
10513ff40c12SJohn Marino 	 * maintaining a local flag stating whether this AUTS has already been
10523ff40c12SJohn Marino 	 * reported. */
10533ff40c12SJohn Marino 	if (!data->auts_reported &&
10543ff40c12SJohn Marino 	    eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent,
10553ff40c12SJohn Marino 				     attr->auts, data->rand)) {
10563ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
10573ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
10583ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
10593ff40c12SJohn Marino 		return;
10603ff40c12SJohn Marino 	}
10613ff40c12SJohn Marino 	data->auts_reported = 1;
10623ff40c12SJohn Marino 
10633ff40c12SJohn Marino 	/* Remain in CHALLENGE state to re-try after resynchronization */
10643ff40c12SJohn Marino 	eap_aka_fullauth(sm, data);
10653ff40c12SJohn Marino }
10663ff40c12SJohn Marino 
10673ff40c12SJohn Marino 
eap_aka_process_reauth(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)10683ff40c12SJohn Marino static void eap_aka_process_reauth(struct eap_sm *sm,
10693ff40c12SJohn Marino 				   struct eap_aka_data *data,
10703ff40c12SJohn Marino 				   struct wpabuf *respData,
10713ff40c12SJohn Marino 				   struct eap_sim_attrs *attr)
10723ff40c12SJohn Marino {
10733ff40c12SJohn Marino 	struct eap_sim_attrs eattr;
10743ff40c12SJohn Marino 	u8 *decrypted = NULL;
10753ff40c12SJohn Marino 
10763ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
10773ff40c12SJohn Marino 
10783ff40c12SJohn Marino 	if (attr->mac == NULL ||
10793ff40c12SJohn Marino 	    eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
10803ff40c12SJohn Marino 			       EAP_SIM_NONCE_S_LEN)) {
10813ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
10823ff40c12SJohn Marino 			   "did not include valid AT_MAC");
10833ff40c12SJohn Marino 		goto fail;
10843ff40c12SJohn Marino 	}
10853ff40c12SJohn Marino 
10863ff40c12SJohn Marino 	if (attr->encr_data == NULL || attr->iv == NULL) {
10873ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
10883ff40c12SJohn Marino 			   "message did not include encrypted data");
10893ff40c12SJohn Marino 		goto fail;
10903ff40c12SJohn Marino 	}
10913ff40c12SJohn Marino 
10923ff40c12SJohn Marino 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
10933ff40c12SJohn Marino 				       attr->encr_data_len, attr->iv, &eattr,
10943ff40c12SJohn Marino 				       0);
10953ff40c12SJohn Marino 	if (decrypted == NULL) {
10963ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
10973ff40c12SJohn Marino 			   "data from reauthentication message");
10983ff40c12SJohn Marino 		goto fail;
10993ff40c12SJohn Marino 	}
11003ff40c12SJohn Marino 
11013ff40c12SJohn Marino 	if (eattr.counter != data->counter) {
11023ff40c12SJohn Marino 		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
11033ff40c12SJohn Marino 			   "used incorrect counter %u, expected %u",
11043ff40c12SJohn Marino 			   eattr.counter, data->counter);
11053ff40c12SJohn Marino 		goto fail;
11063ff40c12SJohn Marino 	}
11073ff40c12SJohn Marino 	os_free(decrypted);
11083ff40c12SJohn Marino 	decrypted = NULL;
11093ff40c12SJohn Marino 
11103ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
11113ff40c12SJohn Marino 		   "the correct AT_MAC");
11123ff40c12SJohn Marino 
11133ff40c12SJohn Marino 	if (eattr.counter_too_small) {
11143ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
11153ff40c12SJohn Marino 			   "included AT_COUNTER_TOO_SMALL - starting full "
11163ff40c12SJohn Marino 			   "authentication");
11173ff40c12SJohn Marino 		eap_aka_fullauth(sm, data);
11183ff40c12SJohn Marino 		return;
11193ff40c12SJohn Marino 	}
11203ff40c12SJohn Marino 
11213ff40c12SJohn Marino 	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
11223ff40c12SJohn Marino 		data->use_result_ind = 1;
11233ff40c12SJohn Marino 		data->notification = EAP_SIM_SUCCESS;
11243ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
11253ff40c12SJohn Marino 	} else
11263ff40c12SJohn Marino 		eap_aka_state(data, SUCCESS);
11273ff40c12SJohn Marino 
11283ff40c12SJohn Marino 	if (data->next_reauth_id) {
11293ff40c12SJohn Marino 		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
11303ff40c12SJohn Marino #ifdef EAP_SERVER_AKA_PRIME
11313ff40c12SJohn Marino 			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
11323ff40c12SJohn Marino 						    data->permanent,
11333ff40c12SJohn Marino 						    data->next_reauth_id,
11343ff40c12SJohn Marino 						    data->counter + 1,
11353ff40c12SJohn Marino 						    data->k_encr, data->k_aut,
11363ff40c12SJohn Marino 						    data->k_re);
11373ff40c12SJohn Marino #endif /* EAP_SERVER_AKA_PRIME */
11383ff40c12SJohn Marino 		} else {
11393ff40c12SJohn Marino 			eap_sim_db_add_reauth(sm->eap_sim_db_priv,
11403ff40c12SJohn Marino 					      data->permanent,
11413ff40c12SJohn Marino 					      data->next_reauth_id,
11423ff40c12SJohn Marino 					      data->counter + 1,
11433ff40c12SJohn Marino 					      data->mk);
11443ff40c12SJohn Marino 		}
11453ff40c12SJohn Marino 		data->next_reauth_id = NULL;
11463ff40c12SJohn Marino 	} else {
11473ff40c12SJohn Marino 		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
11483ff40c12SJohn Marino 		data->reauth = NULL;
11493ff40c12SJohn Marino 	}
11503ff40c12SJohn Marino 
11513ff40c12SJohn Marino 	return;
11523ff40c12SJohn Marino 
11533ff40c12SJohn Marino fail:
11543ff40c12SJohn Marino 	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
11553ff40c12SJohn Marino 	eap_aka_state(data, NOTIFICATION);
11563ff40c12SJohn Marino 	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
11573ff40c12SJohn Marino 	data->reauth = NULL;
11583ff40c12SJohn Marino 	os_free(decrypted);
11593ff40c12SJohn Marino }
11603ff40c12SJohn Marino 
11613ff40c12SJohn Marino 
eap_aka_process_client_error(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)11623ff40c12SJohn Marino static void eap_aka_process_client_error(struct eap_sm *sm,
11633ff40c12SJohn Marino 					 struct eap_aka_data *data,
11643ff40c12SJohn Marino 					 struct wpabuf *respData,
11653ff40c12SJohn Marino 					 struct eap_sim_attrs *attr)
11663ff40c12SJohn Marino {
11673ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
11683ff40c12SJohn Marino 		   attr->client_error_code);
11693ff40c12SJohn Marino 	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
11703ff40c12SJohn Marino 		eap_aka_state(data, SUCCESS);
11713ff40c12SJohn Marino 	else
11723ff40c12SJohn Marino 		eap_aka_state(data, FAILURE);
11733ff40c12SJohn Marino }
11743ff40c12SJohn Marino 
11753ff40c12SJohn Marino 
eap_aka_process_authentication_reject(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)11763ff40c12SJohn Marino static void eap_aka_process_authentication_reject(
11773ff40c12SJohn Marino 	struct eap_sm *sm, struct eap_aka_data *data,
11783ff40c12SJohn Marino 	struct wpabuf *respData, struct eap_sim_attrs *attr)
11793ff40c12SJohn Marino {
11803ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
11813ff40c12SJohn Marino 	eap_aka_state(data, FAILURE);
11823ff40c12SJohn Marino }
11833ff40c12SJohn Marino 
11843ff40c12SJohn Marino 
eap_aka_process_notification(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)11853ff40c12SJohn Marino static void eap_aka_process_notification(struct eap_sm *sm,
11863ff40c12SJohn Marino 					 struct eap_aka_data *data,
11873ff40c12SJohn Marino 					 struct wpabuf *respData,
11883ff40c12SJohn Marino 					 struct eap_sim_attrs *attr)
11893ff40c12SJohn Marino {
11903ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
11913ff40c12SJohn Marino 	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
11923ff40c12SJohn Marino 		eap_aka_state(data, SUCCESS);
11933ff40c12SJohn Marino 	else
11943ff40c12SJohn Marino 		eap_aka_state(data, FAILURE);
11953ff40c12SJohn Marino }
11963ff40c12SJohn Marino 
11973ff40c12SJohn Marino 
eap_aka_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)11983ff40c12SJohn Marino static void eap_aka_process(struct eap_sm *sm, void *priv,
11993ff40c12SJohn Marino 			    struct wpabuf *respData)
12003ff40c12SJohn Marino {
12013ff40c12SJohn Marino 	struct eap_aka_data *data = priv;
12023ff40c12SJohn Marino 	const u8 *pos, *end;
12033ff40c12SJohn Marino 	u8 subtype;
12043ff40c12SJohn Marino 	size_t len;
12053ff40c12SJohn Marino 	struct eap_sim_attrs attr;
12063ff40c12SJohn Marino 
12073ff40c12SJohn Marino 	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
12083ff40c12SJohn Marino 			       &len);
12093ff40c12SJohn Marino 	if (pos == NULL || len < 3)
12103ff40c12SJohn Marino 		return;
12113ff40c12SJohn Marino 
12123ff40c12SJohn Marino 	end = pos + len;
12133ff40c12SJohn Marino 	subtype = *pos;
12143ff40c12SJohn Marino 	pos += 3;
12153ff40c12SJohn Marino 
12163ff40c12SJohn Marino 	if (eap_aka_subtype_ok(data, subtype)) {
12173ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
12183ff40c12SJohn Marino 			   "EAP-AKA Subtype in EAP Response");
12193ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
12203ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
12213ff40c12SJohn Marino 		return;
12223ff40c12SJohn Marino 	}
12233ff40c12SJohn Marino 
12243ff40c12SJohn Marino 	if (eap_sim_parse_attr(pos, end, &attr,
12253ff40c12SJohn Marino 			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
12263ff40c12SJohn Marino 			       0)) {
12273ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
12283ff40c12SJohn Marino 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
12293ff40c12SJohn Marino 		eap_aka_state(data, NOTIFICATION);
12303ff40c12SJohn Marino 		return;
12313ff40c12SJohn Marino 	}
12323ff40c12SJohn Marino 
12333ff40c12SJohn Marino 	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
12343ff40c12SJohn Marino 		eap_aka_process_client_error(sm, data, respData, &attr);
12353ff40c12SJohn Marino 		return;
12363ff40c12SJohn Marino 	}
12373ff40c12SJohn Marino 
12383ff40c12SJohn Marino 	if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
12393ff40c12SJohn Marino 		eap_aka_process_authentication_reject(sm, data, respData,
12403ff40c12SJohn Marino 						      &attr);
12413ff40c12SJohn Marino 		return;
12423ff40c12SJohn Marino 	}
12433ff40c12SJohn Marino 
12443ff40c12SJohn Marino 	switch (data->state) {
12453ff40c12SJohn Marino 	case IDENTITY:
12463ff40c12SJohn Marino 		eap_aka_process_identity(sm, data, respData, &attr);
12473ff40c12SJohn Marino 		break;
12483ff40c12SJohn Marino 	case CHALLENGE:
12493ff40c12SJohn Marino 		if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
12503ff40c12SJohn Marino 			eap_aka_process_sync_failure(sm, data, respData,
12513ff40c12SJohn Marino 						     &attr);
12523ff40c12SJohn Marino 		} else {
12533ff40c12SJohn Marino 			eap_aka_process_challenge(sm, data, respData, &attr);
12543ff40c12SJohn Marino 		}
12553ff40c12SJohn Marino 		break;
12563ff40c12SJohn Marino 	case REAUTH:
12573ff40c12SJohn Marino 		eap_aka_process_reauth(sm, data, respData, &attr);
12583ff40c12SJohn Marino 		break;
12593ff40c12SJohn Marino 	case NOTIFICATION:
12603ff40c12SJohn Marino 		eap_aka_process_notification(sm, data, respData, &attr);
12613ff40c12SJohn Marino 		break;
12623ff40c12SJohn Marino 	default:
12633ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
12643ff40c12SJohn Marino 			   "process", data->state);
12653ff40c12SJohn Marino 		break;
12663ff40c12SJohn Marino 	}
12673ff40c12SJohn Marino }
12683ff40c12SJohn Marino 
12693ff40c12SJohn Marino 
eap_aka_isDone(struct eap_sm * sm,void * priv)12703ff40c12SJohn Marino static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
12713ff40c12SJohn Marino {
12723ff40c12SJohn Marino 	struct eap_aka_data *data = priv;
12733ff40c12SJohn Marino 	return data->state == SUCCESS || data->state == FAILURE;
12743ff40c12SJohn Marino }
12753ff40c12SJohn Marino 
12763ff40c12SJohn Marino 
eap_aka_getKey(struct eap_sm * sm,void * priv,size_t * len)12773ff40c12SJohn Marino static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
12783ff40c12SJohn Marino {
12793ff40c12SJohn Marino 	struct eap_aka_data *data = priv;
12803ff40c12SJohn Marino 	u8 *key;
12813ff40c12SJohn Marino 
12823ff40c12SJohn Marino 	if (data->state != SUCCESS)
12833ff40c12SJohn Marino 		return NULL;
12843ff40c12SJohn Marino 
1285*a1157835SDaniel Fojt 	key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
12863ff40c12SJohn Marino 	if (key == NULL)
12873ff40c12SJohn Marino 		return NULL;
12883ff40c12SJohn Marino 	*len = EAP_SIM_KEYING_DATA_LEN;
12893ff40c12SJohn Marino 	return key;
12903ff40c12SJohn Marino }
12913ff40c12SJohn Marino 
12923ff40c12SJohn Marino 
eap_aka_get_emsk(struct eap_sm * sm,void * priv,size_t * len)12933ff40c12SJohn Marino static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
12943ff40c12SJohn Marino {
12953ff40c12SJohn Marino 	struct eap_aka_data *data = priv;
12963ff40c12SJohn Marino 	u8 *key;
12973ff40c12SJohn Marino 
12983ff40c12SJohn Marino 	if (data->state != SUCCESS)
12993ff40c12SJohn Marino 		return NULL;
13003ff40c12SJohn Marino 
1301*a1157835SDaniel Fojt 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
13023ff40c12SJohn Marino 	if (key == NULL)
13033ff40c12SJohn Marino 		return NULL;
13043ff40c12SJohn Marino 	*len = EAP_EMSK_LEN;
13053ff40c12SJohn Marino 	return key;
13063ff40c12SJohn Marino }
13073ff40c12SJohn Marino 
13083ff40c12SJohn Marino 
eap_aka_isSuccess(struct eap_sm * sm,void * priv)13093ff40c12SJohn Marino static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
13103ff40c12SJohn Marino {
13113ff40c12SJohn Marino 	struct eap_aka_data *data = priv;
13123ff40c12SJohn Marino 	return data->state == SUCCESS;
13133ff40c12SJohn Marino }
13143ff40c12SJohn Marino 
13153ff40c12SJohn Marino 
eap_aka_get_session_id(struct eap_sm * sm,void * priv,size_t * len)1316*a1157835SDaniel Fojt static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
1317*a1157835SDaniel Fojt {
1318*a1157835SDaniel Fojt 	struct eap_aka_data *data = priv;
1319*a1157835SDaniel Fojt 	u8 *id;
1320*a1157835SDaniel Fojt 
1321*a1157835SDaniel Fojt 	if (data->state != SUCCESS)
1322*a1157835SDaniel Fojt 		return NULL;
1323*a1157835SDaniel Fojt 
1324*a1157835SDaniel Fojt 	if (!data->reauth)
1325*a1157835SDaniel Fojt 		*len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
1326*a1157835SDaniel Fojt 	else
1327*a1157835SDaniel Fojt 		*len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
1328*a1157835SDaniel Fojt 	id = os_malloc(*len);
1329*a1157835SDaniel Fojt 	if (id == NULL)
1330*a1157835SDaniel Fojt 		return NULL;
1331*a1157835SDaniel Fojt 
1332*a1157835SDaniel Fojt 	id[0] = data->eap_method;
1333*a1157835SDaniel Fojt 	if (!data->reauth) {
1334*a1157835SDaniel Fojt 		os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
1335*a1157835SDaniel Fojt 		os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn,
1336*a1157835SDaniel Fojt 			  EAP_AKA_AUTN_LEN);
1337*a1157835SDaniel Fojt 	} else {
1338*a1157835SDaniel Fojt 		os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
1339*a1157835SDaniel Fojt 		os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
1340*a1157835SDaniel Fojt 			  EAP_SIM_MAC_LEN);
1341*a1157835SDaniel Fojt 	}
1342*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
1343*a1157835SDaniel Fojt 
1344*a1157835SDaniel Fojt 	return id;
1345*a1157835SDaniel Fojt }
1346*a1157835SDaniel Fojt 
1347*a1157835SDaniel Fojt 
eap_server_aka_register(void)13483ff40c12SJohn Marino int eap_server_aka_register(void)
13493ff40c12SJohn Marino {
13503ff40c12SJohn Marino 	struct eap_method *eap;
13513ff40c12SJohn Marino 
13523ff40c12SJohn Marino 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
13533ff40c12SJohn Marino 				      EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
13543ff40c12SJohn Marino 	if (eap == NULL)
13553ff40c12SJohn Marino 		return -1;
13563ff40c12SJohn Marino 
13573ff40c12SJohn Marino 	eap->init = eap_aka_init;
13583ff40c12SJohn Marino 	eap->reset = eap_aka_reset;
13593ff40c12SJohn Marino 	eap->buildReq = eap_aka_buildReq;
13603ff40c12SJohn Marino 	eap->check = eap_aka_check;
13613ff40c12SJohn Marino 	eap->process = eap_aka_process;
13623ff40c12SJohn Marino 	eap->isDone = eap_aka_isDone;
13633ff40c12SJohn Marino 	eap->getKey = eap_aka_getKey;
13643ff40c12SJohn Marino 	eap->isSuccess = eap_aka_isSuccess;
13653ff40c12SJohn Marino 	eap->get_emsk = eap_aka_get_emsk;
1366*a1157835SDaniel Fojt 	eap->getSessionId = eap_aka_get_session_id;
13673ff40c12SJohn Marino 
1368*a1157835SDaniel Fojt 	return eap_server_method_register(eap);
13693ff40c12SJohn Marino }
13703ff40c12SJohn Marino 
13713ff40c12SJohn Marino 
13723ff40c12SJohn Marino #ifdef EAP_SERVER_AKA_PRIME
eap_server_aka_prime_register(void)13733ff40c12SJohn Marino int eap_server_aka_prime_register(void)
13743ff40c12SJohn Marino {
13753ff40c12SJohn Marino 	struct eap_method *eap;
13763ff40c12SJohn Marino 
13773ff40c12SJohn Marino 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
13783ff40c12SJohn Marino 				      EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
13793ff40c12SJohn Marino 				      "AKA'");
13803ff40c12SJohn Marino 	if (eap == NULL)
13813ff40c12SJohn Marino 		return -1;
13823ff40c12SJohn Marino 
13833ff40c12SJohn Marino 	eap->init = eap_aka_prime_init;
13843ff40c12SJohn Marino 	eap->reset = eap_aka_reset;
13853ff40c12SJohn Marino 	eap->buildReq = eap_aka_buildReq;
13863ff40c12SJohn Marino 	eap->check = eap_aka_check;
13873ff40c12SJohn Marino 	eap->process = eap_aka_process;
13883ff40c12SJohn Marino 	eap->isDone = eap_aka_isDone;
13893ff40c12SJohn Marino 	eap->getKey = eap_aka_getKey;
13903ff40c12SJohn Marino 	eap->isSuccess = eap_aka_isSuccess;
13913ff40c12SJohn Marino 	eap->get_emsk = eap_aka_get_emsk;
1392*a1157835SDaniel Fojt 	eap->getSessionId = eap_aka_get_session_id;
13933ff40c12SJohn Marino 
1394*a1157835SDaniel Fojt 	return eap_server_method_register(eap);
13953ff40c12SJohn Marino }
13963ff40c12SJohn Marino #endif /* EAP_SERVER_AKA_PRIME */
1397