예제 #1
0
static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
						  struct eap_peap_data *data,
						  u8 id, int success)
{
	struct wpabuf *encr_req, msgbuf;
	size_t req_len;
	struct eap_hdr *hdr;

	req_len = sizeof(*hdr);
	hdr = os_zalloc(req_len);
	if (hdr == NULL)
		return NULL;

	hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
	hdr->identifier = id;
	hdr->length = host_to_be16(req_len);

	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
			(u8 *) hdr, req_len);

	wpabuf_set(&msgbuf, hdr, req_len);
	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
	os_free(hdr);

	return encr_req;
}
예제 #2
0
static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
			      size_t cred_len, int wps2)
{
	struct wps_parse_attr attr;
	struct wpabuf msg;

	wpa_printf(MSG_DEBUG, "WPS: Received Credential");
	os_memset(&wps->cred, 0, sizeof(wps->cred));
	wpabuf_set(&msg, cred, cred_len);
	if (wps_parse_msg(&msg, &attr) < 0 ||
	    wps_process_cred(&attr, &wps->cred))
		return -1;

	if (os_memcmp(wps->cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) !=
	    0) {
		wpa_printf(MSG_DEBUG, "WPS: MAC Address in the Credential ("
			   MACSTR ") does not match with own address (" MACSTR
			   ")", MAC2STR(wps->cred.mac_addr),
			   MAC2STR(wps->wps->dev.mac_addr));
		/*
		 * In theory, this could be consider fatal error, but there are
		 * number of deployed implementations using other address here
		 * due to unclarity in the specification. For interoperability
		 * reasons, allow this to be processed since we do not really
		 * use the MAC Address information for anything.
		 */
#ifdef CONFIG_WPS_STRICT
		if (wps2) {
			wpa_printf(MSG_INFO, "WPS: Do not accept incorrect "
				   "MAC Address in AP Settings");
			return -1;
		}
#endif /* CONFIG_WPS_STRICT */
	}

#ifdef CONFIG_WPS2
	if (!(wps->cred.encr_type &
	      (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) {
		if (wps->cred.encr_type & WPS_ENCR_WEP) {
			wpa_printf(MSG_INFO, "WPS: Reject Credential "
				   "due to WEP configuration");
			return -2;
		}

		wpa_printf(MSG_INFO, "WPS: Reject Credential due to "
			   "invalid encr_type 0x%x", wps->cred.encr_type);
		return -1;
	}
#endif /* CONFIG_WPS2 */

	if (wps->wps->cred_cb) {
		wps->cred.cred_attr = cred - 4;
		wps->cred.cred_attr_len = cred_len + 4;
		wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
		wps->cred.cred_attr = NULL;
		wps->cred.cred_attr_len = 0;
	}

	return 0;
}
예제 #3
0
static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
{
	struct wpabuf msg;
	struct wps_parse_attr attr;
	size_t i;

	if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) {
		wpa_printf(MSG_ERROR, "WPS: OOB credential not found");
		return -1;
	}

	for (i = 0; i < attr.num_cred; i++) {
		struct wps_credential local_cred;
		struct wps_parse_attr cattr;

		os_memset(&local_cred, 0, sizeof(local_cred));
		wpabuf_set(&msg, attr.cred[i], attr.cred_len[i]);
		if (wps_parse_msg(&msg, &cattr) < 0 ||
		    wps_process_cred(&cattr, &local_cred)) {
			wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
				   "credential");
			return -1;
		}
		wps->cred_cb(wps->cb_ctx, &local_cred);
	}

	return 0;
}
예제 #4
0
static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
						 struct eap_peap_data *data,
						 u8 id)
{
	struct wpabuf *buf, *encr_req, msgbuf;
	const u8 *req;
	size_t req_len;

	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");
		return NULL;
	}
	buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
	if (buf == NULL)
		return NULL;

	req = wpabuf_head(buf);
	req_len = wpabuf_len(buf);
	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
			req, req_len);

	if (data->peap_version == 0 &&
	    data->phase2_method->method != EAP_TYPE_TLV) {
		req += sizeof(struct eap_hdr);
		req_len -= sizeof(struct eap_hdr);
	}

	wpabuf_set(&msgbuf, req, req_len);
	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
	wpabuf_free(buf);

	return encr_req;
}
static int wps_validate_cred(const u8 *cred, size_t len)
{
	struct wps_parse_attr attr;
	struct wpabuf buf;

	if (cred == NULL)
		return -1;
	wpabuf_set(&buf, cred, len);
	if (wps_parse_msg(&buf, &attr) < 0) {
		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse Credential");
		return -1;
	}

	if (wps_validate_network_idx(attr.network_idx, 1) ||
	    wps_validate_ssid(attr.ssid, attr.ssid_len, 1) ||
	    wps_validate_auth_type(attr.auth_type, 1) ||
	    wps_validate_encr_type(attr.encr_type, 1) ||
	    wps_validate_network_key_index(attr.network_key_idx, 0) ||
	    wps_validate_network_key(attr.network_key, attr.network_key_len,
				     attr.encr_type, 1) ||
	    wps_validate_mac_addr(attr.mac_addr, 1) ||
	    wps_validate_network_key_shareable(attr.network_key_shareable, 0))
	{
		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Credential");
		return -1;
	}


	return 0;
}
예제 #6
0
struct wpabuf * http_client_get_body(struct http_client *c)
{
	if (c->hread == NULL)
		return NULL;
	wpabuf_set(&c->body, httpread_data_get(c->hread),
		   httpread_length_get(c->hread));
	return &c->body;
}
예제 #7
0
static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
				     const u8 **pos, size_t *left)
{
	unsigned int tls_msg_len = 0;
	const u8 *end = *pos + *left;

	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
		if (*left < 4) {
			wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
				   "length");
			return -1;
		}
		tls_msg_len = WPA_GET_BE32(*pos);
		wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
			   tls_msg_len);
		*pos += 4;
		*left -= 4;
	}

	wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
		   "Message Length %u", flags, tls_msg_len);

	if (data->state == WAIT_FRAG_ACK) {
		if (*left != 0) {
			wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
				   "WAIT_FRAG_ACK state");
			return -1;
		}
		wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
		return 1;
	}

	if (data->tls_in &&
	    eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
		return -1;
		
	if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
		if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
						    *pos, end - *pos) < 0)
			return -1;

		data->state = FRAG_ACK;
		return 1;
	}

	if (data->state == FRAG_ACK) {
		wpa_printf(MSG_DEBUG, "SSL: All fragments received");
		data->state = MSG;
	}

	if (data->tls_in == NULL) {
		/* Wrap unfragmented messages as wpabuf without extra copy */
		wpabuf_set(&data->tmpbuf, *pos, end - *pos);
		data->tls_in = &data->tmpbuf;
	}

	return 0;
}
예제 #8
0
/**
 * eap_tls_process_input - Process incoming TLS message
 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 * @data: Data for TLS processing
 * @in_data: Message received from the server
 * @in_len: Length of in_data
 * @out_data: Buffer for returning a pointer to application data (if available)
 * Returns: 0 on success, 1 if more input data is needed, 2 if application data
 * is available, -1 on failure
 */
