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 software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 
     11 #include "common.h"
     12 #include "wpabuf.h"
     13 #include "crypto/aes_wrap.h"
     14 #include "crypto/crypto.h"
     15 #include "crypto/sha1.h"
     16 #include "crypto/sha256.h"
     17 #include "crypto/random.h"
     18 #include "eap_common/eap_defs.h"
     19 #include "eap_common/eap_sim_common.h"
     20 
     21 
     22 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 
     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 
     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 
     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 
    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 
    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 
    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)
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 	if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) {
    949 		os_free(decrypted);
    950 		return NULL;
    951 	}
    952 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
    953 		    decrypted, encr_data_len);
    954 
    955 	if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
    956 			       aka, 1)) {
    957 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
    958 			   "decrypted AT_ENCR_DATA");
    959 		os_free(decrypted);
    960 		return NULL;
    961 	}
    962 
    963 	return decrypted;
    964 }
    965 
    966 
    967 #define EAP_SIM_INIT_LEN 128
    968 
    969 struct eap_sim_msg {
    970 	struct wpabuf *buf;
    971 	size_t mac, iv, encr; /* index from buf */
    972 };
    973 
    974 
    975 struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
    976 {
    977 	struct eap_sim_msg *msg;
    978 	struct eap_hdr *eap;
    979 	u8 *pos;
    980 
    981 	msg = os_zalloc(sizeof(*msg));
    982 	if (msg == NULL)
    983 		return NULL;
    984 
    985 	msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN);
    986 	if (msg->buf == NULL) {
    987 		os_free(msg);
    988 		return NULL;
    989 	}
    990 	eap = wpabuf_put(msg->buf, sizeof(*eap));
    991 	eap->code = code;
    992 	eap->identifier = id;
    993 
    994 	pos = wpabuf_put(msg->buf, 4);
    995 	*pos++ = type;
    996 	*pos++ = subtype;
    997 	*pos++ = 0; /* Reserved */
    998 	*pos++ = 0; /* Reserved */
    999 
   1000 	return msg;
   1001 }
   1002 
   1003 
   1004 struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type,
   1005 				   const u8 *k_aut,
   1006 				   const u8 *extra, size_t extra_len)
   1007 {
   1008 	struct eap_hdr *eap;
   1009 	struct wpabuf *buf;
   1010 
   1011 	if (msg == NULL)
   1012 		return NULL;
   1013 
   1014 	eap = wpabuf_mhead(msg->buf);
   1015 	eap->length = host_to_be16(wpabuf_len(msg->buf));
   1016 
   1017 #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
   1018 	if (k_aut && msg->mac && type == EAP_TYPE_AKA_PRIME) {
   1019 		eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf),
   1020 				       wpabuf_len(msg->buf),
   1021 				       (u8 *) wpabuf_mhead(msg->buf) +
   1022 				       msg->mac, extra, extra_len);
   1023 	} else
   1024 #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
   1025 	if (k_aut && msg->mac) {
   1026 		eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf),
   1027 				wpabuf_len(msg->buf),
   1028 				(u8 *) wpabuf_mhead(msg->buf) + msg->mac,
   1029 				extra, extra_len);
   1030 	}
   1031 
   1032 	buf = msg->buf;
   1033 	os_free(msg);
   1034 	return buf;
   1035 }
   1036 
   1037 
   1038 void eap_sim_msg_free(struct eap_sim_msg *msg)
   1039 {
   1040 	if (msg) {
   1041 		wpabuf_free(msg->buf);
   1042 		os_free(msg);
   1043 	}
   1044 }
   1045 
   1046 
   1047 u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
   1048 			  const u8 *data, size_t len)
   1049 {
   1050 	int attr_len = 2 + len;
   1051 	int pad_len;
   1052 	u8 *start;
   1053 
   1054 	if (msg == NULL)
   1055 		return NULL;
   1056 
   1057 	pad_len = (4 - attr_len % 4) % 4;
   1058 	attr_len += pad_len;
   1059 	if (wpabuf_resize(&msg->buf, attr_len))
   1060 		return NULL;
   1061 	start = wpabuf_put(msg->buf, 0);
   1062 	wpabuf_put_u8(msg->buf, attr);
   1063 	wpabuf_put_u8(msg->buf, attr_len / 4);
   1064 	wpabuf_put_data(msg->buf, data, len);
   1065 	if (pad_len)
   1066 		os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
   1067 	return start;
   1068 }
   1069 
   1070 
   1071 u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
   1072 		     const u8 *data, size_t len)
   1073 {
   1074 	int attr_len = 4 + len;
   1075 	int pad_len;
   1076 	u8 *start;
   1077 
   1078 	if (msg == NULL)
   1079 		return NULL;
   1080 
   1081 	pad_len = (4 - attr_len % 4) % 4;
   1082 	attr_len += pad_len;
   1083 	if (wpabuf_resize(&msg->buf, attr_len))
   1084 		return NULL;
   1085 	start = wpabuf_put(msg->buf, 0);
   1086 	wpabuf_put_u8(msg->buf, attr);
   1087 	wpabuf_put_u8(msg->buf, attr_len / 4);
   1088 	wpabuf_put_be16(msg->buf, value);
   1089 	if (data)
   1090 		wpabuf_put_data(msg->buf, data, len);
   1091 	else
   1092 		wpabuf_put(msg->buf, len);
   1093 	if (pad_len)
   1094 		os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
   1095 	return start;
   1096 }
   1097 
   1098 
   1099 u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
   1100 {
   1101 	u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
   1102 	if (pos)
   1103 		msg->mac = (pos - wpabuf_head_u8(msg->buf)) + 4;
   1104 	return pos;
   1105 }
   1106 
   1107 
   1108 int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
   1109 			       u8 attr_encr)
   1110 {
   1111 	u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
   1112 	if (pos == NULL)
   1113 		return -1;
   1114 	msg->iv = (pos - wpabuf_head_u8(msg->buf)) + 4;
   1115 	if (random_get_bytes(wpabuf_mhead_u8(msg->buf) + msg->iv,
   1116 			     EAP_SIM_IV_LEN)) {
   1117 		msg->iv = 0;
   1118 		return -1;
   1119 	}
   1120 
   1121 	pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
   1122 	if (pos == NULL) {
   1123 		msg->iv = 0;
   1124 		return -1;
   1125 	}
   1126 	msg->encr = pos - wpabuf_head_u8(msg->buf);
   1127 
   1128 	return 0;
   1129 }
   1130 
   1131 
   1132 int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
   1133 {
   1134 	size_t encr_len;
   1135 
   1136 	if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
   1137 		return -1;
   1138 
   1139 	encr_len = wpabuf_len(msg->buf) - msg->encr - 4;
   1140 	if (encr_len % 16) {
   1141 		u8 *pos;
   1142 		int pad_len = 16 - (encr_len % 16);
   1143 		if (pad_len < 4) {
   1144 			wpa_printf(MSG_WARNING, "EAP-SIM: "
   1145 				   "eap_sim_msg_add_encr_end - invalid pad_len"
   1146 				   " %d", pad_len);
   1147 			return -1;
   1148 		}
   1149 		wpa_printf(MSG_DEBUG, "   *AT_PADDING");
   1150 		pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
   1151 		if (pos == NULL)
   1152 			return -1;
   1153 		os_memset(pos + 4, 0, pad_len - 4);
   1154 		encr_len += pad_len;
   1155 	}
   1156 	wpa_printf(MSG_DEBUG, "   (AT_ENCR_DATA data len %lu)",
   1157 		   (unsigned long) encr_len);
   1158 	wpabuf_mhead_u8(msg->buf)[msg->encr + 1] = encr_len / 4 + 1;
   1159 	return aes_128_cbc_encrypt(k_encr, wpabuf_head_u8(msg->buf) + msg->iv,
   1160 				   wpabuf_mhead_u8(msg->buf) + msg->encr + 4,
   1161 				   encr_len);
   1162 }
   1163 
   1164 
   1165 void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
   1166 {
   1167 #ifndef CONFIG_NO_STDOUT_DEBUG
   1168 	const char *type = aka ? "AKA" : "SIM";
   1169 #endif /* CONFIG_NO_STDOUT_DEBUG */
   1170 
   1171 	switch (notification) {
   1172 	case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
   1173 		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
   1174 			   "notification (after authentication)", type);
   1175 		break;
   1176 	case EAP_SIM_TEMPORARILY_DENIED:
   1177 		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
   1178 			   "User has been temporarily denied access to the "
   1179 			   "requested service", type);
   1180 		break;
   1181 	case EAP_SIM_NOT_SUBSCRIBED:
   1182 		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
   1183 			   "User has not subscribed to the requested service",
   1184 			   type);
   1185 		break;
   1186 	case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
   1187 		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
   1188 			   "notification (before authentication)", type);
   1189 		break;
   1190 	case EAP_SIM_SUCCESS:
   1191 		wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
   1192 			   "notification", type);
   1193 		break;
   1194 	default:
   1195 		if (notification >= 32768) {
   1196 			wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
   1197 				   "non-failure notification %d",
   1198 				   type, notification);
   1199 		} else {
   1200 			wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
   1201 				   "failure notification %d",
   1202 				   type, notification);
   1203 		}
   1204 	}
   1205 }
   1206