LCOV - code coverage report
Current view: top level - src/eap_common - eap_sim_common.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1422976643 Lines: 571 633 90.2 %
Date: 2015-02-03 Functions: 23 24 95.8 %

          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         145 : static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
      23             : {
      24         145 :         return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
      25             : }
      26             : 
      27             : 
      28          54 : 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          54 :         addr[0] = identity;
      38          54 :         len[0] = identity_len;
      39          54 :         addr[1] = kc;
      40          54 :         len[1] = num_chal * EAP_SIM_KC_LEN;
      41          54 :         addr[2] = nonce_mt;
      42          54 :         len[2] = EAP_SIM_NONCE_MT_LEN;
      43          54 :         addr[3] = ver_list;
      44          54 :         len[3] = ver_list_len;
      45          54 :         addr[4] = sel_ver;
      46          54 :         len[4] = 2;
      47             : 
      48          54 :         WPA_PUT_BE16(sel_ver, selected_version);
      49             : 
      50             :         /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
      51          54 :         sha1_vector(5, addr, len, mk);
      52          54 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
      53          54 : }
      54             : 
      55             : 
      56          53 : 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          53 :         addr[0] = identity;
      63          53 :         len[0] = identity_len;
      64          53 :         addr[1] = ik;
      65          53 :         len[1] = EAP_AKA_IK_LEN;
      66          53 :         addr[2] = ck;
      67          53 :         len[2] = EAP_AKA_CK_LEN;
      68             : 
      69             :         /* MK = SHA1(Identity|IK|CK) */
      70          53 :         sha1_vector(3, addr, len, mk);
      71          53 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
      72          53 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
      73          53 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
      74          53 : }
      75             : 
      76             : 
      77         121 : 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         121 :         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         121 :         pos = buf;
      86         121 :         os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
      87         121 :         pos += EAP_SIM_K_ENCR_LEN;
      88         121 :         os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
      89         121 :         pos += EAP_SIM_K_AUT_LEN;
      90         121 :         os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
      91         121 :         pos += EAP_SIM_KEYING_DATA_LEN;
      92         121 :         os_memcpy(emsk, pos, EAP_EMSK_LEN);
      93             : 
      94         121 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
      95             :                         k_encr, EAP_SIM_K_ENCR_LEN);
      96         121 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
      97             :                         k_aut, EAP_SIM_K_AUT_LEN);
      98         121 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
      99             :                         msk, EAP_SIM_KEYING_DATA_LEN);
     100         121 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
     101         121 :         os_memset(buf, 0, sizeof(buf));
     102             : 
     103         121 :         return 0;
     104             : }
     105             : 
     106             : 
     107          24 : 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          48 :         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          24 :         addr[0] = identity;
     124          24 :         len[0] = identity_len;
     125          24 :         addr[1] = counter;
     126          24 :         len[1] = 2;
     127          24 :         addr[2] = nonce_s;
     128          24 :         len[2] = EAP_SIM_NONCE_S_LEN;
     129          24 :         addr[3] = mk;
     130          24 :         len[3] = EAP_SIM_MK_LEN;
     131             : 
     132          24 :         WPA_PUT_BE16(counter, _counter);
     133             : 
     134          24 :         wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
     135          24 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
     136             :                           identity, identity_len);
     137          24 :         wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
     138          24 :         wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
     139             :                     EAP_SIM_NONCE_S_LEN);
     140          24 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
     141             : 
     142             :         /* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
     143          24 :         sha1_vector(4, addr, len, xkey);
     144          24 :         wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
     145             : 
     146          24 :         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          24 :         if (msk) {
     151          24 :                 os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
     152          24 :                 wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
     153             :                             msk, EAP_SIM_KEYING_DATA_LEN);
     154             :         }
     155          24 :         if (emsk) {
     156          24 :                 os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
     157          24 :                 wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
     158             :         }
     159          24 :         os_memset(buf, 0, sizeof(buf));
     160             : 
     161          24 :         return 0;
     162             : }
     163             : 
     164             : 
     165         106 : 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         212 :         if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
     174         212 :             mac < wpabuf_head_u8(req) ||
     175         106 :             mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
     176           0 :                 return -1;
     177             : 
     178         106 :         tmp = os_malloc(wpabuf_len(req));
     179         106 :         if (tmp == NULL)
     180           0 :                 return -1;
     181             : 
     182         106 :         addr[0] = tmp;
     183         106 :         len[0] = wpabuf_len(req);
     184         106 :         addr[1] = extra;
     185         106 :         len[1] = extra_len;
     186             : 
     187             :         /* HMAC-SHA1-128 */
     188         106 :         os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
     189         106 :         os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
     190         106 :         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg",
     191             :                     tmp, wpabuf_len(req));
     192         106 :         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
     193             :                     extra, extra_len);
     194         106 :         wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
     195             :                         k_aut, EAP_SIM_K_AUT_LEN);
     196         106 :         hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
     197         106 :         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
     198             :                     hmac, EAP_SIM_MAC_LEN);
     199         106 :         os_free(tmp);
     200             : 
     201         106 :         return (os_memcmp_const(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
     202             : }
     203             : 
     204             : 
     205         140 : 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         140 :         addr[0] = msg;
     213         140 :         len[0] = msg_len;
     214         140 :         addr[1] = extra;
     215         140 :         len[1] = extra_len;
     216             : 
     217             :         /* HMAC-SHA1-128 */
     218         140 :         os_memset(mac, 0, EAP_SIM_MAC_LEN);
     219         140 :         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
     220         140 :         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
     221             :                     extra, extra_len);
     222         140 :         wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
     223             :                         k_aut, EAP_SIM_K_AUT_LEN);
     224         140 :         hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
     225         140 :         os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
     226         140 :         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
     227             :                     mac, EAP_SIM_MAC_LEN);
     228         140 : }
     229             : 
     230             : 
     231             : #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
     232          39 : 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          39 :         addr[0] = hash;
     252          39 :         len[0] = 0;
     253          39 :         addr[1] = (const u8 *) seed1;
     254          39 :         len[1] = os_strlen(seed1);
     255          39 :         addr[2] = seed2;
     256          39 :         len[2] = seed2_len;
     257          39 :         addr[3] = seed3;
     258          39 :         len[3] = seed3_len;
     259          39 :         addr[4] = &iter;
     260          39 :         len[4] = 1;
     261             : 
     262          39 :         iter = 0;
     263         315 :         while (res_len) {
     264             :                 size_t hlen;
     265         237 :                 iter++;
     266         237 :                 hmac_sha256_vector(k, 32, 5, addr, len, hash);
     267         237 :                 len[0] = SHA256_MAC_LEN;
     268         237 :                 hlen = res_len > SHA256_MAC_LEN ? SHA256_MAC_LEN : res_len;
     269         237 :                 os_memcpy(res, hash, hlen);
     270         237 :                 res += hlen;
     271         237 :                 res_len -= hlen;
     272             :         }
     273          39 : }
     274             : 
     275             : 
     276          27 : 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          27 :         os_memcpy(key, ik, EAP_AKA_IK_LEN);
     295          27 :         os_memcpy(key + EAP_AKA_IK_LEN, ck, EAP_AKA_CK_LEN);
     296             : 
     297          27 :         prf_prime(key, "EAP-AKA'", identity, identity_len, NULL, 0,
     298             :                   keys, sizeof(keys));
     299             : 
     300          27 :         pos = keys;
     301          27 :         os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
     302          27 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_encr",
     303             :                         k_encr, EAP_SIM_K_ENCR_LEN);
     304          27 :         pos += EAP_SIM_K_ENCR_LEN;
     305             : 
     306          27 :         os_memcpy(k_aut, pos, EAP_AKA_PRIME_K_AUT_LEN);
     307          27 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_aut",
     308             :                         k_aut, EAP_AKA_PRIME_K_AUT_LEN);
     309          27 :         pos += EAP_AKA_PRIME_K_AUT_LEN;
     310             : 
     311          27 :         os_memcpy(k_re, pos, EAP_AKA_PRIME_K_RE_LEN);
     312          27 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_re",
     313             :                         k_re, EAP_AKA_PRIME_K_RE_LEN);
     314          27 :         pos += EAP_AKA_PRIME_K_RE_LEN;
     315             : 
     316          27 :         os_memcpy(msk, pos, EAP_MSK_LEN);
     317          27 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
     318          27 :         pos += EAP_MSK_LEN;
     319             : 
     320          27 :         os_memcpy(emsk, pos, EAP_EMSK_LEN);
     321          27 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
     322          27 : }
     323             : 
     324             : 
     325          12 : 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          12 :         WPA_PUT_BE16(seed3, counter);
     340          12 :         os_memcpy(seed3 + 2, nonce_s, EAP_SIM_NONCE_S_LEN);
     341             : 
     342          12 :         prf_prime(k_re, "EAP-AKA' re-auth", identity, identity_len,
     343             :                   seed3, sizeof(seed3),
     344             :                   keys, sizeof(keys));
     345             : 
     346          12 :         pos = keys;
     347          12 :         os_memcpy(msk, pos, EAP_MSK_LEN);
     348          12 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
     349          12 :         pos += EAP_MSK_LEN;
     350             : 
     351          12 :         os_memcpy(emsk, pos, EAP_EMSK_LEN);
     352          12 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
     353             : 
     354          12 :         os_memset(keys, 0, sizeof(keys));
     355             : 
     356          12 :         return 0;
     357             : }
     358             : 
     359             : 
     360          42 : 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          84 :         if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
     369          84 :             mac < wpabuf_head_u8(req) ||
     370          42 :             mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
     371           0 :                 return -1;
     372             : 
     373          42 :         tmp = os_malloc(wpabuf_len(req));
     374          42 :         if (tmp == NULL)
     375           0 :                 return -1;
     376             : 
     377          42 :         addr[0] = tmp;
     378          42 :         len[0] = wpabuf_len(req);
     379          42 :         addr[1] = extra;
     380          42 :         len[1] = extra_len;
     381             : 
     382             :         /* HMAC-SHA-256-128 */
     383          42 :         os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
     384          42 :         os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
     385          42 :         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg",
     386             :                     tmp, wpabuf_len(req));
     387          42 :         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - extra data",
     388             :                     extra, extra_len);
     389          42 :         wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Verify MAC - K_aut",
     390             :                         k_aut, EAP_AKA_PRIME_K_AUT_LEN);
     391          42 :         hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
     392          42 :         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC: MAC",
     393             :                     hmac, EAP_SIM_MAC_LEN);
     394          42 :         os_free(tmp);
     395             : 
     396          42 :         return (os_memcmp_const(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
     397             : }
     398             : 
     399             : 
     400          42 : 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          42 :         addr[0] = msg;
     408          42 :         len[0] = msg_len;
     409          42 :         addr[1] = extra;
     410          42 :         len[1] = extra_len;
     411             : 
     412             :         /* HMAC-SHA-256-128 */
     413          42 :         os_memset(mac, 0, EAP_SIM_MAC_LEN);
     414          42 :         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - msg", msg, msg_len);
     415          42 :         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - extra data",
     416             :                     extra, extra_len);
     417          42 :         wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Add MAC - K_aut",
     418             :                         k_aut, EAP_AKA_PRIME_K_AUT_LEN);
     419          42 :         hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
     420          42 :         os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
     421          42 :         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC: MAC",
     422             :                     mac, EAP_SIM_MAC_LEN);
     423          42 : }
     424             : 
     425             : 
     426          27 : 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          27 :         fc = 0x20;
     458             : 
     459          27 :         wpa_printf(MSG_DEBUG, "EAP-AKA': Derive (CK',IK') from (CK,IK)");
     460          27 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK", ck, EAP_AKA_CK_LEN);
     461          27 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK", ik, EAP_AKA_IK_LEN);
     462          27 :         wpa_printf(MSG_DEBUG, "EAP-AKA': FC = 0x%x", fc);
     463          27 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': P0 = Access network identity",
     464             :                           network_name, network_name_len);
     465          27 :         wpa_hexdump(MSG_DEBUG, "EAP-AKA': P1 = SQN xor AK", sqn_ak, 6);
     466             : 
     467          27 :         os_memcpy(key, ck, EAP_AKA_CK_LEN);
     468          27 :         os_memcpy(key + EAP_AKA_CK_LEN, ik, EAP_AKA_IK_LEN);
     469          27 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': Key = CK || IK",
     470             :                         key, sizeof(key));
     471             : 
     472          27 :         addr[0] = &fc;
     473          27 :         len[0] = 1;
     474          27 :         addr[1] = network_name;
     475          27 :         len[1] = network_name_len;
     476          27 :         WPA_PUT_BE16(l0, network_name_len);
     477          27 :         addr[2] = l0;
     478          27 :         len[2] = 2;
     479          27 :         addr[3] = sqn_ak;
     480          27 :         len[3] = 6;
     481          27 :         WPA_PUT_BE16(l1, 6);
     482          27 :         addr[4] = l1;
     483          27 :         len[4] = 2;
     484             : 
     485          27 :         hmac_sha256_vector(key, sizeof(key), 5, addr, len, hash);
     486          27 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': KDF output (CK' || IK')",
     487             :                         hash, sizeof(hash));
     488             : 
     489          27 :         os_memcpy(ck, hash, EAP_AKA_CK_LEN);
     490          27 :         os_memcpy(ik, hash + EAP_AKA_CK_LEN, EAP_AKA_IK_LEN);
     491          27 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK'", ck, EAP_AKA_CK_LEN);
     492          27 :         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK'", ik, EAP_AKA_IK_LEN);
     493          27 : }
     494             : #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
     495             : 
     496             : 
     497         714 : int eap_sim_parse_attr(const u8 *start, const u8 *end,
     498             :                        struct eap_sim_attrs *attr, int aka, int encr)
     499             : {
     500         714 :         const u8 *pos = start, *apos;
     501             :         size_t alen, plen, i, list_len;
     502             : 
     503         714 :         os_memset(attr, 0, sizeof(*attr));
     504         714 :         attr->id_req = NO_ID_REQ;
     505         714 :         attr->notification = -1;
     506         714 :         attr->counter = -1;
     507         714 :         attr->selected_version = -1;
     508         714 :         attr->client_error_code = -1;
     509             : 
     510        3318 :         while (pos < end) {
     511        1926 :                 if (pos + 2 > end) {
     512           1 :                         wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
     513           1 :                         return -1;
     514             :                 }
     515        3850 :                 wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
     516        3850 :                            pos[0], pos[1] * 4);
     517        1925 :                 if (pos + pos[1] * 4 > end) {
     518           1 :                         wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
     519             :                                    "(pos=%p len=%d end=%p)",
     520           1 :                                    pos, pos[1] * 4, end);
     521           1 :                         return -1;
     522             :                 }
     523        1924 :                 if (pos[1] == 0) {
     524           1 :                         wpa_printf(MSG_INFO, "EAP-SIM: Attribute underflow");
     525           1 :                         return -1;
     526             :                 }
     527        1923 :                 apos = pos + 2;
     528        1923 :                 alen = pos[1] * 4 - 2;
     529        1923 :                 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
     530             :                             apos, alen);
     531             : 
     532        1923 :                 switch (pos[0]) {
     533             :                 case EAP_SIM_AT_RAND:
     534         112 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
     535         112 :                         apos += 2;
     536         112 :                         alen -= 2;
     537         112 :                         if ((!aka && (alen % GSM_RAND_LEN)) ||
     538          65 :                             (aka && alen != EAP_AKA_RAND_LEN)) {
     539           1 :                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
     540             :                                            " (len %lu)",
     541             :                                            (unsigned long) alen);
     542           1 :                                 return -1;
     543             :                         }
     544         111 :                         attr->rand = apos;
     545         111 :                         attr->num_chal = alen / GSM_RAND_LEN;
     546         111 :                         break;
     547             :                 case EAP_SIM_AT_AUTN:
     548          66 :                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
     549          66 :                         if (!aka) {
     550           1 :                                 wpa_printf(MSG_DEBUG, "EAP-SIM: "
     551             :                                            "Unexpected AT_AUTN");
     552           1 :                                 return -1;
     553             :                         }
     554          65 :                         apos += 2;
     555          65 :                         alen -= 2;
     556          65 :                         if (alen != EAP_AKA_AUTN_LEN) {
     557           1 :                                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
     558             :                                            " (len %lu)",
     559             :                                            (unsigned long) alen);
     560           1 :                                 return -1;
     561             :                         }
     562          64 :                         attr->autn = apos;
     563          64 :                         break;
     564             :                 case EAP_SIM_AT_PADDING:
     565          89 :                         if (!encr) {
     566           1 :                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
     567             :                                            "AT_PADDING");
     568           1 :                                 return -1;
     569             :                         }
     570          88 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
     571         572 :                         for (i = 2; i < alen; i++) {
     572         484 :                                 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          88 :                         break;
     583             :                 case EAP_SIM_AT_NONCE_MT:
     584          71 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
     585          71 :                         if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
     586           1 :                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
     587             :                                            "AT_NONCE_MT length");
     588           1 :                                 return -1;
     589             :                         }
     590          70 :                         attr->nonce_mt = apos + 2;
     591          70 :                         break;
     592             :                 case EAP_SIM_AT_PERMANENT_ID_REQ:
     593           9 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
     594           9 :                         attr->id_req = PERMANENT_ID;
     595           9 :                         break;
     596             :                 case EAP_SIM_AT_MAC:
     597         216 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
     598         216 :                         if (alen != 2 + EAP_SIM_MAC_LEN) {
     599           1 :                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
     600             :                                            "length");
     601           1 :                                 return -1;
     602             :                         }
     603         215 :                         attr->mac = apos + 2;
     604         215 :                         break;
     605             :                 case EAP_SIM_AT_NOTIFICATION:
     606          21 :                         if (alen != 2) {
     607           1 :                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
     608             :                                            "AT_NOTIFICATION length %lu",
     609             :                                            (unsigned long) alen);
     610           1 :                                 return -1;
     611             :                         }
     612          20 :                         attr->notification = apos[0] * 256 + apos[1];
     613          20 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
     614             :                                    attr->notification);
     615          20 :                         break;
     616             :                 case EAP_SIM_AT_ANY_ID_REQ:
     617          93 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
     618          93 :                         attr->id_req = ANY_ID;
     619          93 :                         break;
     620             :                 case EAP_SIM_AT_IDENTITY:
     621         171 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
     622         171 :                         plen = WPA_GET_BE16(apos);
     623         171 :                         apos += 2;
     624         171 :                         alen -= 2;
     625         171 :                         if (plen > alen) {
     626           1 :                                 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           1 :                                 return -1;
     632             :                         }
     633             : 
     634         170 :                         attr->identity = apos;
     635         170 :                         attr->identity_len = plen;
     636         170 :                         break;
     637             :                 case EAP_SIM_AT_VERSION_LIST:
     638          59 :                         if (aka) {
     639           1 :                                 wpa_printf(MSG_DEBUG, "EAP-AKA: "
     640             :                                            "Unexpected AT_VERSION_LIST");
     641           1 :                                 return -1;
     642             :                         }
     643          58 :                         list_len = apos[0] * 256 + apos[1];
     644          58 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
     645          58 :                         if (list_len < 2 || list_len > alen - 2) {
     646           2 :                                 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           2 :                                 return -1;
     652             :                         }
     653          56 :                         attr->version_list = apos + 2;
     654          56 :                         attr->version_list_len = list_len;
     655          56 :                         break;
     656             :                 case EAP_SIM_AT_SELECTED_VERSION:
     657          71 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
     658          71 :                         if (alen != 2) {
     659           1 :                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
     660             :                                            "AT_SELECTED_VERSION length %lu",
     661             :                                            (unsigned long) alen);
     662           1 :                                 return -1;
     663             :                         }
     664          70 :                         attr->selected_version = apos[0] * 256 + apos[1];
     665          70 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
     666             :                                    "%d", attr->selected_version);
     667          70 :                         break;
     668             :                 case EAP_SIM_AT_FULLAUTH_ID_REQ:
     669          12 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
     670          12 :                         attr->id_req = FULLAUTH_ID;
     671          12 :                         break;
     672             :                 case EAP_SIM_AT_COUNTER:
     673          42 :                         if (!encr) {
     674           1 :                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
     675             :                                            "AT_COUNTER");
     676           1 :                                 return -1;
     677             :                         }
     678          41 :                         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          41 :                         attr->counter = apos[0] * 256 + apos[1];
     685          41 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
     686             :                                    attr->counter);
     687          41 :                         break;
     688             :                 case EAP_SIM_AT_COUNTER_TOO_SMALL:
     689           6 :                         if (!encr) {
     690           1 :                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
     691             :                                            "AT_COUNTER_TOO_SMALL");
     692           1 :                                 return -1;
     693             :                         }
     694           5 :                         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           5 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
     701             :                                    "AT_COUNTER_TOO_SMALL");
     702           5 :                         attr->counter_too_small = 1;
     703           5 :                         break;
     704             :                 case EAP_SIM_AT_NONCE_S:
     705          19 :                         if (!encr) {
     706           1 :                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
     707             :                                            "AT_NONCE_S");
     708           1 :                                 return -1;
     709             :                         }
     710          18 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
     711             :                                    "AT_NONCE_S");
     712          18 :                         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          18 :                         attr->nonce_s = apos + 2;
     719          18 :                         break;
     720             :                 case EAP_SIM_AT_CLIENT_ERROR_CODE:
     721          18 :                         if (alen != 2) {
     722           1 :                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
     723             :                                            "AT_CLIENT_ERROR_CODE length %lu",
     724             :                                            (unsigned long) alen);
     725           1 :                                 return -1;
     726             :                         }
     727          17 :                         attr->client_error_code = apos[0] * 256 + apos[1];
     728          17 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
     729             :                                    "%d", attr->client_error_code);
     730          17 :                         break;
     731             :                 case EAP_SIM_AT_IV:
     732         152 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
     733         152 :                         if (alen != 2 + EAP_SIM_MAC_LEN) {
     734           1 :                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
     735             :                                            "length %lu", (unsigned long) alen);
     736           1 :                                 return -1;
     737             :                         }
     738         151 :                         attr->iv = apos + 2;
     739         151 :                         break;
     740             :                 case EAP_SIM_AT_ENCR_DATA:
     741         152 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
     742         152 :                         attr->encr_data = apos + 2;
     743         152 :                         attr->encr_data_len = alen - 2;
     744         152 :                         if (attr->encr_data_len % 16) {
     745           1 :                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
     746             :                                            "AT_ENCR_DATA length %lu",
     747             :                                            (unsigned long)
     748             :                                            attr->encr_data_len);
     749           1 :                                 return -1;
     750             :                         }
     751         151 :                         break;
     752             :                 case EAP_SIM_AT_NEXT_PSEUDONYM:
     753          48 :                         if (!encr) {
     754           1 :                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
     755             :                                            "AT_NEXT_PSEUDONYM");
     756           1 :                                 return -1;
     757             :                         }
     758          47 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
     759             :                                    "AT_NEXT_PSEUDONYM");
     760          47 :                         plen = apos[0] * 256 + apos[1];
     761          47 :                         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          47 :                         attr->next_pseudonym = pos + 4;
     770          47 :                         attr->next_pseudonym_len = plen;
     771          47 :                         break;
     772             :                 case EAP_SIM_AT_NEXT_REAUTH_ID:
     773          63 :                         if (!encr) {
     774           1 :                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
     775             :                                            "AT_NEXT_REAUTH_ID");
     776           1 :                                 return -1;
     777             :                         }
     778          62 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
     779             :                                    "AT_NEXT_REAUTH_ID");
     780          62 :                         plen = apos[0] * 256 + apos[1];
     781          62 :                         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          62 :                         attr->next_reauth_id = pos + 4;
     790          62 :                         attr->next_reauth_id_len = plen;
     791          62 :                         break;
     792             :                 case EAP_SIM_AT_RES:
     793          29 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
     794          29 :                         attr->res_len_bits = WPA_GET_BE16(apos);
     795          29 :                         apos += 2;
     796          29 :                         alen -= 2;
     797          29 :                         if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
     798             :                             alen > EAP_AKA_MAX_RES_LEN) {
     799           2 :                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
     800             :                                            "(len %lu)",
     801             :                                            (unsigned long) alen);
     802           2 :                                 return -1;
     803             :                         }
     804          27 :                         attr->res = apos;
     805          27 :                         attr->res_len = alen;
     806          27 :                         break;
     807             :                 case EAP_SIM_AT_AUTS:
     808          12 :                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
     809          12 :                         if (!aka) {
     810           1 :                                 wpa_printf(MSG_DEBUG, "EAP-SIM: "
     811             :                                            "Unexpected AT_AUTS");
     812           1 :                                 return -1;
     813             :                         }
     814          11 :                         if (alen != EAP_AKA_AUTS_LEN) {
     815           1 :                                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
     816             :                                            " (len %lu)",
     817             :                                            (unsigned long) alen);
     818           1 :                                 return -1;
     819             :                         }
     820          10 :                         attr->auts = apos;
     821          10 :                         break;
     822             :                 case EAP_SIM_AT_CHECKCODE:
     823         121 :                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_CHECKCODE");
     824         121 :                         if (!aka) {
     825           1 :                                 wpa_printf(MSG_DEBUG, "EAP-SIM: "
     826             :                                            "Unexpected AT_CHECKCODE");
     827           1 :                                 return -1;
     828             :                         }
     829         120 :                         apos += 2;
     830         120 :                         alen -= 2;
     831         120 :                         if (alen != 0 && alen != EAP_AKA_CHECKCODE_LEN &&
     832             :                             alen != EAP_AKA_PRIME_CHECKCODE_LEN) {
     833           1 :                                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
     834             :                                            "AT_CHECKCODE (len %lu)",
     835             :                                            (unsigned long) alen);
     836           1 :                                 return -1;
     837             :                         }
     838         119 :                         attr->checkcode = apos;
     839         119 :                         attr->checkcode_len = alen;
     840         119 :                         break;
     841             :                 case EAP_SIM_AT_RESULT_IND:
     842         128 :                         if (encr) {
     843           0 :                                 wpa_printf(MSG_ERROR, "EAP-SIM: Encrypted "
     844             :                                            "AT_RESULT_IND");
     845           0 :                                 return -1;
     846             :                         }
     847         128 :                         if (alen != 2) {
     848           1 :                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
     849             :                                            "AT_RESULT_IND (alen=%lu)",
     850             :                                            (unsigned long) alen);
     851           1 :                                 return -1;
     852             :                         }
     853         127 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RESULT_IND");
     854         127 :                         attr->result_ind = 1;
     855         127 :                         break;
     856             : #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
     857             :                 case EAP_SIM_AT_KDF_INPUT:
     858          30 :                         if (aka != 2) {
     859           1 :                                 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
     860             :                                            "AT_KDF_INPUT");
     861           1 :                                 return -1;
     862             :                         }
     863             : 
     864          29 :                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF_INPUT");
     865          29 :                         plen = WPA_GET_BE16(apos);
     866          29 :                         apos += 2;
     867          29 :                         alen -= 2;
     868          29 :                         if (plen > alen) {
     869           1 :                                 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           1 :                                 return -1;
     875             :                         }
     876          28 :                         attr->kdf_input = apos;
     877          28 :                         attr->kdf_input_len = plen;
     878          28 :                         break;
     879             :                 case EAP_SIM_AT_KDF:
     880          62 :                         if (aka != 2) {
     881           1 :                                 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
     882             :                                            "AT_KDF");
     883           1 :                                 return -1;
     884             :                         }
     885             : 
     886          61 :                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF");
     887          61 :                         if (alen != 2) {
     888           1 :                                 wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
     889             :                                            "AT_KDF (len %lu)",
     890             :                                            (unsigned long) alen);
     891           1 :                                 return -1;
     892             :                         }
     893          60 :                         if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) {
     894           2 :                                 wpa_printf(MSG_DEBUG, "EAP-AKA': Too many "
     895             :                                            "AT_KDF attributes - ignore this");
     896           2 :                                 break;
     897             :                         }
     898          58 :                         attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos);
     899          58 :                         attr->kdf_count++;
     900          58 :                         break;
     901             :                 case EAP_SIM_AT_BIDDING:
     902          49 :                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_BIDDING");
     903          49 :                         if (alen != 2) {
     904           1 :                                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
     905             :                                            "AT_BIDDING (len %lu)",
     906             :                                            (unsigned long) alen);
     907           1 :                                 return -1;
     908             :                         }
     909          48 :                         attr->bidding = apos;
     910          48 :                         break;
     911             : #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
     912             :                 default:
     913           2 :                         if (pos[0] < 128) {
     914           1 :                                 wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
     915             :                                            "non-skippable attribute %d",
     916           1 :                                            pos[0]);
     917           1 :                                 return -1;
     918             :                         }
     919             : 
     920           1 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
     921           1 :                                    " attribute %d ignored", pos[0]);
     922           1 :                         break;
     923             :                 }
     924             : 
     925        1890 :                 pos += pos[1] * 4;
     926             :         }
     927             : 
     928         678 :         wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
     929             :                    "(aka=%d encr=%d)", aka, encr);
     930             : 
     931         678 :         return 0;
     932             : }
     933             : 
     934             : 
     935          88 : 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          88 :         if (!iv) {
     942           0 :                 wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
     943           0 :                 return NULL;
     944             :         }
     945             : 
     946          88 :         decrypted = os_malloc(encr_data_len);
     947          88 :         if (decrypted == NULL)
     948           0 :                 return NULL;
     949          88 :         os_memcpy(decrypted, encr_data, encr_data_len);
     950             : 
     951          88 :         if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) {
     952           0 :                 os_free(decrypted);
     953           0 :                 return NULL;
     954             :         }
     955          88 :         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
     956             :                     decrypted, encr_data_len);
     957             : 
     958          88 :         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          88 :         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             : };
     976             : 
     977             : 
     978         523 : struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
     979             : {
     980             :         struct eap_sim_msg *msg;
     981             :         struct eap_hdr *eap;
     982             :         u8 *pos;
     983             : 
     984         523 :         msg = os_zalloc(sizeof(*msg));
     985         523 :         if (msg == NULL)
     986           0 :                 return NULL;
     987             : 
     988         523 :         msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN);
     989         523 :         if (msg->buf == NULL) {
     990           0 :                 os_free(msg);
     991           0 :                 return NULL;
     992             :         }
     993         523 :         eap = wpabuf_put(msg->buf, sizeof(*eap));
     994         523 :         eap->code = code;
     995         523 :         eap->identifier = id;
     996             : 
     997         523 :         pos = wpabuf_put(msg->buf, 4);
     998         523 :         *pos++ = type;
     999         523 :         *pos++ = subtype;
    1000         523 :         *pos++ = 0; /* Reserved */
    1001         523 :         *pos++ = 0; /* Reserved */
    1002             : 
    1003         523 :         return msg;
    1004             : }
    1005             : 
    1006             : 
    1007         523 : struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type,
    1008             :                                    const u8 *k_aut,
    1009             :                                    const u8 *extra, size_t extra_len)
    1010             : {
    1011             :         struct eap_hdr *eap;
    1012             :         struct wpabuf *buf;
    1013             : 
    1014         523 :         if (msg == NULL)
    1015           0 :                 return NULL;
    1016             : 
    1017         523 :         eap = wpabuf_mhead(msg->buf);
    1018         523 :         eap->length = host_to_be16(wpabuf_len(msg->buf));
    1019             : 
    1020             : #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
    1021         523 :         if (k_aut && msg->mac && type == EAP_TYPE_AKA_PRIME) {
    1022          84 :                 eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf),
    1023          42 :                                        wpabuf_len(msg->buf),
    1024          42 :                                        (u8 *) wpabuf_mhead(msg->buf) +
    1025             :                                        msg->mac, extra, extra_len);
    1026             :         } else
    1027             : #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
    1028         481 :         if (k_aut && msg->mac) {
    1029         280 :                 eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf),
    1030         140 :                                 wpabuf_len(msg->buf),
    1031         140 :                                 (u8 *) wpabuf_mhead(msg->buf) + msg->mac,
    1032             :                                 extra, extra_len);
    1033             :         }
    1034             : 
    1035         523 :         buf = msg->buf;
    1036         523 :         os_free(msg);
    1037         523 :         return buf;
    1038             : }
    1039             : 
    1040             : 
    1041           0 : void eap_sim_msg_free(struct eap_sim_msg *msg)
    1042             : {
    1043           0 :         if (msg) {
    1044           0 :                 wpabuf_free(msg->buf);
    1045           0 :                 os_free(msg);
    1046             :         }
    1047           0 : }
    1048             : 
    1049             : 
    1050           5 : u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
    1051             :                           const u8 *data, size_t len)
    1052             : {
    1053           5 :         int attr_len = 2 + len;
    1054             :         int pad_len;
    1055             :         u8 *start;
    1056             : 
    1057           5 :         if (msg == NULL)
    1058           0 :                 return NULL;
    1059             : 
    1060           5 :         pad_len = (4 - attr_len % 4) % 4;
    1061           5 :         attr_len += pad_len;
    1062           5 :         if (wpabuf_resize(&msg->buf, attr_len))
    1063           0 :                 return NULL;
    1064           5 :         start = wpabuf_put(msg->buf, 0);
    1065           5 :         wpabuf_put_u8(msg->buf, attr);
    1066           5 :         wpabuf_put_u8(msg->buf, attr_len / 4);
    1067           5 :         wpabuf_put_data(msg->buf, data, len);
    1068           5 :         if (pad_len)
    1069           0 :                 os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
    1070           5 :         return start;
    1071             : }
    1072             : 
    1073             : 
    1074        1687 : u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
    1075             :                      const u8 *data, size_t len)
    1076             : {
    1077        1687 :         int attr_len = 4 + len;
    1078             :         int pad_len;
    1079             :         u8 *start;
    1080             : 
    1081        1687 :         if (msg == NULL)
    1082           0 :                 return NULL;
    1083             : 
    1084        1687 :         pad_len = (4 - attr_len % 4) % 4;
    1085        1687 :         attr_len += pad_len;
    1086        1687 :         if (wpabuf_resize(&msg->buf, attr_len))
    1087           0 :                 return NULL;
    1088        1687 :         start = wpabuf_put(msg->buf, 0);
    1089        1687 :         wpabuf_put_u8(msg->buf, attr);
    1090        1687 :         wpabuf_put_u8(msg->buf, attr_len / 4);
    1091        1687 :         wpabuf_put_be16(msg->buf, value);
    1092        1687 :         if (data)
    1093         649 :                 wpabuf_put_data(msg->buf, data, len);
    1094             :         else
    1095        1038 :                 wpabuf_put(msg->buf, len);
    1096        1687 :         if (pad_len)
    1097         265 :                 os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
    1098        1687 :         return start;
    1099             : }
    1100             : 
    1101             : 
    1102         182 : u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
    1103             : {
    1104         182 :         u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
    1105         182 :         if (pos)
    1106         182 :                 msg->mac = (pos - wpabuf_head_u8(msg->buf)) + 4;
    1107         182 :         return pos;
    1108             : }
    1109             : 
    1110             : 
    1111         128 : int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
    1112             :                                u8 attr_encr)
    1113             : {
    1114         128 :         u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
    1115         128 :         if (pos == NULL)
    1116           0 :                 return -1;
    1117         128 :         msg->iv = (pos - wpabuf_head_u8(msg->buf)) + 4;
    1118         128 :         if (random_get_bytes(wpabuf_mhead_u8(msg->buf) + msg->iv,
    1119             :                              EAP_SIM_IV_LEN)) {
    1120           0 :                 msg->iv = 0;
    1121           0 :                 return -1;
    1122             :         }
    1123             : 
    1124         128 :         pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
    1125         128 :         if (pos == NULL) {
    1126           0 :                 msg->iv = 0;
    1127           0 :                 return -1;
    1128             :         }
    1129         128 :         msg->encr = pos - wpabuf_head_u8(msg->buf);
    1130             : 
    1131         128 :         return 0;
    1132             : }
    1133             : 
    1134             : 
    1135         128 : int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
    1136             : {
    1137             :         size_t encr_len;
    1138             : 
    1139         128 :         if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
    1140           0 :                 return -1;
    1141             : 
    1142         128 :         encr_len = wpabuf_len(msg->buf) - msg->encr - 4;
    1143         128 :         if (encr_len % 16) {
    1144             :                 u8 *pos;
    1145         128 :                 int pad_len = 16 - (encr_len % 16);
    1146         128 :                 if (pad_len < 4) {
    1147           0 :                         wpa_printf(MSG_WARNING, "EAP-SIM: "
    1148             :                                    "eap_sim_msg_add_encr_end - invalid pad_len"
    1149             :                                    " %d", pad_len);
    1150           0 :                         return -1;
    1151             :                 }
    1152         128 :                 wpa_printf(MSG_DEBUG, "   *AT_PADDING");
    1153         128 :                 pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
    1154         128 :                 if (pos == NULL)
    1155           0 :                         return -1;
    1156         128 :                 os_memset(pos + 4, 0, pad_len - 4);
    1157         128 :                 encr_len += pad_len;
    1158             :         }
    1159         128 :         wpa_printf(MSG_DEBUG, "   (AT_ENCR_DATA data len %lu)",
    1160             :                    (unsigned long) encr_len);
    1161         128 :         wpabuf_mhead_u8(msg->buf)[msg->encr + 1] = encr_len / 4 + 1;
    1162         128 :         return aes_128_cbc_encrypt(k_encr, wpabuf_head_u8(msg->buf) + msg->iv,
    1163         128 :                                    wpabuf_mhead_u8(msg->buf) + msg->encr + 4,
    1164             :                                    encr_len);
    1165             : }
    1166             : 
    1167             : 
    1168          14 : void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
    1169             : {
    1170             : #ifndef CONFIG_NO_STDOUT_DEBUG
    1171          14 :         const char *type = aka ? "AKA" : "SIM";
    1172             : #endif /* CONFIG_NO_STDOUT_DEBUG */
    1173             : 
    1174          14 :         switch (notification) {
    1175             :         case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
    1176           0 :                 wpa_printf(MSG_WARNING, "EAP-%s: General failure "
    1177             :                            "notification (after authentication)", type);
    1178           0 :                 break;
    1179             :         case EAP_SIM_TEMPORARILY_DENIED:
    1180           0 :                 wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
    1181             :                            "User has been temporarily denied access to the "
    1182             :                            "requested service", type);
    1183           0 :                 break;
    1184             :         case EAP_SIM_NOT_SUBSCRIBED:
    1185           0 :                 wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
    1186             :                            "User has not subscribed to the requested service",
    1187             :                            type);
    1188           0 :                 break;
    1189             :         case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
    1190           3 :                 wpa_printf(MSG_WARNING, "EAP-%s: General failure "
    1191             :                            "notification (before authentication)", type);
    1192           3 :                 break;
    1193             :         case EAP_SIM_SUCCESS:
    1194           7 :                 wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
    1195             :                            "notification", type);
    1196           7 :                 break;
    1197             :         default:
    1198           4 :                 if (notification >= 32768) {
    1199           2 :                         wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
    1200             :                                    "non-failure notification %d",
    1201             :                                    type, notification);
    1202             :                 } else {
    1203           2 :                         wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
    1204             :                                    "failure notification %d",
    1205             :                                    type, notification);
    1206             :                 }
    1207             :         }
    1208          14 : }

Generated by: LCOV version 1.10