Allow management group cipher to be configured

This allows hostapd to set a different management group cipher than the
previously hardcoded default BIP (AES-128-CMAC). The new configuration
file parameter group_mgmt_cipher can be set to BIP-GMAC-128,
BIP-GMAC-256, or BIP-CMAC-256 to select one of the ciphers defined in
IEEE Std 802.11ac-2013.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2014-03-12 20:26:37 +02:00 committed by Jouni Malinen
parent 67d39cfb32
commit 8dd9f9cdde
14 changed files with 164 additions and 41 deletions

View file

@ -2600,6 +2600,20 @@ static int hostapd_config_fill(struct hostapd_config *conf,
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "ieee80211w") == 0) { } else if (os_strcmp(buf, "ieee80211w") == 0) {
bss->ieee80211w = atoi(pos); bss->ieee80211w = atoi(pos);
} else if (os_strcmp(buf, "group_mgmt_cipher") == 0) {
if (os_strcmp(pos, "AES-128-CMAC") == 0) {
bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
} else if (os_strcmp(pos, "BIP-GMAC-128") == 0) {
bss->group_mgmt_cipher = WPA_CIPHER_BIP_GMAC_128;
} else if (os_strcmp(pos, "BIP-GMAC-256") == 0) {
bss->group_mgmt_cipher = WPA_CIPHER_BIP_GMAC_256;
} else if (os_strcmp(pos, "BIP-CMAC-256") == 0) {
bss->group_mgmt_cipher = WPA_CIPHER_BIP_CMAC_256;
} else {
wpa_printf(MSG_ERROR, "Line %d: invalid group_mgmt_cipher: %s",
line, pos);
return 1;
}
} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) { } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
bss->assoc_sa_query_max_timeout = atoi(pos); bss->assoc_sa_query_max_timeout = atoi(pos);
if (bss->assoc_sa_query_max_timeout == 0) { if (bss->assoc_sa_query_max_timeout == 0) {

View file

@ -1104,6 +1104,17 @@ own_ip_addr=127.0.0.1
# 2 = required # 2 = required
#ieee80211w=0 #ieee80211w=0
# Group management cipher suite
# Default: AES-128-CMAC (BIP)
# Other options (depending on driver support):
# BIP-GMAC-128
# BIP-GMAC-256
# BIP-CMAC-256
# Note: All the stations connecting to the BSS will also need to support the
# selected cipher. The default AES-128-CMAC is the only option that is commonly
# available in deployed devices.
#group_mgmt_cipher=AES-128-CMAC
# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP) # Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
# (maximum time to wait for a SA Query response) # (maximum time to wait for a SA Query response)
# dot11AssociationSAQueryMaximumTimeout, 1...4294967295 # dot11AssociationSAQueryMaximumTimeout, 1...4294967295

View file

@ -73,6 +73,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
bss->assoc_sa_query_max_timeout = 1000; bss->assoc_sa_query_max_timeout = 1000;
bss->assoc_sa_query_retry_timeout = 201; bss->assoc_sa_query_retry_timeout = 201;
bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
#ifdef EAP_SERVER_FAST #ifdef EAP_SERVER_FAST
/* both anonymous and authenticated provisioning */ /* both anonymous and authenticated provisioning */

View file

@ -254,6 +254,7 @@ struct hostapd_bss_config {
int wpa_key_mgmt; int wpa_key_mgmt;
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w; enum mfp_options ieee80211w;
int group_mgmt_cipher;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */ /* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout; unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */ /* dot11AssociationSAQueryRetryTimeout (in TUs) */

View file

@ -1918,7 +1918,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
static int ieee80211w_kde_len(struct wpa_state_machine *sm) static int ieee80211w_kde_len(struct wpa_state_machine *sm)
{ {
if (sm->mgmt_frame_prot) { if (sm->mgmt_frame_prot) {
return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde); size_t len;
len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
} }
return 0; return 0;
@ -1930,6 +1932,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
struct wpa_igtk_kde igtk; struct wpa_igtk_kde igtk;
struct wpa_group *gsm = sm->group; struct wpa_group *gsm = sm->group;
u8 rsc[WPA_KEY_RSC_LEN]; u8 rsc[WPA_KEY_RSC_LEN];
size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
if (!sm->mgmt_frame_prot) if (!sm->mgmt_frame_prot)
return pos; return pos;
@ -1941,17 +1944,18 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
os_memset(igtk.pn, 0, sizeof(igtk.pn)); os_memset(igtk.pn, 0, sizeof(igtk.pn));
else else
os_memcpy(igtk.pn, rsc, sizeof(igtk.pn)); os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
if (sm->wpa_auth->conf.disable_gtk) { if (sm->wpa_auth->conf.disable_gtk) {
/* /*
* Provide unique random IGTK to each STA to prevent use of * Provide unique random IGTK to each STA to prevent use of
* IGTK in the BSS. * IGTK in the BSS.
*/ */
if (random_get_bytes(igtk.igtk, WPA_IGTK_LEN) < 0) if (random_get_bytes(igtk.igtk, len) < 0)
return pos; return pos;
} }
pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK, pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
(const u8 *) &igtk, sizeof(igtk), NULL, 0); (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
NULL, 0);
return pos; return pos;
} }
@ -2457,15 +2461,16 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
size_t len;
len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN); inc_byte_array(group->Counter, WPA_NONCE_LEN);
if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion", if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
wpa_auth->addr, group->GNonce, wpa_auth->addr, group->GNonce,
group->IGTK[group->GN_igtk - 4], group->IGTK[group->GN_igtk - 4], len) < 0)
WPA_IGTK_LEN) < 0)
ret = -1; ret = -1;
wpa_hexdump_key(MSG_DEBUG, "IGTK", wpa_hexdump_key(MSG_DEBUG, "IGTK",
group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN); group->IGTK[group->GN_igtk - 4], len);
} }
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
@ -2582,26 +2587,27 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{ {
struct wpa_group *gsm = sm->group; struct wpa_group *gsm = sm->group;
u8 *start = pos; u8 *start = pos;
size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
/* /*
* IGTK subelement: * IGTK subelement:
* Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16] * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
*/ */
*pos++ = WNM_SLEEP_SUBELEM_IGTK; *pos++ = WNM_SLEEP_SUBELEM_IGTK;
*pos++ = 2 + 6 + WPA_IGTK_LEN; *pos++ = 2 + 6 + len;
WPA_PUT_LE16(pos, gsm->GN_igtk); WPA_PUT_LE16(pos, gsm->GN_igtk);
pos += 2; pos += 2;
if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0) if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
return 0; return 0;
pos += 6; pos += 6;
os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len);
pos += WPA_IGTK_LEN; pos += len;
wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit", wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
gsm->GN_igtk); gsm->GN_igtk);
wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit", wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); gsm->IGTK[gsm->GN_igtk - 4], len);
return pos - start; return pos - start;
} }
@ -2656,12 +2662,19 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
ret = -1; ret = -1;
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION && if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK, enum wpa_alg alg;
size_t len;
alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher);
len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
if (ret == 0 &&
wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
broadcast_ether_addr, group->GN_igtk, broadcast_ether_addr, group->GN_igtk,
group->IGTK[group->GN_igtk - 4], group->IGTK[group->GN_igtk - 4], len) < 0)
WPA_IGTK_LEN) < 0)
ret = -1; ret = -1;
}
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
return ret; return ret;

