eap::metod thorough redesign:

- Support for method stacking introduced
- EAP-TLS method has been discontinued
- ownTLS has been discontinued
This commit is contained in:
Simon Rozman 2016-10-31 16:58:53 +01:00
parent b054dcdc7a
commit c31e019cef
24 changed files with 1740 additions and 3046 deletions

View File

@ -21,14 +21,23 @@
namespace eap
{
///
/// EAP and non-EAP method base class
/// Method base class
///
class method;
///
/// Non-EAP method base class
/// Tunnel method base class
///
class method_noneap;
/// This is a base class for all the methods that encapsulate inner methods to provide stacking framework.
///
class method_tunnel;
///
/// EAP tunnel method
///
/// This method encapsulates inner data in EAP packets.
///
class method_eap;
}
#pragma once
@ -55,25 +64,23 @@ namespace eap
public:
///
/// Constructs an EAP method
/// Constructs a method
///
/// \param[in] mod EAP module to use for global services
/// \param[in] cfg Method configuration
/// \param[in] cred User credentials
/// \param[in] mod Module to use for global services
///
method(_In_ module &module, _In_ config_method &cfg, _In_ credentials &cred);
method(_In_ module &mod);
///
/// Moves an EAP method
/// Moves a method
///
/// \param[in] other EAP method to move from
/// \param[in] other Method to move from
///
method(_Inout_ method &&other);
///
/// Moves an EAP method
/// Moves a method
///
/// \param[in] other EAP method to move from
/// \param[in] other Method to move from
///
/// \returns Reference to this object
///
@ -115,8 +122,8 @@ namespace eap
/// \sa [EapPeerGetResponsePacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363610.aspx)
///
virtual void get_response_packet(
_Inout_bytecap_(*dwSendPacketSize) void *pSendPacket,
_Inout_ DWORD *pdwSendPacketSize) = 0;
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max = MAXDWORD) = 0;
///
/// Obtains the result of an authentication session from the EAP method.
@ -176,89 +183,193 @@ namespace eap
/// @}
public:
module &m_module; ///< EAP module
config_method &m_cfg; ///< Connection configuration
credentials &m_cred; ///< User credentials
std::vector<winstd::eap_attr> m_eap_attr; ///< EAP attributes
module &m_module; ///< Module for global services
};
class method_noneap : public method
class method_tunnel : public method
{
WINSTD_NONCOPYABLE(method_noneap)
WINSTD_NONCOPYABLE(method_tunnel)
public:
///
/// Constructs a non-EAP method
/// Constructs a method
///
/// \param[in] mod EAP module to use for global services
/// \param[in] cfg Method configuration
/// \param[in] cred User credentials
/// \param[in] mod Module to use for global services
/// \param[in] inner Inner method
///
method_noneap(_In_ module &module, _In_ config_method &cfg, _In_ credentials &cred);
method_tunnel(_In_ module &mod, _In_ method *inner);
///
/// Moves a non-EAP method
/// Moves a method
///
/// \param[in] other EAP method to move from
/// \param[in] other Method to move from
///
method_noneap(_Inout_ method_noneap &&other);
method_tunnel(_Inout_ method_tunnel &&other);
///
/// Moves a non-EAP method
/// Moves a method
///
/// \param[in] other EAP method to move from
/// \param[in] other Method to move from
///
/// \returns Reference to this object
///
method_noneap& operator=(_Inout_ method_noneap &&other);
method_tunnel& operator=(_Inout_ method_tunnel &&other);
/// \name Packet processing
/// @{
///
/// Obtains a response packet from the non-EAP method.
/// Starts an EAP authentication session on the peer EapHost using the EAP method.
///
/// \sa [EapPeerBeginSession function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363600.aspx)
///
virtual void begin_session(
_In_ DWORD dwFlags,
_In_ const EapAttributes *pAttributeArray,
_In_ HANDLE hTokenImpersonateUser,
_In_opt_ DWORD dwMaxSendPacketSize = MAXDWORD);
///
/// Ends an EAP authentication session for the EAP method.
///
/// \sa [EapPeerEndSession function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363604.aspx)
///
virtual void end_session();
///
/// Processes a packet received by EapHost from a supplicant.
///
/// \sa [EapPeerProcessRequestPacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363621.aspx)
///
virtual EapPeerMethodResponseAction process_request_packet(
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize);
///
/// Obtains a response packet from the EAP method.
///
/// \sa [EapPeerGetResponsePacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363610.aspx)
///
virtual void get_response_packet(
_Inout_bytecap_(*dwSendPacketSize) void *pSendPacket,
_Inout_ DWORD *pdwSendPacketSize);
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max = MAXDWORD);
///
/// Obtains the result of an authentication session from the EAP method.
///
/// \sa [EapPeerGetResult function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363611.aspx)
///
virtual void get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult);
/// @}
/// \name User Interaction
/// @{
///
/// Obtains the user interface context from the EAP method.
///
/// \note This function is always followed by the `EapPeerInvokeInteractiveUI()` function, which is followed by the `EapPeerSetUIContext()` function.
///
/// \sa [EapPeerGetUIContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363612.aspx)
///
virtual void get_ui_context(
_Inout_ BYTE **ppUIContextData,
_Inout_ DWORD *pdwUIContextDataSize);
///
/// Provides a user interface context to the EAP method.
///
/// \note This function is called after the UI has been raised through the `EapPeerGetUIContext()` function.
///
/// \sa [EapPeerSetUIContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363626.aspx)
///
virtual EapPeerMethodResponseAction set_ui_context(
_In_count_(dwUIContextDataSize) const BYTE *pUIContextData,
_In_ DWORD dwUIContextDataSize);
/// @}
/// \name EAP Response Attributes
/// @{
///
/// Obtains an array of EAP response attributes from the EAP method.
///
/// \sa [EapPeerGetResponseAttributes function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363609.aspx)
///
virtual void get_response_attributes(_Inout_ EapAttributes *pAttribs);
///
/// Provides an updated array of EAP response attributes to the EAP method.
///
/// \sa [EapPeerSetResponseAttributes function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363625.aspx)
///
virtual EapPeerMethodResponseAction set_response_attributes(_In_ const EapAttributes *pAttribs);
/// @}
protected:
std::unique_ptr<method> m_inner; ///< Inner method
};
class method_eap : public method_tunnel
{
WINSTD_NONCOPYABLE(method_eap)
public:
///
/// Appends Diameter AVP to response packet
/// Constructs a method
///
/// \param[in] code AVP code
/// \param[in] flags AVP flags
/// \param[in] data AVP data (<16777212B)
/// \param[in] size Size of \p data in bytes
/// \param[in] mod Module to use for global services
/// \param[in] eap_method EAP method type
/// \param[in] inner Inner method
///
void append_avp(
_In_ unsigned int code,
_In_ unsigned char flags,
_In_bytecount_(size) const void *data,
_In_ unsigned int size);
method_eap(_In_ module &mod, _In_ winstd::eap_type_t eap_method, _In_ method *inner);
///
/// Appends Diameter AVP to response packet
/// Moves a method
///
/// \param[in] code AVP code
/// \param[in] vendor_id Vendor-ID
/// \param[in] flags AVP flags
/// \param[in] data AVP data (<16777212B)
/// \param[in] size Size of \p data in bytes
/// \param[in] other Method to move from
///
void append_avp(
_In_ unsigned int code,
_In_ unsigned int vendor_id,
_In_ unsigned char flags,
_In_bytecount_(size) const void *data,
_In_ unsigned int size);
method_eap(_Inout_ method_eap &&other);
///
/// Moves a method
///
/// \param[in] other Method to move from
///
/// \returns Reference to this object
///
method_eap& operator=(_Inout_ method_eap &&other);
/// \name Packet processing
/// @{
///
/// Processes a packet received by EapHost from a supplicant.
///
/// \sa [EapPeerProcessRequestPacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363621.aspx)
///
virtual EapPeerMethodResponseAction process_request_packet(
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize);
///
/// Obtains a response packet from the EAP method.
///
/// \sa [EapPeerGetResponsePacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363610.aspx)
///
virtual void get_response_packet(
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max = MAXDWORD);
protected:
sanitizing_blob m_packet_res; ///< Response packet
const winstd::eap_type_t m_eap_method; ///< EAP method type
unsigned char m_id; ///< Request packet ID
};
}

View File

