Example #1
0
static const u8 * eap_fast_get_a_id(const u8 *buf, size_t len, size_t *id_len)
{
	const u8 *a_id;
	struct pac_tlv_hdr *hdr;

	/*
	 * Parse authority identity (A-ID) from the EAP-FAST/Start. This
	 * supports both raw A-ID and one inside an A-ID TLV.
	 */
	a_id = buf;
	*id_len = len;
	if (len > sizeof(*hdr)) {
		int tlen;
		hdr = (struct pac_tlv_hdr *) buf;
		tlen = be_to_host16(hdr->len);
		if (be_to_host16(hdr->type) == PAC_TYPE_A_ID &&
		    sizeof(*hdr) + tlen <= len) {
			wpa_printf(MSG_DEBUG, "EAP-FAST: A-ID was in TLV "
				   "(Start)");
			a_id = (u8 *) (hdr + 1);
			*id_len = tlen;
		}
	}
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: A-ID", a_id, *id_len);

	return a_id;
}
Example #2
0
static int wpa_supplicant_process_smk_error(
	struct wpa_sm *sm, const unsigned char *src_addr,
	const struct wpa_eapol_key *key, size_t extra_len)
{
	struct wpa_eapol_ie_parse kde;
	struct rsn_error_kde error;
	u8 peer[ETH_ALEN];
	u16 error_type;

	wpa_printf(MSG_DEBUG, "RSN: Received SMK Error");

	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
			   "the current network");
		return -1;
	}

	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
	    0) {
		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
		return -1;
	}

	if (kde.error == NULL || kde.error_len < sizeof(error)) {
		wpa_printf(MSG_INFO, "RSN: No Error KDE in SMK Error");
		return -1;
	}

	if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN)
		os_memcpy(peer, kde.mac_addr, ETH_ALEN);
	else
		os_memset(peer, 0, ETH_ALEN);
	os_memcpy(&error, kde.error, sizeof(error));
	error_type = be_to_host16(error.error_type);
	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
		"RSN: SMK Error KDE received: MUI %d error_type %d peer "
		MACSTR,
		be_to_host16(error.mui), error_type,
		MAC2STR(peer));

	if (kde.mac_addr &&
	    (error_type == STK_ERR_STA_NR || error_type == STK_ERR_STA_NRSN ||
	     error_type == STK_ERR_CPHR_NS)) {
		struct wpa_peerkey *peerkey;

		for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
			if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) ==
			    0)
				break;
		}
		if (peerkey == NULL) {
			wpa_printf(MSG_DEBUG, "RSN: No matching SMK handshake "
				   "found for SMK Error");
			return -1;
		}
		/* TODO: abort SMK/STK handshake and remove all related keys */
	}

	return 0;
}
static int eap_fast_pac_type(u8 *pac, size_t len, u16 type)
{
	struct eap_tlv_pac_type_tlv *tlv;

	if (pac == NULL || len != sizeof(*tlv))
		return 0;

	tlv = (struct eap_tlv_pac_type_tlv *) pac;

	return be_to_host16(tlv->tlv_type) == PAC_TYPE_PAC_TYPE &&
		be_to_host16(tlv->length) == 2 &&
		be_to_host16(tlv->pac_type) == type;
}
Example #4
0
static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, size_t len)
{
    struct eap_hdr *hdr = (struct eap_hdr *) req;
    u8 *pos;
    char *msg;
    size_t msg_len;
    int i;

    pos = (u8 *) (hdr + 1);
    pos++;

    msg_len = be_to_host16(hdr->length);
    if (msg_len < 5)
        return;
    msg_len -= 5;
    wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
                      pos, msg_len);

    msg = malloc(msg_len + 1);
    if (msg == NULL)
        return;
    for (i = 0; i < msg_len; i++)
        msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
    msg[msg_len] = '\0';
    wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
            WPA_EVENT_EAP_NOTIFICATION, msg);
    free(msg);
}
Example #5
0
static void iapp_process_add_notify(struct iapp_data *iapp,
				    struct sockaddr_in *from,
				    struct iapp_hdr *hdr, int len)
{
	struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
	struct sta_info *sta;

