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