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();