2 * WPA Supplicant - RSN pre-authentication
3 * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
22 #include "l2_packet.h"
25 #include "pmksa_cache.h"
29 #define PMKID_CANDIDATE_PRIO_SCAN 1000
32 struct rsn_pmksa_candidate
{
33 struct rsn_pmksa_candidate
*next
;
40 * pmksa_candidate_free - Free all entries in PMKSA candidate list
41 * @sm: Pointer to WPA state machine data from wpa_sm_init()
43 void pmksa_candidate_free(struct wpa_sm
*sm
)
45 struct rsn_pmksa_candidate
*entry
, *prev
;
50 entry
= sm
->pmksa_candidates
;
51 sm
->pmksa_candidates
= NULL
;
60 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
62 static void rsn_preauth_receive(void *ctx
, const u8
*src_addr
,
63 const u8
*buf
, size_t len
)
65 struct wpa_sm
*sm
= ctx
;
67 wpa_printf(MSG_DEBUG
, "RX pre-auth from " MACSTR
, MAC2STR(src_addr
));
68 wpa_hexdump(MSG_MSGDUMP
, "RX pre-auth", buf
, len
);
70 if (sm
->preauth_eapol
== NULL
||
71 os_memcmp(sm
->preauth_bssid
, "\x00\x00\x00\x00\x00\x00",
73 os_memcmp(sm
->preauth_bssid
, src_addr
, ETH_ALEN
) != 0) {
74 wpa_printf(MSG_WARNING
, "RSN pre-auth frame received from "
75 "unexpected source " MACSTR
" - dropped",
80 eapol_sm_rx_eapol(sm
->preauth_eapol
, src_addr
, buf
, len
);
84 static void rsn_preauth_eapol_cb(struct eapol_sm
*eapol
, int success
,
87 struct wpa_sm
*sm
= ctx
;
93 res
= eapol_sm_get_key(eapol
, pmk
, PMK_LEN
);
96 * EAP-LEAP is an exception from other EAP methods: it
97 * uses only 16-byte PMK.
99 res
= eapol_sm_get_key(eapol
, pmk
, 16);
103 wpa_hexdump_key(MSG_DEBUG
, "RSN: PMK from pre-auth",
105 sm
->pmk_len
= pmk_len
;
106 pmksa_cache_add(sm
->pmksa
, pmk
, pmk_len
,
107 sm
->preauth_bssid
, sm
->own_addr
,
110 wpa_msg(sm
->ctx
->ctx
, MSG_INFO
, "RSN: failed to get "
111 "master session key from pre-auth EAPOL state "
117 wpa_msg(sm
->ctx
->ctx
, MSG_INFO
, "RSN: pre-authentication with " MACSTR
118 " %s", MAC2STR(sm
->preauth_bssid
),
119 success
? "completed successfully" : "failed");
121 rsn_preauth_deinit(sm
);
122 rsn_preauth_candidate_process(sm
);
126 static void rsn_preauth_timeout(void *eloop_ctx
, void *timeout_ctx
)
128 struct wpa_sm
*sm
= eloop_ctx
;
130 wpa_msg(sm
->ctx
->ctx
, MSG_INFO
, "RSN: pre-authentication with " MACSTR
131 " timed out", MAC2STR(sm
->preauth_bssid
));
132 rsn_preauth_deinit(sm
);
133 rsn_preauth_candidate_process(sm
);
137 static int rsn_preauth_eapol_send(void *ctx
, int type
, const u8
*buf
,
140 struct wpa_sm
*sm
= ctx
;
145 /* TODO: could add l2_packet_sendmsg that allows fragments to avoid
148 if (sm
->l2_preauth
== NULL
)
151 msg
= wpa_sm_alloc_eapol(sm
, type
, buf
, len
, &msglen
, NULL
);
155 wpa_hexdump(MSG_MSGDUMP
, "TX EAPOL (preauth)", msg
, msglen
);
156 res
= l2_packet_send(sm
->l2_preauth
, sm
->preauth_bssid
,
157 ETH_P_RSN_PREAUTH
, msg
, msglen
);
164 * rsn_preauth_init - Start new RSN pre-authentication
165 * @sm: Pointer to WPA state machine data from wpa_sm_init()
166 * @dst: Authenticator address (BSSID) with which to preauthenticate
167 * @config: Current network configuration
168 * Returns: 0 on success, -1 on another pre-authentication is in progress,
169 * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine
170 * initialization failure, -4 on memory allocation failure
172 * This function request an RSN pre-authentication with a given destination
173 * address. This is usually called for PMKSA candidates found from scan results
174 * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger
175 * pre-authentication.
177 int rsn_preauth_init(struct wpa_sm
*sm
, const u8
*dst
, struct wpa_ssid
*config
)
179 struct eapol_config eapol_conf
;
180 struct eapol_ctx
*ctx
;
182 if (sm
->preauth_eapol
)
185 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: starting pre-authentication "
186 "with " MACSTR
, MAC2STR(dst
));
188 sm
->l2_preauth
= l2_packet_init(sm
->ifname
, sm
->own_addr
,
190 rsn_preauth_receive
, sm
, 0);
191 if (sm
->l2_preauth
== NULL
) {
192 wpa_printf(MSG_WARNING
, "RSN: Failed to initialize L2 packet "
193 "processing for pre-authentication");
197 if (sm
->bridge_ifname
) {
198 sm
->l2_preauth_br
= l2_packet_init(sm
->bridge_ifname
,
201 rsn_preauth_receive
, sm
, 0);
202 if (sm
->l2_preauth_br
== NULL
) {
203 wpa_printf(MSG_WARNING
, "RSN: Failed to initialize L2 "
204 "packet processing (bridge) for "
205 "pre-authentication");
210 ctx
= os_zalloc(sizeof(*ctx
));
212 wpa_printf(MSG_WARNING
, "Failed to allocate EAPOL context.");
215 ctx
->ctx
= sm
->ctx
->ctx
;
216 ctx
->msg_ctx
= sm
->ctx
->ctx
;
218 ctx
->cb
= rsn_preauth_eapol_cb
;
220 ctx
->scard_ctx
= sm
->scard_ctx
;
221 ctx
->eapol_send
= rsn_preauth_eapol_send
;
222 ctx
->eapol_send_ctx
= sm
;
223 ctx
->set_config_blob
= sm
->ctx
->set_config_blob
;
224 ctx
->get_config_blob
= sm
->ctx
->get_config_blob
;
226 sm
->preauth_eapol
= eapol_sm_init(ctx
);
227 if (sm
->preauth_eapol
== NULL
) {
229 wpa_printf(MSG_WARNING
, "RSN: Failed to initialize EAPOL "
230 "state machines for pre-authentication");
233 os_memset(&eapol_conf
, 0, sizeof(eapol_conf
));
234 eapol_conf
.accept_802_1x_keys
= 0;
235 eapol_conf
.required_keys
= 0;
236 eapol_conf
.fast_reauth
= sm
->fast_reauth
;
238 eapol_conf
.workaround
= config
->eap_workaround
;
239 eapol_sm_notify_config(sm
->preauth_eapol
, config
, &eapol_conf
);
241 * Use a shorter startPeriod with preauthentication since the first
242 * preauth EAPOL-Start frame may end up being dropped due to race
243 * condition in the AP between the data receive and key configuration
244 * after the 4-Way Handshake.
246 eapol_sm_configure(sm
->preauth_eapol
, -1, -1, 5, 6);
247 os_memcpy(sm
->preauth_bssid
, dst
, ETH_ALEN
);
249 eapol_sm_notify_portValid(sm
->preauth_eapol
, TRUE
);
250 /* 802.1X::portControl = Auto */
251 eapol_sm_notify_portEnabled(sm
->preauth_eapol
, TRUE
);
253 eloop_register_timeout(sm
->dot11RSNAConfigSATimeout
, 0,
254 rsn_preauth_timeout
, sm
, NULL
);
261 * rsn_preauth_deinit - Abort RSN pre-authentication
262 * @sm: Pointer to WPA state machine data from wpa_sm_init()
264 * This function aborts the current RSN pre-authentication (if one is started)
265 * and frees resources allocated for it.
267 void rsn_preauth_deinit(struct wpa_sm
*sm
)
269 if (sm
== NULL
|| !sm
->preauth_eapol
)
272 eloop_cancel_timeout(rsn_preauth_timeout
, sm
, NULL
);
273 eapol_sm_deinit(sm
->preauth_eapol
);
274 sm
->preauth_eapol
= NULL
;
275 os_memset(sm
->preauth_bssid
, 0, ETH_ALEN
);
277 l2_packet_deinit(sm
->l2_preauth
);
278 sm
->l2_preauth
= NULL
;
279 if (sm
->l2_preauth_br
) {
280 l2_packet_deinit(sm
->l2_preauth_br
);
281 sm
->l2_preauth_br
= NULL
;
287 * rsn_preauth_candidate_process - Process PMKSA candidates
288 * @sm: Pointer to WPA state machine data from wpa_sm_init()
290 * Go through the PMKSA candidates and start pre-authentication if a candidate
291 * without an existing PMKSA cache entry is found. Processed candidates will be
292 * removed from the list.
294 void rsn_preauth_candidate_process(struct wpa_sm
*sm
)
296 struct rsn_pmksa_candidate
*candidate
;
298 if (sm
->pmksa_candidates
== NULL
)
301 /* TODO: drop priority for old candidate entries */
303 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: processing PMKSA candidate "
305 if (sm
->preauth_eapol
||
306 sm
->proto
!= WPA_PROTO_RSN
||
307 wpa_sm_get_state(sm
) != WPA_COMPLETED
||
308 sm
->key_mgmt
!= WPA_KEY_MGMT_IEEE8021X
) {
309 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: not in suitable state "
310 "for new pre-authentication");
311 return; /* invalid state for new pre-auth */
314 while (sm
->pmksa_candidates
) {
315 struct rsn_pmksa_cache_entry
*p
= NULL
;
316 candidate
= sm
->pmksa_candidates
;
317 p
= pmksa_cache_get(sm
->pmksa
, candidate
->bssid
, NULL
);
318 if (os_memcmp(sm
->bssid
, candidate
->bssid
, ETH_ALEN
) != 0 &&
319 (p
== NULL
|| p
->opportunistic
)) {
320 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: PMKSA "
322 " selected for pre-authentication",
323 MAC2STR(candidate
->bssid
));
324 sm
->pmksa_candidates
= candidate
->next
;
325 rsn_preauth_init(sm
, candidate
->bssid
, sm
->cur_ssid
);
329 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: PMKSA candidate "
330 MACSTR
" does not need pre-authentication anymore",
331 MAC2STR(candidate
->bssid
));
332 /* Some drivers (e.g., NDIS) expect to get notified about the
333 * PMKIDs again, so report the existing data now. */
335 wpa_sm_add_pmkid(sm
, candidate
->bssid
, p
->pmkid
);
338 sm
->pmksa_candidates
= candidate
->next
;
341 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: no more pending PMKSA "
347 * pmksa_candidate_add - Add a new PMKSA candidate
348 * @sm: Pointer to WPA state machine data from wpa_sm_init()
349 * @bssid: BSSID (authenticator address) of the candidate
350 * @prio: Priority (the smaller number, the higher priority)
351 * @preauth: Whether the candidate AP advertises support for pre-authentication
353 * This function is used to add PMKSA candidates for RSN pre-authentication. It
354 * is called from scan result processing and from driver events for PMKSA
355 * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event().
357 void pmksa_candidate_add(struct wpa_sm
*sm
, const u8
*bssid
,
358 int prio
, int preauth
)
360 struct rsn_pmksa_candidate
*cand
, *prev
, *pos
;
362 if (sm
->cur_ssid
&& sm
->cur_ssid
->proactive_key_caching
)
363 pmksa_cache_get_opportunistic(sm
->pmksa
, sm
->cur_ssid
, bssid
);
366 wpa_printf(MSG_DEBUG
, "RSN: Ignored PMKID candidate without "
371 /* If BSSID already on candidate list, update the priority of the old
372 * entry. Do not override priority based on normal scan results. */
374 cand
= sm
->pmksa_candidates
;
376 if (os_memcmp(cand
->bssid
, bssid
, ETH_ALEN
) == 0) {
378 prev
->next
= cand
->next
;
380 sm
->pmksa_candidates
= cand
->next
;
388 if (prio
< PMKID_CANDIDATE_PRIO_SCAN
)
389 cand
->priority
= prio
;
391 cand
= os_zalloc(sizeof(*cand
));
394 os_memcpy(cand
->bssid
, bssid
, ETH_ALEN
);
395 cand
->priority
= prio
;
398 /* Add candidate to the list; order by increasing priority value. i.e.,
399 * highest priority (smallest value) first. */
401 pos
= sm
->pmksa_candidates
;
403 if (cand
->priority
<= pos
->priority
)
412 sm
->pmksa_candidates
= cand
;
414 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: added PMKSA cache "
415 "candidate " MACSTR
" prio %d", MAC2STR(bssid
), prio
);
416 rsn_preauth_candidate_process(sm
);
420 /* TODO: schedule periodic scans if current AP supports preauth */
423 * rsn_preauth_scan_results - Process scan results to find PMKSA candidates
424 * @sm: Pointer to WPA state machine data from wpa_sm_init()
425 * @results: Scan results
426 * @count: Number of BSSes in scan results
428 * This functions goes through the scan results and adds all suitable APs
429 * (Authenticators) into PMKSA candidate list.
431 void rsn_preauth_scan_results(struct wpa_sm
*sm
,
432 struct wpa_scan_result
*results
, int count
)
434 struct wpa_scan_result
*r
;
435 struct wpa_ie_data ie
;
437 struct rsn_pmksa_cache_entry
*pmksa
;
439 if (sm
->cur_ssid
== NULL
)
443 * TODO: is it ok to free all candidates? What about the entries
444 * received from EVENT_PMKID_CANDIDATE?
446 pmksa_candidate_free(sm
);
448 for (i
= count
- 1; i
>= 0; i
--) {
450 if (r
->ssid_len
!= sm
->cur_ssid
->ssid_len
||
451 os_memcmp(r
->ssid
, sm
->cur_ssid
->ssid
,
455 if (os_memcmp(r
->bssid
, sm
->bssid
, ETH_ALEN
) == 0)
458 if (r
->rsn_ie_len
== 0 ||
459 wpa_parse_wpa_ie(r
->rsn_ie
, r
->rsn_ie_len
, &ie
))
462 pmksa
= pmksa_cache_get(sm
->pmksa
, r
->bssid
, NULL
);
464 (!pmksa
->opportunistic
||
465 !(ie
.capabilities
& WPA_CAPABILITY_PREAUTH
)))
469 * Give less priority to candidates found from normal
472 pmksa_candidate_add(sm
, r
->bssid
,
473 PMKID_CANDIDATE_PRIO_SCAN
,
474 ie
.capabilities
& WPA_CAPABILITY_PREAUTH
);
479 #ifdef CONFIG_CTRL_IFACE
481 * rsn_preauth_get_status - Get pre-authentication status
482 * @sm: Pointer to WPA state machine data from wpa_sm_init()
483 * @buf: Buffer for status information
484 * @buflen: Maximum buffer length
485 * @verbose: Whether to include verbose status information
486 * Returns: Number of bytes written to buf.
488 * Query WPA2 pre-authentication for status information. This function fills in
489 * a text area with current status information. If the buffer (buf) is not
490 * large enough, status information will be truncated to fit the buffer.
492 int rsn_preauth_get_status(struct wpa_sm
*sm
, char *buf
, size_t buflen
,
495 char *pos
= buf
, *end
= buf
+ buflen
;
498 if (sm
->preauth_eapol
) {
499 ret
= os_snprintf(pos
, end
- pos
, "Pre-authentication "
500 "EAPOL state machines:\n");
501 if (ret
< 0 || ret
>= end
- pos
)
504 res
= eapol_sm_get_status(sm
->preauth_eapol
,
505 pos
, end
- pos
, verbose
);
512 #endif /* CONFIG_CTRL_IFACE */
516 * rsn_preauth_in_progress - Verify whether pre-authentication is in progress
517 * @sm: Pointer to WPA state machine data from wpa_sm_init()
519 int rsn_preauth_in_progress(struct wpa_sm
*sm
)
521 return sm
->preauth_eapol
!= NULL
;
524 #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */