From 6e97a04bfeeee5b70676bcc3c49d998d4ca4cf44 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Thu, 6 Feb 2020 11:15:34 +0100 Subject: [PATCH] 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 --- lib/TLS/include/Credentials.h | 7 +- lib/TLS/include/Method.h | 3 + lib/TLS/src/Credentials.cpp | 177 ++++++++-------------------------- lib/TLS/src/Method.cpp | 63 +++++++----- lib/TLS_UI/include/TLS_UI.h | 11 +++ lib/TLS_UI/src/TLS_UI.cpp | 21 ++-- 6 files changed, 107 insertions(+), 175 deletions(-) diff --git a/lib/TLS/include/Credentials.h b/lib/TLS/include/Credentials.h index 625b32e..c437885 100644 --- a/lib/TLS/include/Credentials.h +++ b/lib/TLS/include/Credentials.h @@ -142,12 +142,7 @@ namespace eap _In_opt_z_ LPCTSTR pszTargetName); public: - winstd::cert_context m_cert; ///< Client certificate - - private: - /// \cond internal - static const unsigned char s_entropy[1024]; - /// \endcond + std::vector m_cert_hash; ///< Client certificate SHA-1 thumbprint }; /// @} diff --git a/lib/TLS/include/Method.h b/lib/TLS/include/Method.h index 1495179..83f884e 100644 --- a/lib/TLS/include/Method.h +++ b/lib/TLS/include/Method.h @@ -143,6 +143,8 @@ namespace eap _In_ HANDLE hTokenImpersonateUser, _In_opt_ DWORD dwMaxSendPacketSize = MAXDWORD); + virtual void end_session(); + /// @} /// \name Packet processing @@ -192,6 +194,7 @@ namespace eap config_method_tls &m_cfg; ///< Method configuration credentials_tls &m_cred; ///< Method user credentials 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::sec_credentials m_sc_cred; ///< Schannel client credentials std::vector m_sc_queue; ///< TLS data queue diff --git a/lib/TLS/src/Credentials.cpp b/lib/TLS/src/Credentials.cpp index 9a77f6c..80e8ac0 100644 --- a/lib/TLS/src/Credentials.cpp +++ b/lib/TLS/src/Credentials.cpp @@ -34,14 +34,14 @@ eap::credentials_tls::credentials_tls(_In_ module &mod) : credentials(mod) eap::credentials_tls::credentials_tls(_In_ const credentials_tls &other) : - m_cert(other.m_cert), + m_cert_hash(other.m_cert_hash), credentials(other) { } 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)) { } @@ -51,7 +51,7 @@ eap::credentials_tls& eap::credentials_tls::operator=(_In_ const credentials_tls { if (this != &other) { (credentials&)*this = other; - m_cert = other.m_cert; + m_cert_hash = other.m_cert_hash; } return *this; @@ -62,7 +62,7 @@ eap::credentials_tls& eap::credentials_tls::operator=(_Inout_ credentials_tls && { if (this != &other) { (credentials&)*this = std::move(other); - m_cert = std::move(other.m_cert); + m_cert_hash = std::move(other.m_cert_hash); } return *this; @@ -78,13 +78,13 @@ eap::config* eap::credentials_tls::clone() const void eap::credentials_tls::clear() { credentials::clear(); - m_cert.free(); + m_cert_hash.clear(); } 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))) throw com_runtime_error(hr, __FUNCTION__ " Error creating element."); - if (m_cert) { - // / - if (FAILED(hr = eapxml::put_element_value(pDoc, pXmlElClientCertificate, bstr(L"format"), namespace_eapmetadata, bstr(L"PEM")))) - throw com_runtime_error(hr, __FUNCTION__ " Error creating element."); - - // / - 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 element."); + if (!m_cert_hash.empty()) { + // / + 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 element."); } } @@ -123,35 +119,24 @@ void eap::credentials_tls::load(_In_ IXMLDOMNode *pConfigRoot) std::wstring xpath(eapxml::get_xpath(pConfigRoot)); - m_cert.free(); + m_cert_hash.clear(); // com_obj pXmlElClientCertificate; if (FAILED(hr = eapxml::select_element(pConfigRoot, bstr(L"eap-metadata:ClientCertificate"), pXmlElClientCertificate))) throw com_runtime_error(hr, __FUNCTION__ " Error reading element."); - // / - bstr bstrFormat; - 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) { - // / - vector 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()); - } - } + // / + eapxml::get_element_hex(pXmlElClientCertificate, bstr(L"eap-metadata:hash"), m_cert_hash); - if (m_cert) - 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); + m_module.log_config((xpath + L"/ClientCertificateHash").c_str(), m_cert_hash.data(), (ULONG)m_cert_hash.size()); } void eap::credentials_tls::operator<<(_Inout_ cursor_out &cursor) const { credentials::operator<<(cursor); - cursor << m_cert; + cursor << m_cert_hash; } @@ -159,34 +144,24 @@ size_t eap::credentials_tls::get_pk_size() const { return credentials::get_pk_size() + - pksizeof(m_cert); + pksizeof(m_cert_hash); } void eap::credentials_tls::operator>>(_Inout_ cursor_in &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 { 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(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)); // 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 ); CREDENTIAL cred = { 0, // Flags @@ -194,8 +169,8 @@ void eap::credentials_tls::store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int const_cast(target.c_str()), // TargetName _T(""), // Comment { 0, 0 }, // LastWritten - cred_enc.cbData, // CredentialBlobSize - cred_enc.pbData, // CredentialBlob + (DWORD)m_cert_hash.size(), // CredentialBlobSize + (LPBYTE)m_cert_hash.data(), // CredentialBlob CRED_PERSIST_ENTERPRISE, // Persist 0, // AttributeCount 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)) throw win_runtime_error(__FUNCTION__ " CredRead failed."); - if (cred->CredentialBlobSize) { - // Decrypt the certificate using user's key. - DATA_BLOB cred_enc = { cred->CredentialBlobSize, cred->CredentialBlob }; - DATA_BLOB entropy_blob = { sizeof(s_entropy) , const_cast(s_entropy) }; - 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->CredentialBlobSize) + m_cert_hash.assign(cred->CredentialBlob, cred->CredentialBlob + cred->CredentialBlobSize); + else + m_cert_hash.clear(); if (cred->UserName) m_identity = cred->UserName; @@ -238,10 +203,7 @@ void eap::credentials_tls::retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned wstring xpath(pszTargetName); m_module.log_config((xpath + L"/Identity").c_str(), m_identity.c_str()); - if (m_cert) - 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); + m_module.log_config((xpath + L"/CertificateHash").c_str(), m_cert_hash.data(), (ULONG)m_cert_hash.size()); } @@ -255,10 +217,21 @@ std::wstring eap::credentials_tls::get_identity() const { if (!m_identity.empty()) { return m_identity; - } else if (m_cert) { - wstring name; - CertGetNameStringW(m_cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, name); - return name; + } else if (!m_cert_hash.empty()) { + // Find certificate in the store. + winstd::cert_store store; + vector 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; + CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, name); + return name; + } + } + } } return L""; @@ -304,73 +277,3 @@ eap::credentials::source_t eap::credentials_tls::combine( 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 diff --git a/lib/TLS/src/Method.cpp b/lib/TLS/src/Method.cpp index 636c007..0ba94ff 100644 --- a/lib/TLS/src/Method.cpp +++ b/lib/TLS/src/Method.cpp @@ -208,33 +208,44 @@ void eap::method_tls::begin_session( #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. - PCCERT_CONTEXT certs[] = { m_cred.m_cert ? (PCCERT_CONTEXT)m_cred.m_cert : NULL }; + vector certs; + if (!m_cred.empty()) { + vector 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_VERSION, // dwVersion - m_cred.m_cert ? 1ul : 0ul, // cCreds - certs, // paCred - NULL, // hRootStore: Not valid for client credentials - 0, // cMappers - NULL, // aphMappers - 0, // cSupportedAlgs: Use system configured default - NULL, // palgSupportedAlgs: Use system configured default - SP_PROT_TLS1_X_CLIENT | (SP_PROT_TLS1_2_CLIENT<<2), // grbitEnabledProtocols: TLS 1.x - 0, // dwMinimumCipherStrength: Use system configured default - 0, // dwMaximumCipherStrength: Use system configured default - 0, // dwSessionLifespan: Use system configured default = 10hr + SCHANNEL_CRED_VERSION, // dwVersion + (DWORD)certs.size(), // cCreds + certs.data(), // paCred + NULL, // hRootStore: Not valid for client credentials + 0, // cMappers + NULL, // aphMappers + 0, // cSupportedAlgs: Use system configured default + NULL, // palgSupportedAlgs: Use system configured default + SP_PROT_TLS1_X_CLIENT | (SP_PROT_TLS1_2_CLIENT<<2), // grbitEnabledProtocols: TLS 1.x + 0, // dwMinimumCipherStrength: Use system configured default + 0, // dwMaximumCipherStrength: Use system configured default + 0, // dwSessionLifespan: Use system configured default = 10hr #if EAP_TLS >= EAP_TLS_SCHANNEL_FULL - SCH_CRED_AUTO_CRED_VALIDATION | // dwFlags: Let Schannel verify server certificate + SCH_CRED_AUTO_CRED_VALIDATION | // dwFlags: Let Schannel verify server certificate #else - SCH_CRED_MANUAL_CRED_VALIDATION | // dwFlags: Prevent Schannel verify server certificate (we want to use custom root CA store and multiple name checking) + SCH_CRED_MANUAL_CRED_VALIDATION | // dwFlags: Prevent Schannel verify server certificate (we want to use custom root CA store and multiple name checking) #endif - SCH_CRED_CACHE_ONLY_URL_RETRIEVAL_ON_CREATE | // dwFlags: Do not attempt online revocation check - we do not expect to have network connection yet - SCH_CRED_IGNORE_NO_REVOCATION_CHECK | // dwFlags: Ignore no-revocation-check errors - as we cannot check for revocation, it makes little sense to insist certificate has to have revocation set-up - SCH_CRED_IGNORE_REVOCATION_OFFLINE | // dwFlags: Ignore offline-revocation errors - we do not expect to have network connection yet - SCH_CRED_NO_DEFAULT_CREDS | // dwFlags: If client certificate we provided is not acceptable, do not try to select one on your own - (m_cfg.m_server_names.empty() ? SCH_CRED_NO_SERVERNAME_CHECK : 0) | // dwFlags: When no expected server name is given, do not do the server name check. - 0x00400000ul /*SCH_USE_STRONG_CRYPTO*/, // dwFlags: Do not use broken ciphers - 0 // dwCredFormat + SCH_CRED_CACHE_ONLY_URL_RETRIEVAL_ON_CREATE | // dwFlags: Do not attempt online revocation check - we do not expect to have network connection yet + SCH_CRED_IGNORE_NO_REVOCATION_CHECK | // dwFlags: Ignore no-revocation-check errors - as we cannot check for revocation, it makes little sense to insist certificate has to have revocation set-up + SCH_CRED_IGNORE_REVOCATION_OFFLINE | // dwFlags: Ignore offline-revocation errors - we do not expect to have network connection yet + SCH_CRED_NO_DEFAULT_CREDS | // dwFlags: If client certificate we provided is not acceptable, do not try to select one on your own + (m_cfg.m_server_names.empty() ? SCH_CRED_NO_SERVERNAME_CHECK : 0) | // dwFlags: When no expected server name is given, do not do the server name check. + 0x00400000ul /*SCH_USE_STRONG_CRYPTO*/, // dwFlags: Do not use broken ciphers + 0 // dwCredFormat }; SECURITY_STATUS stat = m_sc_cred.acquire(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &cred); if (FAILED(stat)) @@ -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( _In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket, _In_ DWORD dwReceivedPacketSize) diff --git a/lib/TLS_UI/include/TLS_UI.h b/lib/TLS_UI/include/TLS_UI.h index ba1ee56..7743900 100644 --- a/lib/TLS_UI/include/TLS_UI.h +++ b/lib/TLS_UI/include/TLS_UI.h @@ -36,6 +36,7 @@ #include class wxCertificateClientData; +class wxCertificateHashClientData; class wxTLSCredentialsPanel; class wxTLSServerTrustPanel; 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 m_cert_hash; ///< Certificate thumbprint +}; + + /// /// TLS credential panel /// diff --git a/lib/TLS_UI/src/TLS_UI.cpp b/lib/TLS_UI/src/TLS_UI.cpp index 3ce3903..f165ab1 100644 --- a/lib/TLS_UI/src/TLS_UI.cpp +++ b/lib/TLS_UI/src/TLS_UI.cpp @@ -58,7 +58,7 @@ wxTLSCredentialsPanel::wxTLSCredentialsPanel(const eap::config_provider &prov, c bool wxTLSCredentialsPanel::TransferDataToWindow() { // Populate certificate list. - m_certificate->Append(_("(empty)"), (wxCertificateClientData*)NULL); + m_certificate->Append(_("(empty)"), (wxCertificateHashClientData*)NULL); bool is_found = false; 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"))) { @@ -70,13 +70,14 @@ bool wxTLSCredentialsPanel::TransferDataToWindow() } // Prepare certificate information. - std::unique_ptr data(new wxCertificateClientData(CertDuplicateCertificateContext(cert))); + std::unique_ptr 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. - bool is_selected = - 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; + bool is_selected = m_cred.m_cert_hash == data->m_cert_hash; winstd::tstring name(std::move(eap::get_cert_title(cert))); int i = m_certificate->Append(name, data.release()); 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. int sel = m_certificate->GetSelection(); - const wxCertificateClientData *data = + const wxCertificateHashClientData *data = sel != wxNOT_FOUND && m_certificate->HasClientObjectData() ? - dynamic_cast(m_certificate->GetClientObject(sel)) : + dynamic_cast(m_certificate->GetClientObject(sel)) : NULL; if (data) - m_cred.m_cert.attach_duplicated(data->m_cert); + m_cred.m_cert_hash = data->m_cert_hash; else - m_cred.m_cert.free(); + m_cred.m_cert_hash.clear(); m_cred.m_identity = m_identity->GetValue();