Coverage Report

Created: 2025-04-24 06:18

/src/hostap/src/rsn_supp/wpa_ie.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * wpa_supplicant - WPA/RSN IE and KDE processing
3
 * Copyright (c) 2003-2018, 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
int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
29
         struct wpa_ie_data *data)
30
0
{
31
0
  if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
32
0
    return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
33
0
  if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
34
0
      wpa_ie[1] >= 4 &&
35
0
      WPA_GET_BE32(&wpa_ie[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE)
36
0
    return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
37
0
  if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
38
0
      wpa_ie[1] >= 4 &&
39
0
      WPA_GET_BE32(&wpa_ie[2]) == RSNE_OVERRIDE_2_IE_VENDOR_TYPE)
40
0
    return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
41
0
  return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
42
0
}
43
44
45
static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
46
            int pairwise_cipher, int group_cipher,
47
            int key_mgmt)
48
0
{
49
0
  u8 *pos;
50
0
  struct wpa_ie_hdr *hdr;
51
0
  u32 suite;
52
53
0
  if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
54
0
      2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
55
0
    return -1;
56
57
0
  hdr = (struct wpa_ie_hdr *) wpa_ie;
58
0
  hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
59
0
  RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
60
0
  WPA_PUT_LE16(hdr->version, WPA_VERSION);
61
0
  pos = (u8 *) (hdr + 1);
62
63
0
  suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
64
0
  if (suite == 0) {
65
0
    wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
66
0
         group_cipher);
67
0
    return -1;
68
0
  }
69
0
  RSN_SELECTOR_PUT(pos, suite);
70
0
  pos += WPA_SELECTOR_LEN;
71
72
0
  *pos++ = 1;
73
0
  *pos++ = 0;
74
0
  suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher);
75
0
  if (suite == 0 ||
76
0
      (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
77
0
       pairwise_cipher != WPA_CIPHER_NONE)) {
78
0
    wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
79
0
         pairwise_cipher);
80
0
    return -1;
81
0
  }
82
0
  RSN_SELECTOR_PUT(pos, suite);
83
0
  pos += WPA_SELECTOR_LEN;
84
85
0
  *pos++ = 1;
86
0
  *pos++ = 0;
87
0
  if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
88
0
    RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
89
0
  } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
90
0
    RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
91
0
  } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
92
0
    RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
93
0
  } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
94
0
    RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
95
0
  } else {
96
0
    wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
97
0
         key_mgmt);
98
0
    return -1;
99
0
  }
100
0
  pos += WPA_SELECTOR_LEN;
101
102
  /* WPA Capabilities; use defaults, so no need to include it */
103
104
0
  hdr->len = (pos - wpa_ie) - 2;
105
106
0
  WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
107
108
0
  return pos - wpa_ie;
109
0
}
110
111
112
u16 rsn_supp_capab(struct wpa_sm *sm)
113
1.96k
{
114
1.96k
  u16 capab = 0;
115
116
1.96k
  if (sm->wmm_enabled) {
117
    /* Advertise 16 PTKSA replay counters when using WMM */
118
0
    capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2;
119
0
  }
120
1.96k
  if (sm->mfp)
121
0
    capab |= WPA_CAPABILITY_MFPC;
122
1.96k
  if (sm->mfp == 2)
123
0
    capab |= WPA_CAPABILITY_MFPR;
124
1.96k
  if (sm->ocv)
125
0
    capab |= WPA_CAPABILITY_OCVC;
126
1.96k
  if (sm->ext_key_id)
127
0
    capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
128
129
1.96k
  return capab;
130
1.96k
}
131
132
133
static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
134
            int pairwise_cipher, int group_cipher,
135
            int key_mgmt, int mgmt_group_cipher,
136
            struct wpa_sm *sm)
137
1.96k
{
138
1.96k
  u8 *pos;
139
1.96k
  struct rsn_ie_hdr *hdr;
140
1.96k
  u32 suite;
141
142
1.96k
  if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
143
1.96k
      2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
144
1.96k
      (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
145
0
    wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
146
0
         (unsigned long) rsn_ie_len);
147
0
    return -1;
148
0
  }
149
150
1.96k
  hdr = (struct rsn_ie_hdr *) rsn_ie;
151
1.96k
  hdr->elem_id = WLAN_EID_RSN;
152
1.96k
  WPA_PUT_LE16(hdr->version, RSN_VERSION);
153
1.96k
  pos = (u8 *) (hdr + 1);
154
155
1.96k
  suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
156
1.96k
  if (suite == 0) {
157
0
    wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
158
0
         group_cipher);
159
0
    return -1;
160
0
  }
161
1.96k
  RSN_SELECTOR_PUT(pos, suite);
162
1.96k
  pos += RSN_SELECTOR_LEN;
163
164
1.96k
  *pos++ = 1;
165
1.96k
  *pos++ = 0;
166
1.96k
  suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
167
1.96k
  if (suite == 0 ||
168
1.96k
      (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
169
1.96k
       pairwise_cipher != WPA_CIPHER_NONE)) {
170
0
    wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
171
0
         pairwise_cipher);
172
0
    return -1;
173
0
  }
174
1.96k
  RSN_SELECTOR_PUT(pos, suite);
175
1.96k
  pos += RSN_SELECTOR_LEN;
176
177
1.96k
  *pos++ = 1;
