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