add vendor VSA to set additional key and IGTK support

IGTK == Management Frame Protection
This commit is contained in:
Andreas Schultz 2016-08-15 15:30:29 +02:00
parent ac135e16c4
commit a488af66cf
9 changed files with 251 additions and 8 deletions

View File

@ -423,6 +423,23 @@ struct ieee80211_ie_erp {
/* 802.11 RSN information element */
#define IEEE80211_IE_RSN_INFORMATION 48
/* cipher suite selectors */
#define IEEE80211_CIPHER_SUITE_USE_GROUP 0x000FAC00
#define IEEE80211_CIPHER_SUITE_WEP40 0x000FAC01
#define IEEE80211_CIPHER_SUITE_TKIP 0x000FAC02
/* reserved: 0x000FAC03 */
#define IEEE80211_CIPHER_SUITE_CCMP 0x000FAC04
#define IEEE80211_CIPHER_SUITE_WEP104 0x000FAC05
#define IEEE80211_CIPHER_SUITE_AES_CMAC 0x000FAC06
#define IEEE80211_CIPHER_SUITE_NO_GROUP_ADDR 0x000FAC07
#define IEEE80211_CIPHER_SUITE_GCMP 0x000FAC08
#define IEEE80211_CIPHER_SUITE_GCMP_256 0x000FAC09
#define IEEE80211_CIPHER_SUITE_CCMP_256 0x000FAC0A
#define IEEE80211_CIPHER_SUITE_BIP_GMAC_128 0x000FAC0B
#define IEEE80211_CIPHER_SUITE_BIP_GMAC_256 0x000FAC0C
#define IEEE80211_CIPHER_SUITE_BIP_CMAC_256 0x000FAC0D
/* 802.11 Extended Supported Rates information element */
#define IEEE80211_IE_EXTENDED_SUPPORTED_RATES 50
#define IEEE80211_IE_EXTENDED_SUPPORTED_MIN_LENGTH 1

View File

@ -94,7 +94,8 @@ static const struct capwap_message_elements_ops * capwap_vendor_travelping_messa
element_ops(CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP_TYPE, capwap_element_vendor_travelping_wtp_timestamp_ops),
element_ops(CAPWAP_ELEMENT_80211N_RADIO_CONF_TYPE, capwap_element_80211n_radioconf_ops),
element_ops(CAPWAP_ELEMENT_80211N_STATION_INFO_TYPE, capwap_element_80211n_station_info_ops),
element_ops(CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_ENCRYPTION_CAPABILITY_TYPE, capwap_element_vendor_travelping_80211_encryption_capability_ops)
element_ops(CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_ENCRYPTION_CAPABILITY_TYPE, capwap_element_vendor_travelping_80211_encryption_capability_ops),
element_ops(CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_TYPE, capwap_element_vendor_travelping_80211_update_key_ops)
};
#undef element_ops

View File