View file

@ -142,6 +142,7 @@ struct wpa_auth_config {
int tx_status; int tx_status;
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w; enum mfp_options ieee80211w;
int group_mgmt_cipher;
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R #ifdef CONFIG_IEEE80211R
#define SSID_LEN 32 #define SSID_LEN 32

View file

@ -49,6 +49,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->okc = conf->okc; wconf->okc = conf->okc;
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w; wconf->ieee80211w = conf->ieee80211w;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R #ifdef CONFIG_IEEE80211R
wconf->ssid_len = conf->ssid.ssid_len; wconf->ssid_len = conf->ssid.ssid_len;

View file

@ -154,7 +154,7 @@ struct wpa_group {
Boolean first_sta_seen; Boolean first_sta_seen;
Boolean reject_4way_hs_for_entropy; Boolean reject_4way_hs_for_entropy;
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
u8 IGTK[2][WPA_IGTK_LEN]; u8 IGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk; int GN_igtk, GM_igtk;
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
}; };

View file

@ -261,7 +261,25 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
} }
/* Management Group Cipher Suite */ /* Management Group Cipher Suite */
switch (conf->group_mgmt_cipher) {
case WPA_CIPHER_AES_128_CMAC:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
break;
case WPA_CIPHER_BIP_GMAC_128:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128);
break;
case WPA_CIPHER_BIP_GMAC_256:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256);
break;
case WPA_CIPHER_BIP_CMAC_256:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256);
break;
default:
wpa_printf(MSG_DEBUG,
"Invalid group management cipher (0x%x)",
conf->group_mgmt_cipher);
return -1;
}
pos += RSN_SELECTOR_LEN; pos += RSN_SELECTOR_LEN;
} }
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
@ -586,7 +604,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
return WPA_MGMT_FRAME_PROTECTION_VIOLATION; return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
} }
if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher)
{
wpa_printf(MSG_DEBUG, "Unsupported management group " wpa_printf(MSG_DEBUG, "Unsupported management group "
"cipher %d", data.mgmt_group_cipher); "cipher %d", data.mgmt_group_cipher);
return WPA_INVALID_MGMT_GROUP_CIPHER; return WPA_INVALID_MGMT_GROUP_CIPHER;

View file

@ -368,6 +368,8 @@ static int rsn_selector_to_bitfield(const u8 *s)
return WPA_CIPHER_BIP_GMAC_256; return WPA_CIPHER_BIP_GMAC_256;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256) if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256)
return WPA_CIPHER_BIP_CMAC_256; return WPA_CIPHER_BIP_CMAC_256;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
return WPA_CIPHER_GTK_NOT_USED;
return 0; return 0;
} }
@ -400,6 +402,26 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
} }
static int wpa_cipher_valid_group(int cipher)
{
return wpa_cipher_valid_pairwise(cipher) ||
cipher == WPA_CIPHER_WEP104 ||
cipher == WPA_CIPHER_WEP40 ||
cipher == WPA_CIPHER_GTK_NOT_USED;
}
#ifdef CONFIG_IEEE80211W
int wpa_cipher_valid_mgmt_group(int cipher)
{
return cipher == WPA_CIPHER_AES_128_CMAC ||
cipher == WPA_CIPHER_BIP_GMAC_128 ||
cipher == WPA_CIPHER_BIP_GMAC_256 ||
cipher == WPA_CIPHER_BIP_CMAC_256;
}
#endif /* CONFIG_IEEE80211W */
/** /**
* wpa_parse_wpa_ie_rsn - Parse RSN IE * wpa_parse_wpa_ie_rsn - Parse RSN IE
* @rsn_ie: Buffer containing RSN IE * @rsn_ie: Buffer containing RSN IE
@ -455,13 +477,11 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
if (left >= RSN_SELECTOR_LEN) { if (left >= RSN_SELECTOR_LEN) {
data->group_cipher = rsn_selector_to_bitfield(pos); data->group_cipher = rsn_selector_to_bitfield(pos);
#ifdef CONFIG_IEEE80211W if (!wpa_cipher_valid_group(data->group_cipher)) {
if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) { wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x",
wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group " __func__, data->group_cipher);
"cipher", __func__);
return -1; return -1;
} }
#endif /* CONFIG_IEEE80211W */
pos += RSN_SELECTOR_LEN; pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN;
} else if (left > 0) { } else if (left > 0) {
@ -546,7 +566,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
if (left >= 4) { if (left >= 4) {
data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
wpa_printf(MSG_DEBUG, "%s: Unsupported management " wpa_printf(MSG_DEBUG, "%s: Unsupported management "
"group cipher 0x%x", __func__, "group cipher 0x%x", __func__,
data->mgmt_group_cipher); data->mgmt_group_cipher);
@ -1103,9 +1123,13 @@ int wpa_cipher_key_len(int cipher)
switch (cipher) { switch (cipher) {
case WPA_CIPHER_CCMP_256: case WPA_CIPHER_CCMP_256:
case WPA_CIPHER_GCMP_256: case WPA_CIPHER_GCMP_256:
case WPA_CIPHER_BIP_GMAC_256:
case WPA_CIPHER_BIP_CMAC_256:
return 32; return 32;
case WPA_CIPHER_CCMP: case WPA_CIPHER_CCMP:
case WPA_CIPHER_GCMP: case WPA_CIPHER_GCMP:
case WPA_CIPHER_AES_128_CMAC:
case WPA_CIPHER_BIP_GMAC_128:
return 16; return 16;
case WPA_CIPHER_TKIP: case WPA_CIPHER_TKIP:
return 32; return 32;
@ -1153,6 +1177,14 @@ int wpa_cipher_to_alg(int cipher)
case WPA_CIPHER_WEP104: case WPA_CIPHER_WEP104:
case WPA_CIPHER_WEP40: case WPA_CIPHER_WEP40:
return WPA_ALG_WEP; return WPA_ALG_WEP;
case WPA_CIPHER_AES_128_CMAC:
return WPA_ALG_IGTK;
case WPA_CIPHER_BIP_GMAC_128:
return WPA_ALG_BIP_GMAC_128;
case WPA_CIPHER_BIP_GMAC_256:
return WPA_ALG_BIP_GMAC_256;
case WPA_CIPHER_BIP_CMAC_256:
return WPA_ALG_BIP_CMAC_256;
} }
return WPA_ALG_NONE; return WPA_ALG_NONE;
} }
@ -1193,6 +1225,14 @@ u32 wpa_cipher_to_suite(int proto, int cipher)
RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
if (cipher & WPA_CIPHER_GTK_NOT_USED) if (cipher & WPA_CIPHER_GTK_NOT_USED)
return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
if (cipher & WPA_CIPHER_AES_128_CMAC)
return RSN_CIPHER_SUITE_AES_128_CMAC;
if (cipher & WPA_CIPHER_BIP_GMAC_128)
return RSN_CIPHER_SUITE_BIP_GMAC_128;
if (cipher & WPA_CIPHER_BIP_GMAC_256)
return RSN_CIPHER_SUITE_BIP_GMAC_256;
if (cipher & WPA_CIPHER_BIP_CMAC_256)
return RSN_CIPHER_SUITE_BIP_CMAC_256;
return 0; return 0;
} }

