• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * EAP peer: EAP-SIM/AKA shared routines
3  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14 
15 #include "includes.h"
16 
17 #include "common.h"
18 #include "eap_i.h"
19 #include "sha1.h"
20 #include "crypto.h"
21 #include "aes_wrap.h"
22 #include "eap_sim_common.h"
23 
24 
eap_sim_prf(const u8 * key,u8 * x,size_t xlen)25 static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
26 {
27 	return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
28 }
29 
30 
eap_sim_derive_mk(const u8 * identity,size_t identity_len,const u8 * nonce_mt,u16 selected_version,const u8 * ver_list,size_t ver_list_len,int num_chal,const u8 * kc,u8 * mk)31 void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
32 		       const u8 *nonce_mt, u16 selected_version,
33 		       const u8 *ver_list, size_t ver_list_len,
34 		       int num_chal, const u8 *kc, u8 *mk)
35 {
36 	u8 sel_ver[2];
37 	const unsigned char *addr[5];
38 	size_t len[5];
39 
40 	addr[0] = identity;
41 	len[0] = identity_len;
42 	addr[1] = kc;
43 	len[1] = num_chal * EAP_SIM_KC_LEN;
44 	addr[2] = nonce_mt;
45 	len[2] = EAP_SIM_NONCE_MT_LEN;
46 	addr[3] = ver_list;
47 	len[3] = ver_list_len;
48 	addr[4] = sel_ver;
49 	len[4] = 2;
50 
51 	WPA_PUT_BE16(sel_ver, selected_version);
52 
53 	/* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
54 	sha1_vector(5, addr, len, mk);
55 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
56 }
57 
58 
eap_aka_derive_mk(const u8 * identity,size_t identity_len,const u8 * ik,const u8 * ck,u8 * mk)59 void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
60 		       const u8 *ik, const u8 *ck, u8 *mk)
61 {
62 	const u8 *addr[3];
63 	size_t len[3];
64 
65 	addr[0] = identity;
66 	len[0] = identity_len;
67 	addr[1] = ik;
68 	len[1] = EAP_AKA_IK_LEN;
69 	addr[2] = ck;
70 	len[2] = EAP_AKA_CK_LEN;
71 
72 	/* MK = SHA1(Identity|IK|CK) */
73 	sha1_vector(3, addr, len, mk);
74 	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
75 	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
76 	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
77 }
78 
79 
eap_sim_derive_keys(const u8 * mk,u8 * k_encr,u8 * k_aut,u8 * msk,u8 * emsk)80 int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk)
81 {
82 	u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN +
83 	       EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos;
84 	if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) {
85 		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
86 		return -1;
87 	}
88 	pos = buf;
89 	os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
90 	pos += EAP_SIM_K_ENCR_LEN;
91 	os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
92 	pos += EAP_SIM_K_AUT_LEN;
93 	os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
94 	pos += EAP_SIM_KEYING_DATA_LEN;
95 	os_memcpy(emsk, pos, EAP_EMSK_LEN);
96 
97 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
98 			k_encr, EAP_SIM_K_ENCR_LEN);
99 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
100 			k_aut, EAP_SIM_K_AUT_LEN);
101 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
102 			msk, EAP_SIM_KEYING_DATA_LEN);
103 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
104 	os_memset(buf, 0, sizeof(buf));
105 
106 	return 0;
107 }
108 
109 
eap_sim_derive_keys_reauth(u16 _counter,const u8 * identity,size_t identity_len,const u8 * nonce_s,const u8 * mk,u8 * msk,u8 * emsk)110 int eap_sim_derive_keys_reauth(u16 _counter,
111 			       const u8 *identity, size_t identity_len,
112 			       const u8 *nonce_s, const u8 *mk, u8 *msk,
113 			       u8 *emsk)
114 {
115 	u8 xkey[SHA1_MAC_LEN];
116 	u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32];
117 	u8 counter[2];
118 	const u8 *addr[4];
119 	size_t len[4];
120 
121 	while (identity_len > 0 && identity[identity_len - 1] == 0) {
122 		wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop null "
123 			   "character from the end of identity");
124 		identity_len--;
125 	}
126 	addr[0] = identity;
127 	len[0] = identity_len;
128 	addr[1] = counter;
129 	len[1] = 2;
130 	addr[2] = nonce_s;
131 	len[2] = EAP_SIM_NONCE_S_LEN;
132 	addr[3] = mk;
133 	len[3] = EAP_SIM_MK_LEN;
134 
135 	WPA_PUT_BE16(counter, _counter);
136 
137 	wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
138 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
139 			  identity, identity_len);
140 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
141 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
142 		    EAP_SIM_NONCE_S_LEN);
143 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
144 
145 	/* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
146 	sha1_vector(4, addr, len, xkey);
147 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
148 
149 	if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) {
150 		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
151 		return -1;
152 	}
153 	if (msk) {
154 		os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
155 		wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
156 			    msk, EAP_SIM_KEYING_DATA_LEN);
157 	}
158 	if (emsk) {
159 		os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
160 		wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
161 	}
162 	os_memset(buf, 0, sizeof(buf));
163 
164 	return 0;
165 }
166 
167 
eap_sim_verify_mac(const u8 * k_aut,const u8 * req,size_t req_len,const u8 * mac,const u8 * extra,size_t extra_len)168 int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
169 		       const u8 *mac, const u8 *extra, size_t extra_len)
170 {
171 	unsigned char hmac[SHA1_MAC_LEN];
172 	const u8 *addr[2];
173 	size_t len[2];
174 	u8 *tmp;
175 
176 	if (mac == NULL || req_len < EAP_SIM_MAC_LEN || mac < req ||
177 	    mac > req + req_len - EAP_SIM_MAC_LEN)
178 		return -1;
179 
180 	tmp = os_malloc(req_len);
181 	if (tmp == NULL)
182 		return -1;
183 
184 	addr[0] = tmp;
185 	len[0] = req_len;
186 	addr[1] = extra;
187 	len[1] = extra_len;
188 
189 	/* HMAC-SHA1-128 */
190 	os_memcpy(tmp, req, req_len);
191 	os_memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
192 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg", tmp, req_len);
193 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
194 		    extra, extra_len);
195 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
196 			k_aut, EAP_SIM_K_AUT_LEN);
197 	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
198 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
199 		    hmac, EAP_SIM_MAC_LEN);
200 	os_free(tmp);
201 
202 	return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
203 }
204 
205 
eap_sim_add_mac(const u8 * k_aut,u8 * msg,size_t msg_len,u8 * mac,const u8 * extra,size_t extra_len)206 void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
207 		     const u8 *extra, size_t extra_len)
208 {
209 	unsigned char hmac[SHA1_MAC_LEN];
210 	const u8 *addr[2];
211 	size_t len[2];
212 
213 	addr[0] = msg;
214 	len[0] = msg_len;
215 	addr[1] = extra;
216 	len[1] = extra_len;
217 
218 	/* HMAC-SHA1-128 */
219 	os_memset(mac, 0, EAP_SIM_MAC_LEN);
220 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
221 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
222 		    extra, extra_len);
223 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
224 			k_aut, EAP_SIM_K_AUT_LEN);
225 	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
226 	os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
227 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
228 		    mac, EAP_SIM_MAC_LEN);
229 }
230 
231 
eap_sim_parse_attr(const u8 * start,const u8 * end,struct eap_sim_attrs * attr,int aka,int encr)232 int eap_sim_parse_attr(const u8 *start, const u8 *end,
233 		       struct eap_sim_attrs *attr, int aka, int encr)
234 {
235 	const u8 *pos = start, *apos;
236 	size_t alen, plen, i, list_len;
237 
238 	os_memset(attr, 0, sizeof(*attr));
239 	attr->id_req = NO_ID_REQ;
240 	attr->notification = -1;
241 	attr->counter = -1;
242 	attr->selected_version = -1;
243 	attr->client_error_code = -1;
244 
245 	while (pos < end) {
246 		if (pos + 2 > end) {
247 			wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
248 			return -1;
249 		}
250 		wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
251 			   pos[0], pos[1] * 4);
252 		if (pos + pos[1] * 4 > end) {
253 			wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
254 				   "(pos=%p len=%d end=%p)",
255 				   pos, pos[1] * 4, end);
256 			return -1;
257 		}
258 		if (pos[1] == 0) {
259 			wpa_printf(MSG_INFO, "EAP-SIM: Attribute underflow");
260 			return -1;
261 		}
262 		apos = pos + 2;
263 		alen = pos[1] * 4 - 2;
264 		wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
265 			    apos, alen);
266 
267 		switch (pos[0]) {
268 		case EAP_SIM_AT_RAND:
269 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
270 			apos += 2;
271 			alen -= 2;
272 			if ((!aka && (alen % GSM_RAND_LEN)) ||
273 			    (aka && alen != EAP_AKA_RAND_LEN)) {
274 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
275 					   " (len %lu)",
276 					   (unsigned long) alen);
277 				return -1;
278 			}
279 			attr->rand = apos;
280 			attr->num_chal = alen / GSM_RAND_LEN;
281 			break;
282 		case EAP_SIM_AT_AUTN:
283 			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
284 			if (!aka) {
285 				wpa_printf(MSG_DEBUG, "EAP-SIM: "
286 					   "Unexpected AT_AUTN");
287 				return -1;
288 			}
289 			apos += 2;
290 			alen -= 2;
291 			if (alen != EAP_AKA_AUTN_LEN) {
292 				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
293 					   " (len %lu)",
294 					   (unsigned long) alen);
295 				return -1;
296 			}
297 			attr->autn = apos;
298 			break;
299 		case EAP_SIM_AT_PADDING:
300 			if (!encr) {
301 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
302 					   "AT_PADDING");
303 				return -1;
304 			}
305 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
306 			for (i = 2; i < alen; i++) {
307 				if (apos[i] != 0) {
308 					wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
309 						   "AT_PADDING used a non-zero"
310 						   " padding byte");
311 					wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
312 						    "(encr) padding bytes",
313 						    apos + 2, alen - 2);
314 					return -1;
315 				}
316 			}
317 			break;
318 		case EAP_SIM_AT_NONCE_MT:
319 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
320 			if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
321 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
322 					   "AT_NONCE_MT length");
323 				return -1;
324 			}
325 			attr->nonce_mt = apos + 2;
326 			break;
327 		case EAP_SIM_AT_PERMANENT_ID_REQ:
328 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
329 			attr->id_req = PERMANENT_ID;
330 			break;
331 		case EAP_SIM_AT_MAC:
332 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
333 			if (alen != 2 + EAP_SIM_MAC_LEN) {
334 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
335 					   "length");
336 				return -1;
337 			}
338 			attr->mac = apos + 2;
339 			break;
340 		case EAP_SIM_AT_NOTIFICATION:
341 			if (alen != 2) {
342 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
343 					   "AT_NOTIFICATION length %lu",
344 					   (unsigned long) alen);
345 				return -1;
346 			}
347 			attr->notification = apos[0] * 256 + apos[1];
348 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
349 				   attr->notification);
350 			break;
351 		case EAP_SIM_AT_ANY_ID_REQ:
352 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
353 			attr->id_req = ANY_ID;
354 			break;
355 		case EAP_SIM_AT_IDENTITY:
356 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
357 			attr->identity = apos + 2;
358 			attr->identity_len = alen - 2;
359 			break;
360 		case EAP_SIM_AT_VERSION_LIST:
361 			if (aka) {
362 				wpa_printf(MSG_DEBUG, "EAP-AKA: "
363 					   "Unexpected AT_VERSION_LIST");
364 				return -1;
365 			}
366 			list_len = apos[0] * 256 + apos[1];
367 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
368 			if (list_len < 2 || list_len > alen - 2) {
369 				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
370 					   "AT_VERSION_LIST (list_len=%lu "
371 					   "attr_len=%lu)",
372 					   (unsigned long) list_len,
373 					   (unsigned long) alen);
374 				return -1;
375 			}
376 			attr->version_list = apos + 2;
377 			attr->version_list_len = list_len;
378 			break;
379 		case EAP_SIM_AT_SELECTED_VERSION:
380 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
381 			if (alen != 2) {
382 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
383 					   "AT_SELECTED_VERSION length %lu",
384 					   (unsigned long) alen);
385 				return -1;
386 			}
387 			attr->selected_version = apos[0] * 256 + apos[1];
388 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
389 				   "%d", attr->selected_version);
390 			break;
391 		case EAP_SIM_AT_FULLAUTH_ID_REQ:
392 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
393 			attr->id_req = FULLAUTH_ID;
394 			break;
395 		case EAP_SIM_AT_COUNTER:
396 			if (!encr) {
397 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
398 					   "AT_COUNTER");
399 				return -1;
400 			}
401 			if (alen != 2) {
402 				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
403 					   "AT_COUNTER (alen=%lu)",
404 					   (unsigned long) alen);
405 				return -1;
406 			}
407 			attr->counter = apos[0] * 256 + apos[1];
408 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
409 				   attr->counter);
410 			break;
411 		case EAP_SIM_AT_COUNTER_TOO_SMALL:
412 			if (!encr) {
413 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
414 					   "AT_COUNTER_TOO_SMALL");
415 				return -1;
416 			}
417 			if (alen != 2) {
418 				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
419 					   "AT_COUNTER_TOO_SMALL (alen=%lu)",
420 					   (unsigned long) alen);
421 				return -1;
422 			}
423 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
424 				   "AT_COUNTER_TOO_SMALL");
425 			attr->counter_too_small = 1;
426 			break;
427 		case EAP_SIM_AT_NONCE_S:
428 			if (!encr) {
429 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
430 					   "AT_NONCE_S");
431 				return -1;
432 			}
433 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
434 				   "AT_NONCE_S");
435 			if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
436 				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
437 					   "AT_NONCE_S (alen=%lu)",
438 					   (unsigned long) alen);
439 				return -1;
440 			}
441 			attr->nonce_s = apos + 2;
442 			break;
443 		case EAP_SIM_AT_CLIENT_ERROR_CODE:
444 			if (alen != 2) {
445 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
446 					   "AT_CLIENT_ERROR_CODE length %lu",
447 					   (unsigned long) alen);
448 				return -1;
449 			}
450 			attr->client_error_code = apos[0] * 256 + apos[1];
451 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
452 				   "%d", attr->client_error_code);
453 			break;
454 		case EAP_SIM_AT_IV:
455 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
456 			if (alen != 2 + EAP_SIM_MAC_LEN) {
457 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
458 					   "length %lu", (unsigned long) alen);
459 				return -1;
460 			}
461 			attr->iv = apos + 2;
462 			break;
463 		case EAP_SIM_AT_ENCR_DATA:
464 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
465 			attr->encr_data = apos + 2;
466 			attr->encr_data_len = alen - 2;
467 			if (attr->encr_data_len % 16) {
468 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
469 					   "AT_ENCR_DATA length %lu",
470 					   (unsigned long)
471 					   attr->encr_data_len);
472 				return -1;
473 			}
474 			break;
475 		case EAP_SIM_AT_NEXT_PSEUDONYM:
476 			if (!encr) {
477 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
478 					   "AT_NEXT_PSEUDONYM");
479 				return -1;
480 			}
481 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
482 				   "AT_NEXT_PSEUDONYM");
483 			plen = apos[0] * 256 + apos[1];
484 			if (plen > alen - 2) {
485 				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
486 					   " AT_NEXT_PSEUDONYM (actual"
487 					   " len %lu, attr len %lu)",
488 					   (unsigned long) plen,
489 					   (unsigned long) alen);
490 				return -1;
491 			}
492 			attr->next_pseudonym = pos + 4;
493 			attr->next_pseudonym_len = plen;
494 			break;
495 		case EAP_SIM_AT_NEXT_REAUTH_ID:
496 			if (!encr) {
497 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
498 					   "AT_NEXT_REAUTH_ID");
499 				return -1;
500 			}
501 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
502 				   "AT_NEXT_REAUTH_ID");
503 			plen = apos[0] * 256 + apos[1];
504 			if (plen > alen - 2) {
505 				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
506 					   " AT_NEXT_REAUTH_ID (actual"
507 					   " len %lu, attr len %lu)",
508 					   (unsigned long) plen,
509 					   (unsigned long) alen);
510 				return -1;
511 			}
512 			attr->next_reauth_id = pos + 4;
513 			attr->next_reauth_id_len = plen;
514 			break;
515 		case EAP_SIM_AT_RES:
516 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
517 			apos += 2;
518 			alen -= 2;
519 			if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
520 			    alen > EAP_AKA_MAX_RES_LEN) {
521 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
522 					   "(len %lu)",
523 					   (unsigned long) alen);
524 				return -1;
525 			}
526 			attr->res = apos;
527 			attr->res_len = alen;
528 			break;
529 		case EAP_SIM_AT_AUTS:
530 			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
531 			if (!aka) {
532 				wpa_printf(MSG_DEBUG, "EAP-SIM: "
533 					   "Unexpected AT_AUTS");
534 				return -1;
535 			}
536 			if (alen != EAP_AKA_AUTS_LEN) {
537 				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
538 					   " (len %lu)",
539 					   (unsigned long) alen);
540 				return -1;
541 			}
542 			attr->auts = apos;
543 			break;
544 		default:
545 			if (pos[0] < 128) {
546 				wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
547 					   "non-skippable attribute %d",
548 					   pos[0]);
549 				return -1;
550 			}
551 
552 			wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
553 				   " attribute %d ignored", pos[0]);
554 			break;
555 		}
556 
557 		pos += pos[1] * 4;
558 	}
559 
560 	wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
561 		   "(aka=%d encr=%d)", aka, encr);
562 
563 	return 0;
564 }
565 
566 
eap_sim_parse_encr(const u8 * k_encr,const u8 * encr_data,size_t encr_data_len,const u8 * iv,struct eap_sim_attrs * attr,int aka)567 u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
568 			size_t encr_data_len, const u8 *iv,
569 			struct eap_sim_attrs *attr, int aka)
570 {
571 	u8 *decrypted;
572 
573 	if (!iv) {
574 		wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
575 		return NULL;
576 	}
577 
578 	decrypted = os_malloc(encr_data_len);
579 	if (decrypted == NULL)
580 		return NULL;
581 	os_memcpy(decrypted, encr_data, encr_data_len);
582 
583 	aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len);
584 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
585 		    decrypted, encr_data_len);
586 
587 	if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
588 			       aka, 1)) {
589 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
590 			   "decrypted AT_ENCR_DATA");
591 		os_free(decrypted);
592 		return NULL;
593 	}
594 
595 	return decrypted;
596 }
597 
598 
599 #define EAP_SIM_INIT_LEN 128
600 
601 struct eap_sim_msg {
602 	u8 *buf;
603 	size_t buf_len, used;
604 	size_t mac, iv, encr; /* index from buf */
605 };
606 
607 
eap_sim_msg_init(int code,int id,int type,int subtype)608 struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
609 {
610 	struct eap_sim_msg *msg;
611 	struct eap_hdr *eap;
612 	u8 *pos;
613 
614 	msg = os_zalloc(sizeof(*msg));
615 	if (msg == NULL)
616 		return NULL;
617 
618 	msg->buf = os_zalloc(EAP_SIM_INIT_LEN);
619 	if (msg->buf == NULL) {
620 		os_free(msg);
621 		return NULL;
622 	}
623 	msg->buf_len = EAP_SIM_INIT_LEN;
624 	eap = (struct eap_hdr *) msg->buf;
625 	eap->code = code;
626 	eap->identifier = id;
627 	msg->used = sizeof(*eap);
628 
629 	pos = (u8 *) (eap + 1);
630 	*pos++ = type;
631 	*pos++ = subtype;
632 	*pos++ = 0; /* Reserved */
633 	*pos++ = 0; /* Reserved */
634 	msg->used += 4;
635 
636 	return msg;
637 }
638 
639 
eap_sim_msg_finish(struct eap_sim_msg * msg,size_t * len,const u8 * k_aut,const u8 * extra,size_t extra_len)640 u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
641 			const u8 *extra, size_t extra_len)
642 {
643 	struct eap_hdr *eap;
644 	u8 *buf;
645 
646 	if (msg == NULL)
647 		return NULL;
648 
649 	eap = (struct eap_hdr *) msg->buf;
650 	eap->length = host_to_be16(msg->used);
651 
652 	if (k_aut && msg->mac) {
653 		eap_sim_add_mac(k_aut, msg->buf, msg->used,
654 				msg->buf + msg->mac, extra, extra_len);
655 	}
656 
657 	*len = msg->used;
658 	buf = msg->buf;
659 	os_free(msg);
660 	return buf;
661 }
662 
663 
eap_sim_msg_free(struct eap_sim_msg * msg)664 void eap_sim_msg_free(struct eap_sim_msg *msg)
665 {
666 	if (msg) {
667 		os_free(msg->buf);
668 		os_free(msg);
669 	}
670 }
671 
672 
eap_sim_msg_resize(struct eap_sim_msg * msg,size_t add_len)673 static int eap_sim_msg_resize(struct eap_sim_msg *msg, size_t add_len)
674 {
675 	if (msg->used + add_len > msg->buf_len) {
676 		u8 *nbuf = os_realloc(msg->buf, msg->used + add_len);
677 		if (nbuf == NULL)
678 			return -1;
679 		msg->buf = nbuf;
680 		msg->buf_len = msg->used + add_len;
681 	}
682 	return 0;
683 }
684 
685 
eap_sim_msg_add_full(struct eap_sim_msg * msg,u8 attr,const u8 * data,size_t len)686 u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
687 			  const u8 *data, size_t len)
688 {
689 	int attr_len = 2 + len;
690 	int pad_len;
691 	u8 *start, *pos;
692 
693 	if (msg == NULL)
694 		return NULL;
695 
696 	pad_len = (4 - attr_len % 4) % 4;
697 	attr_len += pad_len;
698 	if (eap_sim_msg_resize(msg, attr_len))
699 		return NULL;
700 	start = pos = msg->buf + msg->used;
701 	*pos++ = attr;
702 	*pos++ = attr_len / 4;
703 	os_memcpy(pos, data, len);
704 	if (pad_len) {
705 		pos += len;
706 		os_memset(pos, 0, pad_len);
707 	}
708 	msg->used += attr_len;
709 	return start;
710 }
711 
712 
eap_sim_msg_add(struct eap_sim_msg * msg,u8 attr,u16 value,const u8 * data,size_t len)713 u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
714 		     const u8 *data, size_t len)
715 {
716 	int attr_len = 4 + len;
717 	int pad_len;
718 	u8 *start, *pos;
719 
720 	if (msg == NULL)
721 		return NULL;
722 
723 	pad_len = (4 - attr_len % 4) % 4;
724 	attr_len += pad_len;
725 	if (eap_sim_msg_resize(msg, attr_len))
726 		return NULL;
727 	start = pos = msg->buf + msg->used;
728 	*pos++ = attr;
729 	*pos++ = attr_len / 4;
730 	WPA_PUT_BE16(pos, value);
731 	pos += 2;
732 	if (data)
733 		os_memcpy(pos, data, len);
734 	if (pad_len) {
735 		pos += len;
736 		os_memset(pos, 0, pad_len);
737 	}
738 	msg->used += attr_len;
739 	return start;
740 }
741 
742 
eap_sim_msg_add_mac(struct eap_sim_msg * msg,u8 attr)743 u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
744 {
745 	u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
746 	if (pos)
747 		msg->mac = (pos - msg->buf) + 4;
748 	return pos;
749 }
750 
751 
eap_sim_msg_add_encr_start(struct eap_sim_msg * msg,u8 attr_iv,u8 attr_encr)752 int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
753 			       u8 attr_encr)
754 {
755 	u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
756 	if (pos == NULL)
757 		return -1;
758 	msg->iv = (pos - msg->buf) + 4;
759 	if (hostapd_get_rand(msg->buf + msg->iv, EAP_SIM_IV_LEN)) {
760 		msg->iv = 0;
761 		return -1;
762 	}
763 
764 	pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
765 	if (pos == NULL) {
766 		msg->iv = 0;
767 		return -1;
768 	}
769 	msg->encr = pos - msg->buf;
770 
771 	return 0;
772 }
773 
774 
eap_sim_msg_add_encr_end(struct eap_sim_msg * msg,u8 * k_encr,int attr_pad)775 int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
776 {
777 	size_t encr_len;
778 
779 	if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
780 		return -1;
781 
782 	encr_len = msg->used - msg->encr - 4;
783 	if (encr_len % 16) {
784 		u8 *pos;
785 		int pad_len = 16 - (encr_len % 16);
786 		if (pad_len < 4) {
787 			wpa_printf(MSG_WARNING, "EAP-SIM: "
788 				   "eap_sim_msg_add_encr_end - invalid pad_len"
789 				   " %d", pad_len);
790 			return -1;
791 		}
792 		wpa_printf(MSG_DEBUG, "   *AT_PADDING");
793 		pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
794 		if (pos == NULL)
795 			return -1;
796 		os_memset(pos + 4, 0, pad_len - 4);
797 		encr_len += pad_len;
798 	}
799 	wpa_printf(MSG_DEBUG, "   (AT_ENCR_DATA data len %lu)",
800 		   (unsigned long) encr_len);
801 	msg->buf[msg->encr + 1] = encr_len / 4 + 1;
802 	aes_128_cbc_encrypt(k_encr, msg->buf + msg->iv,
803 			    msg->buf + msg->encr + 4, encr_len);
804 
805 	return 0;
806 }
807 
808 
eap_sim_report_notification(void * msg_ctx,int notification,int aka)809 void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
810 {
811 #ifndef CONFIG_NO_STDOUT_DEBUG
812 	const char *type = aka ? "AKA" : "SIM";
813 #endif /* CONFIG_NO_STDOUT_DEBUG */
814 
815 	switch (notification) {
816 	case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
817 		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
818 			   "notification (after authentication)", type);
819 		break;
820 	case EAP_SIM_TEMPORARILY_DENIED:
821 		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
822 			   "User has been temporarily denied access to the "
823 			   "requested service", type);
824 		break;
825 	case EAP_SIM_NOT_SUBSCRIBED:
826 		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
827 			   "User has not subscribed to the requested service",
828 			   type);
829 		break;
830 	case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
831 		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
832 			   "notification (before authentication)", type);
833 		break;
834 	case EAP_SIM_SUCCESS:
835 		wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
836 			   "notification", type);
837 		break;
838 	default:
839 		if (notification >= 32768) {
840 			wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
841 				   "non-failure notification %d",
842 				   type, notification);
843 		} else {
844 			wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
845 				   "failure notification %d",
846 				   type, notification);
847 		}
848 	}
849 }
850