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