⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eap_peap.c

📁 IEEE802.11 a/b/g 客户端应用程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "			   "cryptobinding TLV");		return -1;	}	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");	return 0;}/** * eap_tlv_process - Process a received EAP-TLV message and generate a response * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @ret: Return values from EAP request validation and processing * @req: EAP-TLV request to be processed. The caller must have validated that * the buffer is large enough to contain full request (hdr->length bytes) and * that the EAP type is EAP_TYPE_TLV. * @resp: Buffer to return a pointer to the allocated response message. This * field should be initialized to %NULL before the call. The value will be * updated if a response message is generated. The caller is responsible for * freeing the allocated message. * @force_failure: Force negotiation to fail * Returns: 0 on success, -1 on failure */static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,			   struct eap_method_ret *ret,			   const struct wpabuf *req, struct wpabuf **resp,			   int force_failure){	size_t left, tlv_len;	const u8 *pos;	const u8 *result_tlv = NULL, *crypto_tlv = NULL;	size_t result_tlv_len = 0, crypto_tlv_len = 0;	int tlv_type, mandatory;	/* Parse TLVs */	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);	if (pos == NULL)		return -1;	wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);	while (left >= 4) {		mandatory = !!(pos[0] & 0x80);		tlv_type = WPA_GET_BE16(pos) & 0x3fff;		pos += 2;		tlv_len = WPA_GET_BE16(pos);		pos += 2;		left -= 4;		if (tlv_len > left) {			wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "				   "(tlv_len=%lu left=%lu)",				   (unsigned long) tlv_len,				   (unsigned long) left);			return -1;		}		switch (tlv_type) {		case EAP_TLV_RESULT_TLV:			result_tlv = pos;			result_tlv_len = tlv_len;			break;		case EAP_TLV_CRYPTO_BINDING_TLV:			crypto_tlv = pos;			crypto_tlv_len = tlv_len;			break;		default:			wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "				   "%d%s", tlv_type,				   mandatory ? " (mandatory)" : "");			if (mandatory) {				/* NAK TLV and ignore all TLVs in this packet.				 */				*resp = eap_tlv_build_nak(eap_get_id(req),							  tlv_type);				return *resp == NULL ? -1 : 0;			}			/* Ignore this TLV, but process other TLVs */			break;		}		pos += tlv_len;		left -= tlv_len;	}	if (left) {		wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "			   "Request (left=%lu)", (unsigned long) left);		return -1;	}	/* Process supported TLVs */	if (crypto_tlv && data->crypto_binding != NO_BINDING) {		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",			    crypto_tlv, crypto_tlv_len);		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,						   crypto_tlv_len + 4) < 0) {			if (result_tlv == NULL)				return -1;			force_failure = 1;		}	} else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");		return -1;	}	if (result_tlv) {		int status, resp_status;		wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",			    result_tlv, result_tlv_len);		if (result_tlv_len < 2) {			wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "				   "(len=%lu)",				   (unsigned long) result_tlv_len);			return -1;		}		status = WPA_GET_BE16(result_tlv);		if (status == EAP_TLV_RESULT_SUCCESS) {			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "				   "- EAP-TLV/Phase2 Completed");			if (force_failure) {				wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"					   " - force failed Phase 2");				resp_status = EAP_TLV_RESULT_FAILURE;				ret->decision = DECISION_FAIL;			} else {				resp_status = EAP_TLV_RESULT_SUCCESS;				ret->decision = DECISION_UNCOND_SUCC;			}		} else if (status == EAP_TLV_RESULT_FAILURE) {			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");			resp_status = EAP_TLV_RESULT_FAILURE;			ret->decision = DECISION_FAIL;		} else {			wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "				   "Status %d", status);			resp_status = EAP_TLV_RESULT_FAILURE;			ret->decision = DECISION_FAIL;		}		ret->methodState = METHOD_DONE;		*resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,					     eap_get_id(req), resp_status);	}	return 0;}static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf){	struct wpabuf *e;	struct eap_tlv_hdr *tlv;	if (buf == NULL)		return NULL;	/* Encapsulate EAP packet in EAP-Payload TLV */	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");	e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));	if (e == NULL) {		wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "			   "for TLV encapsulation");		wpabuf_free(buf);		return NULL;	}	tlv = wpabuf_put(e, sizeof(*tlv));	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |				     EAP_TLV_EAP_PAYLOAD_TLV);	tlv->length = host_to_be16(wpabuf_len(buf));	wpabuf_put_buf(e, buf);	wpabuf_free(buf);	return e;}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(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;				sm->mschapv2_full_key = 1;				data->phase2_priv =					data->phase2_method->init(sm);				sm->init_phase2 = 0;				sm->mschapv2_full_key = 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;}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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -