1/*
2 * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "wpabuf.h"
13#include "crypto/aes_wrap.h"
14#include "crypto/crypto.h"
15#include "crypto/sha1.h"
16#include "crypto/sha256.h"
17#include "crypto/random.h"
18#include "eap_common/eap_defs.h"
19#include "eap_common/eap_sim_common.h"
20
21
22static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
23{
24	return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
25}
26
27
28void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
29		       const u8 *nonce_mt, u16 selected_version,
30		       const u8 *ver_list, size_t ver_list_len,
31		       int num_chal, const u8 *kc, u8 *mk)
32{
33	u8 sel_ver[2];
34	const unsigned char *addr[5];
35	size_t len[5];
36
37	addr[0] = identity;
38	len[0] = identity_len;
39	addr[1] = kc;
40	len[1] = num_chal * EAP_SIM_KC_LEN;
41	addr[2] = nonce_mt;
42	len[2] = EAP_SIM_NONCE_MT_LEN;
43	addr[3] = ver_list;
44	len[3] = ver_list_len;
45	addr[4] = sel_ver;
46	len[4] = 2;
47
48	WPA_PUT_BE16(sel_ver, selected_version);
49
50	/* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
51	sha1_vector(5, addr, len, mk);
52	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
53}
54
55
56void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
57		       const u8 *ik, const u8 *ck, u8 *mk)
58{
59	const u8 *addr[3];
60	size_t len[3];
61
62	addr[0] = identity;
63	len[0] = identity_len;
64	addr[1] = ik;
65	len[1] = EAP_AKA_IK_LEN;
66	addr[2] = ck;
67	len[2] = EAP_AKA_CK_LEN;
68
69	/* MK = SHA1(Identity|IK|CK) */
70	sha1_vector(3, addr, len, mk);
71	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
72	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
73	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
74}
75
76
77int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk)
78{
79	u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN +
80	       EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos;
81	if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) {
82		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
83		return -1;
84	}
85	pos = buf;
86	os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
87	pos += EAP_SIM_K_ENCR_LEN;
88	os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
89	pos += EAP_SIM_K_AUT_LEN;
90	os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
91	pos += EAP_SIM_KEYING_DATA_LEN;
92	os_memcpy(emsk, pos, EAP_EMSK_LEN);
93
94	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
95			k_encr, EAP_SIM_K_ENCR_LEN);
96	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
97			k_aut, EAP_SIM_K_AUT_LEN);
98	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
99			msk, EAP_SIM_KEYING_DATA_LEN);
100	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
101	os_memset(buf, 0, sizeof(buf));
102
103	return 0;
104}
105
106
107int eap_sim_derive_keys_reauth(u16 _counter,
108			       const u8 *identity, size_t identity_len,
109			       const u8 *nonce_s, const u8 *mk, u8 *msk,
110			       u8 *emsk)
111{
112	u8 xkey[SHA1_MAC_LEN];
113	u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32];
114	u8 counter[2];
115	const u8 *addr[4];
116	size_t len[4];
117
118	while (identity_len > 0 && identity[identity_len - 1] == 0) {
119		wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop null "
120			   "character from the end of identity");
121		identity_len--;
122	}
123	addr[0] = identity;
124	len[0] = identity_len;
125	addr[1] = counter;
126	len[1] = 2;
127	addr[2] = nonce_s;
128	len[2] = EAP_SIM_NONCE_S_LEN;
129	addr[3] = mk;
130	len[3] = EAP_SIM_MK_LEN;
131
132	WPA_PUT_BE16(counter, _counter);
133
134	wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
135	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
136			  identity, identity_len);
137	wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
138	wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
139		    EAP_SIM_NONCE_S_LEN);
140	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
141
142	/* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
143	sha1_vector(4, addr, len, xkey);
144	wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
145
146	if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) {
147		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
148		return -1;
149	}
150	if (msk) {
151		os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
152		wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
153			    msk, EAP_SIM_KEYING_DATA_LEN);
154	}
155	if (emsk) {
156		os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
157		wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
158	}
159	os_memset(buf, 0, sizeof(buf));
160
161	return 0;
162}
163
164
165int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
166		       const u8 *mac, const u8 *extra, size_t extra_len)
167{
168	unsigned char hmac[SHA1_MAC_LEN];
169	const u8 *addr[2];
170	size_t len[2];
171	u8 *tmp;
172
173	if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
174	    mac < wpabuf_head_u8(req) ||
175	    mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
176		return -1;
177
178	tmp = os_memdup(wpabuf_head(req), wpabuf_len(req));
179	if (tmp == NULL)
180		return -1;
181
182	addr[0] = tmp;
183	len[0] = wpabuf_len(req);
184	addr[1] = extra;
185	len[1] = extra_len;
186
187	/* HMAC-SHA1-128 */
188	os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
189	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg",
190		    tmp, wpabuf_len(req));
191	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
192		    extra, extra_len);
193	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
194			k_aut, EAP_SIM_K_AUT_LEN);
195	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
196	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
197		    hmac, EAP_SIM_MAC_LEN);
198	os_free(tmp);
199
200	return (os_memcmp_const(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
201}
202
203
204void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac,
205		     const u8 *extra, size_t extra_len)
206{
207	unsigned char hmac[SHA1_MAC_LEN];
208	const u8 *addr[2];
209	size_t len[2];
210
211	addr[0] = msg;
212	len[0] = msg_len;
213	addr[1] = extra;
214	len[1] = extra_len;
215
216	/* HMAC-SHA1-128 */
217	os_memset(mac, 0, EAP_SIM_MAC_LEN);
218	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
219	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
220		    extra, extra_len);
221	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
222			k_aut, EAP_SIM_K_AUT_LEN);
223	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
224	os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
225	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
226		    mac, EAP_SIM_MAC_LEN);
227}
228
229
230#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
231static void prf_prime(const u8 *k, const char *seed1,
232		      const u8 *seed2, size_t seed2_len,
233		      const u8 *seed3, size_t seed3_len,
234		      u8 *res, size_t res_len)
235{
236	const u8 *addr[5];
237	size_t len[5];
238	u8 hash[SHA256_MAC_LEN];
239	u8 iter;
240
241	/*
242	 * PRF'(K,S) = T1 | T2 | T3 | T4 | ...
243	 * T1 = HMAC-SHA-256 (K, S | 0x01)
244	 * T2 = HMAC-SHA-256 (K, T1 | S | 0x02)
245	 * T3 = HMAC-SHA-256 (K, T2 | S | 0x03)
246	 * T4 = HMAC-SHA-256 (K, T3 | S | 0x04)
247	 * ...
248	 */
249
250	addr[0] = hash;
251	len[0] = 0;
252	addr[1] = (const u8 *) seed1;
253	len[1] = os_strlen(seed1);
254	addr[2] = seed2;
255	len[2] = seed2_len;
256	addr[3] = seed3;
257	len[3] = seed3_len;
258	addr[4] = &iter;
259	len[4] = 1;
260
261	iter = 0;
262	while (res_len) {
263		size_t hlen;
264		iter++;
265		hmac_sha256_vector(k, 32, 5, addr, len, hash);
266		len[0] = SHA256_MAC_LEN;
267		hlen = res_len > SHA256_MAC_LEN ? SHA256_MAC_LEN : res_len;
268		os_memcpy(res, hash, hlen);
269		res += hlen;
270		res_len -= hlen;
271	}
272}
273
274
275void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len,
276			       const u8 *ik, const u8 *ck, u8 *k_encr,
277			       u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk)
278{
279	u8 key[EAP_AKA_IK_LEN + EAP_AKA_CK_LEN];
280	u8 keys[EAP_SIM_K_ENCR_LEN + EAP_AKA_PRIME_K_AUT_LEN +
281		EAP_AKA_PRIME_K_RE_LEN + EAP_MSK_LEN + EAP_EMSK_LEN];
282	u8 *pos;
283
284	/*
285	 * MK = PRF'(IK'|CK',"EAP-AKA'"|Identity)
286	 * K_encr = MK[0..127]
287	 * K_aut  = MK[128..383]
288	 * K_re   = MK[384..639]
289	 * MSK    = MK[640..1151]
290	 * EMSK   = MK[1152..1663]
291	 */
292
293	os_memcpy(key, ik, EAP_AKA_IK_LEN);
294	os_memcpy(key + EAP_AKA_IK_LEN, ck, EAP_AKA_CK_LEN);
295
296	prf_prime(key, "EAP-AKA'", identity, identity_len, NULL, 0,
297		  keys, sizeof(keys));
298
299	pos = keys;
300	os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
301	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_encr",
302			k_encr, EAP_SIM_K_ENCR_LEN);
303	pos += EAP_SIM_K_ENCR_LEN;
304
305	os_memcpy(k_aut, pos, EAP_AKA_PRIME_K_AUT_LEN);
306	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_aut",
307			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
308	pos += EAP_AKA_PRIME_K_AUT_LEN;
309
310	os_memcpy(k_re, pos, EAP_AKA_PRIME_K_RE_LEN);
311	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_re",
312			k_re, EAP_AKA_PRIME_K_RE_LEN);
313	pos += EAP_AKA_PRIME_K_RE_LEN;
314
315	os_memcpy(msk, pos, EAP_MSK_LEN);
316	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
317	pos += EAP_MSK_LEN;
318
319	os_memcpy(emsk, pos, EAP_EMSK_LEN);
320	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
321}
322
323
324int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
325				     const u8 *identity, size_t identity_len,
326				     const u8 *nonce_s, u8 *msk, u8 *emsk)
327{
328	u8 seed3[2 + EAP_SIM_NONCE_S_LEN];
329	u8 keys[EAP_MSK_LEN + EAP_EMSK_LEN];
330	u8 *pos;
331
332	/*
333	 * MK = PRF'(K_re,"EAP-AKA' re-auth"|Identity|counter|NONCE_S)
334	 * MSK  = MK[0..511]
335	 * EMSK = MK[512..1023]
336	 */
337
338	WPA_PUT_BE16(seed3, counter);
339	os_memcpy(seed3 + 2, nonce_s, EAP_SIM_NONCE_S_LEN);
340
341	prf_prime(k_re, "EAP-AKA' re-auth", identity, identity_len,
342		  seed3, sizeof(seed3),
343		  keys, sizeof(keys));
344
345	pos = keys;
346	os_memcpy(msk, pos, EAP_MSK_LEN);
347	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
348	pos += EAP_MSK_LEN;
349
350	os_memcpy(emsk, pos, EAP_EMSK_LEN);
351	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
352
353	os_memset(keys, 0, sizeof(keys));
354
355	return 0;
356}
357
358
359int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
360			      const u8 *mac, const u8 *extra, size_t extra_len)
361{
362	unsigned char hmac[SHA256_MAC_LEN];
363	const u8 *addr[2];
364	size_t len[2];
365	u8 *tmp;
366
367	if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
368	    mac < wpabuf_head_u8(req) ||
369	    mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
370		return -1;
371
372	tmp = os_memdup(wpabuf_head(req), wpabuf_len(req));
373	if (tmp == NULL)
374		return -1;
375
376	addr[0] = tmp;
377	len[0] = wpabuf_len(req);
378	addr[1] = extra;
379	len[1] = extra_len;
380
381	/* HMAC-SHA-256-128 */
382	os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
383	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg",
384		    tmp, wpabuf_len(req));
385	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - extra data",
386		    extra, extra_len);
387	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Verify MAC - K_aut",
388			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
389	hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
390	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC: MAC",
391		    hmac, EAP_SIM_MAC_LEN);
392	os_free(tmp);
393
394	return (os_memcmp_const(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
395}
396
397
398void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len,
399			    u8 *mac, const u8 *extra, size_t extra_len)
400{
401	unsigned char hmac[SHA256_MAC_LEN];
402	const u8 *addr[2];
403	size_t len[2];
404
405	addr[0] = msg;
406	len[0] = msg_len;
407	addr[1] = extra;
408	len[1] = extra_len;
409
410	/* HMAC-SHA-256-128 */
411	os_memset(mac, 0, EAP_SIM_MAC_LEN);
412	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - msg", msg, msg_len);
413	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - extra data",
414		    extra, extra_len);
415	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Add MAC - K_aut",
416			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
417	hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
418	os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
419	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC: MAC",
420		    mac, EAP_SIM_MAC_LEN);
421}
422
423
424void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak,
425				      const u8 *network_name,
426				      size_t network_name_len)
427{
428	u8 key[EAP_AKA_CK_LEN + EAP_AKA_IK_LEN];
429	u8 hash[SHA256_MAC_LEN];
430	const u8 *addr[5];
431	size_t len[5];
432	u8 fc;
433	u8 l0[2], l1[2];
434
435	/* 3GPP TS 33.402 V8.0.0
436	 * (CK', IK') = F(CK, IK, <access network identity>)
437	 */
438	/* TODO: CK', IK' generation should really be moved into the actual
439	 * AKA procedure with network name passed in there and option to use
440	 * AMF separation bit = 1 (3GPP TS 33.401). */
441
442	/* Change Request 33.402 CR 0033 to version 8.1.1 from
443	 * 3GPP TSG-SA WG3 Meeting #53 in September 2008:
444	 *
445	 * CK' || IK' = HMAC-SHA-256(Key, S)
446	 * S = FC || P0 || L0 || P1 || L1 || ... || Pn || Ln
447	 * Key = CK || IK
448	 * FC = 0x20
449	 * P0 = access network identity (3GPP TS 24.302)
450	 * L0 = length of acceess network identity (2 octets, big endian)
451	 * P1 = SQN xor AK (if AK is not used, AK is treaded as 000..0
452	 * L1 = 0x00 0x06
453	 */
454
455	fc = 0x20;
456
457	wpa_printf(MSG_DEBUG, "EAP-AKA': Derive (CK',IK') from (CK,IK)");
458	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK", ck, EAP_AKA_CK_LEN);
459	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK", ik, EAP_AKA_IK_LEN);
460	wpa_printf(MSG_DEBUG, "EAP-AKA': FC = 0x%x", fc);
461	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': P0 = Access network identity",
462			  network_name, network_name_len);
463	wpa_hexdump(MSG_DEBUG, "EAP-AKA': P1 = SQN xor AK", sqn_ak, 6);
464
465	os_memcpy(key, ck, EAP_AKA_CK_LEN);
466	os_memcpy(key + EAP_AKA_CK_LEN, ik, EAP_AKA_IK_LEN);
467	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': Key = CK || IK",
468			key, sizeof(key));
469
470	addr[0] = &fc;
471	len[0] = 1;
472	addr[1] = network_name;
473	len[1] = network_name_len;
474	WPA_PUT_BE16(l0, network_name_len);
475	addr[2] = l0;
476	len[2] = 2;
477	addr[3] = sqn_ak;
478	len[3] = 6;
479	WPA_PUT_BE16(l1, 6);
480	addr[4] = l1;
481	len[4] = 2;
482
483	hmac_sha256_vector(key, sizeof(key), 5, addr, len, hash);
484	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': KDF output (CK' || IK')",
485			hash, sizeof(hash));
486
487	os_memcpy(ck, hash, EAP_AKA_CK_LEN);
488	os_memcpy(ik, hash + EAP_AKA_CK_LEN, EAP_AKA_IK_LEN);
489	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK'", ck, EAP_AKA_CK_LEN);
490	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK'", ik, EAP_AKA_IK_LEN);
491}
492#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
493
494
495int eap_sim_parse_attr(const u8 *start, const u8 *end,
496		       struct eap_sim_attrs *attr, int aka, int encr)
497{
498	const u8 *pos = start, *apos;
499	size_t alen, plen, i, list_len;
500
501	os_memset(attr, 0, sizeof(*attr));
502	attr->id_req = NO_ID_REQ;
503	attr->notification = -1;
504	attr->counter = -1;
505	attr->selected_version = -1;
506	attr->client_error_code = -1;
507
508	while (pos < end) {
509		if (pos + 2 > end) {
510			wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
511			return -1;
512		}
513		wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
514			   pos[0], pos[1] * 4);
515		if (pos + pos[1] * 4 > end) {
516			wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
517				   "(pos=%p len=%d end=%p)",
518				   pos, pos[1] * 4, end);
519			return -1;
520		}
521		if (pos[1] == 0) {
522			wpa_printf(MSG_INFO, "EAP-SIM: Attribute underflow");
523			return -1;
524		}
525		apos = pos + 2;
526		alen = pos[1] * 4 - 2;
527		wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
528			    apos, alen);
529
530		switch (pos[0]) {
531		case EAP_SIM_AT_RAND:
532			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
533			apos += 2;
534			alen -= 2;
535			if ((!aka && (alen % GSM_RAND_LEN)) ||
536			    (aka && alen != EAP_AKA_RAND_LEN)) {
537				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
538					   " (len %lu)",
539					   (unsigned long) alen);
540				return -1;
541			}
542			attr->rand = apos;
543			attr->num_chal = alen / GSM_RAND_LEN;
544			break;
545		case EAP_SIM_AT_AUTN:
546			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
547			if (!aka) {
548				wpa_printf(MSG_DEBUG, "EAP-SIM: "
549					   "Unexpected AT_AUTN");
550				return -1;
551			}
552			apos += 2;
553			alen -= 2;
554			if (alen != EAP_AKA_AUTN_LEN) {
555				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
556					   " (len %lu)",
557					   (unsigned long) alen);
558				return -1;
559			}
560			attr->autn = apos;
561			break;
562		case EAP_SIM_AT_PADDING:
563			if (!encr) {
564				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
565					   "AT_PADDING");
566				return -1;
567			}
568			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
569			for (i = 2; i < alen; i++) {
570				if (apos[i] != 0) {
571					wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
572						   "AT_PADDING used a non-zero"
573						   " padding byte");
574					wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
575						    "(encr) padding bytes",
576						    apos + 2, alen - 2);
577					return -1;
578				}
579			}
580			break;
581		case EAP_SIM_AT_NONCE_MT:
582			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
583			if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
584				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
585					   "AT_NONCE_MT length");
586				return -1;
587			}
588			attr->nonce_mt = apos + 2;
589			break;
590		case EAP_SIM_AT_PERMANENT_ID_REQ:
591			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
592			attr->id_req = PERMANENT_ID;
593			break;
594		case EAP_SIM_AT_MAC:
595			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
596			if (alen != 2 + EAP_SIM_MAC_LEN) {
597				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
598					   "length");
599				return -1;
600			}
601			attr->mac = apos + 2;
602			break;
603		case EAP_SIM_AT_NOTIFICATION:
604			if (alen != 2) {
605				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
606					   "AT_NOTIFICATION length %lu",
607					   (unsigned long) alen);
608				return -1;
609			}
610			attr->notification = apos[0] * 256 + apos[1];
611			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
612				   attr->notification);
613			break;
614		case EAP_SIM_AT_ANY_ID_REQ:
615			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
616			attr->id_req = ANY_ID;
617			break;
618		case EAP_SIM_AT_IDENTITY:
619			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
620			plen = WPA_GET_BE16(apos);
621			apos += 2;
622			alen -= 2;
623			if (plen > alen) {
624				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
625					   "AT_IDENTITY (Actual Length %lu, "
626					   "remaining length %lu)",
627					   (unsigned long) plen,
628					   (unsigned long) alen);
629				return -1;
630			}
631
632			attr->identity = apos;
633			attr->identity_len = plen;
634			break;
635		case EAP_SIM_AT_VERSION_LIST:
636			if (aka) {
637				wpa_printf(MSG_DEBUG, "EAP-AKA: "
638					   "Unexpected AT_VERSION_LIST");
639				return -1;
640			}
641			list_len = apos[0] * 256 + apos[1];
642			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
643			if (list_len < 2 || list_len > alen - 2) {
644				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
645					   "AT_VERSION_LIST (list_len=%lu "
646					   "attr_len=%lu)",
647					   (unsigned long) list_len,
648					   (unsigned long) alen);
649				return -1;
650			}
651			attr->version_list = apos + 2;
652			attr->version_list_len = list_len;
653			break;
654		case EAP_SIM_AT_SELECTED_VERSION:
655			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
656			if (alen != 2) {
657				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
658					   "AT_SELECTED_VERSION length %lu",
659					   (unsigned long) alen);
660				return -1;
661			}
662			attr->selected_version = apos[0] * 256 + apos[1];
663			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
664				   "%d", attr->selected_version);
665			break;
666		case EAP_SIM_AT_FULLAUTH_ID_REQ:
667			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
668			attr->id_req = FULLAUTH_ID;
669			break;
670		case EAP_SIM_AT_COUNTER:
671			if (!encr) {
672				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
673					   "AT_COUNTER");
674				return -1;
675			}
676			if (alen != 2) {
677				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
678					   "AT_COUNTER (alen=%lu)",
679					   (unsigned long) alen);
680				return -1;
681			}
682			attr->counter = apos[0] * 256 + apos[1];
683			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
684				   attr->counter);
685			break;
686		case EAP_SIM_AT_COUNTER_TOO_SMALL:
687			if (!encr) {
688				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
689					   "AT_COUNTER_TOO_SMALL");
690				return -1;
691			}
692			if (alen != 2) {
693				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
694					   "AT_COUNTER_TOO_SMALL (alen=%lu)",
695					   (unsigned long) alen);
696				return -1;
697			}
698			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
699				   "AT_COUNTER_TOO_SMALL");
700			attr->counter_too_small = 1;
701			break;
702		case EAP_SIM_AT_NONCE_S:
703			if (!encr) {
704				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
705					   "AT_NONCE_S");
706				return -1;
707			}
708			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
709				   "AT_NONCE_S");
710			if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
711				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
712					   "AT_NONCE_S (alen=%lu)",
713					   (unsigned long) alen);
714				return -1;
715			}
716			attr->nonce_s = apos + 2;
717			break;
718		case EAP_SIM_AT_CLIENT_ERROR_CODE:
719			if (alen != 2) {
720				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
721					   "AT_CLIENT_ERROR_CODE length %lu",
722					   (unsigned long) alen);
723				return -1;
724			}
725			attr->client_error_code = apos[0] * 256 + apos[1];
726			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
727				   "%d", attr->client_error_code);
728			break;
729		case EAP_SIM_AT_IV:
730			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
731			if (alen != 2 + EAP_SIM_MAC_LEN) {
732				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
733					   "length %lu", (unsigned long) alen);
734				return -1;
735			}
736			attr->iv = apos + 2;
737			break;
738		case EAP_SIM_AT_ENCR_DATA:
739			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
740			attr->encr_data = apos + 2;
741			attr->encr_data_len = alen - 2;
742			if (attr->encr_data_len % 16) {
743				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
744					   "AT_ENCR_DATA length %lu",
745					   (unsigned long)
746					   attr->encr_data_len);
747				return -1;
748			}
749			break;
750		case EAP_SIM_AT_NEXT_PSEUDONYM:
751			if (!encr) {
752				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
753					   "AT_NEXT_PSEUDONYM");
754				return -1;
755			}
756			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
757				   "AT_NEXT_PSEUDONYM");
758			plen = apos[0] * 256 + apos[1];
759			if (plen > alen - 2) {
760				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
761					   " AT_NEXT_PSEUDONYM (actual"
762					   " len %lu, attr len %lu)",
763					   (unsigned long) plen,
764					   (unsigned long) alen);
765				return -1;
766			}
767			attr->next_pseudonym = pos + 4;
768			attr->next_pseudonym_len = plen;
769			break;
770		case EAP_SIM_AT_NEXT_REAUTH_ID:
771			if (!encr) {
772				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
773					   "AT_NEXT_REAUTH_ID");
774				return -1;
775			}
776			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
777				   "AT_NEXT_REAUTH_ID");
778			plen = apos[0] * 256 + apos[1];
779			if (plen > alen - 2) {
780				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
781					   " AT_NEXT_REAUTH_ID (actual"
782					   " len %lu, attr len %lu)",
783					   (unsigned long) plen,
784					   (unsigned long) alen);
785				return -1;
786			}
787			attr->next_reauth_id = pos + 4;
788			attr->next_reauth_id_len = plen;
789			break;
790		case EAP_SIM_AT_RES:
791			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
792			attr->res_len_bits = WPA_GET_BE16(apos);
793			apos += 2;
794			alen -= 2;
795			if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
796			    alen > EAP_AKA_MAX_RES_LEN) {
797				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
798					   "(len %lu)",
799					   (unsigned long) alen);
800				return -1;
801			}
802			attr->res = apos;
803			attr->res_len = alen;
804			break;
805		case EAP_SIM_AT_AUTS:
806			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
807			if (!aka) {
808				wpa_printf(MSG_DEBUG, "EAP-SIM: "
809					   "Unexpected AT_AUTS");
810				return -1;
811			}
812			if (alen != EAP_AKA_AUTS_LEN) {
813				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
814					   " (len %lu)",
815					   (unsigned long) alen);
816				return -1;
817			}
818			attr->auts = apos;
819			break;
820		case EAP_SIM_AT_CHECKCODE:
821			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_CHECKCODE");
822			if (!aka) {
823				wpa_printf(MSG_DEBUG, "EAP-SIM: "
824					   "Unexpected AT_CHECKCODE");
825				return -1;
826			}
827			apos += 2;
828			alen -= 2;
829			if (alen != 0 && alen != EAP_AKA_CHECKCODE_LEN &&
830			    alen != EAP_AKA_PRIME_CHECKCODE_LEN) {
831				wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
832					   "AT_CHECKCODE (len %lu)",
833					   (unsigned long) alen);
834				return -1;
835			}
836			attr->checkcode = apos;
837			attr->checkcode_len = alen;
838			break;
839		case EAP_SIM_AT_RESULT_IND:
840			if (encr) {
841				wpa_printf(MSG_ERROR, "EAP-SIM: Encrypted "
842					   "AT_RESULT_IND");
843				return -1;
844			}
845			if (alen != 2) {
846				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
847					   "AT_RESULT_IND (alen=%lu)",
848					   (unsigned long) alen);
849				return -1;
850			}
851			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RESULT_IND");
852			attr->result_ind = 1;
853			break;
854#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
855		case EAP_SIM_AT_KDF_INPUT:
856			if (aka != 2) {
857				wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
858					   "AT_KDF_INPUT");
859				return -1;
860			}
861
862			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF_INPUT");
863			plen = WPA_GET_BE16(apos);
864			apos += 2;
865			alen -= 2;
866			if (plen > alen) {
867				wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
868					   "AT_KDF_INPUT (Actual Length %lu, "
869					   "remaining length %lu)",
870					   (unsigned long) plen,
871					   (unsigned long) alen);
872				return -1;
873			}
874			attr->kdf_input = apos;
875			attr->kdf_input_len = plen;
876			break;
877		case EAP_SIM_AT_KDF:
878			if (aka != 2) {
879				wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
880					   "AT_KDF");
881				return -1;
882			}
883
884			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF");
885			if (alen != 2) {
886				wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
887					   "AT_KDF (len %lu)",
888					   (unsigned long) alen);
889				return -1;
890			}
891			if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) {
892				wpa_printf(MSG_DEBUG, "EAP-AKA': Too many "
893					   "AT_KDF attributes - ignore this");
894				break;
895			}
896			attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos);
897			attr->kdf_count++;
898			break;
899		case EAP_SIM_AT_BIDDING:
900			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_BIDDING");
901			if (alen != 2) {
902				wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
903					   "AT_BIDDING (len %lu)",
904					   (unsigned long) alen);
905				return -1;
906			}
907			attr->bidding = apos;
908			break;
909#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
910		default:
911			if (pos[0] < 128) {
912				wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
913					   "non-skippable attribute %d",
914					   pos[0]);
915				return -1;
916			}
917
918			wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
919				   " attribute %d ignored", pos[0]);
920			break;
921		}
922
923		pos += pos[1] * 4;
924	}
925
926	wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
927		   "(aka=%d encr=%d)", aka, encr);
928
929	return 0;
930}
931
932
933u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
934			size_t encr_data_len, const u8 *iv,
935			struct eap_sim_attrs *attr, int aka)
936{
937	u8 *decrypted;
938
939	if (!iv) {
940		wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
941		return NULL;
942	}
943
944	decrypted = os_memdup(encr_data, encr_data_len);
945	if (decrypted == NULL)
946		return NULL;
947
948#ifdef TEST_FUZZ
949		wpa_printf(MSG_INFO,
950			   "TEST: Skip AES-128-CBC decryption for fuzz testing");
951#else /* TEST_FUZZ */
952	if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) {
953		os_free(decrypted);
954		return NULL;
955	}
956#endif /* TEST_FUZZ */
957	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
958		    decrypted, encr_data_len);
959
960	if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
961			       aka, 1)) {
962		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
963			   "decrypted AT_ENCR_DATA");
964		os_free(decrypted);
965		return NULL;
966	}
967
968	return decrypted;
969}
970
971
972#define EAP_SIM_INIT_LEN 128
973
974struct eap_sim_msg {
975	struct wpabuf *buf;
976	size_t mac, iv, encr; /* index from buf */
977};
978
979
980struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
981{
982	struct eap_sim_msg *msg;
983	struct eap_hdr *eap;
984	u8 *pos;
985
986	msg = os_zalloc(sizeof(*msg));
987	if (msg == NULL)
988		return NULL;
989
990	msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN);
991	if (msg->buf == NULL) {
992		os_free(msg);
993		return NULL;
994	}
995	eap = wpabuf_put(msg->buf, sizeof(*eap));
996	eap->code = code;
997	eap->identifier = id;
998
999	pos = wpabuf_put(msg->buf, 4);
1000	*pos++ = type;
1001	*pos++ = subtype;
1002	*pos++ = 0; /* Reserved */
1003	*pos++ = 0; /* Reserved */
1004
1005	return msg;
1006}
1007
1008
1009struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type,
1010				   const u8 *k_aut,
1011				   const u8 *extra, size_t extra_len)
1012{
1013	struct eap_hdr *eap;
1014	struct wpabuf *buf;
1015
1016	if (msg == NULL)
1017		return NULL;
1018
1019	eap = wpabuf_mhead(msg->buf);
1020	eap->length = host_to_be16(wpabuf_len(msg->buf));
1021
1022#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
1023	if (k_aut && msg->mac && type == EAP_TYPE_AKA_PRIME) {
1024		eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf),
1025				       wpabuf_len(msg->buf),
1026				       (u8 *) wpabuf_mhead(msg->buf) +
1027				       msg->mac, extra, extra_len);
1028	} else
1029#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
1030	if (k_aut && msg->mac) {
1031		eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf),
1032				wpabuf_len(msg->buf),
1033				(u8 *) wpabuf_mhead(msg->buf) + msg->mac,
1034				extra, extra_len);
1035	}
1036
1037	buf = msg->buf;
1038	os_free(msg);
1039	return buf;
1040}
1041
1042
1043void eap_sim_msg_free(struct eap_sim_msg *msg)
1044{
1045	if (msg) {
1046		wpabuf_free(msg->buf);
1047		os_free(msg);
1048	}
1049}
1050
1051
1052u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
1053			  const u8 *data, size_t len)
1054{
1055	int attr_len = 2 + len;
1056	int pad_len;
1057	u8 *start;
1058
1059	if (msg == NULL)
1060		return NULL;
1061
1062	pad_len = (4 - attr_len % 4) % 4;
1063	attr_len += pad_len;
1064	if (wpabuf_resize(&msg->buf, attr_len))
1065		return NULL;
1066	start = wpabuf_put(msg->buf, 0);
1067	wpabuf_put_u8(msg->buf, attr);
1068	wpabuf_put_u8(msg->buf, attr_len / 4);
1069	wpabuf_put_data(msg->buf, data, len);
1070	if (pad_len)
1071		os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
1072	return start;
1073}
1074
1075
1076u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
1077		     const u8 *data, size_t len)
1078{
1079	int attr_len = 4 + len;
1080	int pad_len;
1081	u8 *start;
1082
1083	if (msg == NULL)
1084		return NULL;
1085
1086	pad_len = (4 - attr_len % 4) % 4;
1087	attr_len += pad_len;
1088	if (wpabuf_resize(&msg->buf, attr_len))
1089		return NULL;
1090	start = wpabuf_put(msg->buf, 0);
1091	wpabuf_put_u8(msg->buf, attr);
1092	wpabuf_put_u8(msg->buf, attr_len / 4);
1093	wpabuf_put_be16(msg->buf, value);
1094	if (data)
1095		wpabuf_put_data(msg->buf, data, len);
1096	else
1097		wpabuf_put(msg->buf, len);
1098	if (pad_len)
1099		os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
1100	return start;
1101}
1102
1103
1104u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
1105{
1106	u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
1107	if (pos)
1108		msg->mac = (pos - wpabuf_head_u8(msg->buf)) + 4;
1109	return pos;
1110}
1111
1112
1113int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
1114			       u8 attr_encr)
1115{
1116	u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
1117	if (pos == NULL)
1118		return -1;
1119	msg->iv = (pos - wpabuf_head_u8(msg->buf)) + 4;
1120	if (random_get_bytes(wpabuf_mhead_u8(msg->buf) + msg->iv,
1121			     EAP_SIM_IV_LEN)) {
1122		msg->iv = 0;
1123		return -1;
1124	}
1125
1126	pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
1127	if (pos == NULL) {
1128		msg->iv = 0;
1129		return -1;
1130	}
1131	msg->encr = pos - wpabuf_head_u8(msg->buf);
1132
1133	return 0;
1134}
1135
1136
1137int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
1138{
1139	size_t encr_len;
1140
1141	if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
1142		return -1;
1143
1144	encr_len = wpabuf_len(msg->buf) - msg->encr - 4;
1145	if (encr_len % 16) {
1146		u8 *pos;
1147		int pad_len = 16 - (encr_len % 16);
1148		if (pad_len < 4) {
1149			wpa_printf(MSG_WARNING, "EAP-SIM: "
1150				   "eap_sim_msg_add_encr_end - invalid pad_len"
1151				   " %d", pad_len);
1152			return -1;
1153		}
1154		wpa_printf(MSG_DEBUG, "   *AT_PADDING");
1155		pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
1156		if (pos == NULL)
1157			return -1;
1158		os_memset(pos + 4, 0, pad_len - 4);
1159		encr_len += pad_len;
1160	}
1161	wpa_printf(MSG_DEBUG, "   (AT_ENCR_DATA data len %lu)",
1162		   (unsigned long) encr_len);
1163	wpabuf_mhead_u8(msg->buf)[msg->encr + 1] = encr_len / 4 + 1;
1164	return aes_128_cbc_encrypt(k_encr, wpabuf_head_u8(msg->buf) + msg->iv,
1165				   wpabuf_mhead_u8(msg->buf) + msg->encr + 4,
1166				   encr_len);
1167}
1168
1169
1170void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
1171{
1172#ifndef CONFIG_NO_STDOUT_DEBUG
1173	const char *type = aka ? "AKA" : "SIM";
1174#endif /* CONFIG_NO_STDOUT_DEBUG */
1175
1176	switch (notification) {
1177	case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
1178		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
1179			   "notification (after authentication)", type);
1180		break;
1181	case EAP_SIM_TEMPORARILY_DENIED:
1182		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
1183			   "User has been temporarily denied access to the "
1184			   "requested service", type);
1185		break;
1186	case EAP_SIM_NOT_SUBSCRIBED:
1187		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
1188			   "User has not subscribed to the requested service",
1189			   type);
1190		break;
1191	case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
1192		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
1193			   "notification (before authentication)", type);
1194		break;
1195	case EAP_SIM_SUCCESS:
1196		wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
1197			   "notification", type);
1198		break;
1199	default:
1200		if (notification >= 32768) {
1201			wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
1202				   "non-failure notification %d",
1203				   type, notification);
1204		} else {
1205			wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
1206				   "failure notification %d",
1207				   type, notification);
1208		}
1209	}
1210}
1211
1212
1213static const u8 * get_last_char(const u8 *val, size_t len, char c)
1214{
1215	while (len > 0) {
1216		const u8 *pos = &val[len - 1];
1217
1218		if (*pos == (u8) c)
1219			return pos;
1220		len--;
1221	}
1222
1223	return NULL;
1224}
1225
1226
1227int eap_sim_anonymous_username(const u8 *id, size_t id_len)
1228{
1229	static const char *anonymous_id_prefix = "anonymous@";
1230	const u8 *decorated;
1231	size_t anonymous_id_len = os_strlen(anonymous_id_prefix);
1232
1233	if (id_len > anonymous_id_len &&
1234	    os_memcmp(id, anonymous_id_prefix, anonymous_id_len) == 0)
1235		return 1; /* 'anonymous@realm' */
1236
1237	if (id_len > anonymous_id_len + 1 &&
1238	    os_memcmp(id + 1, anonymous_id_prefix, anonymous_id_len) == 0)
1239		return 1; /* 'Xanonymous@realm' where X is an EAP method code */
1240
1241	if (id_len > 1 && id[0] == '@')
1242		return 1; /* '@realm' */
1243
1244	/* RFC 7542 decorated username, for example:
1245	 * homerealm.example.org!anonymous@otherrealm.example.net */
1246	decorated = get_last_char(id, id_len, '!');
1247	if (decorated) {
1248		decorated++;
1249		return eap_sim_anonymous_username(decorated,
1250						  id + id_len - decorated);
1251	}
1252
1253	return 0;
1254}
1255