Example #1
0
/**
 * wpa_ft_start_over_ds - Generate over-the-DS auth request
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 * @target_ap: Target AP Address
 * @mdie: Mobility Domain IE from the target AP
 * Returns: 0 on success, -1 on failure
 */
int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
			 const u8 *mdie)
{
	u8 *ft_ies;
	size_t ft_ies_len;

	wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR,
		   MAC2STR(target_ap));

	/* Generate a new SNonce */
	if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
		wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
		return -1;
	}

	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
				    NULL, 0, target_ap, NULL, 0, mdie);
	if (ft_ies) {
		sm->over_the_ds_in_progress = 1;
		os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
		wpa_sm_send_ft_action(sm, 1, target_ap, ft_ies, ft_ies_len);
		os_free(ft_ies);
	}

	return 0;
}
Example #2
0
/**
 * wpa_ft_prepare_auth_request - Generate over-the-air auth request
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 * @mdie: Target AP MDIE
 * Returns: 0 on success, -1 on failure
 */
int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
{
	u8 *ft_ies;
	size_t ft_ies_len;

	/* Generate a new SNonce */
	if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
		wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
		return -1;
	}

	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, NULL, 0, sm->bssid, NULL, 0, mdie);
	if (ft_ies) {
		wpa_sm_update_ft_ies(sm, sm->mobility_domain, ft_ies, ft_ies_len);
		os_free(ft_ies);
	}

	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;
}