$search
00001 /* 00002 * EAP peer/server: EAP-SIM/AKA/AKA' shared routines 00003 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "wpabuf.h" 00019 #include "crypto/aes_wrap.h" 00020 #include "crypto/crypto.h" 00021 #include "crypto/sha1.h" 00022 #include "crypto/sha256.h" 00023 #include "eap_common/eap_defs.h" 00024 #include "eap_common/eap_sim_common.h" 00025 00026 00027 static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen) 00028 { 00029 return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen); 00030 } 00031 00032 00033 void eap_sim_derive_mk(const u8 *identity, size_t identity_len, 00034 const u8 *nonce_mt, u16 selected_version, 00035 const u8 *ver_list, size_t ver_list_len, 00036 int num_chal, const u8 *kc, u8 *mk) 00037 { 00038 u8 sel_ver[2]; 00039 const unsigned char *addr[5]; 00040 size_t len[5]; 00041 00042 addr[0] = identity; 00043 len[0] = identity_len; 00044 addr[1] = kc; 00045 len[1] = num_chal * EAP_SIM_KC_LEN; 00046 addr[2] = nonce_mt; 00047 len[2] = EAP_SIM_NONCE_MT_LEN; 00048 addr[3] = ver_list; 00049 len[3] = ver_list_len; 00050 addr[4] = sel_ver; 00051 len[4] = 2; 00052 00053 WPA_PUT_BE16(sel_ver, selected_version); 00054 00055 /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */ 00056 sha1_vector(5, addr, len, mk); 00057 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN); 00058 } 00059 00060 00061 void eap_aka_derive_mk(const u8 *identity, size_t identity_len, 00062 const u8 *ik, const u8 *ck, u8 *mk) 00063 { 00064 const u8 *addr[3]; 00065 size_t len[3]; 00066 00067 addr[0] = identity; 00068 len[0] = identity_len; 00069 addr[1] = ik; 00070 len[1] = EAP_AKA_IK_LEN; 00071 addr[2] = ck; 00072 len[2] = EAP_AKA_CK_LEN; 00073 00074 /* MK = SHA1(Identity|IK|CK) */ 00075 sha1_vector(3, addr, len, mk); 00076 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN); 00077 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN); 00078 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN); 00079 } 00080 00081 00082 int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk) 00083 { 00084 u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN + 00085 EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos; 00086 if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) { 00087 wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys"); 00088 return -1; 00089 } 00090 pos = buf; 00091 os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN); 00092 pos += EAP_SIM_K_ENCR_LEN; 00093 os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN); 00094 pos += EAP_SIM_K_AUT_LEN; 00095 os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN); 00096 pos += EAP_SIM_KEYING_DATA_LEN; 00097 os_memcpy(emsk, pos, EAP_EMSK_LEN); 00098 00099 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr", 00100 k_encr, EAP_SIM_K_ENCR_LEN); 00101 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut", 00102 k_aut, EAP_SIM_K_AUT_LEN); 00103 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)", 00104 msk, EAP_SIM_KEYING_DATA_LEN); 00105 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN); 00106 os_memset(buf, 0, sizeof(buf)); 00107 00108 return 0; 00109 } 00110 00111 00112 int eap_sim_derive_keys_reauth(u16 _counter, 00113 const u8 *identity, size_t identity_len, 00114 const u8 *nonce_s, const u8 *mk, u8 *msk, 00115 u8 *emsk) 00116 { 00117 u8 xkey[SHA1_MAC_LEN]; 00118 u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32]; 00119 u8 counter[2]; 00120 const u8 *addr[4]; 00121 size_t len[4]; 00122 00123 while (identity_len > 0 && identity[identity_len - 1] == 0) { 00124 wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop null " 00125 "character from the end of identity"); 00126 identity_len--; 00127 } 00128 addr[0] = identity; 00129 len[0] = identity_len; 00130 addr[1] = counter; 00131 len[1] = 2; 00132 addr[2] = nonce_s; 00133 len[2] = EAP_SIM_NONCE_S_LEN; 00134 addr[3] = mk; 00135 len[3] = EAP_SIM_MK_LEN; 00136 00137 WPA_PUT_BE16(counter, _counter); 00138 00139 wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth"); 00140 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", 00141 identity, identity_len); 00142 wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2); 00143 wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s, 00144 EAP_SIM_NONCE_S_LEN); 00145 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN); 00146 00147 /* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */ 00148 sha1_vector(4, addr, len, xkey); 00149 wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN); 00150 00151 if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) { 00152 wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys"); 00153 return -1; 00154 } 00155 if (msk) { 00156 os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN); 00157 wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)", 00158 msk, EAP_SIM_KEYING_DATA_LEN); 00159 } 00160 if (emsk) { 00161 os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN); 00162 wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN); 00163 } 00164 os_memset(buf, 0, sizeof(buf)); 00165 00166 return 0; 00167 } 00168 00169 00170 int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req, 00171 const u8 *mac, const u8 *extra, size_t extra_len) 00172 { 00173 unsigned char hmac[SHA1_MAC_LEN]; 00174 const u8 *addr[2]; 00175 size_t len[2]; 00176 u8 *tmp; 00177 00178 if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN || 00179 mac < wpabuf_head_u8(req) || 00180 mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN) 00181 return -1; 00182 00183 tmp = os_malloc(wpabuf_len(req)); 00184 if (tmp == NULL) 00185 return -1; 00186 00187 addr[0] = tmp; 00188 len[0] = wpabuf_len(req); 00189 addr[1] = extra; 00190 len[1] = extra_len; 00191 00192 /* HMAC-SHA1-128 */ 00193 os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req)); 00194 os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN); 00195 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg", 00196 tmp, wpabuf_len(req)); 00197 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data", 00198 extra, extra_len); 00199 wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut", 00200 k_aut, EAP_SIM_K_AUT_LEN); 00201 hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac); 00202 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC", 00203 hmac, EAP_SIM_MAC_LEN); 00204 os_free(tmp); 00205 00206 return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; 00207 } 00208 00209 00210 void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, 00211 const u8 *extra, size_t extra_len) 00212 { 00213 unsigned char hmac[SHA1_MAC_LEN]; 00214 const u8 *addr[2]; 00215 size_t len[2]; 00216 00217 addr[0] = msg; 00218 len[0] = msg_len; 00219 addr[1] = extra; 00220 len[1] = extra_len; 00221 00222 /* HMAC-SHA1-128 */ 00223 os_memset(mac, 0, EAP_SIM_MAC_LEN); 00224 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len); 00225 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data", 00226 extra, extra_len); 00227 wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut", 00228 k_aut, EAP_SIM_K_AUT_LEN); 00229 hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac); 00230 os_memcpy(mac, hmac, EAP_SIM_MAC_LEN); 00231 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC", 00232 mac, EAP_SIM_MAC_LEN); 00233 } 00234 00235 00236 #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) 00237 static void prf_prime(const u8 *k, const char *seed1, 00238 const u8 *seed2, size_t seed2_len, 00239 const u8 *seed3, size_t seed3_len, 00240 u8 *res, size_t res_len) 00241 { 00242 const u8 *addr[5]; 00243 size_t len[5]; 00244 u8 hash[SHA256_MAC_LEN]; 00245 u8 iter; 00246 00247 /* 00248 * PRF'(K,S) = T1 | T2 | T3 | T4 | ... 00249 * T1 = HMAC-SHA-256 (K, S | 0x01) 00250 * T2 = HMAC-SHA-256 (K, T1 | S | 0x02) 00251 * T3 = HMAC-SHA-256 (K, T2 | S | 0x03) 00252 * T4 = HMAC-SHA-256 (K, T3 | S | 0x04) 00253 * ... 00254 */ 00255 00256 addr[0] = hash; 00257 len[0] = 0; 00258 addr[1] = (const u8 *) seed1; 00259 len[1] = os_strlen(seed1); 00260 addr[2] = seed2; 00261 len[2] = seed2_len; 00262 addr[3] = seed3; 00263 len[3] = seed3_len; 00264 addr[4] = &iter; 00265 len[4] = 1; 00266 00267 iter = 0; 00268 while (res_len) { 00269 size_t hlen; 00270 iter++; 00271 hmac_sha256_vector(k, 32, 5, addr, len, hash); 00272 len[0] = SHA256_MAC_LEN; 00273 hlen = res_len > SHA256_MAC_LEN ? SHA256_MAC_LEN : res_len; 00274 os_memcpy(res, hash, hlen); 00275 res += hlen; 00276 res_len -= hlen; 00277 } 00278 } 00279 00280 00281 void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len, 00282 const u8 *ik, const u8 *ck, u8 *k_encr, 00283 u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk) 00284 { 00285 u8 key[EAP_AKA_IK_LEN + EAP_AKA_CK_LEN]; 00286 u8 keys[EAP_SIM_K_ENCR_LEN + EAP_AKA_PRIME_K_AUT_LEN + 00287 EAP_AKA_PRIME_K_RE_LEN + EAP_MSK_LEN + EAP_EMSK_LEN]; 00288 u8 *pos; 00289 00290 /* 00291 * MK = PRF'(IK'|CK',"EAP-AKA'"|Identity) 00292 * K_encr = MK[0..127] 00293 * K_aut = MK[128..383] 00294 * K_re = MK[384..639] 00295 * MSK = MK[640..1151] 00296 * EMSK = MK[1152..1663] 00297 */ 00298 00299 os_memcpy(key, ik, EAP_AKA_IK_LEN); 00300 os_memcpy(key + EAP_AKA_IK_LEN, ck, EAP_AKA_CK_LEN); 00301 00302 prf_prime(key, "EAP-AKA'", identity, identity_len, NULL, 0, 00303 keys, sizeof(keys)); 00304 00305 pos = keys; 00306 os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN); 00307 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_encr", 00308 k_encr, EAP_SIM_K_ENCR_LEN); 00309 pos += EAP_SIM_K_ENCR_LEN; 00310 00311 os_memcpy(k_aut, pos, EAP_AKA_PRIME_K_AUT_LEN); 00312 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_aut", 00313 k_aut, EAP_AKA_PRIME_K_AUT_LEN); 00314 pos += EAP_AKA_PRIME_K_AUT_LEN; 00315 00316 os_memcpy(k_re, pos, EAP_AKA_PRIME_K_RE_LEN); 00317 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_re", 00318 k_re, EAP_AKA_PRIME_K_RE_LEN); 00319 pos += EAP_AKA_PRIME_K_RE_LEN; 00320 00321 os_memcpy(msk, pos, EAP_MSK_LEN); 00322 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN); 00323 pos += EAP_MSK_LEN; 00324 00325 os_memcpy(emsk, pos, EAP_EMSK_LEN); 00326 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN); 00327 } 00328 00329 00330 int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, 00331 const u8 *identity, size_t identity_len, 00332 const u8 *nonce_s, u8 *msk, u8 *emsk) 00333 { 00334 u8 seed3[2 + EAP_SIM_NONCE_S_LEN]; 00335 u8 keys[EAP_MSK_LEN + EAP_EMSK_LEN]; 00336 u8 *pos; 00337 00338 /* 00339 * MK = PRF'(K_re,"EAP-AKA' re-auth"|Identity|counter|NONCE_S) 00340 * MSK = MK[0..511] 00341 * EMSK = MK[512..1023] 00342 */ 00343 00344 WPA_PUT_BE16(seed3, counter); 00345 os_memcpy(seed3 + 2, nonce_s, EAP_SIM_NONCE_S_LEN); 00346 00347 prf_prime(k_re, "EAP-AKA' re-auth", identity, identity_len, 00348 seed3, sizeof(seed3), 00349 keys, sizeof(keys)); 00350 00351 pos = keys; 00352 os_memcpy(msk, pos, EAP_MSK_LEN); 00353 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN); 00354 pos += EAP_MSK_LEN; 00355 00356 os_memcpy(emsk, pos, EAP_EMSK_LEN); 00357 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN); 00358 00359 os_memset(keys, 0, sizeof(keys)); 00360 00361 return 0; 00362 } 00363 00364 00365 int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req, 00366 const u8 *mac, const u8 *extra, size_t extra_len) 00367 { 00368 unsigned char hmac[SHA256_MAC_LEN]; 00369 const u8 *addr[2]; 00370 size_t len[2]; 00371 u8 *tmp; 00372 00373 if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN || 00374 mac < wpabuf_head_u8(req) || 00375 mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN) 00376 return -1; 00377 00378 tmp = os_malloc(wpabuf_len(req)); 00379 if (tmp == NULL) 00380 return -1; 00381 00382 addr[0] = tmp; 00383 len[0] = wpabuf_len(req); 00384 addr[1] = extra; 00385 len[1] = extra_len; 00386 00387 /* HMAC-SHA-256-128 */ 00388 os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req)); 00389 os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN); 00390 wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg", 00391 tmp, wpabuf_len(req)); 00392 wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - extra data", 00393 extra, extra_len); 00394 wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Verify MAC - K_aut", 00395 k_aut, EAP_AKA_PRIME_K_AUT_LEN); 00396 hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac); 00397 wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC: MAC", 00398 hmac, EAP_SIM_MAC_LEN); 00399 os_free(tmp); 00400 00401 return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; 00402 } 00403 00404 00405 void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len, 00406 u8 *mac, const u8 *extra, size_t extra_len) 00407 { 00408 unsigned char hmac[SHA256_MAC_LEN]; 00409 const u8 *addr[2]; 00410 size_t len[2]; 00411 00412 addr[0] = msg; 00413 len[0] = msg_len; 00414 addr[1] = extra; 00415 len[1] = extra_len; 00416 00417 /* HMAC-SHA-256-128 */ 00418 os_memset(mac, 0, EAP_SIM_MAC_LEN); 00419 wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - msg", msg, msg_len); 00420 wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - extra data", 00421 extra, extra_len); 00422 wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Add MAC - K_aut", 00423 k_aut, EAP_AKA_PRIME_K_AUT_LEN); 00424 hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac); 00425 os_memcpy(mac, hmac, EAP_SIM_MAC_LEN); 00426 wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC: MAC", 00427 mac, EAP_SIM_MAC_LEN); 00428 } 00429 00430 00431 void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, 00432 const u8 *network_name, 00433 size_t network_name_len) 00434 { 00435 u8 key[EAP_AKA_CK_LEN + EAP_AKA_IK_LEN]; 00436 u8 hash[SHA256_MAC_LEN]; 00437 const u8 *addr[5]; 00438 size_t len[5]; 00439 u8 fc; 00440 u8 l0[2], l1[2]; 00441 00442 /* 3GPP TS 33.402 V8.0.0 00443 * (CK', IK') = F(CK, IK, <access network identity>) 00444 */ 00445 /* TODO: CK', IK' generation should really be moved into the actual 00446 * AKA procedure with network name passed in there and option to use 00447 * AMF separation bit = 1 (3GPP TS 33.401). */ 00448 00449 /* Change Request 33.402 CR 0033 to version 8.1.1 from 00450 * 3GPP TSG-SA WG3 Meeting #53 in September 2008: 00451 * 00452 * CK' || IK' = HMAC-SHA-256(Key, S) 00453 * S = FC || P0 || L0 || P1 || L1 || ... || Pn || Ln 00454 * Key = CK || IK 00455 * FC = 0x20 00456 * P0 = access network identity (3GPP TS 24.302) 00457 * L0 = length of acceess network identity (2 octets, big endian) 00458 * P1 = SQN xor AK (if AK is not used, AK is treaded as 000..0 00459 * L1 = 0x00 0x06 00460 */ 00461 00462 fc = 0x20; 00463 00464 wpa_printf(MSG_DEBUG, "EAP-AKA': Derive (CK',IK') from (CK,IK)"); 00465 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK", ck, EAP_AKA_CK_LEN); 00466 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK", ik, EAP_AKA_IK_LEN); 00467 wpa_printf(MSG_DEBUG, "EAP-AKA': FC = 0x%x", fc); 00468 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': P0 = Access network identity", 00469 network_name, network_name_len); 00470 wpa_hexdump(MSG_DEBUG, "EAP-AKA': P1 = SQN xor AK", sqn_ak, 6); 00471 00472 os_memcpy(key, ck, EAP_AKA_CK_LEN); 00473 os_memcpy(key + EAP_AKA_CK_LEN, ik, EAP_AKA_IK_LEN); 00474 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': Key = CK || IK", 00475 key, sizeof(key)); 00476 00477 addr[0] = &fc; 00478 len[0] = 1; 00479 addr[1] = network_name; 00480 len[1] = network_name_len; 00481 WPA_PUT_BE16(l0, network_name_len); 00482 addr[2] = l0; 00483 len[2] = 2; 00484 addr[3] = sqn_ak; 00485 len[3] = 6; 00486 WPA_PUT_BE16(l1, 6); 00487 addr[4] = l1; 00488 len[4] = 2; 00489 00490 hmac_sha256_vector(key, sizeof(key), 5, addr, len, hash); 00491 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': KDF output (CK' || IK')", 00492 hash, sizeof(hash)); 00493 00494 os_memcpy(ck, hash, EAP_AKA_CK_LEN); 00495 os_memcpy(ik, hash + EAP_AKA_CK_LEN, EAP_AKA_IK_LEN); 00496 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK'", ck, EAP_AKA_CK_LEN); 00497 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK'", ik, EAP_AKA_IK_LEN); 00498 } 00499 #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ 00500 00501 00502 int eap_sim_parse_attr(const u8 *start, const u8 *end, 00503 struct eap_sim_attrs *attr, int aka, int encr) 00504 { 00505 const u8 *pos = start, *apos; 00506 size_t alen, plen, i, list_len; 00507 00508 os_memset(attr, 0, sizeof(*attr)); 00509 attr->id_req = NO_ID_REQ; 00510 attr->notification = -1; 00511 attr->counter = -1; 00512 attr->selected_version = -1; 00513 attr->client_error_code = -1; 00514 00515 while (pos < end) { 00516 if (pos + 2 > end) { 00517 wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)"); 00518 return -1; 00519 } 00520 wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d", 00521 pos[0], pos[1] * 4); 00522 if (pos + pos[1] * 4 > end) { 00523 wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow " 00524 "(pos=%p len=%d end=%p)", 00525 pos, pos[1] * 4, end); 00526 return -1; 00527 } 00528 if (pos[1] == 0) { 00529 wpa_printf(MSG_INFO, "EAP-SIM: Attribute underflow"); 00530 return -1; 00531 } 00532 apos = pos + 2; 00533 alen = pos[1] * 4 - 2; 00534 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data", 00535 apos, alen); 00536 00537 switch (pos[0]) { 00538 case EAP_SIM_AT_RAND: 00539 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND"); 00540 apos += 2; 00541 alen -= 2; 00542 if ((!aka && (alen % GSM_RAND_LEN)) || 00543 (aka && alen != EAP_AKA_RAND_LEN)) { 00544 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND" 00545 " (len %lu)", 00546 (unsigned long) alen); 00547 return -1; 00548 } 00549 attr->rand = apos; 00550 attr->num_chal = alen / GSM_RAND_LEN; 00551 break; 00552 case EAP_SIM_AT_AUTN: 00553 wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN"); 00554 if (!aka) { 00555 wpa_printf(MSG_DEBUG, "EAP-SIM: " 00556 "Unexpected AT_AUTN"); 00557 return -1; 00558 } 00559 apos += 2; 00560 alen -= 2; 00561 if (alen != EAP_AKA_AUTN_LEN) { 00562 wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN" 00563 " (len %lu)", 00564 (unsigned long) alen); 00565 return -1; 00566 } 00567 attr->autn = apos; 00568 break; 00569 case EAP_SIM_AT_PADDING: 00570 if (!encr) { 00571 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " 00572 "AT_PADDING"); 00573 return -1; 00574 } 00575 wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING"); 00576 for (i = 2; i < alen; i++) { 00577 if (apos[i] != 0) { 00578 wpa_printf(MSG_INFO, "EAP-SIM: (encr) " 00579 "AT_PADDING used a non-zero" 00580 " padding byte"); 00581 wpa_hexdump(MSG_DEBUG, "EAP-SIM: " 00582 "(encr) padding bytes", 00583 apos + 2, alen - 2); 00584 return -1; 00585 } 00586 } 00587 break; 00588 case EAP_SIM_AT_NONCE_MT: 00589 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT"); 00590 if (alen != 2 + EAP_SIM_NONCE_MT_LEN) { 00591 wpa_printf(MSG_INFO, "EAP-SIM: Invalid " 00592 "AT_NONCE_MT length"); 00593 return -1; 00594 } 00595 attr->nonce_mt = apos + 2; 00596 break; 00597 case EAP_SIM_AT_PERMANENT_ID_REQ: 00598 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ"); 00599 attr->id_req = PERMANENT_ID; 00600 break; 00601 case EAP_SIM_AT_MAC: 00602 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC"); 00603 if (alen != 2 + EAP_SIM_MAC_LEN) { 00604 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC " 00605 "length"); 00606 return -1; 00607 } 00608 attr->mac = apos + 2; 00609 break; 00610 case EAP_SIM_AT_NOTIFICATION: 00611 if (alen != 2) { 00612 wpa_printf(MSG_INFO, "EAP-SIM: Invalid " 00613 "AT_NOTIFICATION length %lu", 00614 (unsigned long) alen); 00615 return -1; 00616 } 00617 attr->notification = apos[0] * 256 + apos[1]; 00618 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d", 00619 attr->notification); 00620 break; 00621 case EAP_SIM_AT_ANY_ID_REQ: 00622 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ"); 00623 attr->id_req = ANY_ID; 00624 break; 00625 case EAP_SIM_AT_IDENTITY: 00626 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY"); 00627 plen = WPA_GET_BE16(apos); 00628 apos += 2; 00629 alen -= 2; 00630 if (plen > alen) { 00631 wpa_printf(MSG_INFO, "EAP-SIM: Invalid " 00632 "AT_IDENTITY (Actual Length %lu, " 00633 "remaining length %lu)", 00634 (unsigned long) plen, 00635 (unsigned long) alen); 00636 return -1; 00637 } 00638 00639 attr->identity = apos; 00640 attr->identity_len = plen; 00641 break; 00642 case EAP_SIM_AT_VERSION_LIST: 00643 if (aka) { 00644 wpa_printf(MSG_DEBUG, "EAP-AKA: " 00645 "Unexpected AT_VERSION_LIST"); 00646 return -1; 00647 } 00648 list_len = apos[0] * 256 + apos[1]; 00649 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST"); 00650 if (list_len < 2 || list_len > alen - 2) { 00651 wpa_printf(MSG_WARNING, "EAP-SIM: Invalid " 00652 "AT_VERSION_LIST (list_len=%lu " 00653 "attr_len=%lu)", 00654 (unsigned long) list_len, 00655 (unsigned long) alen); 00656 return -1; 00657 } 00658 attr->version_list = apos + 2; 00659 attr->version_list_len = list_len; 00660 break; 00661 case EAP_SIM_AT_SELECTED_VERSION: 00662 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION"); 00663 if (alen != 2) { 00664 wpa_printf(MSG_INFO, "EAP-SIM: Invalid " 00665 "AT_SELECTED_VERSION length %lu", 00666 (unsigned long) alen); 00667 return -1; 00668 } 00669 attr->selected_version = apos[0] * 256 + apos[1]; 00670 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION " 00671 "%d", attr->selected_version); 00672 break; 00673 case EAP_SIM_AT_FULLAUTH_ID_REQ: 00674 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ"); 00675 attr->id_req = FULLAUTH_ID; 00676 break; 00677 case EAP_SIM_AT_COUNTER: 00678 if (!encr) { 00679 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " 00680 "AT_COUNTER"); 00681 return -1; 00682 } 00683 if (alen != 2) { 00684 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid " 00685 "AT_COUNTER (alen=%lu)", 00686 (unsigned long) alen); 00687 return -1; 00688 } 00689 attr->counter = apos[0] * 256 + apos[1]; 00690 wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d", 00691 attr->counter); 00692 break; 00693 case EAP_SIM_AT_COUNTER_TOO_SMALL: 00694 if (!encr) { 00695 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " 00696 "AT_COUNTER_TOO_SMALL"); 00697 return -1; 00698 } 00699 if (alen != 2) { 00700 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid " 00701 "AT_COUNTER_TOO_SMALL (alen=%lu)", 00702 (unsigned long) alen); 00703 return -1; 00704 } 00705 wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " 00706 "AT_COUNTER_TOO_SMALL"); 00707 attr->counter_too_small = 1; 00708 break; 00709 case EAP_SIM_AT_NONCE_S: 00710 if (!encr) { 00711 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " 00712 "AT_NONCE_S"); 00713 return -1; 00714 } 00715 wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " 00716 "AT_NONCE_S"); 00717 if (alen != 2 + EAP_SIM_NONCE_S_LEN) { 00718 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid " 00719 "AT_NONCE_S (alen=%lu)", 00720 (unsigned long) alen); 00721 return -1; 00722 } 00723 attr->nonce_s = apos + 2; 00724 break; 00725 case EAP_SIM_AT_CLIENT_ERROR_CODE: 00726 if (alen != 2) { 00727 wpa_printf(MSG_INFO, "EAP-SIM: Invalid " 00728 "AT_CLIENT_ERROR_CODE length %lu", 00729 (unsigned long) alen); 00730 return -1; 00731 } 00732 attr->client_error_code = apos[0] * 256 + apos[1]; 00733 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE " 00734 "%d", attr->client_error_code); 00735 break; 00736 case EAP_SIM_AT_IV: 00737 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV"); 00738 if (alen != 2 + EAP_SIM_MAC_LEN) { 00739 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV " 00740 "length %lu", (unsigned long) alen); 00741 return -1; 00742 } 00743 attr->iv = apos + 2; 00744 break; 00745 case EAP_SIM_AT_ENCR_DATA: 00746 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA"); 00747 attr->encr_data = apos + 2; 00748 attr->encr_data_len = alen - 2; 00749 if (attr->encr_data_len % 16) { 00750 wpa_printf(MSG_INFO, "EAP-SIM: Invalid " 00751 "AT_ENCR_DATA length %lu", 00752 (unsigned long) 00753 attr->encr_data_len); 00754 return -1; 00755 } 00756 break; 00757 case EAP_SIM_AT_NEXT_PSEUDONYM: 00758 if (!encr) { 00759 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " 00760 "AT_NEXT_PSEUDONYM"); 00761 return -1; 00762 } 00763 wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " 00764 "AT_NEXT_PSEUDONYM"); 00765 plen = apos[0] * 256 + apos[1]; 00766 if (plen > alen - 2) { 00767 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid" 00768 " AT_NEXT_PSEUDONYM (actual" 00769 " len %lu, attr len %lu)", 00770 (unsigned long) plen, 00771 (unsigned long) alen); 00772 return -1; 00773 } 00774 attr->next_pseudonym = pos + 4; 00775 attr->next_pseudonym_len = plen; 00776 break; 00777 case EAP_SIM_AT_NEXT_REAUTH_ID: 00778 if (!encr) { 00779 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " 00780 "AT_NEXT_REAUTH_ID"); 00781 return -1; 00782 } 00783 wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " 00784 "AT_NEXT_REAUTH_ID"); 00785 plen = apos[0] * 256 + apos[1]; 00786 if (plen > alen - 2) { 00787 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid" 00788 " AT_NEXT_REAUTH_ID (actual" 00789 " len %lu, attr len %lu)", 00790 (unsigned long) plen, 00791 (unsigned long) alen); 00792 return -1; 00793 } 00794 attr->next_reauth_id = pos + 4; 00795 attr->next_reauth_id_len = plen; 00796 break; 00797 case EAP_SIM_AT_RES: 00798 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES"); 00799 attr->res_len_bits = WPA_GET_BE16(apos); 00800 apos += 2; 00801 alen -= 2; 00802 if (!aka || alen < EAP_AKA_MIN_RES_LEN || 00803 alen > EAP_AKA_MAX_RES_LEN) { 00804 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES " 00805 "(len %lu)", 00806 (unsigned long) alen); 00807 return -1; 00808 } 00809 attr->res = apos; 00810 attr->res_len = alen; 00811 break; 00812 case EAP_SIM_AT_AUTS: 00813 wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS"); 00814 if (!aka) { 00815 wpa_printf(MSG_DEBUG, "EAP-SIM: " 00816 "Unexpected AT_AUTS"); 00817 return -1; 00818 } 00819 if (alen != EAP_AKA_AUTS_LEN) { 00820 wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS" 00821 " (len %lu)", 00822 (unsigned long) alen); 00823 return -1; 00824 } 00825 attr->auts = apos; 00826 break; 00827 case EAP_SIM_AT_CHECKCODE: 00828 wpa_printf(MSG_DEBUG, "EAP-AKA: AT_CHECKCODE"); 00829 if (!aka) { 00830 wpa_printf(MSG_DEBUG, "EAP-SIM: " 00831 "Unexpected AT_CHECKCODE"); 00832 return -1; 00833 } 00834 apos += 2; 00835 alen -= 2; 00836 if (alen != 0 && alen != EAP_AKA_CHECKCODE_LEN && 00837 alen != EAP_AKA_PRIME_CHECKCODE_LEN) { 00838 wpa_printf(MSG_INFO, "EAP-AKA: Invalid " 00839 "AT_CHECKCODE (len %lu)", 00840 (unsigned long) alen); 00841 return -1; 00842 } 00843 attr->checkcode = apos; 00844 attr->checkcode_len = alen; 00845 break; 00846 case EAP_SIM_AT_RESULT_IND: 00847 if (encr) { 00848 wpa_printf(MSG_ERROR, "EAP-SIM: Encrypted " 00849 "AT_RESULT_IND"); 00850 return -1; 00851 } 00852 if (alen != 2) { 00853 wpa_printf(MSG_INFO, "EAP-SIM: Invalid " 00854 "AT_RESULT_IND (alen=%lu)", 00855 (unsigned long) alen); 00856 return -1; 00857 } 00858 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RESULT_IND"); 00859 attr->result_ind = 1; 00860 break; 00861 #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) 00862 case EAP_SIM_AT_KDF_INPUT: 00863 if (aka != 2) { 00864 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected " 00865 "AT_KDF_INPUT"); 00866 return -1; 00867 } 00868 00869 wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF_INPUT"); 00870 plen = WPA_GET_BE16(apos); 00871 apos += 2; 00872 alen -= 2; 00873 if (plen > alen) { 00874 wpa_printf(MSG_INFO, "EAP-AKA': Invalid " 00875 "AT_KDF_INPUT (Actual Length %lu, " 00876 "remaining length %lu)", 00877 (unsigned long) plen, 00878 (unsigned long) alen); 00879 return -1; 00880 } 00881 attr->kdf_input = apos; 00882 attr->kdf_input_len = plen; 00883 break; 00884 case EAP_SIM_AT_KDF: 00885 if (aka != 2) { 00886 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected " 00887 "AT_KDF"); 00888 return -1; 00889 } 00890 00891 wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF"); 00892 if (alen != 2) { 00893 wpa_printf(MSG_INFO, "EAP-AKA': Invalid " 00894 "AT_KDF (len %lu)", 00895 (unsigned long) alen); 00896 return -1; 00897 } 00898 if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) { 00899 wpa_printf(MSG_DEBUG, "EAP-AKA': Too many " 00900 "AT_KDF attributes - ignore this"); 00901 continue; 00902 } 00903 attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos); 00904 attr->kdf_count++; 00905 break; 00906 case EAP_SIM_AT_BIDDING: 00907 wpa_printf(MSG_DEBUG, "EAP-AKA: AT_BIDDING"); 00908 if (alen != 2) { 00909 wpa_printf(MSG_INFO, "EAP-AKA: Invalid " 00910 "AT_BIDDING (len %lu)", 00911 (unsigned long) alen); 00912 return -1; 00913 } 00914 attr->bidding = apos; 00915 break; 00916 #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ 00917 default: 00918 if (pos[0] < 128) { 00919 wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized " 00920 "non-skippable attribute %d", 00921 pos[0]); 00922 return -1; 00923 } 00924 00925 wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable" 00926 " attribute %d ignored", pos[0]); 00927 break; 00928 } 00929 00930 pos += pos[1] * 4; 00931 } 00932 00933 wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully " 00934 "(aka=%d encr=%d)", aka, encr); 00935 00936 return 0; 00937 } 00938 00939 00940 u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data, 00941 size_t encr_data_len, const u8 *iv, 00942 struct eap_sim_attrs *attr, int aka) 00943 { 00944 u8 *decrypted; 00945 00946 if (!iv) { 00947 wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV"); 00948 return NULL; 00949 } 00950 00951 decrypted = os_malloc(encr_data_len); 00952 if (decrypted == NULL) 00953 return NULL; 00954 os_memcpy(decrypted, encr_data, encr_data_len); 00955 00956 if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) { 00957 os_free(decrypted); 00958 return NULL; 00959 } 00960 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA", 00961 decrypted, encr_data_len); 00962 00963 if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr, 00964 aka, 1)) { 00965 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse " 00966 "decrypted AT_ENCR_DATA"); 00967 os_free(decrypted); 00968 return NULL; 00969 } 00970 00971 return decrypted; 00972 } 00973 00974 00975 #define EAP_SIM_INIT_LEN 128 00976 00977 struct eap_sim_msg { 00978 struct wpabuf *buf; 00979 size_t mac, iv, encr; /* index from buf */ 00980 int type; 00981 }; 00982 00983 00984 struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype) 00985 { 00986 struct eap_sim_msg *msg; 00987 struct eap_hdr *eap; 00988 u8 *pos; 00989 00990 msg = os_zalloc(sizeof(*msg)); 00991 if (msg == NULL) 00992 return NULL; 00993 00994 msg->type = type; 00995 msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN); 00996 if (msg->buf == NULL) { 00997 os_free(msg); 00998 return NULL; 00999 } 01000 eap = wpabuf_put(msg->buf, sizeof(*eap)); 01001 eap->code = code; 01002 eap->identifier = id; 01003 01004 pos = wpabuf_put(msg->buf, 4); 01005 *pos++ = type; 01006 *pos++ = subtype; 01007 *pos++ = 0; /* Reserved */ 01008 *pos++ = 0; /* Reserved */ 01009 01010 return msg; 01011 } 01012 01013 01014 struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut, 01015 const u8 *extra, size_t extra_len) 01016 { 01017 struct eap_hdr *eap; 01018 struct wpabuf *buf; 01019 01020 if (msg == NULL) 01021 return NULL; 01022 01023 eap = wpabuf_mhead(msg->buf); 01024 eap->length = host_to_be16(wpabuf_len(msg->buf)); 01025 01026 #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) 01027 if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) { 01028 eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf), 01029 wpabuf_len(msg->buf), 01030 (u8 *) wpabuf_mhead(msg->buf) + 01031 msg->mac, extra, extra_len); 01032 } else 01033 #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ 01034 if (k_aut && msg->mac) { 01035 eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf), 01036 wpabuf_len(msg->buf), 01037 (u8 *) wpabuf_mhead(msg->buf) + msg->mac, 01038 extra, extra_len); 01039 } 01040 01041 buf = msg->buf; 01042 os_free(msg); 01043 return buf; 01044 } 01045 01046 01047 void eap_sim_msg_free(struct eap_sim_msg *msg) 01048 { 01049 if (msg) { 01050 wpabuf_free(msg->buf); 01051 os_free(msg); 01052 } 01053 } 01054 01055 01056 u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr, 01057 const u8 *data, size_t len) 01058 { 01059 int attr_len = 2 + len; 01060 int pad_len; 01061 u8 *start; 01062 01063 if (msg == NULL) 01064 return NULL; 01065 01066 pad_len = (4 - attr_len % 4) % 4; 01067 attr_len += pad_len; 01068 if (wpabuf_resize(&msg->buf, attr_len)) 01069 return NULL; 01070 start = wpabuf_put(msg->buf, 0); 01071 wpabuf_put_u8(msg->buf, attr); 01072 wpabuf_put_u8(msg->buf, attr_len / 4); 01073 wpabuf_put_data(msg->buf, data, len); 01074 if (pad_len) 01075 os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len); 01076 return start; 01077 } 01078 01079 01080 u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value, 01081 const u8 *data, size_t len) 01082 { 01083 int attr_len = 4 + len; 01084 int pad_len; 01085 u8 *start; 01086 01087 if (msg == NULL) 01088 return NULL; 01089 01090 pad_len = (4 - attr_len % 4) % 4; 01091 attr_len += pad_len; 01092 if (wpabuf_resize(&msg->buf, attr_len)) 01093 return NULL; 01094 start = wpabuf_put(msg->buf, 0); 01095 wpabuf_put_u8(msg->buf, attr); 01096 wpabuf_put_u8(msg->buf, attr_len / 4); 01097 wpabuf_put_be16(msg->buf, value); 01098 if (data) 01099 wpabuf_put_data(msg->buf, data, len); 01100 else 01101 wpabuf_put(msg->buf, len); 01102 if (pad_len) 01103 os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len); 01104 return start; 01105 } 01106 01107 01108 u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr) 01109 { 01110 u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN); 01111 if (pos) 01112 msg->mac = (pos - wpabuf_head_u8(msg->buf)) + 4; 01113 return pos; 01114 } 01115 01116 01117 int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv, 01118 u8 attr_encr) 01119 { 01120 u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN); 01121 if (pos == NULL) 01122 return -1; 01123 msg->iv = (pos - wpabuf_head_u8(msg->buf)) + 4; 01124 if (os_get_random(wpabuf_mhead_u8(msg->buf) + msg->iv, 01125 EAP_SIM_IV_LEN)) { 01126 msg->iv = 0; 01127 return -1; 01128 } 01129 01130 pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0); 01131 if (pos == NULL) { 01132 msg->iv = 0; 01133 return -1; 01134 } 01135 msg->encr = pos - wpabuf_head_u8(msg->buf); 01136 01137 return 0; 01138 } 01139 01140 01141 int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad) 01142 { 01143 size_t encr_len; 01144 01145 if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0) 01146 return -1; 01147 01148 encr_len = wpabuf_len(msg->buf) - msg->encr - 4; 01149 if (encr_len % 16) { 01150 u8 *pos; 01151 int pad_len = 16 - (encr_len % 16); 01152 if (pad_len < 4) { 01153 wpa_printf(MSG_WARNING, "EAP-SIM: " 01154 "eap_sim_msg_add_encr_end - invalid pad_len" 01155 " %d", pad_len); 01156 return -1; 01157 } 01158 wpa_printf(MSG_DEBUG, " *AT_PADDING"); 01159 pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4); 01160 if (pos == NULL) 01161 return -1; 01162 os_memset(pos + 4, 0, pad_len - 4); 01163 encr_len += pad_len; 01164 } 01165 wpa_printf(MSG_DEBUG, " (AT_ENCR_DATA data len %lu)", 01166 (unsigned long) encr_len); 01167 wpabuf_mhead_u8(msg->buf)[msg->encr + 1] = encr_len / 4 + 1; 01168 return aes_128_cbc_encrypt(k_encr, wpabuf_head_u8(msg->buf) + msg->iv, 01169 wpabuf_mhead_u8(msg->buf) + msg->encr + 4, 01170 encr_len); 01171 } 01172 01173 01174 void eap_sim_report_notification(void *msg_ctx, int notification, int aka) 01175 { 01176 #ifndef CONFIG_NO_STDOUT_DEBUG 01177 const char *type = aka ? "AKA" : "SIM"; 01178 #endif /* CONFIG_NO_STDOUT_DEBUG */ 01179 01180 switch (notification) { 01181 case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH: 01182 wpa_printf(MSG_WARNING, "EAP-%s: General failure " 01183 "notification (after authentication)", type); 01184 break; 01185 case EAP_SIM_TEMPORARILY_DENIED: 01186 wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: " 01187 "User has been temporarily denied access to the " 01188 "requested service", type); 01189 break; 01190 case EAP_SIM_NOT_SUBSCRIBED: 01191 wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: " 01192 "User has not subscribed to the requested service", 01193 type); 01194 break; 01195 case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH: 01196 wpa_printf(MSG_WARNING, "EAP-%s: General failure " 01197 "notification (before authentication)", type); 01198 break; 01199 case EAP_SIM_SUCCESS: 01200 wpa_printf(MSG_INFO, "EAP-%s: Successful authentication " 01201 "notification", type); 01202 break; 01203 default: 01204 if (notification >= 32768) { 01205 wpa_printf(MSG_INFO, "EAP-%s: Unrecognized " 01206 "non-failure notification %d", 01207 type, notification); 01208 } else { 01209 wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized " 01210 "failure notification %d", 01211 type, notification); 01212 } 01213 } 01214 }