static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
				 const u8 *in_data, size_t in_len,
				 struct wpabuf **out_data)
{
	const struct wpabuf *msg;
	int need_more_input;
	struct wpabuf *appl_data;
	struct wpabuf buf;

	wpabuf_set(&buf, in_data, in_len);
	msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input);
	if (msg == NULL)
		return need_more_input ? 1 : -1;

	/* Full TLS message reassembled - continue handshake processing */
	if (data->tls_out) {
		/* This should not happen.. */
		wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending "
			   "tls_out data even though tls_out_len = 0");
		wpabuf_free(data->tls_out);
		WPA_ASSERT(data->tls_out == NULL);
	}
	appl_data = NULL;
	data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn,
						 msg, &appl_data);

	eap_peer_tls_reset_input(data);

	if (appl_data &&
	    tls_connection_established(data->ssl_ctx, data->conn) &&
	    !tls_connection_get_failed(data->ssl_ctx, data->conn)) {
		wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data",
				    appl_data);
		*out_data = appl_data;
		return 2;
	}

	wpabuf_free(appl_data);

	return 0;
}
예제 #9
0
int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
{
	struct wpabuf msg;
	size_t i;

	for (i = 0; i < attr->num_cred; i++) {
		struct wps_credential local_cred;
		struct wps_parse_attr cattr;

		os_memset(&local_cred, 0, sizeof(local_cred));
		wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]);
		if (wps_parse_msg(&msg, &cattr) < 0 ||
		    wps_process_cred(&cattr, &local_cred)) {
			wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
				   "credential");
			return -1;
		}
		wps->cred_cb(wps->cb_ctx, &local_cred);
	}

	return 0;
}
예제 #10
0
static void wps_er_process_wlanevent(struct wps_er_ap *ap,
				     struct wpabuf *event)
{
	u8 *data;
	u8 wlan_event_type;
	u8 wlan_event_mac[ETH_ALEN];
	struct wpabuf msg;

	wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent",
		    wpabuf_head(event), wpabuf_len(event));
	if (wpabuf_len(event) < 1 + 17) {
		wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent");
		return;
	}

	data = wpabuf_mhead(event);
	wlan_event_type = data[0];
	if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) {
		wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in "
			   "WLANEvent");
		return;
	}

	wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17));

	switch (wlan_event_type) {
	case 1:
		wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg);
		break;
	case 2:
		wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg);
		break;
	default:
		wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d",
			   wlan_event_type);
		break;
	}
}
static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
                  size_t cred_len)
{
    struct wps_parse_attr attr;
    struct wpabuf msg;

    wpa_printf(MSG_DEBUG, "WPS: Received Credential");
    os_memset(&wps->cred, 0, sizeof(wps->cred));
    wpabuf_set(&msg, cred, cred_len);
    if (wps_parse_msg(&msg, &attr) < 0 ||
        wps_process_cred(&attr, &wps->cred))
        return -1;

    if (wps->wps->cred_cb) {
        wps->cred.cred_attr = cred - 4;
        wps->cred.cred_attr_len = cred_len + 4;
        wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
        wps->cred.cred_attr = NULL;
        wps->cred.cred_attr_len = 0;
    }

    return 0;
}
예제 #12
0
static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
						 struct eap_peap_data *data,
						 u8 id)
{
	struct wpabuf *buf1, *buf, *encr_req, msgbuf;
	const u8 *req;
	size_t req_len;

	buf1 = tncs_build_soh_request();
	if (buf1 == NULL)
		return NULL;

	buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
			    EAP_CODE_REQUEST, id);
	if (buf == NULL) {
		wpabuf_free(buf1);
		return NULL;
	}
	wpabuf_put_buf(buf, buf1);
	wpabuf_free(buf1);

	req = wpabuf_head(buf);
	req_len = wpabuf_len(buf);

	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
			req, req_len);

	req += sizeof(struct eap_hdr);
	req_len -= sizeof(struct eap_hdr);
	wpabuf_set(&msgbuf, req, req_len);

	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
	wpabuf_free(buf);

	return encr_req;
}
예제 #13
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;
}
예제 #14
0
static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
					struct eap_method_ret *ret,
					const struct wpabuf *reqData)
{
	const struct eap_hdr *req;
	size_t left;
	int res;
	u8 flags, id;
	struct wpabuf *resp;
	const u8 *pos;
	struct eap_peap_data *data = priv;

	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
					reqData, &left, &flags);
	if (pos == NULL)
		return NULL;
	req = wpabuf_head(reqData);
	id = req->identifier;

	if (flags & EAP_TLS_FLAGS_START) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
			   "ver=%d)", flags & EAP_TLS_VERSION_MASK,
			data->peap_version);
		if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version)
			data->peap_version = flags & EAP_TLS_VERSION_MASK;
		if (data->force_peap_version >= 0 &&
		    data->force_peap_version != data->peap_version) {
			wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
				   "forced PEAP version %d",
				   data->force_peap_version);
			ret->methodState = METHOD_DONE;
			ret->decision = DECISION_FAIL;
			ret->allowNotifications = FALSE;
			return NULL;
		}
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
			   data->peap_version);
		left = 0; /* make sure that this frame is empty, even though it
			   * should always be, anyway */
	}

	resp = NULL;
	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
	    !data->resuming) {
		struct wpabuf msg;
		wpabuf_set(&msg, pos, left);
		res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
	} else {
		res = eap_peer_tls_process_helper(sm, &data->ssl,
						  EAP_TYPE_PEAP,
						  data->peap_version, id, pos,
						  left, &resp);

		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
			char *label;
			wpa_printf(MSG_DEBUG,
				   "EAP-PEAP: TLS done, proceed to Phase 2");
			os_free(data->key_data);
			/* draft-josefsson-ppext-eap-tls-eap-05.txt
			 * specifies that PEAPv1 would use "client PEAP
			 * encryption" as the label. However, most existing
			 * PEAPv1 implementations seem to be using the old
			 * label, "client EAP encryption", instead. Use the old
			 * label by default, but allow it to be configured with
			 * phase1 parameter peaplabel=1. */
			if (data->peap_version > 1 || data->force_new_label)
				label = "client PEAP encryption";
			else
				label = "client EAP encryption";
			wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
				   "key derivation", label);
			data->key_data =
				eap_peer_tls_derive_key(sm, &data->ssl, label,
							EAP_TLS_KEY_LEN);
			if (data->key_data) {
				wpa_hexdump_key(MSG_DEBUG, 
						"EAP-PEAP: Derived key",
						data->key_data,
						EAP_TLS_KEY_LEN);
			} else {
				wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
					   "derive key");
			}

			if (sm->workaround && data->resuming) {
				/*
				 * At least few RADIUS servers (Aegis v1.1.6;
				 * but not v1.1.4; and Cisco ACS) seem to be
				 * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
				 * ACS) session resumption with outer
				 * EAP-Success. This does not seem to follow
				 * draft-josefsson-pppext-eap-tls-eap-05.txt
				 * section 4.2, so only allow this if EAP
				 * workarounds are enabled.
				 */
				wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
					   "allow outer EAP-Success to "
					   "terminate PEAP resumption");
				ret->decision = DECISION_COND_SUCC;
				data->phase2_success = 1;
			}

			data->resuming = 0;
		}

		if (res == 2) {
			struct wpabuf msg;
			/*
			 * Application data included in the handshake message.
			 */
			wpabuf_free(data->pending_phase2_req);
			data->pending_phase2_req = resp;
			resp = NULL;
			wpabuf_set(&msg, pos, left);
			res = eap_peap_decrypt(sm, data, ret, req, &msg,
					       &resp);
		}
	}

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

	if (res == 1) {
		wpabuf_free(resp);
		return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
					      data->peap_version);
	}

	return resp;
}
예제 #15
0
static void eap_tnc_process(struct eap_sm *sm, void *priv,
			    struct wpabuf *respData)
{
	struct eap_tnc_data *data = priv;
	const u8 *pos, *end;
	size_t len;
	u8 flags;
	u32 message_length = 0;
	struct wpabuf tmpbuf;

	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len);
	if (pos == NULL)
		return; /* Should not happen; message already verified */

	end = pos + len;

	if (len == 1 && (data->state == DONE || data->state == FAIL)) {
		wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last "
			   "message");
		return;
	}

	if (len == 0) {
		/* fragment ack */
		flags = 0;
	} else
		flags = *pos++;

	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
		if (end - pos < 4) {
			wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
			eap_tnc_set_state(data, FAIL);
			return;
		}
		message_length = WPA_GET_BE32(pos);
		pos += 4;

		if (message_length < (u32) (end - pos) ||
		    message_length > 75000) {
			wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
				   "Length (%d; %ld remaining in this msg)",
				   message_length, (long) (end - pos));
			eap_tnc_set_state(data, FAIL);
			return;
		}
	}
	wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
		   "Message Length %u", flags, message_length);

	if (data->state == WAIT_FRAG_ACK) {
		if (len > 1) {
			wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload "
				   "in WAIT_FRAG_ACK state");
			eap_tnc_set_state(data, FAIL);
			return;
		}
		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
		eap_tnc_set_state(data, CONTINUE);
		return;
	}

	if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
		eap_tnc_set_state(data, FAIL);
		return;
	}
		
	if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
		if (eap_tnc_process_fragment(data, flags, message_length,
					     pos, end - pos) < 0)
			eap_tnc_set_state(data, FAIL);
		else
			eap_tnc_set_state(data, FRAG_ACK);
		return;
	} else if (data->state == FRAG_ACK) {
		wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
		eap_tnc_set_state(data, CONTINUE);
	}

	if (data->in_buf == NULL) {
		/* Wrap unfragmented messages as wpabuf without extra copy */
		wpabuf_set(&tmpbuf, pos, end - pos);
		data->in_buf = &tmpbuf;
	}

	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload",
			  wpabuf_head(data->in_buf), wpabuf_len(data->in_buf));
	tncs_process(data, data->in_buf);

	if (data->in_buf != &tmpbuf)
		wpabuf_free(data->in_buf);
	data->in_buf = NULL;
}
예제 #16
0
static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
					struct eap_method_ret *ret,
					const struct wpabuf *reqData)
{
	const struct eap_hdr *req;
	size_t left;
	int res;
	u8 flags, id;
	struct wpabuf *resp;
	const u8 *pos;
	struct eap_fast_data *data = priv;

	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_FAST, ret,
					reqData, &left, &flags);
	if (pos == NULL)
		return NULL;

	req = wpabuf_head(reqData);
	id = req->identifier;

	if (flags & EAP_TLS_FLAGS_START) {
		if (eap_fast_process_start(sm, data, flags, pos, left) < 0)
			return NULL;

		left = 0; /* A-ID is not used in further packet processing */
	}

	resp = NULL;
	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
	    !data->resuming) {
		/* Process tunneled (encrypted) phase 2 data. */
		struct wpabuf msg;
		wpabuf_set(&msg, pos, left);
		res = eap_fast_decrypt(sm, data, ret, req, &msg, &resp);
		if (res < 0) {
			ret->methodState = METHOD_DONE;
			ret->decision = DECISION_FAIL;
			/*
			 * Ack possible Alert that may have caused failure in
			 * decryption.
			 */
			res = 1;
		}
	} else {
		/* Continue processing TLS handshake (phase 1). */
		res = eap_peer_tls_process_helper(sm, &data->ssl,
						  EAP_TYPE_FAST,
						  data->fast_version, id, pos,
						  left, &resp);

		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
			char cipher[80];
			wpa_printf(MSG_DEBUG,
				   "EAP-FAST: TLS done, proceed to Phase 2");
			if (data->provisioning &&
			    (!(data->provisioning_allowed &
			       EAP_FAST_PROV_AUTH) ||
			     tls_get_cipher(sm->ssl_ctx, data->ssl.conn,
					    cipher, sizeof(cipher)) < 0 ||
			     os_strstr(cipher, "ADH-") ||
			     os_strstr(cipher, "anon"))) {
				wpa_printf(MSG_DEBUG, "EAP-FAST: Using "
					   "anonymous (unauthenticated) "
					   "provisioning");
				data->anon_provisioning = 1;
			} else
				data->anon_provisioning = 0;
			data->resuming = 0;
			eap_fast_derive_keys(sm, data);
		}

		if (res == 2) {
			struct wpabuf msg;
			/*
			 * Application data included in the handshake message.
			 */
			wpabuf_free(data->pending_phase2_req);
			data->pending_phase2_req = resp;
			resp = NULL;
			wpabuf_set(&msg, pos, left);
			res = eap_fast_decrypt(sm, data, ret, req, &msg,
					       &resp);
		}
	}

	if (res == 1) {
		wpabuf_free(resp);
		return eap_peer_tls_build_ack(id, EAP_TYPE_FAST,
					      data->fast_version);
	}

	return resp;
}
예제 #17
0
static void eap_wsc_process(struct eap_sm *sm, void *priv,
			    struct wpabuf *respData)
{
	struct eap_wsc_data *data = priv;
	const u8 *start, *pos, *end;
	size_t len;
	u8 op_code, flags;
	u16 message_length = 0;
	enum wps_process_res res;
	struct wpabuf tmpbuf;

	eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
	if (data->ext_reg_timeout) {
		eap_wsc_state(data, FAIL);
		return;
	}

	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
			       respData, &len);
	if (pos == NULL || len < 2)
		return; /* Should not happen; message already verified */

	start = pos;
	end = start + len;

	op_code = *pos++;
	flags = *pos++;
	if (flags & WSC_FLAGS_LF) {
		if (end - pos < 2) {
			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
			return;
		}
		message_length = WPA_GET_BE16(pos);
		pos += 2;

		if (message_length < end - pos) {
			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
				   "Length");
			return;
		}
	}

	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
		   "Flags 0x%x Message Length %d",
		   op_code, flags, message_length);

	if (data->state == WAIT_FRAG_ACK) {
		if (op_code != WSC_FRAG_ACK) {
			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
				   "in WAIT_FRAG_ACK state", op_code);
			eap_wsc_state(data, FAIL);
			return;
		}
		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
		eap_wsc_state(data, MESG);
		return;
	}

	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
	    op_code != WSC_Done) {
		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
			   op_code);
		eap_wsc_state(data, FAIL);
		return;
	}

	if (data->in_buf &&
	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
		eap_wsc_state(data, FAIL);
		return;
	}

	if (flags & WSC_FLAGS_MF) {
		if (eap_wsc_process_fragment(data, flags, op_code,
					     message_length, pos, end - pos) <
		    0)
			eap_wsc_state(data, FAIL);
		else
			eap_wsc_state(data, FRAG_ACK);
		return;
	}

	if (data->in_buf == NULL) {
		/* Wrap unfragmented messages as wpabuf without extra copy */
		wpabuf_set(&tmpbuf, pos, end - pos);
		data->in_buf = &tmpbuf;
	}

	res = wps_process_msg(data->wps, op_code, data->in_buf);
	switch (res) {
	case WPS_DONE:
		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
			   "successfully - report EAP failure");
		eap_wsc_state(data, FAIL);
		break;
	case WPS_CONTINUE:
		eap_wsc_state(data, MESG);
		break;
	case WPS_FAILURE:
		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
		eap_wsc_state(data, FAIL);
		break;
	case WPS_PENDING:
		eap_wsc_state(data, MESG);
		sm->method_pending = METHOD_PENDING_WAIT;
		eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
		eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
				       sm, data);
		break;
	}

	if (data->in_buf != &tmpbuf)
		wpabuf_free(data->in_buf);
	data->in_buf = NULL;
}
static void eap_ikev2_process(struct eap_sm *sm, void *priv,
			      struct wpabuf *respData)
{
	struct eap_ikev2_data *data = priv;
	const u8 *start, *pos, *end;
	size_t len;
	u8 flags;
	u32 message_length = 0;
	struct wpabuf tmpbuf;

	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData,
			       &len);
	if (pos == NULL)
		return; /* Should not happen; message already verified */

	start = pos;
	end = start + len;

	if (len == 0) {
		/* fragment ack */
		flags = 0;
	} else
		flags = *pos++;

	if (eap_ikev2_process_icv(data, respData, flags, pos, &end,
				  data->state == WAIT_FRAG_ACK && len == 0) < 0)
	{
		eap_ikev2_state(data, FAIL);
		return;
	}

	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
		if (end - pos < 4) {
			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
			eap_ikev2_state(data, FAIL);
			return;
		}
		message_length = WPA_GET_BE32(pos);
		pos += 4;

		if (message_length < (u32) (end - pos)) {
			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
				   "Length (%d; %ld remaining in this msg)",
				   message_length, (long) (end - pos));
			eap_ikev2_state(data, FAIL);
			return;
		}
	}
	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
		   "Message Length %u", flags, message_length);

	if (data->state == WAIT_FRAG_ACK) {
		if (len != 0) {
			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
				   "in WAIT_FRAG_ACK state");
			eap_ikev2_state(data, FAIL);
			return;
		}
		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
		eap_ikev2_state(data, MSG);
		return;
	}

	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
		eap_ikev2_state(data, FAIL);
		return;
	}
		
	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
		if (eap_ikev2_process_fragment(data, flags, message_length,
					       pos, end - pos) < 0)
			eap_ikev2_state(data, FAIL);
		else
			eap_ikev2_state(data, FRAG_ACK);
		return;
	} else if (data->state == FRAG_ACK) {
		wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
		data->state = MSG;
	}

	if (data->in_buf == NULL) {
		/* Wrap unfragmented messages as wpabuf without extra copy */
		wpabuf_set(&tmpbuf, pos, end - pos);
		data->in_buf = &tmpbuf;
	}

	if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) {
		if (data->in_buf == &tmpbuf)
			data->in_buf = NULL;
		eap_ikev2_state(data, FAIL);
		return;
	}

	switch (data->ikev2.state) {
	case SA_AUTH:
		/* SA_INIT was sent out, so message have to be
		 * integrity protected from now on. */
		data->keys_ready = 1;
		break;
	case IKEV2_DONE:
		if (data->state == FAIL)
			break;
		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed "
			   "successfully");
		if (eap_ikev2_server_keymat(data))
			break;
		eap_ikev2_state(data, DONE);
		break;
	default:
		break;
	}

	if (data->in_buf != &tmpbuf)
		wpabuf_free(data->in_buf);
	data->in_buf = NULL;
}
예제 #19
0
static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
				       struct eap_method_ret *ret,
				       const struct wpabuf *reqData)
{
	struct eap_tnc_data *data = priv;
	struct wpabuf *resp;
	const u8 *pos, *end;
	u8 *rpos, *rpos1;
	size_t len, rlen;
	size_t imc_len;
	char *start_buf, *end_buf;
	size_t start_len, end_len;
	int tncs_done = 0;
	u8 flags, id;
	u32 message_length = 0;
	struct wpabuf tmpbuf;

	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len);
	if (pos == NULL) {
		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
			   pos, (unsigned long) len);
		ret->ignore = TRUE;
		return NULL;
	}

	id = eap_get_id(reqData);

	end = pos + len;

	if (len == 0)
		flags = 0; /* fragment ack */
	else
		flags = *pos++;

	if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
		wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
			   flags & EAP_TNC_VERSION_MASK);
		ret->ignore = TRUE;
		return NULL;
	}

	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
		if (end - pos < 4) {
			wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
			ret->ignore = TRUE;
			return NULL;
		}
		message_length = WPA_GET_BE32(pos);
		pos += 4;

		if (message_length < (u32) (end - pos)) {
			wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
				   "Length (%d; %ld remaining in this msg)",
				   message_length, (long) (end - pos));
			ret->ignore = TRUE;
			return NULL;
		}
	}

	wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
		   "Message Length %u", flags, message_length);

	if (data->state == WAIT_FRAG_ACK) {
		if (len > 1) {
			wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
				   "WAIT_FRAG_ACK state");
			ret->ignore = TRUE;
			return NULL;
		}
		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
		data->state = PROC_MSG;
		return eap_tnc_build_msg(data, ret, id);
	}

	if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
		ret->ignore = TRUE;
		return NULL;
	}
		
	if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
		return eap_tnc_process_fragment(data, ret, id, flags,
						message_length, pos,
						end - pos);
	}

	if (data->in_buf == NULL) {
		/* Wrap unfragmented messages as wpabuf without extra copy */
		wpabuf_set(&tmpbuf, pos, end - pos);
		data->in_buf = &tmpbuf;
	}

	if (data->state == WAIT_START) {
		if (!(flags & EAP_TNC_FLAGS_START)) {
			wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
				   "start flag in the first message");
			ret->ignore = TRUE;
			goto fail;
		}

		tncc_init_connection(data->tncc);

		data->state = PROC_MSG;
	} else {
		enum tncc_process_res res;

		if (flags & EAP_TNC_FLAGS_START) {
			wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
				   "flag again");
			ret->ignore = TRUE;
			goto fail;
		}

		res = tncc_process_if_tnccs(data->tncc,
					    wpabuf_head(data->in_buf),
					    wpabuf_len(data->in_buf));
		switch (res) {
		case TNCCS_PROCESS_ERROR:
			ret->ignore = TRUE;
			goto fail;
		case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
		case TNCCS_RECOMMENDATION_ERROR:
			wpa_printf(MSG_DEBUG, "EAP-TNC: No "
				   "TNCCS-Recommendation received");
			break;
		case TNCCS_RECOMMENDATION_ALLOW:
			wpa_msg(sm->msg_ctx, MSG_INFO,
				"TNC: Recommendation = allow");
			tncs_done = 1;
			break;
		case TNCCS_RECOMMENDATION_NONE:
			wpa_msg(sm->msg_ctx, MSG_INFO,
				"TNC: Recommendation = none");
			tncs_done = 1;
			break;
		case TNCCS_RECOMMENDATION_ISOLATE:
			wpa_msg(sm->msg_ctx, MSG_INFO,
				"TNC: Recommendation = isolate");
			tncs_done = 1;
			break;
		}
	}

	if (data->in_buf != &tmpbuf)
		wpabuf_free(data->in_buf);
	data->in_buf = NULL;

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

	if (data->out_buf) {
		data->state = PROC_MSG;
		return eap_tnc_build_msg(data, ret, id);
	}

	if (tncs_done) {
		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
				     EAP_CODE_RESPONSE, eap_get_id(reqData));
		if (resp == NULL)
			return NULL;

		wpabuf_put_u8(resp, EAP_TNC_VERSION);
		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an "
			   "empty ACK message");
		return resp;
	}

	imc_len = tncc_total_send_len(data->tncc);

	start_buf = tncc_if_tnccs_start(data->tncc);
	if (start_buf == NULL)
		return NULL;
	start_len = os_strlen(start_buf);
	end_buf = tncc_if_tnccs_end();
	if (end_buf == NULL) {
		os_free(start_buf);
		return NULL;
	}
	end_len = os_strlen(end_buf);

	rlen = start_len + imc_len + end_len;
	resp = wpabuf_alloc(rlen);
	if (resp == NULL) {
		os_free(start_buf);
		os_free(end_buf);
		return NULL;
	}

	wpabuf_put_data(resp, start_buf, start_len);
	os_free(start_buf);

	rpos1 = wpabuf_put(resp, 0);
	rpos = tncc_copy_send_buf(data->tncc, rpos1);
	wpabuf_put(resp, rpos - rpos1);

	wpabuf_put_data(resp, end_buf, end_len);
	os_free(end_buf);

	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response",
			  wpabuf_head(resp), wpabuf_len(resp));

	data->out_buf = resp;
	data->state = PROC_MSG;
	return eap_tnc_build_msg(data, ret, id);

