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