Compare commits

..

10 Commits

55 changed files with 605 additions and 949 deletions

View File

@@ -40,7 +40,7 @@ static int CredWrite()
return -1; return -1;
} }
eap::credentials_pap cred_pap(g_module); eap::credentials_pass cred_pass(g_module);
// Prepare identity (user name). // Prepare identity (user name).
{ {
@@ -50,7 +50,7 @@ static int CredWrite()
bool is_last; bool is_last;
dec.decode(identity_utf8, is_last, pwcArglist[1], (size_t)-1); dec.decode(identity_utf8, is_last, pwcArglist[1], (size_t)-1);
MultiByteToWideChar(CP_UTF8, 0, identity_utf8.data(), (int)identity_utf8.size(), cred_pap.m_identity); MultiByteToWideChar(CP_UTF8, 0, identity_utf8.data(), (int)identity_utf8.size(), cred_pass.m_identity);
} }
// Prepare password. // Prepare password.
@@ -61,7 +61,7 @@ static int CredWrite()
bool is_last; bool is_last;
dec.decode(password_utf8, is_last, pwcArglist[2], (size_t)-1); dec.decode(password_utf8, is_last, pwcArglist[2], (size_t)-1);
MultiByteToWideChar(CP_UTF8, 0, password_utf8.data(), (int)password_utf8.size(), cred_pap.m_password); MultiByteToWideChar(CP_UTF8, 0, password_utf8.data(), (int)password_utf8.size(), cred_pass.m_password);
} }
// Generate target name (aka realm). // Generate target name (aka realm).
@@ -71,7 +71,7 @@ static int CredWrite()
target_name = pwcArglist[3]; target_name = pwcArglist[3];
} else { } else {
// Get the realm from user name. // Get the realm from user name.
LPCWSTR _identity = cred_pap.m_identity.c_str(), domain; LPCWSTR _identity = cred_pass.m_identity.c_str(), domain;
if ((domain = wcschr(_identity, L'@')) != NULL) { if ((domain = wcschr(_identity, L'@')) != NULL) {
target_name = L"urn:RFC4282:realm:"; target_name = L"urn:RFC4282:realm:";
target_name += domain + 1; target_name += domain + 1;
@@ -79,12 +79,22 @@ static int CredWrite()
target_name = L"*"; target_name = L"*";
} }
// Determine credential level.
unsigned int level;
if (nArgs > 4) {
// User explicitly set the level.
level = wcstoul(pwcArglist[4], NULL, 10);
} else {
// Set default level.
level = 0;
}
// Write credentials. // Write credentials.
#ifdef _DEBUG #ifdef _DEBUG
{ {
eap::credentials_pap cred_stored(g_module); eap::credentials_pass cred_stored(g_module);
try { try {
cred_stored.retrieve(target_name.c_str()); cred_stored.retrieve(target_name.c_str(), level);
} catch(win_runtime_error &err) { } catch(win_runtime_error &err) {
OutputDebugStr(_T("%hs (error %u)\n"), err.what(), err.number()); OutputDebugStr(_T("%hs (error %u)\n"), err.what(), err.number());
} catch(...) { } catch(...) {
@@ -93,7 +103,7 @@ static int CredWrite()
} }
#endif #endif
try { try {
cred_pap.store(target_name.c_str()); cred_pass.store(target_name.c_str(), level);
} catch(win_runtime_error &err) { } catch(win_runtime_error &err) {
OutputDebugStr(_T("%hs (error %u)\n"), err.what(), err.number()); OutputDebugStr(_T("%hs (error %u)\n"), err.what(), err.number());
return 2; return 2;
@@ -102,18 +112,6 @@ static int CredWrite()
return 2; return 2;
} }
// Store empty TLS credentials.
eap::credentials_tls cred_tls(g_module);
try {
cred_tls.store(target_name.c_str());
} catch(win_runtime_error &err) {
OutputDebugStr(_T("%hs (error %u)\n"), err.what(), err.number());
return 3;
} catch(...) {
OutputDebugStr(_T("Writing credentials failed.\n"));
return 3;
}
return 0; return 0;
} }

View File

@@ -3,12 +3,13 @@ Imports given credentials to Windows Credential Manager for G
##Usage ##Usage
``` ```
CredWrite <username> <password> [<realm>] CredWrite <username> <password> [<realm> [level]]
``` ```
- `username` - Base64 encoded UTF-8 user name (usually of the form user@domain or domain\user) - `username` - Base64 encoded UTF-8 user name (usually of the form user@domain or domain\user)
- `password` - Base64 encoded UTF-8 user password - `password` - Base64 encoded UTF-8 user password
- `realm` - A realm ID to allow grouping of credentials over different WLAN profiles (optional, default is domain part of `username`) - `realm` - A realm ID to allow grouping of credentials over different WLAN profiles (optional, default is domain part of `username`)
- `level` - Credential level (0=outer, 1=inner, 2=inner-inner..., default is 0=outer)
The credentials are stored to Windows Credential Manager in invoking user's roaming profile. The credentials are stored to Windows Credential Manager in invoking user's roaming profile.

View File

@@ -20,8 +20,7 @@
#pragma once #pragma once
#include "../lib/PAP/include/Credentials.h" #include "../lib/EAPBase/include/Credentials.h"
#include "../lib/TLS/include/Credentials.h"
#include "../lib/EAPBase/include/Module.h" #include "../lib/EAPBase/include/Module.h"
#include <WinStd/Common.h> #include <WinStd/Common.h>

View File

@@ -2,7 +2,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EAPMethods\n" "Project-Id-Version: EAPMethods\n"
"POT-Creation-Date: 2016-09-02 19:08+0200\n" "POT-Creation-Date: 2016-09-06 14:06+0200\n"
"PO-Revision-Date: 2016-06-02 12:27+0200\n" "PO-Revision-Date: 2016-06-02 12:27+0200\n"
"Last-Translator: Simon Rozman <simon.rozman@amebis.si>\n" "Last-Translator: Simon Rozman <simon.rozman@amebis.si>\n"
"Language-Team: Amebis, d. o. o., Kamnik <info@amebis.si>\n" "Language-Team: Amebis, d. o. o., Kamnik <info@amebis.si>\n"
@@ -253,8 +253,24 @@ msgstr ""
msgid "Your provider" msgid "Your provider"
msgstr "" msgstr ""
#: lib/EAPBase_UI/src/EAP_UI.cpp:249 #: lib/EAPBase_UI/src/EAP_UI.cpp:250
msgid "Previous attempt to connect failed. Please, make sure your credentials are correct, or try again later." msgid "Previous attempt to connect reported invalid credentials."
msgstr ""
#: lib/EAPBase_UI/src/EAP_UI.cpp:251
msgid "Previous attempt to connect reported your credentials expired."
msgstr ""
#: lib/EAPBase_UI/src/EAP_UI.cpp:252
msgid "Previous attempt to connect reported your credentials are being changed."
msgstr ""
#: lib/EAPBase_UI/src/EAP_UI.cpp:253
msgid "Previous attempt to connect failed."
msgstr ""
#: lib/EAPBase_UI/src/EAP_UI.cpp:254
msgid "Please, make sure your credentials are correct, or try again later."
msgstr "" msgstr ""
#: lib/TLS_UI/res/wxTLS_UI.cpp:17 #: lib/TLS_UI/res/wxTLS_UI.cpp:17
@@ -454,7 +470,7 @@ msgstr ""
msgid "MSCHAPv2" msgid "MSCHAPv2"
msgstr "" msgstr ""
#: lib/TTLS_UI/src/TTLS_UI.cpp:123 lib/TTLS_UI/src/TTLS_UI.cpp:256 #: lib/TTLS_UI/src/TTLS_UI.cpp:123 lib/TTLS_UI/src/TTLS_UI.cpp:262
msgid "Outer Authentication" msgid "Outer Authentication"
msgstr "" msgstr ""
@@ -476,24 +492,24 @@ msgstr ""
msgid "Deleting credentials failed (error %u)." msgid "Deleting credentials failed (error %u)."
msgstr "" msgstr ""
#: lib/EAPBase_UI/include/EAP_UI.h:738 #: lib/EAPBase_UI/include/EAP_UI.h:739
#, c-format #, c-format
msgid "<error %u>" msgid "<error %u>"
msgstr "" msgstr ""
#: lib/EAPBase_UI/include/EAP_UI.h:742 #: lib/EAPBase_UI/include/EAP_UI.h:743
msgid "<error>" msgid "<error>"
msgstr "" msgstr ""
#: lib/EAPBase_UI/include/EAP_UI.h:753 lib/EAPBase_UI/include/EAP_UI.h:762 #: lib/EAPBase_UI/include/EAP_UI.h:754 lib/EAPBase_UI/include/EAP_UI.h:764
msgid "<empty>" msgid "<empty>"
msgstr "" msgstr ""
#: lib/EAPBase_UI/include/EAP_UI.h:753 lib/EAPBase_UI/include/EAP_UI.h:762 #: lib/EAPBase_UI/include/EAP_UI.h:754 lib/EAPBase_UI/include/EAP_UI.h:764
msgid "<blank ID>" msgid "<blank ID>"
msgstr "" msgstr ""
#: lib/EAPBase_UI/include/EAP_UI.h:962 #: lib/EAPBase_UI/include/EAP_UI.h:964
msgid "<Your Organization>" msgid "<Your Organization>"
msgstr "" msgstr ""

View File

@@ -547,7 +547,7 @@ msgstr "<napaka>"
#: lib/EAPBase_UI/include/EAP_UI.h:753 lib/EAPBase_UI/include/EAP_UI.h:762 #: lib/EAPBase_UI/include/EAP_UI.h:753 lib/EAPBase_UI/include/EAP_UI.h:762
msgid "<empty>" msgid "<empty>"
msgstr "<napaka>" msgstr "<prazno>"
#: lib/EAPBase_UI/include/EAP_UI.h:753 lib/EAPBase_UI/include/EAP_UI.h:762 #: lib/EAPBase_UI/include/EAP_UI.h:753 lib/EAPBase_UI/include/EAP_UI.h:762
msgid "<blank ID>" msgid "<blank ID>"

View File

@@ -29,7 +29,7 @@
// Product version as a single DWORD // Product version as a single DWORD
// Note: Used for version comparison within C/C++ code. // Note: Used for version comparison within C/C++ code.
// //
#define PRODUCT_VERSION 0x00ff1100 #define PRODUCT_VERSION 0x00ff1200
// //
// Product version by components // Product version by components
@@ -39,26 +39,26 @@
// //
#define PRODUCT_VERSION_MAJ 0 #define PRODUCT_VERSION_MAJ 0
#define PRODUCT_VERSION_MIN 255 #define PRODUCT_VERSION_MIN 255
#define PRODUCT_VERSION_REV 17 #define PRODUCT_VERSION_REV 18
#define PRODUCT_VERSION_BUILD 0 #define PRODUCT_VERSION_BUILD 0
// //
// Human readable product version and build year for UI // Human readable product version and build year for UI
// //
#define PRODUCT_VERSION_STR "1.0-alpha17" #define PRODUCT_VERSION_STR "1.0-beta"
#define PRODUCT_BUILD_YEAR_STR "2016" #define PRODUCT_BUILD_YEAR_STR "2016"
// //
// Numerical version presentation for ProductVersion propery in // Numerical version presentation for ProductVersion propery in
// MSI packages (syntax: N.N[.N[.N]]) // MSI packages (syntax: N.N[.N[.N]])
// //
#define PRODUCT_VERSION_INST "0.255.17" #define PRODUCT_VERSION_INST "0.255.18"
// //
// The product code for ProductCode property in MSI packages // The product code for ProductCode property in MSI packages
// Replace with new on every version change, regardless how minor it is. // Replace with new on every version change, regardless how minor it is.
// //
#define PRODUCT_VERSION_GUID "{7968E51E-8A49-4316-9444-057295392387}" #define PRODUCT_VERSION_GUID "{A638F64B-F40A-4397-A212-EEFCD3773F0E}"
// //
// Product vendor // Product vendor

View File

@@ -206,8 +206,9 @@ namespace eap
/// Constructs configuration /// Constructs configuration
/// ///
/// \param[in] mod EAP module to use for global services /// \param[in] mod EAP module to use for global services
/// \param[in] level Config level (0=outer, 1=inner, 2=inner-inner...)
/// ///
config_method(_In_ module &mod); config_method(_In_ module &mod, _In_ unsigned int level);
/// ///
/// Copies configuration /// Copies configuration
@@ -252,6 +253,9 @@ namespace eap
/// Returns a string identifier of the EAP method type of this configuration /// Returns a string identifier of the EAP method type of this configuration
/// ///
virtual const wchar_t* get_method_str() const = 0; virtual const wchar_t* get_method_str() const = 0;
public:
const unsigned int m_level; ///< Config level (0=outer, 1=inner, 2=inner-inner...)
}; };
@@ -265,8 +269,9 @@ namespace eap
/// Constructs configuration /// Constructs configuration
/// ///
/// \param[in] mod EAP module to use for global services /// \param[in] mod EAP module to use for global services
/// \param[in] level Config level (0=outer, 1=inner, 2=inner-inner...)
/// ///
config_method_with_cred(_In_ module &mod); config_method_with_cred(_In_ module &mod, _In_ unsigned int level);
/// ///
/// Copies configuration /// Copies configuration
@@ -355,7 +360,22 @@ namespace eap
bool m_allow_save; ///< Are credentials allowed to be saved to Windows Credential Manager? bool m_allow_save; ///< Are credentials allowed to be saved to Windows Credential Manager?
bool m_use_preshared; ///< Use pre-shared credentials bool m_use_preshared; ///< Use pre-shared credentials
std::unique_ptr<credentials> m_preshared; ///< Pre-shared credentials std::unique_ptr<credentials> m_preshared; ///< Pre-shared credentials
bool m_auth_failed; ///< Did credential fail last time?
enum status {
status_success = 0, ///< Authentication succeeded
status_auth_failed, ///< Authentication failed
status_cred_invalid, ///< Invalid credentials
status_cred_expired, ///< Credentials expired
status_cred_changing, ///< Credentials are being changed
status_account_disabled, ///< Account is disabled
status_account_logon_hours, ///< Restricted account logon hours
status_account_denied, ///< Account access is denied
// Meta statuses
status_cred_begin = status_cred_invalid, ///< First credential related problem
status_cred_end = status_cred_changing + 1, ///< First problem, that is not credential related any more
} m_last_status; ///< Status of authentication the last time
std::wstring m_last_msg; ///< Server message at the last authentication
}; };
@@ -604,3 +624,21 @@ inline void operator>>(_Inout_ eap::cursor_in &cursor, _Out_ eap::config &val)
{ {
val.operator>>(cursor); val.operator>>(cursor);
} }
inline void operator<<(_Inout_ eap::cursor_out &cursor, _In_ const eap::config_method_with_cred::status &val)
{
cursor << (unsigned char)val;
}
inline size_t pksizeof(_In_ const eap::config_method_with_cred::status &val)
{
return pksizeof((unsigned char)val);
}
inline void operator>>(_Inout_ eap::cursor_in &cursor, _Out_ eap::config_method_with_cred::status &val)
{
cursor >> (unsigned char&)val;
}

View File

