]>
Commit | Line | Data |
---|---|---|
d7d57745 MT |
1 | From 927f891007c402fefd1ff384645b3f07597c3ede Mon Sep 17 00:00:00 2001 |
2 | From: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be> | |
3 | Date: Wed, 12 Jul 2017 16:03:24 +0200 | |
4 | Subject: [PATCH 2/8] Prevent reinstallation of an already in-use group key | |
5 | ||
6 | Track the current GTK and IGTK that is in use and when receiving a | |
7 | (possibly retransmitted) Group Message 1 or WNM-Sleep Mode Response, do | |
8 | not install the given key if it is already in use. This prevents an | |
9 | attacker from trying to trick the client into resetting or lowering the | |
10 | sequence counter associated to the group key. | |
11 | ||
12 | Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be> | |
13 | --- | |
14 | src/common/wpa_common.h | 11 +++++ | |
15 | src/rsn_supp/wpa.c | 116 ++++++++++++++++++++++++++++++------------------ | |
16 | src/rsn_supp/wpa_i.h | 4 ++ | |
17 | 3 files changed, 87 insertions(+), 44 deletions(-) | |
18 | ||
19 | diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h | |
20 | index af1d0f0..d200285 100644 | |
21 | --- a/src/common/wpa_common.h | |
22 | +++ b/src/common/wpa_common.h | |
23 | @@ -217,6 +217,17 @@ struct wpa_ptk { | |
24 | size_t tk_len; | |
25 | }; | |
26 | ||
27 | +struct wpa_gtk { | |
28 | + u8 gtk[WPA_GTK_MAX_LEN]; | |
29 | + size_t gtk_len; | |
30 | +}; | |
31 | + | |
32 | +#ifdef CONFIG_IEEE80211W | |
33 | +struct wpa_igtk { | |
34 | + u8 igtk[WPA_IGTK_MAX_LEN]; | |
35 | + size_t igtk_len; | |
36 | +}; | |
37 | +#endif /* CONFIG_IEEE80211W */ | |
38 | ||
39 | /* WPA IE version 1 | |
40 | * 00-50-f2:1 (OUI:OUI type) | |
41 | diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c | |
42 | index 3c47879..95bd7be 100644 | |
43 | --- a/src/rsn_supp/wpa.c | |
44 | +++ b/src/rsn_supp/wpa.c | |
45 | @@ -714,6 +714,15 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, | |
46 | const u8 *_gtk = gd->gtk; | |
47 | u8 gtk_buf[32]; | |
48 | ||
49 | + /* Detect possible key reinstallation */ | |
50 | + if (sm->gtk.gtk_len == (size_t) gd->gtk_len && | |
51 | + os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) { | |
52 | + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | |
53 | + "WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)", | |
54 | + gd->keyidx, gd->tx, gd->gtk_len); | |
55 | + return 0; | |
56 | + } | |
57 | + | |
58 | wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len); | |
59 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | |
60 | "WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)", | |
61 | @@ -748,6 +757,9 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, | |
62 | } | |
63 | os_memset(gtk_buf, 0, sizeof(gtk_buf)); | |
64 | ||
65 | + sm->gtk.gtk_len = gd->gtk_len; | |
66 | + os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len); | |
67 | + | |
68 | return 0; | |
69 | } | |
70 | ||
71 | @@ -854,6 +866,48 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, | |
72 | } | |
73 | ||
74 | ||
75 | +#ifdef CONFIG_IEEE80211W | |
76 | +static int wpa_supplicant_install_igtk(struct wpa_sm *sm, | |
77 | + const struct wpa_igtk_kde *igtk) | |
78 | +{ | |
79 | + size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher); | |
80 | + u16 keyidx = WPA_GET_LE16(igtk->keyid); | |
81 | + | |
82 | + /* Detect possible key reinstallation */ | |
83 | + if (sm->igtk.igtk_len == len && | |
84 | + os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) { | |
85 | + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | |
86 | + "WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)", | |
87 | + keyidx); | |
88 | + return 0; | |
89 | + } | |
90 | + | |
91 | + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | |
92 | + "WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x", | |
93 | + keyidx, MAC2STR(igtk->pn)); | |
94 | + wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len); | |
95 | + if (keyidx > 4095) { | |
96 | + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | |
97 | + "WPA: Invalid IGTK KeyID %d", keyidx); | |
98 | + return -1; | |
99 | + } | |
100 | + if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), | |
101 | + broadcast_ether_addr, | |
102 | + keyidx, 0, igtk->pn, sizeof(igtk->pn), | |
103 | + igtk->igtk, len) < 0) { | |
104 | + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | |
105 | + "WPA: Failed to configure IGTK to the driver"); | |
106 | + return -1; | |
107 | + } | |
108 | + | |
109 | + sm->igtk.igtk_len = len; | |
110 | + os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len); | |
111 | + | |
112 | + return 0; | |
113 | +} | |
114 | +#endif /* CONFIG_IEEE80211W */ | |
115 | + | |
116 | + | |
117 | static int ieee80211w_set_keys(struct wpa_sm *sm, | |
118 | struct wpa_eapol_ie_parse *ie) | |
119 | { | |
120 | @@ -864,30 +918,14 @@ static int ieee80211w_set_keys(struct wpa_sm *sm, | |
121 | if (ie->igtk) { | |
122 | size_t len; | |
123 | const struct wpa_igtk_kde *igtk; | |
124 | - u16 keyidx; | |
125 | + | |
126 | len = wpa_cipher_key_len(sm->mgmt_group_cipher); | |
127 | if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len) | |
128 | return -1; | |
129 | + | |
130 | igtk = (const struct wpa_igtk_kde *) ie->igtk; | |
131 | - keyidx = WPA_GET_LE16(igtk->keyid); | |
132 | - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d " | |
133 | - "pn %02x%02x%02x%02x%02x%02x", | |
134 | - keyidx, MAC2STR(igtk->pn)); | |
135 | - wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", | |
136 | - igtk->igtk, len); | |
137 | - if (keyidx > 4095) { | |
138 | - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | |
139 | - "WPA: Invalid IGTK KeyID %d", keyidx); | |
140 | - return -1; | |
141 | - } | |
142 | - if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), | |
143 | - broadcast_ether_addr, | |
144 | - keyidx, 0, igtk->pn, sizeof(igtk->pn), | |
145 | - igtk->igtk, len) < 0) { | |
146 | - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | |
147 | - "WPA: Failed to configure IGTK to the driver"); | |
148 | + if (wpa_supplicant_install_igtk(sm, igtk) < 0) | |
149 | return -1; | |
150 | - } | |
151 | } | |
152 | ||
153 | return 0; | |
154 | @@ -2307,7 +2345,7 @@ void wpa_sm_deinit(struct wpa_sm *sm) | |
155 | */ | |
156 | void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) | |
157 | { | |
158 | - int clear_ptk = 1; | |
159 | + int clear_keys = 1; | |
160 | ||
161 | if (sm == NULL) | |
162 | return; | |
163 | @@ -2333,11 +2371,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) | |
164 | /* Prepare for the next transition */ | |
165 | wpa_ft_prepare_auth_request(sm, NULL); | |
166 | ||
167 | - clear_ptk = 0; | |
168 | + clear_keys = 0; | |
169 | } | |
170 | #endif /* CONFIG_IEEE80211R */ | |
171 | ||
172 | - if (clear_ptk) { | |
173 | + if (clear_keys) { | |
174 | /* | |
175 | * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if | |
176 | * this is not part of a Fast BSS Transition. | |
177 | @@ -2347,6 +2385,10 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) | |
178 | os_memset(&sm->ptk, 0, sizeof(sm->ptk)); | |
179 | sm->tptk_set = 0; | |
180 | os_memset(&sm->tptk, 0, sizeof(sm->tptk)); | |
181 | + os_memset(&sm->gtk, 0, sizeof(sm->gtk)); | |
182 | +#ifdef CONFIG_IEEE80211W | |
183 | + os_memset(&sm->igtk, 0, sizeof(sm->igtk)); | |
184 | +#endif /* CONFIG_IEEE80211W */ | |
185 | } | |
186 | ||
187 | #ifdef CONFIG_TDLS | |
188 | @@ -2877,6 +2919,10 @@ void wpa_sm_drop_sa(struct wpa_sm *sm) | |
189 | os_memset(sm->pmk, 0, sizeof(sm->pmk)); | |
190 | os_memset(&sm->ptk, 0, sizeof(sm->ptk)); | |
191 | os_memset(&sm->tptk, 0, sizeof(sm->tptk)); | |
192 | + os_memset(&sm->gtk, 0, sizeof(sm->gtk)); | |
193 | +#ifdef CONFIG_IEEE80211W | |
194 | + os_memset(&sm->igtk, 0, sizeof(sm->igtk)); | |
195 | +#endif /* CONFIG_IEEE80211W */ | |
196 | #ifdef CONFIG_IEEE80211R | |
197 | os_memset(sm->xxkey, 0, sizeof(sm->xxkey)); | |
198 | os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0)); | |
199 | @@ -2949,29 +2995,11 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) | |
200 | os_memset(&gd, 0, sizeof(gd)); | |
201 | #ifdef CONFIG_IEEE80211W | |
202 | } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) { | |
203 | - struct wpa_igtk_kde igd; | |
204 | - u16 keyidx; | |
205 | - | |
206 | - os_memset(&igd, 0, sizeof(igd)); | |
207 | - keylen = wpa_cipher_key_len(sm->mgmt_group_cipher); | |
208 | - os_memcpy(igd.keyid, buf + 2, 2); | |
209 | - os_memcpy(igd.pn, buf + 4, 6); | |
210 | - | |
211 | - keyidx = WPA_GET_LE16(igd.keyid); | |
212 | - os_memcpy(igd.igtk, buf + 10, keylen); | |
213 | - | |
214 | - wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)", | |
215 | - igd.igtk, keylen); | |
216 | - if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), | |
217 | - broadcast_ether_addr, | |
218 | - keyidx, 0, igd.pn, sizeof(igd.pn), | |
219 | - igd.igtk, keylen) < 0) { | |
220 | - wpa_printf(MSG_DEBUG, "Failed to install the IGTK in " | |
221 | - "WNM mode"); | |
222 | - os_memset(&igd, 0, sizeof(igd)); | |
223 | + const struct wpa_igtk_kde *igtk; | |
224 | + | |
225 | + igtk = (const struct wpa_igtk_kde *) (buf + 2); | |
226 | + if (wpa_supplicant_install_igtk(sm, igtk) < 0) | |
227 | return -1; | |
228 | - } | |
229 | - os_memset(&igd, 0, sizeof(igd)); | |
230 | #endif /* CONFIG_IEEE80211W */ | |
231 | } else { | |
232 | wpa_printf(MSG_DEBUG, "Unknown element id"); | |
233 | diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h | |
234 | index f653ba6..afc9e37 100644 | |
235 | --- a/src/rsn_supp/wpa_i.h | |
236 | +++ b/src/rsn_supp/wpa_i.h | |
237 | @@ -31,6 +31,10 @@ struct wpa_sm { | |
238 | u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN]; | |
239 | int rx_replay_counter_set; | |
240 | u8 request_counter[WPA_REPLAY_COUNTER_LEN]; | |
241 | + struct wpa_gtk gtk; | |
242 | +#ifdef CONFIG_IEEE80211W | |
243 | + struct wpa_igtk igtk; | |
244 | +#endif /* CONFIG_IEEE80211W */ | |
245 | ||
246 | struct eapol_sm *eapol; /* EAPOL state machine from upper level code */ | |
247 | ||
248 | -- | |
249 | 2.7.4 | |
250 |