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