	if (len != sizeof(*add)) {
		printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
		       len, (unsigned long) sizeof(*add));
		return;
	}

	sta = ap_get_sta(iapp->hapd, add->mac_addr);

	/* IAPP-ADD.indication(MAC Address, Sequence Number) */
	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
		       HOSTAPD_LEVEL_INFO,
		       "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
		       be_to_host16(add->seq_num),
		       inet_ntoa(from->sin_addr), ntohs(from->sin_port),
		       sta ? "" : " (STA not found)");

	if (!sta)
		return;

	/* TODO: could use seq_num to try to determine whether last association
	 * to this AP is newer than the one advertised in IAPP-ADD. Although,
	 * this is not really a reliable verification. */

	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
		       HOSTAPD_LEVEL_DEBUG,
		       "Removing STA due to IAPP ADD-notify");
	ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
}
Example #6
0
SM_STATE(EAP, NAK)
{
	const struct eap_hdr *nak;
	size_t len = 0;
	const u8 *pos;
	const u8 *nak_list = NULL;

	SM_ENTRY(EAP, NAK);

	if (sm->eap_method_priv) {
		sm->m->reset(sm, sm->eap_method_priv);
		sm->eap_method_priv = NULL;
	}
	sm->m = NULL;

	nak = wpabuf_head(sm->eap_if.eapRespData);
	if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) {
		len = be_to_host16(nak->length);
		if (len > wpabuf_len(sm->eap_if.eapRespData))
			len = wpabuf_len(sm->eap_if.eapRespData);
		pos = (const u8 *) (nak + 1);
		len -= sizeof(*nak);
		if (*pos == EAP_TYPE_NAK) {
			pos++;
			len--;
			nak_list = pos;
		}
	}
	eap_sm_Policy_update(sm, nak_list, len);
}
static void eap_fast_process_phase2_eap(struct eap_sm *sm,
					struct eap_fast_data *data,
					u8 *in_data, size_t in_len)
{
	struct eap_hdr *hdr;
	size_t len;

	hdr = (struct eap_hdr *) in_data;
	if (in_len < (int) sizeof(*hdr)) {
		wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
			   "EAP frame (len=%lu)", (unsigned long) in_len);
		eap_fast_req_failure(sm, data);
		return;
	}
	len = be_to_host16(hdr->length);
	if (len > in_len) {
		wpa_printf(MSG_INFO, "EAP-FAST: Length mismatch in "
			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
			   (unsigned long) in_len, (unsigned long) len);
		eap_fast_req_failure(sm, data);
		return;
	}
	wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: code=%d "
		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
		   (unsigned long) len);
	switch (hdr->code) {
	case EAP_CODE_RESPONSE:
		eap_fast_process_phase2_response(sm, data, (u8 *) hdr, len);
		break;
	default:
		wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
			   "Phase 2 EAP header", hdr->code);
		break;
	}
}
static u8 * eap_mschapv2_failure(struct eap_sm *sm,
				 struct eap_mschapv2_data *data,
				 struct eap_method_ret *ret,
				 const struct eap_mschapv2_hdr *req,
				 size_t *respDataLen)
{
	struct eap_mschapv2_hdr *resp;
	const u8 *msdata = (const u8 *) (req + 1);
	char *buf;
	int len = be_to_host16(req->length) - sizeof(*req);
	int retry = 0;

	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure");
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data",
			  msdata, len);
	buf = malloc(len + 1);
	if (buf) {
		memcpy(buf, msdata, len);
		buf[len] = '\0';
		retry = eap_mschapv2_failure_txt(sm, data, buf);
		free(buf);
	}

	ret->ignore = FALSE;
	ret->methodState = METHOD_DONE;
	ret->decision = DECISION_FAIL;
	ret->allowNotifications = FALSE;

	if (data->prev_error == ERROR_PASSWD_EXPIRED &&
	    data->passwd_change_version == 3) {
		struct wpa_ssid *config = eap_get_config(sm);
		if (config && config->new_password)
			return eap_mschapv2_change_password(sm, data, ret, req,
							    respDataLen);
		if (config && config->pending_req_new_password)
			return NULL;
	} else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
		/* TODO: could try to retry authentication, e.g, after having
		 * changed the username/password. In this case, EAP MS-CHAP-v2
		 * Failure Response would not be sent here. */
		return NULL;
	}

	*respDataLen = 6;
	resp = malloc(6);
	if (resp == NULL) {
		return NULL;
	}

	resp->code = EAP_CODE_RESPONSE;
	resp->identifier = req->identifier;
	resp->length = host_to_be16(6);
	resp->type = EAP_TYPE_MSCHAPV2;
	resp->op_code = MSCHAPV2_OP_FAILURE;

	return (u8 *) resp;
}
Example #9
0
static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, size_t len)
{
	struct eap_hdr *hdr = (struct eap_hdr *) req;
	u8 *pos = (u8 *) (hdr + 1);
	pos++;
	/* TODO: log the Notification Request and make it available for UI */
	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
			  pos, be_to_host16(hdr->length) - 5);
}
Example #10
0
static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len)
{
	struct eap_hdr *hdr = (struct eap_hdr *) req;
	u8 *pos = (u8 *) (hdr + 1);
	pos++;
	/* TODO: could save displayable message so that it can be shown to the
	 * user in case of interaction is required */
	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
			  pos, be_to_host16(hdr->length) - 5);
}
Example #11
0
static int eap_fast_process_pac_info(struct eap_fast_pac *entry)
{
	struct pac_tlv_hdr *hdr;
	u8 *pos;
	size_t left, len;
	int type;

	/* draft-cam-winget-eap-fast-provisioning-04.txt, Section 4.2.4 */

	/* PAC-Type defaults to Tunnel PAC (Type 1) */
	entry->pac_type = PAC_TYPE_TUNNEL_PAC;

	pos = entry->pac_info;
	left = entry->pac_info_len;
	while (left > sizeof(*hdr)) {
		hdr = (struct pac_tlv_hdr *) pos;
		type = be_to_host16(hdr->type);
		len = be_to_host16(hdr->len);
		pos += sizeof(*hdr);
		left -= sizeof(*hdr);
		if (len > left) {
			wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info overrun "
				   "(type=%d len=%lu left=%lu)",
				   type, (unsigned long) len,
				   (unsigned long) left);
			return -1;
		}

		if (eap_fast_parse_pac_info(entry, type, pos, len) < 0)
			return -1;

		pos += len;
		left -= len;
	}

	if (entry->a_id == NULL || entry->a_id_info == NULL) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info does not include "
			   "all the required fields");
		return -1;
	}

	return 0;
}
Example #12
0
static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
{
	const struct eap_hdr *hdr;
	size_t plen;

	/* parse rxResp, respId, respMethod */
	sm->rxResp = FALSE;
	sm->respId = -1;
	sm->respMethod = EAP_TYPE_NONE;
	sm->respVendor = EAP_VENDOR_IETF;
	sm->respVendorMethod = EAP_TYPE_NONE;

	if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) {
		wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p "
			   "len=%lu", resp,
			   resp ? (unsigned long) wpabuf_len(resp) : 0);
		return;
	}

	hdr = wpabuf_head(resp);
	plen = be_to_host16(hdr->length);
	if (plen > wpabuf_len(resp)) {
		wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
			   "(len=%lu plen=%lu)",
			   (unsigned long) wpabuf_len(resp),
			   (unsigned long) plen);
		return;
	}

	sm->respId = hdr->identifier;

	if (hdr->code == EAP_CODE_RESPONSE)
		sm->rxResp = TRUE;

	if (plen > sizeof(*hdr)) {
		u8 *pos = (u8 *) (hdr + 1);
		sm->respMethod = *pos++;
		if (sm->respMethod == EAP_TYPE_EXPANDED) {
			if (plen < sizeof(*hdr) + 8) {
				wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
					   "expanded EAP-Packet (plen=%lu)",
					   (unsigned long) plen);
				return;
			}
			sm->respVendor = WPA_GET_BE24(pos);
			pos += 3;
			sm->respVendorMethod = WPA_GET_BE32(pos);
		}
	}

	wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
		   "respMethod=%u respVendor=%u respVendorMethod=%u",
		   sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
		   sm->respVendorMethod);
}
Example #13
0
static u8 * eap_mschapv2_success(struct eap_sm *sm,
				 struct eap_mschapv2_data *data,
				 struct eap_method_ret *ret,
				 struct eap_mschapv2_hdr *req,
				 size_t *respDataLen)
{
	struct eap_mschapv2_hdr *resp;
	u8 *pos, recv_response[20];
	int len, left;

	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
	len = be_to_host16(req->length);
	pos = (u8 *) (req + 1);
	if (!data->auth_response_valid || len < sizeof(*req) + 42 ||
	    pos[0] != 'S' || pos[1] != '=' ||
	    hexstr2bin((char *) (pos + 2), recv_response, 20) ||
	    memcmp(data->auth_response, recv_response, 20) != 0) {
		wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator "
			   "response in success request");
		ret->methodState = METHOD_DONE;
		ret->decision = DECISION_FAIL;
		return NULL;
	}
	pos += 42;
	left = len - sizeof(*req) - 42;
	while (left > 0 && *pos == ' ') {
		pos++;
		left--;
	}
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message",
			  pos, left);
	wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded");
	*respDataLen = 6;
	resp = malloc(6);
	if (resp == NULL) {
		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
			   "buffer for success response");
		ret->ignore = TRUE;
		return NULL;
	}

	resp->code = EAP_CODE_RESPONSE;
	resp->identifier = req->identifier;
	resp->length = host_to_be16(6);
	resp->type = EAP_TYPE_MSCHAPV2;
	resp->op_code = MSCHAPV2_OP_SUCCESS;

	ret->methodState = METHOD_DONE;
	ret->decision = DECISION_UNCOND_SUCC;
	ret->allowNotifications = FALSE;
	data->success = 1;

	return (u8 *) resp;
}
Example #14
0
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
		   struct wpa_state_machine *sm, struct wpa_eapol_key *key)
{
	struct wpa_eapol_ie_parse kde;
	struct wpa_stsl_search search;
	struct rsn_error_kde error;
	u16 mui, error_type;

