Example #1
0
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
		      const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
	u8 ptk_name[WPA_PMK_NAME_LEN];
	const u8 *anonce = key->key_nonce;

	if (sm->xxkey_len == 0) {
		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
			   "derivation");
		return -1;
	}

	wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
			  sm->ssid_len, sm->mobility_domain,
			  sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
			  sm->pmk_r0, sm->pmk_r0_name);
	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
		    sm->pmk_r0_name, WPA_PMK_NAME_LEN);
	wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
			  sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
		    WPA_PMK_NAME_LEN);
	return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
				 sm->bssid, sm->pmk_r1_name, ptk, ptk_name,
				 sm->key_mgmt, sm->pairwise_cipher);
}
Example #2
0
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
			   struct wpa_ptk *ptk, size_t ptk_len)
{
	u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
	u8 pmk_r1[PMK_LEN];
	u8 ptk_name[WPA_PMK_NAME_LEN];
	const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
	const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
	size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len;
	const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
	const u8 *ssid = sm->wpa_auth->conf.ssid;
	size_t ssid_len = sm->wpa_auth->conf.ssid_len;


	if (sm->xxkey_len == 0) {
		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
			   "derivation");
		return -1;
	}

	wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
			  r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
	wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
			    sm->pairwise);

	wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
			  pmk_r1, sm->pmk_r1_name);
	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
		    WPA_PMK_NAME_LEN);
	wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
			    sm->pairwise);

	wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
			  sm->wpa_auth->addr, sm->pmk_r1_name,
			  (u8 *) ptk, ptk_len, ptk_name);
	wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);

	return 0;
}
Example #3
0
int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
			    int ft_action, const u8 *target_ap,
			    const u8 *ric_ies, size_t ric_ies_len)
{
	u8 *ft_ies;
	size_t ft_ies_len;
	struct wpa_ft_ies parse;
	struct rsn_mdie *mdie;
	struct rsn_ftie *ftie;
	u8 ptk_name[WPA_PMK_NAME_LEN];
	int ret;
	const u8 *bssid;

	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
	wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);

	if (ft_action) {
		if (!sm->over_the_ds_in_progress) {
			wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
				   "- drop FT Action Response");
			return -1;
		}

		if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) {
			wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
				   "with this Target AP - drop FT Action "
				   "Response");
			return -1;
		}
	}

	if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
		wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
			   "enabled for this connection");
		return -1;
	}

	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
		return -1;
	}

	mdie = (struct rsn_mdie *) parse.mdie;
	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
		      MOBILITY_DOMAIN_ID_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
		return -1;
	}

	ftie = (struct rsn_ftie *) parse.ftie;
	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
		return -1;
	}

	if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
			    ftie->snonce, WPA_NONCE_LEN);
		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
			    sm->snonce, WPA_NONCE_LEN);
		return -1;
	}

	if (parse.r0kh_id == NULL) {
		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
		return -1;
	}

	if (parse.r0kh_id_len != sm->r0kh_id_len ||
	    os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
	{
		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
			   "the current R0KH-ID");
		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
			    parse.r0kh_id, parse.r0kh_id_len);
		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
			    sm->r0kh_id, sm->r0kh_id_len);
		return -1;
	}

	if (parse.r1kh_id == NULL) {
		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
		return -1;
	}

	if (parse.rsn_pmkid == NULL ||
	    os_memcmp_const(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN))
	{
		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in "
			   "RSNIE");
		return -1;
	}

	os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN);
	os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN);
	wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
			  sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
		    sm->pmk_r1_name, WPA_PMK_NAME_LEN);

	bssid = target_ap;
	if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce,
			      sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk,
			      ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0)
		return -1;

	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
				    sm->pmk_r1_name,
				    sm->ptk.kck, sm->ptk.kck_len, bssid,
				    ric_ies, ric_ies_len,
				    parse.mdie ? parse.mdie - 2 : NULL);
	if (ft_ies) {
		wpa_sm_update_ft_ies(sm, sm->mobility_domain,
				     ft_ies, ft_ies_len);
		os_free(ft_ies);
	}

	wpa_sm_mark_authenticated(sm, bssid);
	ret = wpa_ft_install_ptk(sm, bssid);
	if (ret) {
		/*
		 * Some drivers do not support key configuration when we are
		 * not associated with the target AP. Work around this by
		 * trying again after the following reassociation gets
		 * completed.
		 */
		wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to "
			   "association - try again after reassociation");
		sm->set_ptk_after_assoc = 1;
	} else
		sm->set_ptk_after_assoc = 0;

	sm->ft_completed = 1;
	if (ft_action) {
		/*
		 * The caller is expected trigger re-association with the
		 * Target AP.
		 */
		os_memcpy(sm->bssid, target_ap, ETH_ALEN);
	}

	return 0;
}
Example #4
0
int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
                            int ft_action, const u8 *target_ap)
{
    u8 *ft_ies;
    size_t ft_ies_len, ptk_len;
    struct wpa_ft_ies parse;
    struct rsn_mdie *mdie;
    struct rsn_ftie *ftie;
    u8 ptk_name[WPA_PMK_NAME_LEN];
    int ret;
    const u8 *bssid;

    wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);

    if (ft_action) {
        if (!sm->over_the_ds_in_progress) {
            wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
                       "- drop FT Action Response");
            return -1;
        }

        if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) {
            wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
                       "with this Target AP - drop FT Action "
                       "Response");
            return -1;
        }
    }

    if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
            sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) {
        wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
                   "enabled for this connection");
        return -1;
    }

    if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
        wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
        return -1;
    }

    mdie = (struct rsn_mdie *) parse.mdie;
    if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
            os_memcmp(mdie->mobility_domain, sm->mobility_domain,
                      MOBILITY_DOMAIN_ID_LEN) != 0) {
        wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
        return -1;
    }

    ftie = (struct rsn_ftie *) parse.ftie;
    if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
        wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
        return -1;
    }

    if (parse.r0kh_id == NULL) {
        wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
        return -1;
    }

    if (parse.r0kh_id_len != sm->r0kh_id_len ||
            os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
        wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
                   "the current R0KH-ID");
        wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
                    parse.r0kh_id, parse.r0kh_id_len);
        wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
                    sm->r0kh_id, sm->r0kh_id_len);
        return -1;
    }

    if (parse.r1kh_id == NULL) {
        wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
        return -1;
    }

    if (parse.rsn_pmkid == NULL ||
            os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) {
        wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in "
                   "RSNIE");
        return -1;
    }

    os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
    wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
    wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
    wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN);
    wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
                      sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
    wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
    wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
                sm->pmk_r1_name, WPA_PMK_NAME_LEN);

    bssid = target_ap;
    ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
    wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
                      bssid, sm->pmk_r1_name,
                      (u8 *) &sm->ptk, ptk_len, ptk_name);
    wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
                    (u8 *) &sm->ptk, ptk_len);
    wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);

    ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
                                sm->pmk_r1_name, sm->ptk.kck, bssid);
    if (ft_ies) {
        wpa_sm_update_ft_ies(sm, sm->mobility_domain,
                             ft_ies, ft_ies_len);
        os_free(ft_ies);
    }

    ret = wpa_ft_install_ptk(sm, bssid);

    if (ret == 0) {
        sm->ft_completed = 1;
        if (ft_action) {
            /* TODO: trigger re-association to the Target AP;
             * MLME is now doing this automatically, but it should
             * really be done only if we get here successfully. */
            os_memcpy(sm->bssid, target_ap, ETH_ALEN);
        }
    }

    return ret;
}
Example #5
0
static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
			      const u8 *src_addr,
			      const u8 *data, size_t data_len)
{
	struct ft_r0kh_r1kh_pull_frame *frame, f;
	struct ft_remote_r1kh *r1kh;
	struct ft_r0kh_r1kh_resp_frame resp, r;
	u8 pmk_r0[PMK_LEN];
	int pairwise;

	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");

	if (data_len < sizeof(*frame))
		return -1;

	r1kh = wpa_auth->conf.r1kh_list;
	while (r1kh) {
		if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
			break;
		r1kh = r1kh->next;
	}
	if (r1kh == NULL) {
		wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for "
			   "PMK-R1 pull source address " MACSTR,
			   MAC2STR(src_addr));
		return -1;
	}

	frame = (struct ft_r0kh_r1kh_pull_frame *) data;
	/* aes_unwrap() does not support inplace decryption, so use a temporary
	 * buffer for the data. */
	if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
		       frame->nonce, f.nonce) < 0) {
		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
			   "request from " MACSTR, MAC2STR(src_addr));
		return -1;
	}

	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
		    f.nonce, sizeof(f.nonce));
	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
		    f.pmk_r0_name, WPA_PMK_NAME_LEN);
	wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
		   MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));

	os_memset(&resp, 0, sizeof(resp));
	resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
	resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
	resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN);
	os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN);

	/* aes_wrap() does not support inplace encryption, so use a temporary
	 * buffer for the data. */
	os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
	os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
	os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
	if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0,
				&pairwise) < 0) {
		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
			   "PMK-R1 pull");
		return -1;
	}

	wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
			  r.pmk_r1, r.pmk_r1_name);
	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
		    WPA_PMK_NAME_LEN);
	r.pairwise = host_to_le16(pairwise);

	if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
		     r.nonce, resp.nonce) < 0) {
		os_memset(pmk_r0, 0, PMK_LEN);
		return -1;
	}

	os_memset(pmk_r0, 0, PMK_LEN);

	wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp));

	return 0;
}