fail:
	if (data->in_buf == &tmpbuf)
		data->in_buf = NULL;
	return NULL;
}
예제 #20
0
static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
					 struct eap_method_ret *ret,
					 const struct wpabuf *reqData)
{
	struct eap_ikev2_data *data = priv;
	const u8 *start, *pos, *end;
	size_t len;
	u8 flags, id;
	u32 message_length = 0;
	struct wpabuf tmpbuf;

	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len);
	if (pos == NULL) {
		ret->ignore = TRUE;
		return NULL;
	}

	id = eap_get_id(reqData);

	start = pos;
	end = start + len;

	if (len == 0)
		flags = 0; /* fragment ack */
	else
		flags = *pos++;

	if (eap_ikev2_process_icv(data, reqData, flags, pos, &end) < 0) {
		ret->ignore = TRUE;
		return NULL;
	}

	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
		if (end - pos < 4) {
			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
			ret->ignore = TRUE;
			return NULL;
		}
		message_length = WPA_GET_BE32(pos);
		pos += 4;

		if (message_length < (u32) (end - pos)) {
			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
				   "Length (%d; %ld remaining in this msg)",
				   message_length, (long) (end - pos));
			ret->ignore = TRUE;
			return NULL;
		}
	}

	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
		   "Message Length %u", flags, message_length);

	if (data->state == WAIT_FRAG_ACK) {
#ifdef CCNS_PL
		if (len > 1) /* Empty Flags field included in ACK */
#else /* CCNS_PL */
		if (len != 0)
#endif /* CCNS_PL */
		{
			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
				   "in WAIT_FRAG_ACK state");
			ret->ignore = TRUE;
			return NULL;
		}
		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
		eap_ikev2_state(data, PROC_MSG);
		return eap_ikev2_build_msg(data, ret, id);
	}

	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
		ret->ignore = TRUE;
		return NULL;
	}
		
	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
		return eap_ikev2_process_fragment(data, ret, id, flags,
						  message_length, pos,
						  end - pos);
	}

	if (data->in_buf == NULL) {
		/* Wrap unfragmented messages as wpabuf without extra copy */
		wpabuf_set(&tmpbuf, pos, end - pos);
		data->in_buf = &tmpbuf;
	}

	if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) {
		if (data->in_buf == &tmpbuf)
			data->in_buf = NULL;
		eap_ikev2_state(data, FAIL);
		return NULL;
	}

	if (data->in_buf != &tmpbuf)
		wpabuf_free(data->in_buf);
	data->in_buf = NULL;

	if (data->out_buf == NULL) {
		data->out_buf = ikev2_responder_build(&data->ikev2);
		if (data->out_buf == NULL) {
			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate "
				   "IKEv2 message");
			return NULL;
		}
		data->out_used = 0;
	}

	eap_ikev2_state(data, PROC_MSG);
	return eap_ikev2_build_msg(data, ret, id);
}
예제 #21
0
static void eap_fast_process_phase2_response(struct eap_sm *sm,
					     struct eap_fast_data *data,
					     u8 *in_data, size_t in_len)
{
	u8 next_type = EAP_TYPE_NONE;
	struct eap_hdr *hdr;
	u8 *pos;
	size_t left;
	struct wpabuf buf;
	const struct eap_method *m = data->phase2_method;
	void *priv = data->phase2_priv;

	if (priv == NULL) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - Phase2 not "
			   "initialized?!", __func__);
		return;
	}

	hdr = (struct eap_hdr *) in_data;
	pos = (u8 *) (hdr + 1);

	if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
		left = in_len - sizeof(*hdr);
		wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; "
			    "allowed types", pos + 1, left - 1);