View file

@ -77,9 +77,7 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#endif #endif
#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4) #define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) #define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#ifdef CONFIG_IEEE80211W
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6) #define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#endif /* CONFIG_IEEE80211W */
#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7) #define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8) #define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
#define RSN_CIPHER_SUITE_GCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 9) #define RSN_CIPHER_SUITE_GCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
@ -130,6 +128,7 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
#define WPA_IGTK_LEN 16 #define WPA_IGTK_LEN 16
#define WPA_IGTK_MAX_LEN 32
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
@ -285,10 +284,11 @@ struct rsn_error_kde {
} STRUCT_PACKED; } STRUCT_PACKED;
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
#define WPA_IGTK_KDE_PREFIX_LEN (2 + 6)
struct wpa_igtk_kde { struct wpa_igtk_kde {
u8 keyid[2]; u8 keyid[2];
u8 pn[6]; u8 pn[6];
u8 igtk[WPA_IGTK_LEN]; u8 igtk[WPA_IGTK_MAX_LEN];
} STRUCT_PACKED; } STRUCT_PACKED;
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
@ -409,6 +409,7 @@ int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher); int wpa_cipher_rsc_len(int cipher);
int wpa_cipher_to_alg(int cipher); int wpa_cipher_to_alg(int cipher);
int wpa_cipher_valid_pairwise(int cipher); int wpa_cipher_valid_pairwise(int cipher);
int wpa_cipher_valid_mgmt_group(int cipher);
u32 wpa_cipher_to_suite(int proto, int cipher); u32 wpa_cipher_to_suite(int proto, int cipher);
int rsn_cipher_put_suites(u8 *pos, int ciphers); int rsn_cipher_put_suites(u8 *pos, int ciphers);
int wpa_cipher_put_suites(u8 *pos, int ciphers); int wpa_cipher_put_suites(u8 *pos, int ciphers);

