1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/*
2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify
6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as
7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation.
8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license.
11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details.
13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h"
16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h"
18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eap_peer/eap_i.h"
19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "pcsc_funcs.h"
20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eap_common/eap_sim_common.h"
21b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/sha1.h"
22b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/sha256.h"
23b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/crypto.h"
24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eap_peer/eap_config.h"
25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_USIM_SIMULATOR
26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "hlr_auc_gw/milenage.h"
27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_USIM_SIMULATOR */
28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct eap_aka_data {
31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 ik[EAP_AKA_IK_LEN], ck[EAP_AKA_CK_LEN], res[EAP_AKA_RES_MAX_LEN];
32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t res_len;
33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 mk[EAP_SIM_MK_LEN];
35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 k_encr[EAP_SIM_K_ENCR_LEN];
37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 msk[EAP_SIM_KEYING_DATA_LEN];
39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 emsk[EAP_EMSK_LEN];
40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN];
41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 auts[EAP_AKA_AUTS_LEN];
42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int num_id_req, num_notification;
44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *pseudonym;
45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t pseudonym_len;
46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *reauth_id;
47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t reauth_id_len;
48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int reauth;
49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	unsigned int counter, counter_too_small;
50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *last_eap_identity;
51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t last_eap_identity_len;
52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	enum {
53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} state;
55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *id_msgs;
57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int prev_id;
58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int result_ind, use_result_ind;
59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 eap_method;
60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *network_name;
61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t network_name_len;
62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u16 kdf;
63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int kdf_negotiation;
64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifndef CONFIG_NO_STDOUT_DEBUG
68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic const char * eap_aka_state_txt(int state)
69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (state) {
71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case CONTINUE:
72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return "CONTINUE";
73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case RESULT_SUCCESS:
74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return "RESULT_SUCCESS";
75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case RESULT_FAILURE:
76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return "RESULT_FAILURE";
77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case SUCCESS:
78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return "SUCCESS";
79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case FAILURE:
80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return "FAILURE";
81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	default:
82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return "?";
83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_NO_STDOUT_DEBUG */
86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_aka_state(struct eap_aka_data *data, int state)
89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   eap_aka_state_txt(data->state),
92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   eap_aka_state_txt(state));
93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->state = state;
94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void * eap_aka_init(struct eap_sm *sm)
98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data;
100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const char *phase1 = eap_get_config_phase1(sm);
101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data = os_zalloc(sizeof(*data));
103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data == NULL)
104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->eap_method = EAP_TYPE_AKA;
107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_aka_state(data, CONTINUE);
109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->prev_id = -1;
110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data;
114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef EAP_AKA_PRIME
118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void * eap_aka_prime_init(struct eap_sm *sm)
119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data = eap_aka_init(sm);
121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data == NULL)
122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->eap_method = EAP_TYPE_AKA_PRIME;
124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data;
125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* EAP_AKA_PRIME */
127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_aka_deinit(struct eap_sm *sm, void *priv)
130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data = priv;
132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data) {
133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data->pseudonym);
134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data->reauth_id);
135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data->last_eap_identity);
136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(data->id_msgs);
137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data->network_name);
138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data);
139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_peer_config *conf;
146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-AKA: UMTS authentication algorithm");
148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	conf = eap_get_config(sm);
150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (conf == NULL)
151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (conf->pcsc) {
153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return scard_umts_auth(sm->scard_ctx, data->rand,
154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       data->autn, data->res, &data->res_len,
155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       data->ik, data->ck, data->auts);
156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_USIM_SIMULATOR
159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (conf->password) {
160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		u8 opc[16], k[16], sqn[6];
161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		const char *pos;
162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-AKA: Use internal Milenage "
163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "implementation for UMTS authentication");
164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (conf->password_len < 78) {
165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-AKA: invalid Milenage "
166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "password");
167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos = (const char *) conf->password;
170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (hexstr2bin(pos, k, 16))
171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += 32;
173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (*pos != ':')
174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos++;
176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (hexstr2bin(pos, opc, 16))
178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += 32;
180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (*pos != ':')
181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos++;
183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (hexstr2bin(pos, sqn, 6))
185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return milenage_check(opc, k, sqn, data->rand, data->autn,
188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				      data->ik, data->ck,
189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				      data->res, &data->res_len, data->auts);
190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_USIM_SIMULATOR */
192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_USIM_HARDCODED
194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-AKA: Use hardcoded Kc and SRES values for "
195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "testing");
196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* These hardcoded Kc and SRES values are used for testing.
198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * Could consider making them configurable. */
199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(data->res, '2', EAP_AKA_RES_MAX_LEN);
200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->res_len = EAP_AKA_RES_MAX_LEN;
201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(data->ik, '3', EAP_AKA_IK_LEN);
202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(data->ck, '4', EAP_AKA_CK_LEN);
203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	{
204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		u8 autn[EAP_AKA_AUTN_LEN];
205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memset(autn, '1', EAP_AKA_AUTN_LEN);
206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "with expected value");
209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#if 0
213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	{
214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		static int test_resync = 1;
215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (test_resync) {
216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			/* Test Resynchronization */
217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			test_resync = 0;
218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -2;
219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif
222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* CONFIG_USIM_HARDCODED */
225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-AKA: No UMTS authentication algorith "
227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "enabled");
228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return -1;
229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_USIM_HARDCODED */
231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define CLEAR_PSEUDONYM	0x01
235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define CLEAR_REAUTH_ID	0x02
236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define CLEAR_EAP_ID	0x04
237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_aka_clear_identities(struct eap_aka_data *data, int id)
239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s",
241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   id & CLEAR_PSEUDONYM ? " pseudonym" : "",
242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   id & CLEAR_REAUTH_ID ? " reauth_id" : "",
243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   id & CLEAR_EAP_ID ? " eap_id" : "");
244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (id & CLEAR_PSEUDONYM) {
245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data->pseudonym);
246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->pseudonym = NULL;
247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->pseudonym_len = 0;
248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (id & CLEAR_REAUTH_ID) {
250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data->reauth_id);
251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->reauth_id = NULL;
252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->reauth_id_len = 0;
253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (id & CLEAR_EAP_ID) {
255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data->last_eap_identity);
256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->last_eap_identity = NULL;
257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->last_eap_identity_len = 0;
258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int eap_aka_learn_ids(struct eap_aka_data *data,
263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     struct eap_sim_attrs *attr)
264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (attr->next_pseudonym) {
266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data->pseudonym);
267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->pseudonym = os_malloc(attr->next_pseudonym_len);
268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->pseudonym == NULL) {
269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "next pseudonym");
271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data->pseudonym, attr->next_pseudonym,
274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  attr->next_pseudonym_len);
275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->pseudonym_len = attr->next_pseudonym_len;
276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG,
277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  data->pseudonym,
279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  data->pseudonym_len);
280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (attr->next_reauth_id) {
283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data->reauth_id);
284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->reauth_id = os_malloc(attr->next_reauth_id_len);
285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->reauth_id == NULL) {
286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "next reauth_id");
288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data->reauth_id, attr->next_reauth_id,
291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  attr->next_reauth_id_len);
292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->reauth_id_len = attr->next_reauth_id_len;
293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG,
294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  data->reauth_id,
296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  data->reauth_id_len);
297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int eap_aka_add_id_msg(struct eap_aka_data *data,
304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      const struct wpabuf *msg)
305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (msg == NULL)
307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->id_msgs == NULL) {
310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->id_msgs = wpabuf_dup(msg);
311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return data->id_msgs == NULL ? -1 : 0;
312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_buf(data->id_msgs, msg);
317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_aka_add_checkcode(struct eap_aka_data *data,
323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  struct eap_sim_msg *msg)
324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *addr;
326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len;
327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 hash[SHA256_MAC_LEN];
328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->id_msgs == NULL) {
332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/*
333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * No EAP-AKA/Identity packets were exchanged - send empty
334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * checkcode.
335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 */
336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return;
338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr = wpabuf_head(data->id_msgs);
342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len = wpabuf_len(data->id_msgs);
343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef EAP_AKA_PRIME
345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->eap_method == EAP_TYPE_AKA_PRIME)
346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sha256_vector(1, &addr, &len, hash);
347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	else
348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* EAP_AKA_PRIME */
349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sha1_vector(1, &addr, &len, hash);
350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->eap_method == EAP_TYPE_AKA_PRIME ?
353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int eap_aka_verify_checkcode(struct eap_aka_data *data,
358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    const u8 *checkcode, size_t checkcode_len)
359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *addr;
361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len;
362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 hash[SHA256_MAC_LEN];
363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t hash_len;
364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (checkcode == NULL)
366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->id_msgs == NULL) {
369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (checkcode_len != 0) {
370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "indicates that AKA/Identity messages were "
372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "used, but they were not");
373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return 0;
376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (checkcode_len != hash_len) {
382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "indicates that AKA/Identity message were not "
384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "used, but they were");
385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr = wpabuf_head(data->id_msgs);
390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len = wpabuf_len(data->id_msgs);
391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef EAP_AKA_PRIME
392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->eap_method == EAP_TYPE_AKA_PRIME)
393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sha256_vector(1, &addr, &len, hash);
394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	else
395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* EAP_AKA_PRIME */
396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sha1_vector(1, &addr, &len, hash);
397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (os_memcmp(hash, checkcode, hash_len) != 0) {
399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    int err)
409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_msg *msg;
411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_aka_state(data, FAILURE);
413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_id_req = 0;
414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_notification = 0;
415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       EAP_AKA_SUBTYPE_CLIENT_ERROR);
418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_sim_msg_finish(msg, NULL, NULL, 0);
420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data,
424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						     u8 id)
425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_msg *msg;
427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_aka_state(data, FAILURE);
429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_id_req = 0;
430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_notification = 0;
431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject "
433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "(id=%d)", id);
434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_sim_msg_finish(msg, NULL, NULL, 0);
437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_synchronization_failure(
441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data, u8 id)
442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_msg *msg;
444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_id_req = 0;
446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_notification = 0;
447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure "
449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "(id=%d)", id);
450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "   AT_AUTS");
453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     EAP_AKA_AUTS_LEN);
455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_sim_msg_finish(msg, NULL, NULL, 0);
456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 struct eap_aka_data *data,
461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 u8 id,
462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 enum eap_sim_id_req id_req)
463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *identity = NULL;
465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t identity_len = 0;
466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_msg *msg;
467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->reauth = 0;
469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (id_req == ANY_ID && data->reauth_id) {
470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		identity = data->reauth_id;
471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		identity_len = data->reauth_id_len;
472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->reauth = 1;
473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   data->pseudonym) {
475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		identity = data->pseudonym;
476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		identity_len = data->pseudonym_len;
477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_clear_identities(data, CLEAR_REAUTH_ID);
478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (id_req != NO_ID_REQ) {
479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		identity = eap_get_config_identity(sm, &identity_len);
480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (identity) {
481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			eap_aka_clear_identities(data, CLEAR_PSEUDONYM |
482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 CLEAR_REAUTH_ID);
483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (id_req != NO_ID_REQ)
486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_clear_identities(data, CLEAR_EAP_ID);
487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       EAP_AKA_SUBTYPE_IDENTITY);
491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (identity) {
493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  identity, identity_len);
495526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				identity, identity_len);
497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_sim_msg_finish(msg, NULL, NULL, 0);
500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data,
504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						  u8 id)
505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_msg *msg;
507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)", id);
509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       EAP_AKA_SUBTYPE_CHALLENGE);
511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "   AT_RES");
512526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len * 8,
513526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->res, data->res_len);
514526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_aka_add_checkcode(data, msg);
515526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->use_result_ind) {
516526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
517526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
518526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
519526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "   AT_MAC");
520526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
521526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_sim_msg_finish(msg, data->k_aut, (u8 *) "", 0);
522526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
523526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
524526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
525526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data,
526526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					       u8 id, int counter_too_small,
527526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					       const u8 *nonce_s)
528526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
529526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_msg *msg;
530526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	unsigned int counter;
531526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
532526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)",
533526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   id);
534526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
535526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
536526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "   AT_IV");
537526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
538526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
539526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
540526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (counter_too_small) {
541526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
542526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
543526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		counter = data->counter_too_small;
544526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else
545526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		counter = data->counter;
546526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
547526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
548526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
549526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
550526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
551526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
552526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "AT_ENCR_DATA");
553526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sim_msg_free(msg);
554526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
555526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
556526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_aka_add_checkcode(data, msg);
557526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->use_result_ind) {
558526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
559526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
560526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
561526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "   AT_MAC");
562526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
563526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
564526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  EAP_SIM_NONCE_S_LEN);
565526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
566526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
567526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
568526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data,
569526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						     u8 id, u16 notification)
570526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
571526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_msg *msg;
572526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
573526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
574526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)", id);
575526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
576526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       EAP_AKA_SUBTYPE_NOTIFICATION);
577526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (k_aut && data->reauth) {
578526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "   AT_IV");
579526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
580526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
581526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   EAP_SIM_AT_ENCR_DATA);
582526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
583526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
584526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				NULL, 0);
585526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (eap_sim_msg_add_encr_end(msg, data->k_encr,
586526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					     EAP_SIM_AT_PADDING)) {
587526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
588526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "AT_ENCR_DATA");
589526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			eap_sim_msg_free(msg);
590526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return NULL;
591526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
592526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
593526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (k_aut) {
594526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "   AT_MAC");
595526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
596526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
597526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
598526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
599526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
600526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
601526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_process_identity(struct eap_sm *sm,
602526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						struct eap_aka_data *data,
603526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						u8 id,
604526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						const struct wpabuf *reqData,
605526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						struct eap_sim_attrs *attr)
606526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
607526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int id_error;
608526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *buf;
609526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
610526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Identity");
611526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
612526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	id_error = 0;
613526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (attr->id_req) {
614526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case NO_ID_REQ:
615526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
616526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case ANY_ID:
617526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->num_id_req > 0)
618526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			id_error++;
619526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->num_id_req++;
620526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
621526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case FULLAUTH_ID:
622526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->num_id_req > 1)
623526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			id_error++;
624526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->num_id_req++;
625526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
626526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case PERMANENT_ID:
627526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->num_id_req > 2)
628526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			id_error++;
629526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->num_id_req++;
630526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
631526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
632526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (id_error) {
633526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests "
634526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "used within one authentication");
635526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
636526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
637526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
638526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
639526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf = eap_aka_response_identity(sm, data, id, attr->id_req);
640526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
641526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->prev_id != id) {
642526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_add_id_msg(data, reqData);
643526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_add_id_msg(data, buf);
644526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->prev_id = id;
645526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
646526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
647526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return buf;
648526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
649526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
650526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
651526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int eap_aka_verify_mac(struct eap_aka_data *data,
652526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      const struct wpabuf *req,
653526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      const u8 *mac, const u8 *extra,
654526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      size_t extra_len)
655526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
656526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->eap_method == EAP_TYPE_AKA_PRIME)
657526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
658526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 extra_len);
659526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
660526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
661526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
662526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
663526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef EAP_AKA_PRIME
664526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data,
665526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						u8 id, u16 kdf)
666526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
667526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_msg *msg;
668526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
669526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->kdf_negotiation = 1;
670526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->kdf = kdf;
671526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF "
672526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "select)", id);
673526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
674526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       EAP_AKA_SUBTYPE_CHALLENGE);
675526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "   AT_KDF");
676526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0);
677526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_sim_msg_finish(msg, NULL, NULL, 0);
678526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
679526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
680526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
681526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data,
682526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					     u8 id, struct eap_sim_attrs *attr)
683526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
684526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t i;
685526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
686526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	for (i = 0; i < attr->kdf_count; i++) {
687526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (attr->kdf[i] == EAP_AKA_PRIME_KDF)
688526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return eap_aka_prime_kdf_select(data, id,
689526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt							EAP_AKA_PRIME_KDF);
690526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
691526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
692526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* No matching KDF found - fail authentication as if AUTN had been
693526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * incorrect */
694526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_aka_authentication_reject(data, id);
695526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
696526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
697526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
698526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int eap_aka_prime_kdf_valid(struct eap_aka_data *data,
699526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   struct eap_sim_attrs *attr)
700526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
701526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t i, j;
702526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
703526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (attr->kdf_count == 0)
704526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return 0;
705526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
706526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* The only allowed (and required) duplication of a KDF is the addition
707526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * of the selected KDF into the beginning of the list. */
708526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
709526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->kdf_negotiation) {
710526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (attr->kdf[0] != data->kdf) {
711526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
712526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "accept the selected KDF");
713526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return 0;
714526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
715526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
716526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		for (i = 1; i < attr->kdf_count; i++) {
717526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (attr->kdf[i] == data->kdf)
718526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				break;
719526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
720526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (i == attr->kdf_count &&
721526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    attr->kdf_count < EAP_AKA_PRIME_KDF_MAX) {
722526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
723526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "duplicate the selected KDF");
724526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return 0;
725526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
726526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
727526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* TODO: should check that the list is identical to the one
728526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * used in the previous Challenge message apart from the added
729526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * entry in the beginning. */
730526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
731526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
732526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) {
733526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		for (j = i + 1; j < attr->kdf_count; j++) {
734526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (attr->kdf[i] == attr->kdf[j]) {
735526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				wpa_printf(MSG_WARNING, "EAP-AKA': The server "
736526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   "included a duplicated KDF");
737526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				return 0;
738526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
739526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
740526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
741526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
742526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 1;
743526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
744526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* EAP_AKA_PRIME */
745526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
746526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
747526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
748526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 struct eap_aka_data *data,
749526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 u8 id,
750526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 const struct wpabuf *reqData,
751526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 struct eap_sim_attrs *attr)
752526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
753526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *identity;
754526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t identity_len;
755526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int res;
756526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_attrs eattr;
757526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
758526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge");
759526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
760526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (attr->checkcode &&
761526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    eap_aka_verify_checkcode(data, attr->checkcode,
762526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     attr->checkcode_len)) {
763526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
764526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "message");
765526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
766526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
767526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
768526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
769526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef EAP_AKA_PRIME
770526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
771526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (!attr->kdf_input || attr->kdf_input_len == 0) {
772526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message "
773526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "did not include non-empty AT_KDF_INPUT");
774526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			/* Fail authentication as if AUTN had been incorrect */
775526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return eap_aka_authentication_reject(data, id);
776526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
777526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data->network_name);
778526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->network_name = os_malloc(attr->kdf_input_len);
779526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->network_name == NULL) {
780526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_WARNING, "EAP-AKA': No memory for "
781526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "storing Network Name");
782526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return eap_aka_authentication_reject(data, id);
783526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
784526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data->network_name, attr->kdf_input,
785526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  attr->kdf_input_len);
786526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->network_name_len = attr->kdf_input_len;
787526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name "
788526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "(AT_KDF_INPUT)",
789526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  data->network_name, data->network_name_len);
790526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* TODO: check Network Name per 3GPP.33.402 */
791526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
792526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (!eap_aka_prime_kdf_valid(data, attr))
793526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return eap_aka_authentication_reject(data, id);
794526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
795526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (attr->kdf[0] != EAP_AKA_PRIME_KDF)
796526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return eap_aka_prime_kdf_neg(data, id, attr);
797526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
798526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->kdf = EAP_AKA_PRIME_KDF;
799526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
800526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
801526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
802526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->eap_method == EAP_TYPE_AKA && attr->bidding) {
803526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		u16 flags = WPA_GET_BE16(attr->bidding);
804526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if ((flags & EAP_AKA_BIDDING_FLAG_D) &&
805526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    eap_allowed_method(sm, EAP_VENDOR_IETF,
806526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       EAP_TYPE_AKA_PRIME)) {
807526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from "
808526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "AKA' to AKA detected");
809526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			/* Fail authentication as if AUTN had been incorrect */
810526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return eap_aka_authentication_reject(data, id);
811526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
812526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
813526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* EAP_AKA_PRIME */
814526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
815526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->reauth = 0;
816526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (!attr->mac || !attr->rand || !attr->autn) {
817526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
818526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "did not include%s%s%s",
819526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   !attr->mac ? " AT_MAC" : "",
820526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   !attr->rand ? " AT_RAND" : "",
821526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   !attr->autn ? " AT_AUTN" : "");
822526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
823526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
824526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
825526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN);
826526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN);
827526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
828526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	res = eap_aka_umts_auth(sm, data);
829526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (res == -1) {
830526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
831526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "failed (AUTN)");
832526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_authentication_reject(data, id);
833526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (res == -2) {
834526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
835526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "failed (AUTN seq# -> AUTS)");
836526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_synchronization_failure(data, id);
837526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (res) {
838526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
839526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
840526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
841526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
842526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef EAP_AKA_PRIME
843526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
844526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
845526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * needed 6-octet SQN ^ AK for CK',IK' derivation */
846526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		u16 amf = WPA_GET_BE16(data->autn + 6);
847526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (!(amf & 0x8000)) {
848526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_WARNING, "EAP-AKA': AMF separation bit "
849526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "not set (AMF=0x%4x)", amf);
850526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return eap_aka_authentication_reject(data, id);
851526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
852526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
853526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 data->autn,
854526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 data->network_name,
855526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 data->network_name_len);
856526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
857526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* EAP_AKA_PRIME */
858526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->last_eap_identity) {
859526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		identity = data->last_eap_identity;
860526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		identity_len = data->last_eap_identity_len;
861526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (data->pseudonym) {
862526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		identity = data->pseudonym;
863526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		identity_len = data->pseudonym_len;
864526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else
865526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		identity = eap_get_config_identity(sm, &identity_len);
866526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
867526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "derivation", identity, identity_len);
868526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
869526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_prime_derive_keys(identity, identity_len, data->ik,
870526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  data->ck, data->k_encr, data->k_aut,
871526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  data->k_re, data->msk, data->emsk);
872526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
873526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
874526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  data->mk);
875526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
876526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    data->msk, data->emsk);
877526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
878526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
879526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
880526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "used invalid AT_MAC");
881526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
882526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
883526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
884526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
885526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Old reauthentication and pseudonym identities must not be used
886526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * anymore. In other words, if no new identities are received, full
887526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * authentication will be used on next reauthentication. */
888526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
889526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 CLEAR_EAP_ID);
890526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
891526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (attr->encr_data) {
892526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		u8 *decrypted;
893526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
894526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					       attr->encr_data_len, attr->iv,
895526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					       &eattr, 0);
896526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (decrypted == NULL) {
897526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return eap_aka_client_error(
898526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
899526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
900526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_learn_ids(data, &eattr);
901526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(decrypted);
902526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
903526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
904526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->result_ind && attr->result_ind)
905526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->use_result_ind = 1;
906526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
907526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
908526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_state(data, data->use_result_ind ?
909526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      RESULT_SUCCESS : SUCCESS);
910526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
911526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
912526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_id_req = 0;
913526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_notification = 0;
914526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* RFC 4187 specifies that counter is initialized to one after
915526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * fullauth, but initializing it to zero makes it easier to implement
916526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * reauth verification. */
917526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->counter = 0;
918526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_aka_response_challenge(data, id);
919526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
920526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
921526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
922526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int eap_aka_process_notification_reauth(struct eap_aka_data *data,
923526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					       struct eap_sim_attrs *attr)
924526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
925526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_attrs eattr;
926526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *decrypted;
927526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
928526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (attr->encr_data == NULL || attr->iv == NULL) {
929526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after "
930526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "reauth did not include encrypted data");
931526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
932526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
933526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
934526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
935526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       attr->encr_data_len, attr->iv, &eattr,
936526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       0);
937526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (decrypted == NULL) {
938526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
939526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "data from notification message");
940526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
941526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
942526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
943526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
944526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
945526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "message does not match with counter in reauth "
946526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "message");
947526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(decrypted);
948526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
949526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
950526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
951526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(decrypted);
952526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
953526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
954526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
955526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
956526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int eap_aka_process_notification_auth(struct eap_aka_data *data,
957526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					     const struct wpabuf *reqData,
958526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					     struct eap_sim_attrs *attr)
959526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
960526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (attr->mac == NULL) {
961526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-AKA: no AT_MAC in after_auth "
962526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "Notification message");
963526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
964526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
965526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
966526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
967526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
968526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "used invalid AT_MAC");
969526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
970526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
971526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
972526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->reauth &&
973526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    eap_aka_process_notification_reauth(data, attr)) {
974526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification "
975526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "message after reauth");
976526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
977526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
978526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
979526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
980526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
981526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
982526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
983526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_process_notification(
984526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sm *sm, struct eap_aka_data *data, u8 id,
985526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
986526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
987526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Notification");
988526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->num_notification > 0) {
989526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-AKA: too many notification "
990526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "rounds (only one allowed)");
991526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
992526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
993526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
994526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_notification++;
995526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (attr->notification == -1) {
996526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in "
997526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "Notification message");
998526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
999526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1000526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1001526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1002526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if ((attr->notification & 0x4000) == 0 &&
1003526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    eap_aka_process_notification_auth(data, reqData, attr)) {
1004526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
1005526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1006526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1007526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1008526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
1009526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (attr->notification >= 0 && attr->notification < 32768) {
1010526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_state(data, FAILURE);
1011526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (attr->notification == EAP_SIM_SUCCESS &&
1012526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   data->state == RESULT_SUCCESS)
1013526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_state(data, SUCCESS);
1014526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_aka_response_notification(data, id, attr->notification);
1015526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1016526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1017526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1018526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_process_reauthentication(
1019526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sm *sm, struct eap_aka_data *data, u8 id,
1020526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
1021526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1022526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_attrs eattr;
1023526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *decrypted;
1024526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1025526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication");
1026526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1027526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (attr->checkcode &&
1028526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    eap_aka_verify_checkcode(data, attr->checkcode,
1029526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     attr->checkcode_len)) {
1030526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
1031526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "message");
1032526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
1033526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1034526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1035526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1036526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->reauth_id == NULL) {
1037526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying "
1038526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "reauthentication, but no reauth_id available");
1039526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
1040526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1041526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1042526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1043526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->reauth = 1;
1044526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
1045526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
1046526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "did not have valid AT_MAC");
1047526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
1048526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1049526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1050526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1051526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (attr->encr_data == NULL || attr->iv == NULL) {
1052526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
1053526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "message did not include encrypted data");
1054526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
1055526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1056526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1057526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1058526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
1059526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       attr->encr_data_len, attr->iv, &eattr,
1060526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       0);
1061526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (decrypted == NULL) {
1062526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
1063526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "data from reauthentication message");
1064526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
1065526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1066526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1067526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1068526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eattr.nonce_s == NULL || eattr.counter < 0) {
1069526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet",
1070526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   !eattr.nonce_s ? " AT_NONCE_S" : "",
1071526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   eattr.counter < 0 ? " AT_COUNTER" : "");
1072526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(decrypted);
1073526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_aka_client_error(data, id,
1074526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1075526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1076526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1077526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
1078526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		struct wpabuf *res;
1079526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter "
1080526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "(%d <= %d)", eattr.counter, data->counter);
1081526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->counter_too_small = eattr.counter;
1082526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1083526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
1084526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * reauth_id must not be used to start a new reauthentication.
1085526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * However, since it was used in the last EAP-Response-Identity
1086526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * packet, it has to saved for the following fullauth to be
1087526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * used in MK derivation. */
1088526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data->last_eap_identity);
1089526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->last_eap_identity = data->reauth_id;
1090526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->last_eap_identity_len = data->reauth_id_len;
1091526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->reauth_id = NULL;
1092526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->reauth_id_len = 0;
1093526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1094526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s);
1095526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(decrypted);
1096526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1097526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return res;
1098526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1099526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->counter = eattr.counter;
1100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
1102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
1103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
1104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
1106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
1107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 data->reauth_id,
1108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 data->reauth_id_len,
1109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 data->nonce_s,
1110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 data->msk, data->emsk);
1111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
1112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sim_derive_keys_reauth(data->counter, data->reauth_id,
1113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   data->reauth_id_len,
1114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   data->nonce_s, data->mk,
1115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   data->msk, data->emsk);
1116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
1118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_aka_learn_ids(data, &eattr);
1119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->result_ind && attr->result_ind)
1121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->use_result_ind = 1;
1122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
1124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_state(data, data->use_result_ind ?
1125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      RESULT_SUCCESS : SUCCESS);
1126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_id_req = 0;
1129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_notification = 0;
1130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
1131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
1132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "fast reauths performed - force fullauth");
1133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
1134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(decrypted);
1136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_aka_response_reauth(data, id, 0, data->nonce_s);
1137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv,
1141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       struct eap_method_ret *ret,
1142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       const struct wpabuf *reqData)
1143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data = priv;
1145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct eap_hdr *req;
1146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 subtype, id;
1147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *res;
1148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pos;
1149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sim_attrs attr;
1150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len;
1151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "EAP-AKA: EAP data", reqData);
1153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_get_config_identity(sm, &len) == NULL) {
1154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
1155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sm_request_identity(sm);
1156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
1157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
1161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       &len);
1162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos == NULL || len < 1) {
1163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
1164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	req = wpabuf_head(reqData);
1167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	id = req->identifier;
1168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len = be_to_host16(req->length);
1169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->ignore = FALSE;
1171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->methodState = METHOD_MAY_CONT;
1172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->decision = DECISION_FAIL;
1173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->allowNotifications = TRUE;
1174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	subtype = *pos++;
1176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
1177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += 2; /* Reserved */
1178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr,
1180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
1181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       0)) {
1182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		res = eap_aka_client_error(data, id,
1183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		goto done;
1185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (subtype) {
1188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case EAP_AKA_SUBTYPE_IDENTITY:
1189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		res = eap_aka_process_identity(sm, data, id, reqData, &attr);
1190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
1191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case EAP_AKA_SUBTYPE_CHALLENGE:
1192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		res = eap_aka_process_challenge(sm, data, id, reqData, &attr);
1193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
1194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case EAP_AKA_SUBTYPE_NOTIFICATION:
1195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		res = eap_aka_process_notification(sm, data, id, reqData,
1196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						   &attr);
1197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
1198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case EAP_AKA_SUBTYPE_REAUTHENTICATION:
1199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		res = eap_aka_process_reauthentication(sm, data, id, reqData,
1200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						       &attr);
1201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
1202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case EAP_AKA_SUBTYPE_CLIENT_ERROR:
1203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error");
1204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		res = eap_aka_client_error(data, id,
1205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
1207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	default:
1208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype);
1209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		res = eap_aka_client_error(data, id,
1210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
1212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtdone:
1215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state == FAILURE) {
1216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->decision = DECISION_FAIL;
1217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->methodState = METHOD_DONE;
1218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (data->state == SUCCESS) {
1219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->decision = data->use_result_ind ?
1220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
1221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/*
1222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * It is possible for the server to reply with AKA
1223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * Notification, so we must allow the method to continue and
1224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * not only accept EAP-Success at this point.
1225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 */
1226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->methodState = data->use_result_ind ?
1227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			METHOD_DONE : METHOD_MAY_CONT;
1228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (data->state == RESULT_FAILURE)
1229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->methodState = METHOD_CONT;
1230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	else if (data->state == RESULT_SUCCESS)
1231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->methodState = METHOD_CONT;
1232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ret->methodState == METHOD_DONE) {
1234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->allowNotifications = FALSE;
1235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return res;
1238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
1242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data = priv;
1244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data->pseudonym || data->reauth_id;
1245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
1249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data = priv;
1251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_aka_clear_identities(data, CLEAR_EAP_ID);
1252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->prev_id = -1;
1253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->id_msgs);
1254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->id_msgs = NULL;
1255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->use_result_ind = 0;
1256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->kdf_negotiation = 0;
1257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv)
1261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data = priv;
1263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_id_req = 0;
1264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_notification = 0;
1265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_aka_state(data, CONTINUE);
1266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return priv;
1267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv,
1271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       size_t *len)
1272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data = priv;
1274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->reauth_id) {
1276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		*len = data->reauth_id_len;
1277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return data->reauth_id;
1278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->pseudonym) {
1281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		*len = data->pseudonym_len;
1282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return data->pseudonym;
1283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return NULL;
1286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
1290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data = priv;
1292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data->state == SUCCESS;
1293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
1297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data = priv;
1299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *key;
1300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state != SUCCESS)
1302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
1305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (key == NULL)
1306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	*len = EAP_SIM_KEYING_DATA_LEN;
1309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
1310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return key;
1312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_aka_data *data = priv;
1318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *key;
1319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state != SUCCESS)
1321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	key = os_malloc(EAP_EMSK_LEN);
1324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (key == NULL)
1325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	*len = EAP_EMSK_LEN;
1328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
1329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return key;
1331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint eap_peer_aka_register(void)
1335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_method *eap;
1337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ret;
1338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
1340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
1341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap == NULL)
1342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
1343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->init = eap_aka_init;
1345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->deinit = eap_aka_deinit;
1346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->process = eap_aka_process;
1347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->isKeyAvailable = eap_aka_isKeyAvailable;
1348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->getKey = eap_aka_getKey;
1349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->has_reauth_data = eap_aka_has_reauth_data;
1350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
1351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->init_for_reauth = eap_aka_init_for_reauth;
1352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->get_identity = eap_aka_get_identity;
1353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->get_emsk = eap_aka_get_emsk;
1354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret = eap_peer_method_register(eap);
1356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ret)
1357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_peer_method_free(eap);
1358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return ret;
1359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef EAP_AKA_PRIME
1363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint eap_peer_aka_prime_register(void)
1364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_method *eap;
1366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ret;
1367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
1369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
1370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    "AKA'");
1371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap == NULL)
1372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
1373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->init = eap_aka_prime_init;
1375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->deinit = eap_aka_deinit;
1376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->process = eap_aka_process;
1377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->isKeyAvailable = eap_aka_isKeyAvailable;
1378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->getKey = eap_aka_getKey;
1379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->has_reauth_data = eap_aka_has_reauth_data;
1380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
1381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->init_for_reauth = eap_aka_init_for_reauth;
1382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->get_identity = eap_aka_get_identity;
1383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->get_emsk = eap_aka_get_emsk;
1384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret = eap_peer_method_register(eap);
1386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ret)
1387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_peer_method_free(eap);
1388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return ret;
1390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* EAP_AKA_PRIME */
1392