#ifdef EAP_SERVER_TNC
		if (m && m->vendor == EAP_VENDOR_IETF &&
		    m->method == EAP_TYPE_TNC) {
			wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required "
				   "TNC negotiation");
			next_type = eap_fast_req_failure(sm, data);
			eap_fast_phase2_init(sm, data, next_type);
			return;
		}
#endif /* EAP_SERVER_TNC */
		eap_sm_process_nak(sm, pos + 1, left - 1);
		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
		    sm->user->methods[sm->user_eap_method_index].method !=
		    EAP_TYPE_NONE) {
			next_type = sm->user->methods[
				sm->user_eap_method_index++].method;
			wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d",
				   next_type);
		} else {
			next_type = eap_fast_req_failure(sm, data);
		}
		eap_fast_phase2_init(sm, data, next_type);
		return;
	}

	wpabuf_set(&buf, in_data, in_len);

	if (m->check(sm, priv, &buf)) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to "
			   "ignore the packet");
		eap_fast_req_failure(sm, data);
		return;
	}

	m->process(sm, priv, &buf);

	if (!m->isDone(sm, priv))
		return;

	if (!m->isSuccess(sm, priv)) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed");
		next_type = eap_fast_req_failure(sm, data);
		eap_fast_phase2_init(sm, data, next_type);
		return;
	}

	switch (data->state) {
	case PHASE2_ID:
		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
			wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Phase2 "
					  "Identity not found in the user "
					  "database",
					  sm->identity, sm->identity_len);
			next_type = eap_fast_req_failure(sm, data);
			break;
		}

		eap_fast_state(data, PHASE2_METHOD);
		if (data->anon_provisioning) {
			/*
			 * Only EAP-MSCHAPv2 is allowed for anonymous
			 * provisioning.
			 */
			next_type = EAP_TYPE_MSCHAPV2;
			sm->user_eap_method_index = 0;
		} else {
			next_type = sm->user->methods[0].method;
			sm->user_eap_method_index = 1;
		}
		wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
		break;
	case PHASE2_METHOD:
	case CRYPTO_BINDING:
		eap_fast_update_icmk(sm, data);
		eap_fast_state(data, CRYPTO_BINDING);
		data->eap_seq++;
		next_type = EAP_TYPE_NONE;
