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