View file

@ -742,13 +742,15 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie) struct wpa_eapol_ie_parse *ie)
{ {
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
return 0; return 0;
if (ie->igtk) { if (ie->igtk) {
size_t len;
const struct wpa_igtk_kde *igtk; const struct wpa_igtk_kde *igtk;
u16 keyidx; u16 keyidx;
if (ie->igtk_len != sizeof(*igtk)) len = wpa_cipher_key_len(sm->mgmt_group_cipher);
if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len)
return -1; return -1;
igtk = (const struct wpa_igtk_kde *) ie->igtk; igtk = (const struct wpa_igtk_kde *) ie->igtk;
keyidx = WPA_GET_LE16(igtk->keyid); keyidx = WPA_GET_LE16(igtk->keyid);
@ -756,15 +758,16 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
"pn %02x%02x%02x%02x%02x%02x", "pn %02x%02x%02x%02x%02x%02x",
keyidx, MAC2STR(igtk->pn)); keyidx, MAC2STR(igtk->pn));
wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
igtk->igtk, WPA_IGTK_LEN); igtk->igtk, len);
if (keyidx > 4095) { if (keyidx > 4095) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid IGTK KeyID %d", keyidx); "WPA: Invalid IGTK KeyID %d", keyidx);
return -1; return -1;
} }
if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
broadcast_ether_addr,
keyidx, 0, igtk->pn, sizeof(igtk->pn), keyidx, 0, igtk->pn, sizeof(igtk->pn),
igtk->igtk, WPA_IGTK_LEN) < 0) { igtk->igtk, len) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to configure IGTK to the driver"); "WPA: Failed to configure IGTK to the driver");
return -1; return -1;
@ -1097,7 +1100,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed; goto failed;
} }
if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) { if (ie.igtk &&
wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) &&
ie.igtk_len != WPA_IGTK_KDE_PREFIX_LEN +
(unsigned int) wpa_cipher_key_len(sm->mgmt_group_cipher)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid IGTK KDE length %lu", "WPA: Invalid IGTK KDE length %lu",
(unsigned long) ie.igtk_len); (unsigned long) ie.igtk_len);
@ -2748,17 +2754,19 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
} }
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) { } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
os_memcpy(igd.keyid, buf + 2, 2); os_memcpy(igd.keyid, buf + 2, 2);
os_memcpy(igd.pn, buf + 4, 6); os_memcpy(igd.pn, buf + 4, 6);
keyidx = WPA_GET_LE16(igd.keyid); keyidx = WPA_GET_LE16(igd.keyid);
os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN); os_memcpy(igd.igtk, buf + 10, keylen);
wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)", wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
igd.igtk, WPA_IGTK_LEN); igd.igtk, keylen);
if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
broadcast_ether_addr,
keyidx, 0, igd.pn, sizeof(igd.pn), keyidx, 0, igd.pn, sizeof(igd.pn),
igd.igtk, WPA_IGTK_LEN) < 0) { igd.igtk, keylen) < 0) {
wpa_printf(MSG_DEBUG, "Failed to install the IGTK in " wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
"WNM mode"); "WNM mode");
return -1; return -1;

View file

@ -201,7 +201,7 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
} }
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
if (!sm->cur_pmksa) { if (!sm->cur_pmksa) {
/* PMKID Count */ /* PMKID Count */
WPA_PUT_LE16(pos, 0); WPA_PUT_LE16(pos, 0);
@ -209,7 +209,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
} }
/* Management Group Cipher Suite */ /* Management Group Cipher Suite */
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
mgmt_group_cipher));
pos += RSN_SELECTOR_LEN; pos += RSN_SELECTOR_LEN;
} }
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */

View file

@ -1114,6 +1114,18 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher " wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
"AES-128-CMAC"); "AES-128-CMAC");
} else if (sel & WPA_CIPHER_BIP_GMAC_128) {
wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
"BIP-GMAC-128");
} else if (sel & WPA_CIPHER_BIP_GMAC_256) {
wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
"BIP-GMAC-256");
} else if (sel & WPA_CIPHER_BIP_CMAC_256) {
wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
"BIP-CMAC-256");
} else { } else {
wpa_s->mgmt_group_cipher = 0; wpa_s->mgmt_group_cipher = 0;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher"); wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");