#ifdef EAP_SERVER_TNC
		if (sm->tnc && !data->tnc_started) {
			wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC");
			next_type = EAP_TYPE_TNC;
			data->tnc_started = 1;
		}
#endif /* EAP_SERVER_TNC */
		break;
	case FAILURE:
		break;
	default:
		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d",
			   __func__, data->state);
		break;
	}

	eap_fast_phase2_init(sm, data, next_type);
}
예제 #22
0
파일: eap_wsc.c 프로젝트: 2asoft/freebsd
static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
				       struct eap_method_ret *ret,
				       const struct wpabuf *reqData)
{
	struct eap_wsc_data *data = priv;
	const u8 *start, *pos, *end;
	size_t len;
	u8 op_code, flags, id;
	u16 message_length = 0;
	enum wps_process_res res;
	struct wpabuf tmpbuf;
	struct wpabuf *r;

	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData,
			       &len);
	if (pos == NULL || len < 2) {
		ret->ignore = TRUE;
		return NULL;
	}

	id = eap_get_id(reqData);

	start = pos;
	end = start + len;

	op_code = *pos++;
	flags = *pos++;
	if (flags & WSC_FLAGS_LF) {
		if (end - pos < 2) {
			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
			ret->ignore = TRUE;
			return NULL;
		}
		message_length = WPA_GET_BE16(pos);
		pos += 2;

		if (message_length < end - pos || message_length > 50000) {
			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
				   "Length");
			ret->ignore = TRUE;
			return NULL;
		}
	}

	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
		   "Flags 0x%x Message Length %d",
		   op_code, flags, message_length);

	if (data->state == WAIT_FRAG_ACK) {
		if (op_code != WSC_FRAG_ACK) {
			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
				   "in WAIT_FRAG_ACK state", op_code);
			ret->ignore = TRUE;
			return NULL;
		}
		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
		eap_wsc_state(data, MESG);
		return eap_wsc_build_msg(data, ret, id);
	}

	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
	    op_code != WSC_Done && op_code != WSC_Start) {
		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
			   op_code);
		ret->ignore = TRUE;
		return NULL;
	}

	if (data->state == WAIT_START) {
		if (op_code != WSC_Start) {
			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
				   "in WAIT_START state", op_code);
			ret->ignore = TRUE;
			return NULL;
		}
		wpa_printf(MSG_DEBUG, "EAP-WSC: Received start");
		eap_wsc_state(data, MESG);
		/* Start message has empty payload, skip processing */
		goto send_msg;
	} else if (op_code == WSC_Start) {
		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
			   op_code);
		ret->ignore = TRUE;
		return NULL;
	}

	if (data->in_buf &&
	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
		ret->ignore = TRUE;
		return NULL;
	}

	if (flags & WSC_FLAGS_MF) {
		return eap_wsc_process_fragment(data, ret, id, flags, op_code,
						message_length, pos,
						end - pos);
	}

	if (data->in_buf == NULL) {
		/* Wrap unfragmented messages as wpabuf without extra copy */
		wpabuf_set(&tmpbuf, pos, end - pos);
		data->in_buf = &tmpbuf;
	}

	res = wps_process_msg(data->wps, op_code, data->in_buf);
	switch (res) {
	case WPS_DONE:
		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
			   "successfully - wait for EAP failure");
		eap_wsc_state(data, FAIL);
		break;
	case WPS_CONTINUE:
		eap_wsc_state(data, MESG);
		break;
	case WPS_FAILURE:
	case WPS_PENDING:
		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
		eap_wsc_state(data, FAIL);
		break;
	}

	if (data->in_buf != &tmpbuf)
		wpabuf_free(data->in_buf);
	data->in_buf = NULL;

