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