/src/hostap/tests/fuzzing/eapol-key-auth/eapol-key-auth.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Testing tool for EAPOL-Key Authenticator routines |
3 | | * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi> |
4 | | * |
5 | | * This software may be distributed under the terms of the BSD license. |
6 | | * See README for more details. |
7 | | */ |
8 | | |
9 | | #include "utils/includes.h" |
10 | | |
11 | | #include "utils/common.h" |
12 | | #include "utils/eloop.h" |
13 | | #include "ap/wpa_auth.h" |
14 | | #include "../fuzzer-common.h" |
15 | | |
16 | | |
17 | | struct wpa { |
18 | | const u8 *data; |
19 | | size_t data_len; |
20 | | size_t data_offset; |
21 | | int wpa1; |
22 | | |
23 | | u8 auth_addr[ETH_ALEN]; |
24 | | u8 supp_addr[ETH_ALEN]; |
25 | | u8 psk[PMK_LEN]; |
26 | | |
27 | | /* from supplicant */ |
28 | | u8 *supp_eapol; |
29 | | size_t supp_eapol_len; |
30 | | |
31 | | struct wpa_auth_callbacks auth_cb; |
32 | | struct wpa_authenticator *auth_group; |
33 | | struct wpa_state_machine *auth; |
34 | | |
35 | | u8 supp_ie[80]; |
36 | | size_t supp_ie_len; |
37 | | |
38 | | int key_request_done; |
39 | | int key_request_done1; |
40 | | int auth_sent; |
41 | | }; |
42 | | |
43 | | |
44 | | const struct wpa_driver_ops *const wpa_drivers[] = { NULL }; |
45 | | |
46 | | |
47 | | static int auth_read_msg(struct wpa *wpa); |
48 | | static void supp_eapol_key_request(void *eloop_data, void *user_ctx); |
49 | | |
50 | | |
51 | | static u8 * read_msg(struct wpa *wpa, size_t *ret_len) |
52 | 4.03M | { |
53 | 4.03M | u16 msg_len; |
54 | 4.03M | u8 *msg; |
55 | | |
56 | 4.03M | if (wpa->data_len - wpa->data_offset < 2) { |
57 | 846 | wpa_printf(MSG_ERROR, "TEST-ERROR: Could not read msg len"); |
58 | 846 | eloop_terminate(); |
59 | 846 | return NULL; |
60 | 846 | } |
61 | 4.03M | msg_len = WPA_GET_BE16(&wpa->data[wpa->data_offset]); |
62 | 4.03M | wpa->data_offset += 2; |
63 | | |
64 | 4.03M | msg = os_malloc(msg_len); |
65 | 4.03M | if (!msg) |
66 | 0 | return NULL; |
67 | 4.03M | if (msg_len > 0 && wpa->data_len - wpa->data_offset < msg_len) { |
68 | 370 | wpa_printf(MSG_ERROR, "TEST-ERROR: Truncated msg (msg_len=%u)", |
69 | 370 | msg_len); |
70 | 370 | os_free(msg); |
71 | 370 | eloop_terminate(); |
72 | 370 | return NULL; |
73 | 370 | } |
74 | 4.03M | os_memcpy(msg, &wpa->data[wpa->data_offset], msg_len); |
75 | 4.03M | wpa->data_offset += msg_len; |
76 | 4.03M | wpa_hexdump(MSG_DEBUG, "TEST: Read message from file", msg, msg_len); |
77 | | |
78 | 4.03M | *ret_len = msg_len; |
79 | 4.03M | return msg; |
80 | 4.03M | } |
81 | | |
82 | | |
83 | | static void auth_eapol_rx(void *eloop_data, void *user_ctx) |
84 | 4.03M | { |
85 | 4.03M | struct wpa *wpa = eloop_data; |
86 | | |
87 | 4.03M | wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame"); |
88 | 4.03M | wpa->auth_sent = 0; |
89 | 4.03M | wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol, |
90 | 4.03M | wpa->supp_eapol_len); |
91 | 4.03M | if (!wpa->auth_sent) { |
92 | | /* Speed up process by not going through retransmit timeout */ |
93 | 4.03M | wpa_printf(MSG_DEBUG, |
94 | 4.03M | "AUTH: No response was sent - process next message"); |
95 | 4.03M | auth_read_msg(wpa); |
96 | 4.03M | } |
97 | 4.03M | if (wpa->wpa1 && wpa->key_request_done && !wpa->key_request_done1) { |
98 | 0 | wpa->key_request_done1 = 1; |
99 | 0 | eloop_register_timeout(0, 0, supp_eapol_key_request, |
100 | 0 | wpa, NULL); |
101 | 0 | } |
102 | | |
103 | 4.03M | } |
104 | | |
105 | | |
106 | | static void auth_logger(void *ctx, const u8 *addr, logger_level level, |
107 | | const char *txt) |
108 | 55.4k | { |
109 | 55.4k | if (addr) |
110 | 54.2k | wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", |
111 | 54.2k | MAC2STR(addr), txt); |
112 | 1.18k | else |
113 | 1.18k | wpa_printf(MSG_DEBUG, "AUTH: %s", txt); |
114 | 55.4k | } |
115 | | |
116 | | |
117 | | static int auth_read_msg(struct wpa *wpa) |
118 | 4.03M | { |
119 | 4.03M | os_free(wpa->supp_eapol); |
120 | 4.03M | wpa->supp_eapol = read_msg(wpa, &wpa->supp_eapol_len); |
121 | 4.03M | if (!wpa->supp_eapol) |
122 | 1.21k | return -1; |
123 | 4.03M | eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL); |
124 | 4.03M | return 0; |
125 | 4.03M | } |
126 | | |
127 | | |
128 | | static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, |
129 | | size_t data_len, int encrypt) |
130 | 2.42k | { |
131 | 2.42k | struct wpa *wpa = ctx; |
132 | | |
133 | 2.42k | wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu " |
134 | 2.42k | "encrypt=%d)", |
135 | 2.42k | __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); |
136 | 2.42k | wpa->auth_sent = 1; |
137 | | |
138 | 2.42k | return auth_read_msg(wpa); |
139 | 2.42k | } |
140 | | |
141 | | |
142 | | static const u8 * auth_get_psk(void *ctx, const u8 *addr, |
143 | | const u8 *p2p_dev_addr, const u8 *prev_psk, |
144 | | size_t *psk_len, int *vlan_id) |
145 | 3.54k | { |
146 | 3.54k | struct wpa *wpa = ctx; |
147 | | |
148 | 3.54k | wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", |
149 | 3.54k | __func__, MAC2STR(addr), prev_psk); |
150 | 3.54k | if (vlan_id) |
151 | 1.10k | *vlan_id = 0; |
152 | 3.54k | if (psk_len) |
153 | 2.32k | *psk_len = PMK_LEN; |
154 | 3.54k | if (prev_psk) |
155 | 222 | return NULL; |
156 | 3.31k | return wpa->psk; |
157 | 3.54k | } |
158 | | |
159 | | |
160 | | static void supp_eapol_key_request(void *eloop_data, void *user_ctx) |
161 | 611 | { |
162 | 611 | struct wpa *wpa = eloop_data; |
163 | | |
164 | 611 | wpa_printf(MSG_DEBUG, "SUPP: EAPOL-Key Request trigger"); |
165 | 611 | if (!eloop_is_timeout_registered(auth_eapol_rx, wpa, NULL)) |
166 | 0 | auth_read_msg(wpa); |
167 | 611 | } |
168 | | |
169 | | |
170 | | static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, |
171 | | const u8 *addr, int idx, u8 *key, |
172 | | size_t key_len, enum key_flag key_flag) |
173 | 5.97k | { |
174 | 5.97k | struct wpa *wpa = ctx; |
175 | | |
176 | 5.97k | wpa_printf(MSG_DEBUG, |
177 | 5.97k | "AUTH: %s (vlan_id=%d alg=%d idx=%d key_len=%d key_flag=0x%x)", |
178 | 5.97k | __func__, vlan_id, alg, idx, (int) key_len, key_flag); |
179 | 5.97k | if (addr) |
180 | 5.97k | wpa_printf(MSG_DEBUG, "AUTH: addr=" MACSTR, MAC2STR(addr)); |
181 | | |
182 | 5.97k | if (alg != WPA_ALG_NONE && idx == 0 && key_len > 0 && |
183 | 5.97k | !wpa->key_request_done) { |
184 | 619 | wpa_printf(MSG_DEBUG, "Test EAPOL-Key Request"); |
185 | 619 | wpa->key_request_done = 1; |
186 | 619 | if (!wpa->wpa1) |
187 | 619 | eloop_register_timeout(0, 0, supp_eapol_key_request, |
188 | 619 | wpa, NULL); |
189 | 619 | } |
190 | | |
191 | 5.97k | return 0; |
192 | 5.97k | } |
193 | | |
194 | | |
195 | | static int auth_init_group(struct wpa *wpa) |
196 | 1.21k | { |
197 | 1.21k | struct wpa_auth_config conf; |
198 | | |
199 | 1.21k | wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); |
200 | | |
201 | 1.21k | os_memset(&conf, 0, sizeof(conf)); |
202 | 1.21k | if (wpa->wpa1) { |
203 | 0 | conf.wpa = 1; |
204 | 0 | conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; |
205 | 0 | conf.wpa_pairwise = WPA_CIPHER_TKIP; |
206 | 0 | conf.wpa_group = WPA_CIPHER_TKIP; |
207 | 1.21k | } else { |
208 | 1.21k | conf.wpa = 2; |
209 | 1.21k | conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; |
210 | 1.21k | conf.wpa_pairwise = WPA_CIPHER_CCMP; |
211 | 1.21k | conf.rsn_pairwise = WPA_CIPHER_CCMP; |
212 | 1.21k | conf.wpa_group = WPA_CIPHER_CCMP; |
213 | 1.21k | conf.ieee80211w = 2; |
214 | 1.21k | conf.group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC; |
215 | 1.21k | } |
216 | 1.21k | conf.eapol_version = 2; |
217 | 1.21k | conf.wpa_group_update_count = 4; |
218 | 1.21k | conf.wpa_pairwise_update_count = 4; |
219 | | |
220 | 1.21k | wpa->auth_cb.logger = auth_logger; |
221 | 1.21k | wpa->auth_cb.send_eapol = auth_send_eapol; |
222 | 1.21k | wpa->auth_cb.get_psk = auth_get_psk; |
223 | 1.21k | wpa->auth_cb.set_key = auth_set_key; |
224 | | |
225 | 1.21k | wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &wpa->auth_cb, wpa); |
226 | 1.21k | if (!wpa->auth_group) { |
227 | 0 | wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); |
228 | 0 | return -1; |
229 | 0 | } |
230 | | |
231 | 1.21k | return 0; |
232 | 1.21k | } |
233 | | |
234 | | |
235 | | static int auth_init(struct wpa *wpa) |
236 | 1.21k | { |
237 | 1.21k | const u8 *supp_ie; |
238 | 1.21k | size_t supp_ie_len; |
239 | 1.21k | static const u8 ie_rsn[] = { |
240 | 1.21k | 0x30, 0x14, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, |
241 | 1.21k | 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, |
242 | 1.21k | 0x00, 0x0f, 0xac, 0x02, 0x80, 0x00 |
243 | 1.21k | }; |
244 | 1.21k | static const u8 ie_wpa[] = { |
245 | 1.21k | 0xdd, 0x16, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00, |
246 | 1.21k | 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, |
247 | 1.21k | 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02 |
248 | 1.21k | }; |
249 | | |
250 | 1.21k | if (wpa->wpa1) { |
251 | 0 | supp_ie = ie_wpa; |
252 | 0 | supp_ie_len = sizeof(ie_wpa); |
253 | 1.21k | } else { |
254 | 1.21k | supp_ie = ie_rsn; |
255 | 1.21k | supp_ie_len = sizeof(ie_rsn); |
256 | 1.21k | } |
257 | | |
258 | 1.21k | wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr, NULL); |
259 | 1.21k | if (!wpa->auth) { |
260 | 0 | wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); |
261 | 0 | return -1; |
262 | 0 | } |
263 | | |
264 | 1.21k | if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, 2412, supp_ie, |
265 | 1.21k | supp_ie_len, NULL, 0, NULL, 0, NULL, 0, NULL, |
266 | 1.21k | false) != WPA_IE_OK) { |
267 | 0 | wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); |
268 | 0 | return -1; |
269 | 0 | } |
270 | | |
271 | 1.21k | wpa_auth_sm_event(wpa->auth, WPA_ASSOC); |
272 | | |
273 | 1.21k | wpa_auth_sta_associated(wpa->auth_group, wpa->auth); |
274 | | |
275 | 1.21k | return 0; |
276 | 1.21k | } |
277 | | |
278 | | |
279 | | static void deinit(struct wpa *wpa) |
280 | 1.21k | { |
281 | 1.21k | wpa_auth_sta_deinit(wpa->auth); |
282 | 1.21k | wpa_deinit(wpa->auth_group); |
283 | 1.21k | os_free(wpa->supp_eapol); |
284 | 1.21k | wpa->supp_eapol = NULL; |
285 | 1.21k | } |
286 | | |
287 | | |
288 | | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
289 | 1.21k | { |
290 | 1.21k | struct wpa wpa; |
291 | | |
292 | 1.21k | wpa_fuzzer_set_debug_level(); |
293 | | |
294 | 1.21k | if (os_program_init()) |
295 | 0 | return -1; |
296 | | |
297 | 1.21k | os_memset(&wpa, 0, sizeof(wpa)); |
298 | 1.21k | wpa.data = data; |
299 | 1.21k | wpa.data_len = size; |
300 | | |
301 | 1.21k | os_memset(wpa.auth_addr, 0x12, ETH_ALEN); |
302 | 1.21k | os_memset(wpa.supp_addr, 0x32, ETH_ALEN); |
303 | 1.21k | os_memset(wpa.psk, 0x44, PMK_LEN); |
304 | | |
305 | 1.21k | if (eloop_init()) { |
306 | 0 | wpa_printf(MSG_ERROR, "Failed to initialize event loop"); |
307 | 0 | goto fail; |
308 | 0 | } |
309 | | |
310 | 1.21k | if (auth_init_group(&wpa) < 0) |
311 | 0 | goto fail; |
312 | | |
313 | 1.21k | if (auth_init(&wpa) < 0) |
314 | 0 | goto fail; |
315 | | |
316 | 1.21k | wpa_printf(MSG_DEBUG, "Starting eloop"); |
317 | 1.21k | eloop_run(); |
318 | 1.21k | wpa_printf(MSG_DEBUG, "eloop done"); |
319 | | |
320 | 1.21k | fail: |
321 | 1.21k | deinit(&wpa); |
322 | | |
323 | 1.21k | eloop_destroy(); |
324 | | |
325 | 1.21k | os_program_deinit(); |
326 | | |
327 | 1.21k | return 0; |
328 | 1.21k | } |