@ -28,19 +28,14 @@ using namespace winstd;
// eap::method
//////////////////////////////////////////////////////////////////////
eap::method::method(_In_ module &module, _In_ config_method &cfg, _In_ credentials &cred) :
m_module(module),
m_cfg(cfg),
m_cred(cred)
eap::method::method(_In_ module &mod) :
m_module(mod)
{
}
eap::method::method(_Inout_ method &&other) :
m_module ( other.m_module ),
m_cfg ( other.m_cfg ),
m_cred ( other.m_cred ),
m_eap_attr(std::move(other.m_eap_attr))
m_module(other.m_module)
{
}
@ -49,9 +44,6 @@ eap::method& eap::method::operator=(_Inout_ method &&other)
{
if (this != std::addressof(other)) {
assert(std::addressof(m_module) == std::addressof(other.m_module)); // Move method within same module only!
assert(std::addressof(m_cfg ) == std::addressof(other.m_cfg )); // Move method with same configuration only!
assert(std::addressof(m_cred ) == std::addressof(other.m_cred )); // Move method with same credentials only!
m_eap_attr = std::move(other.m_eap_attr);
}
return *this;
@ -68,11 +60,6 @@ void eap::method::begin_session(
UNREFERENCED_PARAMETER(pAttributeArray);
UNREFERENCED_PARAMETER(hTokenImpersonateUser);
UNREFERENCED_PARAMETER(dwMaxSendPacketSize);
// Presume authentication will fail with generic protocol failure. (Pesimist!!!)
// We will reset once we get get_result(Success) call.
m_cfg.m_last_status = config_method::status_auth_failed;
m_cfg.m_last_msg.clear();
}
@ -85,27 +72,8 @@ void eap::method::get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult)
{
assert(pResult);
switch (reason) {
case EapPeerMethodResultSuccess: {
m_module.log_event(&EAPMETHOD_METHOD_SUCCESS, event_data((unsigned int)m_cfg.get_method_id()), event_data::blank);
m_cfg.m_last_status = config_method::status_success;
break;
}
case EapPeerMethodResultFailure:
m_module.log_event(&EAPMETHOD_METHOD_FAILURE_ERROR2, event_data((unsigned int)m_cfg.get_method_id()), event_data((unsigned int)m_cfg.m_last_status), event_data::blank);
break;
default:
throw win_runtime_error(ERROR_NOT_SUPPORTED, __FUNCTION__ " Not supported.");
}
// Always ask EAP host to save the connection data. And it will save it *only* when we report "success".
// Don't worry. EapHost is well aware of failed authentication condition.
pResult->fSaveConnectionData = TRUE;
pResult->fIsSuccess = TRUE;
UNREFERENCED_PARAMETER(reason);
UNREFERENCED_PARAMETER(pResult);
}
@ -154,107 +122,192 @@ EapPeerMethodResponseAction eap::method::set_response_attributes(_In_ const EapA
//////////////////////////////////////////////////////////////////////
// eap::method_noneap
// eap::method_tunnel
//////////////////////////////////////////////////////////////////////
eap::method_noneap::method_noneap(_In_ module &module, _In_ config_method &cfg, _In_ credentials &cred) : method(module, cfg, cred)
eap::method_tunnel::method_tunnel(_In_ module &mod, _In_ method *inner) :
m_inner(inner),
method(mod)
{
}
eap::method_noneap::method_noneap(_Inout_ method_noneap &&other) :
m_packet_res(std::move(other.m_packet_res)),
method (std::move(other ))
eap::method_tunnel::method_tunnel(_Inout_ method_tunnel &&other) :
m_inner(std::move(other.m_inner)),
method (std::move(other ))
{
}
eap::method_noneap& eap::method_noneap::operator=(_Inout_ method_noneap &&other)
eap::method_tunnel& eap::method_tunnel::operator=(_Inout_ method_tunnel &&other)
{
if (this != std::addressof(other)) {
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method with same credentials only!
(method&)*this = std::move(other );
m_packet_res = std::move(other.m_packet_res);
(method&)*this = std::move(other );
m_inner = std::move(other.m_inner);
}
return *this;
}
void eap::method_noneap::get_response_packet(
_Inout_bytecap_(*dwSendPacketSize) void *pSendPacket,
_Inout_ DWORD *pdwSendPacketSize)
void eap::method_tunnel::begin_session(
_In_ DWORD dwFlags,
_In_ const EapAttributes *pAttributeArray,
_In_ HANDLE hTokenImpersonateUser,
_In_opt_ DWORD dwMaxSendPacketSize)
{
assert(pdwSendPacketSize);
assert(pSendPacket);
method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
size_t size_packet = m_packet_res.size();
if (size_packet > *pdwSendPacketSize)
throw invalid_argument(string_printf(__FUNCTION__ " This method does not support packet fragmentation, but the data size is too big to fit in one packet (packet: %u, maximum: %u).", size_packet, *pdwSendPacketSize).c_str());
memcpy(pSendPacket, m_packet_res.data(), size_packet);
*pdwSendPacketSize = (DWORD)size_packet;
m_packet_res.clear();
assert(m_inner);
m_inner->begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
}
void eap::method_noneap::append_avp(
_In_ unsigned int code,
_In_ unsigned char flags,
_In_bytecount_(size) const void *data,
_In_ unsigned int size)
void eap::method_tunnel::end_session()
{
unsigned int
padding = (unsigned int)((4 - size) % 4),
size_outer;
assert(m_inner);
m_inner->end_session();
m_packet_res.reserve(
m_packet_res.size() +
(size_outer =
sizeof(diameter_avp_header) + // Diameter header
size) + // Data
padding); // Data padding
// Diameter AVP header
diameter_avp_header hdr;
*reinterpret_cast<unsigned int*>(hdr.code) = htonl(code);
hdr.flags = flags;
hton24(size_outer, hdr.length);
m_packet_res.insert(m_packet_res.end(), reinterpret_cast<const unsigned char*>(&hdr), reinterpret_cast<const unsigned char*>(&hdr + 1));
// Data
m_packet_res.insert(m_packet_res.end(), reinterpret_cast<const unsigned char*>(data), reinterpret_cast<const unsigned char*>(data) + size);
m_packet_res.insert(m_packet_res.end(), padding, 0);
method::end_session();
}
void eap::method_noneap::append_avp(
_In_ unsigned int code,
_In_ unsigned int vendor_id,
_In_ unsigned char flags,
_In_bytecount_(size) const void *data,
_In_ unsigned int size)
EapPeerMethodResponseAction eap::method_tunnel::process_request_packet(
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize)
{
unsigned int
padding = (unsigned int)((4 - size) % 4),
size_outer;
m_packet_res.reserve(
m_packet_res.size() +
(size_outer =
sizeof(diameter_avp_header_ven) + // Diameter header
size) + // Data
padding); // Data padding
// Diameter AVP header
diameter_avp_header_ven hdr;
*reinterpret_cast<unsigned int*>(hdr.code) = htonl(code);
hdr.flags = flags | diameter_avp_flag_vendor;
hton24(size_outer, hdr.length);
*reinterpret_cast<unsigned int*>(hdr.vendor) = htonl(vendor_id);
m_packet_res.insert(m_packet_res.end(), reinterpret_cast<const unsigned char*>(&hdr), reinterpret_cast<const unsigned char*>(&hdr + 1));
// Data
m_packet_res.insert(m_packet_res.end(), reinterpret_cast<const unsigned char*>(data), reinterpret_cast<const unsigned char*>(data) + size);
m_packet_res.insert(m_packet_res.end(), padding, 0);
assert(m_inner);
return m_inner->process_request_packet(pReceivedPacket, dwReceivedPacketSize);
}
void eap::method_tunnel::get_response_packet(
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max)
{
assert(m_inner);
m_inner->get_response_packet(packet, size_max);
}
void eap::method_tunnel::get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult)
{
assert(m_inner);
m_inner->get_result(reason, pResult);
}
void eap::method_tunnel::get_ui_context(
_Inout_ BYTE **ppUIContextData,
_Inout_ DWORD *pdwUIContextDataSize)
{
assert(m_inner);
m_inner->get_ui_context(ppUIContextData, pdwUIContextDataSize);
}
EapPeerMethodResponseAction eap::method_tunnel::set_ui_context(
_In_count_(dwUIContextDataSize) const BYTE *pUIContextData,
_In_ DWORD dwUIContextDataSize)
{
assert(m_inner);
return m_inner->set_ui_context(pUIContextData, dwUIContextDataSize);
}
void eap::method_tunnel::get_response_attributes(_Inout_ EapAttributes *pAttribs)
{
assert(m_inner);
m_inner->get_response_attributes(pAttribs);
}
EapPeerMethodResponseAction eap::method_tunnel::set_response_attributes(_In_ const EapAttributes *pAttribs)
{
assert(m_inner);
return m_inner->set_response_attributes(pAttribs);
}
//////////////////////////////////////////////////////////////////////
// eap::method_eap
//////////////////////////////////////////////////////////////////////
eap::method_eap::method_eap(_In_ module &mod, _In_ eap_type_t eap_method, _In_ method *inner) :
m_eap_method(eap_method),
m_id(0),
method_tunnel(mod, inner)
{
}
eap::method_eap::method_eap(_Inout_ method_eap &&other) :
m_eap_method (std::move(other.m_eap_method)),
m_id (std::move(other.m_id )),
method_tunnel(std::move(other ))
{
}
eap::method_eap& eap::method_eap::operator=(_Inout_ method_eap &&other)
{
if (this != std::addressof(other)) {
assert(m_eap_method == other.m_eap_method); // Move method within same EAP method type only!
(method_tunnel&)*this = std::move(other );
m_id = std::move(other.m_id);
}
return *this;
}
EapPeerMethodResponseAction eap::method_eap::process_request_packet(
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize)
{
assert(dwReceivedPacketSize >= sizeof(EapPacket)); // Request packet should contain an EAP packet header at least.
auto hdr = reinterpret_cast<const EapPacket*>(pReceivedPacket);
// Parse EAP header.
if (hdr->Code != EapCodeRequest)
throw invalid_argument(string_printf(__FUNCTION__ " Unknown EAP packet received (expected: %u, received: %u).", EapCodeRequest, (int)hdr->Code));
DWORD size_packet = ntohs(*reinterpret_cast<const unsigned short*>(hdr->Length));
if (size_packet > dwReceivedPacketSize)
throw invalid_argument(string_printf(__FUNCTION__ " Incorrect EAP packet length (expected: %uB, received: %uB).", size_packet, dwReceivedPacketSize));
if (hdr->Data[0] != m_eap_method)
throw invalid_argument(string_printf(__FUNCTION__ " Unsupported EAP method (expected: %u, received: %u).", (int)m_eap_method, (int)hdr->Data[0]));
// Save request packet ID to make matching response packet in get_response_packet() later.
m_id = hdr->Id;
// Process the data with underlying method.
return method_tunnel::process_request_packet(hdr->Data + 1, size_packet - sizeof(EapPacket));
}
void eap::method_eap::get_response_packet(
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max)
{
assert(size_max >= sizeof(EapPacket)); // We should be able to respond with at least an EAP packet header.
if (size_max > MAXWORD) size_max = MAXWORD; // EAP packets maximum size is 64kB.
packet.reserve(size_max); // To avoid reallocation when inserting EAP packet header later.
// Get data from underlying method.
method_tunnel::get_response_packet(packet, size_max - sizeof(EapPacket));
// Prepare EAP packet header.
EapPacket hdr;
hdr.Code = (BYTE)EapCodeResponse;
hdr.Id = m_id;
size_t size_packet = packet.size() + sizeof(EapPacket);
assert(size_packet <= MAXWORD); // Packets spanning over 64kB are not supported.
*reinterpret_cast<unsigned short*>(hdr.Length) = htons((unsigned short)size_packet);
hdr.Data[0] = m_eap_method;
// Insert EAP packet header before data.
packet.insert(packet.begin(), reinterpret_cast<const unsigned char*>(&hdr), reinterpret_cast<const unsigned char*>(&hdr + 1));
}

View File

