eap_sim_common.c
Go to the documentation of this file.
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 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:35