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:
parent
e5e5f1c63e
commit
9d0e261bbe
@ -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 {
|
||||||
|
@ -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?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user