@@ -179,28 +179,40 @@ namespace eap
/// Save credentials to Windows Credential Manager /// Save credentials to Windows Credential Manager
/// ///
/// \param[in] pszTargetName The name in Windows Credential Manager to store credentials as /// \param[in] pszTargetName The name in Windows Credential Manager to store credentials as
/// \param[in] level Credential level (0=outer, 1=inner, 2=inner-inner...)
/// ///
virtual void store(_In_z_ LPCTSTR pszTargetName) const = 0; virtual void store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const = 0;
/// ///
/// Retrieve credentials from Windows Credential Manager /// Retrieve credentials from Windows Credential Manager
/// ///
/// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from /// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from
/// \param[in] level Credential level (0=outer, 1=inner, 2=inner-inner...)
/// ///
virtual void retrieve(_In_z_ LPCTSTR pszTargetName) = 0; virtual void retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) = 0;
/// ///
/// Returns target name for Windows Credential Manager credential name /// Returns target name for Windows Credential Manager credential name
/// ///
/// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from /// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from
/// \param[in] level Credential level (0=outer, 1=inner, 2=inner-inner...)
/// ///
/// \returns Final target name to store/retrieve credentials in Windows Credential Manager /// \returns Final target name to store/retrieve credentials in Windows Credential Manager
/// ///
inline winstd::tstring target_name(_In_z_ LPCTSTR pszTargetName) const inline winstd::tstring target_name(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const
{ {
// Start with product name and given target name (identity provider usually).
winstd::tstring target_name(_T(PRODUCT_NAME_STR) _T("/")); winstd::tstring target_name(_T(PRODUCT_NAME_STR) _T("/"));
target_name += pszTargetName; target_name += pszTargetName;
target_name += _T('/'); target_name += _T('/');
// Append level of credentials.
TCHAR buf[20];
_ultot_s(level, buf, _countof(buf), 10);
target_name += buf;
target_name += _T('/');
// Append credential type.
target_name += target_suffix(); target_name += target_suffix();
assert(target_name.length() < CRED_MAX_GENERIC_TARGET_NAME_LENGTH); assert(target_name.length() < CRED_MAX_GENERIC_TARGET_NAME_LENGTH);
return target_name; return target_name;
@@ -291,6 +303,13 @@ namespace eap
/// ///
credentials_pass& operator=(_Inout_ credentials_pass &&other); credentials_pass& operator=(_Inout_ credentials_pass &&other);
///
/// Clones credentials
///
/// \returns Pointer to cloned credentials
///
virtual config* clone() const;
/// ///
/// Resets credentials /// Resets credentials
/// ///
@@ -358,18 +377,46 @@ namespace eap
/// Save credentials to Windows Credential Manager /// Save credentials to Windows Credential Manager
/// ///
/// \param[in] pszTargetName The name in Windows Credential Manager to store credentials as /// \param[in] pszTargetName The name in Windows Credential Manager to store credentials as
/// \param[in] level Credential level (0=outer, 1=inner, 2=inner-inner...)
/// ///
virtual void store(_In_z_ LPCTSTR pszTargetName) const; virtual void store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const;
/// ///
/// Retrieve credentials from Windows Credential Manager /// Retrieve credentials from Windows Credential Manager
/// ///
/// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from /// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from
/// \param[in] level Credential level (0=outer, 1=inner, 2=inner-inner...)
/// ///
virtual void retrieve(_In_z_ LPCTSTR pszTargetName); virtual void retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level);
///
/// Return target suffix for Windows Credential Manager credential name
///
virtual LPCTSTR target_suffix() const;
/// @} /// @}
///
/// Combine credentials in the following order:
///
/// 1. Cached credentials
/// 2. Pre-configured credentials
/// 3. Stored credentials
///
/// \param[in] cred_cached Cached credentials (optional, can be \c NULL, must be credentials_pass* type)
/// \param[in] cfg Method configuration (must be config_method_pap type)
/// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from (optional, can be \c NULL)
///
/// \returns
/// - \c source_cache Credentials were obtained from EapHost cache
/// - \c source_preshared Credentials were set by method configuration
/// - \c source_storage Credentials were loaded from Windows Credential Manager
///
virtual source_t combine(
_In_ const credentials *cred_cached,
_In_ const config_method_with_cred &cfg,
_In_opt_z_ LPCTSTR pszTargetName);
public: public:
winstd::sanitizing_wstring m_password; ///< Password winstd::sanitizing_wstring m_password; ///< Password

View File

@@ -445,6 +445,15 @@ inline unsigned __int64 htonll(unsigned __int64 val);
/// ///
inline void hton24(_In_ unsigned int val, _Out_ unsigned char out[3]); inline void hton24(_In_ unsigned int val, _Out_ unsigned char out[3]);
///
/// Converts an 24-bit integer from TCP/IP network to host byte order.
///
/// \param[in] val A 24-bit unsigned number in network byte order
///
/// \returns A 24-bit unsigned number in host byte order
///
inline unsigned int ntoh24(_In_ const unsigned char val[3]);
#pragma once #pragma once
@@ -1113,4 +1122,13 @@ inline void hton24(_In_ unsigned int val, _Out_ unsigned char out[3])
out[2] = (val ) & 0xff; out[2] = (val ) & 0xff;
} }
inline unsigned int ntoh24(_In_ const unsigned char val[3])
{
return
(((unsigned int)val[0]) << 16) |
(((unsigned int)val[1]) << 8) |
(((unsigned int)val[2]) );
}
#endif #endif

View File

@@ -124,7 +124,7 @@ namespace eap
/// ///
virtual void get_result( virtual void get_result(
_In_ EapPeerMethodResultReason reason, _In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *ppResult) = 0; _Inout_ EapPeerMethodResult *ppResult);
/// @} /// @}

View File

@@ -102,25 +102,33 @@ const bstr eap::config::namespace_eapmetadata(L"urn:ietf:params:xml:ns:yang:ietf
// eap::config_method // eap::config_method
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
eap::config_method::config_method(_In_ module &mod) : config(mod) eap::config_method::config_method(_In_ module &mod, _In_ unsigned int level) :
m_level(level),
config(mod)
{ {
} }
eap::config_method::config_method(_In_ const config_method &other) : config(other) eap::config_method::config_method(_In_ const config_method &other) :
m_level(other.m_level),
config(other)
{ {
} }
eap::config_method::config_method(_Inout_ config_method &&other) : config(std::move(other)) eap::config_method::config_method(_Inout_ config_method &&other) :
m_level(other.m_level),
config(std::move(other))
{ {
} }
eap::config_method& eap::config_method::operator=(_In_ const config_method &other) eap::config_method& eap::config_method::operator=(_In_ const config_method &other)
{ {
if (this != &other) if (this != &other) {
assert(m_level == other.m_level); // Allow copy within same configuration level only.
(config&)*this = other; (config&)*this = other;
}
return *this; return *this;
} }
@@ -128,8 +136,10 @@ eap::config_method& eap::config_method::operator=(_In_ const config_method &othe
eap::config_method& eap::config_method::operator=(_Inout_ config_method &&other) eap::config_method& eap::config_method::operator=(_Inout_ config_method &&other)
{ {
if (this != &other) if (this != &other) {
assert(m_level == other.m_level); // Allow move within same configuration level only.
(config&&)*this = std::move(other); (config&&)*this = std::move(other);
}
return *this; return *this;
} }
@@ -139,11 +149,11 @@ eap::config_method& eap::config_method::operator=(_Inout_ config_method &&other)
// eap::config_method_with_cred // eap::config_method_with_cred
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
eap::config_method_with_cred::config_method_with_cred(_In_ module &mod) : eap::config_method_with_cred::config_method_with_cred(_In_ module &mod, _In_ unsigned int level) :
m_allow_save(true), m_allow_save(true),
m_use_preshared(false), m_use_preshared(false),
m_auth_failed(false), m_last_status(status_success),
config_method(mod) config_method(mod, level)
{ {
} }
@@ -152,7 +162,8 @@ eap::config_method_with_cred::config_method_with_cred(_In_ const config_method_w
m_allow_save (other.m_allow_save ), m_allow_save (other.m_allow_save ),
m_use_preshared(other.m_use_preshared ), m_use_preshared(other.m_use_preshared ),
m_preshared (other.m_preshared ? (credentials*)other.m_preshared->clone() : nullptr), m_preshared (other.m_preshared ? (credentials*)other.m_preshared->clone() : nullptr),
m_auth_failed(other.m_auth_failed), m_last_status (other.m_last_status ),
m_last_msg (other.m_last_msg ),
config_method (other ) config_method (other )
{ {
} }
@@ -162,7 +173,8 @@ eap::config_method_with_cred::config_method_with_cred(_Inout_ config_method_with
m_allow_save (std::move(other.m_allow_save )), m_allow_save (std::move(other.m_allow_save )),
m_use_preshared(std::move(other.m_use_preshared)), m_use_preshared(std::move(other.m_use_preshared)),
m_preshared (std::move(other.m_preshared )), m_preshared (std::move(other.m_preshared )),
m_auth_failed (std::move(other.m_auth_failed )), m_last_status (std::move(other.m_last_status )),
m_last_msg (std::move(other.m_last_msg )),
config_method (std::move(other )) config_method (std::move(other ))
{ {
} }
@@ -175,7 +187,8 @@ eap::config_method_with_cred& eap::config_method_with_cred::operator=(_In_ const
m_allow_save = other.m_allow_save; m_allow_save = other.m_allow_save;
m_use_preshared = other.m_use_preshared; m_use_preshared = other.m_use_preshared;
m_preshared.reset(other.m_preshared ? (credentials*)other.m_preshared->clone() : nullptr); m_preshared.reset(other.m_preshared ? (credentials*)other.m_preshared->clone() : nullptr);
m_auth_failed = other.m_auth_failed; m_last_status = other.m_last_status;
m_last_msg = other.m_last_msg;
} }
return *this; return *this;
@@ -189,7 +202,8 @@ eap::config_method_with_cred& eap::config_method_with_cred::operator=(_Inout_ co
m_allow_save = std::move(other.m_allow_save ); m_allow_save = std::move(other.m_allow_save );
m_use_preshared = std::move(other.m_use_preshared); m_use_preshared = std::move(other.m_use_preshared);
m_preshared = std::move(other.m_preshared ); m_preshared = std::move(other.m_preshared );
m_auth_failed = std::move(other.m_auth_failed ); m_last_status = std::move(other.m_last_status );
m_last_msg = std::move(other.m_last_msg );
} }
return *this; return *this;
@@ -241,6 +255,9 @@ void eap::config_method_with_cred::load(_In_ IXMLDOMNode *pConfigRoot)
// This is not really an error - merely an indication pre-shared credentials are unavailable. // This is not really an error - merely an indication pre-shared credentials are unavailable.
} }
} }
m_last_status = status_success;
m_last_msg.clear();
} }
@@ -250,7 +267,8 @@ void eap::config_method_with_cred::operator<<(_Inout_ cursor_out &cursor) const
cursor << m_allow_save; cursor << m_allow_save;
cursor << m_use_preshared; cursor << m_use_preshared;
cursor << *m_preshared; cursor << *m_preshared;
cursor << m_auth_failed; cursor << m_last_status;
cursor << m_last_msg;
} }
@@ -261,7 +279,8 @@ size_t eap::config_method_with_cred::get_pk_size() const
pksizeof(m_allow_save ) + pksizeof(m_allow_save ) +
pksizeof(m_use_preshared) + pksizeof(m_use_preshared) +
pksizeof(*m_preshared ) + pksizeof(*m_preshared ) +
pksizeof(m_auth_failed ); pksizeof(m_last_status ) +
pksizeof(m_last_msg );
} }
@@ -271,7 +290,8 @@ void eap::config_method_with_cred::operator>>(_Inout_ cursor_in &cursor)
cursor >> m_allow_save; cursor >> m_allow_save;
cursor >> m_use_preshared; cursor >> m_use_preshared;
cursor >> *m_preshared; cursor >> *m_preshared;
cursor >> m_auth_failed; cursor >> m_last_status;
cursor >> m_last_msg;
} }

View File

