eap_sim.c revision c5ec7f57ead87efa365800228aa0b09a12d9e6c4
1/*
2 * EAP peer method: EAP-SIM (RFC 4186)
3 * Copyright (c) 2004-2008, 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 "pcsc_funcs.h"
13#include "crypto/milenage.h"
14#include "crypto/random.h"
15#include "eap_peer/eap_i.h"
16#include "eap_config.h"
17#include "eap_common/eap_sim_common.h"
18
19
20struct eap_sim_data {
21	u8 *ver_list;
22	size_t ver_list_len;
23	int selected_version;
24	size_t min_num_chal, num_chal;
25
26	u8 kc[3][EAP_SIM_KC_LEN];
27	u8 sres[3][EAP_SIM_SRES_LEN];
28	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN];
29	u8 mk[EAP_SIM_MK_LEN];
30	u8 k_aut[EAP_SIM_K_AUT_LEN];
31	u8 k_encr[EAP_SIM_K_ENCR_LEN];
32	u8 msk[EAP_SIM_KEYING_DATA_LEN];
33	u8 emsk[EAP_EMSK_LEN];
34	u8 rand[3][GSM_RAND_LEN];
35
36	int num_id_req, num_notification;
37	u8 *pseudonym;
38	size_t pseudonym_len;
39	u8 *reauth_id;
40	size_t reauth_id_len;
41	int reauth;
42	unsigned int counter, counter_too_small;
43	u8 *last_eap_identity;
44	size_t last_eap_identity_len;
45	enum {
46		CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
47	} state;
48	int result_ind, use_result_ind;
49};
50
51
52#ifndef CONFIG_NO_STDOUT_DEBUG
53static const char * eap_sim_state_txt(int state)
54{
55	switch (state) {
56	case CONTINUE:
57		return "CONTINUE";
58	case RESULT_SUCCESS:
59		return "RESULT_SUCCESS";
60	case RESULT_FAILURE:
61		return "RESULT_FAILURE";
62	case SUCCESS:
63		return "SUCCESS";
64	case FAILURE:
65		return "FAILURE";
66	default:
67		return "?";
68	}
69}
70#endif /* CONFIG_NO_STDOUT_DEBUG */
71
72
73static void eap_sim_state(struct eap_sim_data *data, int state)
74{
75	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
76		   eap_sim_state_txt(data->state),
77		   eap_sim_state_txt(state));
78	data->state = state;
79}
80
81
82static void * eap_sim_init(struct eap_sm *sm)
83{
84	struct eap_sim_data *data;
85	struct eap_peer_config *config = eap_get_config(sm);
86
87	data = os_zalloc(sizeof(*data));
88	if (data == NULL)
89		return NULL;
90
91	if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
92		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
93			   "for NONCE_MT");
94		os_free(data);
95		return NULL;
96	}
97
98	data->min_num_chal = 2;
99	if (config && config->phase1) {
100		char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
101		if (pos) {
102			data->min_num_chal = atoi(pos + 17);
103			if (data->min_num_chal < 2 || data->min_num_chal > 3) {
104				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
105					   "sim_min_num_chal configuration "
106					   "(%lu, expected 2 or 3)",
107					   (unsigned long) data->min_num_chal);
108				os_free(data);
109				return NULL;
110			}
111			wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of "
112				   "challenges to %lu",
113				   (unsigned long) data->min_num_chal);
114		}
115
116		data->result_ind = os_strstr(config->phase1, "result_ind=1") !=
117			NULL;
118	}
119
120	eap_sim_state(data, CONTINUE);
121
122	return data;
123}
124
125
126static void eap_sim_deinit(struct eap_sm *sm, void *priv)
127{
128	struct eap_sim_data *data = priv;
129	if (data) {
130		os_free(data->ver_list);
131		os_free(data->pseudonym);
132		os_free(data->reauth_id);
133		os_free(data->last_eap_identity);
134		os_free(data);
135	}
136}
137
138
139static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
140{
141	struct eap_peer_config *conf;
142
143	wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm");
144
145	conf = eap_get_config(sm);
146	if (conf == NULL)
147		return -1;
148	if (conf->pcsc) {
149		if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
150				   data->sres[0], data->kc[0]) ||
151		    scard_gsm_auth(sm->scard_ctx, data->rand[1],
152				   data->sres[1], data->kc[1]) ||
153		    (data->num_chal > 2 &&
154		     scard_gsm_auth(sm->scard_ctx, data->rand[2],
155				    data->sres[2], data->kc[2]))) {
156			wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM "
157				   "authentication could not be completed");
158			return -1;
159		}
160		return 0;
161	}
162
163#ifdef CONFIG_SIM_SIMULATOR
164	if (conf->password) {
165		u8 opc[16], k[16];
166		const char *pos;
167		size_t i;
168		wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage "
169			   "implementation for authentication");
170		if (conf->password_len < 65) {
171			wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage "
172				   "password");
173			return -1;
174		}
175		pos = (const char *) conf->password;
176		if (hexstr2bin(pos, k, 16))
177			return -1;
178		pos += 32;
179		if (*pos != ':')
180			return -1;
181		pos++;
182
183		if (hexstr2bin(pos, opc, 16))
184			return -1;
185
186		for (i = 0; i < data->num_chal; i++) {
187			if (gsm_milenage(opc, k, data->rand[i],
188					 data->sres[i], data->kc[i])) {
189				wpa_printf(MSG_DEBUG, "EAP-SIM: "
190					   "GSM-Milenage authentication "
191					   "could not be completed");
192				return -1;
193			}
194			wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
195				    data->rand[i], GSM_RAND_LEN);
196			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
197					data->sres[i], EAP_SIM_SRES_LEN);
198			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
199					data->kc[i], EAP_SIM_KC_LEN);
200		}
201		return 0;
202	}
203#endif /* CONFIG_SIM_SIMULATOR */
204
205#ifdef CONFIG_SIM_HARDCODED
206	/* These hardcoded Kc and SRES values are used for testing. RAND to
207	 * KC/SREC mapping is very bogus as far as real authentication is
208	 * concerned, but it is quite useful for cases where the AS is rotating
209	 * the order of pre-configured values. */
210	{
211		size_t i;
212
213		wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES "
214			   "values for testing");
215
216		for (i = 0; i < data->num_chal; i++) {
217			if (data->rand[i][0] == 0xaa) {
218				os_memcpy(data->kc[i],
219					  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
220					  EAP_SIM_KC_LEN);
221				os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
222					  EAP_SIM_SRES_LEN);
223			} else if (data->rand[i][0] == 0xbb) {
224				os_memcpy(data->kc[i],
225					  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
226					  EAP_SIM_KC_LEN);
227				os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
228					  EAP_SIM_SRES_LEN);
229			} else {
230				os_memcpy(data->kc[i],
231					  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
232					  EAP_SIM_KC_LEN);
233				os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
234					  EAP_SIM_SRES_LEN);
235			}
236		}
237	}
238
239	return 0;
240
241#else /* CONFIG_SIM_HARDCODED */
242
243	wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm "
244		   "enabled");
245	return -1;
246
247#endif /* CONFIG_SIM_HARDCODED */
248}
249
250
251static int eap_sim_supported_ver(int version)
252{
253	return version == EAP_SIM_VERSION;
254}
255
256
257#define CLEAR_PSEUDONYM	0x01
258#define CLEAR_REAUTH_ID	0x02
259#define CLEAR_EAP_ID	0x04
260
261static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
262{
263	if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
264		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym");
265		os_free(data->pseudonym);
266		data->pseudonym = NULL;
267		data->pseudonym_len = 0;
268	}
269	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
270		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
271		os_free(data->reauth_id);
272		data->reauth_id = NULL;
273		data->reauth_id_len = 0;
274	}
275	if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
276		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id");
277		os_free(data->last_eap_identity);
278		data->last_eap_identity = NULL;
279		data->last_eap_identity_len = 0;
280	}
281}
282
283
284static int eap_sim_learn_ids(struct eap_sm *sm, struct eap_sim_data *data,
285			     struct eap_sim_attrs *attr)
286{
287	if (attr->next_pseudonym) {
288		const u8 *identity = NULL;
289		size_t identity_len = 0;
290		const u8 *realm = NULL;
291		size_t realm_len = 0;
292
293		wpa_hexdump_ascii(MSG_DEBUG,
294				  "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
295				  attr->next_pseudonym,
296				  attr->next_pseudonym_len);
297		os_free(data->pseudonym);
298		/* Look for the realm of the permanent identity */
299		identity = eap_get_config_identity(sm, &identity_len);
300		if (identity) {
301			for (realm = identity, realm_len = identity_len;
302			     realm_len > 0; realm_len--, realm++) {
303				if (*realm == '@')
304					break;
305			}
306		}
307		data->pseudonym = os_malloc(attr->next_pseudonym_len +
308					    realm_len);
309		if (data->pseudonym == NULL) {
310			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
311				   "next pseudonym");
312			data->pseudonym_len = 0;
313			return -1;
314		}
315		os_memcpy(data->pseudonym, attr->next_pseudonym,
316			  attr->next_pseudonym_len);
317		if (realm_len) {
318			os_memcpy(data->pseudonym + attr->next_pseudonym_len,
319				  realm, realm_len);
320		}
321		data->pseudonym_len = attr->next_pseudonym_len + realm_len;
322	}
323
324	if (attr->next_reauth_id) {
325		os_free(data->reauth_id);
326		data->reauth_id = os_malloc(attr->next_reauth_id_len);
327		if (data->reauth_id == NULL) {
328			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
329				   "next reauth_id");
330			data->reauth_id_len = 0;
331			return -1;
332		}
333		os_memcpy(data->reauth_id, attr->next_reauth_id,
334			  attr->next_reauth_id_len);
335		data->reauth_id_len = attr->next_reauth_id_len;
336		wpa_hexdump_ascii(MSG_DEBUG,
337				  "EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
338				  data->reauth_id,
339				  data->reauth_id_len);
340	}
341
342	return 0;
343}
344
345
346static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
347					    int err)
348{
349	struct eap_sim_msg *msg;
350
351	eap_sim_state(data, FAILURE);
352	data->num_id_req = 0;
353	data->num_notification = 0;
354
355	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
356			       EAP_SIM_SUBTYPE_CLIENT_ERROR);
357	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
358	return eap_sim_msg_finish(msg, NULL, NULL, 0);
359}
360
361
362static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
363					      struct eap_sim_data *data, u8 id,
364					      enum eap_sim_id_req id_req)
365{
366	const u8 *identity = NULL;
367	size_t identity_len = 0;
368	struct eap_sim_msg *msg;
369
370	data->reauth = 0;
371	if (id_req == ANY_ID && data->reauth_id) {
372		identity = data->reauth_id;
373		identity_len = data->reauth_id_len;
374		data->reauth = 1;
375	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
376		   data->pseudonym) {
377		identity = data->pseudonym;
378		identity_len = data->pseudonym_len;
379		eap_sim_clear_identities(data, CLEAR_REAUTH_ID);
380	} else if (id_req != NO_ID_REQ) {
381		identity = eap_get_config_identity(sm, &identity_len);
382		if (identity) {
383			eap_sim_clear_identities(data, CLEAR_PSEUDONYM |
384						 CLEAR_REAUTH_ID);
385		}
386	}
387	if (id_req != NO_ID_REQ)
388		eap_sim_clear_identities(data, CLEAR_EAP_ID);
389
390	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
391	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
392			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
393	if (!data->reauth) {
394		wpa_hexdump(MSG_DEBUG, "   AT_NONCE_MT",
395			    data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
396		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0,
397				data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
398		wpa_printf(MSG_DEBUG, "   AT_SELECTED_VERSION %d",
399			   data->selected_version);
400		eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION,
401				data->selected_version, NULL, 0);
402	}
403
404	if (identity) {
405		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
406				  identity, identity_len);
407		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
408				identity, identity_len);
409	}
410
411	return eap_sim_msg_finish(msg, NULL, NULL, 0);
412}
413
414
415static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
416						  u8 id)
417{
418	struct eap_sim_msg *msg;
419
420	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)", id);
421	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
422			       EAP_SIM_SUBTYPE_CHALLENGE);
423	if (data->use_result_ind) {
424		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
425		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
426	}
427	wpa_printf(MSG_DEBUG, "   AT_MAC");
428	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
429	return eap_sim_msg_finish(msg, data->k_aut, (u8 *) data->sres,
430				  data->num_chal * EAP_SIM_SRES_LEN);
431}
432
433
434static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
435					       u8 id, int counter_too_small)
436{
437	struct eap_sim_msg *msg;
438	unsigned int counter;
439
440	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)",
441		   id);
442	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
443			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
444	wpa_printf(MSG_DEBUG, "   AT_IV");
445	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
446	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
447
448	if (counter_too_small) {
449		wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
450		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
451		counter = data->counter_too_small;
452	} else
453		counter = data->counter;
454
455	wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
456	eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
457
458	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
459		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
460			   "AT_ENCR_DATA");
461		eap_sim_msg_free(msg);
462		return NULL;
463	}
464	if (data->use_result_ind) {
465		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
466		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
467	}
468	wpa_printf(MSG_DEBUG, "   AT_MAC");
469	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
470	return eap_sim_msg_finish(msg, data->k_aut, data->nonce_s,
471				  EAP_SIM_NONCE_S_LEN);
472}
473
474
475static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
476						     u8 id, u16 notification)
477{
478	struct eap_sim_msg *msg;
479	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
480
481	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id);
482	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
483			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
484	if (k_aut && data->reauth) {
485		wpa_printf(MSG_DEBUG, "   AT_IV");
486		wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
487		eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
488					   EAP_SIM_AT_ENCR_DATA);
489		wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
490		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
491				NULL, 0);
492		if (eap_sim_msg_add_encr_end(msg, data->k_encr,
493					     EAP_SIM_AT_PADDING)) {
494			wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
495				   "AT_ENCR_DATA");
496			eap_sim_msg_free(msg);
497			return NULL;
498		}
499	}
500	if (k_aut) {
501		wpa_printf(MSG_DEBUG, "   AT_MAC");
502		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
503	}
504	return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
505}
506
507
508static struct wpabuf * eap_sim_process_start(struct eap_sm *sm,
509					     struct eap_sim_data *data, u8 id,
510					     struct eap_sim_attrs *attr)
511{
512	int selected_version = -1, id_error;
513	size_t i;
514	u8 *pos;
515
516	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start");
517	if (attr->version_list == NULL) {
518		wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in "
519			   "SIM/Start");
520		return eap_sim_client_error(data, id,
521					    EAP_SIM_UNSUPPORTED_VERSION);
522	}
523
524	os_free(data->ver_list);
525	data->ver_list = os_malloc(attr->version_list_len);
526	if (data->ver_list == NULL) {
527		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
528			   "memory for version list");
529		return eap_sim_client_error(data, id,
530					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
531	}
532	os_memcpy(data->ver_list, attr->version_list, attr->version_list_len);
533	data->ver_list_len = attr->version_list_len;
534	pos = data->ver_list;
535	for (i = 0; i < data->ver_list_len / 2; i++) {
536		int ver = pos[0] * 256 + pos[1];
537		pos += 2;
538		if (eap_sim_supported_ver(ver)) {
539			selected_version = ver;
540			break;
541		}
542	}
543	if (selected_version < 0) {
544		wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported "
545			   "version");
546		return eap_sim_client_error(data, id,
547					    EAP_SIM_UNSUPPORTED_VERSION);
548	}
549	wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d",
550		   selected_version);
551	data->selected_version = selected_version;
552
553	id_error = 0;
554	switch (attr->id_req) {
555	case NO_ID_REQ:
556		break;
557	case ANY_ID:
558		if (data->num_id_req > 0)
559			id_error++;
560		data->num_id_req++;
561		break;
562	case FULLAUTH_ID:
563		if (data->num_id_req > 1)
564			id_error++;
565		data->num_id_req++;
566		break;
567	case PERMANENT_ID:
568		if (data->num_id_req > 2)
569			id_error++;
570		data->num_id_req++;
571		break;
572	}
573	if (id_error) {
574		wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests "
575			   "used within one authentication");
576		return eap_sim_client_error(data, id,
577					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
578	}
579
580	return eap_sim_response_start(sm, data, id, attr->id_req);
581}
582
583
584static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
585						 struct eap_sim_data *data,
586						 u8 id,
587						 const struct wpabuf *reqData,
588						 struct eap_sim_attrs *attr)
589{
590	const u8 *identity;
591	size_t identity_len;
592	struct eap_sim_attrs eattr;
593
594	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
595	data->reauth = 0;
596	if (!attr->mac || !attr->rand) {
597		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
598			   "did not include%s%s",
599			   !attr->mac ? " AT_MAC" : "",
600			   !attr->rand ? " AT_RAND" : "");
601		return eap_sim_client_error(data, id,
602					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
603	}
604
605	wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges",
606		   (unsigned long) attr->num_chal);
607	if (attr->num_chal < data->min_num_chal) {
608		wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of "
609			   "challenges (%lu)", (unsigned long) attr->num_chal);
610		return eap_sim_client_error(data, id,
611					    EAP_SIM_INSUFFICIENT_NUM_OF_CHAL);
612	}
613	if (attr->num_chal > 3) {
614		wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges "
615			   "(%lu)", (unsigned long) attr->num_chal);
616		return eap_sim_client_error(data, id,
617					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
618	}
619
620	/* Verify that RANDs are different */
621	if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
622		   GSM_RAND_LEN) == 0 ||
623	    (attr->num_chal > 2 &&
624	     (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
625			GSM_RAND_LEN) == 0 ||
626	      os_memcmp(attr->rand + GSM_RAND_LEN,
627			attr->rand + 2 * GSM_RAND_LEN,
628			GSM_RAND_LEN) == 0))) {
629		wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times");
630		return eap_sim_client_error(data, id,
631					    EAP_SIM_RAND_NOT_FRESH);
632	}
633
634	os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
635	data->num_chal = attr->num_chal;
636
637	if (eap_sim_gsm_auth(sm, data)) {
638		wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
639		return eap_sim_client_error(data, id,
640					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
641	}
642	if (data->last_eap_identity) {
643		identity = data->last_eap_identity;
644		identity_len = data->last_eap_identity_len;
645	} else if (data->pseudonym) {
646		identity = data->pseudonym;
647		identity_len = data->pseudonym_len;
648	} else
649		identity = eap_get_config_identity(sm, &identity_len);
650	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
651			  "derivation", identity, identity_len);
652	eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
653			  data->selected_version, data->ver_list,
654			  data->ver_list_len, data->num_chal,
655			  (const u8 *) data->kc, data->mk);
656	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
657			    data->emsk);
658	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt,
659			       EAP_SIM_NONCE_MT_LEN)) {
660		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
661			   "used invalid AT_MAC");
662		return eap_sim_client_error(data, id,
663					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
664	}
665
666	/* Old reauthentication identity must not be used anymore. In
667	 * other words, if no new reauth identity is received, full
668	 * authentication will be used on next reauthentication (using
669	 * pseudonym identity or permanent identity). */
670	eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
671
672	if (attr->encr_data) {
673		u8 *decrypted;
674		decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
675					       attr->encr_data_len, attr->iv,
676					       &eattr, 0);
677		if (decrypted == NULL) {
678			return eap_sim_client_error(
679				data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
680		}
681		eap_sim_learn_ids(sm, data, &eattr);
682		os_free(decrypted);
683	}
684
685	if (data->result_ind && attr->result_ind)
686		data->use_result_ind = 1;
687
688	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
689		eap_sim_state(data, data->use_result_ind ?
690			      RESULT_SUCCESS : SUCCESS);
691	}
692
693	data->num_id_req = 0;
694	data->num_notification = 0;
695	/* RFC 4186 specifies that counter is initialized to one after
696	 * fullauth, but initializing it to zero makes it easier to implement
697	 * reauth verification. */
698	data->counter = 0;
699	return eap_sim_response_challenge(data, id);
700}
701
702
703static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
704					       struct eap_sim_attrs *attr)
705{
706	struct eap_sim_attrs eattr;
707	u8 *decrypted;
708
709	if (attr->encr_data == NULL || attr->iv == NULL) {
710		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
711			   "reauth did not include encrypted data");
712		return -1;
713	}
714
715	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
716				       attr->encr_data_len, attr->iv, &eattr,
717				       0);
718	if (decrypted == NULL) {
719		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
720			   "data from notification message");
721		return -1;
722	}
723
724	if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
725		wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
726			   "message does not match with counter in reauth "
727			   "message");
728		os_free(decrypted);
729		return -1;
730	}
731
732	os_free(decrypted);
733	return 0;
734}
735
736
737static int eap_sim_process_notification_auth(struct eap_sim_data *data,
738					     const struct wpabuf *reqData,
739					     struct eap_sim_attrs *attr)
740{
741	if (attr->mac == NULL) {
742		wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth "
743			   "Notification message");
744		return -1;
745	}
746
747	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
748	{
749		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message "
750			   "used invalid AT_MAC");
751		return -1;
752	}
753
754	if (data->reauth &&
755	    eap_sim_process_notification_reauth(data, attr)) {
756		wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification "
757			   "message after reauth");
758		return -1;
759	}
760
761	return 0;
762}
763
764
765static struct wpabuf * eap_sim_process_notification(
766	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
767	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
768{
769	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification");
770	if (data->num_notification > 0) {
771		wpa_printf(MSG_INFO, "EAP-SIM: too many notification "
772			   "rounds (only one allowed)");
773		return eap_sim_client_error(data, id,
774					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
775	}
776	data->num_notification++;
777	if (attr->notification == -1) {
778		wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in "
779			   "Notification message");
780		return eap_sim_client_error(data, id,
781					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
782	}
783
784	if ((attr->notification & 0x4000) == 0 &&
785	    eap_sim_process_notification_auth(data, reqData, attr)) {
786		return eap_sim_client_error(data, id,
787					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
788	}
789
790	eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
791	if (attr->notification >= 0 && attr->notification < 32768) {
792		eap_sim_state(data, FAILURE);
793	} else if (attr->notification == EAP_SIM_SUCCESS &&
794		   data->state == RESULT_SUCCESS)
795		eap_sim_state(data, SUCCESS);
796	return eap_sim_response_notification(data, id, attr->notification);
797}
798
799
800static struct wpabuf * eap_sim_process_reauthentication(
801	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
802	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
803{
804	struct eap_sim_attrs eattr;
805	u8 *decrypted;
806
807	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
808
809	if (data->reauth_id == NULL) {
810		wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying "
811			   "reauthentication, but no reauth_id available");
812		return eap_sim_client_error(data, id,
813					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
814	}
815
816	data->reauth = 1;
817	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
818	{
819		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
820			   "did not have valid AT_MAC");
821		return eap_sim_client_error(data, id,
822					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
823	}
824
825	if (attr->encr_data == NULL || attr->iv == NULL) {
826		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
827			   "message did not include encrypted data");
828		return eap_sim_client_error(data, id,
829					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
830	}
831
832	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
833				       attr->encr_data_len, attr->iv, &eattr,
834				       0);
835	if (decrypted == NULL) {
836		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
837			   "data from reauthentication message");
838		return eap_sim_client_error(data, id,
839					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
840	}
841
842	if (eattr.nonce_s == NULL || eattr.counter < 0) {
843		wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
844			   !eattr.nonce_s ? " AT_NONCE_S" : "",
845			   eattr.counter < 0 ? " AT_COUNTER" : "");
846		os_free(decrypted);
847		return eap_sim_client_error(data, id,
848					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
849	}
850
851	if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
852		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
853			   "(%d <= %d)", eattr.counter, data->counter);
854		data->counter_too_small = eattr.counter;
855		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
856		 * reauth_id must not be used to start a new reauthentication.
857		 * However, since it was used in the last EAP-Response-Identity
858		 * packet, it has to saved for the following fullauth to be
859		 * used in MK derivation. */
860		os_free(data->last_eap_identity);
861		data->last_eap_identity = data->reauth_id;
862		data->last_eap_identity_len = data->reauth_id_len;
863		data->reauth_id = NULL;
864		data->reauth_id_len = 0;
865		os_free(decrypted);
866		return eap_sim_response_reauth(data, id, 1);
867	}
868	data->counter = eattr.counter;
869
870	os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
871	wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S",
872		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
873
874	eap_sim_derive_keys_reauth(data->counter,
875				   data->reauth_id, data->reauth_id_len,
876				   data->nonce_s, data->mk, data->msk,
877				   data->emsk);
878	eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
879	eap_sim_learn_ids(sm, data, &eattr);
880
881	if (data->result_ind && attr->result_ind)
882		data->use_result_ind = 1;
883
884	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
885		eap_sim_state(data, data->use_result_ind ?
886			      RESULT_SUCCESS : SUCCESS);
887	}
888
889	data->num_id_req = 0;
890	data->num_notification = 0;
891	if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
892		wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
893			   "fast reauths performed - force fullauth");
894		eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
895	}
896	os_free(decrypted);
897	return eap_sim_response_reauth(data, id, 0);
898}
899
900
901static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv,
902				       struct eap_method_ret *ret,
903				       const struct wpabuf *reqData)
904{
905	struct eap_sim_data *data = priv;
906	const struct eap_hdr *req;
907	u8 subtype, id;
908	struct wpabuf *res;
909	const u8 *pos;
910	struct eap_sim_attrs attr;
911	size_t len;
912
913	wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData);
914	if (eap_get_config_identity(sm, &len) == NULL) {
915		wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
916		eap_sm_request_identity(sm);
917		ret->ignore = TRUE;
918		return NULL;
919	}
920
921	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len);
922	if (pos == NULL || len < 1) {
923		ret->ignore = TRUE;
924		return NULL;
925	}
926	req = wpabuf_head(reqData);
927	id = req->identifier;
928	len = be_to_host16(req->length);
929
930	ret->ignore = FALSE;
931	ret->methodState = METHOD_MAY_CONT;
932	ret->decision = DECISION_FAIL;
933	ret->allowNotifications = TRUE;
934
935	subtype = *pos++;
936	wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
937	pos += 2; /* Reserved */
938
939	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0,
940			       0)) {
941		res = eap_sim_client_error(data, id,
942					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
943		goto done;
944	}
945
946	switch (subtype) {
947	case EAP_SIM_SUBTYPE_START:
948		res = eap_sim_process_start(sm, data, id, &attr);
949		break;
950	case EAP_SIM_SUBTYPE_CHALLENGE:
951		res = eap_sim_process_challenge(sm, data, id, reqData, &attr);
952		break;
953	case EAP_SIM_SUBTYPE_NOTIFICATION:
954		res = eap_sim_process_notification(sm, data, id, reqData,
955						   &attr);
956		break;
957	case EAP_SIM_SUBTYPE_REAUTHENTICATION:
958		res = eap_sim_process_reauthentication(sm, data, id, reqData,
959						       &attr);
960		break;
961	case EAP_SIM_SUBTYPE_CLIENT_ERROR:
962		wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
963		res = eap_sim_client_error(data, id,
964					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
965		break;
966	default:
967		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
968		res = eap_sim_client_error(data, id,
969					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
970		break;
971	}
972
973done:
974	if (data->state == FAILURE) {
975		ret->decision = DECISION_FAIL;
976		ret->methodState = METHOD_DONE;
977	} else if (data->state == SUCCESS) {
978		ret->decision = data->use_result_ind ?
979			DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
980		ret->methodState = data->use_result_ind ?
981			METHOD_DONE : METHOD_MAY_CONT;
982	} else if (data->state == RESULT_FAILURE)
983		ret->methodState = METHOD_CONT;
984	else if (data->state == RESULT_SUCCESS)
985		ret->methodState = METHOD_CONT;
986
987	if (ret->methodState == METHOD_DONE) {
988		ret->allowNotifications = FALSE;
989	}
990
991	return res;
992}
993
994
995static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
996{
997	struct eap_sim_data *data = priv;
998	return data->pseudonym || data->reauth_id;
999}
1000
1001
1002static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
1003{
1004	struct eap_sim_data *data = priv;
1005	eap_sim_clear_identities(data, CLEAR_EAP_ID);
1006	data->use_result_ind = 0;
1007}
1008
1009
1010static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
1011{
1012	struct eap_sim_data *data = priv;
1013	if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
1014		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
1015			   "for NONCE_MT");
1016		os_free(data);
1017		return NULL;
1018	}
1019	data->num_id_req = 0;
1020	data->num_notification = 0;
1021	eap_sim_state(data, CONTINUE);
1022	return priv;
1023}
1024
1025
1026static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv,
1027				       size_t *len)
1028{
1029	struct eap_sim_data *data = priv;
1030
1031	if (data->reauth_id) {
1032		*len = data->reauth_id_len;
1033		return data->reauth_id;
1034	}
1035
1036	if (data->pseudonym) {
1037		*len = data->pseudonym_len;
1038		return data->pseudonym;
1039	}
1040
1041	return NULL;
1042}
1043
1044
1045static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
1046{
1047	struct eap_sim_data *data = priv;
1048	return data->state == SUCCESS;
1049}
1050
1051
1052static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
1053{
1054	struct eap_sim_data *data = priv;
1055	u8 *key;
1056
1057	if (data->state != SUCCESS)
1058		return NULL;
1059
1060	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
1061	if (key == NULL)
1062		return NULL;
1063
1064	*len = EAP_SIM_KEYING_DATA_LEN;
1065	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
1066
1067	return key;
1068}
1069
1070
1071static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1072{
1073	struct eap_sim_data *data = priv;
1074	u8 *key;
1075
1076	if (data->state != SUCCESS)
1077		return NULL;
1078
1079	key = os_malloc(EAP_EMSK_LEN);
1080	if (key == NULL)
1081		return NULL;
1082
1083	*len = EAP_EMSK_LEN;
1084	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
1085
1086	return key;
1087}
1088
1089
1090int eap_peer_sim_register(void)
1091{
1092	struct eap_method *eap;
1093	int ret;
1094
1095	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
1096				    EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
1097	if (eap == NULL)
1098		return -1;
1099
1100	eap->init = eap_sim_init;
1101	eap->deinit = eap_sim_deinit;
1102	eap->process = eap_sim_process;
1103	eap->isKeyAvailable = eap_sim_isKeyAvailable;
1104	eap->getKey = eap_sim_getKey;
1105	eap->has_reauth_data = eap_sim_has_reauth_data;
1106	eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
1107	eap->init_for_reauth = eap_sim_init_for_reauth;
1108	eap->get_identity = eap_sim_get_identity;
1109	eap->get_emsk = eap_sim_get_emsk;
1110
1111	ret = eap_peer_method_register(eap);
1112	if (ret)
1113		eap_peer_method_free(eap);
1114	return ret;
1115}
1116