]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/rsn_supp/preauth.c
fefca83ab477a862b6b9cf1b1fbe157bdac8440c
[thirdparty/hostap.git] / src / rsn_supp / preauth.c
1 /*
2 * RSN pre-authentication (supplicant)
3 * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "wpa.h"
19 #include "eloop.h"
20 #include "l2_packet/l2_packet.h"
21 #include "eapol_supp/eapol_supp_sm.h"
22 #include "preauth.h"
23 #include "pmksa_cache.h"
24 #include "wpa_i.h"
25
26
27 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
28
29 #define PMKID_CANDIDATE_PRIO_SCAN 1000
30
31
32 struct rsn_pmksa_candidate {
33 struct dl_list list;
34 u8 bssid[ETH_ALEN];
35 int priority;
36 };
37
38
39 /**
40 * pmksa_candidate_free - Free all entries in PMKSA candidate list
41 * @sm: Pointer to WPA state machine data from wpa_sm_init()
42 */
43 void pmksa_candidate_free(struct wpa_sm *sm)
44 {
45 struct rsn_pmksa_candidate *entry, *n;
46
47 if (sm == NULL)
48 return;
49
50 dl_list_for_each_safe(entry, n, &sm->pmksa_candidates,
51 struct rsn_pmksa_candidate, list) {
52 dl_list_del(&entry->list);
53 os_free(entry);
54 }
55 }
56
57
58 static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
59 const u8 *buf, size_t len)
60 {
61 struct wpa_sm *sm = ctx;
62
63 wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr));
64 wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
65
66 if (sm->preauth_eapol == NULL ||
67 is_zero_ether_addr(sm->preauth_bssid) ||
68 os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
69 wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
70 "unexpected source " MACSTR " - dropped",
71 MAC2STR(src_addr));
72 return;
73 }
74
75 eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len);
76 }
77
78
79 static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
80 void *ctx)
81 {
82 struct wpa_sm *sm = ctx;
83 u8 pmk[PMK_LEN];
84
85 if (success) {
86 int res, pmk_len;
87 pmk_len = PMK_LEN;
88 res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
89 if (res) {
90 /*
91 * EAP-LEAP is an exception from other EAP methods: it
92 * uses only 16-byte PMK.
93 */
94 res = eapol_sm_get_key(eapol, pmk, 16);
95 pmk_len = 16;
96 }
97 if (res == 0) {
98 wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth",
99 pmk, pmk_len);
100 sm->pmk_len = pmk_len;
101 pmksa_cache_add(sm->pmksa, pmk, pmk_len,
102 sm->preauth_bssid, sm->own_addr,
103 sm->network_ctx,
104 WPA_KEY_MGMT_IEEE8021X);
105 } else {
106 wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
107 "RSN: failed to get master session key from "
108 "pre-auth EAPOL state machines");
109 success = 0;
110 }
111 }
112
113 wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
114 MACSTR " %s", MAC2STR(sm->preauth_bssid),
115 success ? "completed successfully" : "failed");
116
117 rsn_preauth_deinit(sm);
118 rsn_preauth_candidate_process(sm);
119 }
120
121
122 static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx)
123 {
124 struct wpa_sm *sm = eloop_ctx;
125
126 wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
127 MACSTR " timed out", MAC2STR(sm->preauth_bssid));
128 rsn_preauth_deinit(sm);
129 rsn_preauth_candidate_process(sm);
130 }
131
132
133 static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf,
134 size_t len)
135 {
136 struct wpa_sm *sm = ctx;
137 u8 *msg;
138 size_t msglen;
139 int res;
140
141 /* TODO: could add l2_packet_sendmsg that allows fragments to avoid
142 * extra copy here */
143
144 if (sm->l2_preauth == NULL)
145 return -1;
146
147 msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL);
148 if (msg == NULL)
149 return -1;
150
151 wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
152 res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid,
153 ETH_P_RSN_PREAUTH, msg, msglen);
154 os_free(msg);
155 return res;
156 }
157
158
159 /**
160 * rsn_preauth_init - Start new RSN pre-authentication
161 * @sm: Pointer to WPA state machine data from wpa_sm_init()
162 * @dst: Authenticator address (BSSID) with which to preauthenticate
163 * @eap_conf: Current EAP configuration
164 * Returns: 0 on success, -1 on another pre-authentication is in progress,
165 * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine
166 * initialization failure, -4 on memory allocation failure
167 *
168 * This function request an RSN pre-authentication with a given destination
169 * address. This is usually called for PMKSA candidates found from scan results
170 * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger
171 * pre-authentication.
172 */
173 int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
174 struct eap_peer_config *eap_conf)
175 {
176 struct eapol_config eapol_conf;
177 struct eapol_ctx *ctx;
178
179 if (sm->preauth_eapol)
180 return -1;
181
182 wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
183 "RSN: starting pre-authentication with " MACSTR, MAC2STR(dst));
184
185 sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr,
186 ETH_P_RSN_PREAUTH,
187 rsn_preauth_receive, sm, 0);
188 if (sm->l2_preauth == NULL) {
189 wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet "
190 "processing for pre-authentication");
191 return -2;
192 }
193
194 if (sm->bridge_ifname) {
195 sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname,
196 sm->own_addr,
197 ETH_P_RSN_PREAUTH,
198 rsn_preauth_receive, sm, 0);
199 if (sm->l2_preauth_br == NULL) {
200 wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
201 "packet processing (bridge) for "
202 "pre-authentication");
203 return -2;
204 }
205 }
206
207 ctx = os_zalloc(sizeof(*ctx));
208 if (ctx == NULL) {
209 wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
210 return -4;
211 }
212 ctx->ctx = sm->ctx->ctx;
213 ctx->msg_ctx = sm->ctx->ctx;
214 ctx->preauth = 1;
215 ctx->cb = rsn_preauth_eapol_cb;
216 ctx->cb_ctx = sm;
217 ctx->scard_ctx = sm->scard_ctx;
218 ctx->eapol_send = rsn_preauth_eapol_send;
219 ctx->eapol_send_ctx = sm;
220 ctx->set_config_blob = sm->ctx->set_config_blob;
221 ctx->get_config_blob = sm->ctx->get_config_blob;
222
223 sm->preauth_eapol = eapol_sm_init(ctx);
224 if (sm->preauth_eapol == NULL) {
225 os_free(ctx);
226 wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
227 "state machines for pre-authentication");
228 return -3;
229 }
230 os_memset(&eapol_conf, 0, sizeof(eapol_conf));
231 eapol_conf.accept_802_1x_keys = 0;
232 eapol_conf.required_keys = 0;
233 eapol_conf.fast_reauth = sm->fast_reauth;
234 eapol_conf.workaround = sm->eap_workaround;
235 eapol_sm_notify_config(sm->preauth_eapol, eap_conf, &eapol_conf);
236 /*
237 * Use a shorter startPeriod with preauthentication since the first
238 * preauth EAPOL-Start frame may end up being dropped due to race
239 * condition in the AP between the data receive and key configuration
240 * after the 4-Way Handshake.
241 */
242 eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
243 os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
244
245 eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
246 /* 802.1X::portControl = Auto */
247 eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
248
249 eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
250 rsn_preauth_timeout, sm, NULL);
251
252 return 0;
253 }
254
255
256 /**
257 * rsn_preauth_deinit - Abort RSN pre-authentication
258 * @sm: Pointer to WPA state machine data from wpa_sm_init()
259 *
260 * This function aborts the current RSN pre-authentication (if one is started)
261 * and frees resources allocated for it.
262 */
263 void rsn_preauth_deinit(struct wpa_sm *sm)
264 {
265 if (sm == NULL || !sm->preauth_eapol)
266 return;
267
268 eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL);
269 eapol_sm_deinit(sm->preauth_eapol);
270 sm->preauth_eapol = NULL;
271 os_memset(sm->preauth_bssid, 0, ETH_ALEN);
272
273 l2_packet_deinit(sm->l2_preauth);
274 sm->l2_preauth = NULL;
275 if (sm->l2_preauth_br) {
276 l2_packet_deinit(sm->l2_preauth_br);
277 sm->l2_preauth_br = NULL;
278 }
279 }
280
281
282 /**
283 * rsn_preauth_candidate_process - Process PMKSA candidates
284 * @sm: Pointer to WPA state machine data from wpa_sm_init()
285 *
286 * Go through the PMKSA candidates and start pre-authentication if a candidate
287 * without an existing PMKSA cache entry is found. Processed candidates will be
288 * removed from the list.
289 */
290 void rsn_preauth_candidate_process(struct wpa_sm *sm)
291 {
292 struct rsn_pmksa_candidate *candidate, *n;
293
294 if (dl_list_empty(&sm->pmksa_candidates))
295 return;
296
297 /* TODO: drop priority for old candidate entries */
298
299 wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: processing PMKSA candidate "
300 "list");
301 if (sm->preauth_eapol ||
302 sm->proto != WPA_PROTO_RSN ||
303 wpa_sm_get_state(sm) != WPA_COMPLETED ||
304 (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
305 sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
306 wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
307 "state for new pre-authentication");
308 return; /* invalid state for new pre-auth */
309 }
310
311 dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates,
312 struct rsn_pmksa_candidate, list) {
313 struct rsn_pmksa_cache_entry *p = NULL;
314 p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL);
315 if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
316 (p == NULL || p->opportunistic)) {
317 wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA "
318 "candidate " MACSTR
319 " selected for pre-authentication",
320 MAC2STR(candidate->bssid));
321 dl_list_del(&candidate->list);
322 rsn_preauth_init(sm, candidate->bssid,
323 sm->eap_conf_ctx);
324 os_free(candidate);
325 return;
326 }
327 wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA candidate "
328 MACSTR " does not need pre-authentication anymore",
329 MAC2STR(candidate->bssid));
330 /* Some drivers (e.g., NDIS) expect to get notified about the
331 * PMKIDs again, so report the existing data now. */
332 if (p) {
333 wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
334 }
335
336 dl_list_del(&candidate->list);
337 os_free(candidate);
338 }
339 wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: no more pending PMKSA "
340 "candidates");
341 }
342
343
344 /**
345 * pmksa_candidate_add - Add a new PMKSA candidate
346 * @sm: Pointer to WPA state machine data from wpa_sm_init()
347 * @bssid: BSSID (authenticator address) of the candidate
348 * @prio: Priority (the smaller number, the higher priority)
349 * @preauth: Whether the candidate AP advertises support for pre-authentication
350 *
351 * This function is used to add PMKSA candidates for RSN pre-authentication. It
352 * is called from scan result processing and from driver events for PMKSA
353 * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event().
354 */
355 void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
356 int prio, int preauth)
357 {
358 struct rsn_pmksa_candidate *cand, *pos;
359
360 if (sm->network_ctx && sm->proactive_key_caching)
361 pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx,
362 bssid);
363
364 if (!preauth) {
365 wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
366 "preauth flag");
367 return;
368 }
369
370 /* If BSSID already on candidate list, update the priority of the old
371 * entry. Do not override priority based on normal scan results. */
372 cand = NULL;
373 dl_list_for_each(pos, &sm->pmksa_candidates,
374 struct rsn_pmksa_candidate, list) {
375 if (os_memcmp(pos->bssid, bssid, ETH_ALEN) == 0) {
376 cand = pos;
377 break;
378 }
379 }
380
381 if (cand) {
382 dl_list_del(&cand->list);
383 if (prio < PMKID_CANDIDATE_PRIO_SCAN)
384 cand->priority = prio;
385 } else {
386 cand = os_zalloc(sizeof(*cand));
387 if (cand == NULL)
388 return;
389 os_memcpy(cand->bssid, bssid, ETH_ALEN);
390 cand->priority = prio;
391 }
392
393 /* Add candidate to the list; order by increasing priority value. i.e.,
394 * highest priority (smallest value) first. */
395 dl_list_for_each(pos, &sm->pmksa_candidates,
396 struct rsn_pmksa_candidate, list) {
397 if (cand->priority <= pos->priority) {
398 dl_list_add(pos->list.prev, &cand->list);
399 cand = NULL;
400 break;
401 }
402 }
403 if (cand)
404 dl_list_add_tail(&sm->pmksa_candidates, &cand->list);
405
406 wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: added PMKSA cache "
407 "candidate " MACSTR " prio %d", MAC2STR(bssid), prio);
408 rsn_preauth_candidate_process(sm);
409 }
410
411
412 /* TODO: schedule periodic scans if current AP supports preauth */
413
414 /**
415 * rsn_preauth_scan_results - Start processing scan results for canditates
416 * @sm: Pointer to WPA state machine data from wpa_sm_init()
417 * Returns: 0 if ready to process results or -1 to skip processing
418 *
419 * This functions is used to notify RSN code about start of new scan results
420 * processing. The actual scan results will be provided by calling
421 * rsn_preauth_scan_result() for each BSS if this function returned 0.
422 */
423 int rsn_preauth_scan_results(struct wpa_sm *sm)
424 {
425 if (sm->ssid_len == 0)
426 return -1;
427
428 /*
429 * TODO: is it ok to free all candidates? What about the entries
430 * received from EVENT_PMKID_CANDIDATE?
431 */
432 pmksa_candidate_free(sm);
433
434 return 0;
435 }
436
437
438 /**
439 * rsn_preauth_scan_result - Processing scan result for PMKSA canditates
440 * @sm: Pointer to WPA state machine data from wpa_sm_init()
441 *
442 * Add all suitable APs (Authenticators) from scan results into PMKSA
443 * candidate list.
444 */
445 void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
446 const u8 *ssid, const u8 *rsn)
447 {
448 struct wpa_ie_data ie;
449 struct rsn_pmksa_cache_entry *pmksa;
450
451 if (ssid[1] != sm->ssid_len ||
452 os_memcmp(ssid + 2, sm->ssid, sm->ssid_len) != 0)
453 return; /* Not for the current SSID */
454
455 if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0)
456 return; /* Ignore current AP */
457
458 if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
459 return;
460
461 pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL);
462 if (pmksa && (!pmksa->opportunistic ||
463 !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
464 return;
465
466 /* Give less priority to candidates found from normal scan results. */
467 pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN,
468 ie.capabilities & WPA_CAPABILITY_PREAUTH);
469 }
470
471
472 #ifdef CONFIG_CTRL_IFACE
473 /**
474 * rsn_preauth_get_status - Get pre-authentication status
475 * @sm: Pointer to WPA state machine data from wpa_sm_init()
476 * @buf: Buffer for status information
477 * @buflen: Maximum buffer length
478 * @verbose: Whether to include verbose status information
479 * Returns: Number of bytes written to buf.
480 *
481 * Query WPA2 pre-authentication for status information. This function fills in
482 * a text area with current status information. If the buffer (buf) is not
483 * large enough, status information will be truncated to fit the buffer.
484 */
485 int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
486 int verbose)
487 {
488 char *pos = buf, *end = buf + buflen;
489 int res, ret;
490
491 if (sm->preauth_eapol) {
492 ret = os_snprintf(pos, end - pos, "Pre-authentication "
493 "EAPOL state machines:\n");
494 if (ret < 0 || ret >= end - pos)
495 return pos - buf;
496 pos += ret;
497 res = eapol_sm_get_status(sm->preauth_eapol,
498 pos, end - pos, verbose);
499 if (res >= 0)
500 pos += res;
501 }
502
503 return pos - buf;
504 }
505 #endif /* CONFIG_CTRL_IFACE */
506
507
508 /**
509 * rsn_preauth_in_progress - Verify whether pre-authentication is in progress
510 * @sm: Pointer to WPA state machine data from wpa_sm_init()
511 */
512 int rsn_preauth_in_progress(struct wpa_sm *sm)
513 {
514 return sm->preauth_eapol != NULL;
515 }
516
517 #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */