implement WPA2 Stations Key handling
Implement the required support for extrace the cipher suite settings from the the RS Information Element and set the station key based on the 802.11 Station Key CAPWAP message element. Group Key update handling is currently not implemented nor is Station Key update handling.
This commit is contained in:
@ -110,6 +110,16 @@ static void wlan_delete(struct wifi_wlan* wlan)
|
||||
wlan->device->instance->ops->wlan_delete(wlan);
|
||||
}
|
||||
|
||||
static int wlan_set_key(struct wifi_wlan* wlan,
|
||||
uint32_t alg, const uint8_t *addr,
|
||||
int key_idx, int set_tx,
|
||||
const uint8_t *seq, size_t seq_len,
|
||||
const uint8_t *key, size_t key_len)
|
||||
{
|
||||
return wlan->device->instance->ops->wlan_set_key(wlan, alg, addr, key_idx, set_tx,
|
||||
seq, seq_len, key, key_len);
|
||||
}
|
||||
|
||||
static int station_authorize(struct wifi_wlan* wlan, struct wifi_station* station)
|
||||
{
|
||||
return wlan->device->instance->ops->station_authorize(wlan, station);
|
||||
@ -1342,8 +1352,13 @@ wifi_wlan_receive_station_mgmt_association_response_ack(struct wifi_wlan* wlan,
|
||||
/* */
|
||||
station->flags |= WIFI_STATION_FLAGS_ASSOCIATE;
|
||||
if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) {
|
||||
int result;
|
||||
|
||||
/* Apply authorization if Station already authorized */
|
||||
if (station_authorize(wlan, station))
|
||||
result = station_authorize(wlan, station);
|
||||
if (!result)
|
||||
result = wifi_station_set_key(wlan, station);
|
||||
if (result)
|
||||
wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID);
|
||||
}
|
||||
}
|
||||
@ -2071,6 +2086,39 @@ static int ht_opmode_from_ie(uint8_t radioid, uint8_t wlanid,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Scan AC provided IEs for RSNE settings */
|
||||
static struct ieee80211_ie *rsn_from_ie(uint8_t radioid, uint8_t wlanid,
|
||||
struct capwap_array *ie)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ie)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < ie->count; i++) {
|
||||
struct ieee80211_ie *rsn;
|
||||
struct capwap_80211_ie_element *e =
|
||||
*(struct capwap_80211_ie_element **)capwap_array_get_item_pointer(ie, i);
|
||||
|
||||
log_printf(LOG_DEBUG, "RSN WIFI 802.11: IE: %d:%d %02x (%p)",
|
||||
radioid, wlanid, e->flags, &e->flags);
|
||||
|
||||
if (e->radioid != radioid ||
|
||||
e->wlanid != wlanid ||
|
||||
e->ielength < 2)
|
||||
continue;
|
||||
|
||||
rsn = (struct ieee80211_ie *)e->ie;
|
||||
log_printf(LOG_DEBUG, "RSN WIFI 802.11: IE: %02d (%p)",
|
||||
rsn->id, rsn);
|
||||
if (rsn->id == IEEE80211_IE_RSN_INFORMATION)
|
||||
return rsn;
|
||||
}
|
||||
|
||||
log_printf(LOG_DEBUG, "WIFI 802.11: No RSN IE present");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params)
|
||||
{
|
||||
@ -2097,6 +2145,12 @@ int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params
|
||||
wlan->ht_opmode = ht_opmode_from_ie(wlan->radioid, wlan->wlanid,
|
||||
params->ie);
|
||||
log_printf(LOG_DEBUG, "WIFI 802.11: HT OpMode: %04x", wlan->ht_opmode);
|
||||
wlan->rsne = rsn_from_ie(wlan->radioid, wlan->wlanid,
|
||||
params->ie);
|
||||
wlan->keyindex = params->keyindex;
|
||||
wlan->keylength = params->keylength;
|
||||
if (params->key && params->keylength)
|
||||
wlan->key = capwap_clone(params->key, params->keylength);
|
||||
|
||||
build_80211_ie(wlan->radioid, wlan->wlanid,
|
||||
CAPWAP_IE_BEACONS_ASSOCIATED,
|
||||
@ -2334,14 +2388,21 @@ int wifi_station_authorize(struct wifi_wlan* wlan,
|
||||
station = wifi_station_get(wlan, params->address);
|
||||
if (!station)
|
||||
return -1;
|
||||
if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED)
|
||||
return 0;
|
||||
|
||||
/* Station is authorized only after Authentication and Association */
|
||||
station->flags |= WIFI_STATION_FLAGS_AUTHORIZED;
|
||||
if (!(station->flags & WIFI_STATION_FLAGS_AUTHENTICATED) ||
|
||||
!(station->flags & WIFI_STATION_FLAGS_ASSOCIATE))
|
||||
if (params->key)
|
||||
station->key = (struct capwap_80211_stationkey_element *)
|
||||
capwap_element_80211_stationkey_ops.clone(params->key);
|
||||
station->pairwise_cipher = params->pairwise;
|
||||
|
||||
if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) {
|
||||
result = wifi_station_set_key(wlan, station);
|
||||
if (result) {
|
||||
wifi_wlan_deauthentication_station(wlan, station,
|
||||
IEEE80211_REASON_PREV_AUTH_NOT_VALID);
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (params->ht_cap) {
|
||||
memcpy(&station->ht_cap, params->ht_cap, sizeof(station->ht_cap));
|
||||
@ -2350,8 +2411,16 @@ int wifi_station_authorize(struct wifi_wlan* wlan,
|
||||
|
||||
station->max_inactivity = params->max_inactivity;
|
||||
|
||||
/* Station is authorized only after Authentication and Association */
|
||||
station->flags |= WIFI_STATION_FLAGS_AUTHORIZED;
|
||||
if (!(station->flags & WIFI_STATION_FLAGS_AUTHENTICATED) ||
|
||||
!(station->flags & WIFI_STATION_FLAGS_ASSOCIATE))
|
||||
return 0;
|
||||
|
||||
/* Station authorized */
|
||||
result = station_authorize(wlan, station);
|
||||
if (!result)
|
||||
result = wifi_station_set_key(wlan, station);
|
||||
if (result) {
|
||||
wifi_wlan_deauthentication_station(wlan, station,
|
||||
IEEE80211_REASON_PREV_AUTH_NOT_VALID);
|
||||
@ -2360,9 +2429,27 @@ int wifi_station_authorize(struct wifi_wlan* wlan,
|
||||
|
||||
/* let the timer expire, but set the action to SEND NULLFUNC */
|
||||
station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wifi_station_set_key(struct wifi_wlan *wlan,
|
||||
struct wifi_station* station)
|
||||
{
|
||||
|
||||
ASSERT(wlan != NULL);
|
||||
ASSERT(wlan->device != NULL);
|
||||
ASSERT(station != NULL);
|
||||
|
||||
if (station->pairwise_cipher)
|
||||
return wlan_set_key(wlan, station->pairwise_cipher, station->address,
|
||||
0, 1, NULL, 0, station->key->key, station->key->keylength);
|
||||
|
||||
return wlan_set_key(wlan, station->pairwise_cipher, station->address,
|
||||
0, 1, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
/* */
|
||||
void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address) {
|
||||
struct wifi_station* station;
|
||||
|
@ -71,6 +71,7 @@ DECLARE_OPAQUE_TYPE(wifi_device_handle);
|
||||
DECLARE_OPAQUE_TYPE(wifi_wlan_handle);
|
||||
|
||||
struct capwap_80211_wtpqos_element;
|
||||
struct capwap_80211_stationkey_element;
|
||||
|
||||
/* */
|
||||
struct device_setrates_params {
|
||||
@ -106,6 +107,10 @@ struct wlan_startap_params {
|
||||
uint8_t macmode;
|
||||
uint8_t tunnelmode;
|
||||
|
||||
uint8_t keyindex;
|
||||
uint8_t keylength;
|
||||
uint8_t *key;
|
||||
|
||||
struct capwap_array *ie;
|
||||
};
|
||||
|
||||
@ -128,6 +133,8 @@ struct wlan_send_frame_params {
|
||||
struct station_add_params {
|
||||
uint8_t* address;
|
||||
struct ieee80211_ht_cap *ht_cap;
|
||||
uint32_t pairwise;
|
||||
struct capwap_80211_stationkey_element *key;
|
||||
int max_inactivity;
|
||||
};
|
||||
|
||||
@ -326,6 +333,12 @@ struct wifi_wlan {
|
||||
|
||||
uint32_t aidbitfield[IEEE80211_AID_BITFIELD_SIZE];
|
||||
|
||||
struct ieee80211_ie *rsne;
|
||||
uint32_t group_cipher_suite;
|
||||
uint8_t keyindex;
|
||||
uint8_t keylength;
|
||||
uint8_t *key;
|
||||
|
||||
int beacon_ies_len;
|
||||
uint8_t *beacon_ies;
|
||||
int response_ies_len;
|
||||
@ -379,6 +392,8 @@ struct wifi_station {
|
||||
|
||||
/* Authentication */
|
||||
uint16_t authalgorithm;
|
||||
uint32_t pairwise_cipher;
|
||||
struct capwap_80211_stationkey_element *key;
|
||||
|
||||
uint8_t qosinfo;
|
||||
|
||||
@ -410,6 +425,11 @@ struct wifi_driver_ops {
|
||||
int (*wlan_sendframe)(struct wifi_wlan* wlan, uint8_t* frame, int length, uint32_t frequency, uint32_t duration, int offchannel_tx_ok, int no_cck_rate, int no_wait_ack);
|
||||
void (*wlan_poll_station)(struct wifi_wlan* wlan, const uint8_t* address, int qos);
|
||||
void (*wlan_delete)(struct wifi_wlan* wlan);
|
||||
int (*wlan_set_key)(struct wifi_wlan* wlan,
|
||||
uint32_t alg, const uint8_t *addr,
|
||||
int key_idx, int set_tx,
|
||||
const uint8_t *seq, size_t seq_len,
|
||||
const uint8_t *key, size_t key_len);
|
||||
|
||||
/* Stations functions */
|
||||
int (*station_authorize)(struct wifi_wlan* wlan, struct wifi_station* station);
|
||||
@ -448,6 +468,7 @@ void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header*
|
||||
void wifi_wlan_client_probe_event(struct wifi_wlan *wlan, const uint8_t *address);
|
||||
|
||||
/* Station management */
|
||||
int wifi_station_set_key(struct wifi_wlan *wlan, struct wifi_station* station);
|
||||
int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params);
|
||||
void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address);
|
||||
|
||||
|
@ -882,6 +882,50 @@ static int nl80211_wlan_setbeacon(struct wifi_wlan* wlan) {
|
||||
nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
|
||||
goto out_err;
|
||||
|
||||
/* privacy */
|
||||
if (wlan->rsne)
|
||||
log_printf(LOG_DEBUG, "RSNE capability: %04x", wlan->capability);
|
||||
|
||||
if (wlan->rsne &&
|
||||
wlan->capability & IEEE80211_CAPABILITY_PRIVACY) {
|
||||
uint8_t *data = (uint8_t *)(wlan->rsne + 1);
|
||||
uint16_t suites_num;
|
||||
uint32_t *suites;
|
||||
int i;
|
||||
|
||||
data += 2;
|
||||
|
||||
nla_put_flag(msg, NL80211_ATTR_PRIVACY);
|
||||
nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, NL80211_WPA_VERSION_2);
|
||||
log_printf(LOG_ERR, "nl80211: Cipher Suite Group: %08x", ntohl(*(uint32_t *)data));
|
||||
/* find a better place for the cipher suite assignment */
|
||||
wlan->group_cipher_suite = ntohl(*(uint32_t *)data);
|
||||
nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, ntohl(*(uint32_t *)data));
|
||||
data += sizeof(uint32_t);
|
||||
|
||||
suites_num = *(uint16_t *)data;
|
||||
data += 2;
|
||||
suites = alloca(suites_num * sizeof(uint32_t));
|
||||
|
||||
for (i = 0; i < suites_num; i++) {
|
||||
suites[i] = ntohl(*(uint32_t *)data);
|
||||
log_printf(LOG_ERR, "nl80211: Cipher Suite Pairwise[%d]: %08x", i, suites[i]);
|
||||
data +=sizeof(uint32_t);
|
||||
}
|
||||
nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, suites_num * sizeof(uint32_t), suites);
|
||||
|
||||
suites_num = *(uint16_t *)data;
|
||||
data += 2;
|
||||
suites = alloca(suites_num * sizeof(uint32_t));
|
||||
|
||||
for (i = 0; i < suites_num; i++) {
|
||||
suites[i] = ntohl(*(uint32_t *)data);
|
||||
log_printf(LOG_ERR, "nl80211: AKM Suite[%d]: %08x", i, suites[i]);
|
||||
data +=sizeof(uint32_t);
|
||||
}
|
||||
nla_put(msg, NL80211_ATTR_AKM_SUITES, suites_num * sizeof(uint32_t), suites);
|
||||
}
|
||||
|
||||
/* Start AP */
|
||||
result = nl80211_wlan_send_and_recv_msg(wlan, msg, NULL, NULL);
|
||||
if (result)
|
||||
@ -931,6 +975,115 @@ out_err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int is_broadcast_ether_addr(const uint8_t *a)
|
||||
{
|
||||
return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff;
|
||||
}
|
||||
|
||||
#define broadcast_ether_addr (const uint8_t *) "\xff\xff\xff\xff\xff\xff"
|
||||
|
||||
static int nl80211_set_key(struct wifi_wlan* wlan,
|
||||
uint32_t alg, const uint8_t *addr,
|
||||
int key_idx, int set_tx,
|
||||
const uint8_t *seq, size_t seq_len,
|
||||
const uint8_t *key, size_t key_len)
|
||||
{
|
||||
struct nl_msg *msg;
|
||||
int ret;
|
||||
|
||||
log_printf(LOG_DEBUG, "%s: ifindex=%d alg=%08x addr=%p key_idx=%d "
|
||||
"set_tx=%d seq_len=%lu key_len=%lu",
|
||||
__func__, wlan->virtindex, alg, addr, key_idx, set_tx,
|
||||
(unsigned long) seq_len, (unsigned long) key_len);
|
||||
|
||||
if (alg == 0) {
|
||||
msg = nl80211_wlan_msg(wlan, 0, NL80211_CMD_DEL_KEY);
|
||||
if (!msg)
|
||||
return -ENOBUFS;
|
||||
} else {
|
||||
msg = nl80211_wlan_msg(wlan, 0, NL80211_CMD_NEW_KEY);
|
||||
if (!msg ||
|
||||
nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, alg))
|
||||
goto fail;
|
||||
log_hexdump(LOG_DEBUG, "nl80211: KEY_DATA", key, key_len);
|
||||
}
|
||||
|
||||
if (seq && seq_len) {
|
||||
if (nla_put(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq))
|
||||
goto fail;
|
||||
log_hexdump(LOG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
|
||||
}
|
||||
|
||||
if (addr && !is_broadcast_ether_addr(addr)) {
|
||||
log_printf(LOG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
|
||||
if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
|
||||
goto fail;
|
||||
|
||||
if (key_idx && !set_tx) {
|
||||
log_printf(LOG_DEBUG, " RSN IBSS RX GTK");
|
||||
if (nla_put_u32(msg, NL80211_ATTR_KEY_TYPE,
|
||||
NL80211_KEYTYPE_GROUP))
|
||||
goto fail;
|
||||
}
|
||||
} else if (addr && is_broadcast_ether_addr(addr)) {
|
||||
struct nlattr *types;
|
||||
|
||||
log_printf(LOG_DEBUG, " broadcast key");
|
||||
|
||||
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
|
||||
if (!types ||
|
||||
nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
|
||||
goto fail;
|
||||
nla_nest_end(msg, types);
|
||||
}
|
||||
if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
|
||||
goto fail;
|
||||
|
||||
ret = nl80211_wlan_send_and_recv_msg(wlan, msg, NULL, NULL);
|
||||
if ((ret == -ENOENT || ret == -ENOLINK) && alg == 0)
|
||||
ret = 0;
|
||||
if (ret)
|
||||
log_printf(LOG_DEBUG, "nl80211: set_key failed; err=%d %s)",
|
||||
ret, strerror(-ret));
|
||||
|
||||
/*
|
||||
* If we failed or don't need to set the default TX key (below),
|
||||
* we're done here.
|
||||
*/
|
||||
if (ret || !set_tx || alg == 0)
|
||||
return ret;
|
||||
|
||||
if (addr && is_broadcast_ether_addr(addr)) {
|
||||
struct nlattr *types;
|
||||
|
||||
msg = nl80211_wlan_msg(wlan, 0, NL80211_CMD_SET_KEY);
|
||||
if (!msg ||
|
||||
nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
|
||||
nla_put_flag(msg, NL80211_ATTR_KEY_DEFAULT))
|
||||
goto fail;
|
||||
|
||||
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
|
||||
if (!types ||
|
||||
nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
|
||||
goto fail;
|
||||
nla_nest_end(msg, types);
|
||||
|
||||
ret = nl80211_wlan_send_and_recv_msg(wlan, msg, NULL, NULL);
|
||||
if (ret == -ENOENT)
|
||||
ret = 0;
|
||||
if (ret)
|
||||
log_printf(LOG_DEBUG, "nl80211: set_key default failed; "
|
||||
"err=%d %s)", ret, strerror(-ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
nlmsg_free(msg);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
/* */
|
||||
static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
|
||||
int i;
|
||||
@ -1006,6 +1159,10 @@ static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wlan->keylength && wlan->key)
|
||||
nl80211_set_key(wlan, wlan->group_cipher_suite, broadcast_ether_addr,
|
||||
wlan->keyindex, 1, NULL, 0, wlan->key, wlan->keylength);
|
||||
|
||||
/* Enable operation status */
|
||||
wlan->flags |= WIFI_WLAN_OPERSTATE_RUNNING;
|
||||
netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle, wlan->virtindex, -1, IF_OPER_UP);
|
||||
@ -2282,6 +2439,7 @@ const struct wifi_driver_ops wifi_driver_nl80211_ops = {
|
||||
.wlan_sendframe = nl80211_wlan_sendframe,
|
||||
.wlan_poll_station = nl80211_wlan_poll_station,
|
||||
.wlan_delete = nl80211_wlan_delete,
|
||||
.wlan_set_key = nl80211_set_key,
|
||||
|
||||
.station_authorize = nl80211_station_authorize,
|
||||
.station_deauthorize = nl80211_station_deauthorize,
|
||||
|
Reference in New Issue
Block a user