2 * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
19 #include "crypto/aes_wrap.h"
20 #include "crypto/crypto.h"
21 #include "crypto/sha1.h"
22 #include "crypto/sha256.h"
23 #include "eap_common/eap_defs.h"
24 #include "eap_common/eap_sim_common.h"
27 static int eap_sim_prf(const u8
*key
, u8
*x
, size_t xlen
)
29 return fips186_2_prf(key
, EAP_SIM_MK_LEN
, x
, xlen
);
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
)
39 const unsigned char *addr
[5];
43 len
[0] = identity_len
;
45 len
[1] = num_chal
* EAP_SIM_KC_LEN
;
47 len
[2] = EAP_SIM_NONCE_MT_LEN
;
49 len
[3] = ver_list_len
;
53 WPA_PUT_BE16(sel_ver
, selected_version
);
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
);
61 void eap_aka_derive_mk(const u8
*identity
, size_t identity_len
,
62 const u8
*ik
, const u8
*ck
, u8
*mk
)
68 len
[0] = identity_len
;
70 len
[1] = EAP_AKA_IK_LEN
;
72 len
[2] = EAP_AKA_CK_LEN
;
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
);
82 int eap_sim_derive_keys(const u8
*mk
, u8
*k_encr
, u8
*k_aut
, u8
*msk
, u8
*emsk
)
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");
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
);
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
));
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
,
117 u8 xkey
[SHA1_MAC_LEN
];
118 u8 buf
[EAP_SIM_KEYING_DATA_LEN
+ EAP_EMSK_LEN
+ 32];
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");
129 len
[0] = identity_len
;
133 len
[2] = EAP_SIM_NONCE_S_LEN
;
135 len
[3] = EAP_SIM_MK_LEN
;
137 WPA_PUT_BE16(counter
, _counter
);
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
);
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
);
151 if (eap_sim_prf(xkey
, buf
, sizeof(buf
)) < 0) {
152 wpa_printf(MSG_ERROR
, "EAP-SIM: Failed to derive keys");
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
);
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
);
164 os_memset(buf
, 0, sizeof(buf
));
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
)
173 unsigned char hmac
[SHA1_MAC_LEN
];
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
)
183 tmp
= os_malloc(wpabuf_len(req
));
188 len
[0] = wpabuf_len(req
);
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",
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
);
206 return (os_memcmp(hmac
, mac
, EAP_SIM_MAC_LEN
) == 0) ? 0 : 1;
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
)
213 unsigned char hmac
[SHA1_MAC_LEN
];
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",
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
);
236 #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_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
)
244 u8 hash
[SHA256_MAC_LEN
];
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)
258 addr
[1] = (const u8
*) seed1
;
259 len
[1] = os_strlen(seed1
);
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
);
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
)
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
];
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]
299 os_memcpy(key
, ik
, EAP_AKA_IK_LEN
);
300 os_memcpy(key
+ EAP_AKA_IK_LEN
, ck
, EAP_AKA_CK_LEN
);
302 prf_prime(key
, "EAP-AKA'", identity
, identity_len
, NULL
, 0,
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
;
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
;
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
;
321 os_memcpy(msk
, pos
, EAP_MSK_LEN
);
322 wpa_hexdump_key(MSG_DEBUG
, "EAP-AKA': MSK", msk
, EAP_MSK_LEN
);
325 os_memcpy(emsk
, pos
, EAP_EMSK_LEN
);
326 wpa_hexdump_key(MSG_DEBUG
, "EAP-AKA': EMSK", emsk
, EAP_EMSK_LEN
);
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
)
334 u8 seed3
[2 + EAP_SIM_NONCE_S_LEN
];
335 u8 keys
[EAP_MSK_LEN
+ EAP_EMSK_LEN
];
339 * MK = PRF'(K_re,"EAP-AKA' re-auth"|Identity|counter|NONCE_S)
341 * EMSK = MK[512..1023]
344 WPA_PUT_BE16(seed3
, counter
);
345 os_memcpy(seed3
+ 2, nonce_s
, EAP_SIM_NONCE_S_LEN
);
347 prf_prime(k_re
, "EAP-AKA' re-auth", identity
, identity_len
,
348 seed3
, sizeof(seed3
),
352 os_memcpy(msk
, pos
, EAP_MSK_LEN
);
353 wpa_hexdump_key(MSG_DEBUG
, "EAP-AKA': MSK", msk
, EAP_MSK_LEN
);
356 os_memcpy(emsk
, pos
, EAP_EMSK_LEN
);
357 wpa_hexdump_key(MSG_DEBUG
, "EAP-AKA': EMSK", emsk
, EAP_EMSK_LEN
);
359 os_memset(keys
, 0, sizeof(keys
));
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
)
368 unsigned char hmac
[SHA256_MAC_LEN
];
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
)
378 tmp
= os_malloc(wpabuf_len(req
));
383 len
[0] = wpabuf_len(req
);
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",
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
);
401 return (os_memcmp(hmac
, mac
, EAP_SIM_MAC_LEN
) == 0) ? 0 : 1;
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
)
408 unsigned char hmac
[SHA256_MAC_LEN
];
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",
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
);
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
)
435 u8 key
[EAP_AKA_CK_LEN
+ EAP_AKA_IK_LEN
];
436 u8 hash
[SHA256_MAC_LEN
];
442 /* 3GPP TS 33.402 V8.0.0
443 * (CK', IK') = F(CK, IK, <access network identity>)
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). */
449 /* Change Request 33.402 CR 0033 to version 8.1.1 from
450 * 3GPP TSG-SA WG3 Meeting #53 in September 2008:
452 * CK' || IK' = HMAC-SHA-256(Key, S)
453 * S = FC || P0 || L0 || P1 || L1 || ... || Pn || Ln
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
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);
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",
479 addr
[1] = network_name
;
480 len
[1] = network_name_len
;
481 WPA_PUT_BE16(l0
, network_name_len
);
490 hmac_sha256_vector(key
, sizeof(key
), 5, addr
, len
, hash
);
491 wpa_hexdump_key(MSG_DEBUG
, "EAP-AKA': KDF output (CK' || IK')",
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
);
499 #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
502 int eap_sim_parse_attr(const u8
*start
, const u8
*end
,
503 struct eap_sim_attrs
*attr
, int aka
, int encr
)
505 const u8
*pos
= start
, *apos
;
506 size_t alen
, plen
, i
, list_len
;
508 os_memset(attr
, 0, sizeof(*attr
));
509 attr
->id_req
= NO_ID_REQ
;
510 attr
->notification
= -1;
512 attr
->selected_version
= -1;
513 attr
->client_error_code
= -1;
517 wpa_printf(MSG_INFO
, "EAP-SIM: Attribute overflow(1)");
520 wpa_printf(MSG_MSGDUMP
, "EAP-SIM: Attribute: Type=%d Len=%d",
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
);
529 wpa_printf(MSG_INFO
, "EAP-SIM: Attribute underflow");
533 alen
= pos
[1] * 4 - 2;
534 wpa_hexdump(MSG_MSGDUMP
, "EAP-SIM: Attribute data",
538 case EAP_SIM_AT_RAND
:
539 wpa_printf(MSG_DEBUG
, "EAP-SIM: AT_RAND");
542 if ((!aka
&& (alen
% GSM_RAND_LEN
)) ||
543 (aka
&& alen
!= EAP_AKA_RAND_LEN
)) {
544 wpa_printf(MSG_INFO
, "EAP-SIM: Invalid AT_RAND"
546 (unsigned long) alen
);
550 attr
->num_chal
= alen
/ GSM_RAND_LEN
;
552 case EAP_SIM_AT_AUTN
:
553 wpa_printf(MSG_DEBUG
, "EAP-AKA: AT_AUTN");
555 wpa_printf(MSG_DEBUG
, "EAP-SIM: "
556 "Unexpected AT_AUTN");
561 if (alen
!= EAP_AKA_AUTN_LEN
) {
562 wpa_printf(MSG_INFO
, "EAP-AKA: Invalid AT_AUTN"
564 (unsigned long) alen
);
569 case EAP_SIM_AT_PADDING
:
571 wpa_printf(MSG_ERROR
, "EAP-SIM: Unencrypted "
575 wpa_printf(MSG_DEBUG
, "EAP-SIM: (encr) AT_PADDING");
576 for (i
= 2; i
< alen
; i
++) {
578 wpa_printf(MSG_INFO
, "EAP-SIM: (encr) "
579 "AT_PADDING used a non-zero"
581 wpa_hexdump(MSG_DEBUG
, "EAP-SIM: "
582 "(encr) padding bytes",
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");
595 attr
->nonce_mt
= apos
+ 2;
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
;
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 "
608 attr
->mac
= apos
+ 2;
610 case EAP_SIM_AT_NOTIFICATION
:
612 wpa_printf(MSG_INFO
, "EAP-SIM: Invalid "
613 "AT_NOTIFICATION length %lu",
614 (unsigned long) alen
);
617 attr
->notification
= apos
[0] * 256 + apos
[1];
618 wpa_printf(MSG_DEBUG
, "EAP-SIM: AT_NOTIFICATION %d",
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
;
625 case EAP_SIM_AT_IDENTITY
:
626 wpa_printf(MSG_DEBUG
, "EAP-SIM: AT_IDENTITY");
627 plen
= WPA_GET_BE16(apos
);
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
);
639 attr
->identity
= apos
;
640 attr
->identity_len
= plen
;
642 case EAP_SIM_AT_VERSION_LIST
:
644 wpa_printf(MSG_DEBUG
, "EAP-AKA: "
645 "Unexpected AT_VERSION_LIST");
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 "
654 (unsigned long) list_len
,
655 (unsigned long) alen
);
658 attr
->version_list
= apos
+ 2;
659 attr
->version_list_len
= list_len
;
661 case EAP_SIM_AT_SELECTED_VERSION
:
662 wpa_printf(MSG_DEBUG
, "EAP-SIM: AT_SELECTED_VERSION");
664 wpa_printf(MSG_INFO
, "EAP-SIM: Invalid "
665 "AT_SELECTED_VERSION length %lu",
666 (unsigned long) alen
);
669 attr
->selected_version
= apos
[0] * 256 + apos
[1];
670 wpa_printf(MSG_DEBUG
, "EAP-SIM: AT_SELECTED_VERSION "
671 "%d", attr
->selected_version
);
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
;
677 case EAP_SIM_AT_COUNTER
:
679 wpa_printf(MSG_ERROR
, "EAP-SIM: Unencrypted "
684 wpa_printf(MSG_INFO
, "EAP-SIM: (encr) Invalid "
685 "AT_COUNTER (alen=%lu)",
686 (unsigned long) alen
);
689 attr
->counter
= apos
[0] * 256 + apos
[1];
690 wpa_printf(MSG_DEBUG
, "EAP-SIM: (encr) AT_COUNTER %d",
693 case EAP_SIM_AT_COUNTER_TOO_SMALL
:
695 wpa_printf(MSG_ERROR
, "EAP-SIM: Unencrypted "
696 "AT_COUNTER_TOO_SMALL");
700 wpa_printf(MSG_INFO
, "EAP-SIM: (encr) Invalid "
701 "AT_COUNTER_TOO_SMALL (alen=%lu)",
702 (unsigned long) alen
);
705 wpa_printf(MSG_DEBUG
, "EAP-SIM: (encr) "
706 "AT_COUNTER_TOO_SMALL");
707 attr
->counter_too_small
= 1;
709 case EAP_SIM_AT_NONCE_S
:
711 wpa_printf(MSG_ERROR
, "EAP-SIM: Unencrypted "
715 wpa_printf(MSG_DEBUG
, "EAP-SIM: (encr) "
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
);
723 attr
->nonce_s
= apos
+ 2;
725 case EAP_SIM_AT_CLIENT_ERROR_CODE
:
727 wpa_printf(MSG_INFO
, "EAP-SIM: Invalid "
728 "AT_CLIENT_ERROR_CODE length %lu",
729 (unsigned long) alen
);
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
);
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
);
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",
753 attr
->encr_data_len
);
757 case EAP_SIM_AT_NEXT_PSEUDONYM
:
759 wpa_printf(MSG_ERROR
, "EAP-SIM: Unencrypted "
760 "AT_NEXT_PSEUDONYM");
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
);
774 attr
->next_pseudonym
= pos
+ 4;
775 attr
->next_pseudonym_len
= plen
;
777 case EAP_SIM_AT_NEXT_REAUTH_ID
:
779 wpa_printf(MSG_ERROR
, "EAP-SIM: Unencrypted "
780 "AT_NEXT_REAUTH_ID");
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
);
794 attr
->next_reauth_id
= pos
+ 4;
795 attr
->next_reauth_id_len
= plen
;
798 wpa_printf(MSG_DEBUG
, "EAP-SIM: AT_RES");
799 attr
->res_len_bits
= WPA_GET_BE16(apos
);
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 "
806 (unsigned long) alen
);
810 attr
->res_len
= alen
;
812 case EAP_SIM_AT_AUTS
:
813 wpa_printf(MSG_DEBUG
, "EAP-AKA: AT_AUTS");
815 wpa_printf(MSG_DEBUG
, "EAP-SIM: "
816 "Unexpected AT_AUTS");
819 if (alen
!= EAP_AKA_AUTS_LEN
) {
820 wpa_printf(MSG_INFO
, "EAP-AKA: Invalid AT_AUTS"
822 (unsigned long) alen
);
827 case EAP_SIM_AT_CHECKCODE
:
828 wpa_printf(MSG_DEBUG
, "EAP-AKA: AT_CHECKCODE");
830 wpa_printf(MSG_DEBUG
, "EAP-SIM: "
831 "Unexpected AT_CHECKCODE");
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
);
843 attr
->checkcode
= apos
;
844 attr
->checkcode_len
= alen
;
846 case EAP_SIM_AT_RESULT_IND
:
848 wpa_printf(MSG_ERROR
, "EAP-SIM: Encrypted "
853 wpa_printf(MSG_INFO
, "EAP-SIM: Invalid "
854 "AT_RESULT_IND (alen=%lu)",
855 (unsigned long) alen
);
858 wpa_printf(MSG_DEBUG
, "EAP-SIM: AT_RESULT_IND");
859 attr
->result_ind
= 1;
861 #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
862 case EAP_SIM_AT_KDF_INPUT
:
864 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected "
869 wpa_printf(MSG_DEBUG
, "EAP-AKA: AT_KDF_INPUT");
870 plen
= WPA_GET_BE16(apos
);
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
);
881 attr
->kdf_input
= apos
;
882 attr
->kdf_input_len
= plen
;
886 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected "
891 wpa_printf(MSG_DEBUG
, "EAP-AKA: AT_KDF");
893 wpa_printf(MSG_INFO
, "EAP-AKA': Invalid "
895 (unsigned long) alen
);
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");
903 attr
->kdf
[attr
->kdf_count
] = WPA_GET_BE16(apos
);
906 case EAP_SIM_AT_BIDDING
:
907 wpa_printf(MSG_DEBUG
, "EAP-AKA: AT_BIDDING");
909 wpa_printf(MSG_INFO
, "EAP-AKA: Invalid "
910 "AT_BIDDING (len %lu)",
911 (unsigned long) alen
);
914 attr
->bidding
= apos
;
916 #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
919 wpa_printf(MSG_INFO
, "EAP-SIM: Unrecognized "
920 "non-skippable attribute %d",
925 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unrecognized skippable"
926 " attribute %d ignored", pos
[0]);
933 wpa_printf(MSG_DEBUG
, "EAP-SIM: Attributes parsed successfully "
934 "(aka=%d encr=%d)", aka
, encr
);
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
)
947 wpa_printf(MSG_INFO
, "EAP-SIM: Encrypted data, but no IV");
951 decrypted
= os_malloc(encr_data_len
);
952 if (decrypted
== NULL
)
954 os_memcpy(decrypted
, encr_data
, encr_data_len
);
956 if (aes_128_cbc_decrypt(k_encr
, iv
, decrypted
, encr_data_len
)) {
960 wpa_hexdump(MSG_MSGDUMP
, "EAP-SIM: Decrypted AT_ENCR_DATA",
961 decrypted
, encr_data_len
);
963 if (eap_sim_parse_attr(decrypted
, decrypted
+ encr_data_len
, attr
,
965 wpa_printf(MSG_INFO
, "EAP-SIM: (encr) Failed to parse "
966 "decrypted AT_ENCR_DATA");
975 #define EAP_SIM_INIT_LEN 128
979 size_t mac
, iv
, encr
; /* index from buf */
984 struct eap_sim_msg
* eap_sim_msg_init(int code
, int id
, int type
, int subtype
)
986 struct eap_sim_msg
*msg
;
990 msg
= os_zalloc(sizeof(*msg
));
995 msg
->buf
= wpabuf_alloc(EAP_SIM_INIT_LEN
);
996 if (msg
->buf
== NULL
) {
1000 eap
= wpabuf_put(msg
->buf
, sizeof(*eap
));
1002 eap
->identifier
= id
;
1004 pos
= wpabuf_put(msg
->buf
, 4);
1007 *pos
++ = 0; /* Reserved */
1008 *pos
++ = 0; /* Reserved */
1014 struct wpabuf
* eap_sim_msg_finish(struct eap_sim_msg
*msg
, const u8
*k_aut
,
1015 const u8
*extra
, size_t extra_len
)
1017 struct eap_hdr
*eap
;
1023 eap
= wpabuf_mhead(msg
->buf
);
1024 eap
->length
= host_to_be16(wpabuf_len(msg
->buf
));
1026 #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_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
);
1033 #endif /* EAP_AKA_PRIME || EAP_SERVER_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
,
1047 void eap_sim_msg_free(struct eap_sim_msg
*msg
)
1050 wpabuf_free(msg
->buf
);
1056 u8
* eap_sim_msg_add_full(struct eap_sim_msg
*msg
, u8 attr
,
1057 const u8
*data
, size_t len
)
1059 int attr_len
= 2 + len
;
1066 pad_len
= (4 - attr_len
% 4) % 4;
1067 attr_len
+= pad_len
;
1068 if (wpabuf_resize(&msg
->buf
, attr_len
))
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
);
1075 os_memset(wpabuf_put(msg
->buf
, pad_len
), 0, pad_len
);
1080 u8
* eap_sim_msg_add(struct eap_sim_msg
*msg
, u8 attr
, u16 value
,
1081 const u8
*data
, size_t len
)
1083 int attr_len
= 4 + len
;
1090 pad_len
= (4 - attr_len
% 4) % 4;
1091 attr_len
+= pad_len
;
1092 if (wpabuf_resize(&msg
->buf
, attr_len
))
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
);
1099 wpabuf_put_data(msg
->buf
, data
, len
);
1101 wpabuf_put(msg
->buf
, len
);
1103 os_memset(wpabuf_put(msg
->buf
, pad_len
), 0, pad_len
);
1108 u8
* eap_sim_msg_add_mac(struct eap_sim_msg
*msg
, u8 attr
)
1110 u8
*pos
= eap_sim_msg_add(msg
, attr
, 0, NULL
, EAP_SIM_MAC_LEN
);
1112 msg
->mac
= (pos
- wpabuf_head_u8(msg
->buf
)) + 4;
1117 int eap_sim_msg_add_encr_start(struct eap_sim_msg
*msg
, u8 attr_iv
,
1120 u8
*pos
= eap_sim_msg_add(msg
, attr_iv
, 0, NULL
, EAP_SIM_IV_LEN
);
1123 msg
->iv
= (pos
- wpabuf_head_u8(msg
->buf
)) + 4;
1124 if (os_get_random(wpabuf_mhead_u8(msg
->buf
) + msg
->iv
,
1130 pos
= eap_sim_msg_add(msg
, attr_encr
, 0, NULL
, 0);
1135 msg
->encr
= pos
- wpabuf_head_u8(msg
->buf
);
1141 int eap_sim_msg_add_encr_end(struct eap_sim_msg
*msg
, u8
*k_encr
, int attr_pad
)
1145 if (msg
== NULL
|| k_encr
== NULL
|| msg
->iv
== 0 || msg
->encr
== 0)
1148 encr_len
= wpabuf_len(msg
->buf
) - msg
->encr
- 4;
1149 if (encr_len
% 16) {
1151 int pad_len
= 16 - (encr_len
% 16);
1153 wpa_printf(MSG_WARNING
, "EAP-SIM: "
1154 "eap_sim_msg_add_encr_end - invalid pad_len"
1158 wpa_printf(MSG_DEBUG
, " *AT_PADDING");
1159 pos
= eap_sim_msg_add(msg
, attr_pad
, 0, NULL
, pad_len
- 4);
1162 os_memset(pos
+ 4, 0, pad_len
- 4);
1163 encr_len
+= pad_len
;
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,
1174 void eap_sim_report_notification(void *msg_ctx
, int notification
, int aka
)
1176 #ifndef CONFIG_NO_STDOUT_DEBUG
1177 const char *type
= aka
? "AKA" : "SIM";
1178 #endif /* CONFIG_NO_STDOUT_DEBUG */
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
);
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
);
1190 case EAP_SIM_NOT_SUBSCRIBED
:
1191 wpa_printf(MSG_WARNING
, "EAP-%s: Failure notification: "
1192 "User has not subscribed to the requested service",
1195 case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
:
1196 wpa_printf(MSG_WARNING
, "EAP-%s: General failure "
1197 "notification (before authentication)", type
);
1199 case EAP_SIM_SUCCESS
:
1200 wpa_printf(MSG_INFO
, "EAP-%s: Successful authentication "
1201 "notification", type
);
1204 if (notification
>= 32768) {
1205 wpa_printf(MSG_INFO
, "EAP-%s: Unrecognized "
1206 "non-failure notification %d",
1207 type
, notification
);
1209 wpa_printf(MSG_WARNING
, "EAP-%s: Unrecognized "
1210 "failure notification %d",
1211 type
, notification
);