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