From 236d2506b5e2272b0c791fa0195d536fc356e0a4 Mon Sep 17 00:00:00 2001 From: Haiqing Bai Date: Fri, 27 Oct 2017 15:37:41 +0800 Subject: [PATCH] hostapd: WPA packet number reuse with replayed messages and key reinstallation Issue: LIN5-23848 LIN5-23828 A vulnerability was found in how a number of implementations can be triggered to reconfigure WPA/WPA2/RSN keys (TK, GTK, or IGTK) by replaying a specific frame that is used to manage the keys. Such reinstallation of the encryption key can result in two different types of vulnerabilities: disabling replay protection and significantly reducing the security of encryption to the point of allowing frames to be decrypted or some parts of the keys to be determined by an attacker depending on which cipher is used. CVE-2017-13077 CVE-2017-13082 Signed-off-by: Haiqing Bai --- ...-Avoid-key-reinstallation-in-FT-handshake.patch | 130 +++++++++++++++++++++ ...Fix-PTK-rekeying-to-generate-a-new-ANonce.patch | 67 +++++++++++ recipes-connectivity/hostapd/hostapd_1.0.bb | 4 +- 3 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 recipes-connectivity/hostapd/hostapd/0001-hostapd-Avoid-key-reinstallation-in-FT-handshake.patch create mode 100644 recipes-connectivity/hostapd/hostapd/0005-Fix-PTK-rekeying-to-generate-a-new-ANonce.patch diff --git a/recipes-connectivity/hostapd/hostapd/0001-hostapd-Avoid-key-reinstallation-in-FT-handshake.patch b/recipes-connectivity/hostapd/hostapd/0001-hostapd-Avoid-key-reinstallation-in-FT-handshake.patch new file mode 100644 index 0000000..5174cfc --- /dev/null +++ b/recipes-connectivity/hostapd/hostapd/0001-hostapd-Avoid-key-reinstallation-in-FT-handshake.patch @@ -0,0 +1,130 @@ +From c34b2957e56e3572020a6cc267e040606b08dd11 Mon Sep 17 00:00:00 2001 +From: Haiqing Bai +Date: Wed, 18 Oct 2017 16:31:14 +0800 +Subject: [PATCH 1/3] hostapd: Avoid key reinstallation in FT handshake + +https://w1.fi/security/2017-1/rebased-v2.6-0001-hostapd-Avoid-key-reinstallation-in-FT-handshake.patch + +Do not reinstall TK to the driver during Reassociation Response frame +processing if the first attempt of setting the TK succeeded. This avoids +issues related to clearing the TX/RX PN that could result in reusing +same PN values for transmitted frames (e.g., due to CCM nonce reuse and +also hitting replay protection on the receiver) and accepting replayed +frames on RX side. + +This issue was introduced by the commit +0e84c25434e6a1f283c7b4e62e483729085b78d2 ('FT: Fix PTK configuration in +authenticator') which allowed wpa_ft_install_ptk() to be called multiple +times with the same PTK. While the second configuration attempt is +needed with some drivers, it must be done only if the first attempt +failed. + +Upstream-Status: Backport + +Signed-off-by: Mathy Vanhoef +Signed-off-by: Haiqing Bai +--- + src/ap/wpa_auth.c | 9 +++++++++ + src/ap/wpa_auth.h | 3 ++- + src/ap/wpa_auth_ft.c | 10 ++++++++++ + src/ap/wpa_auth_i.h | 1 + + 4 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c +index 34202b6..f3b3389 100644 +--- a/src/ap/wpa_auth.c ++++ b/src/ap/wpa_auth.c +@@ -1447,6 +1447,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) + #else /* CONFIG_IEEE80211R */ + break; + #endif /* CONFIG_IEEE80211R */ ++ case WPA_DRV_STA_REMOVED: ++ sm->tk_already_set = FALSE; ++ return 0; + } + + #ifdef CONFIG_IEEE80211R +@@ -2755,6 +2758,12 @@ int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm) + return sm->wpa; + } + ++int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm) ++{ ++ if (!sm || !wpa_key_mgmt_ft(sm->wpa_key_mgmt)) ++ return 0; ++ return sm->tk_already_set; ++} + + int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, + struct rsn_pmksa_cache_entry *entry) +diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h +index ce2751e..fd93ab4 100644 +--- a/src/ap/wpa_auth.h ++++ b/src/ap/wpa_auth.h +@@ -236,7 +236,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, + u8 *data, size_t data_len); + typedef enum { + WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH, +- WPA_REAUTH_EAPOL, WPA_ASSOC_FT ++ WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_DRV_STA_REMOVED + } wpa_event; + void wpa_remove_ptk(struct wpa_state_machine *sm); + int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event); +@@ -249,6 +249,7 @@ int wpa_auth_pairwise_set(struct wpa_state_machine *sm); + int wpa_auth_get_pairwise(struct wpa_state_machine *sm); + int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm); + int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm); ++int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm); + int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, + struct rsn_pmksa_cache_entry *entry); + struct rsn_pmksa_cache_entry * +diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c +index 4a7d619..c4f087d 100644 +--- a/src/ap/wpa_auth_ft.c ++++ b/src/ap/wpa_auth_ft.c +@@ -736,6 +736,14 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm) + return; + } + ++ if (sm->tk_already_set) { ++ /* Must avoid TK reconfiguration to prevent clearing of TX/RX ++ * PN in the driver */ ++ wpa_printf(MSG_DEBUG, ++ "FT: Do not re-install same PTK to the driver"); ++ return; ++ } ++ + /* FIX: add STA entry to kernel/driver here? The set_key will fail + * most likely without this.. At the moment, STA entry is added only + * after association has been completed. This function will be called +@@ -748,6 +756,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm) + + /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ + sm->pairwise_set = TRUE; ++ sm->tk_already_set = TRUE; + } + + +@@ -861,6 +870,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm, + wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); + + sm->pairwise = pairwise; ++ sm->tk_already_set = FALSE; + wpa_ft_install_ptk(sm); + + buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + +diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h +index d82192a..2606b23 100644 +--- a/src/ap/wpa_auth_i.h ++++ b/src/ap/wpa_auth_i.h +@@ -67,6 +67,7 @@ struct wpa_state_machine { + struct wpa_ptk PTK; + Boolean PTK_valid; + Boolean pairwise_set; ++ Boolean tk_already_set; + int keycount; + Boolean Pair; + struct { +-- +1.9.1 + diff --git a/recipes-connectivity/hostapd/hostapd/0005-Fix-PTK-rekeying-to-generate-a-new-ANonce.patch b/recipes-connectivity/hostapd/hostapd/0005-Fix-PTK-rekeying-to-generate-a-new-ANonce.patch new file mode 100644 index 0000000..01e5d0a --- /dev/null +++ b/recipes-connectivity/hostapd/hostapd/0005-Fix-PTK-rekeying-to-generate-a-new-ANonce.patch @@ -0,0 +1,67 @@ +From 50b6fab5ce0f7cc26ff45edc0318f1c013fa0c32 Mon Sep 17 00:00:00 2001 +From: Haiqing Bai +Date: Wed, 18 Oct 2017 15:59:36 +0800 +Subject: [PATCH 2/3] Fix PTK rekeying to generate a new ANonce + +https://w1.fi/security/2017-1/rebased-v2.6-0005-Fix-PTK-rekeying-to-generate-a-new-ANonce.patch + +The Authenticator state machine path for PTK rekeying ended up bypassing +the AUTHENTICATION2 state where a new ANonce is generated when going +directly to the PTKSTART state since there is no need to try to +determine the PMK again in such a case. This is far from ideal since the +new PTK would depend on a new nonce only from the supplicant. + +Fix this by generating a new ANonce when moving to the PTKSTART state +for the purpose of starting new 4-way handshake to rekey PTK. + +Upstream-Status: Backport + +Signed-off-by: Jouni Malinen +Signed-off-by: Haiqing Bai +--- + src/ap/wpa_auth.c | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c +index f3b3389..f1ff8a9 100644 +--- a/src/ap/wpa_auth.c ++++ b/src/ap/wpa_auth.c +@@ -1590,6 +1590,19 @@ SM_STATE(WPA_PTK, AUTHENTICATION2) + sm->TimeoutCtr = 0; + } + ++static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm) ++{ ++ if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) { ++ wpa_printf(MSG_ERROR, ++ "WPA: Failed to get random data for ANonce"); ++ sm->Disconnect = TRUE; ++ return -1; ++ } ++ wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce, ++ WPA_NONCE_LEN); ++ sm->TimeoutCtr = 0; ++ return 0; ++} + + SM_STATE(WPA_PTK, INITPMK) + { +@@ -2068,9 +2081,12 @@ SM_STEP(WPA_PTK) + SM_ENTER(WPA_PTK, AUTHENTICATION); + else if (sm->ReAuthenticationRequest) + SM_ENTER(WPA_PTK, AUTHENTICATION2); +- else if (sm->PTKRequest) +- SM_ENTER(WPA_PTK, PTKSTART); +- else switch (sm->wpa_ptk_state) { ++ else if (sm->PTKRequest) { ++ if (wpa_auth_sm_ptk_update(sm) < 0) ++ SM_ENTER(WPA_PTK, DISCONNECTED); ++ else ++ SM_ENTER(WPA_PTK, PTKSTART); ++ } else switch (sm->wpa_ptk_state) { + case WPA_PTK_INITIALIZE: + break; + case WPA_PTK_DISCONNECT: +-- +1.9.1 + diff --git a/recipes-connectivity/hostapd/hostapd_1.0.bb b/recipes-connectivity/hostapd/hostapd_1.0.bb index 2911385..f446088 100644 --- a/recipes-connectivity/hostapd/hostapd_1.0.bb +++ b/recipes-connectivity/hostapd/hostapd_1.0.bb @@ -22,7 +22,7 @@ LICENSE = "GPLv2.0" LIC_FILES_CHKSUM = "file://COPYING;md5=c54ce9345727175ff66d17b67ff51f58" SECTION = "base" -PR = "r5" +PR = "r6" SRC_URI = "\ http://hostap.epitest.fi/releases/${BPN}-${PV}.tar.gz \ @@ -37,6 +37,8 @@ SRC_URI = "\ file://0001-NFC-Avoid-misaligned-read-of-an-NDEF-field.patch \ file://0001-NFC-Fix-payload-length-validation-in-NDEF-record-par.patch \ file://0001-WPS-Reject-a-Credential-with-invalid-passphrase.patch \ + file://0001-hostapd-Avoid-key-reinstallation-in-FT-handshake.patch \ + file://0005-Fix-PTK-rekeying-to-generate-a-new-ANonce.patch \ " SRC_URI[md5sum] = "236247a7bbd4f60d5fa3e99849d1ffc9" -- 1.9.1