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