예제 #1
0
static int eap_peapv2_start_phase2(struct eap_sm *sm,
				   struct eap_peap_data *data)
{
	struct wpabuf *buf, *buf2;
	int res;

	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
		   "payload in the same message");
	eap_peap_state(data, PHASE1_ID2);
	if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY))
		return -1;

	/* TODO: which Id to use here? */
	buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6);
	if (buf == NULL)
		return -1;

	buf2 = eap_peapv2_tlv_eap_payload(buf);
	if (buf2 == NULL)
		return -1;

	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2);

	buf = wpabuf_alloc(data->ssl.tls_out_limit);
	if (buf == NULL) {
		wpabuf_free(buf2);
		return -1;
	}

	res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
				     wpabuf_head(buf2), wpabuf_len(buf2),
				     wpabuf_put(buf, 0),
				     data->ssl.tls_out_limit);
	wpabuf_free(buf2);

	if (res < 0) {
		wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 "
			   "data");
		wpabuf_free(buf);
		return -1;
	}

	wpabuf_put(buf, res);
	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request",
			buf);

	/* Append TLS data into the pending buffer after the Server Finished */
	if (wpabuf_resize(&data->ssl.out_buf, wpabuf_len(buf)) < 0) {
		wpabuf_free(buf);
		return -1;
	}
	wpabuf_put_buf(data->ssl.out_buf, buf);
	wpabuf_free(buf);

	return 0;
}
예제 #2
0
static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
				 const struct wpabuf *respData)
{
	struct eap_peap_data *data = priv;

	switch (data->state) {
	case PHASE1:
		if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
			eap_peap_state(data, FAILURE);
			break;
		}

		if (data->peap_version >= 2 &&
		    tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
			if (eap_peapv2_start_phase2(sm, data)) {
				eap_peap_state(data, FAILURE);
				break;
			}
		}
		break;
	case PHASE2_START:
		eap_peap_state(data, PHASE2_ID);
		eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
		break;
	case PHASE1_ID2:
	case PHASE2_ID:
	case PHASE2_METHOD:
	case PHASE2_SOH:
	case PHASE2_TLV:
		eap_peap_process_phase2(sm, data, respData, data->ssl.in_buf);
		break;
	case SUCCESS_REQ:
		eap_peap_state(data, SUCCESS);
		break;
	case FAILURE_REQ:
		eap_peap_state(data, FAILURE);
		break;
	default:
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
			   data->state, __func__);
		break;
	}
}
예제 #3
0
static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
				 const struct wpabuf *respData)
{
	struct eap_peap_data *data = priv;

	switch (data->state) {
	case PHASE1:
		if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
			eap_peap_state(data, FAILURE);
			break;
		}
		break;
	case PHASE2_START:
		eap_peap_state(data, PHASE2_ID);
		eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
				     EAP_TYPE_IDENTITY);
		break;
	case PHASE1_ID2:
	case PHASE2_ID:
	case PHASE2_METHOD:
	case PHASE2_SOH:
	case PHASE2_TLV:
		eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in);
		break;
	case SUCCESS_REQ:
		eap_peap_state(data, SUCCESS);
		break;
	case FAILURE_REQ:
		eap_peap_state(data, FAILURE);
		break;
	default:
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
			   data->state, __func__);
		break;
	}
}
예제 #4
0
static void eap_peap_process_phase2_response(struct eap_sm *sm,
					     struct eap_peap_data *data,
					     struct wpabuf *in_data)
{
	int next_vendor = EAP_VENDOR_IETF;
	u32 next_type = EAP_TYPE_NONE;
	const struct eap_hdr *hdr;
	const u8 *pos;
	size_t left;

	if (data->state == PHASE2_TLV) {
		eap_peap_process_phase2_tlv(sm, data, in_data);
		return;
	}

#ifdef EAP_SERVER_TNC
	if (data->state == PHASE2_SOH) {
		eap_peap_process_phase2_soh(sm, data, in_data);
		return;
	}
#endif /* EAP_SERVER_TNC */

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

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

