credentials_tls: Keep thumbprint rather than client certificate

By storing the client certificate the certificate became detached from
its private key stored in user certificate store. This rendered client
certificates useless for client TLS authentication.

Now, the client certificate thumbprint is stored instead. The client
certificate is looked up in the user certificate store as required.

This breaks profile XML and BLOB backward compatibility. Since the
client certificate support was broken, nobody probably used those in
the settings before.

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2020-02-06 11:15:34 +01:00
parent 75488ba870
commit 6e97a04bfe
6 changed files with 107 additions and 175 deletions

View File

@ -142,12 +142,7 @@ namespace eap
_In_opt_z_ LPCTSTR pszTargetName); _In_opt_z_ LPCTSTR pszTargetName);
public: public:
winstd::cert_context m_cert; ///< Client certificate std::vector<unsigned char> m_cert_hash; ///< Client certificate SHA-1 thumbprint
private:
/// \cond internal
static const unsigned char s_entropy[1024];
/// \endcond
}; };
/// @} /// @}

View File

@ -143,6 +143,8 @@ namespace eap
_In_ HANDLE hTokenImpersonateUser, _In_ HANDLE hTokenImpersonateUser,
_In_opt_ DWORD dwMaxSendPacketSize = MAXDWORD); _In_opt_ DWORD dwMaxSendPacketSize = MAXDWORD);
virtual void end_session();
/// @} /// @}
/// \name Packet processing /// \name Packet processing
@ -192,6 +194,7 @@ namespace eap
config_method_tls &m_cfg; ///< Method configuration config_method_tls &m_cfg; ///< Method configuration
credentials_tls &m_cred; ///< Method user credentials credentials_tls &m_cred; ///< Method user credentials
HANDLE m_user_ctx; ///< Handle to user context HANDLE m_user_ctx; ///< Handle to user context
winstd::cert_store m_store; ///< User certificate store
winstd::tstring m_sc_target_name; ///< Schannel target name winstd::tstring m_sc_target_name; ///< Schannel target name
winstd::sec_credentials m_sc_cred; ///< Schannel client credentials winstd::sec_credentials m_sc_cred; ///< Schannel client credentials
std::vector<unsigned char> m_sc_queue; ///< TLS data queue std::vector<unsigned char> m_sc_queue; ///< TLS data queue

View File

