FILS: Add FILS SK auth PFS support in AP mode
This adds an option to configure hostapd to enable use of perfect forward secrecy option in FILS shared key authentication. A new build option CONFIG_FILS_SK_PFS=y can be used to include this functionality. A new runtime configuration parameter fils_dh_group is used to enable this by specifying which DH group to use. For example, fils_dh_group=19 would allow FILS SK PFS to be used with a 256-bit random ECP group. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
cad291d671
commit
1764559eef
10 changed files with 149 additions and 14 deletions
|
@ -272,6 +272,10 @@ L_CFLAGS += -DCONFIG_FILS
|
|||
OBJS += src/ap/fils_hlp.c
|
||||
NEED_SHA384=y
|
||||
NEED_AES_SIV=y
|
||||
ifdef CONFIG_FILS_SK_PFS
|
||||
L_CFLAGS += -DCONFIG_FILS_SK_PFS
|
||||
NEED_ECC=y
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_WNM
|
||||
|
|
|
@ -316,6 +316,10 @@ CFLAGS += -DCONFIG_FILS
|
|||
OBJS += ../src/ap/fils_hlp.o
|
||||
NEED_SHA384=y
|
||||
NEED_AES_SIV=y
|
||||
ifdef CONFIG_FILS_SK_PFS
|
||||
CFLAGS += -DCONFIG_FILS_SK_PFS
|
||||
NEED_ECC=y
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_WNM
|
||||
|
|
|
@ -3658,6 +3658,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
|||
} else if (os_strcmp(buf, "fils_realm") == 0) {
|
||||
if (parse_fils_realm(bss, pos) < 0)
|
||||
return 1;
|
||||
} else if (os_strcmp(buf, "fils_dh_group") == 0) {
|
||||
bss->fils_dh_group = atoi(pos);
|
||||
} else if (os_strcmp(buf, "dhcp_server") == 0) {
|
||||
if (hostapd_parse_ip_addr(pos, &bss->dhcp_server)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
|
|
|
@ -358,6 +358,8 @@ CONFIG_IPV6=y
|
|||
# Note: This is an experimental and not yet complete implementation. This
|
||||
# should not be enabled for production use.
|
||||
#CONFIG_FILS=y
|
||||
# FILS shared key authentication with PFS
|
||||
#CONFIG_FILS_SK_PFS=y
|
||||
|
||||
# Include internal line edit mode in hostapd_cli. This can be used to provide
|
||||
# limited command line editing and history support.
|
||||
|
|
|
@ -1393,6 +1393,11 @@ own_ip_addr=127.0.0.1
|
|||
#fils_realm=example.com
|
||||
#fils_realm=example.org
|
||||
|
||||
# FILS DH Group for PFS
|
||||
# 0 = PFS disabled with FILS shared key authentication (default)
|
||||
# 1-65535 DH Group to use for FILS PFS
|
||||
#fils_dh_group=0
|
||||
|
||||
# DHCP server for FILS HLP
|
||||
# If configured, hostapd will act as a DHCP relay for all FILS HLP requests
|
||||
# that include a DHCPDISCOVER message and send them to the specific DHCP
|
||||
|
|
|
@ -610,6 +610,7 @@ struct hostapd_bss_config {
|
|||
u8 fils_cache_id[FILS_CACHE_ID_LEN];
|
||||
int fils_cache_id_set;
|
||||
struct dl_list fils_realms; /* list of struct fils_realm */
|
||||
int fils_dh_group;
|
||||
struct hostapd_ip_addr dhcp_server;
|
||||
int dhcp_rapid_commit_proxy;
|
||||
unsigned int fils_hlp_wait_time;
|
||||
|
|
|
@ -1015,7 +1015,8 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
|
|||
|
||||
static void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const struct ieee80211_mgmt *mgmt, size_t len,
|
||||
u16 auth_transaction, u16 status_code)
|
||||
u16 auth_alg, u16 auth_transaction,
|
||||
u16 status_code)
|
||||
{
|
||||
u16 resp = WLAN_STATUS_SUCCESS;
|
||||
const u8 *pos, *end;
|
||||
|
@ -1033,8 +1034,76 @@ static void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
|
|||
wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
|
||||
pos, end - pos);
|
||||
|
||||
/* TODO: Finite Cyclic Group when using PK or PFS */
|
||||
/* TODO: Element when using PK or PFS */
|
||||
/* TODO: FILS PK */
|
||||
#ifdef CONFIG_FILS_SK_PFS
|
||||
if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
|
||||
u16 group;
|
||||
struct wpabuf *pub;
|
||||
size_t elem_len;
|
||||
|
||||
/* Using FILS PFS */
|
||||
|
||||
/* Finite Cyclic Group */
|
||||
if (end - pos < 2) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: No room for Finite Cyclic Group");
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
group = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
if (group != hapd->conf->fils_dh_group) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
|
||||
group, hapd->conf->fils_dh_group);
|
||||
resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
crypto_ecdh_deinit(sta->fils_ecdh);
|
||||
sta->fils_ecdh = crypto_ecdh_init(group);
|
||||
if (!sta->fils_ecdh) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"FILS: Could not initialize ECDH with group %d",
|
||||
group);
|
||||
resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
|
||||
if (!pub) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Failed to derive ECDH public key");
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
elem_len = wpabuf_len(pub);
|
||||
wpabuf_free(pub);
|
||||
|
||||
/* Element */
|
||||
if ((size_t) (end - pos) < elem_len) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: No room for Element");
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wpabuf_clear_free(sta->fils_dh_ss);
|
||||
sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
|
||||
pos, elem_len);
|
||||
if (!sta->fils_dh_ss) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
|
||||
pos += elem_len;
|
||||
} else {
|
||||
crypto_ecdh_deinit(sta->fils_ecdh);
|
||||
sta->fils_ecdh = NULL;
|
||||
wpabuf_clear_free(sta->fils_dh_ss);
|
||||
sta->fils_dh_ss = NULL;
|
||||
}
|
||||
#endif /* CONFIG_FILS_SK_PFS */
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
|
||||
if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
|
||||
|
@ -1173,6 +1242,8 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
|
|||
const u8 *pmk = NULL;
|
||||
size_t pmk_len = 0;
|
||||
u8 pmk_buf[PMK_LEN_MAX];
|
||||
struct wpabuf *pub = NULL;
|
||||
u16 auth_alg;
|
||||
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
goto fail;
|
||||
|
@ -1204,14 +1275,32 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
|
|||
wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
|
||||
fils_nonce, FILS_NONCE_LEN);
|
||||
|
||||
data = wpabuf_alloc(1000 + ielen);
|
||||
#ifdef CONFIG_FILS_SK_PFS
|
||||
if (sta->fils_dh_ss && sta->fils_ecdh) {
|
||||
pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
|
||||
if (!pub) {
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_FILS_SK_PFS */
|
||||
|
||||
data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
|
||||
if (!data) {
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* TODO: Finite Cyclic Group when using PK or PFS */
|
||||
/* TODO: Element when using PK or PFS */
|
||||
/* TODO: FILS PK */
|
||||
#ifdef CONFIG_FILS_SK_PFS
|
||||
if (pub) {
|
||||
/* Finite Cyclic Group */
|
||||
wpabuf_put_le16(data, hapd->conf->fils_dh_group);
|
||||
|
||||
/* Element */
|
||||
wpabuf_put_buf(data, pub);
|
||||
}
|
||||
#endif /* CONFIG_FILS_SK_PFS */
|
||||
|
||||
/* RSNE */
|
||||
wpabuf_put_data(data, ie, ielen);
|
||||
|
@ -1243,7 +1332,11 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
|
|||
|
||||
if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
|
||||
msk, msk_len, sta->fils_snonce, fils_nonce,
|
||||
NULL, 0, pmk_buf, &pmk_len)) {
|
||||
sta->fils_dh_ss ?
|
||||
wpabuf_head(sta->fils_dh_ss) : NULL,
|
||||
sta->fils_dh_ss ?
|
||||
wpabuf_len(sta->fils_dh_ss) : 0,
|
||||
pmk_buf, &pmk_len)) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
wpabuf_free(data);
|
||||
|
@ -1273,8 +1366,10 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
|
|||
}
|
||||
|
||||
fail:
|
||||
send_auth_reply(hapd, sta->addr, hapd->own_addr, WLAN_AUTH_FILS_SK, 2,
|
||||
resp,
|
||||
auth_alg = (pub ||
|
||||
resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
|
||||
WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
|
||||
send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
|
||||
data ? wpabuf_head(data) : (u8 *) "",
|
||||
data ? wpabuf_len(data) : 0);
|
||||
wpabuf_free(data);
|
||||
|
@ -1285,11 +1380,18 @@ fail:
|
|||
"authentication OK (FILS)");
|
||||
sta->flags |= WLAN_STA_AUTH;
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
|
||||
sta->auth_alg = WLAN_AUTH_FILS_SK;
|
||||
sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
|
||||
mlme_authenticate_indication(hapd, sta);
|
||||
}
|
||||
|
||||
os_free(ie_buf);
|
||||
wpabuf_free(pub);
|
||||
wpabuf_clear_free(sta->fils_dh_ss);
|
||||
sta->fils_dh_ss = NULL;
|
||||
#ifdef CONFIG_FILS_SK_PFS
|
||||
crypto_ecdh_deinit(sta->fils_ecdh);
|
||||
sta->fils_ecdh = NULL;
|
||||
#endif /* CONFIG_FILS_SK_PFS */
|
||||
}
|
||||
|
||||
|
||||
|
@ -1472,6 +1574,9 @@ static void handle_auth(struct hostapd_data *hapd,
|
|||
#ifdef CONFIG_FILS
|
||||
(hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
|
||||
auth_alg == WLAN_AUTH_FILS_SK) ||
|
||||
(hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
|
||||
hapd->conf->fils_dh_group &&
|
||||
auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
|
||||
#endif /* CONFIG_FILS */
|
||||
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
|
||||
auth_alg == WLAN_AUTH_SHARED_KEY))) {
|
||||
|
@ -1738,8 +1843,9 @@ static void handle_auth(struct hostapd_data *hapd,
|
|||
#endif /* CONFIG_SAE */
|
||||
#ifdef CONFIG_FILS
|
||||
case WLAN_AUTH_FILS_SK:
|
||||
handle_auth_fils(hapd, sta, mgmt, len, auth_transaction,
|
||||
status_code);
|
||||
case WLAN_AUTH_FILS_SK_PFS:
|
||||
handle_auth_fils(hapd, sta, mgmt, len, auth_alg,
|
||||
auth_transaction, status_code);
|
||||
return;
|
||||
#endif /* CONFIG_FILS */
|
||||
}
|
||||
|
|
|
@ -630,7 +630,10 @@ u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid)
|
|||
fils_info |= BIT(8); /* HESSID Included */
|
||||
/* FILS Shared Key Authentication without PFS Supported */
|
||||
fils_info |= BIT(9);
|
||||
/* TODO: B10: FILS Shared Key Authentication with PFS Supported */
|
||||
if (hapd->conf->fils_dh_group) {
|
||||
/* FILS Shared Key Authentication with PFS Supported */
|
||||
fils_info |= BIT(10);
|
||||
}
|
||||
/* TODO: B11: FILS Public Key Authentication Supported */
|
||||
/* B12..B15: Reserved */
|
||||
WPA_PUT_LE16(pos, fils_info);
|
||||
|
|
|
@ -345,6 +345,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
|||
wpabuf_free(sta->fils_hlp_resp);
|
||||
wpabuf_free(sta->hlp_dhcp_discover);
|
||||
eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
|
||||
#ifdef CONFIG_FILS_SK_PFS
|
||||
crypto_ecdh_deinit(sta->fils_ecdh);
|
||||
wpabuf_clear_free(sta->fils_dh_ss);
|
||||
#endif /* CONFIG_FILS_SK_PFS */
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
|
|
|
@ -231,6 +231,10 @@ struct sta_info {
|
|||
unsigned int fils_dhcp_rapid_commit_proxy:1;
|
||||
struct wpabuf *fils_hlp_resp;
|
||||
struct wpabuf *hlp_dhcp_discover;
|
||||
#ifdef CONFIG_FILS_SK_PFS
|
||||
struct crypto_ecdh *fils_ecdh;
|
||||
#endif /* CONFIG_FILS_SK_PFS */
|
||||
struct wpabuf *fils_dh_ss;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
|
|
Loading…
Reference in a new issue