1/*
2 * hostapd / EAP-SIM (RFC 4186)
3 * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "crypto/random.h"
13#include "eap_server/eap_i.h"
14#include "eap_common/eap_sim_common.h"
15#include "eap_server/eap_sim_db.h"
16
17
18struct eap_sim_data {
19	u8 mk[EAP_SIM_MK_LEN];
20	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
21	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
22	u8 k_aut[EAP_SIM_K_AUT_LEN];
23	u8 k_encr[EAP_SIM_K_ENCR_LEN];
24	u8 msk[EAP_SIM_KEYING_DATA_LEN];
25	u8 emsk[EAP_EMSK_LEN];
26	u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
27	u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
28	u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
29	u8 reauth_mac[EAP_SIM_MAC_LEN];
30	int num_chal;
31	enum {
32		START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
33	} state;
34	char *next_pseudonym;
35	char *next_reauth_id;
36	u16 counter;
37	struct eap_sim_reauth *reauth;
38	u16 notification;
39	int use_result_ind;
40	int start_round;
41	char permanent[20]; /* Permanent username */
42};
43
44
45static const char * eap_sim_state_txt(int state)
46{
47	switch (state) {
48	case START:
49		return "START";
50	case CHALLENGE:
51		return "CHALLENGE";
52	case REAUTH:
53		return "REAUTH";
54	case SUCCESS:
55		return "SUCCESS";
56	case FAILURE:
57		return "FAILURE";
58	case NOTIFICATION:
59		return "NOTIFICATION";
60	default:
61		return "Unknown?!";
62	}
63}
64
65
66static void eap_sim_state(struct eap_sim_data *data, int state)
67{
68	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
69		   eap_sim_state_txt(data->state),
70		   eap_sim_state_txt(state));
71	data->state = state;
72}
73
74
75static void * eap_sim_init(struct eap_sm *sm)
76{
77	struct eap_sim_data *data;
78
79	if (!sm->cfg->eap_sim_db_priv) {
80		wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
81		return NULL;
82	}
83
84	data = os_zalloc(sizeof(*data));
85	if (data == NULL)
86		return NULL;
87	data->state = START;
88
89	return data;
90}
91
92
93static void eap_sim_reset(struct eap_sm *sm, void *priv)
94{
95	struct eap_sim_data *data = priv;
96	os_free(data->next_pseudonym);
97	os_free(data->next_reauth_id);
98	bin_clear_free(data, sizeof(*data));
99}
100
101
102static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
103					   struct eap_sim_data *data, u8 id)
104{
105	struct eap_sim_msg *msg;
106	u8 ver[2];
107
108	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
109	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
110			       EAP_SIM_SUBTYPE_START);
111	data->start_round++;
112	if (data->start_round == 1) {
113		/*
114		 * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
115		 * ignored and the SIM/Start is used to request the identity.
116		 */
117		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
118		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
119	} else if (data->start_round > 3) {
120		/* Cannot use more than three rounds of Start messages */
121		eap_sim_msg_free(msg);
122		return NULL;
123	} else if (data->start_round == 0) {
124		/*
125		 * This is a special case that is used to recover from
126		 * AT_COUNTER_TOO_SMALL during re-authentication. Since we
127		 * already know the identity of the peer, there is no need to
128		 * request any identity in this case.
129		 */
130	} else if (sm->identity && sm->identity_len > 0 &&
131		   sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
132		/* Reauth id may have expired - try fullauth */
133		wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
134		eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
135	} else {
136		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
137		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
138	}
139	wpa_printf(MSG_DEBUG, "   AT_VERSION_LIST");
140	ver[0] = 0;
141	ver[1] = EAP_SIM_VERSION;
142	eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
143			ver, sizeof(ver));
144	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
145}
146
147
148static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
149			      struct eap_sim_msg *msg, u16 counter,
150			      const u8 *nonce_s)
151{
152	os_free(data->next_pseudonym);
153	if (!(sm->cfg->eap_sim_id & 0x01)) {
154		/* Use of pseudonyms disabled in configuration */
155		data->next_pseudonym = NULL;
156	} else if (!nonce_s) {
157		data->next_pseudonym =
158			eap_sim_db_get_next_pseudonym(sm->cfg->eap_sim_db_priv,
159						      EAP_SIM_DB_SIM);
160	} else {
161		/* Do not update pseudonym during re-authentication */
162		data->next_pseudonym = NULL;
163	}
164	os_free(data->next_reauth_id);
165	if (!(sm->cfg->eap_sim_id & 0x02)) {
166		/* Use of fast reauth disabled in configuration */
167		data->next_reauth_id = NULL;
168	} else if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
169		data->next_reauth_id =
170			eap_sim_db_get_next_reauth_id(sm->cfg->eap_sim_db_priv,
171						      EAP_SIM_DB_SIM);
172	} else {
173		wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
174			   "count exceeded - force full authentication");
175		data->next_reauth_id = NULL;
176	}
177
178	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
179	    counter == 0 && nonce_s == NULL)
180		return 0;
181
182	wpa_printf(MSG_DEBUG, "   AT_IV");
183	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
184	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
185
186	if (counter > 0) {
187		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
188		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
189	}
190
191	if (nonce_s) {
192		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
193		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
194				EAP_SIM_NONCE_S_LEN);
195	}
196
197	if (data->next_pseudonym) {
198		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
199			   data->next_pseudonym);
200		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
201				os_strlen(data->next_pseudonym),
202				(u8 *) data->next_pseudonym,
203				os_strlen(data->next_pseudonym));
204	}
205
206	if (data->next_reauth_id) {
207		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
208			   data->next_reauth_id);
209		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
210				os_strlen(data->next_reauth_id),
211				(u8 *) data->next_reauth_id,
212				os_strlen(data->next_reauth_id));
213	}
214
215	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
216		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
217			   "AT_ENCR_DATA");
218		return -1;
219	}
220
221	return 0;
222}
223
224
225static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm,
226					       struct eap_sim_data *data,
227					       u8 id)
228{
229	struct eap_sim_msg *msg;
230
231	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge");
232	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
233			       EAP_SIM_SUBTYPE_CHALLENGE);
234	wpa_printf(MSG_DEBUG, "   AT_RAND");
235	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
236			data->num_chal * GSM_RAND_LEN);
237
238	if (eap_sim_build_encr(sm, data, msg, 0, NULL)) {
239		eap_sim_msg_free(msg);
240		return NULL;
241	}
242
243	if (sm->cfg->eap_sim_aka_result_ind) {
244		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
245		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
246	}
247
248	wpa_printf(MSG_DEBUG, "   AT_MAC");
249	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
250	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut,
251				  data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
252}
253
254
255static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm,
256					    struct eap_sim_data *data, u8 id)
257{
258	struct eap_sim_msg *msg;
259	struct wpabuf *buf;
260
261	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
262
263	if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
264		return NULL;
265	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S",
266			data->nonce_s, EAP_SIM_NONCE_S_LEN);
267
268	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
269			    data->emsk);
270	eap_sim_derive_keys_reauth(data->counter, sm->identity,
271				   sm->identity_len, data->nonce_s, data->mk,
272				   data->msk, data->emsk);
273
274	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
275			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
276
277	if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
278		eap_sim_msg_free(msg);
279		return NULL;
280	}
281
282	if (sm->cfg->eap_sim_aka_result_ind) {
283		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
284		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
285	}
286
287	wpa_printf(MSG_DEBUG, "   AT_MAC");
288	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
289	buf = eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
290
291	/* Remember this MAC before sending it to the peer. This MAC is used for
292	 * Session-Id calculation after receiving response from the peer and
293	 * after all other checks pass. */
294	os_memcpy(data->reauth_mac,
295		  wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN,
296		  EAP_SIM_MAC_LEN);
297
298	return buf;
299}
300
301
302static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm,
303						  struct eap_sim_data *data,
304						  u8 id)
305{
306	struct eap_sim_msg *msg;
307
308	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Notification");
309	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
310			       EAP_SIM_SUBTYPE_NOTIFICATION);
311	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
312	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
313			NULL, 0);
314	if (data->use_result_ind) {
315		if (data->reauth) {
316			wpa_printf(MSG_DEBUG, "   AT_IV");
317			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
318			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
319						   EAP_SIM_AT_ENCR_DATA);
320			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
321				   data->counter);
322			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
323					NULL, 0);
324
325			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
326						     EAP_SIM_AT_PADDING)) {
327				wpa_printf(MSG_WARNING, "EAP-SIM: Failed to "
328					   "encrypt AT_ENCR_DATA");
329				eap_sim_msg_free(msg);
330				return NULL;
331			}
332		}
333
334		wpa_printf(MSG_DEBUG, "   AT_MAC");
335		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
336	}
337	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
338}
339
340
341static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id)
342{
343	struct eap_sim_data *data = priv;
344
345	switch (data->state) {
346	case START:
347		return eap_sim_build_start(sm, data, id);
348	case CHALLENGE:
349		return eap_sim_build_challenge(sm, data, id);
350	case REAUTH:
351		return eap_sim_build_reauth(sm, data, id);
352	case NOTIFICATION:
353		return eap_sim_build_notification(sm, data, id);
354	default:
355		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
356			   "buildReq", data->state);
357		break;
358	}
359	return NULL;
360}
361
362
363static bool eap_sim_check(struct eap_sm *sm, void *priv,
364			  struct wpabuf *respData)
365{
366	const u8 *pos;
367	size_t len;
368
369	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
370	if (pos == NULL || len < 3) {
371		wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
372		return true;
373	}
374
375	return false;
376}
377
378
379static bool eap_sim_unexpected_subtype(struct eap_sim_data *data,
380				       u8 subtype)
381{
382	if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
383		return false;
384
385	switch (data->state) {
386	case START:
387		if (subtype != EAP_SIM_SUBTYPE_START) {
388			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
389				   "subtype %d", subtype);
390			return true;
391		}
392		break;
393	case CHALLENGE:
394		if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
395			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
396				   "subtype %d", subtype);
397			return true;
398		}
399		break;
400	case REAUTH:
401		if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
402			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
403				   "subtype %d", subtype);
404			return true;
405		}
406		break;
407	case NOTIFICATION:
408		if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) {
409			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
410				   "subtype %d", subtype);
411			return true;
412		}
413		break;
414	default:
415		wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
416			   "processing a response", data->state);
417		return true;
418	}
419
420	return false;
421}
422
423
424static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
425{
426	return version == EAP_SIM_VERSION;
427}
428
429
430static void eap_sim_process_start(struct eap_sm *sm,
431				  struct eap_sim_data *data,
432				  struct wpabuf *respData,
433				  struct eap_sim_attrs *attr)
434{
435	size_t identity_len;
436	u8 ver_list[2];
437	u8 *new_identity;
438	char *username;
439
440	wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
441
442	if (data->start_round == 0) {
443		/*
444		 * Special case for AT_COUNTER_TOO_SMALL recovery - no identity
445		 * was requested since we already know it.
446		 */
447		goto skip_id_update;
448	}
449
450	/*
451	 * We always request identity in SIM/Start, so the peer is required to
452	 * have replied with one.
453	 */
454	if (!attr->identity || attr->identity_len == 0) {
455		wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any "
456			   "identity");
457		goto failed;
458	}
459
460	new_identity = os_malloc(attr->identity_len);
461	if (new_identity == NULL)
462		goto failed;
463	os_free(sm->identity);
464	sm->identity = new_identity;
465	os_memcpy(sm->identity, attr->identity, attr->identity_len);
466	sm->identity_len = attr->identity_len;
467
468	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
469			  sm->identity, sm->identity_len);
470	username = sim_get_username(sm->identity, sm->identity_len);
471	if (username == NULL)
472		goto failed;
473
474	if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) {
475		wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'",
476			   username);
477		data->reauth = eap_sim_db_get_reauth_entry(
478			sm->cfg->eap_sim_db_priv, username);
479		os_free(username);
480		if (data->reauth == NULL) {
481			wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth "
482				   "identity - request full auth identity");
483			/* Remain in START state for another round */
484			return;
485		}
486		wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication");
487		os_strlcpy(data->permanent, data->reauth->permanent,
488			   sizeof(data->permanent));
489		data->counter = data->reauth->counter;
490		os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
491		eap_sim_state(data, REAUTH);
492		return;
493	}
494
495	if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) {
496		const char *permanent;
497		wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'",
498			   username);
499		permanent = eap_sim_db_get_permanent(
500			sm->cfg->eap_sim_db_priv, username);
501		os_free(username);
502		if (permanent == NULL) {
503			wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym "
504				   "identity - request permanent identity");
505			/* Remain in START state for another round */
506			return;
507		}
508		os_strlcpy(data->permanent, permanent,
509			   sizeof(data->permanent));
510	} else if (username[0] == EAP_SIM_PERMANENT_PREFIX) {
511		wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'",
512			   username);
513		os_strlcpy(data->permanent, username, sizeof(data->permanent));
514		os_free(username);
515	} else {
516		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'",
517			   username);
518		os_free(username);
519		goto failed;
520	}
521
522skip_id_update:
523	/* Full authentication */
524
525	if (attr->nonce_mt == NULL || attr->selected_version < 0) {
526		wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
527			   "required attributes");
528		goto failed;
529	}
530
531	if (!eap_sim_supported_ver(data, attr->selected_version)) {
532		wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
533			   "version %d", attr->selected_version);
534		goto failed;
535	}
536
537	data->counter = 0; /* reset re-auth counter since this is full auth */
538	data->reauth = NULL;
539
540	data->num_chal = eap_sim_db_get_gsm_triplets(
541		sm->cfg->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
542		(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
543	if (data->num_chal == EAP_SIM_DB_PENDING) {
544		wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
545			   "not yet available - pending request");
546		sm->method_pending = METHOD_PENDING_WAIT;
547		return;
548	}
549	if (data->num_chal < 2) {
550		wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
551			   "authentication triplets for the peer");
552		goto failed;
553	}
554
555	if (data->permanent[0] == EAP_SIM_PERMANENT_PREFIX)
556		os_strlcpy(sm->imsi, &data->permanent[1], sizeof(sm->imsi));
557
558	identity_len = sm->identity_len;
559	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
560		wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null "
561			   "character from identity");
562		identity_len--;
563	}
564	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation",
565			  sm->identity, identity_len);
566
567	os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
568	WPA_PUT_BE16(ver_list, EAP_SIM_VERSION);
569	eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt,
570			  attr->selected_version, ver_list, sizeof(ver_list),
571			  data->num_chal, (const u8 *) data->kc, data->mk);
572	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
573			    data->emsk);
574
575	eap_sim_state(data, CHALLENGE);
576	return;
577
578failed:
579	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
580	eap_sim_state(data, NOTIFICATION);
581}
582
583
584static void eap_sim_process_challenge(struct eap_sm *sm,
585				      struct eap_sim_data *data,
586				      struct wpabuf *respData,
587				      struct eap_sim_attrs *attr)
588{
589	if (attr->mac == NULL ||
590	    eap_sim_verify_mac(data->k_aut, respData, attr->mac,
591			       (u8 *) data->sres,
592			       data->num_chal * EAP_SIM_SRES_LEN)) {
593		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
594			   "did not include valid AT_MAC");
595		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
596		eap_sim_state(data, NOTIFICATION);
597		return;
598	}
599
600	wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
601		   "correct AT_MAC");
602	if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
603		data->use_result_ind = 1;
604		data->notification = EAP_SIM_SUCCESS;
605		eap_sim_state(data, NOTIFICATION);
606	} else
607		eap_sim_state(data, SUCCESS);
608
609	if (data->next_pseudonym) {
610		eap_sim_db_add_pseudonym(sm->cfg->eap_sim_db_priv,
611					 data->permanent,
612					 data->next_pseudonym);
613		data->next_pseudonym = NULL;
614	}
615	if (data->next_reauth_id) {
616		eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
617				      data->next_reauth_id, data->counter + 1,
618				      data->mk);
619		data->next_reauth_id = NULL;
620	}
621}
622
623
624static void eap_sim_process_reauth(struct eap_sm *sm,
625				   struct eap_sim_data *data,
626				   struct wpabuf *respData,
627				   struct eap_sim_attrs *attr)
628{
629	struct eap_sim_attrs eattr;
630	u8 *decrypted = NULL;
631
632	if (attr->mac == NULL ||
633	    eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
634			       EAP_SIM_NONCE_S_LEN)) {
635		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
636			   "did not include valid AT_MAC");
637		goto fail;
638	}
639
640	if (attr->encr_data == NULL || attr->iv == NULL) {
641		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
642			   "message did not include encrypted data");
643		goto fail;
644	}
645
646	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
647				       attr->encr_data_len, attr->iv, &eattr,
648				       0);
649	if (decrypted == NULL) {
650		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
651			   "data from reauthentication message");
652		goto fail;
653	}
654
655	if (eattr.counter != data->counter) {
656		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
657			   "used incorrect counter %u, expected %u",
658			   eattr.counter, data->counter);
659		goto fail;
660	}
661	os_free(decrypted);
662	decrypted = NULL;
663
664	wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
665		   "the correct AT_MAC");
666
667	if (eattr.counter_too_small) {
668		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
669			   "included AT_COUNTER_TOO_SMALL - starting full "
670			   "authentication");
671		data->start_round = -1;
672		eap_sim_state(data, START);
673		return;
674	}
675
676	if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
677		data->use_result_ind = 1;
678		data->notification = EAP_SIM_SUCCESS;
679		eap_sim_state(data, NOTIFICATION);
680	} else
681		eap_sim_state(data, SUCCESS);
682
683	if (data->next_reauth_id) {
684		eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
685				      data->next_reauth_id,
686				      data->counter + 1, data->mk);
687		data->next_reauth_id = NULL;
688	} else {
689		eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv,
690					 data->reauth);
691		data->reauth = NULL;
692	}
693
694	return;
695
696fail:
697	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
698	eap_sim_state(data, NOTIFICATION);
699	eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, data->reauth);
700	data->reauth = NULL;
701	os_free(decrypted);
702}
703
704
705static void eap_sim_process_client_error(struct eap_sm *sm,
706					 struct eap_sim_data *data,
707					 struct wpabuf *respData,
708					 struct eap_sim_attrs *attr)
709{
710	wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
711		   attr->client_error_code);
712	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
713		eap_sim_state(data, SUCCESS);
714	else
715		eap_sim_state(data, FAILURE);
716}
717
718
719static void eap_sim_process_notification(struct eap_sm *sm,
720					 struct eap_sim_data *data,
721					 struct wpabuf *respData,
722					 struct eap_sim_attrs *attr)
723{
724	wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification");
725	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
726		eap_sim_state(data, SUCCESS);
727	else
728		eap_sim_state(data, FAILURE);
729}
730
731
732static void eap_sim_process(struct eap_sm *sm, void *priv,
733			    struct wpabuf *respData)
734{
735	struct eap_sim_data *data = priv;
736	const u8 *pos, *end;
737	u8 subtype;
738	size_t len;
739	struct eap_sim_attrs attr;
740
741	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
742	if (pos == NULL || len < 3)
743		return;
744
745	end = pos + len;
746	subtype = *pos;
747	pos += 3;
748
749	if (eap_sim_unexpected_subtype(data, subtype)) {
750		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected "
751			   "EAP-SIM Subtype in EAP Response");
752		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
753		eap_sim_state(data, NOTIFICATION);
754		return;
755	}
756
757	if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) {
758		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
759		if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR &&
760		    (data->state == START || data->state == CHALLENGE ||
761		     data->state == REAUTH)) {
762			data->notification =
763				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
764			eap_sim_state(data, NOTIFICATION);
765			return;
766		}
767		eap_sim_state(data, FAILURE);
768		return;
769	}
770
771	if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
772		eap_sim_process_client_error(sm, data, respData, &attr);
773		return;
774	}
775
776	switch (data->state) {
777	case START:
778		eap_sim_process_start(sm, data, respData, &attr);
779		break;
780	case CHALLENGE:
781		eap_sim_process_challenge(sm, data, respData, &attr);
782		break;
783	case REAUTH:
784		eap_sim_process_reauth(sm, data, respData, &attr);
785		break;
786	case NOTIFICATION:
787		eap_sim_process_notification(sm, data, respData, &attr);
788		break;
789	default:
790		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
791			   "process", data->state);
792		break;
793	}
794}
795
796
797static bool eap_sim_isDone(struct eap_sm *sm, void *priv)
798{
799	struct eap_sim_data *data = priv;
800	return data->state == SUCCESS || data->state == FAILURE;
801}
802
803
804static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
805{
806	struct eap_sim_data *data = priv;
807	u8 *key;
808
809	if (data->state != SUCCESS)
810		return NULL;
811
812	key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
813	if (key == NULL)
814		return NULL;
815	*len = EAP_SIM_KEYING_DATA_LEN;
816	return key;
817}
818
819
820static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
821{
822	struct eap_sim_data *data = priv;
823	u8 *key;
824
825	if (data->state != SUCCESS)
826		return NULL;
827
828	key = os_memdup(data->emsk, EAP_EMSK_LEN);
829	if (key == NULL)
830		return NULL;
831	*len = EAP_EMSK_LEN;
832	return key;
833}
834
835
836static bool eap_sim_isSuccess(struct eap_sm *sm, void *priv)
837{
838	struct eap_sim_data *data = priv;
839	return data->state == SUCCESS;
840}
841
842
843static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
844{
845	struct eap_sim_data *data = priv;
846	u8 *id;
847
848	if (data->state != SUCCESS)
849		return NULL;
850
851	if (!data->reauth)
852		*len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
853	else
854		*len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
855	id = os_malloc(*len);
856	if (id == NULL)
857		return NULL;
858
859	id[0] = EAP_TYPE_SIM;
860	if (!data->reauth) {
861		os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
862		os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN,
863			  data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
864	} else {
865		os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
866		os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
867			  EAP_SIM_MAC_LEN);
868
869	}
870	wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
871
872	return id;
873}
874
875
876int eap_server_sim_register(void)
877{
878	struct eap_method *eap;
879
880	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
881				      EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
882	if (eap == NULL)
883		return -1;
884
885	eap->init = eap_sim_init;
886	eap->reset = eap_sim_reset;
887	eap->buildReq = eap_sim_buildReq;
888	eap->check = eap_sim_check;
889	eap->process = eap_sim_process;
890	eap->isDone = eap_sim_isDone;
891	eap->getKey = eap_sim_getKey;
892	eap->isSuccess = eap_sim_isSuccess;
893	eap->get_emsk = eap_sim_get_emsk;
894	eap->getSessionId = eap_sim_get_session_id;
895
896	return eap_server_method_register(eap);
897}
898