LCOV - code coverage report
Current view: top level - eap_common - eap_sim_common.c (source / functions) Hit Total Coverage
Test: hostapd hwsim test run 1401872338 Lines: 385 634 60.7 %
Date: 2014-06-04 Functions: 21 24 87.5 %

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

Generated by: LCOV version 1.10