	if (wpa_parse_kde_ies((const u8 *) (key + 1),
			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
		return;
	}

	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
	    kde.error == NULL || kde.error_len < sizeof(error)) {
		wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
			   "SMK Error");
		return;
	}

	search.addr = kde.mac_addr;
	search.sm = NULL;
	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
	    0 || search.sm == NULL) {
		wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
			   "associated for SMK Error message from " MACSTR,
			   MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
		return;
	}

	os_memcpy(&error, kde.error, sizeof(error));
	mui = be_to_host16(error.mui);
	error_type = be_to_host16(error.error_type);
	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
			 "STA reported SMK Error: Peer " MACSTR
			 " MUI %d Error Type %d",
			 MAC2STR(kde.mac_addr), mui, error_type);

	wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
}
Example #15
0
const u8 * eap_hdr_validate(int vendor, EapType eap_type,
			    const struct wpabuf *msg, size_t *plen)
{
	const struct eap_hdr *hdr;
	const u8 *pos;
	size_t len;

	hdr = wpabuf_head(msg);

	if (wpabuf_len(msg) < sizeof(*hdr)) {
		wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
		return NULL;
	}

	len = be_to_host16(hdr->length);
	if (len < sizeof(*hdr) + 1 || len > wpabuf_len(msg)) {
		wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
		return NULL;
	}

	pos = (const u8 *) (hdr + 1);

	if (*pos == EAP_TYPE_EXPANDED) {
		int exp_vendor;
		u32 exp_type;
		if (len < sizeof(*hdr) + 8) {
			wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
				   "length");
			return NULL;
		}
		pos++;
		exp_vendor = WPA_GET_BE24(pos);
		pos += 3;
		exp_type = WPA_GET_BE32(pos);
		pos += 4;
		if (exp_vendor != vendor || exp_type != (u32) eap_type) {
			wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
				   "type");
			return NULL;
		}

		*plen = len - sizeof(*hdr) - 8;
		return pos;
	} else {
		if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
			wpa_printf(MSG_INFO, "EAP: Invalid frame type");
			return NULL;
		}
		*plen = len - sizeof(*hdr) - 1;
		return pos + 1;
	}
}
Example #16
0
static int eap_fast_process_pac_tlv(struct eap_fast_pac *entry,
				    u8 *pac, size_t pac_len)
{
	struct pac_tlv_hdr *hdr;
	u8 *pos;
	size_t left, len;
	int type, pac_key_found = 0;

	pos = pac;
	left = pac_len;

	while (left > sizeof(*hdr)) {
		hdr = (struct pac_tlv_hdr *) pos;
		type = be_to_host16(hdr->type);
		len = be_to_host16(hdr->len);
		pos += sizeof(*hdr);
		left -= sizeof(*hdr);
		if (len > left) {
			wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV overrun "
				   "(type=%d len=%lu left=%lu)",
				   type, (unsigned long) len,
				   (unsigned long) left);
			return -1;
		}

		eap_fast_parse_pac_tlv(entry, type, pos, len, &pac_key_found);

		pos += len;
		left -= len;
	}

	if (!pac_key_found || !entry->pac_opaque || !entry->pac_info) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV does not include "
			   "all the required fields");
		return -1;
	}

	return 0;
}
void radius_msg_dump(struct radius_msg *msg)
{
	size_t i;

	printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
	       msg->hdr->code, radius_code_string(msg->hdr->code),
	       msg->hdr->identifier, be_to_host16(msg->hdr->length));

	for (i = 0; i < msg->attr_used; i++) {
		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
		radius_msg_dump_attr(attr);
	}
}
Example #18
0
static void test_driver_ether(struct test_driver_data *drv,
			      struct sockaddr_un *from, socklen_t fromlen,
			      u8 *data, size_t datalen)
{
	struct l2_ethhdr *eth;

	if (datalen < sizeof(*eth))
		return;

	eth = (struct l2_ethhdr *) data;
	wpa_printf(MSG_DEBUG, "test_driver: RX ETHER dst=" MACSTR " src="
		   MACSTR " proto=%04x",
		   MAC2STR(eth->h_dest), MAC2STR(eth->h_source),
		   be_to_host16(eth->h_proto));

#ifdef CONFIG_IEEE80211R
	if (be_to_host16(eth->h_proto) == ETH_P_RRB) {
		wpa_ft_rrb_rx(drv->hapd->wpa_auth, eth->h_source,
			      data + sizeof(*eth), datalen - sizeof(*eth));
	}
#endif /* CONFIG_IEEE80211R */
}
Example #19
0
static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv,
					struct eap_method_ret *ret,
					const struct wpabuf *reqData)
{
	const struct eap_hdr *eap;
	size_t password_len;
	const u8 *password;

	password = eap_get_config_password(sm, &password_len);
	if (password == NULL) {
		wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
		eap_sm_request_password(sm);
		ret->ignore = TRUE;
		return NULL;
	}

	/*
	 * LEAP needs to be able to handle EAP-Success frame which does not
	 * include Type field. Consequently, eap_hdr_validate() cannot be used
	 * here. This validation will be done separately for EAP-Request and
	 * EAP-Response frames.
	 */
	eap = wpabuf_head(reqData);
	if (wpabuf_len(reqData) < sizeof(*eap) ||
	    be_to_host16(eap->length) > wpabuf_len(reqData)) {
		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
		ret->ignore = TRUE;
		return NULL;
	}

	ret->ignore = FALSE;
	ret->allowNotifications = TRUE;
	ret->methodState = METHOD_MAY_CONT;
	ret->decision = DECISION_FAIL;

	sm->leap_done = FALSE;

	switch (eap->code) {
	case EAP_CODE_REQUEST:
		return eap_leap_process_request(sm, priv, ret, reqData);
	case EAP_CODE_SUCCESS:
		return eap_leap_process_success(sm, priv, ret, reqData);
	case EAP_CODE_RESPONSE:
		return eap_leap_process_response(sm, priv, ret, reqData);
	default:
		wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
			   "ignored", eap->code);
		ret->ignore = TRUE;
		return NULL;
	}
}
Example #20
0
static void eap_pwd_process_id_resp(struct eap_sm *sm,
				    struct eap_pwd_data *data,
				    const u8 *payload, size_t payload_len)
{
	struct eap_pwd_id *id;

	if (payload_len < sizeof(struct eap_pwd_id)) {
		wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response");
		return;
	}

	id = (struct eap_pwd_id *) payload;
	if ((data->group_num != be_to_host16(id->group_num)) ||
	    (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
	    (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
	    (id->prf != EAP_PWD_DEFAULT_PRF)) {
		wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
		eap_pwd_state(data, FAILURE);
		return;
	}
	data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
	if (data->id_peer == NULL) {
		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
		return;
	}
	data->id_peer_len = payload_len - sizeof(struct eap_pwd_id);
	os_memcpy(data->id_peer, id->identity, data->id_peer_len);
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
			  data->id_peer, data->id_peer_len);

	if ((data->grp = os_malloc(sizeof(EAP_PWD_group))) == NULL) {
		wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
			   "group");
		return;
	}
	if (compute_password_element(data->grp, data->group_num,
				     data->password, data->password_len,
				     data->id_server, data->id_server_len,
				     data->id_peer, data->id_peer_len,
				     (u8 *) &data->token)) {
		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
			   "PWE");
		return;
	}
	wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
		   BN_num_bits(data->grp->prime));

	eap_pwd_state(data, PWD_Commit_Req);
}
static u8 * eap_leap_process(struct eap_sm *sm, void *priv,
			     struct eap_method_ret *ret,
			     const u8 *reqData, size_t reqDataLen,
			     size_t *respDataLen)
{
	const struct eap_hdr *eap;
	size_t len, password_len;
	const u8 *password;

	password = eap_get_config_password(sm, &password_len);
	if (password == NULL) {
		wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
		eap_sm_request_password(sm);
		ret->ignore = TRUE;
		return NULL;
	}

	eap = (const struct eap_hdr *) reqData;

	if (reqDataLen < sizeof(*eap) ||
	    (len = be_to_host16(eap->length)) > reqDataLen) {
		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
		ret->ignore = TRUE;
		return NULL;
	}

	ret->ignore = FALSE;
	ret->allowNotifications = TRUE;
	ret->methodState = METHOD_MAY_CONT;
	ret->decision = DECISION_FAIL;

	sm->leap_done = FALSE;

	switch (eap->code) {
	case EAP_CODE_REQUEST:
		return eap_leap_process_request(sm, priv, ret, reqData, len,
						respDataLen);
	case EAP_CODE_SUCCESS:
		return eap_leap_process_success(sm, priv, ret, reqData,
						respDataLen);
	case EAP_CODE_RESPONSE:
		return eap_leap_process_response(sm, priv, ret, reqData, len);
	default:
		wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
			   "ignored", eap->code);
		ret->ignore = TRUE;
		return NULL;
	}
}
Example #22
0
static u8 * eap_mschapv2_failure(struct eap_sm *sm,
				 struct eap_mschapv2_data *data,
				 struct eap_method_ret *ret,
				 struct eap_mschapv2_hdr *req,
				 size_t *respDataLen)
{
	struct eap_mschapv2_hdr *resp;
	u8 *msdata = (u8 *) (req + 1);
	char *buf;
	int len = be_to_host16(req->length) - sizeof(*req);
	int retry = 0;

	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure");
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data",
			  msdata, len);
	buf = malloc(len + 1);
	if (buf) {
		memcpy(buf, msdata, len);
		buf[len] = '\0';
		retry = eap_mschapv2_failure_txt(sm, data, buf);
		free(buf);
	}

	ret->ignore = FALSE;
	ret->methodState = METHOD_DONE;
	ret->decision = DECISION_FAIL;
	ret->allowNotifications = FALSE;

	if (retry) {
		/* TODO: could try to retry authentication, e.g, after having
		 * changed the username/password. In this case, EAP MS-CHAP-v2
		 * Failure Response would not be sent here. */
	}

	*respDataLen = 6;
	resp = malloc(6);
	if (resp == NULL) {
		return NULL;
	}

	resp->code = EAP_CODE_RESPONSE;
	resp->identifier = req->identifier;
	resp->length = host_to_be16(6);
	resp->type = EAP_TYPE_MSCHAPV2;
	resp->op_code = MSCHAPV2_OP_FAILURE;

	return (u8 *) resp;
}
Example #23
0
static int ibss_rsn_eapol_dst_supp(const u8 *buf, size_t len)
{
	const struct ieee802_1x_hdr *hdr;
	const struct wpa_eapol_key *key;
	u16 key_info;
	size_t plen;

	/* TODO: Support other EAPOL packets than just EAPOL-Key */

	if (len < sizeof(*hdr) + sizeof(*key))
		return -1;

	hdr = (const struct ieee802_1x_hdr *) buf;
	key = (const struct wpa_eapol_key *) (hdr + 1);
	plen = be_to_host16(hdr->length);

	if (hdr->version < EAPOL_VERSION) {
		/* TODO: backwards compatibility */
	}
	if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
		wpa_printf(MSG_DEBUG, "RSN: EAPOL frame (type %u) discarded, "
			"not a Key frame", hdr->type);
		return -1;
	}
	if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
		wpa_printf(MSG_DEBUG, "RSN: EAPOL frame payload size %lu "
			   "invalid (frame size %lu)",
			   (unsigned long) plen, (unsigned long) len);
		return -1;
	}

	if (key->type != EAPOL_KEY_TYPE_RSN) {
		wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key type (%d) unknown, "
			   "discarded", key->type);
		return -1;
	}

	key_info = WPA_GET_BE16(key->key_info);

	return !!(key_info & WPA_KEY_INFO_ACK);
}
Example #24
0
static int inline file_2_element(int fd,void* ele,int size){
    if(read(fd,ele,size) != size){
        wave_error_printf("读取长度失败");
        return -1;
    }
     switch(size){
        case 1:
            *(u8*)ele = *(u8*)ele;
            break;
        case 2:
            *(u16*)ele = be_to_host16( *(u16*)ele );
            break;
        case 4:
            *(u32*)ele = be_to_host32( *(u32*)ele );
            break;
        case 8:
            *(u64*)ele = be_to_host64( *(u64*)ele );
            break;
    }
    return 0;
}
Example #25
0
/**
 * eap_hdr_len_valid - Validate EAP header length field
 * @msg: EAP frame (starting with EAP header)
 * @min_payload: Minimum payload length needed
 * Returns: 1 for valid header, 0 for invalid
 *
 * This is a helper function that does minimal validation of EAP messages. The
 * length field is verified to be large enough to include the header and not
 * too large to go beyond the end of the buffer.
 */
