Brad Bishop | d5ae7d9 | 2018-06-14 09:52:03 -0700 | [diff] [blame] | 1 | The WPA2 four-way handshake protocol is vulnerable to replay attacks which can |
| 2 | result in unauthenticated clients gaining access to the network. |
| 3 | |
| 4 | Backport a number of patches from upstream to fix this. |
| 5 | |
| 6 | CVE: CVE-2017-13077 |
| 7 | CVE: CVE-2017-13078 |
| 8 | CVE: CVE-2017-13079 |
| 9 | CVE: CVE-2017-13080 |
| 10 | CVE: CVE-2017-13081 |
| 11 | CVE: CVE-2017-13082 |
| 12 | CVE: CVE-2017-13086 |
| 13 | CVE: CVE-2017-13087 |
| 14 | CVE: CVE-2017-13088 |
| 15 | |
| 16 | Upstream-Status: Backport |
| 17 | Signed-off-by: Ross Burton <ross.burton@intel.com> |
| 18 | |
| 19 | From cf4cab804c7afd5c45505528a8d16e46163243a2 Mon Sep 17 00:00:00 2001 |
| 20 | From: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be> |
| 21 | Date: Fri, 14 Jul 2017 15:15:35 +0200 |
| 22 | Subject: [PATCH 1/8] hostapd: Avoid key reinstallation in FT handshake |
| 23 | |
| 24 | Do not reinstall TK to the driver during Reassociation Response frame |
| 25 | processing if the first attempt of setting the TK succeeded. This avoids |
| 26 | issues related to clearing the TX/RX PN that could result in reusing |
| 27 | same PN values for transmitted frames (e.g., due to CCM nonce reuse and |
| 28 | also hitting replay protection on the receiver) and accepting replayed |
| 29 | frames on RX side. |
| 30 | |
| 31 | This issue was introduced by the commit |
| 32 | 0e84c25434e6a1f283c7b4e62e483729085b78d2 ('FT: Fix PTK configuration in |
| 33 | authenticator') which allowed wpa_ft_install_ptk() to be called multiple |
| 34 | times with the same PTK. While the second configuration attempt is |
| 35 | needed with some drivers, it must be done only if the first attempt |
| 36 | failed. |
| 37 | |
| 38 | Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be> |
| 39 | --- |
| 40 | src/ap/ieee802_11.c | 16 +++++++++++++--- |
| 41 | src/ap/wpa_auth.c | 11 +++++++++++ |
| 42 | src/ap/wpa_auth.h | 3 ++- |
| 43 | src/ap/wpa_auth_ft.c | 10 ++++++++++ |
| 44 | src/ap/wpa_auth_i.h | 1 + |
| 45 | 5 files changed, 37 insertions(+), 4 deletions(-) |
| 46 | |
| 47 | diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c |
| 48 | index 4e04169..333035f 100644 |
| 49 | --- a/src/ap/ieee802_11.c |
| 50 | +++ b/src/ap/ieee802_11.c |
| 51 | @@ -1841,6 +1841,7 @@ static int add_associated_sta(struct hostapd_data *hapd, |
| 52 | { |
| 53 | struct ieee80211_ht_capabilities ht_cap; |
| 54 | struct ieee80211_vht_capabilities vht_cap; |
| 55 | + int set = 1; |
| 56 | |
| 57 | /* |
| 58 | * Remove the STA entry to ensure the STA PS state gets cleared and |
| 59 | @@ -1848,9 +1849,18 @@ static int add_associated_sta(struct hostapd_data *hapd, |
| 60 | * FT-over-the-DS, where a station re-associates back to the same AP but |
| 61 | * skips the authentication flow, or if working with a driver that |
| 62 | * does not support full AP client state. |
| 63 | + * |
| 64 | + * Skip this if the STA has already completed FT reassociation and the |
| 65 | + * TK has been configured since the TX/RX PN must not be reset to 0 for |
| 66 | + * the same key. |
| 67 | */ |
| 68 | - if (!sta->added_unassoc) |
| 69 | + if (!sta->added_unassoc && |
| 70 | + (!(sta->flags & WLAN_STA_AUTHORIZED) || |
| 71 | + !wpa_auth_sta_ft_tk_already_set(sta->wpa_sm))) { |
| 72 | hostapd_drv_sta_remove(hapd, sta->addr); |
| 73 | + wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED); |
| 74 | + set = 0; |
| 75 | + } |
| 76 | |
| 77 | #ifdef CONFIG_IEEE80211N |
| 78 | if (sta->flags & WLAN_STA_HT) |
| 79 | @@ -1873,11 +1883,11 @@ static int add_associated_sta(struct hostapd_data *hapd, |
| 80 | sta->flags & WLAN_STA_VHT ? &vht_cap : NULL, |
| 81 | sta->flags | WLAN_STA_ASSOC, sta->qosinfo, |
| 82 | sta->vht_opmode, sta->p2p_ie ? 1 : 0, |
| 83 | - sta->added_unassoc)) { |
| 84 | + set)) { |
| 85 | hostapd_logger(hapd, sta->addr, |
| 86 | HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, |
| 87 | "Could not %s STA to kernel driver", |
| 88 | - sta->added_unassoc ? "set" : "add"); |
| 89 | + set ? "set" : "add"); |
| 90 | |
| 91 | if (sta->added_unassoc) { |
| 92 | hostapd_drv_sta_remove(hapd, sta->addr); |
| 93 | diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c |
| 94 | index 3587086..707971d 100644 |
| 95 | --- a/src/ap/wpa_auth.c |
| 96 | +++ b/src/ap/wpa_auth.c |
| 97 | @@ -1745,6 +1745,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) |
| 98 | #else /* CONFIG_IEEE80211R */ |
| 99 | break; |
| 100 | #endif /* CONFIG_IEEE80211R */ |
| 101 | + case WPA_DRV_STA_REMOVED: |
| 102 | + sm->tk_already_set = FALSE; |
| 103 | + return 0; |
| 104 | } |
| 105 | |
| 106 | #ifdef CONFIG_IEEE80211R |
| 107 | @@ -3250,6 +3253,14 @@ int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm) |
| 108 | } |
| 109 | |
| 110 | |
| 111 | +int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm) |
| 112 | +{ |
| 113 | + if (!sm || !wpa_key_mgmt_ft(sm->wpa_key_mgmt)) |
| 114 | + return 0; |
| 115 | + return sm->tk_already_set; |
| 116 | +} |
| 117 | + |
| 118 | + |
| 119 | int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, |
| 120 | struct rsn_pmksa_cache_entry *entry) |
| 121 | { |
| 122 | diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h |
| 123 | index 0de8d97..97461b0 100644 |
| 124 | --- a/src/ap/wpa_auth.h |
| 125 | +++ b/src/ap/wpa_auth.h |
| 126 | @@ -267,7 +267,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, |
| 127 | u8 *data, size_t data_len); |
| 128 | enum wpa_event { |
| 129 | WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH, |
| 130 | - WPA_REAUTH_EAPOL, WPA_ASSOC_FT |
| 131 | + WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_DRV_STA_REMOVED |
| 132 | }; |
| 133 | void wpa_remove_ptk(struct wpa_state_machine *sm); |
| 134 | int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event); |
| 135 | @@ -280,6 +280,7 @@ int wpa_auth_pairwise_set(struct wpa_state_machine *sm); |
| 136 | int wpa_auth_get_pairwise(struct wpa_state_machine *sm); |
| 137 | int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm); |
| 138 | int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm); |
| 139 | +int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm); |
| 140 | int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, |
| 141 | struct rsn_pmksa_cache_entry *entry); |
| 142 | struct rsn_pmksa_cache_entry * |
| 143 | diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c |
| 144 | index 42242a5..e63b99a 100644 |
| 145 | --- a/src/ap/wpa_auth_ft.c |
| 146 | +++ b/src/ap/wpa_auth_ft.c |
| 147 | @@ -780,6 +780,14 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm) |
| 148 | return; |
| 149 | } |
| 150 | |
| 151 | + if (sm->tk_already_set) { |
| 152 | + /* Must avoid TK reconfiguration to prevent clearing of TX/RX |
| 153 | + * PN in the driver */ |
| 154 | + wpa_printf(MSG_DEBUG, |
| 155 | + "FT: Do not re-install same PTK to the driver"); |
| 156 | + return; |
| 157 | + } |
| 158 | + |
| 159 | /* FIX: add STA entry to kernel/driver here? The set_key will fail |
| 160 | * most likely without this.. At the moment, STA entry is added only |
| 161 | * after association has been completed. This function will be called |
| 162 | @@ -792,6 +800,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm) |
| 163 | |
| 164 | /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ |
| 165 | sm->pairwise_set = TRUE; |
| 166 | + sm->tk_already_set = TRUE; |
| 167 | } |
| 168 | |
| 169 | |
| 170 | @@ -898,6 +907,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, |
| 171 | |
| 172 | sm->pairwise = pairwise; |
| 173 | sm->PTK_valid = TRUE; |
| 174 | + sm->tk_already_set = FALSE; |
| 175 | wpa_ft_install_ptk(sm); |
| 176 | |
| 177 | buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + |
| 178 | diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h |
| 179 | index 72b7eb3..7fd8f05 100644 |
| 180 | --- a/src/ap/wpa_auth_i.h |
| 181 | +++ b/src/ap/wpa_auth_i.h |
| 182 | @@ -65,6 +65,7 @@ struct wpa_state_machine { |
| 183 | struct wpa_ptk PTK; |
| 184 | Boolean PTK_valid; |
| 185 | Boolean pairwise_set; |
| 186 | + Boolean tk_already_set; |
| 187 | int keycount; |
| 188 | Boolean Pair; |
| 189 | struct wpa_key_replay_counter { |
| 190 | -- |
| 191 | 2.7.4 |