@ -23,6 +23,8 @@ namespace eap
///
/// EapHost peer method
///
/// A wrapper class to provide system installed 3rd party EAP methods integration.
///
class method_eaphost;
}
@ -49,7 +51,7 @@ namespace eap
/// \param[in] cfg Method configuration
/// \param[in] cred User credentials
///
method_eaphost(_In_ module &module, _In_ config_method_eaphost &cfg, _In_ credentials_eaphost &cred);
method_eaphost(_In_ module &mod, _In_ config_method_eaphost &cfg, _In_ credentials_eaphost &cred);
///
/// Moves an EAP method
@ -103,8 +105,8 @@ namespace eap
/// \sa [EapPeerGetResponsePacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363610.aspx)
///
virtual void get_response_packet(
_Inout_bytecap_(*dwSendPacketSize) void *pSendPacket,
_Inout_ DWORD *pdwSendPacketSize);
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max = MAXDWORD);
///
/// Obtains the result of an authentication session from the EAP method.
@ -167,7 +169,7 @@ namespace eap
///
/// Converts EapHost peer action to output structure.
///
/// \param[in] action EapHost peer action
/// \param[in] action EapHost peer action
///
/// \returns EAP method output action
///
@ -186,9 +188,9 @@ namespace eap
}
protected:
EAP_SESSIONID m_session_id; ///< EAP session ID
config_method_eaphost &m_cfg; ///< Method configuration
credentials_eaphost &m_cred; ///< Method user credentials
sanitizing_blob m_ctx_req_blob; ///< Inner UI context request
sanitizing_blob m_ctx_res_blob; ///< Inner UI context response
EAP_SESSIONID m_session_id; ///< EAP session ID
};
}

View File

