19165cce2d2838eee0cdef090d10c402e6a3a5a7
[librecmc/librecmc.git] /
1 From 6f234c1e2ee1ede29f2412b7012b3345ed8e52d3 Mon Sep 17 00:00:00 2001
2 From: Jouni Malinen <j@w1.fi>
3 Date: Mon, 16 Oct 2017 18:37:43 +0300
4 Subject: [PATCH] Optional AP side workaround for key reinstallation attacks
5
6 This adds a new hostapd configuration parameter
7 wpa_disable_eapol_key_retries=1 that can be used to disable
8 retransmission of EAPOL-Key frames that are used to install
9 keys (EAPOL-Key message 3/4 and group message 1/2). This is
10 similar to setting wpa_group_update_count=1 and
11 wpa_pairwise_update_count=1, but with no impact to message 1/4
12 retries and with extended timeout for messages 4/4 and group
13 message 2/2 to avoid causing issues with stations that may use
14 aggressive power saving have very long time in replying to the
15 EAPOL-Key messages.
16
17 This option can be used to work around key reinstallation attacks
18 on the station (supplicant) side in cases those station devices
19 cannot be updated for some reason. By removing the
20 retransmissions the attacker cannot cause key reinstallation with
21 a delayed frame transmission. This is related to the station side
22 vulnerabilities CVE-2017-13077, CVE-2017-13078, CVE-2017-13079,
23 CVE-2017-13080, and CVE-2017-13081.
24
25 This workaround might cause interoperability issues and reduced
26 robustness of key negotiation especially in environments with
27 heavy traffic load due to the number of attempts to perform the
28 key exchange is reduced significantly. As such, this workaround
29 is disabled by default (unless overridden in build
30 configuration). To enable this, set the parameter to 1.
31
32 It is also possible to enable this in the build by default by
33 adding the following to the build configuration:
34
35 CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
36
37 Signed-off-by: Jouni Malinen <j@w1.fi>
38 ---
39  hostapd/config_file.c  |  2 ++
40  hostapd/defconfig      |  4 ++++
41  hostapd/hostapd.conf   | 24 ++++++++++++++++++++++++
42  src/ap/ap_config.c     |  6 ++++++
43  src/ap/ap_config.h     |  1 +
44  src/ap/wpa_auth.c      | 22 ++++++++++++++++++++--
45  src/ap/wpa_auth.h      |  1 +
46  src/ap/wpa_auth_glue.c |  2 ++
47  8 files changed, 60 insertions(+), 2 deletions(-)
48
49 --- a/hostapd/config_file.c
50 +++ b/hostapd/config_file.c
51 @@ -2542,6 +2542,8 @@ static int hostapd_config_fill(struct ho
52                         return 1;
53                 }
54                 bss->wpa_pairwise_update_count = (u32) val;
55 +       } else if (os_strcmp(buf, "wpa_disable_eapol_key_retries") == 0) {
56 +               bss->wpa_disable_eapol_key_retries = atoi(pos);
57         } else if (os_strcmp(buf, "wpa_passphrase") == 0) {
58                 int len = os_strlen(pos);
59                 if (len < 8 || len > 63) {
60 --- a/hostapd/defconfig
61 +++ b/hostapd/defconfig
62 @@ -372,3 +372,7 @@ CONFIG_IPV6=y
63  # Opportunistic Wireless Encryption (OWE)
64  # Experimental implementation of draft-harkins-owe-07.txt
65  #CONFIG_OWE=y
66 +
67 +# Override default value for the wpa_disable_eapol_key_retries configuration
68 +# parameter. See that parameter in hostapd.conf for more details.
69 +#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
70 --- a/hostapd/hostapd.conf
71 +++ b/hostapd/hostapd.conf
72 @@ -1315,6 +1315,30 @@ own_ip_addr=127.0.0.1
73  # Range 1..4294967295; default: 4
74  #wpa_pairwise_update_count=4
75  
76 +# Workaround for key reinstallation attacks
77 +#
78 +# This parameter can be used to disable retransmission of EAPOL-Key frames that
79 +# are used to install keys (EAPOL-Key message 3/4 and group message 1/2). This
80 +# is similar to setting wpa_group_update_count=1 and
81 +# wpa_pairwise_update_count=1, but with no impact to message 1/4 and with
82 +# extended timeout on the response to avoid causing issues with stations that
83 +# may use aggressive power saving have very long time in replying to the
84 +# EAPOL-Key messages.
85 +#
86 +# This option can be used to work around key reinstallation attacks on the
87 +# station (supplicant) side in cases those station devices cannot be updated
88 +# for some reason. By removing the retransmissions the attacker cannot cause
89 +# key reinstallation with a delayed frame transmission. This is related to the
90 +# station side vulnerabilities CVE-2017-13077, CVE-2017-13078, CVE-2017-13079,
91 +# CVE-2017-13080, and CVE-2017-13081.
92 +#
93 +# This workaround might cause interoperability issues and reduced robustness of
94 +# key negotiation especially in environments with heavy traffic load due to the
95 +# number of attempts to perform the key exchange is reduced significantly. As
96 +# such, this workaround is disabled by default (unless overridden in build
97 +# configuration). To enable this, set the parameter to 1.
98 +#wpa_disable_eapol_key_retries=1
99 +
100  # Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
101  # roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
102  # authentication and key handshake before actually associating with a new AP.
103 --- a/src/ap/ap_config.c
104 +++ b/src/ap/ap_config.c
105 @@ -37,6 +37,10 @@ static void hostapd_config_free_vlan(str
106  }
107  
108  
109 +#ifndef DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES
110 +#define DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES 0
111 +#endif /* DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES */
112 +
113  void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
114  {
115         dl_list_init(&bss->anqp_elem);
116 @@ -58,6 +62,8 @@ void hostapd_config_defaults_bss(struct
117         bss->wpa_gmk_rekey = 86400;
118         bss->wpa_group_update_count = 4;
119         bss->wpa_pairwise_update_count = 4;
120 +       bss->wpa_disable_eapol_key_retries =
121 +               DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES;
122         bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
123         bss->wpa_pairwise = WPA_CIPHER_TKIP;
124         bss->wpa_group = WPA_CIPHER_TKIP;
125 --- a/src/ap/ap_config.h
126 +++ b/src/ap/ap_config.h
127 @@ -333,6 +333,7 @@ struct hostapd_bss_config {
128         int wpa_ptk_rekey;
129         u32 wpa_group_update_count;
130         u32 wpa_pairwise_update_count;
131 +       int wpa_disable_eapol_key_retries;
132         int rsn_pairwise;
133         int rsn_preauth;
134         char *rsn_preauth_interfaces;
135 --- a/src/ap/wpa_auth.c
136 +++ b/src/ap/wpa_auth.c
137 @@ -65,6 +65,7 @@ static u8 * ieee80211w_kde_add(struct wp
138  static const u32 eapol_key_timeout_first = 100; /* ms */
139  static const u32 eapol_key_timeout_subseq = 1000; /* ms */
140  static const u32 eapol_key_timeout_first_group = 500; /* ms */
141 +static const u32 eapol_key_timeout_no_retrans = 4000; /* ms */
142  
143  /* TODO: make these configurable */
144  static const int dot11RSNAConfigPMKLifetime = 43200;
145 @@ -1653,6 +1654,9 @@ static void wpa_send_eapol(struct wpa_au
146                         eapol_key_timeout_first_group;
147         else
148                 timeout_ms = eapol_key_timeout_subseq;
149 +       if (wpa_auth->conf.wpa_disable_eapol_key_retries &&
150 +           (!pairwise || (key_info & WPA_KEY_INFO_MIC)))
151 +               timeout_ms = eapol_key_timeout_no_retrans;
152         if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
153                 sm->pending_1_of_4_timeout = 1;
154         wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
155 @@ -2882,6 +2886,11 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
156         sm->TimeoutEvt = FALSE;
157  
158         sm->TimeoutCtr++;
159 +       if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
160 +           sm->TimeoutCtr > 1) {
161 +               /* Do not allow retransmission of EAPOL-Key msg 3/4 */
162 +               return;
163 +       }
164         if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
165                 /* No point in sending the EAPOL-Key - we will disconnect
166                  * immediately following this. */
167 @@ -3220,7 +3229,9 @@ SM_STEP(WPA_PTK)
168                          sm->EAPOLKeyPairwise && sm->MICVerified)
169                         SM_ENTER(WPA_PTK, PTKINITDONE);
170                 else if (sm->TimeoutCtr >
171 -                        sm->wpa_auth->conf.wpa_pairwise_update_count) {
172 +                        sm->wpa_auth->conf.wpa_pairwise_update_count ||
173 +                        (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
174 +                         sm->TimeoutCtr > 1)) {
175                         wpa_auth->dot11RSNA4WayHandshakeFailures++;
176                         wpa_auth_vlogger(
177                                 sm->wpa_auth, sm->addr, LOGGER_DEBUG,
178 @@ -3260,6 +3271,11 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING
179         SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
180  
181         sm->GTimeoutCtr++;
182 +       if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
183 +           sm->GTimeoutCtr > 1) {
184 +               /* Do not allow retransmission of EAPOL-Key group msg 1/2 */
185 +               return;
186 +       }
187         if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
188                 /* No point in sending the EAPOL-Key - we will disconnect
189                  * immediately following this. */
190 @@ -3363,7 +3379,9 @@ SM_STEP(WPA_PTK_GROUP)
191                     !sm->EAPOLKeyPairwise && sm->MICVerified)
192                         SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
193                 else if (sm->GTimeoutCtr >
194 -                        sm->wpa_auth->conf.wpa_group_update_count)
195 +                        sm->wpa_auth->conf.wpa_group_update_count ||
196 +                        (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
197 +                         sm->GTimeoutCtr > 1))
198                         SM_ENTER(WPA_PTK_GROUP, KEYERROR);
199                 else if (sm->TimeoutEvt)
200                         SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
201 --- a/src/ap/wpa_auth.h
202 +++ b/src/ap/wpa_auth.h
203 @@ -165,6 +165,7 @@ struct wpa_auth_config {
204         int wpa_ptk_rekey;
205         u32 wpa_group_update_count;
206         u32 wpa_pairwise_update_count;
207 +       int wpa_disable_eapol_key_retries;
208         int rsn_pairwise;
209         int rsn_preauth;
210         int eapol_version;
211 --- a/src/ap/wpa_auth_glue.c
212 +++ b/src/ap/wpa_auth_glue.c
213 @@ -45,6 +45,8 @@ static void hostapd_wpa_auth_conf(struct
214         wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
215         wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
216         wconf->wpa_group_update_count = conf->wpa_group_update_count;
217 +       wconf->wpa_disable_eapol_key_retries =
218 +               conf->wpa_disable_eapol_key_retries;
219         wconf->wpa_pairwise_update_count = conf->wpa_pairwise_update_count;
220         wconf->rsn_pairwise = conf->rsn_pairwise;
221         wconf->rsn_preauth = conf->rsn_preauth;