@@ -197,6 +197,12 @@ eap::credentials_pass& eap::credentials_pass::operator=(_Inout_ credentials_pass
} }
eap::config* eap::credentials_pass::clone() const
{
return new credentials_pass(*this);
}
void eap::credentials_pass::clear() void eap::credentials_pass::clear()
{ {
credentials::clear(); credentials::clear();
@@ -275,7 +281,7 @@ void eap::credentials_pass::operator>>(_Inout_ cursor_in &cursor)
} }
void eap::credentials_pass::store(_In_z_ LPCTSTR pszTargetName) const void eap::credentials_pass::store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const
{ {
assert(pszTargetName); assert(pszTargetName);
@@ -290,7 +296,7 @@ void eap::credentials_pass::store(_In_z_ LPCTSTR pszTargetName) const
if (!CryptProtectData(&cred_blob, NULL, &entropy_blob, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &cred_enc)) if (!CryptProtectData(&cred_blob, NULL, &entropy_blob, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &cred_enc))
throw win_runtime_error(__FUNCTION__ " CryptProtectData failed."); throw win_runtime_error(__FUNCTION__ " CryptProtectData failed.");
tstring target(target_name(pszTargetName)); tstring target(target_name(pszTargetName, level));
// Write credentials. // Write credentials.
assert(cred_enc.cbData < CRED_MAX_CREDENTIAL_BLOB_SIZE); assert(cred_enc.cbData < CRED_MAX_CREDENTIAL_BLOB_SIZE);
@@ -314,13 +320,13 @@ void eap::credentials_pass::store(_In_z_ LPCTSTR pszTargetName) const
} }
void eap::credentials_pass::retrieve(_In_z_ LPCTSTR pszTargetName) void eap::credentials_pass::retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level)
{ {
assert(pszTargetName); assert(pszTargetName);
// Read credentials. // Read credentials.
unique_ptr<CREDENTIAL, CredFree_delete<CREDENTIAL> > cred; unique_ptr<CREDENTIAL, CredFree_delete<CREDENTIAL> > cred;
if (!CredRead(target_name(pszTargetName).c_str(), CRED_TYPE_GENERIC, 0, (PCREDENTIAL*)&cred)) if (!CredRead(target_name(pszTargetName, level).c_str(), CRED_TYPE_GENERIC, 0, (PCREDENTIAL*)&cred))
throw win_runtime_error(__FUNCTION__ " CredRead failed."); throw win_runtime_error(__FUNCTION__ " CredRead failed.");
// Decrypt the password using user's key. // Decrypt the password using user's key.
@@ -351,6 +357,49 @@ void eap::credentials_pass::retrieve(_In_z_ LPCTSTR pszTargetName)
} }
LPCTSTR eap::credentials_pass::target_suffix() const
{
return _T("pass");
}
eap::credentials::source_t eap::credentials_pass::combine(
_In_ const credentials *cred_cached,
_In_ const config_method_with_cred &cfg,
_In_opt_z_ LPCTSTR pszTargetName)
{
if (cred_cached) {
// Using EAP service cached credentials.
*this = *(credentials_pass*)cred_cached;
m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_CACHED1, event_data((unsigned int)cfg.get_method_id()), event_data(credentials_pass::get_name()), event_data::blank);
return source_cache;
}
if (cfg.m_use_preshared) {
// Using preshared credentials.
*this = *(credentials_pass*)cfg.m_preshared.get();
m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_PRESHARED1, event_data((unsigned int)cfg.get_method_id()), event_data(credentials_pass::get_name()), event_data::blank);
return source_preshared;
}
if (pszTargetName) {
try {
credentials_pass cred_loaded(m_module);
cred_loaded.retrieve(pszTargetName, cfg.m_level);
// Using stored credentials.
*this = std::move(cred_loaded);
m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_STORED1, event_data((unsigned int)cfg.get_method_id()), event_data(credentials_pass::get_name()), event_data::blank);
return source_storage;
} catch (...) {
// Not actually an error.
}
}
return source_unknown;
}
const unsigned char eap::credentials_pass::s_entropy[1024] = { const unsigned char eap::credentials_pass::s_entropy[1024] = {
0x40, 0x88, 0xd3, 0x13, 0x81, 0x8a, 0xf6, 0x74, 0x55, 0x8e, 0xcc, 0x73, 0x2c, 0xf8, 0x93, 0x37, 0x40, 0x88, 0xd3, 0x13, 0x81, 0x8a, 0xf6, 0x74, 0x55, 0x8e, 0xcc, 0x73, 0x2c, 0xf8, 0x93, 0x37,
0x4f, 0xeb, 0x1d, 0x66, 0xb7, 0xfb, 0x47, 0x75, 0xb4, 0xfd, 0x07, 0xbb, 0xf6, 0xb3, 0x05, 0x30, 0x4f, 0xeb, 0x1d, 0x66, 0xb7, 0xfb, 0x47, 0x75, 0xb4, 0xfd, 0x07, 0xbb, 0xf6, 0xb3, 0x05, 0x30,

View File

@@ -68,6 +68,11 @@ void eap::method::begin_session(
UNREFERENCED_PARAMETER(pAttributeArray); UNREFERENCED_PARAMETER(pAttributeArray);
UNREFERENCED_PARAMETER(hTokenImpersonateUser); UNREFERENCED_PARAMETER(hTokenImpersonateUser);
UNREFERENCED_PARAMETER(dwMaxSendPacketSize); 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_with_cred::status_auth_failed;
m_cfg.m_last_msg.clear();
} }
@@ -76,6 +81,34 @@ void eap::method::end_session()
} }
void eap::method::get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *ppResult)
{
assert(ppResult);
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_with_cred::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.
ppResult->fSaveConnectionData = TRUE;
ppResult->fIsSuccess = TRUE;
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// eap::method_noneap // eap::method_noneap
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@@ -199,7 +199,6 @@ public:
this->SetIcon(wxIcon(wxICON(product.ico))); this->SetIcon(wxIcon(wxICON(product.ico)));
#endif #endif
wstring target_name;
for (eap::config_connection::provider_list::iterator provider = m_cfg.m_providers.begin(), provider_end = m_cfg.m_providers.end(); provider != provider_end; ++provider) { for (eap::config_connection::provider_list::iterator provider = m_cfg.m_providers.begin(), provider_end = m_cfg.m_providers.end(); provider != provider_end; ++provider) {
bool is_single = provider->m_methods.size() == 1; bool is_single = provider->m_methods.size() == 1;
std::vector<std::unique_ptr<eap::config_method> >::size_type count = 0; std::vector<std::unique_ptr<eap::config_method> >::size_type count = 0;
@@ -268,16 +267,16 @@ protected:
m_cfg.m_providers.push_back(std::move(cfg_provider)); m_cfg.m_providers.push_back(std::move(cfg_provider));
eap::config_provider &cfg_provider2 = m_cfg.m_providers.back(); eap::config_provider &cfg_provider2 = m_cfg.m_providers.back();
eap::config_method *cfg_method2 = cfg_provider2.m_methods.front().get(); eap::config_method *cfg_method2 = cfg_provider2.m_methods.front().get();
m_providers->InsertPage( _wxT *page = new _wxT(cfg_provider2, *cfg_method2, m_providers);
m_providers->GetSelection() + 1, m_providers->InsertPage(m_providers->GetSelection() + 1, page, wxEAPGetProviderName(cfg_provider2.m_name), true);
new _wxT(
cfg_provider2,
*cfg_method2,
m_providers),
wxEAPGetProviderName(cfg_provider2.m_name), true);
this->Layout(); this->Layout();
this->Fit(); this->GetSizer()->Fit(this);
// We initialized other pages in OnInitDialog(). This one was added later so it needs to be initialized.
// (Timers in child panels didn't start otherwise.)
wxInitDialogEvent event_init;
page->GetEventHandler()->ProcessEvent(event_init);
} }
@@ -286,7 +285,7 @@ protected:
int idx = m_providers->GetSelection(); int idx = m_providers->GetSelection();
eap::config_provider &cfg_provider = ((_wxT*)m_providers->GetPage(idx))->GetProvider(); eap::config_provider &cfg_provider = ((_wxT*)m_providers->GetPage(idx))->GetProvider();
if (wxMessageBox(tstring_printf(_("Are you sure you want to permanently remove %ls provider from configuration?"), cfg_provider.m_name.c_str()), _("Warning"), wxYES_NO, this) == wxYES) { if (wxMessageBox(tstring_printf(_("Are you sure you want to permanently remove %ls provider from configuration?"), wxEAPGetProviderName(cfg_provider.m_name).c_str()), _("Warning"), wxYES_NO, this) == wxYES) {
// Delete provider. // Delete provider.
eap::config_connection::provider_list::iterator it(m_cfg.m_providers.begin()); eap::config_connection::provider_list::iterator it(m_cfg.m_providers.begin());
for (int i = 0; i < idx; i++, ++it); for (int i = 0; i < idx; i++, ++it);
@@ -433,7 +432,7 @@ public:
/// ///
/// Constructs a notice pannel and set the title text /// Constructs a notice pannel and set the title text
/// ///
wxEAPCredentialWarningPanel(const eap::config_provider &prov, wxWindow* parent); wxEAPCredentialWarningPanel(const eap::config_provider &prov, eap::config_method_with_cred::status status, wxWindow* parent);
}; };
@@ -682,7 +681,7 @@ protected:
if (dlg.ShowModal() == wxID_OK && panel->GetRemember()) { if (dlg.ShowModal() == wxID_OK && panel->GetRemember()) {
// Write credentials to credential manager. // Write credentials to credential manager.
try { try {
m_cred_own.store(m_prov.get_id().c_str()); m_cred_own.store(m_prov.get_id().c_str(), m_cfg.m_level);
m_has_own = TRUE; m_has_own = TRUE;
UpdateOwnIdentity(); UpdateOwnIdentity();
} catch (winstd::win_runtime_error &err) { } catch (winstd::win_runtime_error &err) {
@@ -698,7 +697,7 @@ protected:
virtual void OnClearOwn(wxCommandEvent& /*event*/) virtual void OnClearOwn(wxCommandEvent& /*event*/)
{ {
if (CredDelete(m_cred_own.target_name(m_prov.get_id().c_str()).c_str(), CRED_TYPE_GENERIC, 0)) { if (CredDelete(m_cred_own.target_name(m_prov.get_id().c_str(), m_cfg.m_level).c_str(), CRED_TYPE_GENERIC, 0)) {
m_own_identity->Clear(); m_own_identity->Clear();
m_has_own = false; m_has_own = false;
} else } else
@@ -720,6 +719,7 @@ protected:
virtual void OnTimerOwn(wxTimerEvent& /*event*/) virtual void OnTimerOwn(wxTimerEvent& /*event*/)
{ {
if (m_own_identity->IsShownOnScreen())
RetrieveOwnCredentials(); RetrieveOwnCredentials();
} }
@@ -727,7 +727,7 @@ protected:
void RetrieveOwnCredentials() void RetrieveOwnCredentials()
{ {
try { try {
m_cred_own.retrieve(m_prov.get_id().c_str()); m_cred_own.retrieve(m_prov.get_id().c_str(), m_cfg.m_level);
m_has_own = true; m_has_own = true;
UpdateOwnIdentity(); UpdateOwnIdentity();
} catch (winstd::win_runtime_error &err) { } catch (winstd::win_runtime_error &err) {
@@ -751,6 +751,7 @@ protected:
m_own_identity->SetValue( m_own_identity->SetValue(
!identity.empty() ? identity : !identity.empty() ? identity :
m_cred_own.empty() ? _("<empty>") : _("<blank ID>")); m_cred_own.empty() ? _("<empty>") : _("<blank ID>"));
m_own_identity->Refresh();
} }

View File

@@ -2358,7 +2358,7 @@
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="name">m_timer_own</property> <property name="name">m_timer_own</property>
<property name="oneshot">0</property> <property name="oneshot">0</property>
<property name="period">3000</property> <property name="period">5000</property>
<property name="permission">protected</property> <property name="permission">protected</property>
<event name="OnTimer">OnTimerOwn</event> <event name="OnTimer">OnTimerOwn</event>
</object> </object>

View File

@@ -239,14 +239,19 @@ wxEAPProviderLockedPanel::wxEAPProviderLockedPanel(const eap::config_provider &p
// wxEAPCredentialWarningPanel // wxEAPCredentialWarningPanel
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
wxEAPCredentialWarningPanel::wxEAPCredentialWarningPanel(const eap::config_provider &prov, wxWindow* parent) : wxEAPNotePanel(parent) wxEAPCredentialWarningPanel::wxEAPCredentialWarningPanel(const eap::config_provider &prov, eap::config_method_with_cred::status status, wxWindow* parent) : wxEAPNotePanel(parent)
{ {
// Load and set icon. // Load and set icon.
winstd::library lib_shell32; winstd::library lib_shell32;
if (lib_shell32.load(_T("shell32.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE)) if (lib_shell32.load(_T("shell32.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE))
m_note_icon->SetIcon(wxLoadIconFromResource(lib_shell32, MAKEINTRESOURCE(161))); m_note_icon->SetIcon(wxLoadIconFromResource(lib_shell32, MAKEINTRESOURCE(161)));
m_note_label->SetLabel(_("Previous attempt to connect failed. Please, make sure your credentials are correct, or try again later.")); m_note_label->SetLabel((
status == eap::config_method_with_cred::status_cred_invalid ? _("Previous attempt to connect reported invalid credentials.") :
status == eap::config_method_with_cred::status_cred_expired ? _("Previous attempt to connect reported your credentials expired.") :
status == eap::config_method_with_cred::status_cred_changing ? _("Previous attempt to connect reported your credentials are being changed.") :
_("Previous attempt to connect failed.")) + " " +
_("Please, make sure your credentials are correct, or try again later."));
m_note_label->Wrap(449); m_note_label->Wrap(449);
CreateContactFields(prov); CreateContactFields(prov);

Binary file not shown.

View File

@@ -80,14 +80,12 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<ItemGroup> <ItemGroup>
<ClInclude Include="..\include\Config.h" /> <ClInclude Include="..\include\Config.h" />
<ClInclude Include="..\include\Credentials.h" />
<ClInclude Include="..\include\Method.h" /> <ClInclude Include="..\include\Method.h" />
<ClInclude Include="..\include\MSCHAPv2.h" /> <ClInclude Include="..\include\MSCHAPv2.h" />
<ClInclude Include="..\src\StdAfx.h" /> <ClInclude Include="..\src\StdAfx.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\src\Config.cpp" /> <ClCompile Include="..\src\Config.cpp" />
<ClCompile Include="..\src\Credentials.cpp" />
<ClCompile Include="..\src\Method.cpp" /> <ClCompile Include="..\src\Method.cpp" />
<ClCompile Include="..\src\MSCHAPv2.cpp" /> <ClCompile Include="..\src\MSCHAPv2.cpp" />
<ClCompile Include="..\src\StdAfx.cpp"> <ClCompile Include="..\src\StdAfx.cpp">

View File

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

View File

@@ -30,7 +30,6 @@ namespace eap
#pragma once #pragma once
#include "Credentials.h"
#include "../../EAPBase/include/Config.h" #include "../../EAPBase/include/Config.h"
#include <Windows.h> #include <Windows.h>
@@ -47,8 +46,9 @@ namespace eap
/// Constructs configuration /// Constructs configuration
/// ///
/// \param[in] mod EAP module to use for global services /// \param[in] mod EAP module to use for global services
/// \param[in] level Config level (0=outer, 1=inner, 2=inner-inner...)
/// ///
config_method_mschapv2(_In_ module &mod); config_method_mschapv2(_In_ module &mod, _In_ unsigned int level);
/// ///
/// Copies configuration /// Copies configuration

View File

@@ -1,122 +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
{
///
/// MSCHAPv2 credentials
///
class credentials_mschapv2;
}
#pragma once
#include "Config.h"
#include "../../EAPBase/include/Credentials.h"
#include <Windows.h>
#include <sal.h>
#include <tchar.h>
namespace eap
{
class credentials_mschapv2 : public credentials_pass
{
public:
///
/// Constructs credentials
///
/// \param[in] mod EAP module to use for global services
///
credentials_mschapv2(_In_ module &mod);
///
/// Copies credentials
///
/// \param[in] other Credentials to copy from
///
credentials_mschapv2(_In_ const credentials_mschapv2 &other);
///
/// Moves credentials
///
/// \param[in] other Credentials to move from
///
credentials_mschapv2(_Inout_ credentials_mschapv2 &&other);
///
/// Copies credentials
///
/// \param[in] other Credentials to copy from
///
/// \returns Reference to this object
///
credentials_mschapv2& operator=(_In_ const credentials_mschapv2 &other);
///
/// Moves credentials
///
/// \param[in] other Credentials to move from
///
/// \returns Reference to this object
///
credentials_mschapv2& operator=(_Inout_ credentials_mschapv2 &&other);
///
/// Clones credentials
///
/// \returns Pointer to cloned credentials
///
virtual config* clone() const;
/// \name Storage
/// @{
///
/// Return target suffix for Windows Credential Manager credential name
///
virtual LPCTSTR target_suffix() const;
/// @}
///
/// Combine credentials in the following order:
///
/// 1. Cached credentials
/// 2. Pre-configured credentials
/// 3. Stored credentials
///
/// \param[in] cred_cached Cached credentials (optional, can be \c NULL, must be credentials_mschapv2* type)
/// \param[in] cfg Method configuration (must be config_method_mschapv2 type)
/// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from (optional, can be \c NULL)
///
/// \returns
/// - \c source_cache Credentials were obtained from EapHost cache
/// - \c source_preshared Credentials were set by method configuration
/// - \c source_storage Credentials were loaded from Windows Credential Manager
///
virtual source_t combine(
_In_ const credentials *cred_cached,
_In_ const config_method_with_cred &cfg,
_In_opt_z_ LPCTSTR pszTargetName);
};
}

View File

@@ -29,11 +29,12 @@ namespace eap
#pragma once #pragma once
#include "Config.h" #include "Config.h"
#include "Credentials.h"
#include "MSCHAPv2.h" #include "MSCHAPv2.h"
#include "../../EAPBase/include/Method.h" #include "../../EAPBase/include/Method.h"
#include <list>
namespace eap namespace eap
{ {
@@ -47,7 +48,7 @@ namespace eap
/// \param[in] cfg Method configuration /// \param[in] cfg Method configuration
/// \param[in] cred User credentials /// \param[in] cred User credentials
/// ///
method_mschapv2(_In_ module &module, _In_ config_method_mschapv2 &cfg, _In_ credentials_mschapv2 &cred); method_mschapv2(_In_ module &module, _In_ config_method_mschapv2 &cfg, _In_ credentials_pass &cred);
/// ///
/// Moves an EAP method /// Moves an EAP method
@@ -89,15 +90,6 @@ namespace eap
_In_ DWORD dwReceivedPacketSize, _In_ DWORD dwReceivedPacketSize,
_Inout_ EapPeerMethodOutput *pEapOutput); _Inout_ EapPeerMethodOutput *pEapOutput);
///
/// 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 *ppResult);
/// @} /// @}
friend class method_ttls; // Setting of initial challenge derived from TLS PRF friend class method_ttls; // Setting of initial challenge derived from TLS PRF
@@ -116,23 +108,31 @@ namespace eap
/// ///
/// \sa [Microsoft PPP CHAP Extensions, Version 2 (Chapter 5. Success Packet)](https://tools.ietf.org/html/rfc2759#section-5) /// \sa [Microsoft PPP CHAP Extensions, Version 2 (Chapter 5. Success Packet)](https://tools.ietf.org/html/rfc2759#section-5)
/// ///
/// \param[in] pck Packet data /// \param[in] argv List of message values
/// \param[in] size_pck \p pck size in bytes
/// ///
void process_success(_In_ int argc, _In_count_(argc) const wchar_t *argv[]); void process_success(_In_ const std::list<std::string> &argv);
/// ///
/// Processes MS-CHAP-Error AVP /// Processes MS-CHAP-Error AVP
/// ///
/// \sa [Microsoft PPP CHAP Extensions, Version 2 (Chapter 6. Failure Packet)](https://tools.ietf.org/html/rfc2759#section-6) /// \sa [Microsoft PPP CHAP Extensions, Version 2 (Chapter 6. Failure Packet)](https://tools.ietf.org/html/rfc2759#section-6)
/// ///
/// \param[in] pck Packet data /// \param[in] argv List of message values
/// \param[in] size_pck \p pck size in bytes
/// ///
void process_error(_In_ int argc, _In_count_(argc) const wchar_t *argv[]); void process_error(_In_ const std::list<std::string> &argv);
///
/// Splits MS-CHAP2-Success or MS-CHAP-Error messages
///
/// \param[in] resp MS-CHAP2-Success or MS-CHAP-Error message (i.e. "E=648 R=1 C=d86e0aa6cb5539e5fb31dd5dc5f6898c V=3 M=Password Expired")
/// \param[in] count Number of characters in \p resp
///
/// \returns A list of individual parts of \p resp message (i.e. ("E=648", "R=1", "C=d86e0aa6cb5539e5fb31dd5dc5f6898c", "V=3", "M=Password Expired"))
///
static std::list<std::string> parse_response(_In_count_(count) const char *resp, _In_ size_t count);
protected: protected:
credentials_mschapv2 &m_cred; ///< EAP-TLS user credentials credentials_pass &m_cred; ///< EAP-TLS user credentials
winstd::crypt_prov m_cp; ///< Cryptography provider for general services winstd::crypt_prov m_cp; ///< Cryptography provider for general services
challenge_mschapv2 m_challenge_server; ///< MSCHAP server challenge challenge_mschapv2 m_challenge_server; ///< MSCHAP server challenge
@@ -146,6 +146,6 @@ namespace eap
phase_init = 0, ///< Send client challenge phase_init = 0, ///< Send client challenge
phase_challenge_server, ///< Verify server challenge phase_challenge_server, ///< Verify server challenge
phase_finished, ///< Connection shut down phase_finished, ///< Connection shut down
} m_phase, m_phase_prev; ///< What phase is our communication at? } m_phase; ///< What phase is our communication at?
}; };
} }

View File

@@ -28,9 +28,9 @@ using namespace winstd;
// eap::config_method_mschapv2 // eap::config_method_mschapv2
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
eap::config_method_mschapv2::config_method_mschapv2(_In_ module &mod) : config_method_with_cred(mod) eap::config_method_mschapv2::config_method_mschapv2(_In_ module &mod, _In_ unsigned int level) : config_method_with_cred(mod, level)
{ {
m_preshared.reset(new credentials_mschapv2(mod)); m_preshared.reset(new credentials_pass(mod));
} }
@@ -84,5 +84,5 @@ const wchar_t* eap::config_method_mschapv2::get_method_str() const
eap::credentials* eap::config_method_mschapv2::make_credentials() const eap::credentials* eap::config_method_mschapv2::make_credentials() const
{ {
return new credentials_mschapv2(m_module); return new credentials_pass(m_module);
} }

View File

@@ -1,112 +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/>.
*/
#include "StdAfx.h"
using namespace std;
using namespace winstd;
//////////////////////////////////////////////////////////////////////
// eap::credentials_mschapv2
//////////////////////////////////////////////////////////////////////
eap::credentials_mschapv2::credentials_mschapv2(_In_ module &mod) : credentials_pass(mod)
{
}
eap::credentials_mschapv2::credentials_mschapv2(_In_ const credentials_mschapv2 &other) :
credentials_pass(other)
{
}
eap::credentials_mschapv2::credentials_mschapv2(_Inout_ credentials_mschapv2 &&other) :
credentials_pass(std::move(other))
{
}
eap::credentials_mschapv2& eap::credentials_mschapv2::operator=(_In_ const credentials_mschapv2 &other)
{
if (this != &other)
(credentials_pass&)*this = other;
return *this;
}
eap::credentials_mschapv2& eap::credentials_mschapv2::operator=(_Inout_ credentials_mschapv2 &&other)
{
if (this != &other)
(credentials_pass&&)*this = std::move(other);
return *this;
}
eap::config* eap::credentials_mschapv2::clone() const
{
return new credentials_mschapv2(*this);
}
LPCTSTR eap::credentials_mschapv2::target_suffix() const
{
return _T("MSCHAPv2");
}
eap::credentials::source_t eap::credentials_mschapv2::combine(
_In_ const credentials *cred_cached,
_In_ const config_method_with_cred &cfg,
_In_opt_z_ LPCTSTR pszTargetName)
{
if (cred_cached) {
// Using EAP service cached credentials.
*this = *(credentials_mschapv2*)cred_cached;
m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_CACHED1, event_data((unsigned int)eap_type_legacy_mschapv2), event_data(credentials_mschapv2::get_name()), event_data::blank);
return source_cache;
}
if (cfg.m_use_preshared) {
// Using preshared credentials.
*this = *(credentials_mschapv2*)cfg.m_preshared.get();
m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_PRESHARED1, event_data((unsigned int)eap_type_legacy_mschapv2), event_data(credentials_mschapv2::get_name()), event_data::blank);
return source_preshared;
}
if (pszTargetName) {
try {
credentials_mschapv2 cred_loaded(m_module);
cred_loaded.retrieve(pszTargetName);
// Using stored credentials.
*this = std::move(cred_loaded);
m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_STORED1, event_data((unsigned int)eap_type_legacy_mschapv2), event_data(credentials_mschapv2::get_name()), event_data::blank);
return source_storage;
} catch (...) {
// Not actually an error.
}
}
return source_unknown;
}

View File

@@ -103,15 +103,12 @@ eap::challenge_hash::challenge_hash(
_In_ const challenge_mschapv2 &challenge_client, _In_ const challenge_mschapv2 &challenge_client,
_In_z_ const char *username) _In_z_ const char *username)
{ {
const char *domain = strchr(username, '@');
size_t len_username = domain ? domain - username : strlen(username);
crypt_hash hash; crypt_hash hash;
if (!hash.create(cp, CALG_SHA)) if (!hash.create(cp, CALG_SHA))
throw win_runtime_error(__FUNCTION__ " Creating SHA hash failed."); throw win_runtime_error(__FUNCTION__ " Creating SHA hash failed.");
if (!CryptHashData(hash, (const BYTE*)&challenge_client, (DWORD)sizeof(challenge_client), 0) || if (!CryptHashData(hash, (const BYTE*)&challenge_client, (DWORD)sizeof(challenge_client), 0) ||
!CryptHashData(hash, (const BYTE*)&challenge_server, (DWORD)sizeof(challenge_server), 0) || !CryptHashData(hash, (const BYTE*)&challenge_server, (DWORD)sizeof(challenge_server), 0) ||
!CryptHashData(hash, (const BYTE*)username , (DWORD)len_username , 0)) !CryptHashData(hash, (const BYTE*)username , (DWORD)strlen(username) , 0))
throw win_runtime_error(__FUNCTION__ " Error hashing data."); throw win_runtime_error(__FUNCTION__ " Error hashing data.");
unsigned char hash_val[20]; unsigned char hash_val[20];
DWORD size_hash_val = sizeof(hash_val); DWORD size_hash_val = sizeof(hash_val);

View File

@@ -28,12 +28,11 @@ using namespace winstd;
// eap::method_mschapv2 // eap::method_mschapv2
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
eap::method_mschapv2::method_mschapv2(_In_ module &module, _In_ config_method_mschapv2 &cfg, _In_ credentials_mschapv2 &cred) : eap::method_mschapv2::method_mschapv2(_In_ module &module, _In_ config_method_mschapv2 &cfg, _In_ credentials_pass &cred) :
m_cred(cred), m_cred(cred),
m_ident(0), m_ident(0),
m_success(false), m_success(false),
m_phase(phase_unknown), m_phase(phase_unknown),
m_phase_prev(phase_unknown),
method_noneap(module, cfg, cred) method_noneap(module, cfg, cred)
{ {
} }
@@ -48,7 +47,6 @@ eap::method_mschapv2::method_mschapv2(_Inout_ method_mschapv2 &&other) :
m_nt_resp (std::move(other.m_nt_resp )), m_nt_resp (std::move(other.m_nt_resp )),
m_success (std::move(other.m_success )), m_success (std::move(other.m_success )),
m_phase (std::move(other.m_phase )), m_phase (std::move(other.m_phase )),
m_phase_prev (std::move(other.m_phase_prev )),
method_noneap (std::move(other )) method_noneap (std::move(other ))
{ {
} }
@@ -66,7 +64,6 @@ eap::method_mschapv2& eap::method_mschapv2::operator=(_Inout_ method_mschapv2 &&
m_nt_resp = std::move(other.m_nt_resp ); m_nt_resp = std::move(other.m_nt_resp );
m_success = std::move(other.m_success ); m_success = std::move(other.m_success );
m_phase = std::move(other.m_phase ); m_phase = std::move(other.m_phase );
m_phase_prev = std::move(other.m_phase_prev );
} }
return *this; return *this;
@@ -100,17 +97,16 @@ void eap::method_mschapv2::process_request_packet(
m_module.log_event(&EAPMETHOD_PACKET_RECV, event_data((unsigned int)eap_type_legacy_mschapv2), event_data((unsigned int)dwReceivedPacketSize), event_data::blank); m_module.log_event(&EAPMETHOD_PACKET_RECV, event_data((unsigned int)eap_type_legacy_mschapv2), event_data((unsigned int)dwReceivedPacketSize), event_data::blank);
process_packet(pReceivedPacket, dwReceivedPacketSize);
m_phase_prev = m_phase;
switch (m_phase) { switch (m_phase) {
case phase_init: { case phase_init: {
// Convert username to UTF-8. // Convert username to UTF-8.
sanitizing_string identity_utf8; sanitizing_string identity_utf8;
WideCharToMultiByte(CP_UTF8, 0, m_cred.m_identity.c_str(), (int)m_cred.m_identity.length(), identity_utf8, NULL, NULL); WideCharToMultiByte(CP_UTF8, 0, m_cred.m_identity.c_str(), (int)m_cred.m_identity.length(), identity_utf8, NULL, NULL);
// Calculate Peer-Challenge and Response // Randomize Peer-Challenge
m_challenge_client.randomize(m_cp); m_challenge_client.randomize(m_cp);
// Calculate NT-Response
m_nt_resp = nt_response(m_cp, m_challenge_server, m_challenge_client, identity_utf8.c_str(), m_cred.m_password.c_str()); 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 // Prepare MS-CHAP2-Response
@@ -129,15 +125,18 @@ void eap::method_mschapv2::process_request_packet(
// Diameter AVP (User-Name=1, MS-CHAP-Challenge=11/311, MS-CHAP2-Response=25/311) // 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( 1, diameter_avp_flag_mandatory, identity_utf8.data(), (unsigned int)identity_utf8.size() );
append_avp(11, 311, diameter_avp_flag_mandatory, (unsigned char*)&m_challenge_server , (unsigned char)sizeof(m_challenge_server)); append_avp(11, 311, diameter_avp_flag_mandatory, (unsigned char*)&m_challenge_server , (unsigned int)sizeof(m_challenge_server));
append_avp(25, 311, diameter_avp_flag_mandatory, response.data() , (unsigned char)response.size() ); append_avp(25, 311, diameter_avp_flag_mandatory, response.data() , (unsigned int)response.size() );
m_phase = phase_challenge_server; m_phase = phase_challenge_server;
m_cfg.m_last_status = config_method_with_cred::status_cred_invalid; // Blame credentials if we fail beyond this point.
break; break;
} }
case phase_challenge_server: { case phase_challenge_server: {
// We do not need to do anything. process_packet(pReceivedPacket, dwReceivedPacketSize);
if (m_success)
m_phase = phase_finished;
break; break;
} }
@@ -150,48 +149,6 @@ void eap::method_mschapv2::process_request_packet(
} }
void eap::method_mschapv2::get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *ppResult)
{
assert(ppResult);
switch (reason) {
case EapPeerMethodResultSuccess: {
m_module.log_event(&EAPMETHOD_METHOD_SUCCESS, event_data((unsigned int)eap_type_legacy_mschapv2), event_data::blank);
m_cfg.m_auth_failed = false;
ppResult->fIsSuccess = TRUE;
ppResult->dwFailureReasonCode = ERROR_SUCCESS;
break;
}
case EapPeerMethodResultFailure:
m_module.log_event(
m_phase_prev < phase_finished ? &EAPMETHOD_METHOD_FAILURE_INIT : &EAPMETHOD_METHOD_FAILURE,
event_data((unsigned int)eap_type_legacy_mschapv2), event_data::blank);
// Mark credentials as failed, so GUI can re-prompt user.
// But be careful: do so only after credentials were actually tried.
m_cfg.m_auth_failed = m_phase_prev < phase_finished && m_phase >= phase_finished;
// 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.
//ppResult->fIsSuccess = FALSE;
//ppResult->dwFailureReasonCode = EAP_E_AUTHENTICATION_FAILED;
break;
default:
throw win_runtime_error(ERROR_NOT_SUPPORTED, __FUNCTION__ " Not supported.");
}
// Always ask EAP host to save the connection data.
ppResult->fSaveConnectionData = TRUE;
}
void eap::method_mschapv2::process_packet(_In_bytecount_(size_pck) const void *_pck, _In_ size_t size_pck) void eap::method_mschapv2::process_packet(_In_bytecount_(size_pck) const void *_pck, _In_ size_t size_pck)
{ {
sanitizing_blob data; sanitizing_blob data;
@@ -214,43 +171,44 @@ void eap::method_mschapv2::process_packet(_In_bytecount_(size_pck) const void *_
vendor = 0; vendor = 0;
msg = (const unsigned char*)(hdr + 1); msg = (const unsigned char*)(hdr + 1);
} }
const unsigned char *msg_end = pck + ntohs(*(unsigned short*)hdr->length); unsigned int length = ntoh24(hdr->length);
const unsigned char
*msg_end = pck + length,
*msg_next = msg_end + (4 - length) % 4;
if (msg_end > pck_end) if (msg_end > pck_end)
throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Incomplete message data."); throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Incomplete message data.");
if (code == 26 && vendor == 311) { if (code == 26 && vendor == 311) {
// MS-CHAP2-Success // MS-CHAP2-Success
MultiByteToWideChar(CP_UTF8, 0, (const char*)msg, (int)(msg_end - msg), msg_w); if (msg[0] != m_ident)
int argc; throw invalid_argument(string_printf(__FUNCTION__ " Wrong MSCHAPv2 ident (expected: %u, received: %u).", m_ident, msg[0]).c_str());
unique_ptr<LPWSTR[], LocalFree_delete<LPWSTR[]> > argv(CommandLineToArgvW(msg_w.c_str(), &argc)); const char *str = (const char*)(msg + 1);
if (!argv) argc = 0; process_success(parse_response(str, ((const char*)msg_end - str)));
process_success(argc, (const wchar_t**)argv.get());
} else if (code == 2 && vendor == 311) { } else if (code == 2 && vendor == 311) {
// MS-CHAP2-Error // MS-CHAP2-Error
MultiByteToWideChar(CP_UTF8, 0, (const char*)msg, (int)(msg_end - msg), msg_w); m_ident = msg[0];
int argc; const char *str = (const char*)(msg + 1);
unique_ptr<LPWSTR[], LocalFree_delete<LPWSTR[]> > argv(CommandLineToArgvW(msg_w.c_str(), &argc)); process_error(parse_response(str, ((const char*)msg_end - str)));
if (!argv) argc = 0;
process_error(argc, (const wchar_t**)argv.get());
} else if (hdr->flags & diameter_avp_flag_mandatory) } else if (hdr->flags & diameter_avp_flag_mandatory)
throw win_runtime_error(ERROR_NOT_SUPPORTED, string_printf(__FUNCTION__ " Server sent mandatory Diameter AVP we do not support (code: %u, vendor: %u).", code, vendor).c_str()); throw win_runtime_error(ERROR_NOT_SUPPORTED, string_printf(__FUNCTION__ " Server sent mandatory Diameter AVP we do not support (code: %u, vendor: %u).", code, vendor).c_str());
pck = msg_end; pck = msg_next;
} }
} }
void eap::method_mschapv2::process_success(_In_ int argc, _In_count_(argc) const wchar_t *argv[]) void eap::method_mschapv2::process_success(_In_ const list<string> &argv)
{ {
m_success = false; m_success = false;
for (int i = 0; i < argc; i++) { for (list<string>::const_iterator arg = argv.cbegin(), arg_end = argv.cend(); arg != arg_end; ++arg) {
if ((argv[i][0] == L'S' || argv[i][0] == L's') && argv[i][1] == L'=') { const string &val = *arg;
if ((val[0] == 'S' || val[0] == 's') && val[1] == '=') {
// "S=" // "S="
hex_dec dec; hex_dec dec;
sanitizing_blob resp; sanitizing_blob resp;
bool is_last; bool is_last;
dec.decode(resp, is_last, argv[i] + 2, (size_t)-1); dec.decode(resp, is_last, val.data() + 2, (size_t)-1);
// Calculate expected authenticator response. // Calculate expected authenticator response.
sanitizing_string identity_utf8; sanitizing_string identity_utf8;
@@ -258,7 +216,7 @@ void eap::method_mschapv2::process_success(_In_ int argc, _In_count_(argc) const
authenticator_response resp_exp(m_cp, m_challenge_server, m_challenge_client, identity_utf8.c_str(), m_cred.m_password.c_str(), m_nt_resp); authenticator_response resp_exp(m_cp, m_challenge_server, m_challenge_client, identity_utf8.c_str(), m_cred.m_password.c_str(), m_nt_resp);
// Compare against provided authemticator response. // Compare against provided authemticator response.
if (resp.size() != sizeof(resp_exp) || memcpy(resp.data(), &resp_exp, sizeof(resp_exp)) != 0) if (resp.size() != sizeof(resp_exp) || memcmp(resp.data(), &resp_exp, sizeof(resp_exp)) != 0)
throw invalid_argument(__FUNCTION__ " MS-CHAP2-Success authentication response string failed."); throw invalid_argument(__FUNCTION__ " MS-CHAP2-Success authentication response string failed.");
m_success = true; m_success = true;
@@ -267,13 +225,60 @@ void eap::method_mschapv2::process_success(_In_ int argc, _In_count_(argc) const
if (!m_success) if (!m_success)
throw invalid_argument(__FUNCTION__ " MS-CHAP2-Success authentication response string not found."); throw invalid_argument(__FUNCTION__ " MS-CHAP2-Success authentication response string not found.");
//m_module.log_event(&EAPMETHOD_TLS_ALERT, event_data((unsigned int)eap_type_tls), event_data((unsigned char)msg[0]), event_data((unsigned char)msg[1]), event_data::blank);
} }
void eap::method_mschapv2::process_error(_In_ int argc, _In_count_(argc) const wchar_t *argv[]) void eap::method_mschapv2::process_error(_In_ const list<string> &argv)
{ {
UNREFERENCED_PARAMETER(argc); for (list<string>::const_iterator arg = argv.cbegin(), arg_end = argv.cend(); arg != arg_end; ++arg) {
UNREFERENCED_PARAMETER(argv); const string &val = *arg;
if ((val[0] == 'E' || val[0] == 'e') && val[1] == '=') {
DWORD dwResult = strtoul(val.data() + 2, NULL, 10);
m_module.log_event(&EAPMETHOD_METHOD_FAILURE_ERROR, event_data((unsigned int)eap_type_legacy_mschapv2), event_data(dwResult), event_data::blank);
switch (dwResult) {
case ERROR_ACCT_DISABLED : m_cfg.m_last_status = config_method_with_cred::status_account_disabled ; break;
case ERROR_RESTRICTED_LOGON_HOURS: m_cfg.m_last_status = config_method_with_cred::status_account_logon_hours; break;
case ERROR_NO_DIALIN_PERMISSION : m_cfg.m_last_status = config_method_with_cred::status_account_denied ; break;
case ERROR_PASSWD_EXPIRED : m_cfg.m_last_status = config_method_with_cred::status_cred_expired ; break;
case ERROR_CHANGING_PASSWORD : m_cfg.m_last_status = config_method_with_cred::status_cred_changing ; break;
default : m_cfg.m_last_status = config_method_with_cred::status_cred_invalid ;
}
} else if ((val[0] == 'C' || val[0] == 'c') && val[1] == '=') {
hex_dec dec;
sanitizing_blob resp;
bool is_last;
dec.decode(resp, is_last, val.data() + 2, (size_t)-1);
if (resp.size() != sizeof(m_challenge_server))
throw invalid_argument(string_printf(__FUNCTION__ " Incorrect MSCHAPv2 challenge length (expected: %uB, received: %uB).", sizeof(m_challenge_server), resp.size()).c_str());
memcpy(&m_challenge_server, resp.data(), sizeof(m_challenge_server));
} else if ((val[0] == 'M' || val[0] == 'm') && val[1] == '=') {
MultiByteToWideChar(CP_UTF8, 0, val.data() + 2, -1, m_cfg.m_last_msg);
m_module.log_event(&EAPMETHOD_METHOD_FAILURE_ERROR1, event_data((unsigned int)eap_type_legacy_mschapv2), event_data(m_cfg.m_last_msg), event_data::blank);
}
}
}
list<string> eap::method_mschapv2::parse_response(_In_count_(count) const char *resp, _In_ size_t count)
{
list<string> argv;
for (size_t i = 0; i < count && resp[i]; ) {
if (i + 1 < count && (resp[i] == 'M' || resp[i] == 'm') && resp[i + 1] == '=') {
// The message is always the last value. It may contain spaces and it spans to the end.
argv.push_back(string(resp + i, strnlen(resp + i, count - i)));
break;
} else if (!isspace(resp[i])) {
// Search for the next space and add value up to it.
size_t j;
for (j = i + 1; j < count && resp[j] && !isspace(resp[j]); j++);
argv.push_back(string(resp + i, j - i));
i = j + 1;
} else {
// Skip (multiple) spaces.
i++;
}
}
return argv;
} }

View File

@@ -21,7 +21,6 @@
#pragma once #pragma once
#include "../include/Config.h" #include "../include/Config.h"
#include "../include/Credentials.h"
#include "../include/Method.h" #include "../include/Method.h"
#include "../include/MSCHAPv2.h" #include "../include/MSCHAPv2.h"
@@ -29,3 +28,4 @@
#include <Windows.h> #include <Windows.h>
#include <EapHostError.h> // include after Windows.h #include <EapHostError.h> // include after Windows.h
#include <RasError.h>

View File

@@ -20,12 +20,11 @@
#include "../../EAPBase_UI/include/EAP_UI.h" #include "../../EAPBase_UI/include/EAP_UI.h"
#include "../../MSCHAPv2/include/Config.h" #include "../../MSCHAPv2/include/Config.h"
#include "../../MSCHAPv2/include/Credentials.h"
/// ///
/// MSCHAPv2 credential configuration panel /// MSCHAPv2 credential configuration panel
/// ///
typedef wxEAPCredentialsConfigPanel<eap::credentials_mschapv2, wxPasswordCredentialsPanel<eap::credentials_mschapv2, wxEAPCredentialsPassPanelBase> > wxMSCHAPv2CredentialsConfigPanel; typedef wxEAPCredentialsConfigPanel<eap::credentials_pass, wxPasswordCredentialsPanel<eap::credentials_pass, wxEAPCredentialsPassPanelBase> > wxMSCHAPv2CredentialsConfigPanel;
/// ///
/// MSCHAPv2 configuration panel /// MSCHAPv2 configuration panel
@@ -35,7 +34,7 @@ class wxMSCHAPv2ConfigPanel;
/// ///
/// MSCHAPv2 credential entry panel /// MSCHAPv2 credential entry panel
/// ///
typedef wxPasswordCredentialsPanel<eap::credentials_mschapv2, wxEAPCredentialsPassPanelBase> wxMSCHAPv2CredentialsPanel; typedef wxPasswordCredentialsPanel<eap::credentials_pass, wxEAPCredentialsPassPanelBase> wxMSCHAPv2CredentialsPanel;
#pragma once #pragma once

View File

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

View File

@@ -17,9 +17,6 @@
<ClInclude Include="..\include\Config.h"> <ClInclude Include="..\include\Config.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\include\Credentials.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\Method.h"> <ClInclude Include="..\include\Method.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@@ -31,9 +28,6 @@
<ClCompile Include="..\src\Config.cpp"> <ClCompile Include="..\src\Config.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\src\Credentials.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\Method.cpp"> <ClCompile Include="..\src\Method.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>

View File

@@ -30,7 +30,6 @@ namespace eap
#pragma once #pragma once
#include "Credentials.h"
#include "../../EAPBase/include/Config.h" #include "../../EAPBase/include/Config.h"
#include <Windows.h> #include <Windows.h>
@@ -47,8 +46,9 @@ namespace eap
/// Constructs configuration /// Constructs configuration
/// ///
/// \param[in] mod EAP module to use for global services /// \param[in] mod EAP module to use for global services
/// \param[in] level Config level (0=outer, 1=inner, 2=inner-inner...)
/// ///
config_method_pap(_In_ module &mod); config_method_pap(_In_ module &mod, _In_ unsigned int level);
/// ///
/// Copies configuration /// Copies configuration

View File

@@ -1,122 +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
{
///
/// PAP credentials
///
class credentials_pap;
}
#pragma once
#include "Config.h"
#include "../../EAPBase/include/Credentials.h"
#include <Windows.h>
#include <sal.h>
#include <tchar.h>
namespace eap
{
class credentials_pap : public credentials_pass
{
public:
///
/// Constructs credentials
///
/// \param[in] mod EAP module to use for global services
///
credentials_pap(_In_ module &mod);
///
/// Copies credentials
///
/// \param[in] other Credentials to copy from
///
credentials_pap(_In_ const credentials_pap &other);
///
/// Moves credentials
///
/// \param[in] other Credentials to move from
///
credentials_pap(_Inout_ credentials_pap &&other);
///
/// Copies credentials
///
/// \param[in] other Credentials to copy from
///
/// \returns Reference to this object
///
credentials_pap& operator=(_In_ const credentials_pap &other);
///
/// Moves credentials
///
/// \param[in] other Credentials to move from
///
/// \returns Reference to this object
///
credentials_pap& operator=(_Inout_ credentials_pap &&other);
///
/// Clones credentials
///
/// \returns Pointer to cloned credentials
///
virtual config* clone() const;
/// \name Storage
/// @{
///
/// Return target suffix for Windows Credential Manager credential name
///
virtual LPCTSTR target_suffix() const;
/// @}
///
/// Combine credentials in the following order:
///
/// 1. Cached credentials
/// 2. Pre-configured credentials
/// 3. Stored credentials
///
/// \param[in] cred_cached Cached credentials (optional, can be \c NULL, must be credentials_pap* type)
/// \param[in] cfg Method configuration (must be config_method_pap type)
/// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from (optional, can be \c NULL)
///
/// \returns
/// - \c source_cache Credentials were obtained from EapHost cache
/// - \c source_preshared Credentials were set by method configuration
/// - \c source_storage Credentials were loaded from Windows Credential Manager
///
virtual source_t combine(
_In_ const credentials *cred_cached,
_In_ const config_method_with_cred &cfg,
_In_opt_z_ LPCTSTR pszTargetName);
};
}

View File

@@ -30,7 +30,6 @@ namespace eap
#pragma once #pragma once
#include "Config.h" #include "Config.h"
#include "Credentials.h"
#include "../../EAPBase/include/Method.h" #include "../../EAPBase/include/Method.h"
@@ -47,7 +46,7 @@ namespace eap
/// \param[in] cfg Method configuration /// \param[in] cfg Method configuration
/// \param[in] cred User credentials /// \param[in] cred User credentials
/// ///
method_pap(_In_ module &module, _In_ config_method_pap &cfg, _In_ credentials_pap &cred); method_pap(_In_ module &module, _In_ config_method_pap &cfg, _In_ credentials_pass &cred);
/// ///
/// Moves an EAP method /// Moves an EAP method
@@ -89,24 +88,15 @@ namespace eap
_In_ DWORD dwReceivedPacketSize, _In_ DWORD dwReceivedPacketSize,
_Inout_ EapPeerMethodOutput *pEapOutput); _Inout_ EapPeerMethodOutput *pEapOutput);
///
/// 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 *ppResult);
/// @} /// @}
protected: protected:
credentials_pap &m_cred; ///< EAP-TLS user credentials credentials_pass &m_cred; ///< EAP-TLS user credentials
enum { enum {
phase_unknown = -1, ///< Unknown phase phase_unknown = -1, ///< Unknown phase
phase_init = 0, ///< Handshake initialize phase_init = 0, ///< Handshake initialize
phase_finished, ///< Connection shut down phase_finished, ///< Connection shut down
} m_phase, m_phase_prev; ///< What phase is our communication at? } m_phase; ///< What phase is our communication at?
}; };
} }

View File

@@ -28,9 +28,9 @@ using namespace winstd;
// eap::config_method_pap // eap::config_method_pap
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
eap::config_method_pap::config_method_pap(_In_ module &mod) : config_method_with_cred(mod) eap::config_method_pap::config_method_pap(_In_ module &mod, _In_ unsigned int level) : config_method_with_cred(mod, level)
{ {
m_preshared.reset(new credentials_pap(mod)); m_preshared.reset(new credentials_pass(mod));
} }
@@ -84,5 +84,5 @@ const wchar_t* eap::config_method_pap::get_method_str() const
eap::credentials* eap::config_method_pap::make_credentials() const eap::credentials* eap::config_method_pap::make_credentials() const
{ {
return new credentials_pap(m_module); return new credentials_pass(m_module);
} }

View File

@@ -1,112 +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/>.
*/
#include "StdAfx.h"
using namespace std;
using namespace winstd;
//////////////////////////////////////////////////////////////////////
// eap::credentials_pap
//////////////////////////////////////////////////////////////////////
eap::credentials_pap::credentials_pap(_In_ module &mod) : credentials_pass(mod)
{
}
eap::credentials_pap::credentials_pap(_In_ const credentials_pap &other) :
credentials_pass(other)
{
}
eap::credentials_pap::credentials_pap(_Inout_ credentials_pap &&other) :
credentials_pass(std::move(other))
{
}
eap::credentials_pap& eap::credentials_pap::operator=(_In_ const credentials_pap &other)
{
if (this != &other)
(credentials_pass&)*this = other;
return *this;
}
eap::credentials_pap& eap::credentials_pap::operator=(_Inout_ credentials_pap &&other)
{
if (this != &other)
(credentials_pass&&)*this = std::move(other);
return *this;
}
eap::config* eap::credentials_pap::clone() const
{
return new credentials_pap(*this);
}
LPCTSTR eap::credentials_pap::target_suffix() const
{
return _T("PAP");
}
eap::credentials::source_t eap::credentials_pap::combine(
_In_ const credentials *cred_cached,
_In_ const config_method_with_cred &cfg,
_In_opt_z_ LPCTSTR pszTargetName)
{
if (cred_cached) {
// Using EAP service cached credentials.
*this = *(credentials_pap*)cred_cached;
m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_CACHED1, event_data((unsigned int)eap_type_legacy_pap), event_data(credentials_pap::get_name()), event_data::blank);
return source_cache;
}
if (cfg.m_use_preshared) {
// Using preshared credentials.
*this = *(credentials_pap*)cfg.m_preshared.get();
m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_PRESHARED1, event_data((unsigned int)eap_type_legacy_pap), event_data(credentials_pap::get_name()), event_data::blank);
return source_preshared;
}
if (pszTargetName) {
try {
credentials_pap cred_loaded(m_module);
cred_loaded.retrieve(pszTargetName);
// Using stored credentials.
*this = std::move(cred_loaded);
m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_STORED1, event_data((unsigned int)eap_type_legacy_pap), event_data(credentials_pap::get_name()), event_data::blank);
return source_storage;
} catch (...) {
// Not actually an error.
}
}
return source_unknown;
}

View File

@@ -28,10 +28,9 @@ using namespace winstd;
// eap::method_pap // eap::method_pap
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
eap::method_pap::method_pap(_In_ module &module, _In_ config_method_pap &cfg, _In_ credentials_pap &cred) : eap::method_pap::method_pap(_In_ module &module, _In_ config_method_pap &cfg, _In_ credentials_pass &cred) :
m_cred(cred), m_cred(cred),
m_phase(phase_unknown), m_phase(phase_unknown),
m_phase_prev(phase_unknown),
method_noneap(module, cfg, cred) method_noneap(module, cfg, cred)
{ {
} }
@@ -40,7 +39,6 @@ eap::method_pap::method_pap(_In_ module &module, _In_ config_method_pap &cfg, _I
eap::method_pap::method_pap(_Inout_ method_pap &&other) : eap::method_pap::method_pap(_Inout_ method_pap &&other) :
m_cred ( other.m_cred ), m_cred ( other.m_cred ),
m_phase (std::move(other.m_phase )), m_phase (std::move(other.m_phase )),
m_phase_prev (std::move(other.m_phase_prev)),
method_noneap(std::move(other )) method_noneap(std::move(other ))
{ {
} }
@@ -52,7 +50,6 @@ eap::method_pap& eap::method_pap::operator=(_Inout_ method_pap &&other)
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method with same credentials only! assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method with same credentials only!
(method_noneap&)*this = std::move(other ); (method_noneap&)*this = std::move(other );
m_phase = std::move(other.m_phase ); m_phase = std::move(other.m_phase );
m_phase_prev = std::move(other.m_phase_prev);
} }
return *this; return *this;
@@ -82,7 +79,6 @@ void eap::method_pap::process_request_packet(
m_module.log_event(&EAPMETHOD_PACKET_RECV, event_data((unsigned int)eap_type_legacy_pap), event_data((unsigned int)dwReceivedPacketSize), event_data::blank); m_module.log_event(&EAPMETHOD_PACKET_RECV, event_data((unsigned int)eap_type_legacy_pap), event_data((unsigned int)dwReceivedPacketSize), event_data::blank);
m_phase_prev = m_phase;
switch (m_phase) { switch (m_phase) {
case phase_init: { case phase_init: {
// Convert username and password to UTF-8. // Convert username and password to UTF-8.
@@ -101,6 +97,7 @@ void eap::method_pap::process_request_packet(
append_avp(2, diameter_avp_flag_mandatory, password_utf8.data(), (unsigned int)password_utf8.size()); append_avp(2, diameter_avp_flag_mandatory, password_utf8.data(), (unsigned int)password_utf8.size());
m_phase = phase_finished; m_phase = phase_finished;
m_cfg.m_last_status = config_method_with_cred::status_cred_invalid; // Blame credentials if we fail beyond this point.
break; break;
} }
@@ -111,45 +108,3 @@ void eap::method_pap::process_request_packet(
pEapOutput->fAllowNotifications = TRUE; pEapOutput->fAllowNotifications = TRUE;
pEapOutput->action = EapPeerMethodResponseActionSend; pEapOutput->action = EapPeerMethodResponseActionSend;
} }
void eap::method_pap::get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *ppResult)
{
assert(ppResult);
switch (reason) {
case EapPeerMethodResultSuccess: {
m_module.log_event(&EAPMETHOD_METHOD_SUCCESS, event_data((unsigned int)eap_type_legacy_pap), event_data::blank);
m_cfg.m_auth_failed = false;
ppResult->fIsSuccess = TRUE;
ppResult->dwFailureReasonCode = ERROR_SUCCESS;
break;
}
case EapPeerMethodResultFailure:
m_module.log_event(
m_phase_prev < phase_finished ? &EAPMETHOD_METHOD_FAILURE_INIT : &EAPMETHOD_METHOD_FAILURE,
event_data((unsigned int)eap_type_legacy_pap), event_data::blank);
// Mark credentials as failed, so GUI can re-prompt user.
// But be careful: do so only after credentials were actually tried.
m_cfg.m_auth_failed = m_phase_prev < phase_finished && m_phase >= phase_finished;
// 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.
//ppResult->fIsSuccess = FALSE;
//ppResult->dwFailureReasonCode = EAP_E_AUTHENTICATION_FAILED;
break;
default:
throw win_runtime_error(ERROR_NOT_SUPPORTED, __FUNCTION__ " Not supported.");
}
// Always ask EAP host to save the connection data.
ppResult->fSaveConnectionData = TRUE;
}

View File

@@ -21,7 +21,6 @@
#pragma once #pragma once
#include "../include/Config.h" #include "../include/Config.h"
#include "../include/Credentials.h"
#include "../include/Method.h" #include "../include/Method.h"
#include <Windows.h> #include <Windows.h>

View File

@@ -20,12 +20,11 @@
#include "../../EAPBase_UI/include/EAP_UI.h" #include "../../EAPBase_UI/include/EAP_UI.h"
#include "../../PAP/include/Config.h" #include "../../PAP/include/Config.h"
#include "../../PAP/include/Credentials.h"
/// ///
/// PAP credential configuration panel /// PAP credential configuration panel
/// ///
typedef wxEAPCredentialsConfigPanel<eap::credentials_pap, wxPasswordCredentialsPanel<eap::credentials_pap, wxEAPCredentialsPassPanelBase> > wxPAPCredentialsConfigPanel; typedef wxEAPCredentialsConfigPanel<eap::credentials_pass, wxPasswordCredentialsPanel<eap::credentials_pass, wxEAPCredentialsPassPanelBase> > wxPAPCredentialsConfigPanel;
/// ///
/// PAP configuration panel /// PAP configuration panel
@@ -35,7 +34,7 @@ class wxPAPConfigPanel;
/// ///
/// PAP credential entry panel /// PAP credential entry panel
/// ///
typedef wxPasswordCredentialsPanel<eap::credentials_pap, wxEAPCredentialsPassPanelBase> wxPAPCredentialsPanel; typedef wxPasswordCredentialsPanel<eap::credentials_pass, wxEAPCredentialsPassPanelBase> wxPAPCredentialsPanel;
#pragma once #pragma once

View File

@@ -67,8 +67,9 @@ namespace eap
/// Constructs configuration /// Constructs configuration
/// ///
/// \param[in] mod EAP module to use for global services /// \param[in] mod EAP module to use for global services
/// \param[in] level Config level (0=outer, 1=inner, 2=inner-inner...)
/// ///
config_method_tls(_In_ module &mod); config_method_tls(_In_ module &mod, _In_ unsigned int level);
/// ///
/// Copies configuration /// Copies configuration

View File

@@ -158,15 +158,17 @@ namespace eap
/// Save credentials to Windows Credential Manager /// Save credentials to Windows Credential Manager
/// ///
/// \param[in] pszTargetName The name in Windows Credential Manager to store credentials as /// \param[in] pszTargetName The name in Windows Credential Manager to store credentials as
/// \param[in] level Credential level (0=outer, 1=inner, 2=inner-inner...)
/// ///
virtual void store(_In_z_ LPCTSTR pszTargetName) const; virtual void store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const;
/// ///
/// Retrieve credentials from Windows Credential Manager /// Retrieve credentials from Windows Credential Manager
/// ///
/// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from /// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from
/// \param[in] level Credential level (0=outer, 1=inner, 2=inner-inner...)
/// ///
virtual void retrieve(_In_z_ LPCTSTR pszTargetName); virtual void retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level);
/// ///
/// Return target suffix for Windows Credential Manager credential name /// Return target suffix for Windows Credential Manager credential name

View File

@@ -235,6 +235,11 @@ namespace eap
/// ///
virtual void derive_msk(); virtual void derive_msk();
///
/// Generates keying material for inner authentication
///
virtual void derive_challenge();
/// @} /// @}
#if EAP_TLS < EAP_TLS_SCHANNEL #if EAP_TLS < EAP_TLS_SCHANNEL
@@ -478,7 +483,7 @@ namespace eap
phase_handshake_cont, ///< Handshake continue phase_handshake_cont, ///< Handshake continue
phase_application_data, ///< Exchange application data phase_application_data, ///< Exchange application data
phase_shutdown, ///< Connection shut down phase_shutdown, ///< Connection shut down
} m_phase, m_phase_prev; ///< What phase is our communication at? } m_phase; ///< What phase is our communication at?
#endif #endif
}; };
} }