@ -28,16 +28,20 @@ using namespace winstd;
// eap::method_eaphost
//////////////////////////////////////////////////////////////////////
eap::method_eaphost::method_eaphost(_In_ module &module, _In_ config_method_eaphost &cfg, _In_ credentials_eaphost &cred) :
eap::method_eaphost::method_eaphost(_In_ module &mod, _In_ config_method_eaphost &cfg, _In_ credentials_eaphost &cred) :
m_cfg(cfg),
m_cred(cred),
m_session_id(0),
method(module, cfg, cred)
method(mod)
{
}
eap::method_eaphost::method_eaphost(_Inout_ method_eaphost &&other) :
m_session_id (std::move(other.m_session_id)),
method(std::move(other ))
m_cfg ( other.m_cfg ),
m_cred ( other.m_cred ),
m_session_id(std::move(other.m_session_id)),
method (std::move(other ))
{
}
@ -45,8 +49,10 @@ eap::method_eaphost::method_eaphost(_Inout_ method_eaphost &&other) :
eap::method_eaphost& eap::method_eaphost::operator=(_Inout_ method_eaphost &&other)
{
if (this != std::addressof(other)) {
assert(std::addressof(m_cfg ) == std::addressof(other.m_cfg )); // Move method within same configuration only!
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method within same credentials only!
(method&)*this = std::move(other );
m_session_id = std::move(other.m_session_id);
m_session_id = std::move(other.m_session_id);
}
return *this;
@ -59,28 +65,30 @@ void eap::method_eaphost::begin_session(
_In_ HANDLE hTokenImpersonateUser,
_In_opt_ DWORD dwMaxSendPacketSize)
{
method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
// Presume authentication will fail with generic protocol failure. (Pesimist!!!)
// We will reset once we get get_result(Success) call.
m_cfg.m_last_status = config_method::status_auth_failed;
m_cfg.m_last_msg.clear();
// Create EapHost peer session using available connection data (m_cfg) and user data (m_cred).
auto &cfg = dynamic_cast<config_method_eaphost&>(m_cfg);
auto &cred = dynamic_cast<credentials_eaphost &>(m_cred);
eap_error_runtime error;
DWORD dwResult = EapHostPeerBeginSession(
dwFlags,
cfg.get_type(),
m_cfg.get_type(),
pAttributeArray,
hTokenImpersonateUser,
(DWORD)cfg.m_cfg_blob.size(),
cfg.m_cfg_blob.data(),
(DWORD)cred.m_cred_blob.size(),
cred.m_cred_blob.data(),
(DWORD)m_cfg.m_cfg_blob.size(),
m_cfg.m_cfg_blob.data(),
(DWORD)m_cred.m_cred_blob.size(),
m_cred.m_cred_blob.data(),
dwMaxSendPacketSize,
NULL, NULL, NULL,
&m_session_id,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// Session succesfully created.
method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
m_module.log_event(&EAPMETHOD_METHOD_HANDSHAKE_START2, event_data((unsigned int)m_cfg.get_method_id()), event_data::blank);
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerBeginSession failed.");
else
@ -90,8 +98,6 @@ void eap::method_eaphost::begin_session(
void eap::method_eaphost::end_session()
{
method::end_session();
// End EapHost peer session.
eap_error_runtime error;
DWORD dwResult = EapHostPeerEndSession(m_session_id, &error._Myptr);
@ -101,6 +107,8 @@ void eap::method_eaphost::end_session()
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerEndSession failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerEndSession failed.");
method::end_session();
}
@ -110,8 +118,6 @@ EapPeerMethodResponseAction eap::method_eaphost::process_request_packet(
{
assert(pReceivedPacket || dwReceivedPacketSize == 0);
m_module.log_event(&EAPMETHOD_PACKET_RECV, event_data((unsigned int)m_cfg.get_method_id()), event_data((unsigned int)dwReceivedPacketSize), event_data::blank);
// Let EapHost peer process the packet.
EapHostPeerResponseAction action;
eap_error_runtime error;
@ -132,24 +138,20 @@ EapPeerMethodResponseAction eap::method_eaphost::process_request_packet(
void eap::method_eaphost::get_response_packet(
_Inout_bytecap_(*dwSendPacketSize) void *pSendPacket,
_Inout_ DWORD *pdwSendPacketSize)
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max)
{
assert(pdwSendPacketSize);
assert(pSendPacket || !*pdwSendPacketSize);
// Let EapHost peer prepare response packet.
DWORD size_max = *pdwSendPacketSize;
eap_blob_runtime packet;
eap_blob_runtime _packet;
eap_error_runtime error;
DWORD dwResult = EapHostPeerGetSendPacket(
m_session_id,
pdwSendPacketSize,
&packet._Myptr,
&size_max,
&_packet._Myptr,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// Packet successfuly prepared.
memcpy_s(pSendPacket, size_max, packet.get(), *pdwSendPacketSize);
packet.assign(_packet.get(), _packet.get() + size_max);
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerGetSendPacket failed.");
else
@ -161,34 +163,49 @@ void eap::method_eaphost::get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult)
{
assert(pResult);
// Let EapHost peer return result.
eap_error_runtime error;
EapHostPeerMethodResult result = {};
DWORD dwResult = EapHostPeerGetResult(
m_session_id,
EapHostPeerMethodResultFromMethod,
&result,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// Result successfuly returned.
method::get_result(reason, pResult);
if (reason == EapPeerMethodResultSuccess) {
// Let EapHost peer return result.
eap_error_runtime error;
EapHostPeerMethodResult result = {};
DWORD dwResult = EapHostPeerGetResult(
m_session_id,
EapHostPeerMethodResultFromMethod,
&result,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// Result successfuly returned.
pResult->fIsSuccess = result.fIsSuccess;
pResult->dwFailureReasonCode = result.dwFailureReasonCode;
pResult->pAttribArray = result.pAttribArray;
pResult->pEapError = result.pEapError;
pResult->dwFailureReasonCode = result.dwFailureReasonCode;
pResult->pAttribArray = result.pAttribArray;
if (result.fSaveConnectionData)
dynamic_cast<config_method_eaphost&>(m_cfg).m_cfg_blob.assign(result.pConnectionData, result.pConnectionData + result.dwSizeofConnectionData);
if (result.pEapError) {
// Transfer error to our module memory space.
pResult->pEapError = m_module.make_error(result.pEapError);
EapHostPeerFreeEapError(result.pEapError);
result.pEapError = NULL;
}
if (result.fSaveUserData)
dynamic_cast<credentials_eaphost &>(m_cred).m_cred_blob.assign(result.pUserData, result.pUserData + result.dwSizeofUserData);
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerGetResult failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerGetResult failed.");
}
if (result.fSaveConnectionData) {
// Update configuration BLOB.
m_cfg.m_cfg_blob.assign(result.pConnectionData, result.pConnectionData + result.dwSizeofConnectionData);
}
if (result.fSaveUserData) {
// Update credentials BLOB.
m_cred.m_cred_blob.assign(result.pUserData, result.pUserData + result.dwSizeofUserData);
}
if (reason == EapPeerMethodResultSuccess)
m_cfg.m_last_status = config_method::status_success;
// Always ask EAP host to save the connection data. And it will save it *only* when we report "success".
// Don't worry. EapHost is well aware of failed authentication condition.
pResult->fSaveConnectionData = TRUE;
pResult->fIsSuccess = TRUE;
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerGetResult failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerGetResult failed.");
}

View File

@ -38,7 +38,7 @@ namespace eap
namespace eap
{
class method_mschapv2 : public method_noneap
class method_mschapv2 : public method
{
WINSTD_NONCOPYABLE(method_mschapv2)
@ -50,7 +50,7 @@ namespace eap
/// \param[in] cfg Method configuration
/// \param[in] cred User credentials
///
method_mschapv2(_In_ module &module, _In_ config_method_mschapv2 &cfg, _In_ credentials_pass &cred);
method_mschapv2(_In_ module &mod, _In_ config_method_mschapv2 &cfg, _In_ credentials_pass &cred);
///
/// Moves a MSCHAPv2 method
@ -91,6 +91,24 @@ namespace eap
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize);
///
/// Obtains a response packet from the EAP method.
///
/// \sa [EapPeerGetResponsePacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363610.aspx)
///
virtual void get_response_packet(
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max = MAXDWORD);
///
/// Obtains the result of an authentication session from the EAP method.
///
/// \sa [EapPeerGetResult function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363611.aspx)
///
virtual void get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult);
/// @}
friend class method_ttls; // Setting of initial challenge derived from TLS PRF
@ -133,6 +151,7 @@ namespace eap
static std::list<std::string> parse_response(_In_count_(count) const char *resp, _In_ size_t count);
protected:
config_method_mschapv2 &m_cfg; ///< Method configuration
credentials_pass &m_cred; ///< Method user credentials
winstd::crypt_prov m_cp; ///< Cryptography provider for general services
@ -148,5 +167,7 @@ namespace eap
phase_challenge_server, ///< Verify server challenge
phase_finished, ///< Connection shut down
} m_phase; ///< What phase is our communication at?
sanitizing_blob m_packet_res; ///< Response packet
};
}

View File

@ -28,17 +28,19 @@ using namespace winstd;
// eap::method_mschapv2
//////////////////////////////////////////////////////////////////////
eap::method_mschapv2::method_mschapv2(_In_ module &module, _In_ config_method_mschapv2 &cfg, _In_ credentials_pass &cred) :
eap::method_mschapv2::method_mschapv2(_In_ module &mod, _In_ config_method_mschapv2 &cfg, _In_ credentials_pass &cred) :
m_cfg(cfg),
m_cred(cred),
m_ident(0),
m_success(false),
m_phase(phase_unknown),
method_noneap(module, cfg, cred)
method(mod)
{
}
eap::method_mschapv2::method_mschapv2(_Inout_ method_mschapv2 &&other) :
m_cfg ( other.m_cfg ),
m_cred ( other.m_cred ),
m_cp (std::move(other.m_cp )),
m_challenge_server(std::move(other.m_challenge_server)),
@ -47,7 +49,8 @@ eap::method_mschapv2::method_mschapv2(_Inout_ method_mschapv2 &&other) :
m_nt_resp (std::move(other.m_nt_resp )),
m_success (std::move(other.m_success )),
m_phase (std::move(other.m_phase )),
method_noneap (std::move(other ))
m_packet_res (std::move(other.m_packet_res )),
method (std::move(other ))
{
}
@ -55,15 +58,17 @@ eap::method_mschapv2::method_mschapv2(_Inout_ method_mschapv2 &&other) :
eap::method_mschapv2& eap::method_mschapv2::operator=(_Inout_ method_mschapv2 &&other)
{
if (this != std::addressof(other)) {
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method with same credentials only!
(method_noneap&)*this = std::move(other );
m_cp = std::move(other.m_cp );
m_challenge_server = std::move(other.m_challenge_server);
m_challenge_client = std::move(other.m_challenge_client);
m_ident = std::move(other.m_ident );
m_nt_resp = std::move(other.m_nt_resp );
m_success = std::move(other.m_success );
m_phase = std::move(other.m_phase );
assert(std::addressof(m_cfg ) == std::addressof(other.m_cfg )); // Move method within same configuration only!
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method within same credentials only!
(method&)*this = std::move(other );
m_cp = std::move(other.m_cp );
m_challenge_server = std::move(other.m_challenge_server);
m_challenge_client = std::move(other.m_challenge_client);
m_ident = std::move(other.m_ident );
m_nt_resp = std::move(other.m_nt_resp );
m_success = std::move(other.m_success );
m_phase = std::move(other.m_phase );
m_packet_res = std::move(other.m_packet_res );
}
return *this;
@ -76,13 +81,17 @@ void eap::method_mschapv2::begin_session(
_In_ HANDLE hTokenImpersonateUser,
_In_opt_ DWORD dwMaxSendPacketSize)
{
method_noneap::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
// Presume authentication will fail with generic protocol failure. (Pesimist!!!)
// We will reset once we get get_result(Success) call.
m_cfg.m_last_status = config_method::status_auth_failed;
m_cfg.m_last_msg.clear();
// Create cryptographics provider for support needs (client challenge ...).
if (!m_cp.create(NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
throw win_runtime_error(__FUNCTION__ " Error creating cryptographics provider.");
m_module.log_event(&EAPMETHOD_METHOD_HANDSHAKE_START2, event_data((unsigned int)eap_type_legacy_mschapv2), event_data::blank);
m_phase = phase_init;
}
@ -93,18 +102,16 @@ EapPeerMethodResponseAction eap::method_mschapv2::process_request_packet(
{
assert(pReceivedPacket || dwReceivedPacketSize == 0);
m_module.log_event(&EAPMETHOD_PACKET_RECV, event_data((unsigned int)eap_type_legacy_mschapv2), event_data((unsigned int)dwReceivedPacketSize), event_data::blank);
switch (m_phase) {
case phase_init: {
// Convert username to UTF-8.
sanitizing_string identity_utf8;
WideCharToMultiByte(CP_UTF8, 0, m_cred.m_identity.c_str(), (int)m_cred.m_identity.length(), identity_utf8, NULL, NULL);
m_module.log_event(&EAPMETHOD_METHOD_HANDSHAKE_START2, event_data((unsigned int)eap_type_legacy_mschapv2), event_data::blank);
// Randomize Peer-Challenge.
m_challenge_client.randomize(m_cp);
// Calculate NT-Response.
sanitizing_string identity_utf8;
WideCharToMultiByte(CP_UTF8, 0, m_cred.m_identity.c_str(), (int)m_cred.m_identity.length(), identity_utf8, NULL, NULL);
m_nt_resp = nt_response(m_cp, m_challenge_server, m_challenge_client, identity_utf8.c_str(), m_cred.m_password.c_str());
// Prepare MS-CHAP2-Response.
@ -122,9 +129,10 @@ EapPeerMethodResponseAction eap::method_mschapv2::process_request_packet(
response.insert(response.end(), reinterpret_cast<const unsigned char*>(&m_nt_resp), reinterpret_cast<const unsigned char*>(&m_nt_resp + 1)); // NT-Response
// Diameter AVP (User-Name=1, MS-CHAP-Challenge=11/311, MS-CHAP2-Response=25/311)
append_avp( 1, diameter_avp_flag_mandatory, identity_utf8.data(), (unsigned int)identity_utf8.size() );
append_avp(11, 311, diameter_avp_flag_mandatory, reinterpret_cast<const unsigned char*>(&m_challenge_server) , (unsigned int)sizeof(m_challenge_server));
append_avp(25, 311, diameter_avp_flag_mandatory, response.data() , (unsigned int)response.size() );
m_packet_res.clear();
diameter_avp_append( 1, diameter_avp_flag_mandatory, identity_utf8.data(), (unsigned int)identity_utf8.size() , m_packet_res);
diameter_avp_append(11, 311, diameter_avp_flag_mandatory, reinterpret_cast<const unsigned char*>(&m_challenge_server) , (unsigned int)sizeof(m_challenge_server), m_packet_res);
diameter_avp_append(25, 311, diameter_avp_flag_mandatory, response.data() , (unsigned int)response.size() , m_packet_res);
m_phase = phase_challenge_server;
m_cfg.m_last_status = config_method::status_cred_invalid; // Blame credentials if we fail beyond this point.
@ -133,9 +141,16 @@ EapPeerMethodResponseAction eap::method_mschapv2::process_request_packet(
case phase_challenge_server: {
process_packet(pReceivedPacket, dwReceivedPacketSize);
if (m_success)
if (m_success) {
m_module.log_event(&EAPMETHOD_METHOD_SUCCESS, event_data((unsigned int)eap_type_legacy_mschapv2), event_data::blank);
m_phase = phase_finished;
return EapPeerMethodResponseActionNone;
// Acknowledge the authentication by sending an empty response packet.
m_packet_res.clear();
return EapPeerMethodResponseActionSend;
} else
return EapPeerMethodResponseActionDiscard;
}
case phase_finished:
@ -147,6 +162,35 @@ EapPeerMethodResponseAction eap::method_mschapv2::process_request_packet(
}
void eap::method_mschapv2::get_response_packet(
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max)
{
if (m_packet_res.size() > size_max)
throw invalid_argument(string_printf(__FUNCTION__ " This method does not support packet fragmentation, but the data size is too big to fit in one packet (packet: %u, maximum: %u).", m_packet_res.size(), size_max).c_str());
packet.assign(m_packet_res.begin(), m_packet_res.end());
}
void eap::method_mschapv2::get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult)
{
assert(pResult);
method::get_result(reason, pResult);
if (reason == EapPeerMethodResultSuccess)
m_cfg.m_last_status = config_method::status_success;
// Always ask EAP host to save the connection data. And it will save it *only* when we report "success".
// Don't worry. EapHost is well aware of failed authentication condition.
pResult->fSaveConnectionData = TRUE;
pResult->fIsSuccess = TRUE;
}
void eap::method_mschapv2::process_packet(_In_bytecount_(size_pck) const void *_pck, _In_ size_t size_pck)
{
for (const unsigned char *pck = reinterpret_cast<const unsigned char*>(_pck), *pck_end = pck + size_pck; pck < pck_end; ) {

View File

@ -36,7 +36,7 @@ namespace eap
namespace eap
{
class method_pap : public method_noneap
class method_pap : public method
{
WINSTD_NONCOPYABLE(method_pap)
@ -48,7 +48,7 @@ namespace eap
/// \param[in] cfg Method configuration
/// \param[in] cred User credentials
///
method_pap(_In_ module &module, _In_ config_method_pap &cfg, _In_ credentials_pass &cred);
method_pap(_In_ module &mod, _In_ config_method_pap &cfg, _In_ credentials_pass &cred);
///
/// Moves a PAP method
@ -89,15 +89,36 @@ namespace eap
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize);
///
/// Obtains a response packet from the EAP method.
///
/// \sa [EapPeerGetResponsePacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363610.aspx)
///
virtual void get_response_packet(
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max = MAXDWORD);
///
/// Obtains the result of an authentication session from the EAP method.
///
/// \sa [EapPeerGetResult function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363611.aspx)
///
virtual void get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult);
/// @}
protected:
credentials_pass &m_cred; ///< Method user credentials
config_method_pap &m_cfg; ///< Method configuration
credentials_pass &m_cred; ///< Method user credentials
enum {
phase_unknown = -1, ///< Unknown phase
phase_init = 0, ///< Handshake initialize
phase_finished, ///< Connection shut down
} m_phase; ///< What phase is our communication at?
phase_unknown = -1, ///< Unknown phase
phase_init = 0, ///< Handshake initialize
phase_finished, ///< Connection shut down
} m_phase; ///< What phase is our communication at?
sanitizing_blob m_packet_res; ///< Response packet
};
}

View File

@ -28,18 +28,21 @@ using namespace winstd;
// eap::method_pap
//////////////////////////////////////////////////////////////////////
eap::method_pap::method_pap(_In_ module &module, _In_ config_method_pap &cfg, _In_ credentials_pass &cred) :
eap::method_pap::method_pap(_In_ module &mod, _In_ config_method_pap &cfg, _In_ credentials_pass &cred) :
m_cfg(cfg),
m_cred(cred),
m_phase(phase_unknown),
method_noneap(module, cfg, cred)
method(mod)
{
}
eap::method_pap::method_pap(_Inout_ method_pap &&other) :
m_cred ( other.m_cred ),
m_phase (std::move(other.m_phase )),
method_noneap(std::move(other ))
m_cfg ( other.m_cfg ),
m_cred ( other.m_cred ),
m_phase (std::move(other.m_phase )),
m_packet_res(std::move(other.m_packet_res)),
method (std::move(other ))
{
}
@ -47,9 +50,11 @@ eap::method_pap::method_pap(_Inout_ method_pap &&other) :
eap::method_pap& eap::method_pap::operator=(_Inout_ method_pap &&other)
{
if (this != std::addressof(other)) {
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method with same credentials only!
(method_noneap&)*this = std::move(other );
m_phase = std::move(other.m_phase );
assert(std::addressof(m_cfg ) == std::addressof(other.m_cfg )); // Move method within same configuration only!
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method within same credentials only!
(method&)*this = std::move(other );
m_phase = std::move(other.m_phase );
m_packet_res = std::move(other.m_packet_res);
}
return *this;
@ -62,9 +67,13 @@ void eap::method_pap::begin_session(
_In_ HANDLE hTokenImpersonateUser,
_In_opt_ DWORD dwMaxSendPacketSize)
{
method_noneap::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
// Presume authentication will fail with generic protocol failure. (Pesimist!!!)
// We will reset once we get get_result(Success) call.
m_cfg.m_last_status = config_method::status_auth_failed;
m_cfg.m_last_msg.clear();
m_module.log_event(&EAPMETHOD_METHOD_HANDSHAKE_START2, event_data((unsigned int)eap_type_legacy_pap), event_data::blank);
m_phase = phase_init;
}
@ -74,12 +83,12 @@ EapPeerMethodResponseAction eap::method_pap::process_request_packet(
_In_ DWORD dwReceivedPacketSize)
{
UNREFERENCED_PARAMETER(pReceivedPacket);
assert(pReceivedPacket || dwReceivedPacketSize == 0);
m_module.log_event(&EAPMETHOD_PACKET_RECV, event_data((unsigned int)eap_type_legacy_pap), event_data((unsigned int)dwReceivedPacketSize), event_data::blank);
UNREFERENCED_PARAMETER(dwReceivedPacketSize);
switch (m_phase) {
case phase_init: {
m_module.log_event(&EAPMETHOD_METHOD_HANDSHAKE_START2, event_data((unsigned int)eap_type_legacy_pap), event_data::blank);
// Convert username and password to UTF-8.
sanitizing_string identity_utf8, password_utf8;
WideCharToMultiByte(CP_UTF8, 0, m_cred.m_identity.c_str(), (int)m_cred.m_identity.length(), identity_utf8, NULL, NULL);
@ -90,8 +99,9 @@ EapPeerMethodResponseAction eap::method_pap::process_request_packet(
password_utf8.append(padding_password_ex, 0);
// Diameter AVP (User-Name=1, User-Password=2)
append_avp(1, diameter_avp_flag_mandatory, identity_utf8.data(), (unsigned int)identity_utf8.size());
append_avp(2, diameter_avp_flag_mandatory, password_utf8.data(), (unsigned int)password_utf8.size());
m_packet_res.clear();
diameter_avp_append(1, diameter_avp_flag_mandatory, identity_utf8.data(), (unsigned int)identity_utf8.size(), m_packet_res);
diameter_avp_append(2, diameter_avp_flag_mandatory, password_utf8.data(), (unsigned int)password_utf8.size(), m_packet_res);
m_phase = phase_finished;
m_cfg.m_last_status = config_method::status_cred_invalid; // Blame credentials if we fail beyond this point.
@ -105,3 +115,32 @@ EapPeerMethodResponseAction eap::method_pap::process_request_packet(
throw invalid_argument(string_printf(__FUNCTION__ " Unknown phase (phase %u).", m_phase).c_str());
}
}
void eap::method_pap::get_response_packet(
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max)
{
if (m_packet_res.size() > size_max)
throw invalid_argument(string_printf(__FUNCTION__ " This method does not support packet fragmentation, but the data size is too big to fit in one packet (packet: %u, maximum: %u).", m_packet_res.size(), size_max).c_str());
packet.assign(m_packet_res.begin(), m_packet_res.end());
}
void eap::method_pap::get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult)
{
assert(pResult);
method::get_result(reason, pResult);
if (reason == EapPeerMethodResultSuccess)
m_cfg.m_last_status = config_method::status_success;
// Always ask EAP host to save the connection data. And it will save it *only* when we report "success".
// Don't worry. EapHost is well aware of failed authentication condition.
pResult->fSaveConnectionData = TRUE;
pResult->fIsSuccess = TRUE;
}

View File

@ -81,13 +81,11 @@
<ItemGroup>
<ClInclude Include="..\include\Config.h" />
<ClInclude Include="..\include\Credentials.h" />
<ClInclude Include="..\include\Method.h" />
<ClInclude Include="..\include\TLS.h" />
<ClInclude Include="..\src\StdAfx.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\Config.cpp" />
<ClCompile Include="..\src\Method.cpp" />
<ClCompile Include="..\src\StdAfx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>

View File

@ -20,9 +20,6 @@
<ClInclude Include="..\include\Credentials.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\Method.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\TLS.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -37,9 +34,6 @@
<ClCompile Include="..\src\Credentials.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\Method.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\TLS.cpp">
<Filter>Source Files</Filter>
</ClCompile>

View File

@ -45,7 +45,6 @@ namespace eap
#pragma once
#include "Credentials.h"
#include "Method.h"
#include "TLS.h"
#include "../../EAPBase/include/Config.h"
@ -183,11 +182,5 @@ namespace eap
public:
std::list<winstd::cert_context> m_trusted_root_ca; ///< Trusted root CAs
std::list<std::wstring> m_server_names; ///< Acceptable authenticating server names
#if EAP_TLS < EAP_TLS_SCHANNEL
// Following members are used for session resumptions. They are not exported/imported to XML.
sanitizing_blob m_session_id; ///< TLS session ID
tls_master_secret m_master_secret; ///< TLS master secret
#endif
};
}

View File

@ -1,490 +0,0 @@
/*
Copyright 2015-2016 Amebis
Copyright 2016 GÉANT
This file is part of GÉANTLink.
GÉANTLink is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
GÉANTLink is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GÉANTLink. If not, see <http://www.gnu.org/licenses/>.
*/
namespace eap
{
///
/// EAP-TLS method
///
class method_tls;
}
#pragma once
#include "Config.h"
#include "Credentials.h"
#include "TLS.h"
#include "../../EAPBase/include/Method.h"
#include <WinStd/Crypt.h>
#include <WinStd/Sec.h>
#include <list>
#include <vector>
namespace eap
{
class method_tls : public method
{
WINSTD_NONCOPYABLE(method_tls)
public:
#pragma pack(push)
#pragma pack(1)
///
/// TLS message
///
struct message_header
{
tls_message_type_t type; ///< Message type (one of `message_type_t` constants)
tls_version version; ///< SSL/TLS version
unsigned char length[2]; ///< Message length (in network byte order)
};
#pragma pack(pop)
public:
///
/// Constructs an EAP-TLS method
///
/// \param[in] mod EAP module to use for global services
/// \param[in] cfg Method configuration
/// \param[in] cred User credentials
///
method_tls(_In_ module &module, _In_ config_method_tls &cfg, _In_ credentials_tls &cred);
///
/// Moves an EAP-TLS method
///
/// \param[in] other EAP-TLS method to move from
///
method_tls(_Inout_ method_tls &&other);
///
/// Moves an EAP-TLS method
///
/// \param[in] other EAP-TLS method to move from
///
/// \returns Reference to this object
///
method_tls& operator=(_Inout_ method_tls &&other);
/// \name Packet processing
/// @{
///
/// Starts an EAP authentication session on the peer EapHost using the EAP method.
///
/// \sa [EapPeerBeginSession function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363600.aspx)
///
virtual void begin_session(
_In_ DWORD dwFlags,
_In_ const EapAttributes *pAttributeArray,
_In_ HANDLE hTokenImpersonateUser,
_In_opt_ DWORD dwMaxSendPacketSize = MAXDWORD);
///
/// Processes a packet received by EapHost from a supplicant.
///
/// \sa [EapPeerProcessRequestPacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363621.aspx)
///
virtual EapPeerMethodResponseAction process_request_packet(
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize);
///
/// Obtains a response packet from the EAP method.
///
/// \sa [EapPeerGetResponsePacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363610.aspx)
///
virtual void get_response_packet(
_Inout_bytecap_(*dwSendPacketSize) void *pSendPacket,
_Inout_ DWORD *pdwSendPacketSize);
///
/// Obtains the result of an authentication session from the EAP method.
///
/// \sa [EapPeerGetResult function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363611.aspx)
///
virtual void get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult);
/// @}
protected:
#if EAP_TLS < EAP_TLS_SCHANNEL
/// \name Client handshake message generation
/// @{
///
/// Makes a TLS client hello message
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.4.1.2. Client Hello)](https://tools.ietf.org/html/rfc5246#section-7.4.1.2)
///
/// \returns Client hello message
///
sanitizing_blob make_client_hello();
///
/// Makes a TLS client certificate message
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.4.6. Client Certificate)](https://tools.ietf.org/html/rfc5246#section-7.4.6)
///
/// \returns Client certificate message
///
sanitizing_blob make_client_cert() const;
///
/// Makes a TLS client key exchange message
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.4.7. Client Key Exchange Message )](https://tools.ietf.org/html/rfc5246#section-7.4.7)
///
/// \param[in] pms Pre-master secret
///
/// \returns Client key exchange message
///
sanitizing_blob make_client_key_exchange(_In_ const tls_master_secret &pms) const;
///
/// Makes a TLS finished message
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter A.1. Record Layer)](https://tools.ietf.org/html/rfc5246#appendix-A.1)
///
/// \returns Change cipher spec
///
eap::sanitizing_blob make_finished() const;
/// @}
/// \name Client/Server handshake hashing
/// @{
///
/// Hashes handshake message for "finished" message validation.
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.4.9. Finished)](https://tools.ietf.org/html/rfc5246#section-7.4.9)
///
/// \param[in] data Data to hash
/// \param[in] size \p data size in bytes
///
inline void hash_handshake(_In_count_(size) const void *data, _In_ size_t size)
{
CryptHashData(m_hash_handshake_msgs_md5 , (const BYTE*)data, (DWORD)size, 0);
CryptHashData(m_hash_handshake_msgs_sha1 , (const BYTE*)data, (DWORD)size, 0);
CryptHashData(m_hash_handshake_msgs_sha256, (const BYTE*)data, (DWORD)size, 0);
}
///
/// Hashes handshake message for "finished" message validation.
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.4.9. Finished)](https://tools.ietf.org/html/rfc5246#section-7.4.9)
///
/// \param[in] data Data to hash
/// \param[in] size \p data size in bytes
///
template<class _Ty, class _Ax>
inline void hash_handshake(_In_ const std::vector<_Ty, _Ax> &data)
{
hash_handshake(data.data(), data.size() * sizeof(_Ty));
}
/// @}
///
/// Makes a TLS message
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter A.1. Record Layer)](https://tools.ietf.org/html/rfc5246#appendix-A.1)
///
/// \param[in] type Message type
/// \param[inout] data Message data contents
///
/// \returns TLS message message
///
eap::sanitizing_blob make_message(_In_ tls_message_type_t type, _Inout_ sanitizing_blob &&data);
/// @}
#endif
/// \name Key derivation
/// @{
///
/// Generates master session key
///
/// \sa [The EAP-TLS Authentication Protocol (Chapter 2.3. Key Hierarchy)](https://tools.ietf.org/html/rfc5216#section-2.3)
///
virtual void derive_msk();
///
/// Generates keying material for inner authentication
///
virtual void derive_challenge();
/// @}
#if EAP_TLS < EAP_TLS_SCHANNEL
/// \name Server message processing
/// @{
///
/// Processes messages in a TLS packet
///
/// \param[in] pck Packet data
/// \param[in] size_pck \p pck size in bytes
///
void process_packet(_In_bytecount_(size_pck) const void *pck, _In_ size_t size_pck);
///
/// Processes a TLS change_cipher_spec message
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.1. Change Cipher Spec Protocol)](https://tools.ietf.org/html/rfc5246#section-7.1)
///
/// \param[in] msg TLS change_cipher_spec message data
/// \param[in] size_msg TLS change_cipher_spec message data size
///
virtual void process_change_cipher_spec(_In_bytecount_(size_msg) const void *msg, _In_ size_t size_msg);
///
/// Processes a TLS alert message
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.2. Alert Protocol)](https://tools.ietf.org/html/rfc5246#section-7.2)
///
/// \param[in] msg TLS alert message data
/// \param[in] size_msg TLS alert message data size
///
virtual void process_alert(_In_bytecount_(size_msg) const void *msg, _In_ size_t size_msg);
///
/// Processes a TLS handshake message
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.4. Handshake Protocol)](https://tools.ietf.org/html/rfc5246#section-7.4)
///
/// \param[in] msg TLS handshake message data
/// \param[in] size_msg TLS handshake message data size
///
virtual void process_handshake(_In_bytecount_(size_msg) const void *msg, _In_ size_t size_msg);
#else
///
/// Process handshake
///
EapPeerMethodResponseAction process_handshake();
#endif
///
/// Process application data
///
EapPeerMethodResponseAction process_application_data();
///
/// Processes a TLS application_data message
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 10. Application Data Protocol)](https://tools.ietf.org/html/rfc5246#section-10)
///
/// \param[in] msg TLS application_data message data
/// \param[in] size_msg TLS application_data message data size
///
virtual EapPeerMethodResponseAction process_application_data(_In_bytecount_(size_msg) const void *msg, _In_ size_t size_msg);
/// @}
#if EAP_TLS < EAP_TLS_SCHANNEL_FULL
///
/// Verifies server's certificate if trusted by configuration
///
void verify_server_trust() const;
#endif
#if EAP_TLS < EAP_TLS_SCHANNEL
/// \name Encryption
/// @{
///
/// Encrypt TLS message
///
/// \param[in] type Message type
/// \param[inout] data TLS message to encrypt
///
void encrypt_message(_In_ tls_message_type_t type, _Inout_ sanitizing_blob &data);
///
/// Decrypt TLS message
///
/// \param[in] type Original message type for HMAC verification
/// \param[inout] data TLS message to decrypt
///
void decrypt_message(_In_ tls_message_type_t type, _Inout_ sanitizing_blob &data);
///
/// Returns maximum netto size of a message for a given TLS message size
///
/// \param[in] size_message Size of the final TLS message
///
/// \returns Netto size of message data
///
size_t get_max_message(_In_ size_t size_message) const;
/// @}
/// \name Pseudo-random generation
/// @{
///
/// Calculates pseudo-random P_hash data defined in RFC 5246
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.1 (Chapter 5. HMAC and the Pseudorandom Function)](https://tools.ietf.org/html/rfc4346#section-5)
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 5. HMAC and the Pseudorandom Function)](https://tools.ietf.org/html/rfc5246#section-5)
///
/// \param[in] cp Handle of the cryptographics provider
/// \param[in] alg Hashing Algorithm to use (CALG_TLS1PRF = combination of MD5 and SHA-1, CALG_SHA_256...)
/// \param[in] secret Hashing secret key
/// \param[in] seed Random seed
/// \param[in] size_seed \p seed size
/// \param[in] size Number of bytes of pseudo-random data required
///
/// \returns Generated pseudo-random data (\p size bytes)
///
static sanitizing_blob prf(
_In_ HCRYPTPROV cp,
_In_ ALG_ID alg,
_In_ const tls_master_secret &secret,
_In_bytecount_(size_seed) const void *seed,
_In_ size_t size_seed,
_In_ size_t size);
///
/// Calculates pseudo-random P_hash data defined in RFC 5246
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.1 (Chapter 5. HMAC and the Pseudorandom Function)](https://tools.ietf.org/html/rfc4346#section-5)
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 5. HMAC and the Pseudorandom Function)](https://tools.ietf.org/html/rfc5246#section-5)
///
/// \param[in] cp Handle of the cryptographics provider
/// \param[in] alg Hashing Algorithm to use (CALG_TLS1PRF = combination of MD5 and SHA-1, CALG_SHA_256...)
/// \param[in] secret Hashing secret key
/// \param[in] seed Random seed
/// \param[in] size Number of bytes of pseudo-random data required
///
/// \returns Generated pseudo-random data (\p size bytes)
///
template<class _Ty, class _Ax>
inline static sanitizing_blob prf(
_In_ HCRYPTPROV cp,
_In_ ALG_ID alg,
_In_ const tls_master_secret &secret,
_In_ const std::vector<_Ty, _Ax> &seed,
_In_ size_t size)
{
return prf(cp, alg, secret, seed.data(), seed.size() * sizeof(_Ty), size);
}
/// @}
///
/// Creates a key
///
/// \sa [How to export and import plain text session keys by using CryptoAPI](https://support.microsoft.com/en-us/kb/228786)
///
/// \param[in] cp Handle of the cryptographics provider
/// \param[in] alg Key algorithm
/// \param[in] key Key that decrypts \p secret
/// \param[in] secret Key data
/// \param[in] size_secret \p secret size
///
/// \returns Key
///
HCRYPTKEY create_key(
_In_ HCRYPTPROV cp,
_In_ ALG_ID alg,
_In_ HCRYPTKEY key,
_In_bytecount_(size_secret) const void *secret,
_In_ size_t size_secret);
#endif
protected:
config_method_tls &m_cfg; ///< EAP-TLS method configuration
credentials_tls &m_cred; ///< EAP-TLS user credentials
HANDLE m_user_ctx; ///< Handle to user context
packet_tls m_packet_req; ///< Request packet
packet_tls m_packet_res; ///< Response packet
tls_random m_key_mppe_client; ///< MS-MPPE-Recv-Key
tls_random m_key_mppe_server; ///< MS-MPPE-Send-Key
#if EAP_TLS < EAP_TLS_SCHANNEL
winstd::crypt_prov m_cp; ///< Cryptography provider for general services
winstd::crypt_prov m_cp_enc_client; ///< Cryptography provider for encryption
winstd::crypt_prov m_cp_enc_server; ///< Cryptography provider for encryption
winstd::crypt_key m_key_exp1; ///< Key for importing derived keys
tls_version m_tls_version; ///< TLS version in use
ALG_ID m_alg_prf; ///< Pseudo-random function algorithm in use
tls_conn_state m_state_client; ///< Client TLS connection state
tls_conn_state m_state_client_pending; ///< Client TLS connection state (pending)
tls_conn_state m_state_server; ///< Server TLS connection state
tls_conn_state m_state_server_pending; ///< Server TLS connection state (pending)
tls_master_secret m_master_secret; ///< TLS master secret
tls_random m_random_client; ///< Client random
tls_random m_random_server; ///< Server random
sanitizing_blob m_session_id; ///< TLS session ID
bool m_session_resumed; ///< Did TLS session resume?
std::list<winstd::cert_context> m_server_cert_chain; ///< Server certificate chain
winstd::crypt_hash m_hash_handshake_msgs_md5; ///< Running MD5 hash of handshake messages
winstd::crypt_hash m_hash_handshake_msgs_sha1; ///< Running SHA-1 hash of handshake messages
winstd::crypt_hash m_hash_handshake_msgs_sha256; ///< Running SHA-256 hash of handshake messages
tls_handshake_flags m_handshake; ///< Handshake flags (map of handshake messages received)
enum {
phase_unknown = -1, ///< Unknown phase
phase_client_hello = 0, ///< Send client hello
phase_server_hello, ///< Wait for server hello
phase_change_cipher_spec, ///< Wait for change cipher spec
phase_application_data ///< Exchange application data
} m_phase; ///< What phase is our communication at?
unsigned __int64 m_seq_num_client; ///< Sequence number for encrypting
unsigned __int64 m_seq_num_server; ///< Sequence number for decrypting
#else
winstd::tstring m_sc_target_name; ///< Schannel target name
winstd::sec_credentials m_sc_cred; ///< Schannel client credentials
std::vector<unsigned char> m_sc_queue; ///< TLS data queue
winstd::sec_context m_sc_ctx; ///< Schannel context
enum {
phase_unknown = -1, ///< Unknown phase
phase_handshake_init = 0, ///< Handshake initialize
phase_handshake_cont, ///< Handshake continue
phase_application_data, ///< Exchange application data
phase_shutdown, ///< Connection shut down
} m_phase; ///< What phase is our communication at?
#endif
};
}

