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; } diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index c01b27d1f4..d1431a1e57 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -510,6 +510,9 @@ int sofia_glue_transport_has_tls(const sofia_transport_t tp) void sofia_glue_get_addr(msg_t *msg, char *buf, size_t buflen, int *port) { su_addrinfo_t *addrinfo = msg_addrinfo(msg); + if (!addrinfo) { + return; + } if (buf) { get_addr(buf, buflen, addrinfo->ai_addr, (socklen_t)addrinfo->ai_addrlen); diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 39ae6b3b03..c8b358b8a9 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -151,8 +151,10 @@ void sofia_reg_fire_custom_gateway_state_event(sofia_gateway_t *gateway, int sta switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Gateway", gateway->name); switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "State", sofia_state_string(gateway->state)); switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Ping-Status", sofia_gateway_status_name(gateway->status)); - switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Register-Network-IP", gateway->register_network_ip); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "Register-Network-Port", "%d", gateway->register_network_port); + if (!zstr_buf(gateway->register_network_ip)) { + switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Register-Network-IP", gateway->register_network_ip); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "Register-Network-Port", "%d", gateway->register_network_port); + } if (!zstr(phrase)) { switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Phrase", phrase); @@ -2406,13 +2408,17 @@ void sofia_reg_handle_sip_r_register(int status, if (sofia_private && gateway) { reg_state_t ostate = gateway->state; char oregister_network_ip[80] = { 0 }; - char network_ip[80]; + char network_ip[80] = { 0 }; - if (!zstr_buf(gateway->register_network_ip)) { - strncpy(oregister_network_ip, gateway->register_network_ip, sizeof(oregister_network_ip) - 1); + if (de && de->data && de->data->e_msg) { + if (!zstr_buf(gateway->register_network_ip)) { + strncpy(oregister_network_ip, gateway->register_network_ip, sizeof(oregister_network_ip) - 1); + } + sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &gateway->register_network_port); + if (!zstr_buf(network_ip)) { + snprintf(gateway->register_network_ip, sizeof(gateway->register_network_ip), (msg_addrinfo(de->data->e_msg))->ai_addr->sa_family == AF_INET6 ? "[%s]" : "%s", network_ip); + } } - sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &gateway->register_network_port); - snprintf(gateway->register_network_ip, sizeof(gateway->register_network_ip), (msg_addrinfo(de->data->e_msg))->ai_addr->sa_family == AF_INET6 ? "[%s]" : "%s", network_ip); switch (status) { case 200: @@ -2470,8 +2476,8 @@ void sofia_reg_handle_sip_r_register(int status, break; } if (ostate != gateway->state || - zstr_buf(oregister_network_ip) || strcmp(oregister_network_ip, gateway->register_network_ip)) { - + (!zstr_buf(gateway->register_network_ip) && + (zstr_buf(oregister_network_ip) || strcmp(oregister_network_ip, gateway->register_network_ip)))) { sofia_reg_fire_custom_gateway_state_event(gateway, status, phrase); } }