LCOV - code coverage report
Current view: top level - src/rsn_supp - wpa_ie.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1426431149 Lines: 300 343 87.5 %
Date: 2015-03-15 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :  * wpa_supplicant - WPA/RSN IE and KDE processing
       3             :  * Copyright (c) 2003-2015, 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 "wpa.h"
      13             : #include "pmksa_cache.h"
      14             : #include "common/ieee802_11_defs.h"
      15             : #include "wpa_i.h"
      16             : #include "wpa_ie.h"
      17             : 
      18             : 
      19             : /**
      20             :  * wpa_parse_wpa_ie - Parse WPA/RSN IE
      21             :  * @wpa_ie: Pointer to WPA or RSN IE
      22             :  * @wpa_ie_len: Length of the WPA/RSN IE
      23             :  * @data: Pointer to data area for parsing results
      24             :  * Returns: 0 on success, -1 on failure
      25             :  *
      26             :  * Parse the contents of WPA or RSN IE and write the parsed data into data.
      27             :  */
      28        5372 : int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
      29             :                      struct wpa_ie_data *data)
      30             : {
      31        5372 :         if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
      32        5268 :                 return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
      33             :         else
      34         104 :                 return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
      35             : }
      36             : 
      37             : 
      38          24 : static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
      39             :                               int pairwise_cipher, int group_cipher,
      40             :                               int key_mgmt)
      41             : {
      42             :         u8 *pos;
      43             :         struct wpa_ie_hdr *hdr;
      44             :         u32 suite;
      45             : 
      46          24 :         if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
      47             :             2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
      48           0 :                 return -1;
      49             : 
      50          24 :         hdr = (struct wpa_ie_hdr *) wpa_ie;
      51          24 :         hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
      52          24 :         RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
      53          24 :         WPA_PUT_LE16(hdr->version, WPA_VERSION);
      54          24 :         pos = (u8 *) (hdr + 1);
      55             : 
      56          24 :         suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
      57          24 :         if (suite == 0) {
      58           0 :                 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
      59             :                            group_cipher);
      60           0 :                 return -1;
      61             :         }
      62          24 :         RSN_SELECTOR_PUT(pos, suite);
      63          24 :         pos += WPA_SELECTOR_LEN;
      64             : 
      65          24 :         *pos++ = 1;
      66          24 :         *pos++ = 0;
      67          24 :         suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher);
      68          48 :         if (suite == 0 ||
      69          24 :             (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
      70             :              pairwise_cipher != WPA_CIPHER_NONE)) {
      71           0 :                 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
      72             :                            pairwise_cipher);
      73           0 :                 return -1;
      74             :         }
      75          24 :         RSN_SELECTOR_PUT(pos, suite);
      76          24 :         pos += WPA_SELECTOR_LEN;
      77             : 
      78          24 :         *pos++ = 1;
      79          24 :         *pos++ = 0;
      80          24 :         if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
      81           2 :                 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
      82          22 :         } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
      83          17 :                 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
      84           5 :         } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
      85           5 :                 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
      86           0 :         } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
      87           0 :                 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
      88             :         } else {
      89           0 :                 wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
      90             :                            key_mgmt);
      91           0 :                 return -1;
      92             :         }
      93          24 :         pos += WPA_SELECTOR_LEN;
      94             : 
      95             :         /* WPA Capabilities; use defaults, so no need to include it */
      96             : 
      97          24 :         hdr->len = (pos - wpa_ie) - 2;
      98             : 
      99             :         WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
     100             : 
     101          24 :         return pos - wpa_ie;
     102             : }
     103             : 
     104             : 
     105        1884 : static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
     106             :                               int pairwise_cipher, int group_cipher,
     107             :                               int key_mgmt, int mgmt_group_cipher,
     108             :                               struct wpa_sm *sm)
     109             : {
     110             :         u8 *pos;
     111             :         struct rsn_ie_hdr *hdr;
     112             :         u16 capab;
     113             :         u32 suite;
     114             : 
     115        1884 :         if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
     116        1884 :             2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
     117        1884 :             (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
     118           0 :                 wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
     119             :                            (unsigned long) rsn_ie_len);
     120           0 :                 return -1;
     121             :         }
     122             : 
     123        1884 :         hdr = (struct rsn_ie_hdr *) rsn_ie;
     124        1884 :         hdr->elem_id = WLAN_EID_RSN;
     125        1884 :         WPA_PUT_LE16(hdr->version, RSN_VERSION);
     126        1884 :         pos = (u8 *) (hdr + 1);
     127             : 
     128        1884 :         suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
     129        1884 :         if (suite == 0) {
     130           0 :                 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
     131             :                            group_cipher);
     132           0 :                 return -1;
     133             :         }
     134        1884 :         RSN_SELECTOR_PUT(pos, suite);
     135        1884 :         pos += RSN_SELECTOR_LEN;
     136             : 
     137        1884 :         *pos++ = 1;
     138        1884 :         *pos++ = 0;
     139        1884 :         suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
     140        3768 :         if (suite == 0 ||
     141        1884 :             (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
     142             :              pairwise_cipher != WPA_CIPHER_NONE)) {
     143           0 :                 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
     144             :                            pairwise_cipher);
     145           0 :                 return -1;
     146             :         }
     147        1884 :         RSN_SELECTOR_PUT(pos, suite);
     148        1884 :         pos += RSN_SELECTOR_LEN;
     149             : 
     150        1884 :         *pos++ = 1;
     151        1884 :         *pos++ = 0;
     152        1884 :         if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
     153         997 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
     154         887 :         } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
     155         654 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
     156         233 :         } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
     157           0 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
     158             : #ifdef CONFIG_IEEE80211R
     159         233 :         } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
     160           8 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
     161         225 :         } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
     162         125 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
     163             : #endif /* CONFIG_IEEE80211R */
     164             : #ifdef CONFIG_IEEE80211W
     165         100 :         } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
     166           4 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
     167          96 :         } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
     168          22 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
     169             : #endif /* CONFIG_IEEE80211W */
     170             : #ifdef CONFIG_SAE
     171          74 :         } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
     172          62 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
     173          12 :         } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
     174           8 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
     175             : #endif /* CONFIG_SAE */
     176           4 :         } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
     177           2 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
     178           2 :         } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
     179           2 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
     180             :         } else {
     181           0 :                 wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
     182             :                            key_mgmt);
     183           0 :                 return -1;
     184             :         }
     185        1884 :         pos += RSN_SELECTOR_LEN;
     186             : 
     187             :         /* RSN Capabilities */
     188        1884 :         capab = 0;
     189             : #ifdef CONFIG_IEEE80211W
     190        1884 :         if (sm->mfp)
     191         344 :                 capab |= WPA_CAPABILITY_MFPC;
     192        1884 :         if (sm->mfp == 2)
     193          23 :                 capab |= WPA_CAPABILITY_MFPR;
     194             : #endif /* CONFIG_IEEE80211W */
     195        1884 :         WPA_PUT_LE16(pos, capab);
     196        1884 :         pos += 2;
     197             : 
     198        1884 :         if (sm->cur_pmksa) {
     199             :                 /* PMKID Count (2 octets, little endian) */
     200          73 :                 *pos++ = 1;
     201          73 :                 *pos++ = 0;
     202             :                 /* PMKID */
     203          73 :                 os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
     204          73 :                 pos += PMKID_LEN;
     205             :         }
     206             : 
     207             : #ifdef CONFIG_IEEE80211W
     208        1884 :         if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
     209          48 :                 if (!sm->cur_pmksa) {
     210             :                         /* PMKID Count */
     211          46 :                         WPA_PUT_LE16(pos, 0);
     212          46 :                         pos += 2;
     213             :                 }
     214             : 
     215             :                 /* Management Group Cipher Suite */
     216          48 :                 RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
     217             :                                                           mgmt_group_cipher));
     218          48 :                 pos += RSN_SELECTOR_LEN;
     219             :         }
     220             : #endif /* CONFIG_IEEE80211W */
     221             : 
     222        1884 :         hdr->len = (pos - rsn_ie) - 2;
     223             : 
     224             :         WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
     225             : 
     226        1884 :         return pos - rsn_ie;
     227             : }
     228             : 
     229             : 
     230             : #ifdef CONFIG_HS20
     231           2 : static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len,
     232             :                                int pairwise_cipher, int group_cipher,
     233             :                                int key_mgmt)
     234             : {
     235             :         u8 *pos, *len;
     236             :         u32 suite;
     237             : 
     238           2 :         if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN +
     239             :             2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN)
     240           0 :                 return -1;
     241             : 
     242           2 :         pos = wpa_ie;
     243           2 :         *pos++ = WLAN_EID_VENDOR_SPECIFIC;
     244           2 :         len = pos++; /* to be filled */
     245           2 :         WPA_PUT_BE24(pos, OUI_WFA);
     246           2 :         pos += 3;
     247           2 :         *pos++ = HS20_OSEN_OUI_TYPE;
     248             : 
     249             :         /* Group Data Cipher Suite */
     250           2 :         suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
     251           2 :         if (suite == 0) {
     252           0 :                 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
     253             :                            group_cipher);
     254           0 :                 return -1;
     255             :         }
     256           2 :         RSN_SELECTOR_PUT(pos, suite);
     257           2 :         pos += RSN_SELECTOR_LEN;
     258             : 
     259             :         /* Pairwise Cipher Suite Count and List */
     260           2 :         WPA_PUT_LE16(pos, 1);
     261           2 :         pos += 2;
     262           2 :         suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
     263           4 :         if (suite == 0 ||
     264           2 :             (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
     265             :              pairwise_cipher != WPA_CIPHER_NONE)) {
     266           0 :                 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
     267             :                            pairwise_cipher);
     268           0 :                 return -1;
     269             :         }
     270           2 :         RSN_SELECTOR_PUT(pos, suite);
     271           2 :         pos += RSN_SELECTOR_LEN;
     272             : 
     273             :         /* AKM Suite Count and List */
     274           2 :         WPA_PUT_LE16(pos, 1);
     275           2 :         pos += 2;
     276           2 :         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
     277           2 :         pos += RSN_SELECTOR_LEN;
     278             : 
     279           2 :         *len = pos - len - 1;
     280             : 
     281             :         WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
     282             : 
     283           2 :         return pos - wpa_ie;
     284             : }
     285             : #endif /* CONFIG_HS20 */
     286             : 
     287             : 
     288             : /**
     289             :  * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
     290             :  * @sm: Pointer to WPA state machine data from wpa_sm_init()
     291             :  * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
     292             :  * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
     293             :  * Returns: Length of the generated WPA/RSN IE or -1 on failure
     294             :  */
     295        1910 : int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
     296             : {
     297        1910 :         if (sm->proto == WPA_PROTO_RSN)
     298        7536 :                 return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
     299        1884 :                                           sm->pairwise_cipher,
     300        1884 :                                           sm->group_cipher,
     301        3768 :                                           sm->key_mgmt, sm->mgmt_group_cipher,
     302             :                                           sm);
     303             : #ifdef CONFIG_HS20
     304          26 :         else if (sm->proto == WPA_PROTO_OSEN)
     305           6 :                 return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len,
     306           2 :                                            sm->pairwise_cipher,
     307           2 :                                            sm->group_cipher,
     308           2 :                                            sm->key_mgmt);
     309             : #endif /* CONFIG_HS20 */
     310             :         else
     311          72 :                 return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
     312          24 :                                           sm->pairwise_cipher,
     313          24 :                                           sm->group_cipher,
     314          24 :                                           sm->key_mgmt);
     315             : }
     316             : 
     317             : 
     318             : /**
     319             :  * wpa_parse_vendor_specific - Parse Vendor Specific IEs
     320             :  * @pos: Pointer to the IE header
     321             :  * @end: Pointer to the end of the Key Data buffer
     322             :  * @ie: Pointer to parsed IE data
     323             :  * Returns: 0 on success, 1 if end mark is found, -1 on failure
     324             :  */
     325        9167 : static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
     326             :                                      struct wpa_eapol_ie_parse *ie)
     327             : {
     328             :         unsigned int oui;
     329             : 
     330        9167 :         if (pos[1] < 4) {
     331           0 :                 wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
     332           0 :                            pos[1]);
     333           0 :                 return 1;
     334             :         }
     335             : 
     336        9167 :         oui = WPA_GET_BE24(&pos[2]);
     337        9167 :         if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
     338        5124 :                 if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
     339          58 :                         ie->wmm = &pos[2];
     340          58 :                         ie->wmm_len = pos[1];
     341         116 :                         wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
     342          58 :                                     ie->wmm, ie->wmm_len);
     343        5066 :                 } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
     344        5066 :                         ie->wmm = &pos[2];
     345        5066 :                         ie->wmm_len = pos[1];
     346       10132 :                         wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
     347        5066 :                                     ie->wmm, ie->wmm_len);
     348             :                 }
     349             :         }
     350        9167 :         return 0;
     351             : }
     352             : 
     353             : 
     354             : /**
     355             :  * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
     356             :  * @pos: Pointer to the IE header
     357             :  * @end: Pointer to the end of the Key Data buffer
     358             :  * @ie: Pointer to parsed IE data
     359             :  * Returns: 0 on success, 1 if end mark is found, -1 on failure
     360             :  */
     361        9167 : static int wpa_parse_generic(const u8 *pos, const u8 *end,
     362             :                              struct wpa_eapol_ie_parse *ie)
     363             : {
     364        9167 :         if (pos[1] == 0)
     365           0 :                 return 1;
     366             : 
     367       17960 :         if (pos[1] >= 6 &&
     368        8901 :             RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
     369         216 :             pos[2 + WPA_SELECTOR_LEN] == 1 &&
     370         108 :             pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
     371         108 :                 ie->wpa_ie = pos;
     372         108 :                 ie->wpa_ie_len = pos[1] + 2;
     373         216 :                 wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
     374         108 :                             ie->wpa_ie, ie->wpa_ie_len);
     375         108 :                 return 0;
     376             :         }
     377             : 
     378       18118 :         if (pos + 1 + RSN_SELECTOR_LEN < end &&
     379       17454 :             pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
     380        8395 :             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
     381         655 :                 ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
     382         655 :                 wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
     383         655 :                             pos, pos[1] + 2);
     384         655 :                 return 0;
     385             :         }
     386             : 
     387       16434 :         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
     388        8030 :             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
     389        1342 :                 ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
     390        1342 :                 ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
     391        1342 :                 wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
     392        1342 :                                 pos, pos[1] + 2);
     393        1342 :                 return 0;
     394             :         }
     395             : 
     396       13750 :         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
     397        6688 :             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
     398           8 :                 ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
     399           8 :                 ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
     400           8 :                 wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
     401           8 :                             pos, pos[1] + 2);
     402           8 :                 return 0;
     403             :         }
     404             : 
     405             : #ifdef CONFIG_PEERKEY
     406       13734 :         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
     407        6680 :             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
     408           2 :                 ie->smk = pos + 2 + RSN_SELECTOR_LEN;
     409           2 :                 ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
     410           2 :                 wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key",
     411           2 :                                 pos, pos[1] + 2);
     412           2 :                 return 0;
     413             :         }
     414             : 
     415       13730 :         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
     416        6678 :             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
     417           2 :                 ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
     418           2 :                 ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
     419           2 :                 wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key",
     420           2 :                             pos, pos[1] + 2);
     421           2 :                 return 0;
     422             :         }
     423             : 
     424       13726 :         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
     425        6676 :             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
     426           4 :                 ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
     427           4 :                 ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
     428           4 :                 wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key",
     429           4 :                             pos, pos[1] + 2);
     430           4 :                 return 0;
     431             :         }
     432             : 
     433       13718 :         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
     434        6672 :             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
     435           3 :                 ie->error = pos + 2 + RSN_SELECTOR_LEN;
     436           3 :                 ie->error_len = pos[1] - RSN_SELECTOR_LEN;
     437           3 :                 wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key",
     438           3 :                             pos, pos[1] + 2);
     439           3 :                 return 0;
     440             :         }
     441             : #endif /* CONFIG_PEERKEY */
     442             : 
     443             : #ifdef CONFIG_IEEE80211W
     444       13712 :         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
     445        6669 :             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
     446          46 :                 ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
     447          46 :                 ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
     448          46 :                 wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
     449          46 :                                 pos, pos[1] + 2);
     450          46 :                 return 0;
     451             :         }
     452             : #endif /* CONFIG_IEEE80211W */
     453             : 
     454             : #ifdef CONFIG_P2P
     455       13620 :         if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
     456        6623 :             RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
     457           0 :                 ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
     458           0 :                 wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
     459           0 :                             ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
     460           0 :                 return 0;
     461             :         }
     462             : 
     463       13442 :         if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
     464        6445 :             RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
     465          72 :                 ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
     466         144 :                 wpa_hexdump(MSG_DEBUG,
     467             :                             "WPA: IP Address Allocation in EAPOL-Key",
     468         144 :                             ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
     469          72 :                 return 0;
     470             :         }
     471             : #endif /* CONFIG_P2P */
     472             : 
     473        6925 :         return 0;
     474             : }
     475             : 
     476             : 
     477             : /**
     478             :  * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
     479             :  * @buf: Pointer to the Key Data buffer
     480             :  * @len: Key Data Length
     481             :  * @ie: Pointer to parsed IE data
     482             :  * Returns: 0 on success, -1 on failure
     483             :  */
     484        7903 : int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
     485             :                              struct wpa_eapol_ie_parse *ie)
     486             : {
     487             :         const u8 *pos, *end;
     488        7903 :         int ret = 0;
     489             : 
     490        7903 :         os_memset(ie, 0, sizeof(*ie));
     491       56980 :         for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
     492       60758 :                 if (pos[0] == 0xdd &&
     493       20846 :                     ((pos == buf + len - 1) || pos[1] == 0)) {
     494             :                         /* Ignore padding */
     495             :                         break;
     496             :                 }
     497       49079 :                 if (pos + 2 + pos[1] > end) {
     498           6 :                         wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
     499             :                                    "underflow (ie=%d len=%d pos=%d)",
     500           6 :                                    pos[0], pos[1], (int) (pos - buf));
     501           2 :                         wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
     502             :                                         buf, len);
     503           2 :                         ret = -1;
     504           2 :                         break;
     505             :                 }
     506       49077 :                 if (*pos == WLAN_EID_RSN) {
     507        3725 :                         ie->rsn_ie = pos;
     508        3725 :                         ie->rsn_ie_len = pos[1] + 2;
     509        7450 :                         wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
     510        3725 :                                     ie->rsn_ie, ie->rsn_ie_len);
     511       45352 :                 } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
     512         419 :                         ie->mdie = pos;
     513         419 :                         ie->mdie_len = pos[1] + 2;
     514         838 :                         wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
     515         419 :                                     ie->mdie, ie->mdie_len);
     516       44933 :                 } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
     517         354 :                         ie->ftie = pos;
     518         354 :                         ie->ftie_len = pos[1] + 2;
     519         708 :                         wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
     520         354 :                                     ie->ftie, ie->ftie_len);
     521       44579 :                 } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
     522         230 :                         if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
     523          25 :                                 ie->reassoc_deadline = pos;
     524          50 :                                 wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
     525             :                                             "in EAPOL-Key",
     526          50 :                                             ie->reassoc_deadline, pos[1] + 2);
     527          90 :                         } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
     528          90 :                                 ie->key_lifetime = pos;
     529         180 :                                 wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
     530             :                                             "in EAPOL-Key",
     531         180 :                                             ie->key_lifetime, pos[1] + 2);
     532             :                         } else {
     533           0 :                                 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
     534             :                                             "EAPOL-Key Key Data IE",
     535           0 :                                             pos, 2 + pos[1]);
     536             :                         }
     537       44464 :                 } else if (*pos == WLAN_EID_LINK_ID) {
     538         110 :                         if (pos[1] >= 18) {
     539         110 :                                 ie->lnkid = pos;
     540         110 :                                 ie->lnkid_len = pos[1] + 2;
     541             :                         }
     542       44354 :                 } else if (*pos == WLAN_EID_EXT_CAPAB) {
     543        5113 :                         ie->ext_capab = pos;
     544        5113 :                         ie->ext_capab_len = pos[1] + 2;
     545       39241 :                 } else if (*pos == WLAN_EID_SUPP_RATES) {
     546        5113 :                         ie->supp_rates = pos;
     547        5113 :                         ie->supp_rates_len = pos[1] + 2;
     548       34128 :                 } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
     549        4261 :                         ie->ext_supp_rates = pos;
     550        4261 :                         ie->ext_supp_rates_len = pos[1] + 2;
     551       29867 :                 } else if (*pos == WLAN_EID_HT_CAP) {
     552        5033 :                         ie->ht_capabilities = pos + 2;
     553        5033 :                         ie->ht_capabilities_len = pos[1];
     554       24834 :                 } else if (*pos == WLAN_EID_VHT_AID) {
     555          57 :                         if (pos[1] >= 2)
     556          57 :                                 ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
     557       24777 :                 } else if (*pos == WLAN_EID_VHT_CAP) {
     558          86 :                         ie->vht_capabilities = pos + 2;
     559          86 :                         ie->vht_capabilities_len = pos[1];
     560       24691 :                 } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
     561           0 :                         ie->qosinfo = pos[2];
     562       24691 :                 } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
     563          58 :                         ie->supp_channels = pos + 2;
     564          58 :                         ie->supp_channels_len = pos[1];
     565       24633 :                 } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
     566             :                         /*
     567             :                          * The value of the Length field of the Supported
     568             :                          * Operating Classes element is between 2 and 253.
     569             :                          * Silently skip invalid elements to avoid interop
     570             :                          * issues when trying to use the value.
     571             :                          */
     572           0 :                         if (pos[1] >= 2 && pos[1] <= 253) {
     573           0 :                                 ie->supp_oper_classes = pos + 2;
     574           0 :                                 ie->supp_oper_classes_len = pos[1];
     575             :                         }
     576       24633 :                 } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
     577        9167 :                         ret = wpa_parse_generic(pos, end, ie);
     578        9167 :                         if (ret < 0)
     579           0 :                                 break;
     580        9167 :                         if (ret > 0) {
     581           0 :                                 ret = 0;
     582           0 :                                 break;
     583             :                         }
     584             : 
     585        9167 :                         ret = wpa_parse_vendor_specific(pos, end, ie);
     586        9167 :                         if (ret < 0)
     587           0 :                                 break;
     588        9167 :                         if (ret > 0) {
     589           0 :                                 ret = 0;
     590           0 :                                 break;
     591             :                         }
     592             :                 } else {
     593       15466 :                         wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
     594       15466 :                                     "Key Data IE", pos, 2 + pos[1]);
     595             :                 }
     596             :         }
     597             : 
     598        7903 :         return ret;
     599             : }

Generated by: LCOV version 1.10