Compare commits

..

10 Commits

55 changed files with 605 additions and 949 deletions

View File

@@ -40,7 +40,7 @@ static int CredWrite()
return -1;
}
eap::credentials_pap cred_pap(g_module);
eap::credentials_pass cred_pass(g_module);
// Prepare identity (user name).
{
@@ -50,7 +50,7 @@ static int CredWrite()
bool is_last;
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.
@@ -61,7 +61,7 @@ static int CredWrite()
bool is_last;
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).
@@ -71,7 +71,7 @@ static int CredWrite()
target_name = pwcArglist[3];
} else {
// 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) {
target_name = L"urn:RFC4282:realm:";
target_name += domain + 1;
@@ -79,12 +79,22 @@ static int CredWrite()
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.
#ifdef _DEBUG
{
eap::credentials_pap cred_stored(g_module);
eap::credentials_pass cred_stored(g_module);
try {
cred_stored.retrieve(target_name.c_str());
cred_stored.retrieve(target_name.c_str(), level);
} catch(win_runtime_error &err) {
OutputDebugStr(_T("%hs (error %u)\n"), err.what(), err.number());
} catch(...) {
@@ -93,7 +103,7 @@ static int CredWrite()
}
#endif
try {
cred_pap.store(target_name.c_str());
cred_pass.store(target_name.c_str(), level);
} catch(win_runtime_error &err) {
OutputDebugStr(_T("%hs (error %u)\n"), err.what(), err.number());
return 2;
@@ -102,18 +112,6 @@ static int CredWrite()
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;
}

View File

@@ -3,12 +3,13 @@ Imports given credentials to Windows Credential Manager for G
##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)
- `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`)
- `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.

View File

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

View File

@@ -2,7 +2,7 @@
msgid ""
msgstr ""
"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"
"Last-Translator: Simon Rozman <simon.rozman@amebis.si>\n"
"Language-Team: Amebis, d. o. o., Kamnik <info@amebis.si>\n"
@@ -253,8 +253,24 @@ msgstr ""
msgid "Your provider"
msgstr ""
#: lib/EAPBase_UI/src/EAP_UI.cpp:249
msgid "Previous attempt to connect failed. Please, make sure your credentials are correct, or try again later."
#: lib/EAPBase_UI/src/EAP_UI.cpp:250
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 ""
#: lib/TLS_UI/res/wxTLS_UI.cpp:17
@@ -454,7 +470,7 @@ msgstr ""
msgid "MSCHAPv2"
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"
msgstr ""
@@ -476,24 +492,24 @@ msgstr ""
msgid "Deleting credentials failed (error %u)."
msgstr ""
#: lib/EAPBase_UI/include/EAP_UI.h:738
#: lib/EAPBase_UI/include/EAP_UI.h:739
#, c-format
msgid "<error %u>"
msgstr ""
#: lib/EAPBase_UI/include/EAP_UI.h:742
#: lib/EAPBase_UI/include/EAP_UI.h:743
msgid "<error>"
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>"
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>"
msgstr ""
#: lib/EAPBase_UI/include/EAP_UI.h:962
#: lib/EAPBase_UI/include/EAP_UI.h:964
msgid "<Your Organization>"
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
msgid "<empty>"
msgstr "<napaka>"
msgstr "<prazno>"
#: lib/EAPBase_UI/include/EAP_UI.h:753 lib/EAPBase_UI/include/EAP_UI.h:762
msgid "<blank ID>"

View File

@@ -29,7 +29,7 @@
// Product version as a single DWORD
// Note: Used for version comparison within C/C++ code.
//
#define PRODUCT_VERSION 0x00ff1100
#define PRODUCT_VERSION 0x00ff1200
//
// Product version by components
@@ -39,26 +39,26 @@
//
#define PRODUCT_VERSION_MAJ 0
#define PRODUCT_VERSION_MIN 255
#define PRODUCT_VERSION_REV 17
#define PRODUCT_VERSION_REV 18
#define PRODUCT_VERSION_BUILD 0
//
// 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"
//
// Numerical version presentation for ProductVersion propery in
// 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
// 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

View File

@@ -206,8 +206,9 @@ namespace eap
/// Constructs configuration
///
/// \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
@@ -252,6 +253,9 @@ namespace eap
/// Returns a string identifier of the EAP method type of this configuration
///
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
///
/// \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
@@ -355,7 +360,22 @@ namespace eap
bool m_allow_save; ///< Are credentials allowed to be saved to Windows Credential Manager?
bool m_use_preshared; ///< Use 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);
}
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
///
/// \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
///
/// \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
///
/// \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
///
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("/"));
target_name += pszTargetName;
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();
assert(target_name.length() < CRED_MAX_GENERIC_TARGET_NAME_LENGTH);
return target_name;
@@ -291,6 +303,13 @@ namespace eap
///
credentials_pass& operator=(_Inout_ credentials_pass &&other);
///
/// Clones credentials
///
/// \returns Pointer to cloned credentials
///
virtual config* clone() const;
///
/// Resets credentials
///
@@ -358,18 +377,46 @@ namespace eap
/// Save credentials to Windows Credential Manager
///
/// \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
///
/// \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:
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]);
///
/// 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
@@ -1113,4 +1122,13 @@ inline void hton24(_In_ unsigned int val, _Out_ unsigned char out[3])
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

View File

@@ -124,7 +124,7 @@ namespace eap
///
virtual void get_result(
_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::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)
{
if (this != &other)
if (this != &other) {
assert(m_level == other.m_level); // Allow copy within same configuration level only.
(config&)*this = other;
}
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)
{
if (this != &other)
if (this != &other) {
assert(m_level == other.m_level); // Allow move within same configuration level only.
(config&&)*this = std::move(other);
}
return *this;
}
@@ -139,21 +149,22 @@ eap::config_method& eap::config_method::operator=(_Inout_ config_method &&other)
// 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_use_preshared(false),
m_auth_failed(false),
config_method(mod)
m_last_status(status_success),
config_method(mod, level)
{
}
eap::config_method_with_cred::config_method_with_cred(_In_ const config_method_with_cred &other) :
m_allow_save(other.m_allow_save),
m_use_preshared(other.m_use_preshared),
m_preshared(other.m_preshared ? (credentials*)other.m_preshared->clone() : nullptr),
m_auth_failed(other.m_auth_failed),
config_method(other)
m_allow_save (other.m_allow_save ),
m_use_preshared(other.m_use_preshared ),
m_preshared (other.m_preshared ? (credentials*)other.m_preshared->clone() : nullptr),
m_last_status (other.m_last_status ),
m_last_msg (other.m_last_msg ),
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_use_preshared(std::move(other.m_use_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 ))
{
}
@@ -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_use_preshared = other.m_use_preshared;
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;
@@ -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_use_preshared = std::move(other.m_use_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;
@@ -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.
}
}
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_use_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_use_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_use_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()
{
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);
@@ -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))
throw win_runtime_error(__FUNCTION__ " CryptProtectData failed.");
tstring target(target_name(pszTargetName));
tstring target(target_name(pszTargetName, level));
// Write credentials.
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);
// Read credentials.
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.");
// 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] = {
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,

View File

@@ -68,6 +68,11 @@ void eap::method::begin_session(
UNREFERENCED_PARAMETER(pAttributeArray);
UNREFERENCED_PARAMETER(hTokenImpersonateUser);
UNREFERENCED_PARAMETER(dwMaxSendPacketSize);
// Presume authentication will fail with generic protocol failure. (Pesimist!!!)
// We will reset once we get get_result(Success) call.
m_cfg.m_last_status = config_method_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
//////////////////////////////////////////////////////////////////////

View File

@@ -199,7 +199,6 @@ public:
this->SetIcon(wxIcon(wxICON(product.ico)));
#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) {
bool is_single = provider->m_methods.size() == 1;
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));
eap::config_provider &cfg_provider2 = m_cfg.m_providers.back();
eap::config_method *cfg_method2 = cfg_provider2.m_methods.front().get();
m_providers->InsertPage(
m_providers->GetSelection() + 1,
new _wxT(
cfg_provider2,
*cfg_method2,
m_providers),
wxEAPGetProviderName(cfg_provider2.m_name), true);
_wxT *page = new _wxT(cfg_provider2, *cfg_method2, m_providers);
m_providers->InsertPage(m_providers->GetSelection() + 1, page, wxEAPGetProviderName(cfg_provider2.m_name), true);
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();
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.
eap::config_connection::provider_list::iterator it(m_cfg.m_providers.begin());
for (int i = 0; i < idx; i++, ++it);
@@ -433,7 +432,7 @@ public:
///
/// 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()) {
// Write credentials to credential manager.
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;
UpdateOwnIdentity();
} catch (winstd::win_runtime_error &err) {
@@ -698,7 +697,7 @@ protected:
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_has_own = false;
} else
@@ -720,6 +719,7 @@ protected:
virtual void OnTimerOwn(wxTimerEvent& /*event*/)
{
if (m_own_identity->IsShownOnScreen())
RetrieveOwnCredentials();
}
@@ -727,7 +727,7 @@ protected:
void RetrieveOwnCredentials()
{
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;
UpdateOwnIdentity();
} catch (winstd::win_runtime_error &err) {
@@ -751,6 +751,7 @@ protected:
m_own_identity->SetValue(
!identity.empty() ? identity :
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="name">m_timer_own</property>
<property name="oneshot">0</property>
<property name="period">3000</property>
<property name="period">5000</property>
<property name="permission">protected</property>
<event name="OnTimer">OnTimerOwn</event>
</object>

View File

@@ -239,14 +239,19 @@ wxEAPProviderLockedPanel::wxEAPProviderLockedPanel(const eap::config_provider &p
// 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.
winstd::library lib_shell32;
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_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);
CreateContactFields(prov);

Binary file not shown.

View File

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

View File

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

View File

@@ -30,7 +30,6 @@ namespace eap
#pragma once
#include "Credentials.h"
#include "../../EAPBase/include/Config.h"
#include <Windows.h>
@@ -47,8 +46,9 @@ namespace eap
/// Constructs configuration
///
/// \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

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
#include "Config.h"
#include "Credentials.h"
#include "MSCHAPv2.h"
#include "../../EAPBase/include/Method.h"
#include <list>
namespace eap
{
@@ -47,7 +48,7 @@ namespace eap
/// \param[in] cfg Method configuration
/// \param[in] cred User credentials
///
method_mschapv2(_In_ module &module, _In_ config_method_mschapv2 &cfg, _In_ credentials_mschapv2 &cred);
method_mschapv2(_In_ module &module, _In_ config_method_mschapv2 &cfg, _In_ credentials_pass &cred);
///
/// Moves an EAP method
@@ -89,15 +90,6 @@ namespace eap
_In_ DWORD dwReceivedPacketSize,
_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
@@ -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)
///
/// \param[in] pck Packet data
/// \param[in] size_pck \p pck size in bytes
/// \param[in] argv List of message values
///
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
///
/// \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] size_pck \p pck size in bytes
/// \param[in] argv List of message values
///
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:
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
challenge_mschapv2 m_challenge_server; ///< MSCHAP server challenge
@@ -146,6 +146,6 @@ namespace eap
phase_init = 0, ///< Send client challenge
phase_challenge_server, ///< Verify server challenge
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::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
{
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_z_ const char *username)
{
const char *domain = strchr(username, '@');
size_t len_username = domain ? domain - username : strlen(username);
crypt_hash hash;
if (!hash.create(cp, CALG_SHA))
throw win_runtime_error(__FUNCTION__ " Creating SHA hash failed.");
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*)username , (DWORD)len_username , 0))
!CryptHashData(hash, (const BYTE*)username , (DWORD)strlen(username) , 0))
throw win_runtime_error(__FUNCTION__ " Error hashing data.");
unsigned char hash_val[20];
DWORD size_hash_val = sizeof(hash_val);

View File

@@ -28,12 +28,11 @@ using namespace winstd;
// 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_ident(0),
m_success(false),
m_phase(phase_unknown),
m_phase_prev(phase_unknown),
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_success (std::move(other.m_success )),
m_phase (std::move(other.m_phase )),
m_phase_prev (std::move(other.m_phase_prev )),
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_success = std::move(other.m_success );
m_phase = std::move(other.m_phase );
m_phase_prev = std::move(other.m_phase_prev );
}
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);
process_packet(pReceivedPacket, dwReceivedPacketSize);
m_phase_prev = m_phase;
switch (m_phase) {
case phase_init: {
// Convert username to UTF-8.
sanitizing_string identity_utf8;
WideCharToMultiByte(CP_UTF8, 0, m_cred.m_identity.c_str(), (int)m_cred.m_identity.length(), identity_utf8, NULL, NULL);
// Calculate Peer-Challenge and Response
// Randomize Peer-Challenge
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());
// Prepare MS-CHAP2-Response
@@ -128,16 +124,19 @@ void eap::method_mschapv2::process_request_packet(
response.insert(response.end(), (unsigned char*)&m_nt_resp, (unsigned char*)(&m_nt_resp + 1)); // NT-Response
// Diameter AVP (User-Name=1, MS-CHAP-Challenge=11/311, MS-CHAP2-Response=25/311)
append_avp( 1, diameter_avp_flag_mandatory, identity_utf8.data(), (unsigned int )identity_utf8.size() );
append_avp(11, 311, diameter_avp_flag_mandatory, (unsigned char*)&m_challenge_server , (unsigned char)sizeof(m_challenge_server));
append_avp(25, 311, diameter_avp_flag_mandatory, response.data() , (unsigned char)response.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 int)sizeof(m_challenge_server));
append_avp(25, 311, diameter_avp_flag_mandatory, response.data() , (unsigned int)response.size() );
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;
}
case phase_challenge_server: {
// We do not need to do anything.
process_packet(pReceivedPacket, dwReceivedPacketSize);
if (m_success)
m_phase = phase_finished;
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)
{
sanitizing_blob data;
@@ -214,43 +171,44 @@ void eap::method_mschapv2::process_packet(_In_bytecount_(size_pck) const void *_
vendor = 0;
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)
throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Incomplete message data.");
if (code == 26 && vendor == 311) {
// MS-CHAP2-Success
MultiByteToWideChar(CP_UTF8, 0, (const char*)msg, (int)(msg_end - msg), msg_w);
int argc;
unique_ptr<LPWSTR[], LocalFree_delete<LPWSTR[]> > argv(CommandLineToArgvW(msg_w.c_str(), &argc));
if (!argv) argc = 0;
process_success(argc, (const wchar_t**)argv.get());
if (msg[0] != m_ident)
throw invalid_argument(string_printf(__FUNCTION__ " Wrong MSCHAPv2 ident (expected: %u, received: %u).", m_ident, msg[0]).c_str());
const char *str = (const char*)(msg + 1);
process_success(parse_response(str, ((const char*)msg_end - str)));
} else if (code == 2 && vendor == 311) {
// MS-CHAP2-Error
MultiByteToWideChar(CP_UTF8, 0, (const char*)msg, (int)(msg_end - msg), msg_w);
int argc;
unique_ptr<LPWSTR[], LocalFree_delete<LPWSTR[]> > argv(CommandLineToArgvW(msg_w.c_str(), &argc));
if (!argv) argc = 0;
process_error(argc, (const wchar_t**)argv.get());
m_ident = msg[0];
const char *str = (const char*)(msg + 1);
process_error(parse_response(str, ((const char*)msg_end - str)));
} 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());
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;
for (int i = 0; i < argc; i++) {
if ((argv[i][0] == L'S' || argv[i][0] == L's') && argv[i][1] == L'=') {
for (list<string>::const_iterator arg = argv.cbegin(), arg_end = argv.cend(); arg != arg_end; ++arg) {
const string &val = *arg;
if ((val[0] == 'S' || val[0] == 's') && val[1] == '=') {
// "S="
hex_dec dec;
sanitizing_blob resp;
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.
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);
// 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.");
m_success = true;
@@ -267,13 +225,60 @@ void eap::method_mschapv2::process_success(_In_ int argc, _In_count_(argc) const
if (!m_success)
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);
UNREFERENCED_PARAMETER(argv);
for (list<string>::const_iterator arg = argv.cbegin(), arg_end = argv.cend(); arg != arg_end; ++arg) {
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
#include "../include/Config.h"
#include "../include/Credentials.h"
#include "../include/Method.h"
#include "../include/MSCHAPv2.h"
@@ -29,3 +28,4 @@
#include <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 "../../MSCHAPv2/include/Config.h"
#include "../../MSCHAPv2/include/Credentials.h"
///
/// 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
@@ -35,7 +34,7 @@ class wxMSCHAPv2ConfigPanel;
///
/// MSCHAPv2 credential entry panel
///
typedef wxPasswordCredentialsPanel<eap::credentials_mschapv2, wxEAPCredentialsPassPanelBase> wxMSCHAPv2CredentialsPanel;
typedef wxPasswordCredentialsPanel<eap::credentials_pass, wxEAPCredentialsPassPanelBase> wxMSCHAPv2CredentialsPanel;
#pragma once

View File

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

View File

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

View File

@@ -30,7 +30,6 @@ namespace eap
#pragma once
#include "Credentials.h"
#include "../../EAPBase/include/Config.h"
#include <Windows.h>
@@ -47,8 +46,9 @@ namespace eap
/// Constructs configuration
///
/// \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

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
#include "Config.h"
#include "Credentials.h"
#include "../../EAPBase/include/Method.h"
@@ -47,7 +46,7 @@ namespace eap
/// \param[in] cfg Method configuration
/// \param[in] cred User credentials
///
method_pap(_In_ module &module, _In_ config_method_pap &cfg, _In_ credentials_pap &cred);
method_pap(_In_ module &module, _In_ config_method_pap &cfg, _In_ credentials_pass &cred);
///
/// Moves an EAP method
@@ -89,24 +88,15 @@ namespace eap
_In_ DWORD dwReceivedPacketSize,
_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:
credentials_pap &m_cred; ///< EAP-TLS user credentials
credentials_pass &m_cred; ///< EAP-TLS user credentials
enum {
phase_unknown = -1, ///< Unknown phase
phase_init = 0, ///< Handshake initialize
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::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
{
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::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_phase(phase_unknown),
m_phase_prev(phase_unknown),
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) :
m_cred ( other.m_cred ),
m_phase (std::move(other.m_phase )),
m_phase_prev (std::move(other.m_phase_prev)),
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!
(method_noneap&)*this = std::move(other );
m_phase = std::move(other.m_phase );
m_phase_prev = std::move(other.m_phase_prev);
}
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_phase_prev = m_phase;
switch (m_phase) {
case phase_init: {
// 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());
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;
}
@@ -111,45 +108,3 @@ void eap::method_pap::process_request_packet(
pEapOutput->fAllowNotifications = TRUE;
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
#include "../include/Config.h"
#include "../include/Credentials.h"
#include "../include/Method.h"
#include <Windows.h>

View File

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

View File

@@ -67,8 +67,9 @@ namespace eap
/// Constructs configuration
///
/// \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

View File

@@ -158,15 +158,17 @@ namespace eap
/// Save credentials to Windows Credential Manager
///
/// \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
///
/// \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

View File

@@ -235,6 +235,11 @@ namespace eap
///
virtual void derive_msk();
///
/// Generates keying material for inner authentication
///
virtual void derive_challenge();
/// @}
#if EAP_TLS < EAP_TLS_SCHANNEL
@@ -478,7 +483,7 @@ namespace eap
phase_handshake_cont, ///< Handshake continue
phase_application_data, ///< Exchange application data
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
};
}

View File

@@ -98,31 +98,6 @@ namespace eap
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
#include <memory>

View File

@@ -66,7 +66,7 @@ tstring eap::get_cert_title(PCCERT_CONTEXT cert)
// 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));
}

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);
@@ -179,7 +179,7 @@ void eap::credentials_tls::store(_In_z_ LPCTSTR pszTargetName) const
throw win_runtime_error(__FUNCTION__ " CryptProtectData failed.");
}
tstring target(target_name(pszTargetName));
tstring target(target_name(pszTargetName, level));
// Write credentials.
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);
// Read credentials.
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.");
if (cred->CredentialBlobSize) {
@@ -240,7 +240,7 @@ void eap::credentials_tls::retrieve(_In_z_ LPCTSTR pszTargetName)
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) {
try {
credentials_tls cred_loaded(m_module);
cred_loaded.retrieve(pszTargetName);
cred_loaded.retrieve(pszTargetName, cfg.m_level);
// Using stored credentials.
*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),
#else
m_phase(phase_unknown),
m_phase_prev(phase_unknown),
#endif
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_ctx (std::move(other.m_sc_ctx )),
m_phase (std::move(other.m_phase )),
m_phase_prev (std::move(other.m_phase_prev )),
#endif
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_ctx = std::move(other.m_sc_ctx );
m_phase = std::move(other.m_phase );
m_phase_prev = std::move(other.m_phase_prev );
#endif
}
@@ -435,6 +432,9 @@ void eap::method_tls::process_request_packet(
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());
// Derive challenge for inner authentication (if any).
derive_challenge();
if (m_handshake[tls_handshake_type_finished]) {
// Go to application data phase. And allow piggybacking of the first data message.
m_phase = phase_application_data;
@@ -443,6 +443,7 @@ void eap::method_tls::process_request_packet(
} else {
m_session_resumed = false;
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;
}
@@ -470,7 +471,6 @@ void eap::method_tls::process_request_packet(
} else
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) {
case phase_handshake_init:
case phase_handshake_cont:
@@ -508,10 +508,10 @@ void eap::method_tls::get_result(
{
assert(ppResult);
method::get_result(reason, ppResult);
switch (reason) {
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();
@@ -524,12 +524,6 @@ void eap::method_tls::get_result(
m_eap_attr.push_back(std::move(a));
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
// Update configuration with session resumption data.
m_cfg.m_session_id = m_session_id;
@@ -567,44 +561,15 @@ void eap::method_tls::get_result(
case EapPeerMethodResultFailure:
#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.
m_cfg.m_session_id.clear();
m_cfg.m_master_secret.clear();
#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.
#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;
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);
}
void eap::method_tls::derive_challenge()
{
}
#if EAP_TLS < EAP_TLS_SCHANNEL
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
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;
process_application_data(m_sc_queue.data(), m_sc_queue.size());
} else
} else {
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) {
// Schannel neeeds more data. Send ACK packet to server to send more.
} else if (FAILED(status)) {
@@ -1262,13 +1238,14 @@ void eap::method_tls::process_application_data()
// Prepare input/output buffer(s).
SecBuffer buf[] = {
{ 0, SECBUFFER_TOKEN, NULL },
{ 0, SECBUFFER_ALERT, NULL },
{
(unsigned long)m_sc_queue.size(),
SECBUFFER_DATA,
m_sc_queue.data()
},
{ 0, SECBUFFER_EMPTY, NULL },
{ 0, SECBUFFER_EMPTY, NULL },
{ 0, SECBUFFER_EMPTY, NULL },
};
SecBufferDesc buf_desc = {
SECBUFFER_VERSION,
@@ -1279,8 +1256,17 @@ void eap::method_tls::process_application_data()
// Decrypt the message.
SECURITY_STATUS status = DecryptMessage(m_sc_ctx, &buf_desc, 0, NULL);
if (status == SEC_E_OK) {
assert(buf[2].BufferType == SECBUFFER_DATA);
process_application_data(buf[2].pvBuffer, buf[2].cbBuffer);
// Find SECBUFFER_DATA buffer(s) and process data.
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) {
// Schannel neeeds more data. Send ACK packet to server to send more.
} else if (status == SEC_I_CONTEXT_EXPIRED) {
@@ -1292,16 +1278,8 @@ void eap::method_tls::process_application_data()
m_sc_queue.clear();
m_phase = phase_handshake_init;
process_handshake();
} 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);
}
} else if (FAILED(status))
throw sec_runtime_error(status, __FUNCTION__ " Schannel error.");
}
}
#endif

View File

@@ -48,8 +48,9 @@ namespace eap {
/// Constructs configuration
///
/// \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

View File

@@ -149,15 +149,17 @@ namespace eap
/// Save credentials to Windows Credential Manager
///
/// \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
///
/// \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.

View File

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

View File

@@ -28,9 +28,9 @@ using namespace winstd;
// eap::config_method_ttls
//////////////////////////////////////////////////////////////////////
eap::config_method_ttls::config_method_ttls(_In_ module &mod) :
m_inner(new config_method_pap(mod)),
config_method_tls(mod)
eap::config_method_ttls::config_method_ttls(_In_ module &mod, _In_ unsigned int level) :
m_inner(new config_method_pap(mod, level + 1)),
config_method_tls(mod, level)
{
// TTLS is using blank pre-shared credentials per default.
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
{
switch (eap_type) {
case eap_type_tls : return new config_method_tls (m_module);
case eap_type_ttls : return new config_method_ttls (m_module);
case eap_type_legacy_pap : return new config_method_pap (m_module);
case eap_type_legacy_mschapv2: return new config_method_mschapv2(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, m_level + 1);
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, m_level + 1);
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
{
if (_wcsicmp(eap_type, L"EAP-TLS" ) == 0) return new config_method_tls (m_module);
else if (_wcsicmp(eap_type, L"EAP-TTLS") == 0) return new config_method_ttls (m_module);
else if (_wcsicmp(eap_type, L"PAP" ) == 0) return new config_method_pap (m_module);
else if (_wcsicmp(eap_type, L"MSCHAPv2") == 0) return new config_method_mschapv2(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, m_level + 1);
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, m_level + 1);
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:
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:
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.
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_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_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_pass&)*m_cred.m_inner.get())); break;
default: throw invalid_argument(__FUNCTION__ " Unsupported inner authentication method.");
}
m_inner->begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, MAXDWORD);
@@ -129,6 +129,12 @@ void eap::method_ttls::get_result(
m_inner->get_result(reason, &result);
if (result.fSaveConnectionData)
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
static const unsigned char s_label[] = "ttls challenge";
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_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
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 };
@@ -207,18 +217,11 @@ eap::sanitizing_blob eap::method_ttls::derive_challenge(_In_ size_t size)
status = QueryContextAttributes(m_sc_ctx, SECPKG_ATTR_EAP_KEY_BLOCK, &key_block);
if (FAILED(status))
throw sec_runtime_error(status, __FUNCTION__ " Error generating PRF in Schannel.");
sanitizing_blob key;
key.reserve(size);
if (size <= sizeof(key_block.rgbKeys))
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;
memcpy(&inner_mschapv2->m_challenge_server, key_block.rgbKeys, sizeof(challenge_mschapv2));
inner_mschapv2->m_ident = key_block.rgbKeys[sizeof(challenge_mschapv2) + 0];
#endif
}
}
@@ -245,13 +248,6 @@ void eap::method_ttls::process_application_data(_In_bytecount_(size_msg) const v
}
#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 = {};
m_inner->process_request_packet(msg, (DWORD)size_msg, &eap_output);
switch (eap_output.action) {
@@ -279,6 +275,7 @@ void eap::method_ttls::process_application_data(_In_bytecount_(size_msg) const v
#endif
m_inner->get_response_packet(ptr_data, &size_data);
if (size_data) {
#if EAP_TLS < EAP_TLS_SCHANNEL
data.resize(size_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.");
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
} else {
// Empty packets represent ACK message, and are not encrypted.
}
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()
{
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();
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) {
pack(s->m_cfg, &ppResult->pConnectionData, &ppResult->dwSizeofConnectionData);
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 ((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.
log_event(&EAPMETHOD_TRACE_EVT_CRED_PROBLEM1, event_data(target_name), event_data((unsigned int)eap_type_tls), event_data::blank);
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.
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;

View File

@@ -27,11 +27,9 @@
#include "../include/TTLS.h"
#include "../../PAP/include/Config.h"
#include "../../PAP/include/Credentials.h"
#include "../../PAP/include/Method.h"
#include "../../MSCHAPv2/include/Config.h"
#include "../../MSCHAPv2/include/Credentials.h"
#include "../../MSCHAPv2/include/Method.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()
{
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.
if (panel->m_outer_cred->GetRemember()) {
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) {
wxLogError(winstd::tstring_printf(_("Error writing credentials to Credential Manager: %hs (error %u)"), err.what(), err.number()).c_str());
} catch (...) {
@@ -280,7 +280,7 @@ void eap::peer_ttls_ui::invoke_identity_ui(
if (panel->m_inner_cred->GetRemember()) {
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) {
wxLogError(winstd::tstring_printf(_("Error writing credentials to Credential Manager: %hs (error %u)"), err.what(), err.number()).c_str());
} catch (...) {

View File

@@ -95,8 +95,8 @@ void wxTTLSConfigPanel::OnUpdateUI(wxUpdateUIEvent& /*event*/)
wxTTLSConfigWindow::wxTTLSConfigWindow(eap::config_provider &prov, eap::config_method &cfg, wxWindow* parent) :
m_cfg((eap::config_method_ttls&)cfg),
m_cfg_pap(cfg.m_module),
m_cfg_mschapv2(cfg.m_module),
m_cfg_pap(cfg.m_module, cfg.m_level + 1),
m_cfg_mschapv2(cfg.m_module, cfg.m_level + 1),
wxEAPConfigWindow(prov, cfg, parent)
{
wxBoxSizer* sb_content;
@@ -239,14 +239,20 @@ wxTTLSCredentialsPanel::wxTTLSCredentialsPanel(const eap::config_provider &prov,
assert(m_cfg.m_inner);
if (m_cfg.m_inner->m_auth_failed)
sb_content->Add(new wxEAPCredentialWarningPanel(m_prov, this), 0, wxALL|wxEXPAND, 5);
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, 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());
if (cfg_inner_pap) {
const eap::config_method_pap *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;
if (!cred_ttls.m_inner) cred_ttls.m_inner.reset(new eap::credentials_pap(cred.m_module));
m_inner_cred = new wxPAPCredentialsPanel(m_prov, *cfg_inner_pap, *(eap::credentials_pap*)cred_ttls.m_inner.get(), this, is_config);
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_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);
} else
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 ) );
sb_content->Add(m_outer_title, 0, wxALL|wxALIGN_RIGHT, 5);
if (m_cfg.m_auth_failed)
sb_content->Add(new wxEAPCredentialWarningPanel(m_prov, this), 0, wxALL|wxEXPAND, 5);
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, 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);
sb_content->Add(m_outer_cred, 0, wxALL|wxEXPAND, 5);