• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
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/sha256.h"
14 #include "crypto/crypto.h"
15 #include "crypto/random.h"
16 #include "eap_common/eap_sim_common.h"
17 #include "eap_server/eap_i.h"
18 #include "eap_server/eap_sim_db.h"
19 
20 
21 struct eap_aka_data {
22 	u8 mk[EAP_SIM_MK_LEN];
23 	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
24 	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
25 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
26 	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
27 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
28 	u8 emsk[EAP_EMSK_LEN];
29 	u8 rand[EAP_AKA_RAND_LEN];
30 	u8 autn[EAP_AKA_AUTN_LEN];
31 	u8 ck[EAP_AKA_CK_LEN];
32 	u8 ik[EAP_AKA_IK_LEN];
33 	u8 res[EAP_AKA_RES_MAX_LEN];
34 	u8 reauth_mac[EAP_SIM_MAC_LEN];
35 	size_t res_len;
36 	enum {
37 		IDENTITY, 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 	int auts_reported; /* whether the current AUTS has been reported to the
44 			    * eap_sim_db */
45 	u16 notification;
46 	int use_result_ind;
47 
48 	struct wpabuf *id_msgs;
49 	int pending_id;
50 	u8 eap_method;
51 	u8 *network_name;
52 	size_t network_name_len;
53 	u16 kdf;
54 	int identity_round;
55 	char permanent[20]; /* Permanent username */
56 };
57 
58 
59 static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data);
60 
61 
eap_aka_state_txt(int state)62 static const char * eap_aka_state_txt(int state)
63 {
64 	switch (state) {
65 	case IDENTITY:
66 		return "IDENTITY";
67 	case CHALLENGE:
68 		return "CHALLENGE";
69 	case REAUTH:
70 		return "REAUTH";
71 	case SUCCESS:
72 		return "SUCCESS";
73 	case FAILURE:
74 		return "FAILURE";
75 	case NOTIFICATION:
76 		return "NOTIFICATION";
77 	default:
78 		return "Unknown?!";
79 	}
80 }
81 
82 
eap_aka_state(struct eap_aka_data * data,int state)83 static void eap_aka_state(struct eap_aka_data *data, int state)
84 {
85 	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
86 		   eap_aka_state_txt(data->state),
87 		   eap_aka_state_txt(state));
88 	data->state = state;
89 }
90 
91 
eap_aka_check_identity_reauth(struct eap_sm * sm,struct eap_aka_data * data,const char * username)92 static int eap_aka_check_identity_reauth(struct eap_sm *sm,
93 					 struct eap_aka_data *data,
94 					 const char *username)
95 {
96 	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
97 	    username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)
98 		return 0;
99 	if (data->eap_method == EAP_TYPE_AKA &&
100 	    username[0] != EAP_AKA_REAUTH_ID_PREFIX)
101 		return 0;
102 
103 	wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
104 	data->reauth = eap_sim_db_get_reauth_entry(sm->cfg->eap_sim_db_priv,
105 						   username);
106 	if (data->reauth == NULL) {
107 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - "
108 			   "request full auth identity");
109 		/* Remain in IDENTITY state for another round */
110 		return 0;
111 	}
112 
113 	wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication");
114 	os_strlcpy(data->permanent, data->reauth->permanent,
115 		   sizeof(data->permanent));
116 	data->counter = data->reauth->counter;
117 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
118 		os_memcpy(data->k_encr, data->reauth->k_encr,
119 			  EAP_SIM_K_ENCR_LEN);
120 		os_memcpy(data->k_aut, data->reauth->k_aut,
121 			  EAP_AKA_PRIME_K_AUT_LEN);
122 		os_memcpy(data->k_re, data->reauth->k_re,
123 			  EAP_AKA_PRIME_K_RE_LEN);
124 	} else {
125 		os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
126 	}
127 
128 	eap_aka_state(data, REAUTH);
129 	return 1;
130 }
131 
132 
eap_aka_check_identity(struct eap_sm * sm,struct eap_aka_data * data)133 static void eap_aka_check_identity(struct eap_sm *sm,
134 				   struct eap_aka_data *data)
135 {
136 	char *username;
137 
138 	/* Check if we already know the identity from EAP-Response/Identity */
139 
140 	username = sim_get_username(sm->identity, sm->identity_len);
141 	if (username == NULL)
142 		return;
143 
144 	if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
145 		os_free(username);
146 		/*
147 		 * Since re-auth username was recognized, skip AKA/Identity
148 		 * exchange.
149 		 */
150 		return;
151 	}
152 
153 	if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
154 	     username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
155 	    (data->eap_method == EAP_TYPE_AKA &&
156 	     username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
157 		const char *permanent;
158 		wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
159 			   username);
160 		permanent = eap_sim_db_get_permanent(
161 			sm->cfg->eap_sim_db_priv, username);
162 		if (permanent == NULL) {
163 			os_free(username);
164 			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
165 				   "identity - request permanent identity");
166 			/* Remain in IDENTITY state for another round */
167 			return;
168 		}
169 		os_strlcpy(data->permanent, permanent,
170 			   sizeof(data->permanent));
171 		/*
172 		 * Since pseudonym username was recognized, skip AKA/Identity
173 		 * exchange.
174 		 */
175 		eap_aka_fullauth(sm, data);
176 	}
177 
178 	os_free(username);
179 }
180 
181 
eap_aka_init(struct eap_sm * sm)182 static void * eap_aka_init(struct eap_sm *sm)
183 {
184 	struct eap_aka_data *data;
185 
186 	if (!sm->cfg->eap_sim_db_priv) {
187 		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
188 		return NULL;
189 	}
190 
191 	data = os_zalloc(sizeof(*data));
192 	if (data == NULL)
193 		return NULL;
194 
195 	data->eap_method = EAP_TYPE_AKA;
196 
197 	data->state = IDENTITY;
198 	data->pending_id = -1;
199 	eap_aka_check_identity(sm, data);
200 
201 	return data;
202 }
203 
204 
205 #ifdef EAP_SERVER_AKA_PRIME
eap_aka_prime_init(struct eap_sm * sm)206 static void * eap_aka_prime_init(struct eap_sm *sm)
207 {
208 	struct eap_aka_data *data;
209 	/* TODO: make ANID configurable; see 3GPP TS 24.302 */
210 	char *network_name = "WLAN";
211 
212 	if (sm->cfg->eap_sim_db_priv == NULL) {
213 		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
214 		return NULL;
215 	}
216 
217 	data = os_zalloc(sizeof(*data));
218 	if (data == NULL)
219 		return NULL;
220 
221 	data->eap_method = EAP_TYPE_AKA_PRIME;
222 	data->network_name = (u8 *) os_strdup(network_name);
223 	if (data->network_name == NULL) {
224 		os_free(data);
225 		return NULL;
226 	}
227 
228 	data->network_name_len = os_strlen(network_name);
229 
230 	data->state = IDENTITY;
231 	data->pending_id = -1;
232 	eap_aka_check_identity(sm, data);
233 
234 	return data;
235 }
236 #endif /* EAP_SERVER_AKA_PRIME */
237 
238 
eap_aka_reset(struct eap_sm * sm,void * priv)239 static void eap_aka_reset(struct eap_sm *sm, void *priv)
240 {
241 	struct eap_aka_data *data = priv;
242 	os_free(data->next_pseudonym);
243 	os_free(data->next_reauth_id);
244 	wpabuf_free(data->id_msgs);
245 	os_free(data->network_name);
246 	bin_clear_free(data, sizeof(*data));
247 }
248 
249 
eap_aka_add_id_msg(struct eap_aka_data * data,const struct wpabuf * msg)250 static int eap_aka_add_id_msg(struct eap_aka_data *data,
251 			      const struct wpabuf *msg)
252 {
253 	if (msg == NULL)
254 		return -1;
255 
256 	if (data->id_msgs == NULL) {
257 		data->id_msgs = wpabuf_dup(msg);
258 		return data->id_msgs == NULL ? -1 : 0;
259 	}
260 
261 	if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
262 		return -1;
263 	wpabuf_put_buf(data->id_msgs, msg);
264 
265 	return 0;
266 }
267 
268 
eap_aka_add_checkcode(struct eap_aka_data * data,struct eap_sim_msg * msg)269 static void eap_aka_add_checkcode(struct eap_aka_data *data,
270 				  struct eap_sim_msg *msg)
271 {
272 	const u8 *addr;
273 	size_t len;
274 	u8 hash[SHA256_MAC_LEN];
275 
276 	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
277 
278 	if (data->id_msgs == NULL) {
279 		/*
280 		 * No EAP-AKA/Identity packets were exchanged - send empty
281 		 * checkcode.
282 		 */
283 		eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
284 		return;
285 	}
286 
287 	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
288 	addr = wpabuf_head(data->id_msgs);
289 	len = wpabuf_len(data->id_msgs);
290 	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
291 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
292 		sha256_vector(1, &addr, &len, hash);
293 	else
294 		sha1_vector(1, &addr, &len, hash);
295 
296 	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
297 			data->eap_method == EAP_TYPE_AKA_PRIME ?
298 			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
299 }
300 
301 
eap_aka_verify_checkcode(struct eap_aka_data * data,const u8 * checkcode,size_t checkcode_len)302 static int eap_aka_verify_checkcode(struct eap_aka_data *data,
303 				    const u8 *checkcode, size_t checkcode_len)
304 {
305 	const u8 *addr;
306 	size_t len;
307 	u8 hash[SHA256_MAC_LEN];
308 	size_t hash_len;
309 
310 	if (checkcode == NULL)
311 		return -1;
312 
313 	if (data->id_msgs == NULL) {
314 		if (checkcode_len != 0) {
315 			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
316 				   "indicates that AKA/Identity messages were "
317 				   "used, but they were not");
318 			return -1;
319 		}
320 		return 0;
321 	}
322 
323 	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
324 		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
325 
326 	if (checkcode_len != hash_len) {
327 		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
328 			   "that AKA/Identity message were not used, but they "
329 			   "were");
330 		return -1;
331 	}
332 
333 	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
334 	addr = wpabuf_head(data->id_msgs);
335 	len = wpabuf_len(data->id_msgs);
336 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
337 		sha256_vector(1, &addr, &len, hash);
338 	else
339 		sha1_vector(1, &addr, &len, hash);
340 
341 	if (os_memcmp_const(hash, checkcode, hash_len) != 0) {
342 		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
343 		return -1;
344 	}
345 
346 	return 0;
347 }
348 
349 
eap_aka_build_identity(struct eap_sm * sm,struct eap_aka_data * data,u8 id)350 static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
351 					      struct eap_aka_data *data, u8 id)
352 {
353 	struct eap_sim_msg *msg;
354 	struct wpabuf *buf;
355 
356 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
357 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
358 			       EAP_AKA_SUBTYPE_IDENTITY);
359 	data->identity_round++;
360 	if (data->identity_round == 1) {
361 		/*
362 		 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
363 		 * ignored and the AKA/Identity is used to request the
364 		 * identity.
365 		 */
366 		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
367 		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
368 	} else if (data->identity_round > 3) {
369 		/* Cannot use more than three rounds of Identity messages */
370 		eap_sim_msg_free(msg);
371 		return NULL;
372 	} else if (sm->identity && sm->identity_len > 0 &&
373 		   (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
374 		    sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) {
375 		/* Reauth id may have expired - try fullauth */
376 		wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
377 		eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
378 	} else {
379 		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
380 		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
381 	}
382 	buf = eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
383 	if (eap_aka_add_id_msg(data, buf) < 0) {
384 		wpabuf_free(buf);
385 		return NULL;
386 	}
387 	data->pending_id = id;
388 	return buf;
389 }
390 
391 
eap_aka_build_encr(struct eap_sm * sm,struct eap_aka_data * data,struct eap_sim_msg * msg,u16 counter,const u8 * nonce_s)392 static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
393 			      struct eap_sim_msg *msg, u16 counter,
394 			      const u8 *nonce_s)
395 {
396 	os_free(data->next_pseudonym);
397 	if (!(sm->cfg->eap_sim_id & 0x01)) {
398 		/* Use of pseudonyms disabled in configuration */
399 		data->next_pseudonym = NULL;
400 	} else if (!nonce_s) {
401 		data->next_pseudonym =
402 			eap_sim_db_get_next_pseudonym(
403 				sm->cfg->eap_sim_db_priv,
404 				data->eap_method == EAP_TYPE_AKA_PRIME ?
405 				EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
406 	} else {
407 		/* Do not update pseudonym during re-authentication */
408 		data->next_pseudonym = NULL;
409 	}
410 	os_free(data->next_reauth_id);
411 	if (!(sm->cfg->eap_sim_id & 0x02)) {
412 		/* Use of fast reauth disabled in configuration */
413 		data->next_reauth_id = NULL;
414 	} else if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
415 		data->next_reauth_id =
416 			eap_sim_db_get_next_reauth_id(
417 				sm->cfg->eap_sim_db_priv,
418 				data->eap_method == EAP_TYPE_AKA_PRIME ?
419 				EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
420 	} else {
421 		wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
422 			   "count exceeded - force full authentication");
423 		data->next_reauth_id = NULL;
424 	}
425 
426 	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
427 	    counter == 0 && nonce_s == NULL)
428 		return 0;
429 
430 	wpa_printf(MSG_DEBUG, "   AT_IV");
431 	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
432 	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
433 
434 	if (counter > 0) {
435 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
436 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
437 	}
438 
439 	if (nonce_s) {
440 		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
441 		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
442 				EAP_SIM_NONCE_S_LEN);
443 	}
444 
445 	if (data->next_pseudonym) {
446 		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
447 			   data->next_pseudonym);
448 		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
449 				os_strlen(data->next_pseudonym),
450 				(u8 *) data->next_pseudonym,
451 				os_strlen(data->next_pseudonym));
452 	}
453 
454 	if (data->next_reauth_id) {
455 		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
456 			   data->next_reauth_id);
457 		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
458 				os_strlen(data->next_reauth_id),
459 				(u8 *) data->next_reauth_id,
460 				os_strlen(data->next_reauth_id));
461 	}
462 
463 	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
464 		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
465 			   "AT_ENCR_DATA");
466 		return -1;
467 	}
468 
469 	return 0;
470 }
471 
472 
eap_aka_build_challenge(struct eap_sm * sm,struct eap_aka_data * data,u8 id)473 static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
474 					       struct eap_aka_data *data,
475 					       u8 id)
476 {
477 	struct eap_sim_msg *msg;
478 
479 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
480 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
481 			       EAP_AKA_SUBTYPE_CHALLENGE);
482 	wpa_printf(MSG_DEBUG, "   AT_RAND");
483 	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
484 	wpa_printf(MSG_DEBUG, "   AT_AUTN");
485 	eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
486 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
487 		if (data->kdf) {
488 			/* Add the selected KDF into the beginning */
489 			wpa_printf(MSG_DEBUG, "   AT_KDF");
490 			eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
491 					NULL, 0);
492 		}
493 		wpa_printf(MSG_DEBUG, "   AT_KDF");
494 		eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
495 				NULL, 0);
496 		wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
497 		eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
498 				data->network_name_len,
499 				data->network_name, data->network_name_len);
500 	}
501 
502 	if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
503 		eap_sim_msg_free(msg);
504 		return NULL;
505 	}
506 
507 	eap_aka_add_checkcode(data, msg);
508 
509 	if (sm->cfg->eap_sim_aka_result_ind) {
510 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
511 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
512 	}
513 
514 #ifdef EAP_SERVER_AKA_PRIME
515 	if (data->eap_method == EAP_TYPE_AKA) {
516 		u16 flags = 0;
517 		int i;
518 		int aka_prime_preferred = 0;
519 
520 		i = 0;
521 		while (sm->user && i < EAP_MAX_METHODS &&
522 		       (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
523 			sm->user->methods[i].method != EAP_TYPE_NONE)) {
524 			if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
525 				if (sm->user->methods[i].method ==
526 				    EAP_TYPE_AKA)
527 					break;
528 				if (sm->user->methods[i].method ==
529 				    EAP_TYPE_AKA_PRIME) {
530 					aka_prime_preferred = 1;
531 					break;
532 				}
533 			}
534 			i++;
535 		}
536 
537 		if (aka_prime_preferred)
538 			flags |= EAP_AKA_BIDDING_FLAG_D;
539 		eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
540 	}
541 #endif /* EAP_SERVER_AKA_PRIME */
542 
543 	wpa_printf(MSG_DEBUG, "   AT_MAC");
544 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
545 	return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
546 }
547 
548 
eap_aka_build_reauth(struct eap_sm * sm,struct eap_aka_data * data,u8 id)549 static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
550 					    struct eap_aka_data *data, u8 id)
551 {
552 	struct eap_sim_msg *msg;
553 	struct wpabuf *buf;
554 
555 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
556 
557 	if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
558 		return NULL;
559 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
560 			data->nonce_s, EAP_SIM_NONCE_S_LEN);
561 
562 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
563 		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
564 						 sm->identity,
565 						 sm->identity_len,
566 						 data->nonce_s,
567 						 data->msk, data->emsk);
568 	} else {
569 		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
570 				    data->msk, data->emsk);
571 		eap_sim_derive_keys_reauth(data->counter, sm->identity,
572 					   sm->identity_len, data->nonce_s,
573 					   data->mk, data->msk, data->emsk);
574 	}
575 
576 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
577 			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
578 
579 	if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
580 		eap_sim_msg_free(msg);
581 		return NULL;
582 	}
583 
584 	eap_aka_add_checkcode(data, msg);
585 
586 	if (sm->cfg->eap_sim_aka_result_ind) {
587 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
588 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
589 	}
590 
591 	wpa_printf(MSG_DEBUG, "   AT_MAC");
592 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
593 	buf = eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
594 
595 	/* Remember this MAC before sending it to the peer. This MAC is used for
596 	 * Session-Id calculation after receiving response from the peer and
597 	 * after all other checks pass. */
598 	os_memcpy(data->reauth_mac,
599 		  wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN,
600 		  EAP_SIM_MAC_LEN);
601 
602 	return buf;
603 }
604 
605 
eap_aka_build_notification(struct eap_sm * sm,struct eap_aka_data * data,u8 id)606 static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
607 						  struct eap_aka_data *data,
608 						  u8 id)
609 {
610 	struct eap_sim_msg *msg;
611 
612 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
613 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
614 			       EAP_AKA_SUBTYPE_NOTIFICATION);
615 	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
616 	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
617 			NULL, 0);
618 	if (data->use_result_ind) {
619 		if (data->reauth) {
620 			wpa_printf(MSG_DEBUG, "   AT_IV");
621 			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
622 			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
623 						   EAP_SIM_AT_ENCR_DATA);
624 			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
625 				   data->counter);
626 			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
627 					NULL, 0);
628 
629 			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
630 						     EAP_SIM_AT_PADDING)) {
631 				wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
632 					   "encrypt AT_ENCR_DATA");
633 				eap_sim_msg_free(msg);
634 				return NULL;
635 			}
636 		}
637 
638 		wpa_printf(MSG_DEBUG, "   AT_MAC");
639 		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
640 	}
641 	return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
642 }
643 
644 
eap_aka_buildReq(struct eap_sm * sm,void * priv,u8 id)645 static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
646 {
647 	struct eap_aka_data *data = priv;
648 
649 	data->auts_reported = 0;
650 	switch (data->state) {
651 	case IDENTITY:
652 		return eap_aka_build_identity(sm, data, id);
653 	case CHALLENGE:
654 		return eap_aka_build_challenge(sm, data, id);
655 	case REAUTH:
656 		return eap_aka_build_reauth(sm, data, id);
657 	case NOTIFICATION:
658 		return eap_aka_build_notification(sm, data, id);
659 	default:
660 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
661 			   "buildReq", data->state);
662 		break;
663 	}
664 	return NULL;
665 }
666 
667 
eap_aka_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)668 static bool eap_aka_check(struct eap_sm *sm, void *priv,
669 			  struct wpabuf *respData)
670 {
671 	struct eap_aka_data *data = priv;
672 	const u8 *pos;
673 	size_t len;
674 
675 	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
676 			       &len);
677 	if (pos == NULL || len < 3) {
678 		wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
679 		return true;
680 	}
681 
682 	return false;
683 }
684 
685 
eap_aka_subtype_ok(struct eap_aka_data * data,u8 subtype)686 static bool eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
687 {
688 	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
689 	    subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
690 		return false;
691 
692 	switch (data->state) {
693 	case IDENTITY:
694 		if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
695 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
696 				   "subtype %d", subtype);
697 			return true;
698 		}
699 		break;
700 	case CHALLENGE:
701 		if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
702 		    subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
703 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
704 				   "subtype %d", subtype);
705 			return true;
706 		}
707 		break;
708 	case REAUTH:
709 		if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
710 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
711 				   "subtype %d", subtype);
712 			return true;
713 		}
714 		break;
715 	case NOTIFICATION:
716 		if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
717 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
718 				   "subtype %d", subtype);
719 			return true;
720 		}
721 		break;
722 	default:
723 		wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
724 			   "processing a response", data->state);
725 		return true;
726 	}
727 
728 	return false;
729 }
730 
731 
eap_aka_determine_identity(struct eap_sm * sm,struct eap_aka_data * data)732 static void eap_aka_determine_identity(struct eap_sm *sm,
733 				       struct eap_aka_data *data)
734 {
735 	char *username;
736 
737 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
738 			  sm->identity, sm->identity_len);
739 
740 	username = sim_get_username(sm->identity, sm->identity_len);
741 	if (!username)
742 		goto fail;
743 
744 	if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
745 		os_free(username);
746 		return;
747 	}
748 
749 	if (((data->eap_method == EAP_TYPE_AKA_PRIME &&
750 	      username[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) ||
751 	     (data->eap_method == EAP_TYPE_AKA &&
752 	      username[0] == EAP_AKA_REAUTH_ID_PREFIX)) &&
753 	    data->identity_round == 1) {
754 		/* Remain in IDENTITY state for another round to request full
755 		 * auth identity since we did not recognize reauth id */
756 		os_free(username);
757 		return;
758 	}
759 
760 	if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
761 	     username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
762 	    (data->eap_method == EAP_TYPE_AKA &&
763 	     username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
764 		const char *permanent;
765 		wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
766 			   username);
767 		permanent = eap_sim_db_get_permanent(
768 			sm->cfg->eap_sim_db_priv, username);
769 		os_free(username);
770 		if (permanent == NULL) {
771 			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
772 				   "identity - request permanent identity");
773 			/* Remain in IDENTITY state for another round */
774 			return;
775 		}
776 		os_strlcpy(data->permanent, permanent,
777 			   sizeof(data->permanent));
778 	} else if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
779 		    username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) ||
780 		   (data->eap_method == EAP_TYPE_AKA &&
781 		    username[0] == EAP_AKA_PERMANENT_PREFIX)) {
782 		wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'",
783 			   username);
784 		os_strlcpy(data->permanent, username, sizeof(data->permanent));
785 		os_free(username);
786 #ifdef CRYPTO_RSA_OAEP_SHA256
787 	} else if (sm->identity_len > 1 && sm->identity[0] == '\0') {
788 		char *enc_id, *pos, *end;
789 		size_t enc_id_len;
790 		u8 *decoded_id;
791 		size_t decoded_id_len;
792 		struct wpabuf *enc, *dec;
793 		u8 *new_id;
794 
795 		os_free(username);
796 		if (!sm->cfg->imsi_privacy_key) {
797 			wpa_printf(MSG_DEBUG,
798 				   "EAP-AKA: Received encrypted identity, but no IMSI privacy key configured to decrypt it");
799 			goto fail;
800 		}
801 
802 		enc_id = (char *) &sm->identity[1];
803 		end = (char *) &sm->identity[sm->identity_len];
804 		for (pos = enc_id; pos < end; pos++) {
805 			if (*pos == ',')
806 				break;
807 		}
808 		enc_id_len = pos - enc_id;
809 
810 		wpa_hexdump_ascii(MSG_DEBUG,
811 				  "EAP-AKA: Encrypted permanent identity",
812 				  enc_id, enc_id_len);
813 		decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len);
814 		if (!decoded_id) {
815 			wpa_printf(MSG_DEBUG,
816 				   "EAP-AKA: Could not base64 decode encrypted identity");
817 			goto fail;
818 		}
819 		wpa_hexdump(MSG_DEBUG,
820 			    "EAP-AKA: Decoded encrypted permanent identity",
821 			    decoded_id, decoded_id_len);
822 		enc = wpabuf_alloc_copy(decoded_id, decoded_id_len);
823 		os_free(decoded_id);
824 		if (!enc)
825 			goto fail;
826 		dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key,
827 						     enc);
828 		wpabuf_free(enc);
829 		if (!dec) {
830 			wpa_printf(MSG_DEBUG,
831 				   "EAP-AKA: Failed to decrypt encrypted identity");
832 			goto fail;
833 		}
834 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Decrypted permanent identity",
835 				  wpabuf_head(dec), wpabuf_len(dec));
836 		username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec));
837 		if (!username) {
838 			wpabuf_free(dec);
839 			goto fail;
840 		}
841 		new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec));
842 		if (!new_id) {
843 			wpabuf_free(dec);
844 			goto fail;
845 		}
846 		os_free(sm->identity);
847 		sm->identity = new_id;
848 		sm->identity_len = wpabuf_len(dec);
849 		wpabuf_free(dec);
850 		os_strlcpy(data->permanent, username, sizeof(data->permanent));
851 		os_free(username);
852 #endif /* CRYPTO_RSA_OAEP_SHA256 */
853 	} else {
854 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'",
855 			   username);
856 		os_free(username);
857 		goto fail;
858 		return;
859 	}
860 
861 	eap_aka_fullauth(sm, data);
862 	return;
863 
864 fail:
865 	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
866 	eap_aka_state(data, NOTIFICATION);
867 }
868 
869 
eap_aka_fullauth(struct eap_sm * sm,struct eap_aka_data * data)870 static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data)
871 {
872 	size_t identity_len;
873 	int res;
874 
875 	res = eap_sim_db_get_aka_auth(sm->cfg->eap_sim_db_priv, data->permanent,
876 				      data->rand, data->autn, data->ik,
877 				      data->ck, data->res, &data->res_len, sm);
878 	if (res == EAP_SIM_DB_PENDING) {
879 		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
880 			   "not yet available - pending request");
881 		sm->method_pending = METHOD_PENDING_WAIT;
882 		return;
883 	}
884 
885 	if (data->permanent[0] == EAP_AKA_PERMANENT_PREFIX ||
886 	    data->permanent[0] == EAP_AKA_PRIME_PERMANENT_PREFIX)
887 		os_strlcpy(sm->imsi, &data->permanent[1], sizeof(sm->imsi));
888 
889 #ifdef EAP_SERVER_AKA_PRIME
890 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
891 		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
892 		 * needed 6-octet SQN ^AK for CK',IK' derivation */
893 		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
894 						 data->autn,
895 						 data->network_name,
896 						 data->network_name_len);
897 	}
898 #endif /* EAP_SERVER_AKA_PRIME */
899 
900 	data->reauth = NULL;
901 	data->counter = 0; /* reset re-auth counter since this is full auth */
902 
903 	if (res != 0) {
904 		wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
905 			   "authentication data for the peer");
906 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
907 		eap_aka_state(data, NOTIFICATION);
908 		return;
909 	}
910 	if (sm->method_pending == METHOD_PENDING_WAIT) {
911 		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
912 			   "available - abort pending wait");
913 		sm->method_pending = METHOD_PENDING_NONE;
914 	}
915 
916 	identity_len = sm->identity_len;
917 	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
918 		wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
919 			   "character from identity");
920 		identity_len--;
921 	}
922 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
923 			  sm->identity, identity_len);
924 
925 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
926 		eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik,
927 					  data->ck, data->k_encr, data->k_aut,
928 					  data->k_re, data->msk, data->emsk);
929 	} else {
930 		eap_aka_derive_mk(sm->identity, identity_len, data->ik,
931 				  data->ck, data->mk);
932 		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
933 				    data->msk, data->emsk);
934 	}
935 
936 	eap_aka_state(data, CHALLENGE);
937 }
938 
939 
eap_aka_process_identity(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)940 static void eap_aka_process_identity(struct eap_sm *sm,
941 				     struct eap_aka_data *data,
942 				     struct wpabuf *respData,
943 				     struct eap_sim_attrs *attr)
944 {
945 	u8 *new_identity;
946 
947 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
948 
949 	if (attr->mac || attr->iv || attr->encr_data) {
950 		wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
951 			   "received in EAP-Response/AKA-Identity");
952 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
953 		eap_aka_state(data, NOTIFICATION);
954 		return;
955 	}
956 
957 	/*
958 	 * We always request identity with AKA/Identity, so the peer is
959 	 * required to have replied with one.
960 	 */
961 	if (!attr->identity || attr->identity_len == 0) {
962 		wpa_printf(MSG_DEBUG, "EAP-AKA: Peer did not provide any "
963 			   "identity");
964 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
965 		eap_aka_state(data, NOTIFICATION);
966 		return;
967 	}
968 
969 	new_identity = os_malloc(attr->identity_len);
970 	if (new_identity == NULL) {
971 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
972 		eap_aka_state(data, NOTIFICATION);
973 		return;
974 	}
975 	os_free(sm->identity);
976 	sm->identity = new_identity;
977 	os_memcpy(sm->identity, attr->identity, attr->identity_len);
978 	sm->identity_len = attr->identity_len;
979 
980 	eap_aka_determine_identity(sm, data);
981 	if (eap_get_id(respData) == data->pending_id) {
982 		data->pending_id = -1;
983 		eap_aka_add_id_msg(data, respData);
984 	}
985 }
986 
987 
eap_aka_verify_mac(struct eap_aka_data * data,const struct wpabuf * req,const u8 * mac,const u8 * extra,size_t extra_len)988 static int eap_aka_verify_mac(struct eap_aka_data *data,
989 			      const struct wpabuf *req,
990 			      const u8 *mac, const u8 *extra,
991 			      size_t extra_len)
992 {
993 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
994 		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
995 						 extra_len);
996 	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
997 }
998 
999 
eap_aka_process_challenge(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)1000 static void eap_aka_process_challenge(struct eap_sm *sm,
1001 				      struct eap_aka_data *data,
1002 				      struct wpabuf *respData,
1003 				      struct eap_sim_attrs *attr)
1004 {
1005 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
1006 
1007 #ifdef EAP_SERVER_AKA_PRIME
1008 #if 0
1009 	/* KDF negotiation; to be enabled only after more than one KDF is
1010 	 * supported */
1011 	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
1012 	    attr->kdf_count == 1 && attr->mac == NULL) {
1013 		if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
1014 			wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
1015 				   "unknown KDF");
1016 			data->notification =
1017 				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1018 			eap_aka_state(data, NOTIFICATION);
1019 			return;
1020 		}
1021 
1022 		data->kdf = attr->kdf[0];
1023 
1024 		/* Allow negotiation to continue with the selected KDF by
1025 		 * sending another Challenge message */
1026 		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
1027 		return;
1028 	}
1029 #endif
1030 #endif /* EAP_SERVER_AKA_PRIME */
1031 
1032 	if (attr->checkcode &&
1033 	    eap_aka_verify_checkcode(data, attr->checkcode,
1034 				     attr->checkcode_len)) {
1035 		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
1036 			   "message");
1037 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1038 		eap_aka_state(data, NOTIFICATION);
1039 		return;
1040 	}
1041 	if (attr->mac == NULL ||
1042 	    eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
1043 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
1044 			   "did not include valid AT_MAC");
1045 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1046 		eap_aka_state(data, NOTIFICATION);
1047 		return;
1048 	}
1049 
1050 	/*
1051 	 * AT_RES is padded, so verify that there is enough room for RES and
1052 	 * that the RES length in bits matches with the expected RES.
1053 	 */
1054 	if (attr->res == NULL || attr->res_len < data->res_len ||
1055 	    attr->res_len_bits != data->res_len * 8 ||
1056 	    os_memcmp_const(attr->res, data->res, data->res_len) != 0) {
1057 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
1058 			   "include valid AT_RES (attr len=%lu, res len=%lu "
1059 			   "bits, expected %lu bits)",
1060 			   (unsigned long) attr->res_len,
1061 			   (unsigned long) attr->res_len_bits,
1062 			   (unsigned long) data->res_len * 8);
1063 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1064 		eap_aka_state(data, NOTIFICATION);
1065 		return;
1066 	}
1067 
1068 	wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
1069 		   "correct AT_MAC");
1070 	if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
1071 		data->use_result_ind = 1;
1072 		data->notification = EAP_SIM_SUCCESS;
1073 		eap_aka_state(data, NOTIFICATION);
1074 	} else
1075 		eap_aka_state(data, SUCCESS);
1076 
1077 	if (data->next_pseudonym) {
1078 		eap_sim_db_add_pseudonym(sm->cfg->eap_sim_db_priv,
1079 					 data->permanent,
1080 					 data->next_pseudonym);
1081 		data->next_pseudonym = NULL;
1082 	}
1083 	if (data->next_reauth_id) {
1084 		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
1085 #ifdef EAP_SERVER_AKA_PRIME
1086 			eap_sim_db_add_reauth_prime(sm->cfg->eap_sim_db_priv,
1087 						    data->permanent,
1088 						    data->next_reauth_id,
1089 						    data->counter + 1,
1090 						    data->k_encr, data->k_aut,
1091 						    data->k_re);
1092 #endif /* EAP_SERVER_AKA_PRIME */
1093 		} else {
1094 			eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv,
1095 					      data->permanent,
1096 					      data->next_reauth_id,
1097 					      data->counter + 1,
1098 					      data->mk);
1099 		}
1100 		data->next_reauth_id = NULL;
1101 	}
1102 }
1103 
1104 
eap_aka_process_sync_failure(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)1105 static void eap_aka_process_sync_failure(struct eap_sm *sm,
1106 					 struct eap_aka_data *data,
1107 					 struct wpabuf *respData,
1108 					 struct eap_sim_attrs *attr)
1109 {
1110 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
1111 
1112 	if (attr->auts == NULL) {
1113 		wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
1114 			   "message did not include valid AT_AUTS");
1115 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1116 		eap_aka_state(data, NOTIFICATION);
1117 		return;
1118 	}
1119 
1120 	/* Avoid re-reporting AUTS when processing pending EAP packet by
1121 	 * maintaining a local flag stating whether this AUTS has already been
1122 	 * reported. */
1123 	if (!data->auts_reported &&
1124 	    eap_sim_db_resynchronize(sm->cfg->eap_sim_db_priv, data->permanent,
1125 				     attr->auts, data->rand)) {
1126 		wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
1127 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1128 		eap_aka_state(data, NOTIFICATION);
1129 		return;
1130 	}
1131 	data->auts_reported = 1;
1132 
1133 	/* Remain in CHALLENGE state to re-try after resynchronization */
1134 	eap_aka_fullauth(sm, data);
1135 }
1136 
1137 
eap_aka_process_reauth(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)1138 static void eap_aka_process_reauth(struct eap_sm *sm,
1139 				   struct eap_aka_data *data,
1140 				   struct wpabuf *respData,
1141 				   struct eap_sim_attrs *attr)
1142 {
1143 	struct eap_sim_attrs eattr;
1144 	u8 *decrypted = NULL;
1145 
1146 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
1147 
1148 	if (attr->mac == NULL ||
1149 	    eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
1150 			       EAP_SIM_NONCE_S_LEN)) {
1151 		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
1152 			   "did not include valid AT_MAC");
1153 		goto fail;
1154 	}
1155 
1156 	if (attr->encr_data == NULL || attr->iv == NULL) {
1157 		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
1158 			   "message did not include encrypted data");
1159 		goto fail;
1160 	}
1161 
1162 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
1163 				       attr->encr_data_len, attr->iv, &eattr,
1164 				       0);
1165 	if (decrypted == NULL) {
1166 		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
1167 			   "data from reauthentication message");
1168 		goto fail;
1169 	}
1170 
1171 	if (eattr.counter != data->counter) {
1172 		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
1173 			   "used incorrect counter %u, expected %u",
1174 			   eattr.counter, data->counter);
1175 		goto fail;
1176 	}
1177 	os_free(decrypted);
1178 	decrypted = NULL;
1179 
1180 	wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
1181 		   "the correct AT_MAC");
1182 
1183 	if (eattr.counter_too_small) {
1184 		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
1185 			   "included AT_COUNTER_TOO_SMALL - starting full "
1186 			   "authentication");
1187 		eap_aka_fullauth(sm, data);
1188 		return;
1189 	}
1190 
1191 	if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
1192 		data->use_result_ind = 1;
1193 		data->notification = EAP_SIM_SUCCESS;
1194 		eap_aka_state(data, NOTIFICATION);
1195 	} else
1196 		eap_aka_state(data, SUCCESS);
1197 
1198 	if (data->next_reauth_id) {
1199 		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
1200 #ifdef EAP_SERVER_AKA_PRIME
1201 			eap_sim_db_add_reauth_prime(sm->cfg->eap_sim_db_priv,
1202 						    data->permanent,
1203 						    data->next_reauth_id,
1204 						    data->counter + 1,
1205 						    data->k_encr, data->k_aut,
1206 						    data->k_re);
1207 #endif /* EAP_SERVER_AKA_PRIME */
1208 		} else {
1209 			eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv,
1210 					      data->permanent,
1211 					      data->next_reauth_id,
1212 					      data->counter + 1,
1213 					      data->mk);
1214 		}
1215 		data->next_reauth_id = NULL;
1216 	} else {
1217 		eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv,
1218 					 data->reauth);
1219 		data->reauth = NULL;
1220 	}
1221 
1222 	return;
1223 
1224 fail:
1225 	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1226 	eap_aka_state(data, NOTIFICATION);
1227 	eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, data->reauth);
1228 	data->reauth = NULL;
1229 	os_free(decrypted);
1230 }
1231 
1232 
eap_aka_process_client_error(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)1233 static void eap_aka_process_client_error(struct eap_sm *sm,
1234 					 struct eap_aka_data *data,
1235 					 struct wpabuf *respData,
1236 					 struct eap_sim_attrs *attr)
1237 {
1238 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
1239 		   attr->client_error_code);
1240 	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
1241 		eap_aka_state(data, SUCCESS);
1242 	else
1243 		eap_aka_state(data, FAILURE);
1244 }
1245 
1246 
eap_aka_process_authentication_reject(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)1247 static void eap_aka_process_authentication_reject(
1248 	struct eap_sm *sm, struct eap_aka_data *data,
1249 	struct wpabuf *respData, struct eap_sim_attrs *attr)
1250 {
1251 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
1252 	eap_aka_state(data, FAILURE);
1253 }
1254 
1255 
eap_aka_process_notification(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)1256 static void eap_aka_process_notification(struct eap_sm *sm,
1257 					 struct eap_aka_data *data,
1258 					 struct wpabuf *respData,
1259 					 struct eap_sim_attrs *attr)
1260 {
1261 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
1262 	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
1263 		eap_aka_state(data, SUCCESS);
1264 	else
1265 		eap_aka_state(data, FAILURE);
1266 }
1267 
1268 
eap_aka_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)1269 static void eap_aka_process(struct eap_sm *sm, void *priv,
1270 			    struct wpabuf *respData)
1271 {
1272 	struct eap_aka_data *data = priv;
1273 	const u8 *pos, *end;
1274 	u8 subtype;
1275 	size_t len;
1276 	struct eap_sim_attrs attr;
1277 
1278 	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
1279 			       &len);
1280 	if (pos == NULL || len < 3)
1281 		return;
1282 
1283 	end = pos + len;
1284 	subtype = *pos;
1285 	pos += 3;
1286 
1287 	if (eap_aka_subtype_ok(data, subtype)) {
1288 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
1289 			   "EAP-AKA Subtype in EAP Response");
1290 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1291 		eap_aka_state(data, NOTIFICATION);
1292 		return;
1293 	}
1294 
1295 	if (eap_sim_parse_attr(pos, end, &attr,
1296 			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
1297 			       0)) {
1298 		wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
1299 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1300 		eap_aka_state(data, NOTIFICATION);
1301 		return;
1302 	}
1303 
1304 	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
1305 		eap_aka_process_client_error(sm, data, respData, &attr);
1306 		return;
1307 	}
1308 
1309 	if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
1310 		eap_aka_process_authentication_reject(sm, data, respData,
1311 						      &attr);
1312 		return;
1313 	}
1314 
1315 	switch (data->state) {
1316 	case IDENTITY:
1317 		eap_aka_process_identity(sm, data, respData, &attr);
1318 		break;
1319 	case CHALLENGE:
1320 		if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
1321 			eap_aka_process_sync_failure(sm, data, respData,
1322 						     &attr);
1323 		} else {
1324 			eap_aka_process_challenge(sm, data, respData, &attr);
1325 		}
1326 		break;
1327 	case REAUTH:
1328 		eap_aka_process_reauth(sm, data, respData, &attr);
1329 		break;
1330 	case NOTIFICATION:
1331 		eap_aka_process_notification(sm, data, respData, &attr);
1332 		break;
1333 	default:
1334 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
1335 			   "process", data->state);
1336 		break;
1337 	}
1338 }
1339 
1340 
eap_aka_isDone(struct eap_sm * sm,void * priv)1341 static bool eap_aka_isDone(struct eap_sm *sm, void *priv)
1342 {
1343 	struct eap_aka_data *data = priv;
1344 	return data->state == SUCCESS || data->state == FAILURE;
1345 }
1346 
1347 
eap_aka_getKey(struct eap_sm * sm,void * priv,size_t * len)1348 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
1349 {
1350 	struct eap_aka_data *data = priv;
1351 	u8 *key;
1352 
1353 	if (data->state != SUCCESS)
1354 		return NULL;
1355 
1356 	key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
1357 	if (key == NULL)
1358 		return NULL;
1359 	*len = EAP_SIM_KEYING_DATA_LEN;
1360 	return key;
1361 }
1362 
1363 
eap_aka_get_emsk(struct eap_sm * sm,void * priv,size_t * len)1364 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1365 {
1366 	struct eap_aka_data *data = priv;
1367 	u8 *key;
1368 
1369 	if (data->state != SUCCESS)
1370 		return NULL;
1371 
1372 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
1373 	if (key == NULL)
1374 		return NULL;
1375 	*len = EAP_EMSK_LEN;
1376 	return key;
1377 }
1378 
1379 
eap_aka_isSuccess(struct eap_sm * sm,void * priv)1380 static bool eap_aka_isSuccess(struct eap_sm *sm, void *priv)
1381 {
1382 	struct eap_aka_data *data = priv;
1383 	return data->state == SUCCESS;
1384 }
1385 
1386 
eap_aka_get_session_id(struct eap_sm * sm,void * priv,size_t * len)1387 static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
1388 {
1389 	struct eap_aka_data *data = priv;
1390 	u8 *id;
1391 
1392 	if (data->state != SUCCESS)
1393 		return NULL;
1394 
1395 	if (!data->reauth)
1396 		*len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
1397 	else
1398 		*len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
1399 	id = os_malloc(*len);
1400 	if (id == NULL)
1401 		return NULL;
1402 
1403 	id[0] = data->eap_method;
1404 	if (!data->reauth) {
1405 		os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
1406 		os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn,
1407 			  EAP_AKA_AUTN_LEN);
1408 	} else {
1409 		os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
1410 		os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
1411 			  EAP_SIM_MAC_LEN);
1412 	}
1413 	wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
1414 
1415 	return id;
1416 }
1417 
1418 
eap_server_aka_register(void)1419 int eap_server_aka_register(void)
1420 {
1421 	struct eap_method *eap;
1422 
1423 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1424 				      EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
1425 	if (eap == NULL)
1426 		return -1;
1427 
1428 	eap->init = eap_aka_init;
1429 	eap->reset = eap_aka_reset;
1430 	eap->buildReq = eap_aka_buildReq;
1431 	eap->check = eap_aka_check;
1432 	eap->process = eap_aka_process;
1433 	eap->isDone = eap_aka_isDone;
1434 	eap->getKey = eap_aka_getKey;
1435 	eap->isSuccess = eap_aka_isSuccess;
1436 	eap->get_emsk = eap_aka_get_emsk;
1437 	eap->getSessionId = eap_aka_get_session_id;
1438 
1439 	return eap_server_method_register(eap);
1440 }
1441 
1442 
1443 #ifdef EAP_SERVER_AKA_PRIME
eap_server_aka_prime_register(void)1444 int eap_server_aka_prime_register(void)
1445 {
1446 	struct eap_method *eap;
1447 
1448 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1449 				      EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
1450 				      "AKA'");
1451 	if (eap == NULL)
1452 		return -1;
1453 
1454 	eap->init = eap_aka_prime_init;
1455 	eap->reset = eap_aka_reset;
1456 	eap->buildReq = eap_aka_buildReq;
1457 	eap->check = eap_aka_check;
1458 	eap->process = eap_aka_process;
1459 	eap->isDone = eap_aka_isDone;
1460 	eap->getKey = eap_aka_getKey;
1461 	eap->isSuccess = eap_aka_isSuccess;
1462 	eap->get_emsk = eap_aka_get_emsk;
1463 	eap->getSessionId = eap_aka_get_session_id;
1464 
1465 	return eap_server_method_register(eap);
1466 }
1467 #endif /* EAP_SERVER_AKA_PRIME */
1468