send_msg:
	if (data->out_buf == NULL) {
		data->out_buf = wps_get_msg(data->wps, &data->out_op_code);
		if (data->out_buf == NULL) {
			wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive "
				   "message from WPS");
			eap_wsc_state(data, FAIL);
			ret->methodState = METHOD_DONE;
			ret->decision = DECISION_FAIL;
			return NULL;
		}
		data->out_used = 0;
	}

	eap_wsc_state(data, MESG);
	r = eap_wsc_build_msg(data, ret, id);
	if (data->state == FAIL && ret->methodState == METHOD_DONE) {
		/* Use reduced client timeout for WPS to avoid long wait */
		if (sm->ClientTimeout > 2)
			sm->ClientTimeout = 2;
	}
	return r;
}
예제 #23
0
static int eap_fast_phase2_request(struct eap_sm *sm,
				   struct eap_fast_data *data,
				   struct eap_method_ret *ret,
				   struct eap_hdr *hdr,
				   struct wpabuf **resp)
{
	size_t len = be_to_host16(hdr->length);
	u8 *pos;
	struct eap_method_ret iret;
	struct eap_peer_config *config = eap_get_config(sm);
	struct wpabuf msg;

	if (len <= sizeof(struct eap_hdr)) {
		wpa_printf(MSG_INFO, "EAP-FAST: too short "
			   "Phase 2 request (len=%lu)", (unsigned long) len);
		return -1;
	}
	pos = (u8 *) (hdr + 1);
	wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
	if (*pos == EAP_TYPE_IDENTITY) {
		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
		return 0;
	}

	if (data->phase2_priv && data->phase2_method &&
	    *pos != data->phase2_type.method) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
			   "deinitialize previous method");
		data->phase2_method->deinit(sm, data->phase2_priv);
		data->phase2_method = NULL;
		data->phase2_priv = NULL;
		data->phase2_type.vendor = EAP_VENDOR_IETF;
		data->phase2_type.method = EAP_TYPE_NONE;
	}

	if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
	    data->phase2_type.method == EAP_TYPE_NONE &&
	    eap_fast_select_phase2_method(data, *pos) < 0) {
		if (eap_peer_tls_phase2_nak(data->phase2_types,
					    data->num_phase2_types,
					    hdr, resp))
			return -1;
		return 0;
	}

	if (data->phase2_priv == NULL &&
	    eap_fast_init_phase2_method(sm, data) < 0) {
		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
			   "Phase 2 EAP method %d", *pos);
		ret->methodState = METHOD_DONE;
		ret->decision = DECISION_FAIL;
		return -1;
	}

	os_memset(&iret, 0, sizeof(iret));
	wpabuf_set(&msg, hdr, len);
	*resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
					     &msg);
	if (*resp == NULL ||
	    (iret.methodState == METHOD_DONE &&
	     iret.decision == DECISION_FAIL)) {
		ret->methodState = METHOD_DONE;
		ret->decision = DECISION_FAIL;
	} else if ((iret.methodState == METHOD_DONE ||
		    iret.methodState == METHOD_MAY_CONT) &&
		   (iret.decision == DECISION_UNCOND_SUCC ||
		    iret.decision == DECISION_COND_SUCC)) {
		data->phase2_success = 1;
	}

	if (*resp == NULL && config &&
	    (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);
	} else if (*resp == NULL)
		return -1;

	return 0;
}