@ -0,0 +1,108 @@
#include "capwap.h"
#include "capwap_element.h"
/*
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Radio ID | WLAN ID | Key Index | Key Status |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Cipher Suite |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Key... |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* IEEE 802.11 Update Key
*
* Vendor Id: 18681 (Travelping GmbH)
* Type: 19
*
* Length: >= 6
*
*/
/* */
static void
capwap_vendor_travelping_80211_update_key_element_create(void *data,
capwap_message_elements_handle handle,
struct capwap_write_message_elements_ops *func)
{
struct capwap_vendor_travelping_80211_update_key_element *element =
(struct capwap_vendor_travelping_80211_update_key_element*)data;
ASSERT(data != NULL);
func->write_u8(handle, element->radioid);
func->write_u8(handle, element->wlanid);
func->write_u8(handle, element->keyindex);
func->write_u8(handle, element->keystatus);
func->write_u32(handle, element->ciphersuite);
if (element->keylength > 0)
func->write_block(handle, element->key, element->keylength);
}
/* */
static void *
capwap_vendor_travelping_80211_update_key_element_parsing(capwap_message_elements_handle handle,
struct capwap_read_message_elements_ops *func)
{
unsigned short length;
struct capwap_vendor_travelping_80211_update_key_element *data;
ASSERT(handle != NULL);
ASSERT(func != NULL);
length = func->read_ready(handle);
if (length < 8) {
log_printf(LOG_DEBUG, "Invalid Vendor Travelping IEEE 802.11 Update Key element");
return NULL;
}
length -= 8;
/* */
data = (struct capwap_vendor_travelping_80211_update_key_element *)
capwap_alloc(sizeof(struct capwap_vendor_travelping_80211_update_key_element) + length);
memset(data, 0, sizeof(struct capwap_vendor_travelping_80211_update_key_element) + length);
/* Retrieve data */
func->read_u8(handle, &data->radioid);
func->read_u8(handle, &data->wlanid);
func->read_u8(handle, &data->keyindex);
func->read_u8(handle, &data->keystatus);
func->read_u32(handle, &data->ciphersuite);
data->keylength = length;
func->read_block(handle, data->key, data->keylength);
return data;
}
/* */
static void *capwap_vendor_travelping_80211_update_key_element_clone(void *data)
{
struct capwap_vendor_travelping_80211_update_key_element *element =
(struct capwap_vendor_travelping_80211_update_key_element*)data;
ASSERT(data != NULL);
return capwap_clone(data, sizeof(struct capwap_vendor_travelping_80211_update_key_element) +
element->keylength);
}
/* */
static void capwap_vendor_travelping_80211_update_key_element_free(void *data)
{
ASSERT(data != NULL);
capwap_free(data);
}
/* */
const struct capwap_message_elements_ops capwap_element_vendor_travelping_80211_update_key_ops = {
.category = CAPWAP_MESSAGE_ELEMENT_ARRAY,
.create = capwap_vendor_travelping_80211_update_key_element_create,
.parse = capwap_vendor_travelping_80211_update_key_element_parsing,
.clone = capwap_vendor_travelping_80211_update_key_element_clone,
.free = capwap_vendor_travelping_80211_update_key_element_free
};

View File

@ -0,0 +1,27 @@
#ifndef __CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_HEADER__
#define __CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_HEADER__
#define CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_VENDOR CAPWAP_VENDOR_TRAVELPING_ID
#define CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_TYPE 19
#define CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY \
(struct capwap_message_element_id){ \
.vendor = CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_VENDOR, \
.type = CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_TYPE \
}
#define CAPWAP_UPDATE_WLAN_KEY_STATUS_REKEYING 2
#define CAPWAP_UPDATE_WLAN_KEY_STATUS_COMPLETE 3
struct capwap_vendor_travelping_80211_update_key_element {
uint8_t radioid;
uint8_t wlanid;
uint8_t keyindex;
uint8_t keystatus;
uint32_t ciphersuite;
uint16_t keylength;
uint8_t key[];
};
extern const struct capwap_message_elements_ops capwap_element_vendor_travelping_80211_update_key_ops;
#endif /* __CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_HEADER__ */

View File

@ -5,6 +5,7 @@
#include "capwap_element_vendor_travelping_wtp_timestamp.h"
#include "capwap_element_vendor_travelping_80211_encryption_capability.h"
#include "capwap_element_vendor_travelping_80211_update_key.h"
/* draft-ietf-opsawg-capwap-extension-06 */
#include "capwap_element_80211n_radioconf.h"

View File