View File

@ -75,10 +75,6 @@ eap::config_method_tls::config_method_tls(_In_ module &mod, _In_ unsigned int le
eap::config_method_tls::config_method_tls(_In_ const config_method_tls &other) :
m_trusted_root_ca(other.m_trusted_root_ca),
m_server_names(other.m_server_names),
#if EAP_TLS < EAP_TLS_SCHANNEL
m_session_id(other.m_session_id),
m_master_secret(other.m_master_secret),
#endif
config_method_with_cred(other)
{
}
@ -87,10 +83,6 @@ eap::config_method_tls::config_method_tls(_In_ const config_method_tls &other) :
eap::config_method_tls::config_method_tls(_Inout_ config_method_tls &&other) :
m_trusted_root_ca(std::move(other.m_trusted_root_ca)),
m_server_names(std::move(other.m_server_names)),
#if EAP_TLS < EAP_TLS_SCHANNEL
m_session_id(std::move(other.m_session_id)),
m_master_secret(std::move(other.m_master_secret)),
#endif
config_method_with_cred(std::move(other))
{
}
@ -102,10 +94,6 @@ eap::config_method_tls& eap::config_method_tls::operator=(_In_ const config_meth
(config_method_with_cred&)*this = other;
m_trusted_root_ca = other.m_trusted_root_ca;
m_server_names = other.m_server_names;
#if EAP_TLS < EAP_TLS_SCHANNEL
m_session_id = other.m_session_id;
m_master_secret = other.m_master_secret;
#endif
}
return *this;
@ -118,10 +106,6 @@ eap::config_method_tls& eap::config_method_tls::operator=(_Inout_ config_method_
(config_method_with_cred&&)*this = std::move(other);
m_trusted_root_ca = std::move(other.m_trusted_root_ca);
m_server_names = std::move(other.m_server_names);
#if EAP_TLS < EAP_TLS_SCHANNEL
m_session_id = std::move(other.m_session_id);
m_master_secret = std::move(other.m_master_secret);
#endif
}
return *this;
@ -250,10 +234,6 @@ void eap::config_method_tls::operator<<(_Inout_ cursor_out &cursor) const
config_method_with_cred::operator<<(cursor);
cursor << m_trusted_root_ca;
cursor << m_server_names ;
#if EAP_TLS < EAP_TLS_SCHANNEL
cursor << m_session_id ;
cursor << m_master_secret ;
#endif
}
@ -262,14 +242,7 @@ size_t eap::config_method_tls::get_pk_size() const
return
config_method_with_cred::get_pk_size() +
pksizeof(m_trusted_root_ca) +
pksizeof(m_server_names )
#if EAP_TLS < EAP_TLS_SCHANNEL
+
pksizeof(m_session_id ) +
pksizeof(m_master_secret );
#else
;
#endif
pksizeof(m_server_names );
}
@ -278,10 +251,6 @@ void eap::config_method_tls::operator>>(_Inout_ cursor_in &cursor)
config_method_with_cred::operator>>(cursor);
cursor >> m_trusted_root_ca;
cursor >> m_server_names ;
#if EAP_TLS < EAP_TLS_SCHANNEL
cursor >> m_session_id ;
cursor >> m_master_secret ;
#endif
}

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,6 @@
#include "../include/Config.h"
#include "../include/Credentials.h"
#include "../include/Method.h"
#include "../include/TLS.h"
#include "../../EAPBase/include/EAPXML.h"

