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