@ -34,14 +34,14 @@ eap::credentials_tls::credentials_tls(_In_ module &mod) : credentials(mod)
eap::credentials_tls::credentials_tls(_In_ const credentials_tls &other) : eap::credentials_tls::credentials_tls(_In_ const credentials_tls &other) :
m_cert(other.m_cert), m_cert_hash(other.m_cert_hash),
credentials(other) credentials(other)
{ {
} }
eap::credentials_tls::credentials_tls(_Inout_ credentials_tls &&other) noexcept : eap::credentials_tls::credentials_tls(_Inout_ credentials_tls &&other) noexcept :
m_cert(std::move(other.m_cert)), m_cert_hash(std::move(other.m_cert_hash)),
credentials(std::move(other)) credentials(std::move(other))
{ {
} }
@ -51,7 +51,7 @@ eap::credentials_tls& eap::credentials_tls::operator=(_In_ const credentials_tls
{ {
if (this != &other) { if (this != &other) {
(credentials&)*this = other; (credentials&)*this = other;
m_cert = other.m_cert; m_cert_hash = other.m_cert_hash;
} }
return *this; return *this;
@ -62,7 +62,7 @@ eap::credentials_tls& eap::credentials_tls::operator=(_Inout_ credentials_tls &&
{ {
if (this != &other) { if (this != &other) {
(credentials&)*this = std::move(other); (credentials&)*this = std::move(other);
m_cert = std::move(other.m_cert); m_cert_hash = std::move(other.m_cert_hash);
} }
return *this; return *this;
@ -78,13 +78,13 @@ eap::config* eap::credentials_tls::clone() const
void eap::credentials_tls::clear() void eap::credentials_tls::clear()
{ {
credentials::clear(); credentials::clear();
m_cert.free(); m_cert_hash.clear();
} }
bool eap::credentials_tls::empty() const bool eap::credentials_tls::empty() const
{ {
return !m_cert; return m_cert_hash.empty();
} }
@ -102,14 +102,10 @@ void eap::credentials_tls::save(_In_ IXMLDOMDocument *pDoc, _In_ IXMLDOMNode *pC
if (FAILED(hr = eapxml::create_element(pDoc, pConfigRoot, bstr(L"eap-metadata:ClientCertificate"), bstr(L"ClientCertificate"), namespace_eapmetadata, pXmlElClientCertificate))) if (FAILED(hr = eapxml::create_element(pDoc, pConfigRoot, bstr(L"eap-metadata:ClientCertificate"), bstr(L"ClientCertificate"), namespace_eapmetadata, pXmlElClientCertificate)))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <ClientCertificate> element."); throw com_runtime_error(hr, __FUNCTION__ " Error creating <ClientCertificate> element.");
if (m_cert) { if (!m_cert_hash.empty()) {
// <ClientCertificate>/<format> // <ClientCertificate>/<hash>
if (FAILED(hr = eapxml::put_element_value(pDoc, pXmlElClientCertificate, bstr(L"format"), namespace_eapmetadata, bstr(L"PEM")))) if (FAILED(hr = eapxml::put_element_hex(pDoc, pXmlElClientCertificate, bstr(L"hash"), namespace_eapmetadata, m_cert_hash.data(), m_cert_hash.size())))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <format> element."); throw com_runtime_error(hr, __FUNCTION__ " Error creating <hash> element.");
// <ClientCertificate>/<cert-data>
if (FAILED(hr = eapxml::put_element_base64(pDoc, pXmlElClientCertificate, bstr(L"cert-data"), namespace_eapmetadata, m_cert->pbCertEncoded, m_cert->cbCertEncoded)))
throw com_runtime_error(hr, __FUNCTION__ " Error creating <cert-data> element.");
} }
} }
@ -123,35 +119,24 @@ void eap::credentials_tls::load(_In_ IXMLDOMNode *pConfigRoot)
std::wstring xpath(eapxml::get_xpath(pConfigRoot)); std::wstring xpath(eapxml::get_xpath(pConfigRoot));
m_cert.free(); m_cert_hash.clear();
// <ClientCertificate> // <ClientCertificate>
com_obj<IXMLDOMElement> pXmlElClientCertificate; com_obj<IXMLDOMElement> pXmlElClientCertificate;
if (FAILED(hr = eapxml::select_element(pConfigRoot, bstr(L"eap-metadata:ClientCertificate"), pXmlElClientCertificate))) if (FAILED(hr = eapxml::select_element(pConfigRoot, bstr(L"eap-metadata:ClientCertificate"), pXmlElClientCertificate)))
throw com_runtime_error(hr, __FUNCTION__ " Error reading <ClientCertificate> element."); throw com_runtime_error(hr, __FUNCTION__ " Error reading <ClientCertificate> element.");
// <ClientCertificate>/<format> // <ClientCertificate>/<hash>
bstr bstrFormat; eapxml::get_element_hex(pXmlElClientCertificate, bstr(L"eap-metadata:hash"), m_cert_hash);
if (SUCCEEDED(eapxml::get_element_value(pXmlElClientCertificate, bstr(L"eap-metadata:format"), bstrFormat))) {
if (CompareStringEx(LOCALE_NAME_INVARIANT, NORM_IGNORECASE, bstrFormat, bstrFormat.length(), L"PEM", -1, NULL, NULL, 0) == CSTR_EQUAL) {
// <ClientCertificate>/<cert-data>
vector<unsigned char> aData;
if (SUCCEEDED(eapxml::get_element_base64(pXmlElClientCertificate, bstr(L"eap-metadata:cert-data"), aData)))
m_cert.create(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, aData.data(), (DWORD)aData.size());
}
}
if (m_cert) m_module.log_config((xpath + L"/ClientCertificateHash").c_str(), m_cert_hash.data(), (ULONG)m_cert_hash.size());
m_module.log_config_discrete((xpath + L"/ClientCertificate").c_str(), m_cert->pbCertEncoded, m_cert->cbCertEncoded);
else
m_module.log_config_discrete((xpath + L"/ClientCertificate").c_str(), NULL, 0);
} }
void eap::credentials_tls::operator<<(_Inout_ cursor_out &cursor) const void eap::credentials_tls::operator<<(_Inout_ cursor_out &cursor) const
{ {
credentials::operator<<(cursor); credentials::operator<<(cursor);
cursor << m_cert; cursor << m_cert_hash;
} }
@ -159,34 +144,24 @@ size_t eap::credentials_tls::get_pk_size() const
{ {
return return
credentials::get_pk_size() + credentials::get_pk_size() +
pksizeof(m_cert); pksizeof(m_cert_hash);
} }
void eap::credentials_tls::operator>>(_Inout_ cursor_in &cursor) void eap::credentials_tls::operator>>(_Inout_ cursor_in &cursor)
{ {
credentials::operator>>(cursor); credentials::operator>>(cursor);
cursor >> m_cert; cursor >> m_cert_hash;
} }
void eap::credentials_tls::store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const void eap::credentials_tls::store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const
{ {
assert(pszTargetName); assert(pszTargetName);
data_blob cred_enc;
if (m_cert) {
// Encrypt the certificate using user's key.
DATA_BLOB cred_blob = { m_cert->cbCertEncoded, m_cert->pbCertEncoded };
DATA_BLOB entropy_blob = { sizeof(s_entropy) , const_cast<LPBYTE>(s_entropy) };
if (!CryptProtectData(&cred_blob, NULL, &entropy_blob, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN | CRYPTPROTECT_AUDIT, &cred_enc))
throw win_runtime_error(__FUNCTION__ " CryptProtectData failed.");
}
tstring target(target_name(pszTargetName, level)); tstring target(target_name(pszTargetName, level));
// Write credentials. // Write credentials.
assert(cred_enc.cbData < CRED_MAX_CREDENTIAL_BLOB_SIZE); assert(m_cert_hash.size() < CRED_MAX_CREDENTIAL_BLOB_SIZE);
assert(m_identity.length() < CRED_MAX_USERNAME_LENGTH ); assert(m_identity.length() < CRED_MAX_USERNAME_LENGTH );
CREDENTIAL cred = { CREDENTIAL cred = {
0, // Flags 0, // Flags
@ -194,8 +169,8 @@ void eap::credentials_tls::store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int
const_cast<LPTSTR>(target.c_str()), // TargetName const_cast<LPTSTR>(target.c_str()), // TargetName
_T(""), // Comment _T(""), // Comment
{ 0, 0 }, // LastWritten { 0, 0 }, // LastWritten
cred_enc.cbData, // CredentialBlobSize (DWORD)m_cert_hash.size(), // CredentialBlobSize
cred_enc.pbData, // CredentialBlob (LPBYTE)m_cert_hash.data(), // CredentialBlob
CRED_PERSIST_ENTERPRISE, // Persist CRED_PERSIST_ENTERPRISE, // Persist
0, // AttributeCount 0, // AttributeCount
NULL, // Attributes NULL, // Attributes
@ -216,20 +191,10 @@ void eap::credentials_tls::retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned
if (!CredRead(target_name(pszTargetName, level).c_str(), CRED_TYPE_GENERIC, 0, (PCREDENTIAL*)&cred)) if (!CredRead(target_name(pszTargetName, level).c_str(), CRED_TYPE_GENERIC, 0, (PCREDENTIAL*)&cred))
throw win_runtime_error(__FUNCTION__ " CredRead failed."); throw win_runtime_error(__FUNCTION__ " CredRead failed.");
if (cred->CredentialBlobSize) { if (cred->CredentialBlobSize)
// Decrypt the certificate using user's key. m_cert_hash.assign(cred->CredentialBlob, cred->CredentialBlob + cred->CredentialBlobSize);
DATA_BLOB cred_enc = { cred->CredentialBlobSize, cred->CredentialBlob }; else
DATA_BLOB entropy_blob = { sizeof(s_entropy) , const_cast<LPBYTE>(s_entropy) }; m_cert_hash.clear();
data_blob cred_int;
if (!CryptUnprotectData(&cred_enc, NULL, &entropy_blob, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN | CRYPTPROTECT_VERIFY_PROTECTION, &cred_int))
throw win_runtime_error(__FUNCTION__ " CryptUnprotectData failed.");
bool bResult = m_cert.create(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cred_int.pbData, cred_int.cbData);
SecureZeroMemory(cred_int.pbData, cred_int.cbData);
if (!bResult)
throw win_runtime_error(__FUNCTION__ " Error loading certificate.");
} else
m_cert.free();
if (cred->UserName) if (cred->UserName)
m_identity = cred->UserName; m_identity = cred->UserName;
@ -238,10 +203,7 @@ void eap::credentials_tls::retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned
wstring xpath(pszTargetName); wstring xpath(pszTargetName);
m_module.log_config((xpath + L"/Identity").c_str(), m_identity.c_str()); m_module.log_config((xpath + L"/Identity").c_str(), m_identity.c_str());
if (m_cert) m_module.log_config((xpath + L"/CertificateHash").c_str(), m_cert_hash.data(), (ULONG)m_cert_hash.size());
m_module.log_config_discrete((xpath + L"/Certificate").c_str(), m_cert->pbCertEncoded, m_cert->cbCertEncoded);
else
m_module.log_config_discrete((xpath + L"/Certificate").c_str(), NULL, 0);
} }
@ -255,11 +217,22 @@ std::wstring eap::credentials_tls::get_identity() const
{ {
if (!m_identity.empty()) { if (!m_identity.empty()) {
return m_identity; return m_identity;
} else if (m_cert) { } else if (!m_cert_hash.empty()) {
// Find certificate in the store.
winstd::cert_store store;
vector<unsigned char> hash;
if (store.create(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, (HCRYPTPROV)NULL, CERT_SYSTEM_STORE_CURRENT_USER, _T("My"))) {
for (PCCERT_CONTEXT cert = NULL; (cert = CertEnumCertificatesInStore(store, cert)) != NULL;) {
if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, hash) &&
hash == m_cert_hash)
{
wstring name; wstring name;
CertGetNameStringW(m_cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, name); CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, name);
return name; return name;
} }
}
}
}
return L""; return L"";
} }
@ -304,73 +277,3 @@ eap::credentials::source_t eap::credentials_tls::combine(
return source_t::unknown; return source_t::unknown;
} }
/// \cond internal
const unsigned char eap::credentials_tls::s_entropy[1024] = {
0xb9, 0xd1, 0x62, 0xd4, 0x1c, 0xe6, 0x8c, 0x25, 0x98, 0x9b, 0x1d, 0xbc, 0x40, 0x46, 0x9e, 0x6d,
0x63, 0xba, 0xda, 0x78, 0x65, 0x56, 0x97, 0x4f, 0xa0, 0x89, 0xf4, 0xc5, 0x1b, 0xf5, 0x8d, 0x69,
0xa1, 0x8c, 0xf3, 0xf9, 0x91, 0x86, 0x7f, 0xf3, 0x47, 0x2e, 0x23, 0x61, 0xde, 0x4f, 0x61, 0x94,
0xba, 0xba, 0x27, 0x63, 0x0b, 0xf0, 0x4e, 0xa0, 0x24, 0xab, 0x17, 0x62, 0x3f, 0xc4, 0xd8, 0xad,
0xd6, 0x03, 0x1f, 0x3b, 0xdd, 0x88, 0xf7, 0x9a, 0x56, 0xf4, 0x0d, 0xce, 0x9b, 0x18, 0x33, 0x54,
0x5a, 0x1a, 0x3b, 0x91, 0x70, 0xf5, 0x95, 0x1c, 0x39, 0xe8, 0x42, 0x6c, 0x6e, 0xe6, 0x4d, 0xb8,
0x1c, 0xa6, 0xce, 0xad, 0xcd, 0x9e, 0x55, 0x88, 0x90, 0xff, 0x5e, 0x81, 0xdf, 0x08, 0x68, 0x54,
0xa1, 0x60, 0xfb, 0x41, 0x8a, 0xc1, 0xf2, 0xf0, 0xc4, 0x0e, 0xb9, 0xd1, 0x61, 0xa5, 0xc4, 0x02,
0xd9, 0x43, 0xbb, 0x16, 0x9f, 0x9a, 0xc3, 0xe0, 0x61, 0xf8, 0x57, 0x16, 0xb1, 0x7f, 0x00, 0x53,
0xf6, 0x8b, 0x97, 0x8f, 0xec, 0x3f, 0x72, 0x32, 0x0c, 0x0a, 0x80, 0x00, 0x4f, 0x87, 0x36, 0x2e,
0x24, 0x1d, 0xb4, 0xe5, 0x6c, 0x41, 0x34, 0xe9, 0x75, 0x4c, 0xf2, 0xdb, 0x16, 0xb5, 0x9a, 0x54,
0x40, 0xe9, 0x1f, 0xc0, 0xf1, 0xc5, 0x0d, 0x5d, 0xa7, 0xb5, 0x51, 0x15, 0x05, 0x95, 0xe2, 0x46,
0x9d, 0xc7, 0x74, 0xd7, 0xab, 0x93, 0xce, 0x7d, 0xf9, 0x61, 0x9d, 0x2b, 0xe7, 0x45, 0x61, 0x0b,
0xcc, 0x18, 0xf1, 0xf4, 0x00, 0xb9, 0x78, 0x23, 0x45, 0x8a, 0xd6, 0x1d, 0x95, 0x6b, 0x99, 0xe0,
0x21, 0x6b, 0x98, 0x91, 0xcb, 0x0e, 0x50, 0x9a, 0x2e, 0x64, 0xa2, 0xe9, 0x1b, 0x1f, 0x6e, 0x69,
0x78, 0x1d, 0xd1, 0xa1, 0xe5, 0x95, 0x34, 0x78, 0xf2, 0x8b, 0xe6, 0x38, 0x74, 0xd6, 0x48, 0x69,
0x62, 0xf6, 0xd3, 0x18, 0x1c, 0xb1, 0x0e, 0xc0, 0xdf, 0xff, 0x2e, 0xd3, 0xbc, 0x4e, 0xae, 0xd7,
0xe0, 0xb8, 0x47, 0x15, 0xcc, 0x10, 0xc3, 0x3a, 0x3d, 0x67, 0x79, 0x33, 0x1d, 0xb1, 0x73, 0xdf,
0xfb, 0xb2, 0x89, 0xbb, 0x04, 0x76, 0xec, 0x4a, 0x73, 0x73, 0xa8, 0x07, 0xb7, 0xb0, 0xbe, 0x15,
0xac, 0xc3, 0x32, 0x1e, 0x70, 0xc2, 0x0e, 0x8c, 0x29, 0x2e, 0x2d, 0xfc, 0x36, 0x1f, 0x9d, 0x90,
0x86, 0x1b, 0x12, 0xca, 0x82, 0x4d, 0xea, 0x9e, 0xb4, 0x5e, 0xb0, 0x33, 0xc4, 0x19, 0x25, 0x3f,
0x27, 0x11, 0x5a, 0x79, 0x91, 0x44, 0x2c, 0x50, 0x56, 0xe0, 0xd2, 0xb3, 0x81, 0x17, 0x3f, 0x06,
0x57, 0x39, 0x18, 0x2c, 0xd4, 0x1e, 0xf3, 0x90, 0x7e, 0xc3, 0x08, 0x50, 0x89, 0x7a, 0xf7, 0x7f,
0xe9, 0xf1, 0x2d, 0x73, 0x95, 0xd9, 0x2e, 0x83, 0xc8, 0x93, 0x33, 0xd9, 0x00, 0xc3, 0xa0, 0x43,
0x32, 0x57, 0x7b, 0xa9, 0xbf, 0x55, 0xfc, 0x35, 0xfb, 0x85, 0x08, 0x1c, 0x84, 0xa7, 0xce, 0xb0,
0x8b, 0xab, 0x56, 0xfa, 0x70, 0x9c, 0xd5, 0x8f, 0x21, 0xf6, 0x8f, 0x5e, 0xd5, 0x1b, 0x81, 0x17,
0xf7, 0x82, 0xb2, 0x28, 0xde, 0xc5, 0xc1, 0xba, 0xe7, 0xfa, 0x21, 0x06, 0xff, 0xf3, 0x27, 0xf8,
0x3a, 0x7d, 0xbc, 0x96, 0x5e, 0xdf, 0xf4, 0x89, 0x9f, 0x1c, 0x40, 0x03, 0x1a, 0xd2, 0x53, 0xb9,
0xe4, 0xeb, 0x16, 0xbf, 0xaa, 0xe3, 0xdf, 0x5d, 0x2a, 0xef, 0x16, 0x6f, 0x5d, 0x2b, 0x75, 0x4c,
0x0e, 0xe0, 0xda, 0xc4, 0xd7, 0x05, 0x52, 0x28, 0x25, 0xc4, 0x3f, 0xe0, 0x55, 0x07, 0x93, 0x21,
0x80, 0x2b, 0x49, 0x0c, 0x00, 0xd7, 0x13, 0xb3, 0xe0, 0x29, 0x93, 0x66, 0x0a, 0x4b, 0x88, 0x63,
0xac, 0x14, 0x5f, 0x9b, 0x1c, 0xf4, 0xe3, 0xe7, 0xeb, 0xac, 0x2d, 0xe3, 0x08, 0x7d, 0xcf, 0xce,
0x12, 0xf0, 0xcd, 0x68, 0x6e, 0xe2, 0x06, 0x16, 0x38, 0x17, 0x93, 0xbc, 0xf9, 0xfe, 0x8e, 0xb2,
0x14, 0x99, 0x76, 0x82, 0xf7, 0xc2, 0x93, 0x46, 0x95, 0xd7, 0x81, 0x03, 0x16, 0xae, 0xfc, 0x39,
0xb0, 0x26, 0xd1, 0x74, 0x73, 0x82, 0x21, 0xdb, 0x74, 0x48, 0xd7, 0xc2, 0xae, 0x73, 0x2d, 0x81,
0x84, 0x61, 0x6d, 0x1d, 0x8a, 0xb4, 0x9d, 0xb3, 0x2a, 0xa7, 0x9b, 0x08, 0x89, 0x2a, 0x96, 0x98,
0xc1, 0x64, 0xf2, 0x10, 0x8b, 0x8d, 0xaa, 0xbe, 0x0d, 0x37, 0xaa, 0x42, 0x94, 0x9f, 0xae, 0x18,
0x64, 0xcd, 0x77, 0x24, 0x41, 0xc8, 0x6a, 0xbc, 0x80, 0x7f, 0xd8, 0x1f, 0x94, 0x29, 0xe7, 0x38,
0xb8, 0x7f, 0x90, 0x54, 0xe4, 0xb6, 0xb8, 0x30, 0x7f, 0x40, 0xeb, 0x60, 0x6c, 0x6a, 0x07, 0x36,
0x5b, 0xfc, 0x09, 0x72, 0xff, 0x02, 0x96, 0xce, 0xd6, 0xdc, 0x07, 0x80, 0x25, 0x70, 0x6f, 0x9e,
0x63, 0xac, 0x97, 0x1d, 0x3d, 0x3a, 0x26, 0x83, 0xc8, 0xe3, 0x99, 0xa8, 0x10, 0xf4, 0x68, 0xf4,
0xf3, 0x8c, 0x38, 0x8d, 0xd2, 0x13, 0xd5, 0x95, 0xce, 0x80, 0x1e, 0xcf, 0x14, 0xb8, 0x16, 0x64,
0x28, 0xf1, 0x40, 0xd9, 0xa0, 0x24, 0x13, 0x84, 0x3b, 0x8b, 0x92, 0x73, 0x67, 0x77, 0x93, 0xfe,
0x07, 0x67, 0x7d, 0xcf, 0x7f, 0x9e, 0x7b, 0x74, 0x6a, 0x07, 0xb8, 0x1f, 0xdc, 0xa6, 0xdd, 0xbb,
0x63, 0xc8, 0x5d, 0xde, 0x48, 0x93, 0x34, 0xf3, 0x3b, 0xa6, 0x4d, 0x08, 0xdf, 0xd4, 0x40, 0x55,
0x0c, 0x85, 0x6c, 0xda, 0x41, 0xc2, 0xd5, 0x4f, 0x08, 0xfc, 0x87, 0x43, 0x22, 0x42, 0x59, 0x53,
0xbe, 0x21, 0xe4, 0x09, 0xcc, 0x6a, 0xa2, 0x50, 0x6e, 0x2d, 0x9a, 0x61, 0xdc, 0x36, 0xd0, 0x51,
0xab, 0xdb, 0x24, 0xad, 0x37, 0xe5, 0x47, 0x93, 0xcd, 0x74, 0x94, 0x17, 0x71, 0x8f, 0xc1, 0xca,
0x3f, 0xfa, 0x4f, 0xd8, 0xb5, 0xbb, 0xb6, 0xf3, 0xab, 0x7d, 0xa6, 0x65, 0x24, 0x42, 0x2a, 0x4b,
0x3a, 0xbb, 0x7c, 0xcf, 0x1e, 0x32, 0x12, 0xf4, 0xe1, 0x90, 0xb3, 0x50, 0xb1, 0xfc, 0x7c, 0x6b,
0x91, 0x06, 0x18, 0x02, 0x33, 0x83, 0x4b, 0x20, 0x75, 0xf5, 0xad, 0x37, 0x5d, 0xb8, 0xc2, 0xb5,
0x23, 0x28, 0x32, 0x50, 0x36, 0xd8, 0x6d, 0x65, 0x98, 0xca, 0x58, 0x51, 0x91, 0x72, 0x3b, 0x42,
0xd5, 0xcd, 0x09, 0x1e, 0xcf, 0x8c, 0x88, 0x4c, 0xf4, 0x4d, 0x31, 0x0b, 0xd3, 0x81, 0xe8, 0x28,
0x2b, 0xf6, 0x6d, 0x70, 0x34, 0x0f, 0x7e, 0x8d, 0xfc, 0x03, 0xc4, 0x8c, 0xf2, 0xc5, 0x6c, 0xbd,
0xf8, 0x14, 0xec, 0x2b, 0x0a, 0xb7, 0x7e, 0x8b, 0xcf, 0xb5, 0x58, 0xa5, 0x4d, 0x34, 0x61, 0x58,
0xa3, 0xfd, 0x72, 0x4e, 0x20, 0xbe, 0x96, 0xc4, 0x6c, 0xec, 0x1f, 0xb6, 0x0c, 0x15, 0xbc, 0x71,
0x30, 0xa1, 0x57, 0x13, 0x85, 0x5c, 0xf3, 0x36, 0x42, 0x8b, 0x22, 0x26, 0x5b, 0xfb, 0x76, 0x01,
0xf3, 0xf3, 0xff, 0xe1, 0x6b, 0xf3, 0x8c, 0x25, 0xe3, 0x60, 0xee, 0xc8, 0x8f, 0xe3, 0xdb, 0xa8,
0x6e, 0xed, 0x1e, 0x5a, 0xd4, 0xd2, 0xff, 0x28, 0xea, 0x63, 0x56, 0xc1, 0xc3, 0xee, 0x37, 0x57,
0xd7, 0x6d, 0x92, 0xf8, 0x2b, 0x9a, 0x55, 0x62, 0x7b, 0x08, 0x27, 0xde, 0x13, 0x27, 0x35, 0x30,
0x20, 0xb3, 0x43, 0x31, 0xeb, 0xf6, 0x28, 0xb4, 0x6e, 0x92, 0x82, 0x48, 0x1e, 0xbf, 0xe6, 0x3d,
0x84, 0x0d, 0x9f, 0x5f, 0x55, 0x97, 0x96, 0x26, 0x65, 0x59, 0xfa, 0x6a, 0x72, 0xc6, 0x49, 0xa5,
0x0d, 0xd0, 0x84, 0x17, 0x97, 0x56, 0x2e, 0xff, 0x82, 0x76, 0x61, 0x75, 0x9f, 0x15, 0xd2, 0x08,
0xbb, 0x24, 0xb5, 0xba, 0xaa, 0x5e, 0x20, 0xdd, 0x03, 0x4c, 0x3c, 0x54, 0xd8, 0x8f, 0x87, 0x49,
};
/// \endcond

View File

@ -208,12 +208,23 @@ void eap::method_tls::begin_session(
#endif #endif
} }
if (!m_store.create(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, (HCRYPTPROV)NULL, CERT_SYSTEM_STORE_CURRENT_USER, _T("My")))
throw win_runtime_error(__FUNCTION__ " CertOpenStore failed.");
// Prepare client credentials for Schannel. // Prepare client credentials for Schannel.
PCCERT_CONTEXT certs[] = { m_cred.m_cert ? (PCCERT_CONTEXT)m_cred.m_cert : NULL }; vector<PCCERT_CONTEXT> certs;
if (!m_cred.empty()) {
vector<unsigned char> hash;
for (PCCERT_CONTEXT cert = NULL; (cert = CertEnumCertificatesInStore(m_store, cert)) != NULL;) {
if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, hash) &&
hash == m_cred.m_cert_hash)
certs.push_back(cert);
}
}
SCHANNEL_CRED cred = { SCHANNEL_CRED cred = {
SCHANNEL_CRED_VERSION, // dwVersion SCHANNEL_CRED_VERSION, // dwVersion
m_cred.m_cert ? 1ul : 0ul, // cCreds (DWORD)certs.size(), // cCreds
certs, // paCred certs.data(), // paCred
NULL, // hRootStore: Not valid for client credentials NULL, // hRootStore: Not valid for client credentials
0, // cMappers 0, // cMappers
NULL, // aphMappers NULL, // aphMappers
@ -244,6 +255,14 @@ void eap::method_tls::begin_session(
} }
void eap::method_tls::end_session()
{
m_store.free();
method::end_session();
}
EapPeerMethodResponseAction eap::method_tls::process_request_packet( EapPeerMethodResponseAction eap::method_tls::process_request_packet(
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket, _In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize) _In_ DWORD dwReceivedPacketSize)

View File

@ -36,6 +36,7 @@
#include <string> #include <string>
class wxCertificateClientData; class wxCertificateClientData;
class wxCertificateHashClientData;
class wxTLSCredentialsPanel; class wxTLSCredentialsPanel;
class wxTLSServerTrustPanel; class wxTLSServerTrustPanel;
class wxTLSConfigPanel; class wxTLSConfigPanel;
@ -93,6 +94,16 @@ public:
}; };
///
/// Helper class for auto-destroyable certificate hashes used in wxWidget's item containers
///
class wxCertificateHashClientData : public wxClientData
{
public:
std::vector<unsigned char> m_cert_hash; ///< Certificate thumbprint
};
/// ///
/// TLS credential panel /// TLS credential panel
/// ///

