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