11558Srgrimes/*
21558Srgrimes * hostapd / EAP-SIM (RFC 4186)
31558Srgrimes * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
41558Srgrimes *
51558Srgrimes * This software may be distributed under the terms of the BSD license.
61558Srgrimes * See README for more details.
71558Srgrimes */
81558Srgrimes
91558Srgrimes#include "includes.h"
101558Srgrimes
111558Srgrimes#include "common.h"
121558Srgrimes#include "crypto/random.h"
131558Srgrimes#include "eap_server/eap_i.h"
141558Srgrimes#include "eap_common/eap_sim_common.h"
151558Srgrimes#include "eap_server/eap_sim_db.h"
161558Srgrimes
171558Srgrimes
181558Srgrimesstruct eap_sim_data {
191558Srgrimes	u8 mk[EAP_SIM_MK_LEN];
201558Srgrimes	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
211558Srgrimes	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
221558Srgrimes	u8 k_aut[EAP_SIM_K_AUT_LEN];
231558Srgrimes	u8 k_encr[EAP_SIM_K_ENCR_LEN];
241558Srgrimes	u8 msk[EAP_SIM_KEYING_DATA_LEN];
251558Srgrimes	u8 emsk[EAP_EMSK_LEN];
261558Srgrimes	u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
271558Srgrimes	u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
281558Srgrimes	u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
291558Srgrimes	u8 reauth_mac[EAP_SIM_MAC_LEN];
301558Srgrimes	int num_chal;
311558Srgrimes	enum {
321558Srgrimes		START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
33114589Sobrien	} state;
341558Srgrimes	char *next_pseudonym;
3537667Scharnier	char *next_reauth_id;
361558Srgrimes	u16 counter;
371558Srgrimes	struct eap_sim_reauth *reauth;
38100635Speter	u16 notification;
391558Srgrimes	int use_result_ind;
401558Srgrimes	int start_round;
4123684Speter	char permanent[20]; /* Permanent username */
4237667Scharnier};
43100635Speter
44114589Sobrien
45114589Sobrienstatic const char * eap_sim_state_txt(int state)
461558Srgrimes{
471558Srgrimes	switch (state) {
481558Srgrimes	case START:
491558Srgrimes		return "START";
50101651Smux	case CHALLENGE:
512999Swollman		return "CHALLENGE";
52100635Speter	case REAUTH:
531558Srgrimes		return "REAUTH";
541558Srgrimes	case SUCCESS:
551558Srgrimes		return "SUCCESS";
561558Srgrimes	case FAILURE:
571558Srgrimes		return "FAILURE";
581558Srgrimes	case NOTIFICATION:
5996954Speter		return "NOTIFICATION";
601558Srgrimes	default:
6196954Speter		return "Unknown?!";
6296954Speter	}
6396954Speter}
6496954Speter
6596954Speter
6696954Speterstatic void eap_sim_state(struct eap_sim_data *data, int state)
671558Srgrimes{
681558Srgrimes	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
6996954Speter		   eap_sim_state_txt(data->state),
701558Srgrimes		   eap_sim_state_txt(state));
71100635Speter	data->state = state;
72101651Smux}
7323684Speter
74100635Speter
7596954Speterstatic void * eap_sim_init(struct eap_sm *sm)
761558Srgrimes{
7723684Speter	struct eap_sim_data *data;
78101651Smux
79101676Smux	if (sm->eap_sim_db_priv == NULL) {
80101651Smux		wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
8123684Speter		return NULL;
822999Swollman	}
8396954Speter
842999Swollman	data = os_zalloc(sizeof(*data));
852999Swollman	if (data == NULL)
8696954Speter		return NULL;
8724359Simp	data->state = START;
881558Srgrimes
891558Srgrimes	return data;
901558Srgrimes}
9196954Speter
92201015Sru
9396954Speterstatic void eap_sim_reset(struct eap_sm *sm, void *priv)
9496954Speter{
951558Srgrimes	struct eap_sim_data *data = priv;
9696954Speter	os_free(data->next_pseudonym);
97201015Sru	os_free(data->next_reauth_id);
9896954Speter	bin_clear_free(data, sizeof(*data));
9996954Speter}
10096954Speter
1011558Srgrimes
1021558Srgrimesstatic struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
1031558Srgrimes					   struct eap_sim_data *data, u8 id)
1041558Srgrimes{
1051558Srgrimes	struct eap_sim_msg *msg;
1061558Srgrimes	u8 ver[2];
1071558Srgrimes
1081558Srgrimes	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
10996954Speter	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
1101558Srgrimes			       EAP_SIM_SUBTYPE_START);
1111558Srgrimes	data->start_round++;
11296954Speter	if (data->start_round == 1) {
11396954Speter		/*
11496954Speter		 * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
11596954Speter		 * ignored and the SIM/Start is used to request the identity.
11696954Speter		 */
11796954Speter		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
11896954Speter		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
119144757Sbrooks	} else if (data->start_round > 3) {
120201015Sru		/* Cannot use more than three rounds of Start messages */
121201015Sru		eap_sim_msg_free(msg);
122201015Sru		return NULL;
123201015Sru	} else if (data->start_round == 0) {
124201015Sru		/*
12596954Speter		 * This is a special case that is used to recover from
12696954Speter		 * AT_COUNTER_TOO_SMALL during re-authentication. Since we
12796954Speter		 * already know the identity of the peer, there is no need to
12896954Speter		 * request any identity in this case.
12996954Speter		 */
13096954Speter	} else if (sm->identity && sm->identity_len > 0 &&
13196954Speter		   sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
1321558Srgrimes		/* Reauth id may have expired - try fullauth */
13396954Speter		wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
13496954Speter		eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
13596954Speter	} else {
13696954Speter		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
137100635Speter		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
1381558Srgrimes	}
1391558Srgrimes	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->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->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->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->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->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->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 Boolean 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 Boolean 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->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->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->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->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->eap_sim_db_priv, data->permanent,
611					 data->next_pseudonym);
612		data->next_pseudonym = NULL;
613	}
614	if (data->next_reauth_id) {
615		eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
616				      data->next_reauth_id, data->counter + 1,
617				      data->mk);
618		data->next_reauth_id = NULL;
619	}
620}
621
622
623static void eap_sim_process_reauth(struct eap_sm *sm,
624				   struct eap_sim_data *data,
625				   struct wpabuf *respData,
626				   struct eap_sim_attrs *attr)
627{
628	struct eap_sim_attrs eattr;
629	u8 *decrypted = NULL;
630
631	if (attr->mac == NULL ||
632	    eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
633			       EAP_SIM_NONCE_S_LEN)) {
634		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
635			   "did not include valid AT_MAC");
636		goto fail;
637	}
638
639	if (attr->encr_data == NULL || attr->iv == NULL) {
640		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
641			   "message did not include encrypted data");
642		goto fail;
643	}
644
645	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
646				       attr->encr_data_len, attr->iv, &eattr,
647				       0);
648	if (decrypted == NULL) {
649		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
650			   "data from reauthentication message");
651		goto fail;
652	}
653
654	if (eattr.counter != data->counter) {
655		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
656			   "used incorrect counter %u, expected %u",
657			   eattr.counter, data->counter);
658		goto fail;
659	}
660	os_free(decrypted);
661	decrypted = NULL;
662
663	wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
664		   "the correct AT_MAC");
665
666	if (eattr.counter_too_small) {
667		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
668			   "included AT_COUNTER_TOO_SMALL - starting full "
669			   "authentication");
670		data->start_round = -1;
671		eap_sim_state(data, START);
672		return;
673	}
674
675	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
676		data->use_result_ind = 1;
677		data->notification = EAP_SIM_SUCCESS;
678		eap_sim_state(data, NOTIFICATION);
679	} else
680		eap_sim_state(data, SUCCESS);
681
682	if (data->next_reauth_id) {
683		eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
684				      data->next_reauth_id,
685				      data->counter + 1, data->mk);
686		data->next_reauth_id = NULL;
687	} else {
688		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
689		data->reauth = NULL;
690	}
691
692	return;
693
694fail:
695	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
696	eap_sim_state(data, NOTIFICATION);
697	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
698	data->reauth = NULL;
699	os_free(decrypted);
700}
701
702
703static void eap_sim_process_client_error(struct eap_sm *sm,
704					 struct eap_sim_data *data,
705					 struct wpabuf *respData,
706					 struct eap_sim_attrs *attr)
707{
708	wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
709		   attr->client_error_code);
710	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
711		eap_sim_state(data, SUCCESS);
712	else
713		eap_sim_state(data, FAILURE);
714}
715
716
717static void eap_sim_process_notification(struct eap_sm *sm,
718					 struct eap_sim_data *data,
719					 struct wpabuf *respData,
720					 struct eap_sim_attrs *attr)
721{
722	wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification");
723	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
724		eap_sim_state(data, SUCCESS);
725	else
726		eap_sim_state(data, FAILURE);
727}
728
729
730static void eap_sim_process(struct eap_sm *sm, void *priv,
731			    struct wpabuf *respData)
732{
733	struct eap_sim_data *data = priv;
734	const u8 *pos, *end;
735	u8 subtype;
736	size_t len;
737	struct eap_sim_attrs attr;
738
739	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
740	if (pos == NULL || len < 3)
741		return;
742
743	end = pos + len;
744	subtype = *pos;
745	pos += 3;
746
747	if (eap_sim_unexpected_subtype(data, subtype)) {
748		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected "
749			   "EAP-SIM Subtype in EAP Response");
750		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
751		eap_sim_state(data, NOTIFICATION);
752		return;
753	}
754
755	if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) {
756		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
757		if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR &&
758		    (data->state == START || data->state == CHALLENGE ||
759		     data->state == REAUTH)) {
760			data->notification =
761				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
762			eap_sim_state(data, NOTIFICATION);
763			return;
764		}
765		eap_sim_state(data, FAILURE);
766		return;
767	}
768
769	if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
770		eap_sim_process_client_error(sm, data, respData, &attr);
771		return;
772	}
773
774	switch (data->state) {
775	case START:
776		eap_sim_process_start(sm, data, respData, &attr);
777		break;
778	case CHALLENGE:
779		eap_sim_process_challenge(sm, data, respData, &attr);
780		break;
781	case REAUTH:
782		eap_sim_process_reauth(sm, data, respData, &attr);
783		break;
784	case NOTIFICATION:
785		eap_sim_process_notification(sm, data, respData, &attr);
786		break;
787	default:
788		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
789			   "process", data->state);
790		break;
791	}
792}
793
794
795static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
796{
797	struct eap_sim_data *data = priv;
798	return data->state == SUCCESS || data->state == FAILURE;
799}
800
801
802static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
803{
804	struct eap_sim_data *data = priv;
805	u8 *key;
806
807	if (data->state != SUCCESS)
808		return NULL;
809
810	key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
811	if (key == NULL)
812		return NULL;
813	*len = EAP_SIM_KEYING_DATA_LEN;
814	return key;
815}
816
817
818static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
819{
820	struct eap_sim_data *data = priv;
821	u8 *key;
822
823	if (data->state != SUCCESS)
824		return NULL;
825
826	key = os_memdup(data->emsk, EAP_EMSK_LEN);
827	if (key == NULL)
828		return NULL;
829	*len = EAP_EMSK_LEN;
830	return key;
831}
832
833
834static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
835{
836	struct eap_sim_data *data = priv;
837	return data->state == SUCCESS;
838}
839
840
841static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
842{
843	struct eap_sim_data *data = priv;
844	u8 *id;
845
846	if (data->state != SUCCESS)
847		return NULL;
848
849	if (!data->reauth)
850		*len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
851	else
852		*len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
853	id = os_malloc(*len);
854	if (id == NULL)
855		return NULL;
856
857	id[0] = EAP_TYPE_SIM;
858	if (!data->reauth) {
859		os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
860		os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN,
861			  data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
862	} else {
863		os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
864		os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
865			  EAP_SIM_MAC_LEN);
866
867	}
868	wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
869
870	return id;
871}
872
873
874int eap_server_sim_register(void)
875{
876	struct eap_method *eap;
877
878	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
879				      EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
880	if (eap == NULL)
881		return -1;
882
883	eap->init = eap_sim_init;
884	eap->reset = eap_sim_reset;
885	eap->buildReq = eap_sim_buildReq;
886	eap->check = eap_sim_check;
887	eap->process = eap_sim_process;
888	eap->isDone = eap_sim_isDone;
889	eap->getKey = eap_sim_getKey;
890	eap->isSuccess = eap_sim_isSuccess;
891	eap->get_emsk = eap_sim_get_emsk;
892	eap->getSessionId = eap_sim_get_session_id;
893
894	return eap_server_method_register(eap);
895}
896