From 58e65350b0cd9452ddb93ba2ff14b3dbcf80d717 Mon Sep 17 00:00:00 2001 From: Andrey Volk Date: Thu, 27 Dec 2018 03:17:31 +0400 Subject: [PATCH] FS-11582: [mod_signalwire] Fix CA certificate detection on Windows. --- .../applications/mod_signalwire/cacert.cpp | 106 ++++++++++++++++++ .../mod_signalwire.2017.vcxproj | 5 + .../mod_signalwire/mod_signalwire.c | 18 +++ 3 files changed, 129 insertions(+) create mode 100644 src/mod/applications/mod_signalwire/cacert.cpp diff --git a/src/mod/applications/mod_signalwire/cacert.cpp b/src/mod/applications/mod_signalwire/cacert.cpp new file mode 100644 index 0000000000..79f0d6e297 --- /dev/null +++ b/src/mod/applications/mod_signalwire/cacert.cpp @@ -0,0 +1,106 @@ +/* + * cacert.cpp -- CA Certificate for cURL on Windows + * + * Copyright (c) 2018 SignalWire, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifdef WIN32 + +#include +#include +#include + +#include +#include + +std::vector m_trustedCertificateList; + +SWITCH_BEGIN_EXTERN_C + +static void addCertificatesForStore(LPCSTR name) +{ + HCERTSTORE storeHandle = CertOpenSystemStore(NULL, name); + + if (storeHandle == nullptr) { + return; + } + + PCCERT_CONTEXT windowsCertificate = CertEnumCertificatesInStore(storeHandle, nullptr); + + while (windowsCertificate != nullptr) { + X509 *opensslCertificate = d2i_X509(nullptr, const_cast(&windowsCertificate->pbCertEncoded), windowsCertificate->cbCertEncoded); + if (opensslCertificate == nullptr) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "A certificate could not be converted.\n"); + } else { + m_trustedCertificateList.push_back(opensslCertificate); + } + + windowsCertificate = CertEnumCertificatesInStore(storeHandle, windowsCertificate); + } + + CertCloseStore(storeHandle, 0); +} + +static void setupSslContext(SSL_CTX* context) +{ + X509_STORE* certStore = SSL_CTX_get_cert_store(context); + for (X509 *x509 : m_trustedCertificateList) { + X509_STORE_add_cert(certStore, x509); + } +} + +void sslLoadWindowsCACertificate() { + if (m_trustedCertificateList.empty()) { + addCertificatesForStore("CA"); + addCertificatesForStore("AuthRoot"); + addCertificatesForStore("ROOT"); + } +} + +void sslUnLoadWindowsCACertificate() +{ + for (X509 *x509 : m_trustedCertificateList) { + X509_free(x509); + } + + m_trustedCertificateList.clear(); +} + +int sslContextFunction(void* curl, void* sslctx, void* userdata) +{ + setupSslContext(reinterpret_cast(sslctx)); + return CURLE_OK; +} + +SWITCH_END_EXTERN_C + +#endif + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet + */ diff --git a/src/mod/applications/mod_signalwire/mod_signalwire.2017.vcxproj b/src/mod/applications/mod_signalwire/mod_signalwire.2017.vcxproj index 192c82d51d..c620dff061 100644 --- a/src/mod/applications/mod_signalwire/mod_signalwire.2017.vcxproj +++ b/src/mod/applications/mod_signalwire/mod_signalwire.2017.vcxproj @@ -46,6 +46,7 @@ v141 + @@ -77,6 +78,9 @@ + + crypt32.lib;%(AdditionalDependencies) + @@ -135,6 +139,7 @@ + diff --git a/src/mod/applications/mod_signalwire/mod_signalwire.c b/src/mod/applications/mod_signalwire/mod_signalwire.c index 5fd2fe828e..ad2b15b3d3 100644 --- a/src/mod/applications/mod_signalwire/mod_signalwire.c +++ b/src/mod/applications/mod_signalwire/mod_signalwire.c @@ -31,6 +31,12 @@ #include #endif +#ifdef WIN32 +void sslLoadWindowsCACertificate(); +void sslUnLoadWindowsCACertificate(); +int sslContextFunction(void* curl, void* sslctx, void* userdata); +#endif + #define SW_KS_JSON_PRINT(_h, _j) do { \ char *_json = ks_json_print(_j); \ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ALERT, "--- %s ---\n%s\n---\n", _h, _json); \ @@ -356,6 +362,9 @@ static ks_status_t mod_signalwire_adoption_post(void) switch_curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); switch_curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&rd); switch_curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, response_data_handler); +#ifdef WIN32 + curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslContextFunction); +#endif if ((res = switch_curl_easy_perform(curl))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Curl Result %d, Error: %s\n", res, errbuf); @@ -861,6 +870,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_signalwire_load) ks_global_set_logger(mod_signalwire_kslogger); } +#ifdef WIN32 + sslLoadWindowsCACertificate(); +#endif + // Configuration swclt_config_create(&globals.config); load_config(); @@ -967,6 +980,11 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_signalwire_shutdown) // shutdown libblade (but not libks?) swclt_shutdown(); +#ifdef WIN32 + // free certificate pointers previously loaded + sslUnLoadWindowsCACertificate(); +#endif + return SWITCH_STATUS_SUCCESS; }