@ -2123,6 +2123,41 @@ static struct ieee80211_ie *rsn_from_ie(uint8_t radioid, uint8_t wlanid,
return NULL;
}
#define broadcast_ether_addr (const uint8_t *) "\xff\xff\xff\xff\xff\xff"
static int update_keys(struct wifi_wlan* wlan, struct capwap_array *keys)
{
int i, result = 0;
log_printf(LOG_DEBUG, "Wifi Update Keys: %p", keys);
if (!keys)
return 0;
log_printf(LOG_DEBUG, "Wifi Update Keys: #%ld", keys->count);
for (i = 0; i < keys->count; i++) {
struct capwap_vendor_travelping_80211_update_key_element *key =
*(struct capwap_vendor_travelping_80211_update_key_element **)
capwap_array_get_item_pointer(keys, i);
log_printf(LOG_DEBUG, "Wifi Update Keys: Update: Status: %d, CipherSuite: %08x, Index: %d, Len: %d",
key->keystatus, key->ciphersuite, key->keyindex, key->keylength);
switch (key->keystatus) {
case 3:
result = wlan_set_key(wlan, key->ciphersuite, broadcast_ether_addr,
key->keyindex, 1, NULL, 0,
key->keylength ? key->key : NULL, key->keylength);
log_printf(LOG_INFO, "Update KEY on interface: %s, SSID: '%s', result: %d",
wlan->virtname, wlan->ssid, result);
break;
default:
break;
}
}
return result;
}
/* */
int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params)
{
@ -2167,18 +2202,19 @@ int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params
/* Start AP */
result = wlan_startap(wlan);
if (!result) {
wlan->device->wlanactive++;
log_printf(LOG_INFO, "Configured interface: %s, SSID: '%s'", wlan->virtname, wlan->ssid);
} else {
if (result) {
wifi_wlan_stopap(wlan);
return result;
}
update_keys(wlan, params->updatekeys);
wlan->device->wlanactive++;
log_printf(LOG_INFO, "Configured interface: %s, SSID: '%s'", wlan->virtname, wlan->ssid);
return result;
}
#define broadcast_ether_addr (const uint8_t *) "\xff\xff\xff\xff\xff\xff"
/* */
int wifi_wlan_updateap(struct wifi_wlan* wlan, struct wlan_updateap_params* params)
{
@ -2237,6 +2273,9 @@ int wifi_wlan_updateap(struct wifi_wlan* wlan, struct wlan_updateap_params* para
break;
}
if (!result)
update_keys(wlan, params->updatekeys);
return result;
}

View File

@ -103,6 +103,7 @@ struct wlan_startap_params {
uint8_t *key;
struct capwap_array *ie;
struct capwap_array *updatekeys;
};
struct wlan_updateap_params {
@ -118,6 +119,7 @@ struct wlan_updateap_params {
uint8_t *key;
struct capwap_array *ie;
struct capwap_array *updatekeys;
};
/* */

View File

@ -1060,7 +1060,12 @@ static int nl80211_set_key(struct wifi_wlan* wlan,
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))
nla_put_flag(msg, (alg == IEEE80211_CIPHER_SUITE_AES_CMAC ||
alg == IEEE80211_CIPHER_SUITE_BIP_GMAC_128 ||
alg == IEEE80211_CIPHER_SUITE_BIP_GMAC_256 ||
alg == IEEE80211_CIPHER_SUITE_BIP_CMAC_256) ?
NL80211_ATTR_KEY_DEFAULT_MGMT :
NL80211_ATTR_KEY_DEFAULT))
goto fail;
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);

View File

@ -652,6 +652,47 @@ void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, cons
}
}
static struct capwap_array *wtp_radio_set_update_keys(struct capwap_parsed_packet *packet,
uint8_t radioid, uint8_t wlanid)
{
int i;
struct capwap_array *keys;
struct capwap_array *updatekeys = NULL;
ASSERT(packet != NULL);
keys = (struct capwap_array *)
capwap_get_message_element_data(packet, CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY);
log_printf(LOG_DEBUG, "Set Update Keys: %p", keys);
if (!keys)
return NULL;
log_printf(LOG_DEBUG, "Set Update Keys: #%ld", keys->count);
for (i = 0; i < keys->count; i++) {
struct capwap_vendor_travelping_80211_update_key_element *key =
*(struct capwap_vendor_travelping_80211_update_key_element **)
capwap_array_get_item_pointer(keys, i);
log_printf(LOG_DEBUG, "RadioId: %d .. %d, WlanId: %d .. %d",
key->radioid, radioid,
key->wlanid, wlanid);
if (key->radioid != radioid || key->wlanid != wlanid)
continue;
if (!updatekeys)
updatekeys = capwap_array_create(sizeof(void *), 0, 0);
if (!updatekeys) {
log_printf(LOG_DEBUG, "Update WLAN: Out of Memory");
return NULL;
}
*(void **)capwap_array_get_item_pointer(updatekeys, updatekeys->count) = key;
log_printf(LOG_DEBUG, "Set Update Keys: Update #%ld", updatekeys->count);
}
return updatekeys;
}
/* source http://stackoverflow.com/a/16994674 */
static uint16_t reverse(register uint16_t x)
{
@ -721,6 +762,7 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet,
params.key = addwlan->key;
params.ie = (struct capwap_array *)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE);
params.updatekeys = wtp_radio_set_update_keys(packet, addwlan->radioid, addwlan->wlanid);
/* Start AP */
if (wifi_wlan_startap(wlan->wlanhandle, &params)) {
@ -788,6 +830,7 @@ uint32_t wtp_radio_update_wlan(struct capwap_parsed_packet* packet)
params.key = updatewlan->key;
params.ie = (struct capwap_array *)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE);
params.updatekeys = wtp_radio_set_update_keys(packet, updatewlan->radioid, updatewlan->wlanid);
/* Update AP */
if (wifi_wlan_updateap(wlan->wlanhandle, &params)) {