View File

@@ -98,31 +98,6 @@ namespace eap
class packet_tls; class packet_tls;
} }
/////
///// Packs a TLS connection state
/////
///// \param[inout] cursor Memory cursor
///// \param[in] val Variable with data to pack
/////
//inline void operator<<(_Inout_ eap::cursor_out &cursor, _In_ const eap::tls_conn_state &val);
//
/////
///// Returns packed size of TLS connection state
/////
///// \param[in] val Data to pack
/////
///// \returns Size of data when packed (in bytes)
/////
//inline size_t pksizeof(_In_ const eap::tls_conn_state &val);
//
/////
///// Unpacks a TLS connection state
/////
///// \param[inout] cursor Memory cursor
///// \param[out] val Variable to receive unpacked value
/////
//inline void operator>>(_Inout_ eap::cursor_in &cursor, _Out_ eap::tls_conn_state &val);
#pragma once #pragma once
#include <memory> #include <memory>

View File

@@ -66,7 +66,7 @@ tstring eap::get_cert_title(PCCERT_CONTEXT cert)
// eap::config_method_tls // eap::config_method_tls
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
eap::config_method_tls::config_method_tls(_In_ module &mod) : config_method_with_cred(mod) eap::config_method_tls::config_method_tls(_In_ module &mod, _In_ unsigned int level) : config_method_with_cred(mod, level)
{ {
m_preshared.reset(new credentials_tls(mod)); m_preshared.reset(new credentials_tls(mod));
} }