View File

@ -58,7 +58,7 @@ wxTLSCredentialsPanel::wxTLSCredentialsPanel(const eap::config_provider &prov, c
bool wxTLSCredentialsPanel::TransferDataToWindow() bool wxTLSCredentialsPanel::TransferDataToWindow()
{ {
// Populate certificate list. // Populate certificate list.
m_certificate->Append(_("(empty)"), (wxCertificateClientData*)NULL); m_certificate->Append(_("(empty)"), (wxCertificateHashClientData*)NULL);
bool is_found = false; bool is_found = false;
winstd::cert_store store; winstd::cert_store store;
if (store.create(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, (HCRYPTPROV)NULL, CERT_SYSTEM_STORE_CURRENT_USER, _T("My"))) { if (store.create(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, (HCRYPTPROV)NULL, CERT_SYSTEM_STORE_CURRENT_USER, _T("My"))) {
@ -70,13 +70,14 @@ bool wxTLSCredentialsPanel::TransferDataToWindow()
} }
// Prepare certificate information. // Prepare certificate information.
std::unique_ptr<wxCertificateClientData> data(new wxCertificateClientData(CertDuplicateCertificateContext(cert))); std::unique_ptr<wxCertificateHashClientData> data(new wxCertificateHashClientData);
if (!CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, data->m_cert_hash)) {
// Skip certificates we cannot get thumbprint for.
continue;
}
// Add to list. // Add to list.
bool is_selected = bool is_selected = m_cred.m_cert_hash == data->m_cert_hash;
m_cred.m_cert &&
m_cred.m_cert->cbCertEncoded == data->m_cert->cbCertEncoded &&
memcmp(m_cred.m_cert->pbCertEncoded, data->m_cert->pbCertEncoded, m_cred.m_cert->cbCertEncoded) == 0;
winstd::tstring name(std::move(eap::get_cert_title(cert))); winstd::tstring name(std::move(eap::get_cert_title(cert)));
int i = m_certificate->Append(name, data.release()); int i = m_certificate->Append(name, data.release());
if (is_selected) { if (is_selected) {
@ -99,14 +100,14 @@ bool wxTLSCredentialsPanel::TransferDataFromWindow()
{ {
// Check if m_certificate control has selected item, and has client object data (at least one user certificate on the list). Then try to get the data from selected item. // Check if m_certificate control has selected item, and has client object data (at least one user certificate on the list). Then try to get the data from selected item.
int sel = m_certificate->GetSelection(); int sel = m_certificate->GetSelection();
const wxCertificateClientData *data = const wxCertificateHashClientData *data =
sel != wxNOT_FOUND && m_certificate->HasClientObjectData() ? sel != wxNOT_FOUND && m_certificate->HasClientObjectData() ?
dynamic_cast<const wxCertificateClientData*>(m_certificate->GetClientObject(sel)) : dynamic_cast<const wxCertificateHashClientData*>(m_certificate->GetClientObject(sel)) :
NULL; NULL;
if (data) if (data)
m_cred.m_cert.attach_duplicated(data->m_cert); m_cred.m_cert_hash = data->m_cert_hash;
else else
m_cred.m_cert.free(); m_cred.m_cert_hash.clear();
m_cred.m_identity = m_identity->GetValue(); m_cred.m_identity = m_identity->GetValue();