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