	if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
		left = wpabuf_len(in_data) - sizeof(*hdr);
		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
			    "allowed types", pos + 1, left - 1);
		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].vendor !=
		     EAP_VENDOR_IETF ||
		     sm->user->methods[sm->user_eap_method_index].method !=
		     EAP_TYPE_NONE)) {
			next_vendor = sm->user->methods[
				sm->user_eap_method_index].vendor;
			next_type = sm->user->methods[
				sm->user_eap_method_index++].method;
			wpa_printf(MSG_DEBUG,
				   "EAP-PEAP: try EAP vendor %d type 0x%x",
				   next_vendor, next_type);
		} else {
			eap_peap_req_failure(sm, data);
			next_vendor = EAP_VENDOR_IETF;
			next_type = EAP_TYPE_NONE;
		}
		eap_peap_phase2_init(sm, data, next_vendor, next_type);
		return;
	}

	if (data->phase2_method->check(sm, data->phase2_priv, in_data)) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
			   "ignore the packet");
		return;
	}

	data->phase2_method->process(sm, data->phase2_priv, in_data);

	if (sm->method_pending == METHOD_PENDING_WAIT) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in "
			   "pending wait state - save decrypted response");
		wpabuf_free(data->pending_phase2_resp);
		data->pending_phase2_resp = wpabuf_dup(in_data);
	}

	if (!data->phase2_method->isDone(sm, data->phase2_priv))
		return;

	if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
		eap_peap_req_failure(sm, data);
		next_vendor = EAP_VENDOR_IETF;
		next_type = EAP_TYPE_NONE;
		eap_peap_phase2_init(sm, data, next_vendor, next_type);
		return;
	}

	os_free(data->phase2_key);
	if (data->phase2_method->getKey) {
		data->phase2_key = data->phase2_method->getKey(
			sm, data->phase2_priv, &data->phase2_key_len);
		if (data->phase2_key == NULL) {
			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
				   "failed");
			eap_peap_req_failure(sm, data);
			eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
					     EAP_TYPE_NONE);
			return;
		}
	}

	switch (data->state) {
	case PHASE1_ID2:
	case PHASE2_ID:
	case PHASE2_SOH:
		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
			wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
					  "Identity not found in the user "
					  "database",
					  sm->identity, sm->identity_len);
			eap_peap_req_failure(sm, data);
			next_vendor = EAP_VENDOR_IETF;
			next_type = EAP_TYPE_NONE;
			break;
		}

#ifdef EAP_SERVER_TNC
		if (data->state != PHASE2_SOH && sm->tnc &&
		    data->peap_version == 0) {
			eap_peap_state(data, PHASE2_SOH);
			wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
				   "TNC (NAP SOH)");
			next_vendor = EAP_VENDOR_IETF;
			next_type = EAP_TYPE_NONE;
			break;
		}
#endif /* EAP_SERVER_TNC */

		eap_peap_state(data, PHASE2_METHOD);
		next_vendor = sm->user->methods[0].vendor;
		next_type = sm->user->methods[0].method;
		sm->user_eap_method_index = 1;
		wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type 0x%x",
			   next_vendor, next_type);
		break;
	case PHASE2_METHOD:
		eap_peap_req_success(sm, data);
		next_vendor = EAP_VENDOR_IETF;
		next_type = EAP_TYPE_NONE;
		break;
	case FAILURE:
		break;
	default:
		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
			   __func__, data->state);
		break;
	}

	eap_peap_phase2_init(sm, data, next_vendor, next_type);
}
예제 #5
0
static void eap_peap_process_phase2_soh(struct eap_sm *sm,
					struct eap_peap_data *data,
					struct wpabuf *in_data)
{
	const u8 *pos, *vpos;
	size_t left;
	const u8 *soh_tlv = NULL;
	size_t soh_tlv_len = 0;
	int tlv_type, mandatory, tlv_len, vtlv_len;
	u32 next_type;
	u32 vendor_id;

	pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
	if (pos == NULL) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP "
			   "Extensions Method header - skip TNC");
		goto auth_method;
	}

	/* Parse TLVs */
	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
	while (left >= 4) {
		mandatory = !!(pos[0] & 0x80);
		tlv_type = pos[0] & 0x3f;
		tlv_type = (tlv_type << 8) | pos[1];
		tlv_len = ((int) pos[2] << 8) | pos[3];
		pos += 4;
		left -= 4;
		if ((size_t) tlv_len > left) {
			wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
				   "(tlv_len=%d left=%lu)", tlv_len,
				   (unsigned long) left);
			eap_peap_state(data, FAILURE);
			return;
		}
		switch (tlv_type) {
		case EAP_TLV_VENDOR_SPECIFIC_TLV:
			if (tlv_len < 4) {
				wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short "
					   "vendor specific TLV (len=%d)",
					   (int) tlv_len);
				eap_peap_state(data, FAILURE);
				return;
			}

			vendor_id = WPA_GET_BE32(pos);
			if (vendor_id != EAP_VENDOR_MICROSOFT) {
				if (mandatory) {
					eap_peap_state(data, FAILURE);
					return;
				}
				break;
			}

			vpos = pos + 4;
			mandatory = !!(vpos[0] & 0x80);
			tlv_type = vpos[0] & 0x3f;
			tlv_type = (tlv_type << 8) | vpos[1];
			vtlv_len = ((int) vpos[2] << 8) | vpos[3];
			vpos += 4;
			if (vpos + vtlv_len > pos + left) {
				wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV "
					   "underrun");
				eap_peap_state(data, FAILURE);
				return;
			}

			if (tlv_type == 1) {
				soh_tlv = vpos;
				soh_tlv_len = vtlv_len;
				break;
			}

			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV "
				   "Type %d%s", tlv_type,
				   mandatory ? " (mandatory)" : "");
			if (mandatory) {
				eap_peap_state(data, FAILURE);
				return;
			}
			/* Ignore this TLV, but process other TLVs */
			break;
		default:
			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
				   "%d%s", tlv_type,
				   mandatory ? " (mandatory)" : "");
			if (mandatory) {
				eap_peap_state(data, FAILURE);
				return;
			}
			/* Ignore this TLV, but process other TLVs */
			break;
		}

		pos += tlv_len;
		left -= tlv_len;
	}
	if (left) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
			   "Request (left=%lu)", (unsigned long) left);
		eap_peap_state(data, FAILURE);
		return;
	}

	/* Process supported TLVs */
	if (soh_tlv) {
		int failure = 0;
		wpabuf_free(data->soh_response);
		data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
						      &failure);
		if (failure) {
			eap_peap_state(data, FAILURE);
			return;
		}
	} else {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received");
		eap_peap_state(data, FAILURE);
		return;
	}

