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