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