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