int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload)
{
	const struct eap_hdr *hdr;
	size_t len;

	if (msg == NULL)
		return 0;

	hdr = wpabuf_head(msg);

	if (wpabuf_len(msg) < sizeof(*hdr)) {
		wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
		return 0;
	}

	len = be_to_host16(hdr->length);
	if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) {
		wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
		return 0;
	}

	return 1;
}
Example #26
0
static struct wpabuf * eap_fast_process_eap_payload_tlv(
	struct eap_sm *sm, struct eap_fast_data *data,
	struct eap_method_ret *ret, const struct eap_hdr *req,
	u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
{
	struct eap_hdr *hdr;
	struct wpabuf *resp = NULL;

	if (eap_payload_tlv_len < sizeof(*hdr)) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP "
			   "Payload TLV (len=%lu)",
			   (unsigned long) eap_payload_tlv_len);
		return NULL;
	}

	hdr = (struct eap_hdr *) eap_payload_tlv;
	if (be_to_host16(hdr->length) > eap_payload_tlv_len) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow in "
			   "EAP Payload TLV");
		return NULL;
	}

	if (hdr->code != EAP_CODE_REQUEST) {
		wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
			   "Phase 2 EAP header", hdr->code);
		return NULL;
	}

	if (eap_fast_phase2_request(sm, data, ret, hdr, &resp)) {
		wpa_printf(MSG_INFO, "EAP-FAST: Phase2 Request processing "
			   "failed");
		return NULL;
	}

	return eap_fast_tlv_eap_payload(resp);
}
Example #27
0
static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
			    struct eap_method_ret *ret,
			    const struct eap_hdr *req,
			    const struct wpabuf *in_data,
			    struct wpabuf **out_data)
{
	struct wpabuf *in_decrypted = NULL;
	int res, skip_change = 0;
	struct eap_hdr *hdr, *rhdr;
	struct wpabuf *resp = NULL;
	size_t len;

	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
		   " Phase 2", (unsigned long) wpabuf_len(in_data));

	if (data->pending_phase2_req) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
			   "skip decryption and use old data");
		/* Clear TLS reassembly state. */
		eap_peer_tls_reset_input(&data->ssl);
		in_decrypted = data->pending_phase2_req;
		data->pending_phase2_req = NULL;
		skip_change = 1;
		goto continue_req;
	}

	if (wpabuf_len(in_data) == 0 && sm->workaround &&
	    data->phase2_success) {
		/*
		 * Cisco ACS seems to be using TLS ACK to terminate
		 * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
		 */
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
			   "expected data - acknowledge with TLS ACK since "
			   "Phase 2 has been completed");
		ret->decision = DECISION_COND_SUCC;
		ret->methodState = METHOD_DONE;
		return 1;
	} else if (wpabuf_len(in_data) == 0) {
		/* Received TLS ACK - requesting more fragments */
		return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
					    data->peap_version,
					    req->identifier, NULL, out_data);
	}

	res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
	if (res)
		return res;

