eap_sim_common.c

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

Generated on Sat Nov 21 23:16:51 2009 for hostapd by  doxygen 1.6.1