View File

@ -428,7 +428,7 @@ void eap::tls_conn_state::set_cipher(_In_ const unsigned char cipher[2])
m_size_mac_key = 384/8; // SHA-384
m_size_mac_hash = 384/8; // SHA-384
} else
throw win_runtime_error(ERROR_NOT_SUPPORTED, string_printf(__FUNCTION__ " Unknown cipher (received 0x%02x%02x).", cipher[0], cipher[1]));
throw win_runtime_error(ERROR_NOT_SUPPORTED, string_printf(__FUNCTION__ " Unknown cipher (received: 0x%02x%02x).", cipher[0], cipher[1]));
}

View File

@ -172,9 +172,6 @@ public:
protected:
/// \cond internal
virtual void OnInitDialog(wxInitDialogEvent& event);
#if EAP_TLS < EAP_TLS_SCHANNEL
virtual bool TransferDataFromWindow();
#endif
/// \endcond
protected:

View File

@ -339,23 +339,3 @@ void wxTLSConfigPanel::OnInitDialog(wxInitDialogEvent& event)
if (m_credentials)
m_credentials->GetEventHandler()->ProcessEvent(event);
}
#if EAP_TLS < EAP_TLS_SCHANNEL
bool wxTLSConfigPanel::TransferDataFromWindow()
{
wxCHECK(wxPanel::TransferDataFromWindow(), false);
if (!m_prov.m_read_only) {
// This is not a provider-locked configuration. The data will get saved.
// Reset session ID and master secret to force clean connect next time.
m_cfg.m_session_id.clear();
m_cfg.m_master_secret.clear();
}
return true;
}
#endif

