peer_tls: Move all applicable methods upstream to make reusable

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2020-02-04 14:56:39 +01:00
parent db056f5150
commit 570eb83558
6 changed files with 490 additions and 481 deletions

View File

@ -50,6 +50,104 @@ namespace eap
virtual void shutdown();
virtual void get_identity(
_In_ DWORD dwFlags,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_Out_ BYTE **ppUserDataOut,
_Out_ DWORD *pdwUserDataOutSize,
_In_ HANDLE hTokenImpersonateUser,
_Out_ BOOL *pfInvokeUI,
_Out_ WCHAR **ppwszIdentity);
virtual void get_method_properties(
_In_ DWORD dwVersion,
_In_ DWORD dwFlags,
_In_ HANDLE hUserImpersonationToken,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_Out_ EAP_METHOD_PROPERTY_ARRAY *pMethodPropertyArray);
virtual void credentials_xml2blob(
_In_ DWORD dwFlags,
_In_ IXMLDOMNode *pConfigRoot,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_Out_ BYTE **ppCredentialsOut,
_Out_ DWORD *pdwCredentialsOutSize);
/// \name Session management
/// @{
virtual EAP_SESSION_HANDLE begin_session(
_In_ DWORD dwFlags,
_In_ const EapAttributes *pAttributeArray,
_In_ HANDLE hTokenImpersonateUser,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_In_ DWORD dwMaxSendPacketSize);
virtual void end_session(_In_ EAP_SESSION_HANDLE hSession);
/// @}
/// \name Packet processing
/// @{
virtual void process_request_packet(
_In_ EAP_SESSION_HANDLE hSession,
_In_bytecount_(dwReceivedPacketSize) const EapPacket *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize,
_Out_ EapPeerMethodOutput *pEapOutput);
virtual void get_response_packet(
_In_ EAP_SESSION_HANDLE hSession,
_Out_bytecapcount_(*pdwSendPacketSize) EapPacket *pSendPacket,
_Inout_ DWORD *pdwSendPacketSize);
/// @}
virtual void get_result(
_In_ EAP_SESSION_HANDLE hSession,
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult);
/// \name User Interaction
/// @{
virtual void get_ui_context(
_In_ EAP_SESSION_HANDLE hSession,
_Out_ BYTE **ppUIContextData,
_Out_ DWORD *pdwUIContextDataSize);
virtual void set_ui_context(
_In_ EAP_SESSION_HANDLE hSession,
_In_count_(dwUIContextDataSize) const BYTE *pUIContextData,
_In_ DWORD dwUIContextDataSize,
_Out_ EapPeerMethodOutput *pEapOutput);
/// @}
/// \name EAP Response Attributes
/// @{
virtual void get_response_attributes(
_In_ EAP_SESSION_HANDLE hSession,
_Out_ EapAttributes *pAttribs);
virtual void set_response_attributes(
_In_ EAP_SESSION_HANDLE hSession,
_In_ const EapAttributes *pAttribs,
_Out_ EapPeerMethodOutput *pEapOutput);
/// @}
///
/// Spawns a new certificate revocation check thread
///
@ -58,6 +156,57 @@ namespace eap
void spawn_crl_check(_Inout_ winstd::cert_context &&cert);
protected:
///
/// Makes a new inner method
///
/// \param[in] cfg Method configuration
/// \param[in] cred Credentials
///
/// \returns A new inner method of given type
///
virtual method* make_method(_In_ config_method_tls &cfg, _In_ credentials_tls &cred) = 0;
///
/// Checks all configured providers and tries to combine credentials.
///
_Success_(return != 0) virtual const config_method_with_cred* combine_credentials(
_In_ DWORD dwFlags,
_In_ const config_connection &cfg,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_Inout_ credentials_connection& cred_out,
_In_ HANDLE hTokenImpersonateUser) = 0;
protected:
///
/// TTL tunnel session
///
class session {
public:
///
/// Constructs a session
///
session(_In_ module &mod);
///
/// Destructs the session
///
virtual ~session();
public:
module &m_module; ///< Module
config_connection m_cfg; ///< Connection configuration
credentials_connection m_cred; ///< Connection credentials
std::unique_ptr<method> m_method; ///< EAP method
// The following members are required to avoid memory leakage in get_result() and get_ui_context().
BYTE *m_blob_cfg; ///< Configuration BLOB
#if EAP_USE_NATIVE_CREDENTIAL_CACHE
BYTE *m_blob_cred; ///< Credentials BLOB
#endif
BYTE *m_blob_ui_ctx; ///< User Interface context data
};
///
///< Post-festum server certificate revocation verify thread
///

View File

@ -48,6 +48,309 @@ void eap::peer_tls::shutdown()
}
void eap::peer_tls::get_identity(
_In_ DWORD dwFlags,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_Out_ BYTE **ppUserDataOut,
_Out_ DWORD *pdwUserDataOutSize,
_In_ HANDLE hTokenImpersonateUser,
_Out_ BOOL *pfInvokeUI,
_Out_ WCHAR **ppwszIdentity)
{
assert(ppUserDataOut);
assert(pdwUserDataOutSize);
assert(pfInvokeUI);
assert(ppwszIdentity);
// Unpack configuration.
config_connection cfg(*this);
unpack(cfg, pConnectionData, dwConnectionDataSize);
// Combine credentials.
credentials_connection cred_out(*this, cfg);
const config_method_with_cred *cfg_method = combine_credentials(dwFlags, cfg, pUserData, dwUserDataSize, cred_out, hTokenImpersonateUser);
if (cfg_method) {
// No UI will be necessary.
*pfInvokeUI = FALSE;
} else {
// Credentials missing or incomplete.
if ((dwFlags & EAP_FLAG_MACHINE_AUTH) == 0) {
// Per-user authentication, request UI.
log_event(&EAPMETHOD_TRACE_EVT_CRED_INVOKE_UI2, event_data::blank);
*ppUserDataOut = NULL;
*pdwUserDataOutSize = 0;
*pfInvokeUI = TRUE;
*ppwszIdentity = NULL;
return;
} else {
// Per-machine authentication, cannot use UI.
throw win_runtime_error(ERROR_NO_SUCH_USER, __FUNCTION__ " Credentials for per-machine authentication not available.");
}
}
// Build our identity. ;)
wstring identity(std::move(cfg_method->get_public_identity(*cred_out.m_cred.get())));
log_event(&EAPMETHOD_TRACE_EVT_CRED_OUTER_ID1, event_data((unsigned int)cfg_method->get_method_id()), event_data(identity), event_data::blank);
size_t size = sizeof(WCHAR)*(identity.length() + 1);
*ppwszIdentity = (WCHAR*)alloc_memory(size);
memcpy(*ppwszIdentity, identity.c_str(), size);
// Pack credentials.
pack(cred_out, ppUserDataOut, pdwUserDataOutSize);
}
void eap::peer_tls::get_method_properties(
_In_ DWORD dwVersion,
_In_ DWORD dwFlags,
_In_ HANDLE hUserImpersonationToken,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_Out_ EAP_METHOD_PROPERTY_ARRAY *pMethodPropertyArray)
{
UNREFERENCED_PARAMETER(dwVersion);
UNREFERENCED_PARAMETER(dwFlags);
UNREFERENCED_PARAMETER(hUserImpersonationToken);
UNREFERENCED_PARAMETER(pConnectionData);
UNREFERENCED_PARAMETER(dwConnectionDataSize);
UNREFERENCED_PARAMETER(pUserData);
UNREFERENCED_PARAMETER(dwUserDataSize);
assert(pMethodPropertyArray);
vector<EAP_METHOD_PROPERTY> properties;
properties.reserve(20);
properties.push_back(eap_method_prop(emptPropCipherSuiteNegotiation, TRUE));
properties.push_back(eap_method_prop(emptPropMutualAuth, TRUE));
properties.push_back(eap_method_prop(emptPropIntegrity, TRUE));
properties.push_back(eap_method_prop(emptPropReplayProtection, TRUE));
properties.push_back(eap_method_prop(emptPropConfidentiality, TRUE));
properties.push_back(eap_method_prop(emptPropKeyDerivation, TRUE));
properties.push_back(eap_method_prop(emptPropKeyStrength128, TRUE));
properties.push_back(eap_method_prop(emptPropDictionaryAttackResistance, TRUE));
properties.push_back(eap_method_prop(emptPropFastReconnect, TRUE));
properties.push_back(eap_method_prop(emptPropCryptoBinding, TRUE));
properties.push_back(eap_method_prop(emptPropSessionIndependence, TRUE));
properties.push_back(eap_method_prop(emptPropFragmentation, TRUE));
properties.push_back(eap_method_prop(emptPropStandalone, TRUE));
properties.push_back(eap_method_prop(emptPropMppeEncryption, TRUE));
properties.push_back(eap_method_prop(emptPropTunnelMethod, TRUE));
properties.push_back(eap_method_prop(emptPropSupportsConfig, TRUE));
properties.push_back(eap_method_prop(emptPropMachineAuth, TRUE));
properties.push_back(eap_method_prop(emptPropUserAuth, TRUE));
properties.push_back(eap_method_prop(emptPropIdentityPrivacy, TRUE));
properties.push_back(eap_method_prop(emptPropSharedStateEquivalence, TRUE));
// Allocate property array.
DWORD dwCount = (DWORD)properties.size();
pMethodPropertyArray->pMethodProperty = (EAP_METHOD_PROPERTY*)alloc_memory(sizeof(EAP_METHOD_PROPERTY) * dwCount);
// Copy properties.
memcpy(pMethodPropertyArray->pMethodProperty, properties.data(), sizeof(EAP_METHOD_PROPERTY) * dwCount);
pMethodPropertyArray->dwNumberOfProperties = dwCount;
}
void eap::peer_tls::credentials_xml2blob(
_In_ DWORD dwFlags,
_In_ IXMLDOMNode *pConfigRoot,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_Out_ BYTE **ppCredentialsOut,
_Out_ DWORD *pdwCredentialsOutSize)
{
UNREFERENCED_PARAMETER(dwFlags);
UNREFERENCED_PARAMETER(pConnectionData);
UNREFERENCED_PARAMETER(dwConnectionDataSize);
// Load credentials from XML.
unique_ptr<config_method> cfg(make_config_method());
unique_ptr<credentials> cred(cfg->make_credentials());
cred->load(pConfigRoot);
// Pack credentials.
pack(*cred, ppCredentialsOut, pdwCredentialsOutSize);
}
EAP_SESSION_HANDLE eap::peer_tls::begin_session(
_In_ DWORD dwFlags,
_In_ const EapAttributes *pAttributeArray,
_In_ HANDLE hTokenImpersonateUser,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_In_ DWORD dwMaxSendPacketSize)
{
// Create new session.
unique_ptr<session> s(new session(*this));
// Unpack configuration.
unpack(s->m_cfg, pConnectionData, dwConnectionDataSize);
// Unpack credentials.
unpack(s->m_cred, pUserData, dwUserDataSize);
// Look-up the provider.
config_method_tls *cfg_method;
for (auto cfg_prov = s->m_cfg.m_providers.begin(), cfg_prov_end = s->m_cfg.m_providers.end();; ++cfg_prov) {
if (cfg_prov != cfg_prov_end) {
if (s->m_cred.match(*cfg_prov)) {
// Matching provider found.
if (cfg_prov->m_methods.empty())
throw invalid_argument(string_printf(__FUNCTION__ " %ls provider has no methods.", cfg_prov->get_id().c_str()));
cfg_method = dynamic_cast<config_method_tls*>(cfg_prov->m_methods.front().get());
break;
}
} else
throw invalid_argument(string_printf(__FUNCTION__ " Credentials do not match to any provider within this connection configuration (provider: %ls).", s->m_cred.get_id().c_str()));
}
// We have configuration, we have credentials, create method.
s->m_method.reset(make_method(*cfg_method, *dynamic_cast<credentials_tls*>(s->m_cred.m_cred.get())));
// Initialize method.
s->m_method->begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
return s.release();
}
void eap::peer_tls::end_session(_In_ EAP_SESSION_HANDLE hSession)
{
assert(hSession);
// End the session.
auto s = static_cast<session*>(hSession);
s->m_method->end_session();
delete s;
}
void eap::peer_tls::process_request_packet(
_In_ EAP_SESSION_HANDLE hSession,
_In_bytecount_(dwReceivedPacketSize) const EapPacket *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize,
_Out_ EapPeerMethodOutput *pEapOutput)
{
assert(dwReceivedPacketSize == ntohs(*(WORD*)pReceivedPacket->Length));
assert(pEapOutput);
pEapOutput->action = static_cast<session*>(hSession)->m_method->process_request_packet(pReceivedPacket, dwReceivedPacketSize);
pEapOutput->fAllowNotifications = TRUE;
}
void eap::peer_tls::get_response_packet(
_In_ EAP_SESSION_HANDLE hSession,
_Out_bytecapcount_(*pdwSendPacketSize) EapPacket *pSendPacket,
_Inout_ DWORD *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());
}
void eap::peer_tls::get_result(
_In_ EAP_SESSION_HANDLE hSession,
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult)
{
auto s = static_cast<session*>(hSession);
s->m_method->get_result(reason, pResult);
// 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.
//pResult->fIsSuccess = FALSE;
//pResult->dwFailureReasonCode = EAP_E_AUTHENTICATION_FAILED;
pResult->fIsSuccess = TRUE;
pResult->dwFailureReasonCode = ERROR_SUCCESS;
if (pResult->fSaveConnectionData) {
pack(s->m_cfg, &pResult->pConnectionData, &pResult->dwSizeofConnectionData);
if (s->m_blob_cfg)
free_memory(s->m_blob_cfg);
s->m_blob_cfg = pResult->pConnectionData;
}
#if EAP_USE_NATIVE_CREDENTIAL_CACHE
pResult->fSaveUserData = TRUE;
pack(s->m_cred, &pResult->pUserData, &pResult->dwSizeofUserData);
if (s->m_blob_cred)
free_memory(s->m_blob_cred);
s->m_blob_cred = pResult->pUserData;
#endif
}
void eap::peer_tls::get_ui_context(
_In_ EAP_SESSION_HANDLE hSession,
_Out_ BYTE **ppUIContextData,
_Out_ DWORD *pdwUIContextDataSize)
{
assert(ppUIContextData);
assert(pdwUIContextDataSize);
auto s = static_cast<session*>(hSession);
// Get context data from method.
ui_context ctx(s->m_cfg, s->m_cred);
s->m_method->get_ui_context(ctx.m_data);
// Pack context data.
pack(ctx, ppUIContextData, pdwUIContextDataSize);
if (s->m_blob_ui_ctx)
free_memory(s->m_blob_ui_ctx);
s->m_blob_ui_ctx = *ppUIContextData;
}
void eap::peer_tls::set_ui_context(
_In_ EAP_SESSION_HANDLE hSession,
_In_count_(dwUIContextDataSize) const BYTE *pUIContextData,
_In_ DWORD dwUIContextDataSize,
_Out_ EapPeerMethodOutput *pEapOutput)
{
assert(pEapOutput);
sanitizing_blob data(std::move(unpack(pUIContextData, dwUIContextDataSize)));
pEapOutput->action = static_cast<session*>(hSession)->m_method->set_ui_context(data.data(), (DWORD)data.size());
pEapOutput->fAllowNotifications = TRUE;
}
void eap::peer_tls::get_response_attributes(
_In_ EAP_SESSION_HANDLE hSession,
_Out_ EapAttributes *pAttribs)
{
static_cast<session*>(hSession)->m_method->get_response_attributes(pAttribs);
}
void eap::peer_tls::set_response_attributes(
_In_ EAP_SESSION_HANDLE hSession,
_In_ const EapAttributes *pAttribs,
_Out_ EapPeerMethodOutput *pEapOutput)
{
assert(pEapOutput);
pEapOutput->action = static_cast<session*>(hSession)->m_method->set_response_attributes(pAttribs);
pEapOutput->fAllowNotifications = TRUE;
}
void eap::peer_tls::spawn_crl_check(_Inout_ winstd::cert_context &&cert)
{
// Create the thread and add it to the list.
@ -59,6 +362,37 @@ void eap::peer_tls::spawn_crl_check(_Inout_ winstd::cert_context &&cert)
}
//////////////////////////////////////////////////////////////////////
// eap::peer_tls_tunnel::session
//////////////////////////////////////////////////////////////////////
eap::peer_tls::session::session(_In_ module &mod) :
m_module(mod),
m_cfg(mod),
m_cred(mod, m_cfg),
m_blob_cfg(NULL),
#if EAP_USE_NATIVE_CREDENTIAL_CACHE
m_blob_cred(NULL),
#endif
m_blob_ui_ctx(NULL)
{}
eap::peer_tls::session::~session()
{
if (m_blob_cfg)
m_module.free_memory(m_blob_cfg);
#if EAP_USE_NATIVE_CREDENTIAL_CACHE
if (m_blob_cred)
m_module.free_memory(m_blob_cred);
#endif
if (m_blob_ui_ctx)
m_module.free_memory(m_blob_ui_ctx);
}
//////////////////////////////////////////////////////////////////////
// eap::peer_tls::crl_checker
//////////////////////////////////////////////////////////////////////