continue_req:
	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
			in_decrypted);

	hdr = wpabuf_mhead(in_decrypted);
	if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST &&
	    be_to_host16(hdr->length) == 5 &&
	    eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) {
		/* At least FreeRADIUS seems to send full EAP header with
		 * EAP Request Identity */
		skip_change = 1;
	}
	if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST &&
	    eap_get_type(in_decrypted) == EAP_TYPE_TLV) {
		skip_change = 1;
	}

	if (data->peap_version == 0 && !skip_change) {
		struct eap_hdr *nhdr;
		struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
						   wpabuf_len(in_decrypted));
		if (nmsg == NULL) {
			wpabuf_free(in_decrypted);
			return 0;
		}
		nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
		wpabuf_put_buf(nmsg, in_decrypted);
		nhdr->code = req->code;
		nhdr->identifier = req->identifier;
		nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
					    wpabuf_len(in_decrypted));

		wpabuf_free(in_decrypted);
		in_decrypted = nmsg;
	}

	if (data->peap_version >= 2) {
		struct eap_tlv_hdr *tlv;
		struct wpabuf *nmsg;

		if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
			wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
				   "EAP TLV");
			wpabuf_free(in_decrypted);
			return 0;
		}
		tlv = wpabuf_mhead(in_decrypted);
		if ((be_to_host16(tlv->tlv_type) & 0x3fff) !=
		    EAP_TLV_EAP_PAYLOAD_TLV) {
			wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
			wpabuf_free(in_decrypted);
			return 0;
		}
		if (sizeof(*tlv) + be_to_host16(tlv->length) >
		    wpabuf_len(in_decrypted)) {
			wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
				   "length");
			wpabuf_free(in_decrypted);
			return 0;
		}
		hdr = (struct eap_hdr *) (tlv + 1);
		if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
			wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
				   "EAP packet in EAP TLV");
			wpabuf_free(in_decrypted);
			return 0;
		}

		nmsg = wpabuf_alloc(be_to_host16(hdr->length));
		if (nmsg == NULL) {
			wpabuf_free(in_decrypted);
			return 0;
		}

		wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
		wpabuf_free(in_decrypted);
		in_decrypted = nmsg;
	}

	hdr = wpabuf_mhead(in_decrypted);
	if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
			   "EAP frame (len=%lu)",
			   (unsigned long) wpabuf_len(in_decrypted));
		wpabuf_free(in_decrypted);
		return 0;
	}
	len = be_to_host16(hdr->length);
	if (len > wpabuf_len(in_decrypted)) {
		wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
			   (unsigned long) wpabuf_len(in_decrypted),
			   (unsigned long) len);
		wpabuf_free(in_decrypted);
		return 0;
	}
	if (len < wpabuf_len(in_decrypted)) {
		wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
			   "shorter length than full decrypted data "
			   "(%lu < %lu)",
			   (unsigned long) len,
			   (unsigned long) wpabuf_len(in_decrypted));
	}
	wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
		   (unsigned long) len);
	switch (hdr->code) {
	case EAP_CODE_REQUEST:
		if (eap_peap_phase2_request(sm, data, ret, in_decrypted,
					    &resp)) {
			wpabuf_free(in_decrypted);
			wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
				   "processing failed");
			return 0;
		}
		break;
	case EAP_CODE_SUCCESS:
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
		if (data->peap_version == 1) {
			/* EAP-Success within TLS tunnel is used to indicate
			 * shutdown of the TLS channel. The authentication has
			 * been completed. */
			if (data->phase2_eap_started &&
			    !data->phase2_eap_success) {
				wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
					   "Success used to indicate success, "
					   "but Phase 2 EAP was not yet "
					   "completed successfully");
				ret->methodState = METHOD_DONE;
				ret->decision = DECISION_FAIL;
				wpabuf_free(in_decrypted);
				return 0;
			}
			wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
				   "EAP-Success within TLS tunnel - "
				   "authentication completed");
			ret->decision = DECISION_UNCOND_SUCC;
			ret->methodState = METHOD_DONE;
			data->phase2_success = 1;
			if (data->peap_outer_success == 2) {
				wpabuf_free(in_decrypted);
				wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
					   "to finish authentication");
				return 1;
			} else if (data->peap_outer_success == 1) {
				/* Reply with EAP-Success within the TLS
				 * channel to complete the authentication. */
				resp = wpabuf_alloc(sizeof(struct eap_hdr));
				if (resp) {
					rhdr = wpabuf_put(resp, sizeof(*rhdr));
					rhdr->code = EAP_CODE_SUCCESS;
					rhdr->identifier = hdr->identifier;
					rhdr->length =
						host_to_be16(sizeof(*rhdr));
				}
			} else {
				/* No EAP-Success expected for Phase 1 (outer,
				 * unencrypted auth), so force EAP state
				 * machine to SUCCESS state. */
				sm->peap_done = TRUE;
			}
		} else {
			/* FIX: ? */
		}
		break;
	case EAP_CODE_FAILURE:
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
		ret->decision = DECISION_FAIL;
		ret->methodState = METHOD_MAY_CONT;
		ret->allowNotifications = FALSE;
		/* Reply with EAP-Failure within the TLS channel to complete
		 * failure reporting. */
		resp = wpabuf_alloc(sizeof(struct eap_hdr));
		if (resp) {
			rhdr = wpabuf_put(resp, sizeof(*rhdr));
			rhdr->code = EAP_CODE_FAILURE;
			rhdr->identifier = hdr->identifier;
			rhdr->length = host_to_be16(sizeof(*rhdr));
		}
		break;
	default:
		wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
			   "Phase 2 EAP header", hdr->code);
		break;
	}

	wpabuf_free(in_decrypted);

	if (resp) {
		int skip_change2 = 0;
		struct wpabuf *rmsg, buf;

		wpa_hexdump_buf_key(MSG_DEBUG,
				    "EAP-PEAP: Encrypting Phase 2 data", resp);
		/* PEAP version changes */
		if (data->peap_version >= 2) {
			resp = eap_peapv2_tlv_eap_payload(resp);
			if (resp == NULL)
				return -1;
		}
		if (wpabuf_len(resp) >= 5 &&
		    wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
		    eap_get_type(resp) == EAP_TYPE_TLV)
			skip_change2 = 1;
		rmsg = resp;
		if (data->peap_version == 0 && !skip_change2) {
			wpabuf_set(&buf, wpabuf_head_u8(resp) +
				   sizeof(struct eap_hdr),
				   wpabuf_len(resp) - sizeof(struct eap_hdr));
			rmsg = &buf;
		}

		if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
					 data->peap_version, req->identifier,
					 rmsg, out_data)) {
			wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
				   "a Phase 2 frame");
		}
		wpabuf_free(resp);
	}

	return 0;
}
Example #28
0
static int eap_peap_phase2_request(struct eap_sm *sm,
				   struct eap_peap_data *data,
				   struct eap_method_ret *ret,
				   struct wpabuf *req,
				   struct wpabuf **resp)
{
	struct eap_hdr *hdr = wpabuf_mhead(req);
	size_t len = be_to_host16(hdr->length);
	u8 *pos;
	struct eap_method_ret iret;
	struct eap_peer_config *config = eap_get_config(sm);

