From 8ebf9a3505ee6d2ffa6c9d0cd2892cf36d314982 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 1 Apr 2018 21:29:12 +0200 Subject: [PATCH] Add new property in [sip] section called "tls_certificate_subject_regexp" providing a regexp to match with TLS certificate subjects: subjectAltNames.DNS subjectAltNames.URI and CN. If nothing is matched the TLS connection is rejected. --- coreapi/linphonecore.c | 37 ++++++++++++++++++++++++++++++++-- src/c-wrapper/internal/c-sal.h | 1 + src/sal/sal.cpp | 6 ++++++ src/sal/sal.h | 4 +++- tester/register_tester.c | 31 ++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7247c5a24..bf14e10a3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -42,8 +42,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include -#include -#include +#include "bctoolbox/defs.h" +#include "bctoolbox/regex.h" +#include "belr/grammarbuilder.h" #include "mediastreamer2/dtmfgen.h" #include "mediastreamer2/mediastream.h" @@ -53,6 +54,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mediastreamer2/msjpegwriter.h" #include "mediastreamer2/msogl.h" #include "mediastreamer2/msvolume.h" + #include "bctoolbox/charconv.h" #include "chat/chat-room/client-group-chat-room-p.h" @@ -69,6 +71,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "address/address-p.h" #include "c-wrapper/c-wrapper.h" + #ifdef INET6 #ifndef _WIN32 #include @@ -1274,6 +1277,34 @@ static void sound_config_read(LinphoneCore *lc) _linphone_core_set_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL); } +static int _linphone_core_tls_postcheck_callback(void *data, const bctbx_x509_certificate_t *peer_cert){ + LinphoneCore *lc = (LinphoneCore *) data; + const char *tls_certificate_subject_regexp = lp_config_get_string(lc->config,"sip","tls_certificate_subject_regexp", NULL); + int ret = 0; + if (tls_certificate_subject_regexp){ + ret = -1; + /*the purpose of this handling is to a peer certificate for which there is no single subject matching the regexp given + * in the "tls_certificate_subject_regexp" property. + */ + bctbx_list_t *subjects = bctbx_x509_certificate_get_subjects(peer_cert); + bctbx_list_t *elem; + for(elem = subjects; elem != NULL; elem = elem->next){ + const char *subject = (const char *)elem->data; + ms_message("_linphone_core_tls_postcheck_callback: subject=%s", subject); + if (bctbx_is_matching_regex(subject, tls_certificate_subject_regexp)){ + ret = 0; + ms_message("_linphone_core_tls_postcheck_callback(): successful by matching '%s'", subject); + break; + } + } + bctbx_list_free_with_data(subjects, bctbx_free); + } + if (ret == -1){ + ms_message("_linphone_core_tls_postcheck_callback(): postcheck failed, nothing matched."); + } + return ret; +} + static void certificates_config_read(LinphoneCore *lc) { LinphoneFactory *factory = linphone_factory_get(); const char *data_dir = linphone_factory_get_data_resources_dir(factory); @@ -1295,6 +1326,8 @@ static void certificates_config_read(LinphoneCore *lc) { linphone_core_verify_server_certificates(lc, !!lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); linphone_core_verify_server_cn(lc, !!lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); bctbx_free(root_ca_path); + + lc->sal->setTlsPostcheckCallback(_linphone_core_tls_postcheck_callback, lc); } static void sip_config_read(LinphoneCore *lc) { diff --git a/src/c-wrapper/internal/c-sal.h b/src/c-wrapper/internal/c-sal.h index c7bd15ef6..77cd79a01 100644 --- a/src/c-wrapper/internal/c-sal.h +++ b/src/c-wrapper/internal/c-sal.h @@ -33,6 +33,7 @@ #include "mediastreamer2/mediastream.h" #include "ortp/rtpsession.h" #include "belle-sip/belle-sip.h" +#include "bctoolbox/crypto.h" #ifndef LINPHONE_PUBLIC #if defined(_MSC_VER) diff --git a/src/sal/sal.cpp b/src/sal/sal.cpp index 71c2e169e..193588ca4 100644 --- a/src/sal/sal.cpp +++ b/src/sal/sal.cpp @@ -469,6 +469,7 @@ void Sal::setTlsProperties(){ if (!mRootCaData.empty()) belle_tls_crypto_config_set_root_ca_data(crypto_config, mRootCaData.c_str()); if (mSslConfig != NULL) belle_tls_crypto_config_set_ssl_config(crypto_config, mSslConfig); + if (mTlsPostcheckCb) belle_tls_crypto_config_set_postcheck_callback(crypto_config, mTlsPostcheckCb, mTlsPostcheckCbData); belle_sip_tls_listening_point_set_crypto_config(tlp, crypto_config); belle_sip_object_unref(crypto_config); } @@ -707,6 +708,11 @@ void Sal::setSslConfig(void *ssl_config) { setTlsProperties(); } +void Sal::setTlsPostcheckCallback(int (*cb)(void *, const bctbx_x509_certificate_t *), void *data){ + mTlsPostcheckCb = cb; + mTlsPostcheckCbData = data; +} + int Sal::createUuid(char *uuid, size_t len) { if (generateUuid(uuid, len) == 0) { setUuid(uuid); diff --git a/src/sal/sal.h b/src/sal/sal.h index 082929f1b..1de178d5f 100644 --- a/src/sal/sal.h +++ b/src/sal/sal.h @@ -224,7 +224,7 @@ public: void verifyServerCertificates (bool value); void verifyServerCn (bool value); - + void setTlsPostcheckCallback(int (*cb)(void *, const bctbx_x509_certificate_t *), void *data); // --------------------------------------------------------------------------- // DNS resolution @@ -317,6 +317,8 @@ private: void *mSslConfig = nullptr; std::vector mSupportedContentTypes; std::string mLinphoneSpecs; + belle_tls_crypto_config_postcheck_callback_t mTlsPostcheckCb; + void *mTlsPostcheckCbData; // Cache values mutable std::string mDnsUserHostsFile; diff --git a/tester/register_tester.c b/tester/register_tester.c index e69ec1937..9865b5845 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -999,6 +999,36 @@ static void tls_certificate_failure(void){ } } +static void tls_certificate_subject_check(void){ + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* lcm; + LinphoneCore *lc; + char *rootcapath = bc_tester_res("certificates/cn/cafile.pem"); + lcm=linphone_core_manager_new2("pauline_alt_rc",FALSE); + lc=lcm->lc; + linphone_core_set_root_ca(lc, rootcapath); + /*let's search for a subject that is not in the certificate, it should fail*/ + lp_config_set_string(linphone_core_get_config(lc), "sip", "tls_certificate_subject_regexp", "cotcotcot.org"); + linphone_core_set_network_reachable(lc,TRUE); + BC_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&lcm->stat.number_of_LinphoneRegistrationFailed,1)); + + /*let's search for a subject (in subjectAltNames and CN) that exist in the certificate, it should pass*/ + lp_config_set_string(linphone_core_get_config(lc), "sip", "tls_certificate_subject_regexp", "altname.linphone.org"); + linphone_core_refresh_registers(lcm->lc); + BC_ASSERT_TRUE(wait_for(lc,lc,&lcm->stat.number_of_LinphoneRegistrationOk,1)); + linphone_core_set_network_reachable(lc,FALSE); + + /*let's search for a subject (in subjectAltNames and CN) that exist in the certificate, it should pass*/ + lp_config_set_string(linphone_core_get_config(lc), "sip", "tls_certificate_subject_regexp", "Jehan Monnier"); + linphone_core_set_network_reachable(lc,TRUE); + BC_ASSERT_TRUE(wait_for(lc,lc,&lcm->stat.number_of_LinphoneRegistrationOk,2)); + + BC_ASSERT_EQUAL(lcm->stat.number_of_LinphoneRegistrationFailed,1, int, "%d"); + linphone_core_manager_destroy(lcm); + bc_free(rootcapath); + } +} + char *read_file(const char *path) { long numbytes = 0; size_t readbytes; @@ -1331,6 +1361,7 @@ test_t register_tests[] = { TEST_NO_TAG("TLS register with alt. name certificate", tls_alt_name_register), TEST_NO_TAG("TLS register with wildcard certificate", tls_wildcard_register), TEST_NO_TAG("TLS certificate not verified",tls_certificate_failure), + TEST_NO_TAG("TLS certificate subjects check",tls_certificate_subject_check), TEST_NO_TAG("TLS certificate given by string instead of file",tls_certificate_data), TEST_NO_TAG("TLS with non tls server",tls_with_non_tls_server), TEST_NO_TAG("Simple authenticated register", simple_authenticated_register),