178
1.96k
  *pos++ = 0;
179
1.96k
  if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
180
0
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
181
1.96k
  } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
182
1.96k
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
183
1.96k
  } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
184
0
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
185
0
#ifdef CONFIG_IEEE80211R
186
0
  } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
187
0
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
188
#ifdef CONFIG_SHA384
189
  } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
190
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
191
#endif /* CONFIG_SHA384 */
192
0
  } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
193
0
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
194
0
#endif /* CONFIG_IEEE80211R */
195
0
  } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
196
0
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
197
0
  } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
198
0
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
199
#ifdef CONFIG_SAE
200
  } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
201
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
202
  } else if (key_mgmt == WPA_KEY_MGMT_SAE_EXT_KEY) {
203
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY);
204
  } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
205
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
206
  } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
207
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY);
208
#endif /* CONFIG_SAE */
209
0
  } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
210
0
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
211
0
  } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
212
0
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
213
#ifdef CONFIG_FILS
214
  } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
215
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
216
  } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
217
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
218
#ifdef CONFIG_IEEE80211R
219
  } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
220
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
221
  } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
222
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
223
#endif /* CONFIG_IEEE80211R */
224
#endif /* CONFIG_FILS */
225
#ifdef CONFIG_OWE
226
  } else if (key_mgmt & WPA_KEY_MGMT_OWE) {
227
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
228
#endif /* CONFIG_OWE */
229
#ifdef CONFIG_DPP
230
  } else if (key_mgmt & WPA_KEY_MGMT_DPP) {
231
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
232
#endif /* CONFIG_DPP */
233
#ifdef CONFIG_SHA384
234
  } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA384) {
235
    RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA384);
236
#endif /* CONFIG_SHA384 */
237
0
  } else {
238
0
    wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
239
0
         key_mgmt);
240
0
    return -1;
241
0
  }
242
1.96k
  pos += RSN_SELECTOR_LEN;
243
244
  /* RSN Capabilities */
245
1.96k
  WPA_PUT_LE16(pos, rsn_supp_capab(sm));
246
1.96k
  pos += 2;
247
248
1.96k
  if (sm->cur_pmksa) {
249
    /* PMKID Count (2 octets, little endian) */
250
0
    *pos++ = 1;
251
0
    *pos++ = 0;
252
    /* PMKID */
253
0
    os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
254
0
    pos += PMKID_LEN;
255
0
  }
256
257
1.96k
  if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
258
0
    if (!sm->cur_pmksa) {
259
      /* PMKID Count */
260
0
      WPA_PUT_LE16(pos, 0);
261
0
      pos += 2;
262
0
    }
263
264
    /* Management Group Cipher Suite */
265
0
    RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
266
0
                mgmt_group_cipher));
267
0
    pos += RSN_SELECTOR_LEN;
268
0
  }
269
270
1.96k
  hdr->len = (pos - rsn_ie) - 2;
271
272
1.96k
  WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
273
274
1.96k
  return pos - rsn_ie;
275
1.96k
}
276
277
278
/**
279
 * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
280
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
281
 * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
282
 * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
283
 * Returns: Length of the generated WPA/RSN IE or -1 on failure
284
 */
285
int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
286
1.96k
{
287
1.96k
  if (sm->proto == WPA_PROTO_RSN)
288
1.96k
    return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
289
1.96k
            sm->pairwise_cipher,
290
1.96k
            sm->group_cipher,
291
1.96k
            sm->key_mgmt, sm->mgmt_group_cipher,
292
1.96k
            sm);
293
0
  else
294
0
    return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
295
0
            sm->pairwise_cipher,
296
0
            sm->group_cipher,
297
0
            sm->key_mgmt);
298
1.96k
}
299
300
301
int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
302
0
{
303
0
  u8 *pos = rsnxe;
304
0
  u32 capab = 0, tmp;
305
0
  size_t flen;
306
307
0
  if (wpa_key_mgmt_sae(sm->key_mgmt) &&
308
0
      (sm->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
309
0
       sm->sae_pwe == SAE_PWE_BOTH || sm->sae_pk)) {
310
0
    capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
311
#ifdef CONFIG_SAE_PK
312
    if (sm->sae_pk)
313
      capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
314
#endif /* CONFIG_SAE_PK */
315
0
  }
316
317
0
  if (sm->secure_ltf)
318
0
    capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
319
0
  if (sm->secure_rtt)
320
0
    capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
321
0
  if (sm->prot_range_neg)
322
0
    capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
323
0
  if (sm->ssid_protection)
324
0
    capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
325
0
  if (sm->spp_amsdu)
326
0
    capab |= BIT(WLAN_RSNX_CAPAB_SPP_A_MSDU);
327
328
0
  if (!capab)
329
0
    return 0; /* no supported extended RSN capabilities */
330
0
  tmp = capab;
331
0
  flen = 0;
332
0
  while (tmp) {
333
0
    flen++;
334
0
    tmp >>= 8;
335
0
  }
336
0
  if (rsnxe_len < 2 + flen)
337
0
    return -1;
338
0
  capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
339
340
0
  *pos++ = WLAN_EID_RSNX;
341
0
  *pos++ = flen;
342
0
  while (capab) {
343
0
    *pos++ = capab & 0xff;
344
0
    capab >>= 8;
345
0
  }
346
347
0
  return pos - rsnxe;
348
0
}