View File

@ -28,6 +28,7 @@
#include "../../MSCHAPv2/include/Method.h"
#include "../../EAPBase/include/EAPXML.h"
#include "../../EAPBase/include/UIContext.h"
#include <WinStd/Cred.h>
#include <WinStd/EAP.h>

View File

@ -55,155 +55,14 @@ namespace eap
virtual void initialize();
virtual void shutdown();
virtual void get_identity(
_In_ DWORD dwFlags,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_Out_ BYTE **ppUserDataOut,
_Out_ DWORD *pdwUserDataOutSize,
_In_ HANDLE hTokenImpersonateUser,
_Out_ BOOL *pfInvokeUI,
_Out_ WCHAR **ppwszIdentity);
virtual void get_method_properties(
_In_ DWORD dwVersion,
_In_ DWORD dwFlags,
_In_ HANDLE hUserImpersonationToken,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_Out_ EAP_METHOD_PROPERTY_ARRAY *pMethodPropertyArray);
virtual void credentials_xml2blob(
_In_ DWORD dwFlags,
_In_ IXMLDOMNode *pConfigRoot,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_Out_ BYTE **ppCredentialsOut,
_Out_ DWORD *pdwCredentialsOutSize);
/// \name Session management
/// @{
virtual EAP_SESSION_HANDLE begin_session(
_In_ DWORD dwFlags,
_In_ const EapAttributes *pAttributeArray,
_In_ HANDLE hTokenImpersonateUser,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_In_ DWORD dwMaxSendPacketSize);
virtual void end_session(_In_ EAP_SESSION_HANDLE hSession);
/// @}
/// \name Packet processing
/// @{
virtual void process_request_packet(
_In_ EAP_SESSION_HANDLE hSession,
_In_bytecount_(dwReceivedPacketSize) const EapPacket *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize,
_Out_ EapPeerMethodOutput *pEapOutput);
virtual void get_response_packet(
_In_ EAP_SESSION_HANDLE hSession,
_Out_bytecapcount_(*pdwSendPacketSize) EapPacket *pSendPacket,
_Inout_ DWORD *pdwSendPacketSize);
/// @}
virtual void get_result(
_In_ EAP_SESSION_HANDLE hSession,
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult);
/// \name User Interaction
/// @{
virtual void get_ui_context(
_In_ EAP_SESSION_HANDLE hSession,
_Out_ BYTE **ppUIContextData,
_Out_ DWORD *pdwUIContextDataSize);
virtual void set_ui_context(
_In_ EAP_SESSION_HANDLE hSession,
_In_count_(dwUIContextDataSize) const BYTE *pUIContextData,
_In_ DWORD dwUIContextDataSize,
_Out_ EapPeerMethodOutput *pEapOutput);
/// @}
/// \name EAP Response Attributes
/// @{
virtual void get_response_attributes(
_In_ EAP_SESSION_HANDLE hSession,
_Out_ EapAttributes *pAttribs);
virtual void set_response_attributes(
_In_ EAP_SESSION_HANDLE hSession,
_In_ const EapAttributes *pAttribs,
_Out_ EapPeerMethodOutput *pEapOutput);
/// @}
protected:
///
/// Makes a new inner method
///
/// \param[in] cfg Method configuration
/// \param[in] cred Credentials
///
/// \returns A new inner method of given type
///
virtual method* make_method(_In_ config_method_tls_tunnel &cfg, _In_ credentials_tls_tunnel &cred) = 0;
///
/// Checks all configured providers and tries to combine credentials.
///
_Success_(return != 0) const config_method_tls_tunnel* combine_credentials(
_Success_(return != 0) virtual const config_method_with_cred* combine_credentials(
_In_ DWORD dwFlags,
_In_ const config_connection &cfg,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_Inout_ credentials_connection& cred_out,
_In_ HANDLE hTokenImpersonateUser);
protected:
///
/// TTL tunnel session
///
class session {
public:
///
/// Constructs a session
///
session(_In_ module &mod);
///
/// Destructs the session
///
virtual ~session();
public:
module &m_module; ///< Module
config_connection m_cfg; ///< Connection configuration
credentials_connection m_cred; ///< Connection credentials
std::unique_ptr<method> m_method; ///< EAP method
// The following members are required to avoid memory leakage in get_result() and get_ui_context().
BYTE *m_blob_cfg; ///< Configuration BLOB
#if EAP_USE_NATIVE_CREDENTIAL_CACHE
BYTE *m_blob_cred; ///< Credentials BLOB
#endif
BYTE *m_blob_ui_ctx; ///< User Interface context data
};
};
@ -226,7 +85,7 @@ namespace eap
protected:
/// @copydoc eap::method::make_config_method()
virtual method* make_method(_In_ config_method_tls_tunnel &cfg, _In_ credentials_tls_tunnel &cred);
virtual method* make_method(_In_ config_method_tls &cfg, _In_ credentials_tls &cred);
};
/// @}

