Server names can be Unicode now

This commit is contained in:
2016-08-23 14:42:11 +02:00
parent 59768e8097
commit f39cb94ee5
7 changed files with 3255 additions and 3262 deletions

View File

@@ -1,176 +1,176 @@
/*
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 <WinStd/Common.h>
#include <Windows.h>
#include <WinCrypt.h> // Must include after <Windows.h>
#include <sal.h>
namespace eap
{
///
/// TLS configuration
///
class config_method_tls;
///
/// Helper function to compile human-readable certificate name for UI display
///
winstd::tstring get_cert_title(PCCERT_CONTEXT cert);
}
#pragma once
#include "Credentials.h"
#include "Method.h"
#include "TLS.h"
#include "../../EAPBase/include/Config.h"
#include <WinStd/Crypt.h>
#include <Windows.h>
#include <list>
#include <string>
namespace eap
{
class config_method_tls : public config_method_with_cred
{
public:
///
/// Constructs configuration
///
/// \param[in] mod EAP module to use for global services
///
config_method_tls(_In_ module &mod);
///
/// Copies configuration
///
/// \param[in] other Configuration to copy from
///
config_method_tls(_In_ const config_method_tls &other);
///
/// Moves configuration
///
/// \param[in] other Configuration to move from
///
config_method_tls(_Inout_ config_method_tls &&other);
///
/// Copies configuration
///
/// \param[in] other Configuration to copy from
///
/// \returns Reference to this object
///
config_method_tls& operator=(_In_ const config_method_tls &other);
///
/// Moves configuration
///
/// \param[in] other Configuration to move from
///
/// \returns Reference to this object
///
config_method_tls& operator=(_Inout_ config_method_tls &&other);
///
/// Clones configuration
///
/// \returns Pointer to cloned configuration
///
virtual config* clone() const;
/// \name XML configuration management
/// @{
///
/// Save to XML document
///
/// \param[in] pDoc XML document
/// \param[in] pConfigRoot Suggested root element for saving
///
virtual void save(_In_ IXMLDOMDocument *pDoc, _In_ IXMLDOMNode *pConfigRoot) const;
///
/// Load from XML document
///
/// \param[in] pConfigRoot Root element for loading
///
virtual void load(_In_ IXMLDOMNode *pConfigRoot);
/// @}
/// \name BLOB management
/// @{
///
/// Packs a configuration
///
/// \param[inout] cursor Memory cursor
///
virtual void operator<<(_Inout_ cursor_out &cursor) const;
///
/// Returns packed size of a configuration
///
/// \returns Size of data when packed (in bytes)
///
virtual size_t get_pk_size() const;
///
/// Unpacks a configuration
///
/// \param[inout] cursor Memory cursor
///
virtual void operator>>(_Inout_ cursor_in &cursor);
/// @}
///
/// Returns EAP method type of this configuration
///
/// \returns `eap::type_tls`
///
virtual winstd::eap_type_t get_method_id() const;
///
/// Adds CA to the list of trusted root CA's
///
/// \sa [CertCreateCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376033.aspx)
///
bool add_trusted_ca(_In_ DWORD dwCertEncodingType, _In_ const BYTE *pbCertEncoded, _In_ DWORD cbCertEncoded);
public:
std::list<winstd::cert_context> m_trusted_root_ca; ///< Trusted root CAs
std::list<std::string> m_server_names; ///< Acceptable authenticating server names
// Following members are used for session resumptions. They are not exported/imported to XML.
sanitizing_blob m_session_id; ///< TLS session ID
tls_master_secret m_master_secret; ///< TLS master secret
};
}
/*
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 <WinStd/Common.h>
#include <Windows.h>
#include <WinCrypt.h> // Must include after <Windows.h>
#include <sal.h>
namespace eap
{
///
/// TLS configuration
///
class config_method_tls;
///
/// Helper function to compile human-readable certificate name for UI display
///
winstd::tstring get_cert_title(PCCERT_CONTEXT cert);
}
#pragma once
#include "Credentials.h"
#include "Method.h"
#include "TLS.h"
#include "../../EAPBase/include/Config.h"
#include <WinStd/Crypt.h>
#include <Windows.h>
#include <list>
#include <string>
namespace eap
{
class config_method_tls : public config_method_with_cred
{
public:
///
/// Constructs configuration
///
/// \param[in] mod EAP module to use for global services
///
config_method_tls(_In_ module &mod);
///
/// Copies configuration
///
/// \param[in] other Configuration to copy from
///
config_method_tls(_In_ const config_method_tls &other);
///
/// Moves configuration
///
/// \param[in] other Configuration to move from
///
config_method_tls(_Inout_ config_method_tls &&other);
///
/// Copies configuration
///
/// \param[in] other Configuration to copy from
///
/// \returns Reference to this object
///
config_method_tls& operator=(_In_ const config_method_tls &other);
///
/// Moves configuration
///
/// \param[in] other Configuration to move from
///
/// \returns Reference to this object
///
config_method_tls& operator=(_Inout_ config_method_tls &&other);
///
/// Clones configuration
///
/// \returns Pointer to cloned configuration
///
virtual config* clone() const;
/// \name XML configuration management
/// @{
///
/// Save to XML document
///
/// \param[in] pDoc XML document
/// \param[in] pConfigRoot Suggested root element for saving
///
virtual void save(_In_ IXMLDOMDocument *pDoc, _In_ IXMLDOMNode *pConfigRoot) const;
///
/// Load from XML document
///
/// \param[in] pConfigRoot Root element for loading
///
virtual void load(_In_ IXMLDOMNode *pConfigRoot);
/// @}
/// \name BLOB management
/// @{
///
/// Packs a configuration
///
/// \param[inout] cursor Memory cursor
///
virtual void operator<<(_Inout_ cursor_out &cursor) const;
///
/// Returns packed size of a configuration
///
/// \returns Size of data when packed (in bytes)
///
virtual size_t get_pk_size() const;
///
/// Unpacks a configuration
///
/// \param[inout] cursor Memory cursor
///
virtual void operator>>(_Inout_ cursor_in &cursor);
/// @}
///
/// Returns EAP method type of this configuration
///
/// \returns `eap::type_tls`
///
virtual winstd::eap_type_t get_method_id() const;
///
/// Adds CA to the list of trusted root CA's
///
/// \sa [CertCreateCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376033.aspx)
///
bool add_trusted_ca(_In_ DWORD dwCertEncodingType, _In_ const BYTE *pbCertEncoded, _In_ DWORD cbCertEncoded);
public:
std::list<winstd::cert_context> m_trusted_root_ca; ///< Trusted root CAs
std::list<std::wstring> m_server_names; ///< Acceptable authenticating server names
// Following members are used for session resumptions. They are not exported/imported to XML.
sanitizing_blob m_session_id; ///< TLS session ID
tls_master_secret m_master_secret; ///< TLS master secret
};
}

View File

@@ -1,305 +1,298 @@
/*
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"
#pragma comment(lib, "Cryptui.lib")
using namespace std;
using namespace winstd;
//////////////////////////////////////////////////////////////////////
// eap::get_cert_title
//////////////////////////////////////////////////////////////////////
tstring eap::get_cert_title(PCCERT_CONTEXT cert)
{
tstring name, str, issuer, title;
FILETIME ft;
SYSTEMTIME st;
// Prepare certificate information
CertGetNameString(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, name);
title += name;
FileTimeToLocalFileTime(&(cert->pCertInfo->NotBefore), &ft);
FileTimeToSystemTime(&ft, &st);
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, str);
title += _T(", ");
title += str;
FileTimeToLocalFileTime(&(cert->pCertInfo->NotAfter ), &ft);
FileTimeToSystemTime(&ft, &st);
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, str);
title += _T('-');
title += str;
CertGetNameString(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, issuer);
if (name != issuer) {
title += _T(", ");
title += issuer;
}
return title;
}
//////////////////////////////////////////////////////////////////////
// eap::config_method_tls
//////////////////////////////////////////////////////////////////////
eap::config_method_tls::config_method_tls(_In_ module &mod) : config_method_with_cred(mod)
{
m_preshared.reset(new credentials_tls(mod));
}
eap::config_method_tls::config_method_tls(_In_ const config_method_tls &other) :
m_trusted_root_ca(other.m_trusted_root_ca),
m_server_names(other.m_server_names),
m_session_id(other.m_session_id),
m_master_secret(other.m_master_secret),
config_method_with_cred(other)
{
}
eap::config_method_tls::config_method_tls(_Inout_ config_method_tls &&other) :
m_trusted_root_ca(std::move(other.m_trusted_root_ca)),
m_server_names(std::move(other.m_server_names)),
m_session_id(std::move(other.m_session_id)),
m_master_secret(std::move(other.m_master_secret)),
config_method_with_cred(std::move(other))
{
}
eap::config_method_tls& eap::config_method_tls::operator=(_In_ const config_method_tls &other)
{
if (this != &other) {
(config_method_with_cred&)*this = other;
m_trusted_root_ca = other.m_trusted_root_ca;
m_server_names = other.m_server_names;
m_session_id = other.m_session_id;
m_master_secret = other.m_master_secret;
}
return *this;
}
eap::config_method_tls& eap::config_method_tls::operator=(_Inout_ config_method_tls &&other)
{
if (this != &other) {
(config_method_with_cred&&)*this = std::move(other);
m_trusted_root_ca = std::move(other.m_trusted_root_ca);
m_server_names = std::move(other.m_server_names);
m_session_id = std::move(other.m_session_id);
m_master_secret = std::move(other.m_master_secret);
}
return *this;
}
eap::config* eap::config_method_tls::clone() const
{
return new config_method_tls(*this);
}
void eap::config_method_tls::save(_In_ IXMLDOMDocument *pDoc, _In_ IXMLDOMNode *pConfigRoot) const
{
assert(pDoc);
assert(pConfigRoot);
config_method_with_cred::save(pDoc, pConfigRoot);
const bstr bstrNamespace(L"urn:ietf:params:xml:ns:yang:ietf-eap-metadata");
HRESULT hr;
// <ServerSideCredential>
com_obj<IXMLDOMElement> pXmlElServerSideCredential;
if (FAILED(hr = eapxml::create_element(pDoc, pConfigRoot, bstr(L"eap-metadata:ServerSideCredential"), bstr(L"ServerSideCredential"), bstrNamespace, &pXmlElServerSideCredential)))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <ServerSideCredential> element.");
for (list<cert_context>::const_iterator i = m_trusted_root_ca.begin(), i_end = m_trusted_root_ca.end(); i != i_end; ++i) {
// <CA>
com_obj<IXMLDOMElement> pXmlElCA;
if (FAILED(hr = eapxml::create_element(pDoc, bstr(L"CA"), bstrNamespace, &pXmlElCA)))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <CA> element.");
// <CA>/<format>
if (FAILED(hr = eapxml::put_element_value(pDoc, pXmlElCA, bstr(L"format"), bstrNamespace, bstr(L"PEM"))))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <format> element.");
// <CA>/<cert-data>
const cert_context &cc = *i;
if (FAILED(hr = eapxml::put_element_base64(pDoc, pXmlElCA, bstr(L"cert-data"), bstrNamespace, cc->pbCertEncoded, cc->cbCertEncoded)))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <cert-data> element.");
if (FAILED(hr = pXmlElServerSideCredential->appendChild(pXmlElCA, NULL)))
throw com_runtime_error(hr, __FUNCTION__ " Error appending <CA> element.");
}
// <ServerName>
for (list<string>::const_iterator i = m_server_names.begin(), i_end = m_server_names.end(); i != i_end; ++i) {
wstring str;
MultiByteToWideChar(CP_UTF8, 0, i->c_str(), (int)i->length(), str);
if (FAILED(hr = eapxml::put_element_value(pDoc, pXmlElServerSideCredential, bstr(L"ServerName"), bstrNamespace, bstr(str))))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <ServerName> element.");
}
}
void eap::config_method_tls::load(_In_ IXMLDOMNode *pConfigRoot)
{
assert(pConfigRoot);
config_method_with_cred::load(pConfigRoot);
std::wstring xpath(eapxml::get_xpath(pConfigRoot));
m_trusted_root_ca.clear();
m_server_names.clear();
// <ServerSideCredential>
com_obj<IXMLDOMElement> pXmlElServerSideCredential;
if (SUCCEEDED(eapxml::select_element(pConfigRoot, bstr(L"eap-metadata:ServerSideCredential"), &pXmlElServerSideCredential))) {
std::wstring xpathServerSideCredential(xpath + L"/ServerSideCredential");
// <CA>
com_obj<IXMLDOMNodeList> pXmlListCAs;
long lCACount = 0;
if (SUCCEEDED(eapxml::select_nodes(pXmlElServerSideCredential, bstr(L"eap-metadata:CA"), &pXmlListCAs)) && SUCCEEDED(pXmlListCAs->get_length(&lCACount))) {
for (long j = 0; j < lCACount; j++) {
// Load CA certificate.
com_obj<IXMLDOMNode> pXmlElCA;
pXmlListCAs->get_item(j, &pXmlElCA);
bstr bstrFormat;
if (FAILED(eapxml::get_element_value(pXmlElCA, bstr(L"eap-metadata:format"), &bstrFormat))) {
// <format> not specified.
continue;
}
if (CompareStringEx(LOCALE_NAME_INVARIANT, NORM_IGNORECASE, bstrFormat, bstrFormat.length(), L"PEM", -1, NULL, NULL, 0) != CSTR_EQUAL) {
// Certificate must be PEM encoded.
continue;
}
vector<unsigned char> aData;
if (FAILED(eapxml::get_element_base64(pXmlElCA, bstr(L"eap-metadata:cert-data"), aData))) {
// Error reading <cert-data> element.
continue;
}
add_trusted_ca(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, aData.data(), (DWORD)aData.size());
}
// Log loaded CA certificates.
list<tstring> cert_names;
for (std::list<winstd::cert_context>::const_iterator cert = m_trusted_root_ca.cbegin(), cert_end = m_trusted_root_ca.cend(); cert != cert_end; ++cert)
cert_names.push_back(std::move(get_cert_title(*cert)));
m_module.log_config((xpathServerSideCredential + L"/CA").c_str(), cert_names);
}
// <ServerName>
com_obj<IXMLDOMNodeList> pXmlListServerIDs;
long lServerIDCount = 0;
if (SUCCEEDED(eapxml::select_nodes(pXmlElServerSideCredential, bstr(L"eap-metadata:ServerName"), &pXmlListServerIDs)) && SUCCEEDED(pXmlListServerIDs->get_length(&lServerIDCount))) {
for (long j = 0; j < lServerIDCount; j++) {
// Load server name (<ServerName>).
com_obj<IXMLDOMNode> pXmlElServerID;
pXmlListServerIDs->get_item(j, &pXmlElServerID);
bstr bstrServerID;
pXmlElServerID->get_text(&bstrServerID);
// Server names (FQDNs) are always ASCII. Hopefully. Convert them to UTF-8 anyway for consistent comparison. CP_ANSI varies.
string str;
WideCharToMultiByte(CP_UTF8, 0, bstrServerID, bstrServerID.length(), str, NULL, NULL);
m_server_names.push_back(str);
}
m_module.log_config((xpathServerSideCredential + L"/ServerName").c_str(), m_server_names);
}
}
}
void eap::config_method_tls::operator<<(_Inout_ cursor_out &cursor) const
{
config_method_with_cred::operator<<(cursor);
cursor << m_trusted_root_ca;
cursor << m_server_names ;
cursor << m_session_id ;
cursor << m_master_secret ;
}
size_t eap::config_method_tls::get_pk_size() const
{
return
config_method_with_cred::get_pk_size() +
pksizeof(m_trusted_root_ca) +
pksizeof(m_server_names ) +
pksizeof(m_session_id ) +
pksizeof(m_master_secret );
}
void eap::config_method_tls::operator>>(_Inout_ cursor_in &cursor)
{
config_method_with_cred::operator>>(cursor);
cursor >> m_trusted_root_ca;
cursor >> m_server_names ;
cursor >> m_session_id ;
cursor >> m_master_secret ;
}
eap_type_t eap::config_method_tls::get_method_id() const
{
return eap_type_tls;
}
bool eap::config_method_tls::add_trusted_ca(_In_ DWORD dwCertEncodingType, _In_ const BYTE *pbCertEncoded, _In_ DWORD cbCertEncoded)
{
cert_context cert;
if (!cert.create(dwCertEncodingType, pbCertEncoded, cbCertEncoded)) {
// Invalid or unsupported certificate.
return false;
}
for (list<cert_context>::const_iterator i = m_trusted_root_ca.cbegin(), i_end = m_trusted_root_ca.cend();; ++i) {
if (i != i_end) {
if (*i == cert) {
// This certificate is already on the list.
return false;
}
} else {
// End of list reached. Append certificate.
m_trusted_root_ca.push_back(std::move(cert));
return true;
}
}
}
/*
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"
#pragma comment(lib, "Cryptui.lib")
using namespace std;
using namespace winstd;
//////////////////////////////////////////////////////////////////////
// eap::get_cert_title
//////////////////////////////////////////////////////////////////////
tstring eap::get_cert_title(PCCERT_CONTEXT cert)
{
tstring name, str, issuer, title;
FILETIME ft;
SYSTEMTIME st;
// Prepare certificate information
CertGetNameString(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, name);
title += name;
FileTimeToLocalFileTime(&(cert->pCertInfo->NotBefore), &ft);
FileTimeToSystemTime(&ft, &st);
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, str);
title += _T(", ");
title += str;
FileTimeToLocalFileTime(&(cert->pCertInfo->NotAfter ), &ft);
FileTimeToSystemTime(&ft, &st);
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, str);
title += _T('-');
title += str;
CertGetNameString(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, issuer);
if (name != issuer) {
title += _T(", ");
title += issuer;
}
return title;
}
//////////////////////////////////////////////////////////////////////
// eap::config_method_tls
//////////////////////////////////////////////////////////////////////
eap::config_method_tls::config_method_tls(_In_ module &mod) : config_method_with_cred(mod)
{
m_preshared.reset(new credentials_tls(mod));
}
eap::config_method_tls::config_method_tls(_In_ const config_method_tls &other) :
m_trusted_root_ca(other.m_trusted_root_ca),
m_server_names(other.m_server_names),
m_session_id(other.m_session_id),
m_master_secret(other.m_master_secret),
config_method_with_cred(other)
{
}
eap::config_method_tls::config_method_tls(_Inout_ config_method_tls &&other) :
m_trusted_root_ca(std::move(other.m_trusted_root_ca)),
m_server_names(std::move(other.m_server_names)),
m_session_id(std::move(other.m_session_id)),
m_master_secret(std::move(other.m_master_secret)),
config_method_with_cred(std::move(other))
{
}
eap::config_method_tls& eap::config_method_tls::operator=(_In_ const config_method_tls &other)
{
if (this != &other) {
(config_method_with_cred&)*this = other;
m_trusted_root_ca = other.m_trusted_root_ca;
m_server_names = other.m_server_names;
m_session_id = other.m_session_id;
m_master_secret = other.m_master_secret;
}
return *this;
}
eap::config_method_tls& eap::config_method_tls::operator=(_Inout_ config_method_tls &&other)
{
if (this != &other) {
(config_method_with_cred&&)*this = std::move(other);
m_trusted_root_ca = std::move(other.m_trusted_root_ca);
m_server_names = std::move(other.m_server_names);
m_session_id = std::move(other.m_session_id);
m_master_secret = std::move(other.m_master_secret);
}
return *this;
}
eap::config* eap::config_method_tls::clone() const
{
return new config_method_tls(*this);
}
void eap::config_method_tls::save(_In_ IXMLDOMDocument *pDoc, _In_ IXMLDOMNode *pConfigRoot) const
{
assert(pDoc);
assert(pConfigRoot);
config_method_with_cred::save(pDoc, pConfigRoot);
const bstr bstrNamespace(L"urn:ietf:params:xml:ns:yang:ietf-eap-metadata");
HRESULT hr;
// <ServerSideCredential>
com_obj<IXMLDOMElement> pXmlElServerSideCredential;
if (FAILED(hr = eapxml::create_element(pDoc, pConfigRoot, bstr(L"eap-metadata:ServerSideCredential"), bstr(L"ServerSideCredential"), bstrNamespace, &pXmlElServerSideCredential)))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <ServerSideCredential> element.");
for (list<cert_context>::const_iterator i = m_trusted_root_ca.begin(), i_end = m_trusted_root_ca.end(); i != i_end; ++i) {
// <CA>
com_obj<IXMLDOMElement> pXmlElCA;
if (FAILED(hr = eapxml::create_element(pDoc, bstr(L"CA"), bstrNamespace, &pXmlElCA)))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <CA> element.");
// <CA>/<format>
if (FAILED(hr = eapxml::put_element_value(pDoc, pXmlElCA, bstr(L"format"), bstrNamespace, bstr(L"PEM"))))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <format> element.");
// <CA>/<cert-data>
const cert_context &cc = *i;
if (FAILED(hr = eapxml::put_element_base64(pDoc, pXmlElCA, bstr(L"cert-data"), bstrNamespace, cc->pbCertEncoded, cc->cbCertEncoded)))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <cert-data> element.");
if (FAILED(hr = pXmlElServerSideCredential->appendChild(pXmlElCA, NULL)))
throw com_runtime_error(hr, __FUNCTION__ " Error appending <CA> element.");
}
// <ServerName>
for (list<wstring>::const_iterator i = m_server_names.begin(), i_end = m_server_names.end(); i != i_end; ++i) {
if (FAILED(hr = eapxml::put_element_value(pDoc, pXmlElServerSideCredential, bstr(L"ServerName"), bstrNamespace, bstr(*i))))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <ServerName> element.");
}
}
void eap::config_method_tls::load(_In_ IXMLDOMNode *pConfigRoot)
{
assert(pConfigRoot);
config_method_with_cred::load(pConfigRoot);
std::wstring xpath(eapxml::get_xpath(pConfigRoot));
m_trusted_root_ca.clear();
m_server_names.clear();
// <ServerSideCredential>
com_obj<IXMLDOMElement> pXmlElServerSideCredential;
if (SUCCEEDED(eapxml::select_element(pConfigRoot, bstr(L"eap-metadata:ServerSideCredential"), &pXmlElServerSideCredential))) {
std::wstring xpathServerSideCredential(xpath + L"/ServerSideCredential");
// <CA>
com_obj<IXMLDOMNodeList> pXmlListCAs;
long lCACount = 0;
if (SUCCEEDED(eapxml::select_nodes(pXmlElServerSideCredential, bstr(L"eap-metadata:CA"), &pXmlListCAs)) && SUCCEEDED(pXmlListCAs->get_length(&lCACount))) {
for (long j = 0; j < lCACount; j++) {
// Load CA certificate.
com_obj<IXMLDOMNode> pXmlElCA;
pXmlListCAs->get_item(j, &pXmlElCA);
bstr bstrFormat;
if (FAILED(eapxml::get_element_value(pXmlElCA, bstr(L"eap-metadata:format"), &bstrFormat))) {
// <format> not specified.
continue;
}
if (CompareStringEx(LOCALE_NAME_INVARIANT, NORM_IGNORECASE, bstrFormat, bstrFormat.length(), L"PEM", -1, NULL, NULL, 0) != CSTR_EQUAL) {
// Certificate must be PEM encoded.
continue;
}
vector<unsigned char> aData;
if (FAILED(eapxml::get_element_base64(pXmlElCA, bstr(L"eap-metadata:cert-data"), aData))) {
// Error reading <cert-data> element.
continue;
}
add_trusted_ca(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, aData.data(), (DWORD)aData.size());
}
// Log loaded CA certificates.
list<tstring> cert_names;
for (std::list<winstd::cert_context>::const_iterator cert = m_trusted_root_ca.cbegin(), cert_end = m_trusted_root_ca.cend(); cert != cert_end; ++cert)
cert_names.push_back(std::move(get_cert_title(*cert)));
m_module.log_config((xpathServerSideCredential + L"/CA").c_str(), cert_names);
}
// <ServerName>
com_obj<IXMLDOMNodeList> pXmlListServerIDs;
long lServerIDCount = 0;
if (SUCCEEDED(eapxml::select_nodes(pXmlElServerSideCredential, bstr(L"eap-metadata:ServerName"), &pXmlListServerIDs)) && SUCCEEDED(pXmlListServerIDs->get_length(&lServerIDCount))) {
for (long j = 0; j < lServerIDCount; j++) {
// Load server name (<ServerName>).
com_obj<IXMLDOMNode> pXmlElServerID;
pXmlListServerIDs->get_item(j, &pXmlElServerID);
bstr bstrServerID;
pXmlElServerID->get_text(&bstrServerID);
m_server_names.push_back(wstring(bstrServerID));
}
m_module.log_config((xpathServerSideCredential + L"/ServerName").c_str(), m_server_names);
}
}
}
void eap::config_method_tls::operator<<(_Inout_ cursor_out &cursor) const
{
config_method_with_cred::operator<<(cursor);
cursor << m_trusted_root_ca;
cursor << m_server_names ;
cursor << m_session_id ;
cursor << m_master_secret ;
}
size_t eap::config_method_tls::get_pk_size() const
{
return
config_method_with_cred::get_pk_size() +
pksizeof(m_trusted_root_ca) +
pksizeof(m_server_names ) +
pksizeof(m_session_id ) +
pksizeof(m_master_secret );
}
void eap::config_method_tls::operator>>(_Inout_ cursor_in &cursor)
{
config_method_with_cred::operator>>(cursor);
cursor >> m_trusted_root_ca;
cursor >> m_server_names ;
cursor >> m_session_id ;
cursor >> m_master_secret ;
}
eap_type_t eap::config_method_tls::get_method_id() const
{
return eap_type_tls;
}
bool eap::config_method_tls::add_trusted_ca(_In_ DWORD dwCertEncodingType, _In_ const BYTE *pbCertEncoded, _In_ DWORD cbCertEncoded)
{
cert_context cert;
if (!cert.create(dwCertEncodingType, pbCertEncoded, cbCertEncoded)) {
// Invalid or unsupported certificate.
return false;
}
for (list<cert_context>::const_iterator i = m_trusted_root_ca.cbegin(), i_end = m_trusted_root_ca.cend();; ++i) {
if (i != i_end) {
if (*i == cert) {
// This certificate is already on the list.
return false;
}
} else {
// End of list reached. Append certificate.
m_trusted_root_ca.push_back(std::move(cert));
return true;
}
}
}

View File

@@ -1166,8 +1166,8 @@ void eap::method_tls::verify_server_trust() const
assert(!m_server_cert_chain.empty());
const cert_context &cert = m_server_cert_chain.front();
string subj;
if (!CertGetNameStringA(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, subj))
wstring subj;
if (!CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, subj))
throw win_runtime_error(__FUNCTION__ " Error retrieving server's certificate subject name.");
const config_provider &cfg_prov(m_cfg.m_providers.front());
@@ -1176,29 +1176,29 @@ void eap::method_tls::verify_server_trust() const
if (!cfg_method->m_server_names.empty()) {
// Check server name.
for (list<string>::const_iterator s = cfg_method->m_server_names.cbegin(), s_end = cfg_method->m_server_names.cend();; ++s) {
for (list<wstring>::const_iterator s = cfg_method->m_server_names.cbegin(), s_end = cfg_method->m_server_names.cend();; ++s) {
if (s != s_end) {
const char
const wchar_t
*a = s->c_str(),
*b = subj.c_str();
size_t
len_a = s->length(),
len_b = subj.length();
if (_stricmp(a, b) == 0 || // Direct match
a[0] == '*' && len_b + 1 >= len_a && _stricmp(a + 1, b + len_b - (len_a - 1)) == 0) // "*..." wildchar match
if (_wcsicmp(a, b) == 0 || // Direct match
a[0] == '*' && len_b + 1 >= len_a && _wcsicmp(a + 1, b + len_b - (len_a - 1)) == 0) // "*..." wildchar match
{
m_module.log_event(&EAPMETHOD_TLS_SERVER_NAME_TRUSTED, event_data(subj), event_data::blank);
m_module.log_event(&EAPMETHOD_TLS_SERVER_NAME_TRUSTED1, event_data(subj), event_data::blank);
break;
}
} else
throw win_runtime_error(ERROR_INVALID_DOMAINNAME, string_printf(__FUNCTION__ " Server name %s is not on the list of trusted server names.", subj.c_str()).c_str());
throw win_runtime_error(ERROR_INVALID_DOMAINNAME, string_printf(__FUNCTION__ " Server name %ls is not on the list of trusted server names.", subj.c_str()).c_str());
}
}
if (cert->pCertInfo->Issuer.cbData == cert->pCertInfo->Subject.cbData &&
memcmp(cert->pCertInfo->Issuer.pbData, cert->pCertInfo->Subject.pbData, cert->pCertInfo->Issuer.cbData) == 0)
throw com_runtime_error(CRYPT_E_SELF_SIGNED, string_printf(__FUNCTION__ " Server is using a self-signed certificate %s. Cannot trust it.", subj.c_str()).c_str());
throw com_runtime_error(CRYPT_E_SELF_SIGNED, string_printf(__FUNCTION__ " Server is using a self-signed certificate %ls. Cannot trust it.", subj.c_str()).c_str());
// Create temporary certificate store of our trusted root CAs.
cert_store store;