eap_server_aka.c revision d5e4923d04122f81300fa68fb07d64ede28fd44d
19f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
29f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
39f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
49f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
59f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * This software may be distributed under the terms of the BSD license.
69f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * See README for more details.
79f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
89f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
99f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "includes.h"
109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "common.h"
129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "crypto/sha256.h"
139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "crypto/crypto.h"
149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "crypto/random.h"
159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "eap_common/eap_sim_common.h"
169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "eap_server/eap_i.h"
179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "eap_server/eap_sim_db.h"
189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstruct eap_aka_data {
219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 mk[EAP_SIM_MK_LEN];
229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 k_encr[EAP_SIM_K_ENCR_LEN];
259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 msk[EAP_SIM_KEYING_DATA_LEN];
279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 emsk[EAP_EMSK_LEN];
289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 rand[EAP_AKA_RAND_LEN];
299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 autn[EAP_AKA_AUTN_LEN];
309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 ck[EAP_AKA_CK_LEN];
319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 ik[EAP_AKA_IK_LEN];
329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 res[EAP_AKA_RES_MAX_LEN];
339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	size_t res_len;
349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	enum {
359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	} state;
379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	char *next_pseudonym;
389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	char *next_reauth_id;
399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u16 counter;
409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct eap_sim_reauth *reauth;
419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int auts_reported; /* whether the current AUTS has been reported to the
429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			    * eap_sim_db */
439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u16 notification;
449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int use_result_ind;
459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct wpabuf *id_msgs;
479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int pending_id;
489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 eap_method;
499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 *network_name;
509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	size_t network_name_len;
519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u16 kdf;
529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int identity_round;
539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	char permanent[20]; /* Permanent username */
549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson};
559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data);
589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic const char * eap_aka_state_txt(int state)
619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	switch (state) {
639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case IDENTITY:
649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return "IDENTITY";
659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case CHALLENGE:
669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return "CHALLENGE";
679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case REAUTH:
689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return "REAUTH";
699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case SUCCESS:
709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return "SUCCESS";
719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case FAILURE:
729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return "FAILURE";
739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case NOTIFICATION:
749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return "NOTIFICATION";
759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	default:
769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return "Unknown?!";
779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic void eap_aka_state(struct eap_aka_data *data, int state)
829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		   eap_aka_state_txt(data->state),
859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		   eap_aka_state_txt(state));
869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->state = state;
879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic int eap_aka_check_identity_reauth(struct eap_sm *sm,
919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					 struct eap_aka_data *data,
929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					 const char *username)
939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	    username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)
969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return 0;
979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->eap_method == EAP_TYPE_AKA &&
989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	    username[0] != EAP_AKA_REAUTH_ID_PREFIX)
999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return 0;
1009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
1029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv,
1039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson						   username);
1049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->reauth == NULL) {
1059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - "
1069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   "request full auth identity");
1079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		/* Remain in IDENTITY state for another round */
1089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return 0;
1099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
1109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication");
1129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	os_strlcpy(data->permanent, data->reauth->permanent,
1139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		   sizeof(data->permanent));
1149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->counter = data->reauth->counter;
1159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
1169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		os_memcpy(data->k_encr, data->reauth->k_encr,
1179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			  EAP_SIM_K_ENCR_LEN);
1189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		os_memcpy(data->k_aut, data->reauth->k_aut,
1199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			  EAP_AKA_PRIME_K_AUT_LEN);
1209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		os_memcpy(data->k_re, data->reauth->k_re,
1219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			  EAP_AKA_PRIME_K_RE_LEN);
1229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	} else {
1239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
1249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
1259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_aka_state(data, REAUTH);
1279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return 1;
1289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
1299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic void eap_aka_check_identity(struct eap_sm *sm,
1329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				   struct eap_aka_data *data)
1339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
1349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	char *username;
1359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	/* Check if we already know the identity from EAP-Response/Identity */
1379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	username = sim_get_username(sm->identity, sm->identity_len);
1399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (username == NULL)
1409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return;
1419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
1439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		os_free(username);
1449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		/*
1459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 * Since re-auth username was recognized, skip AKA/Identity
1469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 * exchange.
1479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 */
1489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return;
1499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
1509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
1529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	     username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
1539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	    (data->eap_method == EAP_TYPE_AKA &&
1549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	     username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
1559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		const char *permanent;
1569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
1579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   username);
1589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		permanent = eap_sim_db_get_permanent(
1599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			sm->eap_sim_db_priv, username);
1609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if (permanent == NULL) {
1619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			os_free(username);
1629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
1639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				   "identity - request permanent identity");
1649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			/* Remain in IDENTITY state for another round */
1659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			return;
1669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
1679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		os_strlcpy(data->permanent, permanent,
1689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   sizeof(data->permanent));
1699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		/*
1709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 * Since pseudonym username was recognized, skip AKA/Identity
1719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 * exchange.
1729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 */
1739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_aka_fullauth(sm, data);
1749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
1759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	os_free(username);
1779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
1789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic void * eap_aka_init(struct eap_sm *sm)
1819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
1829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct eap_aka_data *data;
1839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (sm->eap_sim_db_priv == NULL) {
1859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
1869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return NULL;
1879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
1889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data = os_zalloc(sizeof(*data));
1909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data == NULL)
1919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return NULL;
1929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->eap_method = EAP_TYPE_AKA;
1949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->state = IDENTITY;
1969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->pending_id = -1;
1979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_aka_check_identity(sm, data);
1989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return data;
2009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
2019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#ifdef EAP_SERVER_AKA_PRIME
2049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic void * eap_aka_prime_init(struct eap_sm *sm)
2059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
2069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct eap_aka_data *data;
2079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	/* TODO: make ANID configurable; see 3GPP TS 24.302 */
2089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	char *network_name = "WLAN";
2099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (sm->eap_sim_db_priv == NULL) {
2119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
2129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return NULL;
2139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
2149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data = os_zalloc(sizeof(*data));
2169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data == NULL)
2179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return NULL;
2189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->eap_method = EAP_TYPE_AKA_PRIME;
2209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->network_name = (u8 *) os_strdup(network_name);
2219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->network_name == NULL) {
2229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		os_free(data);
2239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return NULL;
2249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
2259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->network_name_len = os_strlen(network_name);
2279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->state = IDENTITY;
2299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->pending_id = -1;
2309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_aka_check_identity(sm, data);
2319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return data;
2339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
2349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#endif /* EAP_SERVER_AKA_PRIME */
2359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic void eap_aka_reset(struct eap_sm *sm, void *priv)
2389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
2399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct eap_aka_data *data = priv;
2409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	os_free(data->next_pseudonym);
2419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	os_free(data->next_reauth_id);
2429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpabuf_free(data->id_msgs);
2439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	os_free(data->network_name);
2449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	os_free(data);
2459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
2469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic int eap_aka_add_id_msg(struct eap_aka_data *data,
2499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			      const struct wpabuf *msg)
2509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
2519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (msg == NULL)
2529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return -1;
2539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->id_msgs == NULL) {
2559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		data->id_msgs = wpabuf_dup(msg);
2569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return data->id_msgs == NULL ? -1 : 0;
2579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
2589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
2609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return -1;
2619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpabuf_put_buf(data->id_msgs, msg);
2629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return 0;
2649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
2659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic void eap_aka_add_checkcode(struct eap_aka_data *data,
2689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				  struct eap_sim_msg *msg)
2699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
2709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	const u8 *addr;
2719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	size_t len;
2729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 hash[SHA256_MAC_LEN];
2739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
2759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->id_msgs == NULL) {
2779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		/*
2789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 * No EAP-AKA/Identity packets were exchanged - send empty
2799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 * checkcode.
2809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 */
2819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
2829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return;
2839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
2849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
2869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	addr = wpabuf_head(data->id_msgs);
2879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	len = wpabuf_len(data->id_msgs);
2889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
2899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->eap_method == EAP_TYPE_AKA_PRIME)
2909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		sha256_vector(1, &addr, &len, hash);
2919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	else
2929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		sha1_vector(1, &addr, &len, hash);
2939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
2959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			data->eap_method == EAP_TYPE_AKA_PRIME ?
2969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
2979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
2989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic int eap_aka_verify_checkcode(struct eap_aka_data *data,
3019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				    const u8 *checkcode, size_t checkcode_len)
3029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
3039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	const u8 *addr;
3049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	size_t len;
3059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	u8 hash[SHA256_MAC_LEN];
3069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	size_t hash_len;
3079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (checkcode == NULL)
3099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return -1;
3109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->id_msgs == NULL) {
3129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if (checkcode_len != 0) {
3139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
3149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				   "indicates that AKA/Identity messages were "
3159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				   "used, but they were not");
3169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			return -1;
3179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
3189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return 0;
3199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
3209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
3229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
3239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (checkcode_len != hash_len) {
3259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
3269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   "that AKA/Identity message were not used, but they "
3279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   "were");
3289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return -1;
3299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
3309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
3329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	addr = wpabuf_head(data->id_msgs);
3339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	len = wpabuf_len(data->id_msgs);
3349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->eap_method == EAP_TYPE_AKA_PRIME)
3359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		sha256_vector(1, &addr, &len, hash);
3369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	else
3379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		sha1_vector(1, &addr, &len, hash);
3389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (os_memcmp(hash, checkcode, hash_len) != 0) {
3409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
3419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return -1;
3429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
3439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return 0;
3459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
3469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
3499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					      struct eap_aka_data *data, u8 id)
3509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
3519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct eap_sim_msg *msg;
3529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct wpabuf *buf;
3539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
3559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
3569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			       EAP_AKA_SUBTYPE_IDENTITY);
3579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->identity_round++;
3589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->identity_round == 1) {
3599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		/*
3609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
3619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 * ignored and the AKA/Identity is used to request the
3629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 * identity.
3639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		 */
3649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
3659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
3669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	} else if (data->identity_round > 3) {
3679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		/* Cannot use more than three rounds of Identity messages */
3689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_free(msg);
3699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return NULL;
3709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	} else if (sm->identity && sm->identity_len > 0 &&
3719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		   (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
3729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		    sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) {
3739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		/* Reauth id may have expired - try fullauth */
3749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
3759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
3769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	} else {
3779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
3789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
3799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
3809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
3819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (eap_aka_add_id_msg(data, buf) < 0) {
3829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpabuf_free(buf);
3839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return NULL;
3849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
3859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->pending_id = id;
3869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return buf;
3879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
3889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
3919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			      struct eap_sim_msg *msg, u16 counter,
3929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			      const u8 *nonce_s)
3939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
3949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	os_free(data->next_pseudonym);
3959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (nonce_s == NULL) {
3969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		data->next_pseudonym =
3979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			eap_sim_db_get_next_pseudonym(
3989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				sm->eap_sim_db_priv,
3999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				data->eap_method == EAP_TYPE_AKA_PRIME ?
4009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
4019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	} else {
4029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		/* Do not update pseudonym during re-authentication */
4039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		data->next_pseudonym = NULL;
4049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
4059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	os_free(data->next_reauth_id);
4069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
4079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		data->next_reauth_id =
4089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			eap_sim_db_get_next_reauth_id(
4099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				sm->eap_sim_db_priv,
4109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				data->eap_method == EAP_TYPE_AKA_PRIME ?
4119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
4129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	} else {
4139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
4149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   "count exceeded - force full authentication");
4159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		data->next_reauth_id = NULL;
4169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
4179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
4199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	    counter == 0 && nonce_s == NULL)
4209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return 0;
4219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "   AT_IV");
4239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
4249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
4259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (counter > 0) {
4279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
4289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
4299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
4309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (nonce_s) {
4329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
4339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
4349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				EAP_SIM_NONCE_S_LEN);
4359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
4369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->next_pseudonym) {
4389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
4399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   data->next_pseudonym);
4409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
4419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				os_strlen(data->next_pseudonym),
4429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				(u8 *) data->next_pseudonym,
4439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				os_strlen(data->next_pseudonym));
4449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
4459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->next_reauth_id) {
4479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
4489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   data->next_reauth_id);
4499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
4509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				os_strlen(data->next_reauth_id),
4519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				(u8 *) data->next_reauth_id,
4529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				os_strlen(data->next_reauth_id));
4539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
4549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
4569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
4579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   "AT_ENCR_DATA");
4589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return -1;
4599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
4609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return 0;
4629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
4639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
4669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					       struct eap_aka_data *data,
4679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					       u8 id)
4689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
4699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct eap_sim_msg *msg;
4709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
4729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
4739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			       EAP_AKA_SUBTYPE_CHALLENGE);
4749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "   AT_RAND");
4759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
4769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "   AT_AUTN");
4779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
4789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
4799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if (data->kdf) {
4809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			/* Add the selected KDF into the beginning */
4819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			wpa_printf(MSG_DEBUG, "   AT_KDF");
4829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
4839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					NULL, 0);
4849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
4859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   AT_KDF");
4869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
4879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				NULL, 0);
4889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
4899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
4909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				data->network_name_len,
4919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				data->network_name, data->network_name_len);
4929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
4939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
4959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_free(msg);
4969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return NULL;
4979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
4989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_aka_add_checkcode(data, msg);
5009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (sm->eap_sim_aka_result_ind) {
5029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
5039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
5049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
5059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#ifdef EAP_SERVER_AKA_PRIME
5079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->eap_method == EAP_TYPE_AKA) {
5089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		u16 flags = 0;
5099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		int i;
5109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		int aka_prime_preferred = 0;
5119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		i = 0;
5139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		while (sm->user && i < EAP_MAX_METHODS &&
5149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		       (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
5159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			sm->user->methods[i].method != EAP_TYPE_NONE)) {
5169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
5179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				if (sm->user->methods[i].method ==
5189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				    EAP_TYPE_AKA)
5199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					break;
5209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				if (sm->user->methods[i].method ==
5219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				    EAP_TYPE_AKA_PRIME) {
5229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					aka_prime_preferred = 1;
5239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					break;
5249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				}
5259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			}
5269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			i++;
5279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
5289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if (aka_prime_preferred)
5309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			flags |= EAP_AKA_BIDDING_FLAG_D;
5319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
5329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
5339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#endif /* EAP_SERVER_AKA_PRIME */
5349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "   AT_MAC");
5369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
5379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
5389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
5399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
5429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					    struct eap_aka_data *data, u8 id)
5439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
5449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct eap_sim_msg *msg;
5459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
5479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
5499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return NULL;
5509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
5519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			data->nonce_s, EAP_SIM_NONCE_S_LEN);
5529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
5549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
5559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson						 sm->identity,
5569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson						 sm->identity_len,
5579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson						 data->nonce_s,
5589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson						 data->msk, data->emsk);
5599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	} else {
5609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
5619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				    data->msk, data->emsk);
5629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_derive_keys_reauth(data->counter, sm->identity,
5639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					   sm->identity_len, data->nonce_s,
5649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					   data->mk, data->msk, data->emsk);
5659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
5669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
5689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
5699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
5719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_free(msg);
5729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return NULL;
5739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
5749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_aka_add_checkcode(data, msg);
5769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (sm->eap_sim_aka_result_ind) {
5789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
5799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
5809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
5819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "   AT_MAC");
5839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
5849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
5859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
5869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
5899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson						  struct eap_aka_data *data,
5909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson						  u8 id)
5919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
5929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct eap_sim_msg *msg;
5939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
5959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
5969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			       EAP_AKA_SUBTYPE_NOTIFICATION);
5979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
5989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
5999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			NULL, 0);
6009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (data->use_result_ind) {
6019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if (data->reauth) {
6029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			wpa_printf(MSG_DEBUG, "   AT_IV");
6039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
6049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
6059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson						   EAP_SIM_AT_ENCR_DATA);
6069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
6079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				   data->counter);
6089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
6099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					NULL, 0);
6109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
6129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson						     EAP_SIM_AT_PADDING)) {
6139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
6149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					   "encrypt AT_ENCR_DATA");
6159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				eap_sim_msg_free(msg);
6169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				return NULL;
6179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			}
6189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
6199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "   AT_MAC");
6219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
6229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
6239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
6249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
6259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
6289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
6299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct eap_aka_data *data = priv;
6309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	data->auts_reported = 0;
6329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	switch (data->state) {
6339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case IDENTITY:
6349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return eap_aka_build_identity(sm, data, id);
6359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case CHALLENGE:
6369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return eap_aka_build_challenge(sm, data, id);
6379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case REAUTH:
6389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return eap_aka_build_reauth(sm, data, id);
6399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case NOTIFICATION:
6409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return eap_aka_build_notification(sm, data, id);
6419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	default:
6429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
6439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   "buildReq", data->state);
6449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		break;
6459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
6469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return NULL;
6479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
6489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic Boolean eap_aka_check(struct eap_sm *sm, void *priv,
6519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			     struct wpabuf *respData)
6529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
6539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	struct eap_aka_data *data = priv;
6549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	const u8 *pos;
6559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	size_t len;
6569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
6589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			       &len);
6599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (pos == NULL || len < 3) {
6609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
6619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return TRUE;
6629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
6639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return FALSE;
6659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
6669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
6699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
6709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
6719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	    subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
6729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return FALSE;
6739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	switch (data->state) {
6759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case IDENTITY:
6769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
6779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
6789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				   "subtype %d", subtype);
6799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			return TRUE;
6809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
6819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		break;
6829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case CHALLENGE:
6839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
6849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		    subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
6859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
6869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				   "subtype %d", subtype);
6879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			return TRUE;
6889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
6899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		break;
6909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case REAUTH:
6919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
6929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
6939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				   "subtype %d", subtype);
6949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			return TRUE;
6959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
6969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		break;
6979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	case NOTIFICATION:
6989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
6999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
7009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				   "subtype %d", subtype);
7019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			return TRUE;
7029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
7039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		break;
7049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	default:
7059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
7069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   "processing a response", data->state);
7079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return TRUE;
7089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
7099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return FALSE;
7119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
7129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstatic void eap_aka_determine_identity(struct eap_sm *sm,
7159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				       struct eap_aka_data *data)
7169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
7179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	char *username;
7189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
7209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			  sm->identity, sm->identity_len);
7219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	username = sim_get_username(sm->identity, sm->identity_len);
7239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (username == NULL) {
7249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
7259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		eap_aka_state(data, NOTIFICATION);
7269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return;
7279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
7289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
7309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		os_free(username);
7319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return;
7329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
7339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
7359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	     username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
7369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	    (data->eap_method == EAP_TYPE_AKA &&
7379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	     username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
7389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		const char *permanent;
7399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
7409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			   username);
7419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		permanent = eap_sim_db_get_permanent(
7429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			sm->eap_sim_db_priv, username);
7439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		os_free(username);
7449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if (permanent == NULL) {
7459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
7469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				   "identity - request permanent identity");
7479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			/* Remain in IDENTITY state for another round */
7489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			return;
7499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
750		os_strlcpy(data->permanent, permanent,
751			   sizeof(data->permanent));
752	} else if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
753		    username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) ||
754		   (data->eap_method == EAP_TYPE_AKA &&
755		    username[0] == EAP_AKA_PERMANENT_PREFIX)) {
756		wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'",
757			   username);
758		os_strlcpy(data->permanent, username, sizeof(data->permanent));
759		os_free(username);
760	} else {
761		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'",
762			   username);
763		os_free(username);
764		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
765		eap_aka_state(data, NOTIFICATION);
766		return;
767	}
768
769	eap_aka_fullauth(sm, data);
770}
771
772
773static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data)
774{
775	size_t identity_len;
776	int res;
777
778	res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
779				      data->rand, data->autn, data->ik,
780				      data->ck, data->res, &data->res_len, sm);
781	if (res == EAP_SIM_DB_PENDING) {
782		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
783			   "not yet available - pending request");
784		sm->method_pending = METHOD_PENDING_WAIT;
785		return;
786	}
787
788#ifdef EAP_SERVER_AKA_PRIME
789	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
790		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
791		 * needed 6-octet SQN ^AK for CK',IK' derivation */
792		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
793						 data->autn,
794						 data->network_name,
795						 data->network_name_len);
796	}
797#endif /* EAP_SERVER_AKA_PRIME */
798
799	data->reauth = NULL;
800	data->counter = 0; /* reset re-auth counter since this is full auth */
801
802	if (res != 0) {
803		wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
804			   "authentication data for the peer");
805		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
806		eap_aka_state(data, NOTIFICATION);
807		return;
808	}
809	if (sm->method_pending == METHOD_PENDING_WAIT) {
810		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
811			   "available - abort pending wait");
812		sm->method_pending = METHOD_PENDING_NONE;
813	}
814
815	identity_len = sm->identity_len;
816	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
817		wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
818			   "character from identity");
819		identity_len--;
820	}
821	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
822			  sm->identity, identity_len);
823
824	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
825		eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik,
826					  data->ck, data->k_encr, data->k_aut,
827					  data->k_re, data->msk, data->emsk);
828	} else {
829		eap_aka_derive_mk(sm->identity, identity_len, data->ik,
830				  data->ck, data->mk);
831		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
832				    data->msk, data->emsk);
833	}
834
835	eap_aka_state(data, CHALLENGE);
836}
837
838
839static void eap_aka_process_identity(struct eap_sm *sm,
840				     struct eap_aka_data *data,
841				     struct wpabuf *respData,
842				     struct eap_sim_attrs *attr)
843{
844	u8 *new_identity;
845
846	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
847
848	if (attr->mac || attr->iv || attr->encr_data) {
849		wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
850			   "received in EAP-Response/AKA-Identity");
851		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
852		eap_aka_state(data, NOTIFICATION);
853		return;
854	}
855
856	/*
857	 * We always request identity with AKA/Identity, so the peer is
858	 * required to have replied with one.
859	 */
860	if (!attr->identity || attr->identity_len == 0) {
861		wpa_printf(MSG_DEBUG, "EAP-AKA: Peer did not provide any "
862			   "identity");
863		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
864		eap_aka_state(data, NOTIFICATION);
865		return;
866	}
867
868	new_identity = os_malloc(attr->identity_len);
869	if (new_identity == NULL) {
870		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
871		eap_aka_state(data, NOTIFICATION);
872		return;
873	}
874	os_free(sm->identity);
875	sm->identity = new_identity;
876	os_memcpy(sm->identity, attr->identity, attr->identity_len);
877	sm->identity_len = attr->identity_len;
878
879	eap_aka_determine_identity(sm, data);
880	if (eap_get_id(respData) == data->pending_id) {
881		data->pending_id = -1;
882		eap_aka_add_id_msg(data, respData);
883	}
884}
885
886
887static int eap_aka_verify_mac(struct eap_aka_data *data,
888			      const struct wpabuf *req,
889			      const u8 *mac, const u8 *extra,
890			      size_t extra_len)
891{
892	if (data->eap_method == EAP_TYPE_AKA_PRIME)
893		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
894						 extra_len);
895	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
896}
897
898
899static void eap_aka_process_challenge(struct eap_sm *sm,
900				      struct eap_aka_data *data,
901				      struct wpabuf *respData,
902				      struct eap_sim_attrs *attr)
903{
904	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
905
906#ifdef EAP_SERVER_AKA_PRIME
907#if 0
908	/* KDF negotiation; to be enabled only after more than one KDF is
909	 * supported */
910	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
911	    attr->kdf_count == 1 && attr->mac == NULL) {
912		if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
913			wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
914				   "unknown KDF");
915			data->notification =
916				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
917			eap_aka_state(data, NOTIFICATION);
918			return;
919		}
920
921		data->kdf = attr->kdf[0];
922
923		/* Allow negotiation to continue with the selected KDF by
924		 * sending another Challenge message */
925		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
926		return;
927	}
928#endif
929#endif /* EAP_SERVER_AKA_PRIME */
930
931	if (attr->checkcode &&
932	    eap_aka_verify_checkcode(data, attr->checkcode,
933				     attr->checkcode_len)) {
934		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
935			   "message");
936		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
937		eap_aka_state(data, NOTIFICATION);
938		return;
939	}
940	if (attr->mac == NULL ||
941	    eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
942		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
943			   "did not include valid AT_MAC");
944		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
945		eap_aka_state(data, NOTIFICATION);
946		return;
947	}
948
949	/*
950	 * AT_RES is padded, so verify that there is enough room for RES and
951	 * that the RES length in bits matches with the expected RES.
952	 */
953	if (attr->res == NULL || attr->res_len < data->res_len ||
954	    attr->res_len_bits != data->res_len * 8 ||
955	    os_memcmp(attr->res, data->res, data->res_len) != 0) {
956		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
957			   "include valid AT_RES (attr len=%lu, res len=%lu "
958			   "bits, expected %lu bits)",
959			   (unsigned long) attr->res_len,
960			   (unsigned long) attr->res_len_bits,
961			   (unsigned long) data->res_len * 8);
962		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
963		eap_aka_state(data, NOTIFICATION);
964		return;
965	}
966
967	wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
968		   "correct AT_MAC");
969	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
970		data->use_result_ind = 1;
971		data->notification = EAP_SIM_SUCCESS;
972		eap_aka_state(data, NOTIFICATION);
973	} else
974		eap_aka_state(data, SUCCESS);
975
976	if (data->next_pseudonym) {
977		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
978					 data->next_pseudonym);
979		data->next_pseudonym = NULL;
980	}
981	if (data->next_reauth_id) {
982		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
983#ifdef EAP_SERVER_AKA_PRIME
984			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
985						    data->permanent,
986						    data->next_reauth_id,
987						    data->counter + 1,
988						    data->k_encr, data->k_aut,
989						    data->k_re);
990#endif /* EAP_SERVER_AKA_PRIME */
991		} else {
992			eap_sim_db_add_reauth(sm->eap_sim_db_priv,
993					      data->permanent,
994					      data->next_reauth_id,
995					      data->counter + 1,
996					      data->mk);
997		}
998		data->next_reauth_id = NULL;
999	}
1000}
1001
1002
1003static void eap_aka_process_sync_failure(struct eap_sm *sm,
1004					 struct eap_aka_data *data,
1005					 struct wpabuf *respData,
1006					 struct eap_sim_attrs *attr)
1007{
1008	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
1009
1010	if (attr->auts == NULL) {
1011		wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
1012			   "message did not include valid AT_AUTS");
1013		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1014		eap_aka_state(data, NOTIFICATION);
1015		return;
1016	}
1017
1018	/* Avoid re-reporting AUTS when processing pending EAP packet by
1019	 * maintaining a local flag stating whether this AUTS has already been
1020	 * reported. */
1021	if (!data->auts_reported &&
1022	    eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent,
1023				     attr->auts, data->rand)) {
1024		wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
1025		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1026		eap_aka_state(data, NOTIFICATION);
1027		return;
1028	}
1029	data->auts_reported = 1;
1030
1031	/* Remain in CHALLENGE state to re-try after resynchronization */
1032}
1033
1034
1035static void eap_aka_process_reauth(struct eap_sm *sm,
1036				   struct eap_aka_data *data,
1037				   struct wpabuf *respData,
1038				   struct eap_sim_attrs *attr)
1039{
1040	struct eap_sim_attrs eattr;
1041	u8 *decrypted = NULL;
1042
1043	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
1044
1045	if (attr->mac == NULL ||
1046	    eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
1047			       EAP_SIM_NONCE_S_LEN)) {
1048		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
1049			   "did not include valid AT_MAC");
1050		goto fail;
1051	}
1052
1053	if (attr->encr_data == NULL || attr->iv == NULL) {
1054		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
1055			   "message did not include encrypted data");
1056		goto fail;
1057	}
1058
1059	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
1060				       attr->encr_data_len, attr->iv, &eattr,
1061				       0);
1062	if (decrypted == NULL) {
1063		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
1064			   "data from reauthentication message");
1065		goto fail;
1066	}
1067
1068	if (eattr.counter != data->counter) {
1069		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
1070			   "used incorrect counter %u, expected %u",
1071			   eattr.counter, data->counter);
1072		goto fail;
1073	}
1074	os_free(decrypted);
1075	decrypted = NULL;
1076
1077	wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
1078		   "the correct AT_MAC");
1079
1080	if (eattr.counter_too_small) {
1081		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
1082			   "included AT_COUNTER_TOO_SMALL - starting full "
1083			   "authentication");
1084		eap_aka_fullauth(sm, data);
1085		return;
1086	}
1087
1088	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
1089		data->use_result_ind = 1;
1090		data->notification = EAP_SIM_SUCCESS;
1091		eap_aka_state(data, NOTIFICATION);
1092	} else
1093		eap_aka_state(data, SUCCESS);
1094
1095	if (data->next_reauth_id) {
1096		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
1097#ifdef EAP_SERVER_AKA_PRIME
1098			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
1099						    data->permanent,
1100						    data->next_reauth_id,
1101						    data->counter + 1,
1102						    data->k_encr, data->k_aut,
1103						    data->k_re);
1104#endif /* EAP_SERVER_AKA_PRIME */
1105		} else {
1106			eap_sim_db_add_reauth(sm->eap_sim_db_priv,
1107					      data->permanent,
1108					      data->next_reauth_id,
1109					      data->counter + 1,
1110					      data->mk);
1111		}
1112		data->next_reauth_id = NULL;
1113	} else {
1114		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
1115		data->reauth = NULL;
1116	}
1117
1118	return;
1119
1120fail:
1121	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1122	eap_aka_state(data, NOTIFICATION);
1123	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
1124	data->reauth = NULL;
1125	os_free(decrypted);
1126}
1127
1128
1129static void eap_aka_process_client_error(struct eap_sm *sm,
1130					 struct eap_aka_data *data,
1131					 struct wpabuf *respData,
1132					 struct eap_sim_attrs *attr)
1133{
1134	wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
1135		   attr->client_error_code);
1136	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
1137		eap_aka_state(data, SUCCESS);
1138	else
1139		eap_aka_state(data, FAILURE);
1140}
1141
1142
1143static void eap_aka_process_authentication_reject(
1144	struct eap_sm *sm, struct eap_aka_data *data,
1145	struct wpabuf *respData, struct eap_sim_attrs *attr)
1146{
1147	wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
1148	eap_aka_state(data, FAILURE);
1149}
1150
1151
1152static void eap_aka_process_notification(struct eap_sm *sm,
1153					 struct eap_aka_data *data,
1154					 struct wpabuf *respData,
1155					 struct eap_sim_attrs *attr)
1156{
1157	wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
1158	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
1159		eap_aka_state(data, SUCCESS);
1160	else
1161		eap_aka_state(data, FAILURE);
1162}
1163
1164
1165static void eap_aka_process(struct eap_sm *sm, void *priv,
1166			    struct wpabuf *respData)
1167{
1168	struct eap_aka_data *data = priv;
1169	const u8 *pos, *end;
1170	u8 subtype;
1171	size_t len;
1172	struct eap_sim_attrs attr;
1173
1174	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
1175			       &len);
1176	if (pos == NULL || len < 3)
1177		return;
1178
1179	end = pos + len;
1180	subtype = *pos;
1181	pos += 3;
1182
1183	if (eap_aka_subtype_ok(data, subtype)) {
1184		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
1185			   "EAP-AKA Subtype in EAP Response");
1186		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1187		eap_aka_state(data, NOTIFICATION);
1188		return;
1189	}
1190
1191	if (eap_sim_parse_attr(pos, end, &attr,
1192			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
1193			       0)) {
1194		wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
1195		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1196		eap_aka_state(data, NOTIFICATION);
1197		return;
1198	}
1199
1200	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
1201		eap_aka_process_client_error(sm, data, respData, &attr);
1202		return;
1203	}
1204
1205	if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
1206		eap_aka_process_authentication_reject(sm, data, respData,
1207						      &attr);
1208		return;
1209	}
1210
1211	switch (data->state) {
1212	case IDENTITY:
1213		eap_aka_process_identity(sm, data, respData, &attr);
1214		break;
1215	case CHALLENGE:
1216		if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
1217			eap_aka_process_sync_failure(sm, data, respData,
1218						     &attr);
1219		} else {
1220			eap_aka_process_challenge(sm, data, respData, &attr);
1221		}
1222		break;
1223	case REAUTH:
1224		eap_aka_process_reauth(sm, data, respData, &attr);
1225		break;
1226	case NOTIFICATION:
1227		eap_aka_process_notification(sm, data, respData, &attr);
1228		break;
1229	default:
1230		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
1231			   "process", data->state);
1232		break;
1233	}
1234}
1235
1236
1237static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
1238{
1239	struct eap_aka_data *data = priv;
1240	return data->state == SUCCESS || data->state == FAILURE;
1241}
1242
1243
1244static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
1245{
1246	struct eap_aka_data *data = priv;
1247	u8 *key;
1248
1249	if (data->state != SUCCESS)
1250		return NULL;
1251
1252	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
1253	if (key == NULL)
1254		return NULL;
1255	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
1256	*len = EAP_SIM_KEYING_DATA_LEN;
1257	return key;
1258}
1259
1260
1261static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1262{
1263	struct eap_aka_data *data = priv;
1264	u8 *key;
1265
1266	if (data->state != SUCCESS)
1267		return NULL;
1268
1269	key = os_malloc(EAP_EMSK_LEN);
1270	if (key == NULL)
1271		return NULL;
1272	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
1273	*len = EAP_EMSK_LEN;
1274	return key;
1275}
1276
1277
1278static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
1279{
1280	struct eap_aka_data *data = priv;
1281	return data->state == SUCCESS;
1282}
1283
1284
1285int eap_server_aka_register(void)
1286{
1287	struct eap_method *eap;
1288	int ret;
1289
1290	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1291				      EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
1292	if (eap == NULL)
1293		return -1;
1294
1295	eap->init = eap_aka_init;
1296	eap->reset = eap_aka_reset;
1297	eap->buildReq = eap_aka_buildReq;
1298	eap->check = eap_aka_check;
1299	eap->process = eap_aka_process;
1300	eap->isDone = eap_aka_isDone;
1301	eap->getKey = eap_aka_getKey;
1302	eap->isSuccess = eap_aka_isSuccess;
1303	eap->get_emsk = eap_aka_get_emsk;
1304
1305	ret = eap_server_method_register(eap);
1306	if (ret)
1307		eap_server_method_free(eap);
1308	return ret;
1309}
1310
1311
1312#ifdef EAP_SERVER_AKA_PRIME
1313int eap_server_aka_prime_register(void)
1314{
1315	struct eap_method *eap;
1316	int ret;
1317
1318	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1319				      EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
1320				      "AKA'");
1321	if (eap == NULL)
1322		return -1;
1323
1324	eap->init = eap_aka_prime_init;
1325	eap->reset = eap_aka_reset;
1326	eap->buildReq = eap_aka_buildReq;
1327	eap->check = eap_aka_check;
1328	eap->process = eap_aka_process;
1329	eap->isDone = eap_aka_isDone;
1330	eap->getKey = eap_aka_getKey;
1331	eap->isSuccess = eap_aka_isSuccess;
1332	eap->get_emsk = eap_aka_get_emsk;
1333
1334	ret = eap_server_method_register(eap);
1335	if (ret)
1336		eap_server_method_free(eap);
1337
1338	return ret;
1339}
1340#endif /* EAP_SERVER_AKA_PRIME */
1341