View File

@ -61,309 +61,7 @@ void eap::peer_tls_tunnel::shutdown()
}
void eap::peer_tls_tunnel::get_identity(
_In_ DWORD dwFlags,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_Out_ BYTE **ppUserDataOut,
_Out_ DWORD *pdwUserDataOutSize,
_In_ HANDLE hTokenImpersonateUser,
_Out_ BOOL *pfInvokeUI,
_Out_ WCHAR **ppwszIdentity)
{
assert(ppUserDataOut);
assert(pdwUserDataOutSize);
assert(pfInvokeUI);
assert(ppwszIdentity);
// Unpack configuration.
config_connection cfg(*this);
unpack(cfg, pConnectionData, dwConnectionDataSize);
// Combine credentials.
credentials_connection cred_out(*this, cfg);
const config_method_tls_tunnel *cfg_method = combine_credentials(dwFlags, cfg, pUserData, dwUserDataSize, cred_out, hTokenImpersonateUser);
if (cfg_method) {
// No UI will be necessary.
*pfInvokeUI = FALSE;
} else {
// Credentials missing or incomplete.
if ((dwFlags & EAP_FLAG_MACHINE_AUTH) == 0) {
// Per-user authentication, request UI.
log_event(&EAPMETHOD_TRACE_EVT_CRED_INVOKE_UI2, event_data::blank);
*ppUserDataOut = NULL;
*pdwUserDataOutSize = 0;
*pfInvokeUI = TRUE;
*ppwszIdentity = NULL;
return;
} else {
// Per-machine authentication, cannot use UI.
throw win_runtime_error(ERROR_NO_SUCH_USER, __FUNCTION__ " Credentials for per-machine authentication not available.");
}
}
// Build our identity. ;)
wstring identity(std::move(cfg_method->get_public_identity(*cred_out.m_cred.get())));
log_event(&EAPMETHOD_TRACE_EVT_CRED_OUTER_ID1, event_data((unsigned int)cfg_method->get_method_id()), event_data(identity), event_data::blank);
size_t size = sizeof(WCHAR)*(identity.length() + 1);
*ppwszIdentity = (WCHAR*)alloc_memory(size);
memcpy(*ppwszIdentity, identity.c_str(), size);
// Pack credentials.
pack(cred_out, ppUserDataOut, pdwUserDataOutSize);
}
void eap::peer_tls_tunnel::get_method_properties(
_In_ DWORD dwVersion,
_In_ DWORD dwFlags,
_In_ HANDLE hUserImpersonationToken,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_Out_ EAP_METHOD_PROPERTY_ARRAY *pMethodPropertyArray)
{
UNREFERENCED_PARAMETER(dwVersion);
UNREFERENCED_PARAMETER(dwFlags);
UNREFERENCED_PARAMETER(hUserImpersonationToken);
UNREFERENCED_PARAMETER(pConnectionData);
UNREFERENCED_PARAMETER(dwConnectionDataSize);
UNREFERENCED_PARAMETER(pUserData);
UNREFERENCED_PARAMETER(dwUserDataSize);
assert(pMethodPropertyArray);
vector<EAP_METHOD_PROPERTY> properties;
properties.reserve(20);
properties.push_back(eap_method_prop(emptPropCipherSuiteNegotiation, TRUE));
properties.push_back(eap_method_prop(emptPropMutualAuth, TRUE));
properties.push_back(eap_method_prop(emptPropIntegrity, TRUE));
properties.push_back(eap_method_prop(emptPropReplayProtection, TRUE));
properties.push_back(eap_method_prop(emptPropConfidentiality, TRUE));
properties.push_back(eap_method_prop(emptPropKeyDerivation, TRUE));
properties.push_back(eap_method_prop(emptPropKeyStrength128, TRUE));
properties.push_back(eap_method_prop(emptPropDictionaryAttackResistance, TRUE));
properties.push_back(eap_method_prop(emptPropFastReconnect, TRUE));
properties.push_back(eap_method_prop(emptPropCryptoBinding, TRUE));
properties.push_back(eap_method_prop(emptPropSessionIndependence, TRUE));
properties.push_back(eap_method_prop(emptPropFragmentation, TRUE));
properties.push_back(eap_method_prop(emptPropStandalone, TRUE));
properties.push_back(eap_method_prop(emptPropMppeEncryption, TRUE));
properties.push_back(eap_method_prop(emptPropTunnelMethod, TRUE));
properties.push_back(eap_method_prop(emptPropSupportsConfig, TRUE));
properties.push_back(eap_method_prop(emptPropMachineAuth, TRUE));
properties.push_back(eap_method_prop(emptPropUserAuth, TRUE));
properties.push_back(eap_method_prop(emptPropIdentityPrivacy, TRUE));
properties.push_back(eap_method_prop(emptPropSharedStateEquivalence, TRUE));
// Allocate property array.
DWORD dwCount = (DWORD)properties.size();
pMethodPropertyArray->pMethodProperty = (EAP_METHOD_PROPERTY*)alloc_memory(sizeof(EAP_METHOD_PROPERTY) * dwCount);
// Copy properties.
memcpy(pMethodPropertyArray->pMethodProperty, properties.data(), sizeof(EAP_METHOD_PROPERTY) * dwCount);
pMethodPropertyArray->dwNumberOfProperties = dwCount;
}
void eap::peer_tls_tunnel::credentials_xml2blob(
_In_ DWORD dwFlags,
_In_ IXMLDOMNode *pConfigRoot,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_Out_ BYTE **ppCredentialsOut,
_Out_ DWORD *pdwCredentialsOutSize)
{
UNREFERENCED_PARAMETER(dwFlags);
UNREFERENCED_PARAMETER(pConnectionData);
UNREFERENCED_PARAMETER(dwConnectionDataSize);
// Load credentials from XML.
credentials_tls_tunnel cred(*this);
cred.load(pConfigRoot);
// Pack credentials.
pack(cred, ppCredentialsOut, pdwCredentialsOutSize);
}
EAP_SESSION_HANDLE eap::peer_tls_tunnel::begin_session(
_In_ DWORD dwFlags,
_In_ const EapAttributes *pAttributeArray,
_In_ HANDLE hTokenImpersonateUser,
_In_count_(dwConnectionDataSize) const BYTE *pConnectionData,
_In_ DWORD dwConnectionDataSize,
_In_count_(dwUserDataSize) const BYTE *pUserData,
_In_ DWORD dwUserDataSize,
_In_ DWORD dwMaxSendPacketSize)
{
// Create new session.
unique_ptr<session> s(new session(*this));
// Unpack configuration.
unpack(s->m_cfg, pConnectionData, dwConnectionDataSize);
// Unpack credentials.
unpack(s->m_cred, pUserData, dwUserDataSize);
// Look-up the provider.
config_method_tls_tunnel *cfg_method;
for (auto cfg_prov = s->m_cfg.m_providers.begin(), cfg_prov_end = s->m_cfg.m_providers.end();; ++cfg_prov) {
if (cfg_prov != cfg_prov_end) {
if (s->m_cred.match(*cfg_prov)) {
// Matching provider found.
if (cfg_prov->m_methods.empty())
throw invalid_argument(string_printf(__FUNCTION__ " %ls provider has no methods.", cfg_prov->get_id().c_str()));
cfg_method = dynamic_cast<config_method_tls_tunnel*>(cfg_prov->m_methods.front().get());
break;
}
} else
throw invalid_argument(string_printf(__FUNCTION__ " Credentials do not match to any provider within this connection configuration (provider: %ls).", s->m_cred.get_id().c_str()));
}
// We have configuration, we have credentials, create method.
s->m_method.reset(make_method(*cfg_method, *dynamic_cast<credentials_tls_tunnel*>(s->m_cred.m_cred.get())));
// Initialize method.
s->m_method->begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
return s.release();
}
void eap::peer_tls_tunnel::end_session(_In_ EAP_SESSION_HANDLE hSession)
{
assert(hSession);
// End the session.
auto s = static_cast<session*>(hSession);
s->m_method->end_session();
delete s;
}
void eap::peer_tls_tunnel::process_request_packet(
_In_ EAP_SESSION_HANDLE hSession,
_In_bytecount_(dwReceivedPacketSize) const EapPacket *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize,
_Out_ EapPeerMethodOutput *pEapOutput)
{
assert(dwReceivedPacketSize == ntohs(*(WORD*)pReceivedPacket->Length));
assert(pEapOutput);
pEapOutput->action = static_cast<session*>(hSession)->m_method->process_request_packet(pReceivedPacket, dwReceivedPacketSize);
pEapOutput->fAllowNotifications = TRUE;
}
void eap::peer_tls_tunnel::get_response_packet(
_In_ EAP_SESSION_HANDLE hSession,
_Out_bytecapcount_(*pdwSendPacketSize) EapPacket *pSendPacket,
_Inout_ DWORD *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());
}
void eap::peer_tls_tunnel::get_result(
_In_ EAP_SESSION_HANDLE hSession,
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult)
{
auto s = static_cast<session*>(hSession);
s->m_method->get_result(reason, pResult);
// 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.
//pResult->fIsSuccess = FALSE;
//pResult->dwFailureReasonCode = EAP_E_AUTHENTICATION_FAILED;
pResult->fIsSuccess = TRUE;
pResult->dwFailureReasonCode = ERROR_SUCCESS;
if (pResult->fSaveConnectionData) {
pack(s->m_cfg, &pResult->pConnectionData, &pResult->dwSizeofConnectionData);
if (s->m_blob_cfg)
free_memory(s->m_blob_cfg);
s->m_blob_cfg = pResult->pConnectionData;
}
#if EAP_USE_NATIVE_CREDENTIAL_CACHE
pResult->fSaveUserData = TRUE;
pack(s->m_cred, &pResult->pUserData, &pResult->dwSizeofUserData);
if (s->m_blob_cred)
free_memory(s->m_blob_cred);
s->m_blob_cred = pResult->pUserData;
#endif
}
void eap::peer_tls_tunnel::get_ui_context(
_In_ EAP_SESSION_HANDLE hSession,
_Out_ BYTE **ppUIContextData,
_Out_ DWORD *pdwUIContextDataSize)
{
assert(ppUIContextData);
assert(pdwUIContextDataSize);
auto s = static_cast<session*>(hSession);
// Get context data from method.
ui_context ctx(s->m_cfg, s->m_cred);
s->m_method->get_ui_context(ctx.m_data);
// Pack context data.
pack(ctx, ppUIContextData, pdwUIContextDataSize);
if (s->m_blob_ui_ctx)
free_memory(s->m_blob_ui_ctx);
s->m_blob_ui_ctx = *ppUIContextData;
}
void eap::peer_tls_tunnel::set_ui_context(
_In_ EAP_SESSION_HANDLE hSession,
_In_count_(dwUIContextDataSize) const BYTE *pUIContextData,
_In_ DWORD dwUIContextDataSize,
_Out_ EapPeerMethodOutput *pEapOutput)
{
assert(pEapOutput);
sanitizing_blob data(std::move(unpack(pUIContextData, dwUIContextDataSize)));
pEapOutput->action = static_cast<session*>(hSession)->m_method->set_ui_context(data.data(), (DWORD)data.size());
pEapOutput->fAllowNotifications = TRUE;
}
void eap::peer_tls_tunnel::get_response_attributes(
_In_ EAP_SESSION_HANDLE hSession,
_Out_ EapAttributes *pAttribs)
{
static_cast<session*>(hSession)->m_method->get_response_attributes(pAttribs);
}
void eap::peer_tls_tunnel::set_response_attributes(
_In_ EAP_SESSION_HANDLE hSession,
_In_ const EapAttributes *pAttribs,
_Out_ EapPeerMethodOutput *pEapOutput)
{
assert(pEapOutput);
pEapOutput->action = static_cast<session*>(hSession)->m_method->set_response_attributes(pAttribs);
pEapOutput->fAllowNotifications = TRUE;
}
_Success_(return != 0) const eap::config_method_tls_tunnel* eap::peer_tls_tunnel::combine_credentials(
_Success_(return != 0) const eap::config_method_with_cred* eap::peer_tls_tunnel::combine_credentials(
_In_ DWORD dwFlags,
_In_ const config_connection &cfg,
_In_count_(dwUserDataSize) const BYTE *pUserData,
@ -458,37 +156,6 @@ _Success_(return != 0) const eap::config_method_tls_tunnel* eap::peer_tls_tunnel
}
//////////////////////////////////////////////////////////////////////
// eap::peer_tls_tunnel::session
//////////////////////////////////////////////////////////////////////
eap::peer_tls_tunnel::session::session(_In_ module &mod) :
m_module(mod),
m_cfg(mod),
m_cred(mod, m_cfg),
m_blob_cfg(NULL),
#if EAP_USE_NATIVE_CREDENTIAL_CACHE
m_blob_cred(NULL),
#endif
m_blob_ui_ctx(NULL)
{}
eap::peer_tls_tunnel::session::~session()
{
if (m_blob_cfg)
m_module.free_memory(m_blob_cfg);
#if EAP_USE_NATIVE_CREDENTIAL_CACHE
if (m_blob_cred)
m_module.free_memory(m_blob_cred);
#endif
if (m_blob_ui_ctx)
m_module.free_memory(m_blob_ui_ctx);
}
//////////////////////////////////////////////////////////////////////
// eap::peer_ttls
//////////////////////////////////////////////////////////////////////
@ -504,11 +171,11 @@ eap::config_method* eap::peer_ttls::make_config_method()
}
eap::method* eap::peer_ttls::make_method(_In_ config_method_tls_tunnel &cfg, _In_ credentials_tls_tunnel &cred)
eap::method* eap::peer_ttls::make_method(_In_ config_method_tls &cfg, _In_ credentials_tls &cred)
{
unique_ptr<method> meth_inner;
auto cfg_inner = cfg.m_inner.get();
auto cred_inner = cred.m_inner.get();
auto cfg_inner = dynamic_cast<config_method_tls_tunnel&>(cfg).m_inner.get();
auto cred_inner = dynamic_cast<credentials_tls_tunnel&>(cred).m_inner.get();
assert(cfg_inner);
switch (cfg_inner->get_method_id()) {

View File

@ -43,7 +43,6 @@
#include "../../EapHost/include/Method.h"
#include "../../EAPBase/include/EAPXML.h"
#include "../../EAPBase/include/UIContext.h"
#include <WinStd/EAP.h>