method_eap: Add EAP Success/Failure support

Although, EapHost takes care for EAP Success and Failure packets for us,
it does so for the outer-most method only. When using EAP inside a TLS
tunnel, we are responsible for EAP Success and Failure packets ourselves.

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2020-01-20 16:00:37 +01:00
parent e5e5f1c63e
commit 9d0e261bbe
3 changed files with 47 additions and 22 deletions

View File

@ -358,7 +358,7 @@ DWORD APIENTRY EapPeerProcessRequestPacket(
*ppEapError = NULL; *ppEapError = NULL;
// Parameter check // Parameter check
if (!hSession || !pReceivedPacket || dwReceivedPacketSize < 6 || pReceivedPacket->Data[0] != EAPMETHOD_TYPE || !pEapOutput) if (!hSession || !pReceivedPacket || dwReceivedPacketSize < sizeof(EapPacket) || pReceivedPacket->Data[0] != EAPMETHOD_TYPE || !pEapOutput)
return dwResult = ERROR_INVALID_PARAMETER; return dwResult = ERROR_INVALID_PARAMETER;
try { try {

View File

@ -319,9 +319,11 @@ namespace eap
/// ///
enum class phase_t { enum class phase_t {
unknown = -1, ///< Unknown phase unknown = -1, ///< Unknown phase
identity = 0, ///< Send identity init = 0, ///< Initialize
identity, ///< Send identity
inner, ///< Send inner method response inner, ///< Send inner method response
nak, ///< Send Legacy Nak response nak, ///< Send Legacy Nak response
finished, ///< EAP Success packet received
} m_phase; ///< What phase is our communication at? } m_phase; ///< What phase is our communication at?
}; };

View File

@ -222,9 +222,11 @@ void eap::method_eap::begin_session(
// Inner method can generate packets of up to 64kB (less the EAP packet header). // Inner method can generate packets of up to 64kB (less the EAP packet header).
// Initialize inner method with appropriately less packet size maximum. // Initialize inner method with appropriately less packet size maximum.
if (dwMaxSendPacketSize < sizeof(EapPacket)) if (dwMaxSendPacketSize < sizeof(EapPacket))
throw invalid_argument(string_printf(__FUNCTION__ " Maximum packet size too small (minimum: %zu, available: %u).", sizeof(EapPacket) + 1, dwMaxSendPacketSize)); throw invalid_argument(string_printf(__FUNCTION__ " Maximum packet size too small (minimum: %zu, available: %u).", sizeof(EapPacket), dwMaxSendPacketSize));
assert(m_inner); assert(m_inner);
m_inner->begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, std::min<DWORD>(dwMaxSendPacketSize, MAXWORD) - sizeof(EapPacket)); m_inner->begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, std::min<DWORD>(dwMaxSendPacketSize, MAXWORD) - sizeof(EapPacket));
m_phase = phase_t::init;
} }
@ -232,33 +234,54 @@ EapPeerMethodResponseAction eap::method_eap::process_request_packet(
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket, _In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize) _In_ DWORD dwReceivedPacketSize)
{ {
assert(dwReceivedPacketSize >= sizeof(EapPacket)); // Request packet should contain an EAP packet header at least. if (dwReceivedPacketSize < offsetof(EapPacket, Data))
auto hdr = reinterpret_cast<const EapPacket*>(pReceivedPacket); throw invalid_argument(string_printf(__FUNCTION__ " Incomplete EAP packet header (minimum: %zu, received: %u).", offsetof(EapPacket, Data), dwReceivedPacketSize));
// This must be an EAP-Request packet. auto hdr = reinterpret_cast<const EapPacket*>(pReceivedPacket);
if (hdr->Code != EapCodeRequest)
throw invalid_argument(string_printf(__FUNCTION__ " Unknown EAP packet received (expected: %u, received: %u).", EapCodeRequest, (int)hdr->Code));
// Check packet size. // Check packet size.
DWORD size_packet = ntohs(*reinterpret_cast<const unsigned short*>(hdr->Length)); DWORD size_packet = ntohs(*reinterpret_cast<const unsigned short*>(hdr->Length));
if (size_packet > dwReceivedPacketSize) if (size_packet > dwReceivedPacketSize)
throw invalid_argument(string_printf(__FUNCTION__ " Incorrect EAP packet length (expected: %u, received: %u).", size_packet, dwReceivedPacketSize)); throw invalid_argument(string_printf(__FUNCTION__ " Incorrect EAP packet length (expected: %u, received: %u).", size_packet, dwReceivedPacketSize));
// Save request packet ID to make matching response packet in get_response_packet() later. switch (hdr->Code) {
m_id = hdr->Id; case EapCodeRequest:
if (dwReceivedPacketSize < sizeof(EapPacket))
throw invalid_argument(string_printf(__FUNCTION__ " Incomplete EAP packet (minimum: %zu, received: %u).", sizeof(EapPacket), dwReceivedPacketSize));
if ((eap_type_t)hdr->Data[0] == eap_type_t::identity) { // Save request packet ID to make matching response packet in get_response_packet() later.
// EAP Identity. Respond with identity. m_id = hdr->Id;
m_phase = phase_t::identity;
return EapPeerMethodResponseActionSend; if ((eap_type_t)hdr->Data[0] == eap_type_t::identity) {
} else if ((eap_type_t)hdr->Data[0] == m_eap_method) { // EAP Identity. Respond with identity.
// Process the data with underlying method. m_phase = phase_t::identity;
m_phase = phase_t::inner; return EapPeerMethodResponseActionSend;
return method_tunnel::process_request_packet(hdr->Data + 1, size_packet - sizeof(EapPacket)); } else if ((eap_type_t)hdr->Data[0] == m_eap_method) {
} else { // Process the data with underlying method.
// Unsupported EAP method. Respond with Legacy Nak. m_phase = phase_t::inner;
m_phase = phase_t::nak; return method_tunnel::process_request_packet(hdr->Data + 1, size_packet - sizeof(EapPacket));
return EapPeerMethodResponseActionSend; } else {
// Unsupported EAP method. Respond with Legacy Nak.
m_phase = phase_t::nak;
return EapPeerMethodResponseActionSend;
}
// Check EAP Success/Failure packets for inner methods.
case EapCodeSuccess:
assert(size_packet == 4);
if (m_phase == phase_t::init) {
// Discard "canned" success packet.
return EapPeerMethodResponseActionDiscard;
}
m_phase = phase_t::finished;
return EapPeerMethodResponseActionResult;
case EapCodeFailure:
assert(size_packet == 4);
throw invalid_argument(string_printf(__FUNCTION__ " EAP Failure packet received."));
default:
throw invalid_argument(string_printf(__FUNCTION__ " Unknown EAP packet received (expected: %u, received: %u).", EapCodeRequest, (int)hdr->Code));
} }
} }