Home | History | Annotate | Download | only in wpa_supplicant
      1 /*
      2  * EAP peer: EAP-SIM/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_i.h"
     19 #include "sha1.h"
     20 #include "crypto.h"
     21 #include "aes_wrap.h"
     22 #include "eap_sim_common.h"
     23 
     24 
     25 static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
     26 {
     27 	return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
     28 }
     29 
     30 
     31 void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
     32 		       const u8 *nonce_mt, u16 selected_version,
     33 		       const u8 *ver_list, size_t ver_list_len,
     34 		       int num_chal, const u8 *kc, u8 *mk)
     35 {
     36 	u8 sel_ver[2];
     37 	const unsigned char *addr[5];
     38 	size_t len[5];
     39 
     40 	addr[0] = identity;
     41 	len[0] = identity_len;
     42 	addr[1] = kc;
     43 	len[1] = num_chal * EAP_SIM_KC_LEN;
     44 	addr[2] = nonce_mt;
     45 	len[2] = EAP_SIM_NONCE_MT_LEN;
     46 	addr[3] = ver_list;
     47 	len[3] = ver_list_len;
     48 	addr[4] = sel_ver;
     49 	len[4] = 2;
     50 
     51 	WPA_PUT_BE16(sel_ver, selected_version);
     52 
     53 	/* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
     54 	sha1_vector(5, addr, len, mk);
     55 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
     56 }
     57 
     58 
     59 void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
     60 		       const u8 *ik, const u8 *ck, u8 *mk)
     61 {
     62 	const u8 *addr[3];
     63 	size_t len[3];
     64 
     65 	addr[0] = identity;
     66 	len[0] = identity_len;
     67 	addr[1] = ik;
     68 	len[1] = EAP_AKA_IK_LEN;
     69 	addr[2] = ck;
     70 	len[2] = EAP_AKA_CK_LEN;
     71 
     72 	/* MK = SHA1(Identity|IK|CK) */
     73 	sha1_vector(3, addr, len, mk);
     74 	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
     75 	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
     76 	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
     77 }
     78 
     79 
     80 int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk)
     81 {
     82 	u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN +
     83 	       EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos;
     84 	if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) {
     85 		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
     86 		return -1;
     87 	}
     88 	pos = buf;
     89 	os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
     90 	pos += EAP_SIM_K_ENCR_LEN;
     91 	os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
     92 	pos += EAP_SIM_K_AUT_LEN;
     93 	os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
     94 	pos += EAP_SIM_KEYING_DATA_LEN;
     95 	os_memcpy(emsk, pos, EAP_EMSK_LEN);
     96 
     97 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
     98 			k_encr, EAP_SIM_K_ENCR_LEN);
     99 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
    100 			k_aut, EAP_SIM_K_AUT_LEN);
    101 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
    102 			msk, EAP_SIM_KEYING_DATA_LEN);
    103 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
    104 	os_memset(buf, 0, sizeof(buf));
    105 
    106 	return 0;
    107 }
    108 
    109 
    110 int eap_sim_derive_keys_reauth(u16 _counter,
    111 			       const u8 *identity, size_t identity_len,
    112 			       const u8 *nonce_s, const u8 *mk, u8 *msk,
    113 			       u8 *emsk)
    114 {
    115 	u8 xkey[SHA1_MAC_LEN];
    116 	u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32];
    117 	u8 counter[2];
    118 	const u8 *addr[4];
    119 	size_t len[4];
    120 
    121 	while (identity_len > 0 && identity[identity_len - 1] == 0) {
    122 		wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop null "
    123 			   "character from the end of identity");
    124 		identity_len--;
    125 	}
    126 	addr[0] = identity;
    127 	len[0] = identity_len;
    128 	addr[1] = counter;
    129 	len[1] = 2;
    130 	addr[2] = nonce_s;
    131 	len[2] = EAP_SIM_NONCE_S_LEN;
    132 	addr[3] = mk;
    133 	len[3] = EAP_SIM_MK_LEN;
    134 
    135 	WPA_PUT_BE16(counter, _counter);
    136 
    137 	wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
    138 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
    139 			  identity, identity_len);
    140 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
    141 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
    142 		    EAP_SIM_NONCE_S_LEN);
    143 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
    144 
    145 	/* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
    146 	sha1_vector(4, addr, len, xkey);
    147 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
    148 
    149 	if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) {
    150 		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
    151 		return -1;
    152 	}
    153 	if (msk) {
    154 		os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
    155 		wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
    156 			    msk, EAP_SIM_KEYING_DATA_LEN);
    157 	}
    158 	if (emsk) {
    159 		os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
    160 		wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
    161 	}
    162 	os_memset(buf, 0, sizeof(buf));
    163 
    164 	return 0;
    165 }
    166 
    167 
    168 int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
    169 		       const u8 *mac, const u8 *extra, size_t extra_len)
    170 {
    171 	unsigned char hmac[SHA1_MAC_LEN];
    172 	const u8 *addr[2];
    173 	size_t len[2];
    174 	u8 *tmp;
    175 
    176 	if (mac == NULL || req_len < EAP_SIM_MAC_LEN || mac < req ||
    177 	    mac > req + req_len - EAP_SIM_MAC_LEN)
    178 		return -1;
    179 
    180 	tmp = os_malloc(req_len);
    181 	if (tmp == NULL)
    182 		return -1;
    183 
    184 	addr[0] = tmp;
    185 	len[0] = req_len;
    186 	addr[1] = extra;
    187 	len[1] = extra_len;
    188 
    189 	/* HMAC-SHA1-128 */
    190 	os_memcpy(tmp, req, req_len);
    191 	os_memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
    192 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg", tmp, req_len);
    193 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
    194 		    extra, extra_len);
    195 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
    196 			k_aut, EAP_SIM_K_AUT_LEN);
    197 	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
    198 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
    199 		    hmac, EAP_SIM_MAC_LEN);
    200 	os_free(tmp);
    201 
    202 	return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
    203 }
    204 
    205 
    206 void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
    207 		     const u8 *extra, size_t extra_len)
    208 {
    209 	unsigned char hmac[SHA1_MAC_LEN];
    210 	const u8 *addr[2];
    211 	size_t len[2];
    212 
    213 	addr[0] = msg;
    214 	len[0] = msg_len;
    215 	addr[1] = extra;
    216 	len[1] = extra_len;
    217 
    218 	/* HMAC-SHA1-128 */
    219 	os_memset(mac, 0, EAP_SIM_MAC_LEN);
    220 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
    221 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
    222 		    extra, extra_len);
    223 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
    224 			k_aut, EAP_SIM_K_AUT_LEN);
    225 	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
    226 	os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
    227 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
    228 		    mac, EAP_SIM_MAC_LEN);
    229 }
    230 
    231 
    232 int eap_sim_parse_attr(const u8 *start, const u8 *end,
    233 		       struct eap_sim_attrs *attr, int aka, int encr)
    234 {
    235 	const u8 *pos = start, *apos;
    236 	size_t alen, plen, i, list_len;
    237 
    238 	os_memset(attr, 0, sizeof(*attr));
    239 	attr->id_req = NO_ID_REQ;
    240 	attr->notification = -1;
    241 	attr->counter = -1;
    242 	attr->selected_version = -1;
    243 	attr->client_error_code = -1;
    244 
    245 	while (pos < end) {
    246 		if (pos + 2 > end) {
    247 			wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
    248 			return -1;
    249 		}
    250 		wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
    251 			   pos[0], pos[1] * 4);
    252 		if (pos + pos[1] * 4 > end) {
    253 			wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
    254 				   "(pos=%p len=%d end=%p)",
    255 				   pos, pos[1] * 4, end);
    256 			return -1;
    257 		}
    258 		if (pos[1] == 0) {
    259 			wpa_printf(MSG_INFO, "EAP-SIM: Attribute underflow");
    260 			return -1;
    261 		}
    262 		apos = pos + 2;
    263 		alen = pos[1] * 4 - 2;
    264 		wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
    265 			    apos, alen);
    266 
    267 		switch (pos[0]) {
    268 		case EAP_SIM_AT_RAND:
    269 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
    270 			apos += 2;
    271 			alen -= 2;
    272 			if ((!aka && (alen % GSM_RAND_LEN)) ||
    273 			    (aka && alen != EAP_AKA_RAND_LEN)) {
    274 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
    275 					   " (len %lu)",
    276 					   (unsigned long) alen);
    277 				return -1;
    278 			}
    279 			attr->rand = apos;
    280 			attr->num_chal = alen / GSM_RAND_LEN;
    281 			break;
    282 		case EAP_SIM_AT_AUTN:
    283 			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
    284 			if (!aka) {
    285 				wpa_printf(MSG_DEBUG, "EAP-SIM: "
    286 					   "Unexpected AT_AUTN");
    287 				return -1;
    288 			}
    289 			apos += 2;
    290 			alen -= 2;
    291 			if (alen != EAP_AKA_AUTN_LEN) {
    292 				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
    293 					   " (len %lu)",
    294 					   (unsigned long) alen);
    295 				return -1;
    296 			}
    297 			attr->autn = apos;
    298 			break;
    299 		case EAP_SIM_AT_PADDING:
    300 			if (!encr) {
    301 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
    302 					   "AT_PADDING");
    303 				return -1;
    304 			}
    305 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
    306 			for (i = 2; i < alen; i++) {
    307 				if (apos[i] != 0) {
    308 					wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
    309 						   "AT_PADDING used a non-zero"
    310 						   " padding byte");
    311 					wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
    312 						    "(encr) padding bytes",
    313 						    apos + 2, alen - 2);
    314 					return -1;
    315 				}
    316 			}
    317 			break;
    318 		case EAP_SIM_AT_NONCE_MT:
    319 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
    320 			if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
    321 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
    322 					   "AT_NONCE_MT length");
    323 				return -1;
    324 			}
    325 			attr->nonce_mt = apos + 2;
    326 			break;
    327 		case EAP_SIM_AT_PERMANENT_ID_REQ:
    328 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
    329 			attr->id_req = PERMANENT_ID;
    330 			break;
    331 		case EAP_SIM_AT_MAC:
    332 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
    333 			if (alen != 2 + EAP_SIM_MAC_LEN) {
    334 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
    335 					   "length");
    336 				return -1;
    337 			}
    338 			attr->mac = apos + 2;
    339 			break;
    340 		case EAP_SIM_AT_NOTIFICATION:
    341 			if (alen != 2) {
    342 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
    343 					   "AT_NOTIFICATION length %lu",
    344 					   (unsigned long) alen);
    345 				return -1;
    346 			}
    347 			attr->notification = apos[0] * 256 + apos[1];
    348 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
    349 				   attr->notification);
    350 			break;
    351 		case EAP_SIM_AT_ANY_ID_REQ:
    352 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
    353 			attr->id_req = ANY_ID;
    354 			break;
    355 		case EAP_SIM_AT_IDENTITY:
    356 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
    357 			attr->identity = apos + 2;
    358 			attr->identity_len = alen - 2;
    359 			break;
    360 		case EAP_SIM_AT_VERSION_LIST:
    361 			if (aka) {
    362 				wpa_printf(MSG_DEBUG, "EAP-AKA: "
    363 					   "Unexpected AT_VERSION_LIST");
    364 				return -1;
    365 			}
    366 			list_len = apos[0] * 256 + apos[1];
    367 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
    368 			if (list_len < 2 || list_len > alen - 2) {
    369 				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
    370 					   "AT_VERSION_LIST (list_len=%lu "
    371 					   "attr_len=%lu)",
    372 					   (unsigned long) list_len,
    373 					   (unsigned long) alen);
    374 				return -1;
    375 			}
    376 			attr->version_list = apos + 2;
    377 			attr->version_list_len = list_len;
    378 			break;
    379 		case EAP_SIM_AT_SELECTED_VERSION:
    380 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
    381 			if (alen != 2) {
    382 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
    383 					   "AT_SELECTED_VERSION length %lu",
    384 					   (unsigned long) alen);
    385 				return -1;
    386 			}
    387 			attr->selected_version = apos[0] * 256 + apos[1];
    388 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
    389 				   "%d", attr->selected_version);
    390 			break;
    391 		case EAP_SIM_AT_FULLAUTH_ID_REQ:
    392 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
    393 			attr->id_req = FULLAUTH_ID;
    394 			break;
    395 		case EAP_SIM_AT_COUNTER:
    396 			if (!encr) {
    397 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
    398 					   "AT_COUNTER");
    399 				return -1;
    400 			}
    401 			if (alen != 2) {
    402 				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
    403 					   "AT_COUNTER (alen=%lu)",
    404 					   (unsigned long) alen);
    405 				return -1;
    406 			}
    407 			attr->counter = apos[0] * 256 + apos[1];
    408 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
    409 				   attr->counter);
    410 			break;
    411 		case EAP_SIM_AT_COUNTER_TOO_SMALL:
    412 			if (!encr) {
    413 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
    414 					   "AT_COUNTER_TOO_SMALL");
    415 				return -1;
    416 			}
    417 			if (alen != 2) {
    418 				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
    419 					   "AT_COUNTER_TOO_SMALL (alen=%lu)",
    420 					   (unsigned long) alen);
    421 				return -1;
    422 			}
    423 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
    424 				   "AT_COUNTER_TOO_SMALL");
    425 			attr->counter_too_small = 1;
    426 			break;
    427 		case EAP_SIM_AT_NONCE_S:
    428 			if (!encr) {
    429 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
    430 					   "AT_NONCE_S");
    431 				return -1;
    432 			}
    433 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
    434 				   "AT_NONCE_S");
    435 			if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
    436 				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
    437 					   "AT_NONCE_S (alen=%lu)",
    438 					   (unsigned long) alen);
    439 				return -1;
    440 			}
    441 			attr->nonce_s = apos + 2;
    442 			break;
    443 		case EAP_SIM_AT_CLIENT_ERROR_CODE:
    444 			if (alen != 2) {
    445 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
    446 					   "AT_CLIENT_ERROR_CODE length %lu",
    447 					   (unsigned long) alen);
    448 				return -1;
    449 			}
    450 			attr->client_error_code = apos[0] * 256 + apos[1];
    451 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
    452 				   "%d", attr->client_error_code);
    453 			break;
    454 		case EAP_SIM_AT_IV:
    455 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
    456 			if (alen != 2 + EAP_SIM_MAC_LEN) {
    457 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
    458 					   "length %lu", (unsigned long) alen);
    459 				return -1;
    460 			}
    461 			attr->iv = apos + 2;
    462 			break;
    463 		case EAP_SIM_AT_ENCR_DATA:
    464 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
    465 			attr->encr_data = apos + 2;
    466 			attr->encr_data_len = alen - 2;
    467 			if (attr->encr_data_len % 16) {
    468 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
    469 					   "AT_ENCR_DATA length %lu",
    470 					   (unsigned long)
    471 					   attr->encr_data_len);
    472 				return -1;
    473 			}
    474 			break;
    475 		case EAP_SIM_AT_NEXT_PSEUDONYM:
    476 			if (!encr) {
    477 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
    478 					   "AT_NEXT_PSEUDONYM");
    479 				return -1;
    480 			}
    481 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
    482 				   "AT_NEXT_PSEUDONYM");
    483 			plen = apos[0] * 256 + apos[1];
    484 			if (plen > alen - 2) {
    485 				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
    486 					   " AT_NEXT_PSEUDONYM (actual"
    487 					   " len %lu, attr len %lu)",
    488 					   (unsigned long) plen,
    489 					   (unsigned long) alen);
    490 				return -1;
    491 			}
    492 			attr->next_pseudonym = pos + 4;
    493 			attr->next_pseudonym_len = plen;
    494 			break;
    495 		case EAP_SIM_AT_NEXT_REAUTH_ID:
    496 			if (!encr) {
    497 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
    498 					   "AT_NEXT_REAUTH_ID");
    499 				return -1;
    500 			}
    501 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
    502 				   "AT_NEXT_REAUTH_ID");
    503 			plen = apos[0] * 256 + apos[1];
    504 			if (plen > alen - 2) {
    505 				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
    506 					   " AT_NEXT_REAUTH_ID (actual"
    507 					   " len %lu, attr len %lu)",
    508 					   (unsigned long) plen,
    509 					   (unsigned long) alen);
    510 				return -1;
    511 			}
    512 			attr->next_reauth_id = pos + 4;
    513 			attr->next_reauth_id_len = plen;
    514 			break;
    515 		case EAP_SIM_AT_RES:
    516 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
    517 			apos += 2;
    518 			alen -= 2;
    519 			if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
    520 			    alen > EAP_AKA_MAX_RES_LEN) {
    521 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
    522 					   "(len %lu)",
    523 					   (unsigned long) alen);
    524 				return -1;
    525 			}
    526 			attr->res = apos;
    527 			attr->res_len = alen;
    528 			break;
    529 		case EAP_SIM_AT_AUTS:
    530 			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
    531 			if (!aka) {
    532 				wpa_printf(MSG_DEBUG, "EAP-SIM: "
    533 					   "Unexpected AT_AUTS");
    534 				return -1;
    535 			}
    536 			if (alen != EAP_AKA_AUTS_LEN) {
    537 				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
    538 					   " (len %lu)",
    539 					   (unsigned long) alen);
    540 				return -1;
    541 			}
    542 			attr->auts = apos;
    543 			break;
    544 		default:
    545 			if (pos[0] < 128) {
    546 				wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
    547 					   "non-skippable attribute %d",
    548 					   pos[0]);
    549 				return -1;
    550 			}
    551 
    552 			wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
    553 				   " attribute %d ignored", pos[0]);
    554 			break;
    555 		}
    556 
    557 		pos += pos[1] * 4;
    558 	}
    559 
    560 	wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
    561 		   "(aka=%d encr=%d)", aka, encr);
    562 
    563 	return 0;
    564 }
    565 
    566 
    567 u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
    568 			size_t encr_data_len, const u8 *iv,
    569 			struct eap_sim_attrs *attr, int aka)
    570 {
    571 	u8 *decrypted;
    572 
    573 	if (!iv) {
    574 		wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
    575 		return NULL;
    576 	}
    577 
    578 	decrypted = os_malloc(encr_data_len);
    579 	if (decrypted == NULL)
    580 		return NULL;
    581 	os_memcpy(decrypted, encr_data, encr_data_len);
    582 
    583 	aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len);
    584 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
    585 		    decrypted, encr_data_len);
    586 
    587 	if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
    588 			       aka, 1)) {
    589 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
    590 			   "decrypted AT_ENCR_DATA");
    591 		os_free(decrypted);
    592 		return NULL;
    593 	}
    594 
    595 	return decrypted;
    596 }
    597 
    598 
    599 #define EAP_SIM_INIT_LEN 128
    600 
    601 struct eap_sim_msg {
    602 	u8 *buf;
    603 	size_t buf_len, used;
    604 	size_t mac, iv, encr; /* index from buf */
    605 };
    606 
    607 
    608 struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
    609 {
    610 	struct eap_sim_msg *msg;
    611 	struct eap_hdr *eap;
    612 	u8 *pos;
    613 
    614 	msg = os_zalloc(sizeof(*msg));
    615 	if (msg == NULL)
    616 		return NULL;
    617 
    618 	msg->buf = os_zalloc(EAP_SIM_INIT_LEN);
    619 	if (msg->buf == NULL) {
    620 		os_free(msg);
    621 		return NULL;
    622 	}
    623 	msg->buf_len = EAP_SIM_INIT_LEN;
    624 	eap = (struct eap_hdr *) msg->buf;
    625 	eap->code = code;
    626 	eap->identifier = id;
    627 	msg->used = sizeof(*eap);
    628 
    629 	pos = (u8 *) (eap + 1);
    630 	*pos++ = type;
    631 	*pos++ = subtype;
    632 	*pos++ = 0; /* Reserved */
    633 	*pos++ = 0; /* Reserved */
    634 	msg->used += 4;
    635 
    636 	return msg;
    637 }
    638 
    639 
    640 u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
    641 			const u8 *extra, size_t extra_len)
    642 {
    643 	struct eap_hdr *eap;
    644 	u8 *buf;
    645 
    646 	if (msg == NULL)
    647 		return NULL;
    648 
    649 	eap = (struct eap_hdr *) msg->buf;
    650 	eap->length = host_to_be16(msg->used);
    651 
    652 	if (k_aut && msg->mac) {
    653 		eap_sim_add_mac(k_aut, msg->buf, msg->used,
    654 				msg->buf + msg->mac, extra, extra_len);
    655 	}
    656 
    657 	*len = msg->used;
    658 	buf = msg->buf;
    659 	os_free(msg);
    660 	return buf;
    661 }
    662 
    663 
    664 void eap_sim_msg_free(struct eap_sim_msg *msg)
    665 {
    666 	if (msg) {
    667 		os_free(msg->buf);
    668 		os_free(msg);
    669 	}
    670 }
    671 
    672 
    673 static int eap_sim_msg_resize(struct eap_sim_msg *msg, size_t add_len)
    674 {
    675 	if (msg->used + add_len > msg->buf_len) {
    676 		u8 *nbuf = os_realloc(msg->buf, msg->used + add_len);
    677 		if (nbuf == NULL)
    678 			return -1;
    679 		msg->buf = nbuf;
    680 		msg->buf_len = msg->used + add_len;
    681 	}
    682 	return 0;
    683 }
    684 
    685 
    686 u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
    687 			  const u8 *data, size_t len)
    688 {
    689 	int attr_len = 2 + len;
    690 	int pad_len;
    691 	u8 *start, *pos;
    692 
    693 	if (msg == NULL)
    694 		return NULL;
    695 
    696 	pad_len = (4 - attr_len % 4) % 4;
    697 	attr_len += pad_len;
    698 	if (eap_sim_msg_resize(msg, attr_len))
    699 		return NULL;
    700 	start = pos = msg->buf + msg->used;
    701 	*pos++ = attr;
    702 	*pos++ = attr_len / 4;
    703 	os_memcpy(pos, data, len);
    704 	if (pad_len) {
    705 		pos += len;
    706 		os_memset(pos, 0, pad_len);
    707 	}
    708 	msg->used += attr_len;
    709 	return start;
    710 }
    711 
    712 
    713 u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
    714 		     const u8 *data, size_t len)
    715 {
    716 	int attr_len = 4 + len;
    717 	int pad_len;
    718 	u8 *start, *pos;
    719 
    720 	if (msg == NULL)
    721 		return NULL;
    722 
    723 	pad_len = (4 - attr_len % 4) % 4;
    724 	attr_len += pad_len;
    725 	if (eap_sim_msg_resize(msg, attr_len))
    726 		return NULL;
    727 	start = pos = msg->buf + msg->used;
    728 	*pos++ = attr;
    729 	*pos++ = attr_len / 4;
    730 	WPA_PUT_BE16(pos, value);
    731 	pos += 2;
    732 	if (data)
    733 		os_memcpy(pos, data, len);
    734 	if (pad_len) {
    735 		pos += len;
    736 		os_memset(pos, 0, pad_len);
    737 	}
    738 	msg->used += attr_len;
    739 	return start;
    740 }
    741 
    742 
    743 u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
    744 {
    745 	u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
    746 	if (pos)
    747 		msg->mac = (pos - msg->buf) + 4;
    748 	return pos;
    749 }
    750 
    751 
    752 int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
    753 			       u8 attr_encr)
    754 {
    755 	u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
    756 	if (pos == NULL)
    757 		return -1;
    758 	msg->iv = (pos - msg->buf) + 4;
    759 	if (hostapd_get_rand(msg->buf + msg->iv, EAP_SIM_IV_LEN)) {
    760 		msg->iv = 0;
    761 		return -1;
    762 	}
    763 
    764 	pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
    765 	if (pos == NULL) {
    766 		msg->iv = 0;
    767 		return -1;
    768 	}
    769 	msg->encr = pos - msg->buf;
    770 
    771 	return 0;
    772 }
    773 
    774 
    775 int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
    776 {
    777 	size_t encr_len;
    778 
    779 	if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
    780 		return -1;
    781 
    782 	encr_len = msg->used - msg->encr - 4;
    783 	if (encr_len % 16) {
    784 		u8 *pos;
    785 		int pad_len = 16 - (encr_len % 16);
    786 		if (pad_len < 4) {
    787 			wpa_printf(MSG_WARNING, "EAP-SIM: "
    788 				   "eap_sim_msg_add_encr_end - invalid pad_len"
    789 				   " %d", pad_len);
    790 			return -1;
    791 		}
    792 		wpa_printf(MSG_DEBUG, "   *AT_PADDING");
    793 		pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
    794 		if (pos == NULL)
    795 			return -1;
    796 		os_memset(pos + 4, 0, pad_len - 4);
    797 		encr_len += pad_len;
    798 	}
    799 	wpa_printf(MSG_DEBUG, "   (AT_ENCR_DATA data len %lu)",
    800 		   (unsigned long) encr_len);
    801 	msg->buf[msg->encr + 1] = encr_len / 4 + 1;
    802 	aes_128_cbc_encrypt(k_encr, msg->buf + msg->iv,
    803 			    msg->buf + msg->encr + 4, encr_len);
    804 
    805 	return 0;
    806 }
    807 
    808 
    809 void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
    810 {
    811 #ifndef CONFIG_NO_STDOUT_DEBUG
    812 	const char *type = aka ? "AKA" : "SIM";
    813 #endif /* CONFIG_NO_STDOUT_DEBUG */
    814 
    815 	switch (notification) {
    816 	case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
    817 		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
    818 			   "notification (after authentication)", type);
    819 		break;
    820 	case EAP_SIM_TEMPORARILY_DENIED:
    821 		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
    822 			   "User has been temporarily denied access to the "
    823 			   "requested service", type);
    824 		break;
    825 	case EAP_SIM_NOT_SUBSCRIBED:
    826 		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
    827 			   "User has not subscribed to the requested service",
    828 			   type);
    829 		break;
    830 	case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
    831 		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
    832 			   "notification (before authentication)", type);
    833 		break;
    834 	case EAP_SIM_SUCCESS:
    835 		wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
    836 			   "notification", type);
    837 		break;
    838 	default:
    839 		if (notification >= 32768) {
    840 			wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
    841 				   "non-failure notification %d",
    842 				   type, notification);
    843 		} else {
    844 			wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
    845 				   "failure notification %d",
    846 				   type, notification);
    847 		}
    848 	}
    849 }
    850