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