View File

@ -21,7 +21,17 @@
namespace eap
{
///
/// EAP-TTLS method
/// EAP-(T)TLS class defragging method tunnel
///
class method_defrag;
///
/// Diameter EAP-Message tunnel method
///
class method_eapmsg;
///
/// TTLS method
///
class method_ttls;
}
@ -32,37 +42,203 @@ namespace eap
#include "Credentials.h"
#include "TTLS.h"
#include "../../TLS/include/Method.h"
#include "../../EAPBase/include/Method.h"
#include <WinStd/Sec.h>
namespace eap
{
class method_ttls : public method_tls
class method_defrag : public method_tunnel
{
WINSTD_NONCOPYABLE(method_defrag)
public:
#pragma warning(push)
#pragma warning(disable: 4480)
///
/// EAP-(T)TLS request packet flags
///
/// \sa [The EAP-TLS Authentication Protocol (Chapter: 3.1 EAP-TLS Request Packet)](https://tools.ietf.org/html/rfc5216#section-3.1)
/// \sa [The EAP-TTLS Authentication Protocol Version 0 (Chapter: 9.1. Packet Format)](https://tools.ietf.org/html/rfc5281#section-9.1)
///
enum flags_req_t : unsigned char {
flags_req_length_incl = 0x80, ///< Length included
flags_req_more_frag = 0x40, ///< More fragments
flags_req_start = 0x20, ///< Start
flags_req_ver_mask = 0x07, ///< Version mask
};
///
/// EAP-(T)TLS response packet flags
///
/// \sa [The EAP-TLS Authentication Protocol (Chapter: 3.2 EAP-TLS Response Packet)](https://tools.ietf.org/html/rfc5216#section-3.2)
/// \sa [The EAP-TTLS Authentication Protocol Version 0 (Chapter: 9.1. Packet Format)](https://tools.ietf.org/html/rfc5281#section-9.1)
///
enum flags_res_t : unsigned char {
flags_res_length_incl = 0x80, ///< Length included
flags_res_more_frag = 0x40, ///< More fragments
flags_res_ver_mask = 0x07, ///< Version mask
};
#pragma warning(pop)
public:
///
/// Constructs a method
///
/// \param[in] mod Module to use for global services
/// \param[in] inner Inner method
///
method_defrag(_In_ module &mod, _In_ method *inner);
///
/// Moves a method
///
/// \param[in] other Method to move from
///
method_defrag(_Inout_ method_defrag &&other);
///
/// Moves a method
///
/// \param[in] other Method to move from
///
/// \returns Reference to this object
///
method_defrag& operator=(_Inout_ method_defrag &&other);
/// \name Packet processing
/// @{
///
/// Processes a packet received by EapHost from a supplicant.
///
/// \sa [EapPeerProcessRequestPacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363621.aspx)
///
virtual EapPeerMethodResponseAction process_request_packet(
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize);
///
/// Obtains a response packet from the EAP method.
///
/// \sa [EapPeerGetResponsePacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363610.aspx)
///
virtual void get_response_packet(
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max = MAXDWORD);
protected:
DWORD m_size_frag_max; ///< Maximum size of a fragment
sanitizing_blob m_data_req; ///< Data in request
sanitizing_blob m_data_res; ///< Data in response
bool m_send_res; ///< Are we sending a response?
};
class method_eapmsg : public method_tunnel
{
public:
///
/// Constructs a method
///
/// \param[in] mod Module to use for global services
/// \param[in] identity User identity
/// \param[in] inner Inner method
///
method_eapmsg(_In_ module &mod, _In_ const wchar_t *identity, _In_ method *inner);
///
/// Moves a method
///
/// \param[in] other Method to move from
///
method_eapmsg(_Inout_ method_eapmsg &&other);
///
/// Moves a method
///
/// \param[in] other Method to move from
///
/// \returns Reference to this object
///
method_eapmsg& operator=(_Inout_ method_eapmsg &&other);
/// \name Packet processing
/// @{
///
/// Starts an EAP authentication session on the peer EapHost using the EAP method.
///
/// \sa [EapPeerBeginSession function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363600.aspx)
///
virtual void begin_session(
_In_ DWORD dwFlags,
_In_ const EapAttributes *pAttributeArray,
_In_ HANDLE hTokenImpersonateUser,
_In_opt_ DWORD dwMaxSendPacketSize = MAXDWORD);
///
/// Processes a packet received by EapHost from a supplicant.
///
/// \sa [EapPeerProcessRequestPacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363621.aspx)
///
virtual EapPeerMethodResponseAction process_request_packet(
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize);
///
/// Obtains a response packet from the EAP method.
///
/// \sa [EapPeerGetResponsePacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363610.aspx)
///
virtual void get_response_packet(
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max = MAXDWORD);
/// @}
protected:
std::wstring m_identity; ///< User identity
enum {
phase_unknown = -1, ///< Unknown phase
phase_identity = 0, ///< Send identity
phase_finished, ///< Connection shut down
} m_phase; ///< What phase is our communication at?
sanitizing_blob m_packet_res; ///< Response packet
};
class method_ttls : public method_tunnel
{
WINSTD_NONCOPYABLE(method_ttls)
public:
///
/// Constructs an EAP-TTLS method
/// Constructs an TTLS method
///
/// \param[in] mod EAP module to use for global services
/// \param[in] cfg Method configuration
/// \param[in] cred User credentials
/// \param[in] mod EAP module to use for global services
/// \param[in] cfg Method configuration
/// \param[in] cred User credentials
/// \param[in] inner Inner method
///
method_ttls(_In_ module &module, _In_ config_method_ttls &cfg, _In_ credentials_ttls &cred);
method_ttls(_In_ module &mod, _In_ config_method_ttls &cfg, _In_ credentials_ttls &cred, _In_ method *inner);
///
/// Moves an EAP-TTLS method
/// Moves an TTLS method
///
/// \param[in] other EAP-TTLS method to move from
/// \param[in] other TTLS method to move from
///
method_ttls(_Inout_ method_ttls &&other);
///
/// Moves an EAP-TTLS method
/// Moves an TTLS method
///
/// \param[in] other EAP-TTLS method to move from
/// \param[in] other TTLS method to move from
///
/// \returns Reference to this object
///
@ -82,13 +258,6 @@ namespace eap
_In_ HANDLE hTokenImpersonateUser,
_In_opt_ DWORD dwMaxSendPacketSize = MAXDWORD);
///
/// Ends an EAP authentication session for the EAP method.
///
/// \sa [EapPeerEndSession function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363604.aspx)
///
virtual void end_session();
///
/// Processes a packet received by EapHost from a supplicant.
///
@ -104,8 +273,8 @@ namespace eap
/// \sa [EapPeerGetResponsePacket function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363610.aspx)
///
virtual void get_response_packet(
_Inout_bytecap_(*dwSendPacketSize) void *pSendPacket,
_Inout_ DWORD *pdwSendPacketSize);
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max = MAXDWORD);
///
/// Obtains the result of an authentication session from the EAP method.
@ -118,79 +287,34 @@ namespace eap
/// @}
/// \name User Interaction
/// @{
protected:
#if EAP_TLS < EAP_TLS_SCHANNEL_FULL
///
/// Obtains the user interface context from the EAP method.
/// Verifies server's certificate if trusted by configuration
///
/// \note This function is always followed by the `EapPeerInvokeInteractiveUI()` function, which is followed by the `EapPeerSetUIContext()` function.
///
/// \sa [EapPeerGetUIContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363612.aspx)
///
virtual void get_ui_context(
_Inout_ BYTE **ppUIContextData,
_Inout_ DWORD *pdwUIContextDataSize);
///
/// Provides a user interface context to the EAP method.
///
/// \note This function is called after the UI has been raised through the `EapPeerGetUIContext()` function.
///
/// \sa [EapPeerSetUIContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363626.aspx)
///
virtual EapPeerMethodResponseAction set_ui_context(
_In_count_(dwUIContextDataSize) const BYTE *pUIContextData,
_In_ DWORD dwUIContextDataSize);
/// @}
/// \name EAP Response Attributes
/// @{
///
/// Obtains an array of EAP response attributes from the EAP method.
///
/// \sa [EapPeerGetResponseAttributes function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363609.aspx)
///
virtual void get_response_attributes(_Inout_ EapAttributes *pAttribs);
///
/// Provides an updated array of EAP response attributes to the EAP method.
///
/// \sa [EapPeerSetResponseAttributes function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363625.aspx)
///
virtual EapPeerMethodResponseAction set_response_attributes(_In_ const EapAttributes *pAttribs);
/// @}
void verify_server_trust() const;
#endif
protected:
///
/// Generates master session key
///
/// \sa [The EAP-TLS Authentication Protocol (Chapter 2.3. Key Hierarchy)](https://tools.ietf.org/html/rfc5216#section-2.3)
///
virtual void derive_msk();
config_method_ttls &m_cfg; ///< Method configuration
credentials_ttls &m_cred; ///< Method user credentials
HANDLE m_user_ctx; ///< Handle to user context
winstd::tstring m_sc_target_name; ///< Schannel target name
winstd::sec_credentials m_sc_cred; ///< Schannel client credentials
std::vector<unsigned char> m_sc_queue; ///< TLS data queue
winstd::sec_context m_sc_ctx; ///< Schannel context
///
/// Generates keying material for inner authentication
///
virtual void derive_challenge();
enum {
phase_unknown = -1, ///< Unknown phase
phase_handshake_init = 0, ///< Handshake initialize
phase_handshake_cont, ///< Handshake continue
phase_finished, ///< Exchange application data
} m_phase; ///< What phase is our communication at?
///
/// Processes an application message
///
/// \param[in] msg Application message data
/// \param[in] size_msg Application message data size
///
virtual EapPeerMethodResponseAction process_application_data(_In_bytecount_(size_msg) const void *msg, _In_ size_t size_msg);
sanitizing_blob m_packet_res; ///< Response packet
bool m_packet_res_inner; ///< Get and ancrypt data from inner method too?
protected:
#pragma warning(suppress: 4480)
enum version_t :unsigned char {
version_0 = 0, ///< EAP-TTLS v0
} m_version; ///< EAP-TTLS version
std::unique_ptr<method> m_inner; ///< Inner authentication method
std::vector<winstd::eap_attr> m_eap_attr; ///< EAP attributes returned by get_result() method
EAP_ATTRIBUTES m_eap_attr_desc; ///< EAP attributes descriptor (required to avoid memory leakage in get_result())
};
}