auth_method:
	eap_peap_state(data, PHASE2_METHOD);
	next_type = sm->user->methods[0].method;
	sm->user_eap_method_index = 1;
	wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type %d",
		   sm->user->methods[0].vendor, next_type);
	eap_peap_phase2_init(sm, data, sm->user->methods[0].vendor, next_type);
}
예제 #6
0
static void eap_peap_process(struct eap_sm *sm, void *priv,
			     u8 *respData, size_t respDataLen)
{
	struct eap_peap_data *data = priv;
	struct eap_hdr *resp;
	u8 *pos, flags;
	int left;
	unsigned int tls_msg_len;
	int peer_version;

	resp = (struct eap_hdr *) respData;
	pos = (u8 *) (resp + 1);
	pos++;
	flags = *pos++;
	left = htons(resp->length) - sizeof(struct eap_hdr) - 2;
	wpa_printf(MSG_DEBUG, "EAP-PEAP: Received packet(len=%lu) - "
		   "Flags 0x%02x", (unsigned long) respDataLen, flags);
	peer_version = flags & EAP_PEAP_VERSION_MASK;
	if (data->force_version >= 0 && peer_version != data->force_version) {
		wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
			   " version (forced=%d peer=%d) - reject",
			   data->force_version, peer_version);
		eap_peap_state(data, FAILURE);
		return;
	}
	if (peer_version < data->peap_version) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
			   "use version %d",
			   peer_version, data->peap_version, peer_version);
		data->peap_version = peer_version;
			   
	}
	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
		if (left < 4) {
			wpa_printf(MSG_INFO, "EAP-PEAP: Short frame with TLS "
				   "length");
			eap_peap_state(data, FAILURE);
			return;
		}
		tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
			pos[3];
		wpa_printf(MSG_DEBUG, "EAP-PEAP: TLS Message Length: %d",
			   tls_msg_len);
		if (data->ssl.tls_in_left == 0) {
			data->ssl.tls_in_total = tls_msg_len;
			data->ssl.tls_in_left = tls_msg_len;
			free(data->ssl.tls_in);
			data->ssl.tls_in = NULL;
			data->ssl.tls_in_len = 0;
		}
		pos += 4;
		left -= 4;
	}

	switch (data->state) {
	case PHASE1:
		if (eap_tls_process_helper(sm, &data->ssl, pos, left) < 0) {
			wpa_printf(MSG_INFO, "EAP-PEAP: TLS processing "
				   "failed");
			eap_peap_state(data, FAILURE);
		}
		break;
	case PHASE2_START:
		eap_peap_state(data, PHASE2_ID);
		eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
		break;
	case PHASE2_ID:
	case PHASE2_METHOD:
	case PHASE2_TLV:
		eap_peap_process_phase2(sm, data, resp, pos, left);
		break;
	case SUCCESS_REQ:
		eap_peap_state(data, SUCCESS);
		break;
	case FAILURE_REQ:
		eap_peap_state(data, FAILURE);
		break;
	default:
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
			   data->state, __func__);
		break;
	}

	if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
		wpa_printf(MSG_INFO, "EAP-PEAP: Locally detected fatal error "
			   "in TLS processing");
		eap_peap_state(data, FAILURE);
	}
}
예제 #7
0
static void eap_peap_process_phase2_response(struct eap_sm *sm,
					     struct eap_peap_data *data,
					     u8 *in_data, size_t in_len)
{
	u8 next_type = EAP_TYPE_NONE;
	struct eap_hdr *hdr;
	u8 *pos;
	size_t left;

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

	hdr = (struct eap_hdr *) in_data;
	pos = (u8 *) (hdr + 1);
	left = in_len - sizeof(*hdr);

	if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
			    "allowed types", pos + 1, left - 1);
		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] !=
		    EAP_TYPE_NONE) {
			next_type =
				sm->user->methods[sm->user_eap_method_index++];
			wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
				   next_type);
		} else {
			next_type = eap_peap_req_failure(sm, data);
		}
		eap_peap_phase2_init(sm, data, next_type);
		return;
	}

	if (data->phase2_method->check(sm, data->phase2_priv, in_data,
				       in_len)) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
			   "ignore the packet");
		return;
	}

	data->phase2_method->process(sm, data->phase2_priv, in_data, in_len);

	if (!data->phase2_method->isDone(sm, data->phase2_priv))
		return;


	if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
		next_type = eap_peap_req_failure(sm, data);
		eap_peap_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_PEAP: Phase2 "
					  "Identity not found in the user "
					  "database",
					  sm->identity, sm->identity_len);
			next_type = eap_peap_req_failure(sm, data);
			break;
		}

		eap_peap_state(data, PHASE2_METHOD);
		next_type = sm->user->methods[0];
		sm->user_eap_method_index = 1;
		wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
		break;
	case PHASE2_METHOD:
		next_type = eap_peap_req_success(sm, data);
		break;
	case PHASE2_TLV:
		if (sm->tlv_request == TLV_REQ_SUCCESS ||
		    data->state == SUCCESS_REQ) {
			eap_peap_state(data, SUCCESS);
		} else {
			eap_peap_state(data, FAILURE);
		}
		break;
	case FAILURE:
		break;
	default:
		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
			   __func__, data->state);
		break;
	}

	eap_peap_phase2_init(sm, data, next_type);
}