View File

@@ -166,7 +166,7 @@ void eap::credentials_tls::operator>>(_Inout_ cursor_in &cursor)
} }
void eap::credentials_tls::store(_In_z_ LPCTSTR pszTargetName) const void eap::credentials_tls::store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const
{ {
assert(pszTargetName); assert(pszTargetName);
@@ -179,7 +179,7 @@ void eap::credentials_tls::store(_In_z_ LPCTSTR pszTargetName) const
throw win_runtime_error(__FUNCTION__ " CryptProtectData failed."); throw win_runtime_error(__FUNCTION__ " CryptProtectData failed.");
} }
tstring target(target_name(pszTargetName)); tstring target(target_name(pszTargetName, level));
// Write credentials. // Write credentials.
assert(cred_enc.cbData < CRED_MAX_CREDENTIAL_BLOB_SIZE); assert(cred_enc.cbData < CRED_MAX_CREDENTIAL_BLOB_SIZE);
@@ -203,13 +203,13 @@ void eap::credentials_tls::store(_In_z_ LPCTSTR pszTargetName) const
} }
void eap::credentials_tls::retrieve(_In_z_ LPCTSTR pszTargetName) void eap::credentials_tls::retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level)
{ {
assert(pszTargetName); assert(pszTargetName);
// Read credentials. // Read credentials.
unique_ptr<CREDENTIAL, CredFree_delete<CREDENTIAL> > cred; unique_ptr<CREDENTIAL, CredFree_delete<CREDENTIAL> > cred;
if (!CredRead(target_name(pszTargetName).c_str(), CRED_TYPE_GENERIC, 0, (PCREDENTIAL*)&cred)) if (!CredRead(target_name(pszTargetName, level).c_str(), CRED_TYPE_GENERIC, 0, (PCREDENTIAL*)&cred))
throw win_runtime_error(__FUNCTION__ " CredRead failed."); throw win_runtime_error(__FUNCTION__ " CredRead failed.");
if (cred->CredentialBlobSize) { if (cred->CredentialBlobSize) {
@@ -240,7 +240,7 @@ void eap::credentials_tls::retrieve(_In_z_ LPCTSTR pszTargetName)
LPCTSTR eap::credentials_tls::target_suffix() const LPCTSTR eap::credentials_tls::target_suffix() const
{ {
return _T("TLS"); return _T("Cert");
} }
@@ -313,7 +313,7 @@ eap::credentials::source_t eap::credentials_tls::combine(
if (pszTargetName) { if (pszTargetName) {
try { try {
credentials_tls cred_loaded(m_module); credentials_tls cred_loaded(m_module);
cred_loaded.retrieve(pszTargetName); cred_loaded.retrieve(pszTargetName, cfg.m_level);
// Using stored credentials. // Using stored credentials.
*this = std::move(cred_loaded); *this = std::move(cred_loaded);

View File

@@ -71,7 +71,6 @@ eap::method_tls::method_tls(_In_ module &module, _In_ config_method_tls &cfg, _I
m_seq_num_server(0), m_seq_num_server(0),
#else #else
m_phase(phase_unknown), m_phase(phase_unknown),
m_phase_prev(phase_unknown),
#endif #endif
method(module, cfg, cred) method(module, cfg, cred)
{ {
@@ -121,7 +120,6 @@ eap::method_tls::method_tls(_Inout_ method_tls &&other) :
m_sc_queue (std::move(other.m_sc_queue )), m_sc_queue (std::move(other.m_sc_queue )),
m_sc_ctx (std::move(other.m_sc_ctx )), m_sc_ctx (std::move(other.m_sc_ctx )),
m_phase (std::move(other.m_phase )), m_phase (std::move(other.m_phase )),
m_phase_prev (std::move(other.m_phase_prev )),
#endif #endif
method (std::move(other )) method (std::move(other ))
{ {
@@ -178,7 +176,6 @@ eap::method_tls& eap::method_tls::operator=(_Inout_ method_tls &&other)
m_sc_queue = std::move(other.m_sc_queue ); m_sc_queue = std::move(other.m_sc_queue );
m_sc_ctx = std::move(other.m_sc_ctx ); m_sc_ctx = std::move(other.m_sc_ctx );
m_phase = std::move(other.m_phase ); m_phase = std::move(other.m_phase );
m_phase_prev = std::move(other.m_phase_prev );
#endif #endif
} }
@@ -435,6 +432,9 @@ void eap::method_tls::process_request_packet(
sanitizing_blob msg_finished(make_message(tls_message_type_handshake, make_finished())); sanitizing_blob msg_finished(make_message(tls_message_type_handshake, make_finished()));
m_packet_res.m_data.insert(m_packet_res.m_data.end(), msg_finished.begin(), msg_finished.end()); m_packet_res.m_data.insert(m_packet_res.m_data.end(), msg_finished.begin(), msg_finished.end());
// Derive challenge for inner authentication (if any).
derive_challenge();
if (m_handshake[tls_handshake_type_finished]) { if (m_handshake[tls_handshake_type_finished]) {
// Go to application data phase. And allow piggybacking of the first data message. // Go to application data phase. And allow piggybacking of the first data message.
m_phase = phase_application_data; m_phase = phase_application_data;
@@ -443,6 +443,7 @@ void eap::method_tls::process_request_packet(
} else { } else {
m_session_resumed = false; m_session_resumed = false;
m_phase = phase_change_cipher_spec; m_phase = phase_change_cipher_spec;
m_cfg.m_last_status = config_method_with_cred::status_cred_invalid; // Blame credentials if we fail beyond this point.
} }
break; break;
} }
@@ -470,7 +471,6 @@ void eap::method_tls::process_request_packet(
} else } else
m_sc_queue.insert(m_sc_queue.end(), m_packet_req.m_data.begin(), m_packet_req.m_data.end()); m_sc_queue.insert(m_sc_queue.end(), m_packet_req.m_data.begin(), m_packet_req.m_data.end());
m_phase_prev = m_phase;
switch (m_phase) { switch (m_phase) {
case phase_handshake_init: case phase_handshake_init:
case phase_handshake_cont: case phase_handshake_cont:
@@ -508,10 +508,10 @@ void eap::method_tls::get_result(
{ {
assert(ppResult); assert(ppResult);
method::get_result(reason, ppResult);
switch (reason) { switch (reason) {
case EapPeerMethodResultSuccess: { case EapPeerMethodResultSuccess: {
m_module.log_event(&EAPMETHOD_METHOD_SUCCESS, event_data((unsigned int)eap_type_tls), event_data::blank);
// Derive MSK/EMSK for line encryption. // Derive MSK/EMSK for line encryption.
derive_msk(); derive_msk();
@@ -524,12 +524,6 @@ void eap::method_tls::get_result(
m_eap_attr.push_back(std::move(a)); m_eap_attr.push_back(std::move(a));
m_eap_attr.push_back(eap_attr::blank); m_eap_attr.push_back(eap_attr::blank);
// Clear credentials as failed.
m_cfg.m_auth_failed = false;
ppResult->fIsSuccess = TRUE;
ppResult->dwFailureReasonCode = ERROR_SUCCESS;
#if EAP_TLS < EAP_TLS_SCHANNEL #if EAP_TLS < EAP_TLS_SCHANNEL
// Update configuration with session resumption data. // Update configuration with session resumption data.
m_cfg.m_session_id = m_session_id; m_cfg.m_session_id = m_session_id;
@@ -567,44 +561,15 @@ void eap::method_tls::get_result(
case EapPeerMethodResultFailure: case EapPeerMethodResultFailure:
#if EAP_TLS < EAP_TLS_SCHANNEL #if EAP_TLS < EAP_TLS_SCHANNEL
m_module.log_event(
m_phase < phase_change_cipher_spec ? &EAPMETHOD_METHOD_FAILURE_INIT :
m_phase < phase_application_data ? &EAPMETHOD_METHOD_FAILURE_HANDSHAKE : &EAPMETHOD_METHOD_FAILURE,
event_data((unsigned int)eap_type_tls), event_data::blank);
// Mark credentials as failed, so GUI can re-prompt user.
// But be careful: do so only if this happened after transition from handshake to application data phase.
m_cfg.m_auth_failed = m_phase_prev < phase_application_data && m_phase >= phase_application_data;
// Clear session resumption data. // Clear session resumption data.
m_cfg.m_session_id.clear(); m_cfg.m_session_id.clear();
m_cfg.m_master_secret.clear(); m_cfg.m_master_secret.clear();
#else #else
m_module.log_event(
m_phase_prev < phase_handshake_cont ? &EAPMETHOD_METHOD_FAILURE_INIT :
m_phase_prev < phase_application_data ? &EAPMETHOD_METHOD_FAILURE_HANDSHAKE : &EAPMETHOD_METHOD_FAILURE,
event_data((unsigned int)eap_type_tls), event_data::blank);
// Mark credentials as failed, so GUI can re-prompt user.
// But be careful: do so only if this happened after transition from handshake to application data phase.
m_cfg.m_auth_failed = m_phase_prev < phase_application_data && m_phase >= phase_application_data;
// TODO: Research how a Schannel session context can be cleared not to resume. // TODO: Research how a Schannel session context can be cleared not to resume.
#endif #endif
// 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.
//ppResult->fIsSuccess = FALSE;
//ppResult->dwFailureReasonCode = EAP_E_AUTHENTICATION_FAILED;
break; break;
default:
throw win_runtime_error(ERROR_NOT_SUPPORTED, __FUNCTION__ " Not supported.");
} }
// Always ask EAP host to save the connection data.
ppResult->fSaveConnectionData = TRUE;
} }
@@ -831,6 +796,12 @@ void eap::method_tls::derive_msk()
_key_block += sizeof(tls_random); _key_block += sizeof(tls_random);
} }
void eap::method_tls::derive_challenge()
{
}
#if EAP_TLS < EAP_TLS_SCHANNEL #if EAP_TLS < EAP_TLS_SCHANNEL
void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck, _In_ size_t size_pck) void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck, _In_ size_t size_pck)
@@ -1230,10 +1201,15 @@ void eap::method_tls::process_handshake()
else else
m_module.log_event(&EAPMETHOD_TLS_QUERY_FAILED, event_data((unsigned int)SECPKG_ATTR_CONNECTION_INFO), event_data(status), event_data::blank); m_module.log_event(&EAPMETHOD_TLS_QUERY_FAILED, event_data((unsigned int)SECPKG_ATTR_CONNECTION_INFO), event_data(status), event_data::blank);
// Derive challenge for inner authentication (if any).
derive_challenge();
m_phase = phase_application_data; m_phase = phase_application_data;
process_application_data(m_sc_queue.data(), m_sc_queue.size()); process_application_data(m_sc_queue.data(), m_sc_queue.size());
} else } else {
m_phase = phase_handshake_cont; m_phase = phase_handshake_cont;
m_cfg.m_last_status = config_method_with_cred::status_cred_invalid; // Blame credentials if we fail beyond this point.
}
} else if (status == SEC_E_INCOMPLETE_MESSAGE) { } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
// Schannel neeeds more data. Send ACK packet to server to send more. // Schannel neeeds more data. Send ACK packet to server to send more.
} else if (FAILED(status)) { } else if (FAILED(status)) {
@@ -1262,13 +1238,14 @@ void eap::method_tls::process_application_data()
// Prepare input/output buffer(s). // Prepare input/output buffer(s).
SecBuffer buf[] = { SecBuffer buf[] = {
{ 0, SECBUFFER_TOKEN, NULL },
{ 0, SECBUFFER_ALERT, NULL },
{ {
(unsigned long)m_sc_queue.size(), (unsigned long)m_sc_queue.size(),
SECBUFFER_DATA, SECBUFFER_DATA,
m_sc_queue.data() m_sc_queue.data()
}, },
{ 0, SECBUFFER_EMPTY, NULL },
{ 0, SECBUFFER_EMPTY, NULL },
{ 0, SECBUFFER_EMPTY, NULL },
}; };
SecBufferDesc buf_desc = { SecBufferDesc buf_desc = {
SECBUFFER_VERSION, SECBUFFER_VERSION,
@@ -1279,8 +1256,17 @@ void eap::method_tls::process_application_data()
// Decrypt the message. // Decrypt the message.
SECURITY_STATUS status = DecryptMessage(m_sc_ctx, &buf_desc, 0, NULL); SECURITY_STATUS status = DecryptMessage(m_sc_ctx, &buf_desc, 0, NULL);
if (status == SEC_E_OK) { if (status == SEC_E_OK) {
assert(buf[2].BufferType == SECBUFFER_DATA); // Find SECBUFFER_DATA buffer(s) and process data.
process_application_data(buf[2].pvBuffer, buf[2].cbBuffer); for (size_t i = 0; i < _countof(buf); i++)
if (buf[i].BufferType == SECBUFFER_DATA)
process_application_data(buf[i].pvBuffer, buf[i].cbBuffer);
// Find SECBUFFER_EXTRA buffer(s) and queue data for the next time.
std::vector<unsigned char> extra;
for (size_t i = 0; i < _countof(buf); i++)
if (buf[i].BufferType == SECBUFFER_EXTRA)
extra.insert(extra.end(), (unsigned char*)buf[i].pvBuffer, (unsigned char*)buf[i].pvBuffer + buf[i].cbBuffer);
m_sc_queue = std::move(extra);
} else if (status == SEC_E_INCOMPLETE_MESSAGE) { } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
// Schannel neeeds more data. Send ACK packet to server to send more. // Schannel neeeds more data. Send ACK packet to server to send more.
} else if (status == SEC_I_CONTEXT_EXPIRED) { } else if (status == SEC_I_CONTEXT_EXPIRED) {
@@ -1292,17 +1278,9 @@ void eap::method_tls::process_application_data()
m_sc_queue.clear(); m_sc_queue.clear();
m_phase = phase_handshake_init; m_phase = phase_handshake_init;
process_handshake(); process_handshake();
} else if (FAILED(status)) { } else if (FAILED(status))
if (m_sc_ctx.m_attrib & ISC_RET_EXTENDED_ERROR) {
// Send alert via EAP. Not that EAP will transmit it once we throw this is an error...
assert(buf[1].BufferType == SECBUFFER_ALERT);
assert(m_sc_ctx.m_attrib & ISC_RET_ALLOCATED_MEMORY);
m_packet_res.m_data.assign((const unsigned char*)buf[1].pvBuffer, (const unsigned char*)buf[1].pvBuffer + buf[1].cbBuffer);
}
throw sec_runtime_error(status, __FUNCTION__ " Schannel error."); throw sec_runtime_error(status, __FUNCTION__ " Schannel error.");
} }
}
#endif #endif

View File

@@ -48,8 +48,9 @@ namespace eap {
/// Constructs configuration /// Constructs configuration
/// ///
/// \param[in] mod EAP module to use for global services /// \param[in] mod EAP module to use for global services
/// \param[in] level Config level (0=outer, 1=inner, 2=inner-inner...)
/// ///
config_method_ttls(_In_ module &mod); config_method_ttls(_In_ module &mod, _In_ unsigned int level);
/// ///
/// Copies configuration /// Copies configuration

View File

@@ -149,15 +149,17 @@ namespace eap
/// Save credentials to Windows Credential Manager /// Save credentials to Windows Credential Manager
/// ///
/// \param[in] pszTargetName The name in Windows Credential Manager to store credentials as /// \param[in] pszTargetName The name in Windows Credential Manager to store credentials as
/// \param[in] level Credential level (0=outer, 1=inner, 2=inner-inner...)
/// ///
virtual void store(_In_z_ LPCTSTR pszTargetName) const; virtual void store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const;
/// ///
/// Retrieve credentials from Windows Credential Manager /// Retrieve credentials from Windows Credential Manager
/// ///
/// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from /// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from
/// \param[in] level Credential level (0=outer, 1=inner, 2=inner-inner...)
/// ///
virtual void retrieve(_In_z_ LPCTSTR pszTargetName); virtual void retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level);
/// ///
/// Returns credential identity. /// Returns credential identity.

View File

@@ -128,11 +128,7 @@ namespace eap
/// ///
/// Generates keying material for inner authentication /// Generates keying material for inner authentication
/// ///
/// \param[in] size Number of bytes of keying material required virtual void derive_challenge();
///
/// \returns Keing material
///
virtual sanitizing_blob derive_challenge(_In_ size_t size);
/// ///
/// Processes an application message /// Processes an application message

View File

@@ -28,9 +28,9 @@ using namespace winstd;
// eap::config_method_ttls // eap::config_method_ttls
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
eap::config_method_ttls::config_method_ttls(_In_ module &mod) : eap::config_method_ttls::config_method_ttls(_In_ module &mod, _In_ unsigned int level) :
m_inner(new config_method_pap(mod)), m_inner(new config_method_pap(mod, level + 1)),
config_method_tls(mod) config_method_tls(mod, level)
{ {
// TTLS is using blank pre-shared credentials per default. // TTLS is using blank pre-shared credentials per default.
m_use_preshared = true; m_use_preshared = true;
@@ -265,10 +265,10 @@ eap::credentials* eap::config_method_ttls::make_credentials() const
eap::config_method_with_cred* eap::config_method_ttls::make_config_method(_In_ winstd::eap_type_t eap_type) const eap::config_method_with_cred* eap::config_method_ttls::make_config_method(_In_ winstd::eap_type_t eap_type) const
{ {
switch (eap_type) { switch (eap_type) {
case eap_type_tls : return new config_method_tls (m_module); case eap_type_tls : return new config_method_tls (m_module, m_level + 1);
case eap_type_ttls : return new config_method_ttls (m_module); case eap_type_ttls : return new config_method_ttls (m_module, m_level + 1);
case eap_type_legacy_pap : return new config_method_pap (m_module); case eap_type_legacy_pap : return new config_method_pap (m_module, m_level + 1);
case eap_type_legacy_mschapv2: return new config_method_mschapv2(m_module); case eap_type_legacy_mschapv2: return new config_method_mschapv2(m_module, m_level + 1);
default : throw invalid_argument(__FUNCTION__ " Unsupported inner authentication method."); default : throw invalid_argument(__FUNCTION__ " Unsupported inner authentication method.");
} }
} }
@@ -276,10 +276,10 @@ eap::config_method_with_cred* eap::config_method_ttls::make_config_method(_In_ w
eap::config_method_with_cred* eap::config_method_ttls::make_config_method(_In_ const wchar_t *eap_type) const eap::config_method_with_cred* eap::config_method_ttls::make_config_method(_In_ const wchar_t *eap_type) const
{ {
if (_wcsicmp(eap_type, L"EAP-TLS" ) == 0) return new config_method_tls (m_module); if (_wcsicmp(eap_type, L"EAP-TLS" ) == 0) return new config_method_tls (m_module, m_level + 1);
else if (_wcsicmp(eap_type, L"EAP-TTLS") == 0) return new config_method_ttls (m_module); else if (_wcsicmp(eap_type, L"EAP-TTLS") == 0) return new config_method_ttls (m_module, m_level + 1);
else if (_wcsicmp(eap_type, L"PAP" ) == 0) return new config_method_pap (m_module); else if (_wcsicmp(eap_type, L"PAP" ) == 0) return new config_method_pap (m_module, m_level + 1);
else if (_wcsicmp(eap_type, L"MSCHAPv2") == 0) return new config_method_mschapv2(m_module); else if (_wcsicmp(eap_type, L"MSCHAPv2") == 0) return new config_method_mschapv2(m_module, m_level + 1);
else throw invalid_argument(__FUNCTION__ " Unsupported inner authentication method."); else throw invalid_argument(__FUNCTION__ " Unsupported inner authentication method.");
} }

View File

@@ -146,23 +146,23 @@ void eap::credentials_ttls::operator>>(_Inout_ cursor_in &cursor)
} }
void eap::credentials_ttls::store(_In_z_ LPCTSTR pszTargetName) const void eap::credentials_ttls::store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const
{ {
assert(0); // Not that we would ever store inner&outer credentials to Windows Credential Manager joined, but for completness sake... Here we go: assert(0); // Not that we would ever store inner&outer credentials to Windows Credential Manager joined, but for completness sake... Here we go:
credentials_tls::store(pszTargetName); credentials_tls::store(pszTargetName, level);
m_inner->store(pszTargetName); m_inner->store(pszTargetName, level + 1);
} }
void eap::credentials_ttls::retrieve(_In_z_ LPCTSTR pszTargetName) void eap::credentials_ttls::retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level)
{ {
assert(0); // Not that we would ever retrieve inner&outer credentials to Windows Credential Manager joined, but for completness sake... Here we go: assert(0); // Not that we would ever retrieve inner&outer credentials to Windows Credential Manager joined, but for completness sake... Here we go:
credentials_tls::retrieve(pszTargetName); credentials_tls::retrieve(pszTargetName, level);
m_inner->retrieve(pszTargetName); m_inner->retrieve(pszTargetName, level + 1);
} }

View File

@@ -69,8 +69,8 @@ void eap::method_ttls::begin_session(
// Initialize inner method. // Initialize inner method.
switch (m_cfg.m_inner->get_method_id()) { switch (m_cfg.m_inner->get_method_id()) {
case eap_type_legacy_pap : m_inner.reset(new method_pap (m_module, (config_method_pap &)*m_cfg.m_inner, (credentials_pap &)*m_cred.m_inner.get())); break; case eap_type_legacy_pap : m_inner.reset(new method_pap (m_module, (config_method_pap &)*m_cfg.m_inner, (credentials_pass &)*m_cred.m_inner.get())); break;
case eap_type_legacy_mschapv2: m_inner.reset(new method_mschapv2(m_module, (config_method_mschapv2&)*m_cfg.m_inner, (credentials_mschapv2&)*m_cred.m_inner.get())); break; case eap_type_legacy_mschapv2: m_inner.reset(new method_mschapv2(m_module, (config_method_mschapv2&)*m_cfg.m_inner, (credentials_pass&)*m_cred.m_inner.get())); break;
default: throw invalid_argument(__FUNCTION__ " Unsupported inner authentication method."); default: throw invalid_argument(__FUNCTION__ " Unsupported inner authentication method.");
} }
m_inner->begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, MAXDWORD); m_inner->begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, MAXDWORD);
@@ -129,6 +129,12 @@ void eap::method_ttls::get_result(
m_inner->get_result(reason, &result); m_inner->get_result(reason, &result);
if (result.fSaveConnectionData) if (result.fSaveConnectionData)
ppResult->fSaveConnectionData = TRUE; ppResult->fSaveConnectionData = TRUE;
if (m_inner->m_cfg.m_last_status != config_method_with_cred::status_success) {
// Inner method admitted problems, so autentication must have proceeded to inner authentication already.
// Therefore, outer authentication must have been OK.
m_cfg.m_last_status = config_method_with_cred::status_success;
}
} }
} }
@@ -188,14 +194,18 @@ void eap::method_ttls::derive_msk()
} }
eap::sanitizing_blob eap::method_ttls::derive_challenge(_In_ size_t size) void eap::method_ttls::derive_challenge()
{ {
method_mschapv2 *inner_mschapv2 = dynamic_cast<method_mschapv2*>(m_inner.get());
if (inner_mschapv2) {
#if EAP_TLS < EAP_TLS_SCHANNEL #if EAP_TLS < EAP_TLS_SCHANNEL
static const unsigned char s_label[] = "ttls challenge"; static const unsigned char s_label[] = "ttls challenge";
sanitizing_blob seed(s_label, s_label + _countof(s_label) - 1); sanitizing_blob seed(s_label, s_label + _countof(s_label) - 1);
seed.insert(seed.end(), (const unsigned char*)&m_random_client, (const unsigned char*)(&m_random_client + 1)); seed.insert(seed.end(), (const unsigned char*)&m_random_client, (const unsigned char*)(&m_random_client + 1));
seed.insert(seed.end(), (const unsigned char*)&m_random_server, (const unsigned char*)(&m_random_server + 1)); seed.insert(seed.end(), (const unsigned char*)&m_random_server, (const unsigned char*)(&m_random_server + 1));
return prf(m_cp, CALG_TLS1PRF, m_master_secret, seed, size); sanitizing_blob keying(prf(m_cp, CALG_TLS1PRF, m_master_secret, seed, sizeof(challenge_mschapv2) + 1));
memcpy(&inner_mschapv2->m_challenge_server, keying.data(), sizeof(challenge_mschapv2));
inner_mschapv2->m_ident = keying[sizeof(challenge_mschapv2) + 0];
#else #else
static const DWORD s_key_id = 0x02; // EAP-TTLSv0 Challenge Data static const DWORD s_key_id = 0x02; // EAP-TTLSv0 Challenge Data
static const SecPkgContext_EapPrfInfo s_prf_info = { 0, sizeof(s_key_id), (PBYTE)&s_key_id }; static const SecPkgContext_EapPrfInfo s_prf_info = { 0, sizeof(s_key_id), (PBYTE)&s_key_id };
@@ -207,19 +217,12 @@ eap::sanitizing_blob eap::method_ttls::derive_challenge(_In_ size_t size)
status = QueryContextAttributes(m_sc_ctx, SECPKG_ATTR_EAP_KEY_BLOCK, &key_block); status = QueryContextAttributes(m_sc_ctx, SECPKG_ATTR_EAP_KEY_BLOCK, &key_block);
if (FAILED(status)) if (FAILED(status))
throw sec_runtime_error(status, __FUNCTION__ " Error generating PRF in Schannel."); throw sec_runtime_error(status, __FUNCTION__ " Error generating PRF in Schannel.");
sanitizing_blob key;
key.reserve(size); memcpy(&inner_mschapv2->m_challenge_server, key_block.rgbKeys, sizeof(challenge_mschapv2));
if (size <= sizeof(key_block.rgbKeys)) inner_mschapv2->m_ident = key_block.rgbKeys[sizeof(challenge_mschapv2) + 0];
key.assign(key_block.rgbKeys, key_block.rgbKeys + size);
else if (size <= sizeof(key_block.rgbKeys) + sizeof(key_block.rgbIVs)) {
key.assign( key_block.rgbKeys, key_block.rgbKeys + sizeof(key_block.rgbKeys));
key.insert(key.end(), key_block.rgbIVs , key_block.rgbIVs + size - sizeof(key_block.rgbKeys));
} else
throw invalid_argument(string_printf(__FUNCTION__ " Schannel cannot generate PRF this big (maximum: %u, requested: %u).", sizeof(key_block.rgbKeys) + sizeof(key_block.rgbIVs), size).c_str());
SecureZeroMemory(&key_block, sizeof(key_block));
return key;
#endif #endif
} }
}
void eap::method_ttls::process_application_data(_In_bytecount_(size_msg) const void *msg, _In_ size_t size_msg) void eap::method_ttls::process_application_data(_In_bytecount_(size_msg) const void *msg, _In_ size_t size_msg)
@@ -245,13 +248,6 @@ void eap::method_ttls::process_application_data(_In_bytecount_(size_msg) const v
} }
#endif #endif
method_mschapv2 *inner_mschapv2 = dynamic_cast<method_mschapv2*>(m_inner.get());
if (inner_mschapv2) {
sanitizing_blob keying(derive_challenge(sizeof(challenge_mschapv2) + 1));
memcpy(&inner_mschapv2->m_challenge_server, keying.data(), sizeof(challenge_mschapv2));
inner_mschapv2->m_ident = keying[sizeof(challenge_mschapv2) + 0];
}
EapPeerMethodOutput eap_output = {}; EapPeerMethodOutput eap_output = {};
m_inner->process_request_packet(msg, (DWORD)size_msg, &eap_output); m_inner->process_request_packet(msg, (DWORD)size_msg, &eap_output);
switch (eap_output.action) { switch (eap_output.action) {
@@ -279,6 +275,7 @@ void eap::method_ttls::process_application_data(_In_bytecount_(size_msg) const v
#endif #endif
m_inner->get_response_packet(ptr_data, &size_data); m_inner->get_response_packet(ptr_data, &size_data);
if (size_data) {
#if EAP_TLS < EAP_TLS_SCHANNEL #if EAP_TLS < EAP_TLS_SCHANNEL
data.resize(size_data); data.resize(size_data);
sanitizing_blob msg_application(make_message(tls_message_type_application_data, std::move(data))); sanitizing_blob msg_application(make_message(tls_message_type_application_data, std::move(data)));
@@ -303,6 +300,9 @@ void eap::method_ttls::process_application_data(_In_bytecount_(size_msg) const v
throw sec_runtime_error(status, __FUNCTION__ " Error encrypting message."); throw sec_runtime_error(status, __FUNCTION__ " Error encrypting message.");
m_packet_res.m_data.insert(m_packet_res.m_data.end(), (const unsigned char*)buf[0].pvBuffer, (const unsigned char*)buf[0].pvBuffer + buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer); m_packet_res.m_data.insert(m_packet_res.m_data.end(), (const unsigned char*)buf[0].pvBuffer, (const unsigned char*)buf[0].pvBuffer + buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer);
#endif #endif
} else {
// Empty packets represent ACK message, and are not encrypted.
}
break; break;
} }

View File

@@ -35,7 +35,7 @@ eap::peer_ttls::peer_ttls() : peer(eap_type_ttls)
eap::config_method* eap::peer_ttls::make_config_method() eap::config_method* eap::peer_ttls::make_config_method()
{ {
return new config_method_ttls(*this); return new config_method_ttls(*this, 0);
} }
@@ -270,6 +270,13 @@ void eap::peer_ttls::get_result(
s->m_eap_attr_desc.pAttribs = s->m_method->m_eap_attr.data(); s->m_eap_attr_desc.pAttribs = s->m_method->m_eap_attr.data();
ppResult->pAttribArray = &s->m_eap_attr_desc; ppResult->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.
//ppResult->fIsSuccess = FALSE;
//ppResult->dwFailureReasonCode = EAP_E_AUTHENTICATION_FAILED;
ppResult->fIsSuccess = TRUE;
ppResult->dwFailureReasonCode = ERROR_SUCCESS;
if (ppResult->fSaveConnectionData) { if (ppResult->fSaveConnectionData) {
pack(s->m_cfg, &ppResult->pConnectionData, &ppResult->dwSizeofConnectionData); pack(s->m_cfg, &ppResult->pConnectionData, &ppResult->dwSizeofConnectionData);
if (s->m_blob_cfg) if (s->m_blob_cfg)
@@ -409,13 +416,13 @@ const eap::config_method_ttls* eap::peer_ttls::combine_credentials(
// If we got here, we have all credentials we need. But, wait! // If we got here, we have all credentials we need. But, wait!
if ((dwFlags & EAP_FLAG_MACHINE_AUTH) == 0) { if ((dwFlags & EAP_FLAG_MACHINE_AUTH) == 0) {
if (cfg_method->m_auth_failed) { if (config_method_with_cred::status_cred_begin <= cfg_method->m_last_status && cfg_method->m_last_status < config_method_with_cred::status_cred_end) {
// Outer: Credentials failed on last connection attempt. // Outer: Credentials failed on last connection attempt.
log_event(&EAPMETHOD_TRACE_EVT_CRED_PROBLEM1, event_data(target_name), event_data((unsigned int)eap_type_tls), event_data::blank); log_event(&EAPMETHOD_TRACE_EVT_CRED_PROBLEM1, event_data(target_name), event_data((unsigned int)eap_type_tls), event_data::blank);
continue; continue;
} }
if (cfg_method->m_inner->m_auth_failed) { if (config_method_with_cred::status_cred_begin <= cfg_method->m_inner->m_last_status && cfg_method->m_inner->m_last_status < config_method_with_cred::status_cred_end) {
// Inner: Credentials failed on last connection attempt. // Inner: Credentials failed on last connection attempt.
log_event(&EAPMETHOD_TRACE_EVT_CRED_PROBLEM1, event_data(target_name), event_data((unsigned int)cfg_method->m_inner->get_method_id()), event_data::blank); log_event(&EAPMETHOD_TRACE_EVT_CRED_PROBLEM1, event_data(target_name), event_data((unsigned int)cfg_method->m_inner->get_method_id()), event_data::blank);
continue; continue;

View File

@@ -27,11 +27,9 @@
#include "../include/TTLS.h" #include "../include/TTLS.h"
#include "../../PAP/include/Config.h" #include "../../PAP/include/Config.h"
#include "../../PAP/include/Credentials.h"
#include "../../PAP/include/Method.h" #include "../../PAP/include/Method.h"
#include "../../MSCHAPv2/include/Config.h" #include "../../MSCHAPv2/include/Config.h"
#include "../../MSCHAPv2/include/Credentials.h"
#include "../../MSCHAPv2/include/Method.h" #include "../../MSCHAPv2/include/Method.h"
#include "../../MSCHAPv2/include/MSCHAPv2.h" #include "../../MSCHAPv2/include/MSCHAPv2.h"

View File

@@ -52,7 +52,7 @@ eap::peer_ttls_ui::peer_ttls_ui() : peer_ui(eap_type_ttls)
eap::config_method* eap::peer_ttls_ui::make_config_method() eap::config_method* eap::peer_ttls_ui::make_config_method()
{ {
return new config_method_ttls(*this); return new config_method_ttls(*this, 0);
} }
@@ -270,7 +270,7 @@ void eap::peer_ttls_ui::invoke_identity_ui(
// Write credentials to credential manager. // Write credentials to credential manager.
if (panel->m_outer_cred->GetRemember()) { if (panel->m_outer_cred->GetRemember()) {
try { try {
_cred_out->credentials_tls::store(target_name.c_str()); _cred_out->credentials_tls::store(target_name.c_str(), 0);
} catch (winstd::win_runtime_error &err) { } catch (winstd::win_runtime_error &err) {
wxLogError(winstd::tstring_printf(_("Error writing credentials to Credential Manager: %hs (error %u)"), err.what(), err.number()).c_str()); wxLogError(winstd::tstring_printf(_("Error writing credentials to Credential Manager: %hs (error %u)"), err.what(), err.number()).c_str());
} catch (...) { } catch (...) {
@@ -280,7 +280,7 @@ void eap::peer_ttls_ui::invoke_identity_ui(
if (panel->m_inner_cred->GetRemember()) { if (panel->m_inner_cred->GetRemember()) {
try { try {
_cred_out->m_inner->store(target_name.c_str()); _cred_out->m_inner->store(target_name.c_str(), 1);
} catch (winstd::win_runtime_error &err) { } catch (winstd::win_runtime_error &err) {
wxLogError(winstd::tstring_printf(_("Error writing credentials to Credential Manager: %hs (error %u)"), err.what(), err.number()).c_str()); wxLogError(winstd::tstring_printf(_("Error writing credentials to Credential Manager: %hs (error %u)"), err.what(), err.number()).c_str());
} catch (...) { } catch (...) {

View File

@@ -95,8 +95,8 @@ void wxTTLSConfigPanel::OnUpdateUI(wxUpdateUIEvent& /*event*/)
wxTTLSConfigWindow::wxTTLSConfigWindow(eap::config_provider &prov, eap::config_method &cfg, wxWindow* parent) : wxTTLSConfigWindow::wxTTLSConfigWindow(eap::config_provider &prov, eap::config_method &cfg, wxWindow* parent) :
m_cfg((eap::config_method_ttls&)cfg), m_cfg((eap::config_method_ttls&)cfg),
m_cfg_pap(cfg.m_module), m_cfg_pap(cfg.m_module, cfg.m_level + 1),
m_cfg_mschapv2(cfg.m_module), m_cfg_mschapv2(cfg.m_module, cfg.m_level + 1),
wxEAPConfigWindow(prov, cfg, parent) wxEAPConfigWindow(prov, cfg, parent)
{ {
wxBoxSizer* sb_content; wxBoxSizer* sb_content;
@@ -239,14 +239,20 @@ wxTTLSCredentialsPanel::wxTTLSCredentialsPanel(const eap::config_provider &prov,
assert(m_cfg.m_inner); assert(m_cfg.m_inner);
if (m_cfg.m_inner->m_auth_failed) if (eap::config_method_with_cred::status_cred_begin <= m_cfg.m_inner->m_last_status && m_cfg.m_inner->m_last_status < eap::config_method_with_cred::status_cred_end)
sb_content->Add(new wxEAPCredentialWarningPanel(m_prov, this), 0, wxALL|wxEXPAND, 5); sb_content->Add(new wxEAPCredentialWarningPanel(m_prov, m_cfg.m_inner->m_last_status, this), 0, wxALL|wxEXPAND, 5);
const eap::config_method_pap *cfg_inner_pap = dynamic_cast<const eap::config_method_pap*>(m_cfg.m_inner.get()); const eap::config_method_pap *cfg_inner_pap;
if (cfg_inner_pap) { const eap::config_method_mschapv2 *cfg_inner_mschapv2;
if ((cfg_inner_pap = dynamic_cast<const eap::config_method_pap*>(m_cfg.m_inner.get())) != NULL) {
eap::credentials_ttls &cred_ttls = (eap::credentials_ttls&)cred; eap::credentials_ttls &cred_ttls = (eap::credentials_ttls&)cred;
if (!cred_ttls.m_inner) cred_ttls.m_inner.reset(new eap::credentials_pap(cred.m_module)); if (!cred_ttls.m_inner) cred_ttls.m_inner.reset(new eap::credentials_pass(cred.m_module));
m_inner_cred = new wxPAPCredentialsPanel(m_prov, *cfg_inner_pap, *(eap::credentials_pap*)cred_ttls.m_inner.get(), this, is_config); m_inner_cred = new wxPAPCredentialsPanel(m_prov, *cfg_inner_pap, *(eap::credentials_pass*)cred_ttls.m_inner.get(), this, is_config);
sb_content->Add(m_inner_cred, 0, wxALL|wxEXPAND, 5);
} else if ((cfg_inner_mschapv2 = dynamic_cast<const eap::config_method_mschapv2*>(m_cfg.m_inner.get())) != NULL) {
eap::credentials_ttls &cred_ttls = (eap::credentials_ttls&)cred;
if (!cred_ttls.m_inner) cred_ttls.m_inner.reset(new eap::credentials_pass(cred.m_module));
m_inner_cred = new wxMSCHAPv2CredentialsPanel(m_prov, *cfg_inner_mschapv2, *(eap::credentials_pass*)cred_ttls.m_inner.get(), this, is_config);
sb_content->Add(m_inner_cred, 0, wxALL|wxEXPAND, 5); sb_content->Add(m_inner_cred, 0, wxALL|wxEXPAND, 5);
} else } else
assert(0); // Unsupported inner authentication method type. assert(0); // Unsupported inner authentication method type.
@@ -258,8 +264,8 @@ wxTTLSCredentialsPanel::wxTTLSCredentialsPanel(const eap::config_provider &prov,
m_outer_title->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_INACTIVECAPTION ) ); m_outer_title->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_INACTIVECAPTION ) );
sb_content->Add(m_outer_title, 0, wxALL|wxALIGN_RIGHT, 5); sb_content->Add(m_outer_title, 0, wxALL|wxALIGN_RIGHT, 5);
if (m_cfg.m_auth_failed) if (eap::config_method_with_cred::status_cred_begin <= m_cfg.m_last_status && m_cfg.m_last_status < eap::config_method_with_cred::status_cred_end)
sb_content->Add(new wxEAPCredentialWarningPanel(m_prov, this), 0, wxALL|wxEXPAND, 5); sb_content->Add(new wxEAPCredentialWarningPanel(m_prov, m_cfg.m_last_status, this), 0, wxALL|wxEXPAND, 5);
m_outer_cred = new wxTLSCredentialsPanel(m_prov, (const eap::config_method_tls&)m_cfg, (eap::credentials_tls&)cred, this, is_config); m_outer_cred = new wxTLSCredentialsPanel(m_prov, (const eap::config_method_tls&)m_cfg, (eap::credentials_tls&)cred, this, is_config);
sb_content->Add(m_outer_cred, 0, wxALL|wxEXPAND, 5); sb_content->Add(m_outer_cred, 0, wxALL|wxEXPAND, 5);