1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* 2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_supplicant - WPA/RSN IE and KDE processing 3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> 4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify 6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as 7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation. 8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license. 11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details. 13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h" 16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h" 18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "wpa.h" 19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "pmksa_cache.h" 20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "ieee802_11_defs.h" 21526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "wpa_i.h" 22526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "wpa_ie.h" 23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int wpa_selector_to_bitfield(const u8 *s) 26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) 28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return WPA_CIPHER_NONE; 29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40) 30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return WPA_CIPHER_WEP40; 31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) 32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return WPA_CIPHER_TKIP; 33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) 34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return WPA_CIPHER_CCMP; 35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104) 36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return WPA_CIPHER_WEP104; 37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int wpa_key_mgmt_to_bitfield(const u8 *s) 42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X) 44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return WPA_KEY_MGMT_IEEE8021X; 45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X) 46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return WPA_KEY_MGMT_PSK; 47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE) 48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return WPA_KEY_MGMT_WPA_NONE; 49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, 54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct wpa_ie_data *data) 55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const struct wpa_ie_hdr *hdr; 57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos; 58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int left; 59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int i, count; 60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(data, 0, sizeof(*data)); 62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->proto = WPA_PROTO_WPA; 63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->pairwise_cipher = WPA_CIPHER_TKIP; 64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->group_cipher = WPA_CIPHER_TKIP; 65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; 66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->capabilities = 0; 67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->pmkid = NULL; 68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->num_pmkid = 0; 69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->mgmt_group_cipher = 0; 70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (wpa_ie_len == 0) { 72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* No WPA IE - fail silently */ 73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { 77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", 78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt __func__, (unsigned long) wpa_ie_len); 79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr = (const struct wpa_ie_hdr *) wpa_ie; 83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || 85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr->len != wpa_ie_len - 2 || 86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || 87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt WPA_GET_LE16(hdr->version) != WPA_VERSION) { 88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", 89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt __func__); 90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = (const u8 *) (hdr + 1); 94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left = wpa_ie_len - sizeof(*hdr); 95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (left >= WPA_SELECTOR_LEN) { 97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->group_cipher = wpa_selector_to_bitfield(pos); 98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += WPA_SELECTOR_LEN; 99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left -= WPA_SELECTOR_LEN; 100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (left > 0) { 101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", 102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt __func__, left); 103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (left >= 2) { 107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->pairwise_cipher = 0; 108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt count = WPA_GET_LE16(pos); 109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left -= 2; 111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (count == 0 || left < count * WPA_SELECTOR_LEN) { 112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " 113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "count %u left %u", __func__, count, left); 114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < count; i++) { 117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->pairwise_cipher |= wpa_selector_to_bitfield(pos); 118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += WPA_SELECTOR_LEN; 119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left -= WPA_SELECTOR_LEN; 120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (left == 1) { 122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", 123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt __func__); 124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (left >= 2) { 128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->key_mgmt = 0; 129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt count = WPA_GET_LE16(pos); 130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left -= 2; 132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (count == 0 || left < count * WPA_SELECTOR_LEN) { 133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " 134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "count %u left %u", __func__, count, left); 135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < count; i++) { 138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); 139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += WPA_SELECTOR_LEN; 140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left -= WPA_SELECTOR_LEN; 141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (left == 1) { 143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", 144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt __func__); 145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (left >= 2) { 149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data->capabilities = WPA_GET_LE16(pos); 150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left -= 2; 152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (left > 0) { 155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", 156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt __func__, left); 157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_parse_wpa_ie - Parse WPA/RSN IE 165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @wpa_ie: Pointer to WPA or RSN IE 166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @wpa_ie_len: Length of the WPA/RSN IE 167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @data: Pointer to data area for parsing results 168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 on success, -1 on failure 169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Parse the contents of WPA or RSN IE and write the parsed data into data. 171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, 173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct wpa_ie_data *data) 174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) 176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); 177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); 179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, 183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int pairwise_cipher, int group_cipher, 184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int key_mgmt) 185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 *pos; 187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct wpa_ie_hdr *hdr; 188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + 190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) 191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr = (struct wpa_ie_hdr *) wpa_ie; 194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; 195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); 196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt WPA_PUT_LE16(hdr->version, WPA_VERSION); 197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = (u8 *) (hdr + 1); 198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (group_cipher == WPA_CIPHER_CCMP) { 200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); 201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (group_cipher == WPA_CIPHER_TKIP) { 202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); 203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (group_cipher == WPA_CIPHER_WEP104) { 204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104); 205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (group_cipher == WPA_CIPHER_WEP40) { 206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40); 207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt group_cipher); 210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += WPA_SELECTOR_LEN; 213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = 1; 215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = 0; 216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pairwise_cipher == WPA_CIPHER_CCMP) { 217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); 218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (pairwise_cipher == WPA_CIPHER_TKIP) { 219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); 220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (pairwise_cipher == WPA_CIPHER_NONE) { 221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); 222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pairwise_cipher); 225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += WPA_SELECTOR_LEN; 228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = 1; 230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = 0; 231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); 233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); 235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { 236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); 237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt key_mgmt); 240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += WPA_SELECTOR_LEN; 243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* WPA Capabilities; use defaults, so no need to include it */ 245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr->len = (pos - wpa_ie) - 2; 247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); 249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return pos - wpa_ie; 251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, 255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int pairwise_cipher, int group_cipher, 256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int key_mgmt, int mgmt_group_cipher, 257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct wpa_sm *sm) 258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifndef CONFIG_NO_WPA2 260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 *pos; 261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_ie_hdr *hdr; 262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u16 capab; 263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + 265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + 266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { 267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", 268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned long) rsn_ie_len); 269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr = (struct rsn_ie_hdr *) rsn_ie; 273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr->elem_id = WLAN_EID_RSN; 274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt WPA_PUT_LE16(hdr->version, RSN_VERSION); 275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = (u8 *) (hdr + 1); 276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (group_cipher == WPA_CIPHER_CCMP) { 278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (group_cipher == WPA_CIPHER_TKIP) { 280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (group_cipher == WPA_CIPHER_WEP104) { 282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104); 283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (group_cipher == WPA_CIPHER_WEP40) { 284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40); 285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt group_cipher); 288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += RSN_SELECTOR_LEN; 291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = 1; 293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = 0; 294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pairwise_cipher == WPA_CIPHER_CCMP) { 295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (pairwise_cipher == WPA_CIPHER_TKIP) { 297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (pairwise_cipher == WPA_CIPHER_NONE) { 299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); 300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pairwise_cipher); 303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += RSN_SELECTOR_LEN; 306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = 1; 308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = 0; 309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); 311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); 313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211R 314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { 315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); 316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { 317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); 318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211R */ 319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W 320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { 321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); 322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { 323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); 324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */ 325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt key_mgmt); 328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += RSN_SELECTOR_LEN; 331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* RSN Capabilities */ 333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt capab = 0; 334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W 335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) 336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt capab |= WPA_CAPABILITY_MFPC; 337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */ 338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt WPA_PUT_LE16(pos, capab); 339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sm->cur_pmksa) { 342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* PMKID Count (2 octets, little endian) */ 343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = 1; 344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = 0; 345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* PMKID */ 346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); 347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += PMKID_LEN; 348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W 351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { 352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!sm->cur_pmksa) { 353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* PMKID Count */ 354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt WPA_PUT_LE16(pos, 0); 355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Management Group Cipher Suite */ 359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); 360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += RSN_SELECTOR_LEN; 361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */ 363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr->len = (pos - rsn_ie) - 2; 365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); 367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return pos - rsn_ie; 369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* CONFIG_NO_WPA2 */ 370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_NO_WPA2 */ 372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy 377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sm: Pointer to WPA state machine data from wpa_sm_init() 378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE 379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @wpa_ie_len: Maximum length of the generated WPA/RSN IE 380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Length of the generated WPA/RSN IE or -1 on failure 381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) 383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sm->proto == WPA_PROTO_RSN) 385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, 386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->pairwise_cipher, 387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->group_cipher, 388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->key_mgmt, sm->mgmt_group_cipher, 389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm); 390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, 392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->pairwise_cipher, 393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->group_cipher, 394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->key_mgmt); 395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs 400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pos: Pointer to the IE header 401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @end: Pointer to the end of the Key Data buffer 402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ie: Pointer to parsed IE data 403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 on success, 1 if end mark is found, -1 on failure 404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int wpa_parse_generic(const u8 *pos, const u8 *end, 406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct wpa_eapol_ie_parse *ie) 407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[1] == 0) 409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[1] >= 6 && 412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && 413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos[2 + WPA_SELECTOR_LEN] == 1 && 414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos[2 + WPA_SELECTOR_LEN + 1] == 0) { 415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->wpa_ie = pos; 416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->wpa_ie_len = pos[1] + 2; 417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos + 1 + RSN_SELECTOR_LEN < end && 421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && 422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { 423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; 424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[1] > RSN_SELECTOR_LEN + 2 && 428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { 429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->gtk = pos + 2 + RSN_SELECTOR_LEN; 430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; 431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[1] > RSN_SELECTOR_LEN + 2 && 435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { 436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; 437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; 438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_PEERKEY 442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[1] > RSN_SELECTOR_LEN + 2 && 443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { 444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->smk = pos + 2 + RSN_SELECTOR_LEN; 445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->smk_len = pos[1] - RSN_SELECTOR_LEN; 446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[1] > RSN_SELECTOR_LEN + 2 && 450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { 451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->nonce = pos + 2 + RSN_SELECTOR_LEN; 452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; 453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[1] > RSN_SELECTOR_LEN + 2 && 457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { 458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; 459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; 460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[1] > RSN_SELECTOR_LEN + 2 && 464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { 465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->error = pos + 2 + RSN_SELECTOR_LEN; 466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->error_len = pos[1] - RSN_SELECTOR_LEN; 467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_PEERKEY */ 470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W 472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[1] > RSN_SELECTOR_LEN + 2 && 473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { 474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->igtk = pos + 2 + RSN_SELECTOR_LEN; 475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; 476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */ 479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs 486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @buf: Pointer to the Key Data buffer 487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @len: Key Data Length 488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ie: Pointer to parsed IE data 489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 on success, -1 on failure 490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint wpa_supplicant_parse_ies(const u8 *buf, size_t len, 492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct wpa_eapol_ie_parse *ie) 493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, *end; 495526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int ret = 0; 496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(ie, 0, sizeof(*ie)); 498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { 499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[0] == 0xdd && 500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ((pos == buf + len - 1) || pos[1] == 0)) { 501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Ignore padding */ 502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos + 2 + pos[1] > end) { 505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " 506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "underflow (ie=%d len=%d pos=%d)", 507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos[0], pos[1], (int) (pos - buf)); 508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", 509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf, len); 510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = -1; 511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 512526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 513526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (*pos == WLAN_EID_RSN) { 514526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->rsn_ie = pos; 515526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->rsn_ie_len = pos[1] + 2; 516526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211R 517526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { 518526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->mdie = pos; 519526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ie->mdie_len = pos[1] + 2; 520526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211R */ 521526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { 522526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = wpa_parse_generic(pos, end, ie); 523526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret < 0) 524526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 525526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret > 0) { 526526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = 0; 527526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 528526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 529526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 530526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " 531526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Key Data IE", pos, 2 + pos[1]); 532526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 533526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 534526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 535526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return ret; 536526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 537