	if (len <= sizeof(struct eap_hdr)) {
		wpa_printf(MSG_INFO, "EAP-PEAP: too short "
			   "Phase 2 request (len=%lu)", (unsigned long) len);
		return -1;
	}
	pos = (u8 *) (hdr + 1);
	wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
	switch (*pos) {
	case EAP_TYPE_IDENTITY:
		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
		break;
	case EAP_TYPE_TLV:
		os_memset(&iret, 0, sizeof(iret));
		if (eap_tlv_process(sm, data, &iret, req, resp,
				    data->phase2_eap_started &&
				    !data->phase2_eap_success)) {
			ret->methodState = METHOD_DONE;
			ret->decision = DECISION_FAIL;
			return -1;
		}
		if (iret.methodState == METHOD_DONE ||
		    iret.methodState == METHOD_MAY_CONT) {
			ret->methodState = iret.methodState;
			ret->decision = iret.decision;
			data->phase2_success = 1;
		}
		break;
	case EAP_TYPE_EXPANDED:
#ifdef EAP_TNC
		if (data->soh) {
			const u8 *epos;
			size_t eleft;

			epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
						req, &eleft);
			if (epos) {
				struct wpabuf *buf;
				wpa_printf(MSG_DEBUG,
					   "EAP-PEAP: SoH EAP Extensions");
				buf = tncc_process_soh_request(data->soh,
							       epos, eleft);
				if (buf) {
					*resp = eap_msg_alloc(
						EAP_VENDOR_MICROSOFT, 0x21,
						wpabuf_len(buf),
						EAP_CODE_RESPONSE,
						hdr->identifier);
					if (*resp == NULL) {
						ret->methodState = METHOD_DONE;
						ret->decision = DECISION_FAIL;
						return -1;
					}
					wpabuf_put_buf(*resp, buf);
					wpabuf_free(buf);
					break;
				}
			}
		}
#endif /* EAP_TNC */
		/* fall through */
	default:
		if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
		    data->phase2_type.method == EAP_TYPE_NONE) {
			size_t i;
			for (i = 0; i < data->num_phase2_types; i++) {
				if (data->phase2_types[i].vendor !=
				    EAP_VENDOR_IETF ||
				    data->phase2_types[i].method != *pos)
					continue;

				data->phase2_type.vendor =
					data->phase2_types[i].vendor;
				data->phase2_type.method =
					data->phase2_types[i].method;
				wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
					   "Phase 2 EAP vendor %d method %d",
					   data->phase2_type.vendor,
					   data->phase2_type.method);
				break;
			}
		}
		if (*pos != data->phase2_type.method ||
		    *pos == EAP_TYPE_NONE) {
			if (eap_peer_tls_phase2_nak(data->phase2_types,
						    data->num_phase2_types,
						    hdr, resp))
				return -1;
			return 0;
		}

		if (data->phase2_priv == NULL) {
			data->phase2_method = eap_peer_get_eap_method(
				data->phase2_type.vendor,
				data->phase2_type.method);
			if (data->phase2_method) {
				sm->init_phase2 = 1;
				data->phase2_priv =
					data->phase2_method->init(sm);
				sm->init_phase2 = 0;
			}
		}
		if (data->phase2_priv == NULL || data->phase2_method == NULL) {
			wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
				   "Phase 2 EAP method %d", *pos);
			ret->methodState = METHOD_DONE;
			ret->decision = DECISION_FAIL;
			return -1;
		}
		data->phase2_eap_started = 1;
		os_memset(&iret, 0, sizeof(iret));
		*resp = data->phase2_method->process(sm, data->phase2_priv,
						     &iret, req);
		if ((iret.methodState == METHOD_DONE ||
		     iret.methodState == METHOD_MAY_CONT) &&
		    (iret.decision == DECISION_UNCOND_SUCC ||
		     iret.decision == DECISION_COND_SUCC)) {
			data->phase2_eap_success = 1;
			data->phase2_success = 1;
		}
		break;
	}

	if (*resp == NULL &&
	    (config->pending_req_identity || config->pending_req_password ||
	     config->pending_req_otp || config->pending_req_new_password)) {
		wpabuf_free(data->pending_phase2_req);
		data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
	}

	return 0;
}
Example #29
0
static u8 * eap_sim_process(struct eap_sm *sm, void *priv,
			    struct eap_method_ret *ret,
			    u8 *reqData, size_t reqDataLen,
			    size_t *respDataLen)
{
	struct eap_sim_data *data = priv;
	struct wpa_ssid *config = eap_get_config(sm);
	struct eap_hdr *req;
	u8 *pos, subtype, *res;
	struct eap_sim_attrs attr;
	size_t len;

	wpa_hexdump(MSG_DEBUG, "EAP-SIM: EAP data", reqData, reqDataLen);
	if (config == NULL || config->identity == NULL) {
		wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
		eap_sm_request_identity(sm, config);
		ret->ignore = TRUE;
		return NULL;
	}

	req = (struct eap_hdr *) reqData;
	pos = (u8 *) (req + 1);
	if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_SIM ||
	    (len = be_to_host16(req->length)) > reqDataLen) {
		wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
		ret->ignore = TRUE;
		return NULL;
	}

	ret->ignore = FALSE;
	ret->methodState = METHOD_CONT;
	ret->decision = DECISION_FAIL;
	ret->allowNotifications = TRUE;

	pos++;
	subtype = *pos++;
	wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
	pos += 2; /* Reserved */

	if (eap_sim_parse_attr(pos, reqData + len, &attr, 0, 0)) {
		res = eap_sim_client_error(sm, data, req, respDataLen,
					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
		goto done;
	}

	switch (subtype) {
	case EAP_SIM_SUBTYPE_START:
		res = eap_sim_process_start(sm, data, req, len,
					    respDataLen, &attr);
		break;
	case EAP_SIM_SUBTYPE_CHALLENGE:
		res = eap_sim_process_challenge(sm, data, req, len,
						respDataLen, &attr);
		break;
	case EAP_SIM_SUBTYPE_NOTIFICATION:
		res = eap_sim_process_notification(sm, data, req, len,
						   respDataLen, &attr);
		break;
	case EAP_SIM_SUBTYPE_REAUTHENTICATION:
		res = eap_sim_process_reauthentication(sm, data, req, len,
						       respDataLen, &attr);
		break;
	case EAP_SIM_SUBTYPE_CLIENT_ERROR:
		wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
		res = eap_sim_client_error(sm, data, req, respDataLen,
					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
		break;
	default:
		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
		res = eap_sim_client_error(sm, data, req, respDataLen,
					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
		break;
	}

done:
	if (data->state == FAILURE) {
		ret->decision = DECISION_FAIL;
		ret->methodState = METHOD_DONE;
	} else if (data->state == SUCCESS) {
		ret->decision = DECISION_UNCOND_SUCC;
		ret->methodState = METHOD_DONE;
	}

	if (ret->methodState == METHOD_DONE) {
		ret->allowNotifications = FALSE;
	}

	return res;
}
Example #30
0
static void eapol_sm_processKey(struct eapol_sm *sm)
{
	struct ieee802_1x_hdr *hdr;
	struct ieee802_1x_eapol_key *key;
	struct eap_key_data keydata;
	u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
	u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
	int key_len, res, sign_key_len, encr_key_len;
	u16 rx_key_length;

	wpa_printf(MSG_DEBUG, "EAPOL: processKey");
	if (sm->last_rx_key == NULL)
		return;

	if (!sm->conf.accept_802_1x_keys) {
		wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
			   " even though this was not accepted - "
			   "ignoring this packet");
		return;
	}

	hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
	if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
		wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
		return;
	}
	rx_key_length = WPA_GET_BE16(key->key_length);
	wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
		   "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
		   hdr->version, hdr->type, be_to_host16(hdr->length),
		   key->type, rx_key_length, key->key_index);

	eapol_sm_notify_lower_layer_success(sm, 1);
	sign_key_len = IEEE8021X_SIGN_KEY_LEN;
	encr_key_len = IEEE8021X_ENCR_KEY_LEN;
	res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
	if (res < 0) {
		wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
			   "decrypting EAPOL-Key keys");
		return;
	}
	if (res == 16) {
		/* LEAP derives only 16 bytes of keying material. */
		res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
		if (res) {
			wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
				   "master key for decrypting EAPOL-Key keys");
			return;
		}
		sign_key_len = 16;
		encr_key_len = 16;
		os_memcpy(keydata.sign_key, keydata.encr_key, 16);
	} else if (res) {
		wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
			   "data for decrypting EAPOL-Key keys (res=%d)", res);
		return;
	}

	/* The key replay_counter must increase when same master key */
	if (sm->replay_counter_valid &&
	    os_memcmp(sm->last_replay_counter, key->replay_counter,
		      IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
		wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
			   "not increase - ignoring key");
		wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
			    sm->last_replay_counter,
			    IEEE8021X_REPLAY_COUNTER_LEN);
		wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
			    key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
		return;
	}

	/* Verify key signature (HMAC-MD5) */
	os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
	os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
	hmac_md5(keydata.sign_key, sign_key_len,
		 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
		 key->key_signature);
	if (os_memcmp(orig_key_sign, key->key_signature,
		      IEEE8021X_KEY_SIGN_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
			   "EAPOL-Key packet");
		os_memcpy(key->key_signature, orig_key_sign,
			  IEEE8021X_KEY_SIGN_LEN);
		return;
	}
	wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");

	key_len = be_to_host16(hdr->length) - sizeof(*key);
	if (key_len > 32 || rx_key_length > 32) {
		wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
			   key_len ? key_len : rx_key_length);
		return;
	}
	if (key_len == rx_key_length) {
		os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
		os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
			  encr_key_len);
		os_memcpy(datakey, key + 1, key_len);
		rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
			 datakey, key_len);
		wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
				datakey, key_len);
	} else if (key_len == 0) {
		/*
		 * IEEE 802.1X-2004 specifies that least significant Key Length
		 * octets from MS-MPPE-Send-Key are used as the key if the key
		 * data is not present. This seems to be meaning the beginning
		 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
		 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
		 * Anyway, taking the beginning of the keying material from EAP
		 * seems to interoperate with Authenticators.
		 */
		key_len = rx_key_length;
		os_memcpy(datakey, keydata.encr_key, key_len);
		wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
				"material data encryption key",
				datakey, key_len);
	} else {
		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
			   "(key_length=%d)", key_len, rx_key_length);
		return;
	}

	sm->replay_counter_valid = TRUE;
	os_memcpy(sm->last_replay_counter, key->replay_counter,
		  IEEE8021X_REPLAY_COUNTER_LEN);

	wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
		   "len %d",
		   key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
		   "unicast" : "broadcast",
		   key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);

	if (sm->ctx->set_wep_key &&
	    sm->ctx->set_wep_key(sm->ctx->ctx,
				 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
				 key->key_index & IEEE8021X_KEY_INDEX_MASK,
				 datakey, key_len) < 0) {
		wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
			   " driver.");
	} else {
		if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
			sm->unicast_key_received = TRUE;
		else
			sm->broadcast_key_received = TRUE;

		if ((sm->unicast_key_received ||
		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
		    (sm->broadcast_key_received ||
		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
		{
			wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
				   "frames received");
			sm->portValid = TRUE;
			if (sm->ctx->eapol_done_cb)
				sm->ctx->eapol_done_cb(sm->ctx->ctx);
		}
	}
}