View File

@ -41,7 +41,7 @@ namespace eap
public:
///
/// Constructs a EAP TTLS peer module
/// Constructs a EAP-TTLS peer module
///
peer_ttls();
@ -228,20 +228,26 @@ namespace eap
protected:
class session {
public:
///
/// Constructs a EAP-TTLS session
///
session(_In_ module &mod);
///
/// Destructs EAP-TTLS session
///
virtual ~session();
public:
module &m_module; ///< Module
config_connection m_cfg; ///< Connection configuration
credentials_connection m_cred; ///< Connection credentials
std::unique_ptr<method_ttls> m_method; ///< EAP-TTLS method
module &m_module; ///< Module
config_connection m_cfg; ///< Connection configuration
credentials_connection m_cred; ///< Connection credentials
std::unique_ptr<method> m_method; ///< EAP-TTLS method
// The following members are required to avoid memory leakage in get_result()
EAP_ATTRIBUTES m_eap_attr_desc; ///< EAP attributes descriptor
BYTE *m_blob_cfg; ///< Configuration BLOB
BYTE *m_blob_cfg; ///< Configuration BLOB
#ifdef EAP_USE_NATIVE_CREDENTIAL_CACHE
BYTE *m_blob_cred; ///< Credentials BLOB
BYTE *m_blob_cred; ///< Credentials BLOB
#endif
};
};

File diff suppressed because it is too large Load Diff

View File

@ -227,7 +227,27 @@ EAP_SESSION_HANDLE eap::peer_ttls::begin_session(
}
// We have configuration, we have credentials, create method.
s->m_method.reset(new method_ttls(*this, *cfg_method, *dynamic_cast<credentials_ttls*>(s->m_cred.m_cred.get())));
auto cfg_inner = cfg_method->m_inner.get();
auto cred_inner = dynamic_cast<credentials_ttls*>(s->m_cred.m_cred.get())->m_inner.get();
auto cfg_inner_eaphost = dynamic_cast<config_method_eaphost*>(cfg_inner);
unique_ptr<method> meth_inner;
if (!cfg_inner_eaphost) {
// Native inner methods
switch (cfg_inner->get_method_id()) {
case eap_type_legacy_pap : meth_inner.reset(new method_pap (*this, dynamic_cast<config_method_pap &>(*cfg_inner), dynamic_cast<credentials_pass&>(*cred_inner))); break;
case eap_type_legacy_mschapv2: meth_inner.reset(new method_mschapv2(*this, dynamic_cast<config_method_mschapv2&>(*cfg_inner), dynamic_cast<credentials_pass&>(*cred_inner))); break;
default: throw invalid_argument(__FUNCTION__ " Unsupported inner authentication method.");
}
} else {
// EapHost inner method
meth_inner.reset(
new method_eapmsg (*this, cred_inner->get_identity().c_str(),
new method_eaphost(*this, *cfg_inner_eaphost, dynamic_cast<credentials_eaphost&>(*cred_inner))));
}
s->m_method.reset(
new method_eap (*this, eap_type_ttls,
new method_defrag(*this,
new method_ttls (*this, *cfg_method, *dynamic_cast<credentials_ttls*>(s->m_cred.m_cred.get()), meth_inner.release()))));
// Initialize method.
s->m_method->begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
@ -265,7 +285,14 @@ void eap::peer_ttls::get_response_packet(
_Inout_bytecap_(*dwSendPacketSize) EapPacket *pSendPacket,
_Inout_ DWORD *pdwSendPacketSize)
{
static_cast<session*>(hSession)->m_method->get_response_packet(pSendPacket, pdwSendPacketSize);
assert(pdwSendPacketSize);
assert(pSendPacket || !*pdwSendPacketSize);
sanitizing_blob packet;
static_cast<session*>(hSession)->m_method->get_response_packet(packet, *pdwSendPacketSize);
assert(packet.size() <= *pdwSendPacketSize);
memcpy(pSendPacket, packet.data(), *pdwSendPacketSize = (DWORD)packet.size());
}
@ -277,9 +304,6 @@ void eap::peer_ttls::get_result(
auto s = static_cast<session*>(hSession);
s->m_method->get_result(reason, pResult);
s->m_eap_attr_desc.dwNumberOfAttributes = (DWORD)s->m_method->m_eap_attr.size();
s->m_eap_attr_desc.pAttribs = s->m_method->m_eap_attr.data();
pResult->pAttribArray = &s->m_eap_attr_desc;
// Do not report failure to EapHost, as it will not save updated configuration then. But we need it to save it, to alert user on next connection attempt.
// EapHost is well aware of the failed condition.

View File

@ -39,7 +39,7 @@ namespace eap
{
public:
///
/// Constructs a EAP TTLS UI peer module
/// Constructs a EAP-TTLS UI peer module
///
peer_ttls_ui();

View File

@ -24,14 +24,20 @@ using namespace std;
using namespace winstd;
//////////////////////////////////////////////////////////////////////
// wxInitializerPeer
//////////////////////////////////////////////////////////////////////
///
/// Peer initializer
///
class wxInitializerPeer
{
public:
///
/// Initialize peer
///
wxInitializerPeer(_In_ HINSTANCE instance);
///
/// Uninitialize peer
///
virtual ~wxInitializerPeer();
protected: