From a1c17a29422aafeaf6748de32c6d65b91f65a2ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com>
Date: Fri, 27 Feb 2015 17:07:44 -0500
Subject: [PATCH] tls: transmit certificate and cipher to client

Refs #66534

Change-Id: I1ae97785690f37ae6a11e1632d25347ddd4115d0
---
 .../dbus/configurationmanager-introspec.xml   | 31 ++++++++++++++
 daemon/bin/dbus/dbusconfigurationmanager.cpp  | 12 ++++++
 daemon/bin/dbus/dbusconfigurationmanager.h    |  3 +-
 daemon/contrib/src/opendht/rules.mak          |  2 +-
 daemon/contrib/src/pjproject/gnutls.patch     | 40 ++++++++++---------
 daemon/contrib/src/pjproject/rules.mak        |  1 +
 daemon/contrib/src/pjproject/tls_cert.patch   | 10 +++++
 daemon/src/call.cpp                           |  8 ++--
 daemon/src/call.h                             |  8 ++--
 daemon/src/client/configurationmanager.cpp    | 34 +++++++++++++++-
 .../dring/configurationmanager_interface.h    |  3 ++
 daemon/src/ringdht/sips_transport_ice.cpp     |  4 ++
 daemon/src/sip/sipcall.cpp                    | 14 +++++++
 daemon/src/sip/sipcall.h                      |  2 +
 daemon/src/sip/siptransport.cpp               | 20 ++++++++++
 daemon/src/sip/siptransport.h                 | 15 +++++++
 daemon/src/sip/tlsvalidator.cpp               | 32 +++++++++++----
 daemon/src/sip/tlsvalidator.h                 |  8 ++--
 18 files changed, 208 insertions(+), 39 deletions(-)
 create mode 100644 daemon/contrib/src/pjproject/tls_cert.patch

diff --git a/daemon/bin/dbus/configurationmanager-introspec.xml b/daemon/bin/dbus/configurationmanager-introspec.xml
index 3c219b4809..1bebf00e83 100644
--- a/daemon/bin/dbus/configurationmanager-introspec.xml
+++ b/daemon/bin/dbus/configurationmanager-introspec.xml
@@ -649,6 +649,22 @@
            </arg>
        </method>
 
+       <method name="validateCertificateRaw" tp:name-for-bindings="validateCertificateRaw">
+           <arg type="s" name="accountId" direction="in"></arg>
+           <arg type="ay" name="certificateRaw" direction="in">
+              <tp:docstring>
+               <p>A certificate path</p>
+              </tp:docstring>
+           </arg>
+           <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringString"/>
+           <arg type="a{ss}" name="details" direction="out">
+              <tp:docstring>
+               <p>A key-value list of all certificate validation</p>
+               The constants used as keys are defined in the "security.h" constants header file
+              </tp:docstring>
+           </arg>
+       </method>
+
        <method name="getCertificateDetails" tp:name-for-bindings="getCertificateDetails">
            <arg type="s" name="certificatePath" direction="in">
               <tp:docstring>
@@ -664,6 +680,21 @@
            </arg>
        </method>
 
+       <method name="getCertificateDetailsRaw" tp:name-for-bindings="getCertificateDetailsRaw">
+           <arg type="ay" name="certificateRaw" direction="in">
+              <tp:docstring>
+               <p>A raw certificate</p>
+              </tp:docstring>
+           </arg>
+           <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringString"/>
+           <arg type="a{ss}" name="details" direction="out">
+              <tp:docstring>
+               <p>A key-value list of all certificate details</p>
+               The constants used as keys are defined in the "security.h" constants header file
+              </tp:docstring>
+           </arg>
+       </method>
+
        <method name="getAddrFromInterfaceName" tp:name-for-bindings="getAddrFromInterfaceName">
            <arg type="s" name="interface" direction="in">
            </arg>
diff --git a/daemon/bin/dbus/dbusconfigurationmanager.cpp b/daemon/bin/dbus/dbusconfigurationmanager.cpp
index 856a0be490..5099912e05 100644
--- a/daemon/bin/dbus/dbusconfigurationmanager.cpp
+++ b/daemon/bin/dbus/dbusconfigurationmanager.cpp
@@ -360,12 +360,24 @@ DBusConfigurationManager::validateCertificate(const std::string& accountId, cons
    return DRing::validateCertificate(accountId, certificate, privateKey);
 }
 
+std::map<std::string, std::string>
+DBusConfigurationManager::validateCertificateRaw(const std::string& accountId, const std::vector<uint8_t>& certificate)
+{
+    return DRing::validateCertificateRaw(accountId, certificate);
+}
+
 auto
 DBusConfigurationManager::getCertificateDetails(const std::string& certificate) -> decltype(DRing::getCertificateDetails(certificate))
 {
     return DRing::getCertificateDetails(certificate);
 }
 
+auto
+DBusConfigurationManager::getCertificateDetailsRaw(const std::vector<uint8_t>& certificate) -> decltype(DRing::getCertificateDetailsRaw(certificate))
+{
+    return DRing::getCertificateDetailsRaw(certificate);
+}
+
 void
 DBusConfigurationManager::setTlsSettings(const std::map<std::string, std::string>& details)
 {
diff --git a/daemon/bin/dbus/dbusconfigurationmanager.h b/daemon/bin/dbus/dbusconfigurationmanager.h
index 18447aa96c..4ebba7a264 100644
--- a/daemon/bin/dbus/dbusconfigurationmanager.h
+++ b/daemon/bin/dbus/dbusconfigurationmanager.h
@@ -128,8 +128,9 @@ class DBusConfigurationManager :
         void setVolume(const std::string& device, const double& value);
         double getVolume(const std::string& device);
         std::map<std::string, std::string> validateCertificate(const std::string& accountId, const std::string& certificate, const std::string& privateKey);
+        std::map<std::string, std::string> validateCertificateRaw(const std::string& accountId, const std::vector<uint8_t>& certificate);
         std::map<std::string, std::string> getCertificateDetails(const std::string& certificate);
-
+        std::map<std::string, std::string> getCertificateDetailsRaw(const std::vector<uint8_t>& certificate);
 };
 
 #endif // __RING_DBUSCONFIGURATIONMANAGER_H__
diff --git a/daemon/contrib/src/opendht/rules.mak b/daemon/contrib/src/opendht/rules.mak
index d3859c0a8c..309d906917 100644
--- a/daemon/contrib/src/opendht/rules.mak
+++ b/daemon/contrib/src/opendht/rules.mak
@@ -1,5 +1,5 @@
 # OPENDHT
-OPENDHT_VERSION := 13902b0f19f702c43bc34e24a8d42db6a8d81a31
+OPENDHT_VERSION := 6e01255bc00da5ea75c6ee48526743ba56d1f8df
 OPENDHT_URL := https://github.com/savoirfairelinux/opendht/archive/$(OPENDHT_VERSION).tar.gz
 
 PKGS += opendht
diff --git a/daemon/contrib/src/pjproject/gnutls.patch b/daemon/contrib/src/pjproject/gnutls.patch
index 62f5ef4b61..2b2903fd6e 100644
--- a/daemon/contrib/src/pjproject/gnutls.patch
+++ b/daemon/contrib/src/pjproject/gnutls.patch
@@ -24,13 +24,13 @@ ssl_sock_gtls: avoid NULL dereference
  pjlib/include/pj/compat/os_auto.h.in |    3 +
  pjlib/include/pj/config.h            |    4 +-
  pjlib/src/pj/ssl_sock_common.c       |    5 +
- pjlib/src/pj/ssl_sock_gtls.c         | 2778 ++++++++++++++++++++++++++++++++++
+ pjlib/src/pj/ssl_sock_gtls.c         | 2782 ++++++++++++++++++++++++++++++++++
  pjlib/src/pj/ssl_sock_ossl.c         |    6 +-
- 8 files changed, 3019 insertions(+), 62 deletions(-)
+ 8 files changed, 3023 insertions(+), 62 deletions(-)
  create mode 100644 pjlib/src/pj/ssl_sock_gtls.c
 
 diff --git a/aconfigure b/aconfigure
-index 24de91d..37e0914 100755
+index a296266..03f727f 100755
 --- a/aconfigure
 +++ b/aconfigure
 @@ -637,6 +637,8 @@ ac_no_opencore_amrnb
@@ -40,9 +40,9 @@ index 24de91d..37e0914 100755
 +libgnutls_present
 +gnutls_h_present
  ac_no_ssl
- ac_openh264_ldflags
- ac_openh264_cflags
-@@ -1462,8 +1464,8 @@ Optional Features:
+ ac_v4l2_ldflags
+ ac_v4l2_cflags
+@@ -1457,8 +1459,8 @@ Optional Features:
                            package and samples location using IPPROOT and
                            IPPSAMPLES env var or with --with-ipp and
                            --with-ipp-samples options
@@ -53,7 +53,7 @@ index 24de91d..37e0914 100755
    --disable-opencore-amr  Exclude OpenCORE AMR support from the build
                            (default: autodetect)
  
-@@ -7482,33 +7484,159 @@ fi
+@@ -7380,33 +7382,159 @@ fi
  
  # Check whether --enable-ssl was given.
  if test "${enable_ssl+set}" = set; then :
@@ -227,7 +227,7 @@ index 24de91d..37e0914 100755
  $as_echo_n "checking for ERR_load_BIO_strings in -lcrypto... " >&6; }
  if ${ac_cv_lib_crypto_ERR_load_BIO_strings+:} false; then :
    $as_echo_n "(cached) " >&6
-@@ -7548,7 +7676,7 @@ if test "x$ac_cv_lib_crypto_ERR_load_BIO_strings" = xyes; then :
+@@ -7446,7 +7574,7 @@ if test "x$ac_cv_lib_crypto_ERR_load_BIO_strings" = xyes; then :
    libcrypto_present=1 && LIBS="$LIBS -lcrypto"
  fi
  
@@ -236,7 +236,7 @@ index 24de91d..37e0914 100755
  $as_echo_n "checking for SSL_library_init in -lssl... " >&6; }
  if ${ac_cv_lib_ssl_SSL_library_init+:} false; then :
    $as_echo_n "(cached) " >&6
-@@ -7588,22 +7716,23 @@ if test "x$ac_cv_lib_ssl_SSL_library_init" = xyes; then :
+@@ -7486,22 +7614,23 @@ if test "x$ac_cv_lib_ssl_SSL_library_init" = xyes; then :
    libssl_present=1 && LIBS="$LIBS -lssl"
  fi
  
@@ -271,10 +271,10 @@ index 24de91d..37e0914 100755
  if test "${with_opencore_amrnb+set}" = set; then :
    withval=$with_opencore_amrnb; as_fn_error $? "This option is obsolete and replaced by --with-opencore-amr=DIR" "$LINENO" 5
 diff --git a/aconfigure.ac b/aconfigure.ac
-index 6c35836..3be55c5 100644
+index cd71a7a..465285e 100644
 --- a/aconfigure.ac
 +++ b/aconfigure.ac
-@@ -1418,38 +1418,76 @@ fi
+@@ -1346,38 +1346,76 @@ fi
  
  dnl # Include SSL support
  AC_SUBST(ac_no_ssl)
@@ -383,7 +383,7 @@ index 6c35836..3be55c5 100644
  dnl # Obsolete option --with-opencore-amrnb
  AC_ARG_WITH(opencore-amrnb,
 diff --git a/pjlib/build/Makefile b/pjlib/build/Makefile
-index 1e64950..e650a31 100644
+index a75fa65..529e0ff 100644
 --- a/pjlib/build/Makefile
 +++ b/pjlib/build/Makefile
 @@ -35,7 +35,7 @@ export PJLIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
@@ -396,7 +396,7 @@ index 1e64950..e650a31 100644
  export PJLIB_CFLAGS += $(_CFLAGS)
  export PJLIB_CXXFLAGS += $(_CXXFLAGS)
 diff --git a/pjlib/include/pj/compat/os_auto.h.in b/pjlib/include/pj/compat/os_auto.h.in
-index 77980d3..6d6a625 100644
+index 18df2bf..9295740 100644
 --- a/pjlib/include/pj/compat/os_auto.h.in
 +++ b/pjlib/include/pj/compat/os_auto.h.in
 @@ -206,6 +206,9 @@
@@ -410,7 +410,7 @@ index 77980d3..6d6a625 100644
  
  #endif	/* __PJ_COMPAT_OS_AUTO_H__ */
 diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
-index c191ef1..4ace1bc 100644
+index 31020a3..90aefe2 100644
 --- a/pjlib/include/pj/config.h
 +++ b/pjlib/include/pj/config.h
 @@ -854,13 +854,15 @@
@@ -431,7 +431,7 @@ index c191ef1..4ace1bc 100644
  
  
 diff --git a/pjlib/src/pj/ssl_sock_common.c b/pjlib/src/pj/ssl_sock_common.c
-index 67a8d63..602a1af 100644
+index 768a640..b116f1b 100644
 --- a/pjlib/src/pj/ssl_sock_common.c
 +++ b/pjlib/src/pj/ssl_sock_common.c
 @@ -34,7 +34,12 @@ PJ_DEF(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param)
@@ -449,10 +449,10 @@ index 67a8d63..602a1af 100644
  #endif
 diff --git a/pjlib/src/pj/ssl_sock_gtls.c b/pjlib/src/pj/ssl_sock_gtls.c
 new file mode 100644
-index 0000000..c2a4349
+index 0000000..7b4b941
 --- /dev/null
 +++ b/pjlib/src/pj/ssl_sock_gtls.c
-@@ -0,0 +1,2778 @@
+@@ -0,0 +1,2782 @@
 +/* $Id$ */
 +/*
 + * Copyright (C) 2014 Savoir-Faire Linux. (http://www.savoirfairelinux.com)
@@ -1594,6 +1594,8 @@ index 0000000..c2a4349
 +        goto us_out;
 +
 +    tls_cert_get_info(ssock->pool, &ssock->local_cert_info, cert);
++    const pj_str_t local_crt_raw = {(char*)us->data, (pj_ssize_t)us->size};
++    pj_strdup(ssock->pool, &ssock->local_cert_info.cert_raw, &local_crt_raw);
 +
 +us_out:
 +    tls_last_error = ret;
@@ -1620,6 +1622,8 @@ index 0000000..c2a4349
 +        goto peer_out;
 +
 +    tls_cert_get_info(ssock->pool, &ssock->remote_cert_info, cert);
++    const pj_str_t remote_crt_raw = {(char*)certs->data, (pj_ssize_t)certs->size};
++    pj_strdup(ssock->pool, &ssock->remote_cert_info.cert_raw, &remote_crt_raw);
 +
 +peer_out:
 +    tls_last_error = ret;
@@ -3232,7 +3236,7 @@ index 0000000..c2a4349
 +
 +#endif /* PJ_HAS_SSL_SOCK */
 diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
-index 7c7b6d0..e466bb7 100644
+index ba4ae0b..98bbfee 100644
 --- a/pjlib/src/pj/ssl_sock_ossl.c
 +++ b/pjlib/src/pj/ssl_sock_ossl.c
 @@ -31,8 +31,10 @@
diff --git a/daemon/contrib/src/pjproject/rules.mak b/daemon/contrib/src/pjproject/rules.mak
index 829bf3fac3..ce28d89aad 100644
--- a/daemon/contrib/src/pjproject/rules.mak
+++ b/daemon/contrib/src/pjproject/rules.mak
@@ -53,6 +53,7 @@ endif
 	$(APPLY) $(SRC)/pjproject/aconfigureupdate.patch
 	$(APPLY) $(SRC)/pjproject/endianness.patch
 	$(APPLY) $(SRC)/pjproject/unknowncipher.patch
+	$(APPLY) $(SRC)/pjproject/tls_cert.patch
 	$(APPLY) $(SRC)/pjproject/gnutls.patch
 	$(APPLY) $(SRC)/pjproject/notestsapps.patch
 	$(APPLY) $(SRC)/pjproject/ipv6.patch
diff --git a/daemon/contrib/src/pjproject/tls_cert.patch b/daemon/contrib/src/pjproject/tls_cert.patch
new file mode 100644
index 0000000000..f030b42319
--- /dev/null
+++ b/daemon/contrib/src/pjproject/tls_cert.patch
@@ -0,0 +1,10 @@
+--- a/pjlib/include/pj/ssl_sock.h
++++ b/pjlib/include/pj/ssl_sock.h
+@@ -181,6 +181,8 @@ typedef struct pj_ssl_cert_info {
+     } subj_alt_name;               /**< Subject alternative
+                                         name extension         */
+ 
++    pj_str_t cert_raw;
++
+ } pj_ssl_cert_info;
+
diff --git a/daemon/src/call.cpp b/daemon/src/call.cpp
index 769fc662d2..0873fe8ef4 100644
--- a/daemon/src/call.cpp
+++ b/daemon/src/call.cpp
@@ -80,7 +80,7 @@ Call::setConnectionState(ConnectionState state)
 }
 
 Call::ConnectionState
-Call::getConnectionState()
+Call::getConnectionState() const
 {
     std::lock_guard<std::mutex> lock(callMutex_);
     return connectionState_;
@@ -137,14 +137,14 @@ Call::setState(CallState state)
 }
 
 Call::CallState
-Call::getState()
+Call::getState() const
 {
     std::lock_guard<std::mutex> lock(callMutex_);
     return callState_;
 }
 
 std::string
-Call::getStateStr()
+Call::getStateStr() const
 {
     switch (getState()) {
         case ACTIVE:
@@ -238,7 +238,7 @@ std::string Call::getTypeStr() const
 }
 
 std::map<std::string, std::string>
-Call::getDetails()
+Call::getDetails() const
 {
     return {
         {DRing::Call::Details::CALL_TYPE,        ring::to_string(type_)},
diff --git a/daemon/src/call.h b/daemon/src/call.h
index faa3a68886..31963a5cd3 100644
--- a/daemon/src/call.h
+++ b/daemon/src/call.h
@@ -167,7 +167,7 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> {
          * Get the connection state of the call (protected by mutex)
          * @return ConnectionState The connection state
          */
-        ConnectionState getConnectionState();
+        ConnectionState getConnectionState() const;
 
         /**
          * Set the state of the call (protected by mutex)
@@ -180,9 +180,9 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> {
          * Get the call state of the call (protected by mutex)
          * @return CallState  The call state
          */
-        CallState getState();
+        CallState getState() const;
 
-        std::string getStateStr();
+        std::string getStateStr() const;
 
         void setIPToIP(bool IPToIP) {
             isIPToIP_ = IPToIP;
@@ -231,7 +231,7 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> {
         unsigned int getLocalVideoPort() const;
 
         void time_stop();
-        virtual std::map<std::string, std::string> getDetails();
+        virtual std::map<std::string, std::string> getDetails() const;
         static std::map<std::string, std::string> getNullDetails();
 
         virtual bool toggleRecording();
diff --git a/daemon/src/client/configurationmanager.cpp b/daemon/src/client/configurationmanager.cpp
index 2126bb3f4a..beb916b888 100644
--- a/daemon/src/client/configurationmanager.cpp
+++ b/daemon/src/client/configurationmanager.cpp
@@ -168,6 +168,23 @@ validateCertificate(const std::string&,
 #endif
 }
 
+std::map<std::string, std::string>
+validateCertificateRaw(const std::string&,
+                    const std::vector<uint8_t>& certificate_raw)
+{
+#if HAVE_TLS && HAVE_DHT
+    try {
+        return TlsValidator{certificate_raw}.getSerializedChecks();
+    } catch(const std::runtime_error& e) {
+        RING_WARN("Certificate loading failed");
+        return {{Certificate::ChecksNames::EXIST, Certificate::CheckValuesNames::FAILED}};
+    }
+#else
+    RING_WARN("TLS not supported");
+    return {};
+#endif
+}
+
 std::map<std::string, std::string>
 getCertificateDetails(const std::string& certificate)
 {
@@ -180,7 +197,22 @@ getCertificateDetails(const std::string& certificate)
 #else
     RING_WARN("TLS not supported");
 #endif
-    return std::map<std::string, std::string>();
+    return {};
+}
+
+std::map<std::string, std::string>
+getCertificateDetailsRaw(const std::vector<uint8_t>& certificate_raw)
+{
+#if HAVE_TLS && HAVE_DHT
+    try {
+        return TlsValidator{certificate_raw}.getSerializedDetails();
+    } catch(const std::runtime_error& e) {
+        RING_WARN("Certificate loading failed");
+    }
+#else
+    RING_WARN("TLS not supported");
+#endif
+    return {};
 }
 
 void
diff --git a/daemon/src/dring/configurationmanager_interface.h b/daemon/src/dring/configurationmanager_interface.h
index 9ef4a02625..280a473082 100644
--- a/daemon/src/dring/configurationmanager_interface.h
+++ b/daemon/src/dring/configurationmanager_interface.h
@@ -169,7 +169,10 @@ double getVolume(const std::string& device);
  */
 std::map<std::string, std::string> validateCertificate(const std::string& accountId,
     const std::string& certificate, const std::string& privateKey);
+std::map<std::string, std::string> validateCertificateRaw(const std::string& accountId,
+    const std::vector<uint8_t>& certificate);
 std::map<std::string, std::string> getCertificateDetails(const std::string& certificate);
+std::map<std::string, std::string> getCertificateDetailsRaw(const std::vector<uint8_t>& certificate);
 
 } // namespace DRing
 
diff --git a/daemon/src/ringdht/sips_transport_ice.cpp b/daemon/src/ringdht/sips_transport_ice.cpp
index ba66dc5fb0..4de5b2f868 100644
--- a/daemon/src/ringdht/sips_transport_ice.cpp
+++ b/daemon/src/ringdht/sips_transport_ice.cpp
@@ -389,6 +389,10 @@ SipsIceTransport::certGetInfo(pj_pool_t *pool, pj_ssl_cert_info *ci, const gnutl
     /* Update cert info */
     pj_bzero(ci, sizeof(pj_ssl_cert_info));
 
+    /* Full raw certificate */
+    const pj_str_t raw_crt_pjstr {(char*)crt_raw.data, crt_raw.size};
+    pj_strdup(pool, &ci->cert_raw, &raw_crt_pjstr);
+
     /* Version */
     ci->version = gnutls_x509_crt_get_version(crt.cert);
 
diff --git a/daemon/src/sip/sipcall.cpp b/daemon/src/sip/sipcall.cpp
index 1a55a5e4b8..5c98c74bc3 100644
--- a/daemon/src/sip/sipcall.cpp
+++ b/daemon/src/sip/sipcall.cpp
@@ -52,6 +52,8 @@
 #include "im/instant_messaging.h"
 #endif
 
+#include "dring/call_const.h"
+
 #ifdef RING_VIDEO
 #include "client/videomanager.h"
 #include "video/video_rtp_session.h"
@@ -869,6 +871,18 @@ SIPCall::openPortsUPnP()
     }
 }
 
+std::map<std::string, std::string>
+SIPCall::getDetails() const
+{
+    auto details = Call::getDetails();
+    if (transport_ and transport_->isSecure()) {
+        const auto& tlsInfos = transport_->getTlsInfos();
+        details.emplace(DRing::Call::Details::TLS_PEER_CERT,    tlsInfos.peerCert.toString());
+        details.emplace(DRing::Call::Details::TLS_CIPHER,       pj_ssl_cipher_name(tlsInfos.cipher));
+    }
+    return details;
+}
+
 void
 SIPCall::setSecure(bool sec)
 {
diff --git a/daemon/src/sip/sipcall.h b/daemon/src/sip/sipcall.h
index a3499dd243..92fb964aaf 100644
--- a/daemon/src/sip/sipcall.h
+++ b/daemon/src/sip/sipcall.h
@@ -193,6 +193,8 @@ class SIPCall : public Call
 
         void openPortsUPnP();
 
+        virtual std::map<std::string, std::string> getDetails() const;
+
     private:
         NON_COPYABLE(SIPCall);
 
diff --git a/daemon/src/sip/siptransport.cpp b/daemon/src/sip/siptransport.cpp
index 36aa772fe5..7b0fe75a70 100644
--- a/daemon/src/sip/siptransport.cpp
+++ b/daemon/src/sip/siptransport.cpp
@@ -45,6 +45,7 @@
 #include <pjsip/sip_types.h>
 #if HAVE_TLS
 #include <pjsip/sip_transport_tls.h>
+#include <pj/ssl_sock.h>
 #endif
 #include <pjnath.h>
 #include <pjnath/stun_config.h>
@@ -131,6 +132,25 @@ void
 SipTransport::stateCallback(pjsip_transport_state state,
                             const pjsip_transport_state_info *info)
 {
+#if HAVE_TLS
+    auto extInfo = static_cast<const pjsip_tls_state_info*>(info->ext_info);
+    if (isSecure() && extInfo && extInfo->ssl_sock_info && extInfo->ssl_sock_info->established) {
+        auto tlsInfo = extInfo->ssl_sock_info;
+        tlsInfos_.proto = tlsInfo->proto;
+        tlsInfos_.cipher = tlsInfo->cipher;
+        tlsInfos_.verifyStatus = (pj_ssl_cert_verify_flag_t)tlsInfo->verify_status;
+        const auto& peer_crt = tlsInfo->remote_cert_info->cert_raw;
+        if (peer_crt.ptr && peer_crt.slen)
+            tlsInfos_.peerCert = {std::vector<uint8_t>(peer_crt.ptr, peer_crt.ptr + peer_crt.slen)};
+        else
+            tlsInfos_.peerCert = {};
+    } else {
+        tlsInfos_.proto = PJ_SSL_SOCK_PROTO_DEFAULT;
+        tlsInfos_.cipher = PJ_TLS_UNKNOWN_CIPHER;
+        tlsInfos_.peerCert = {};
+    }
+#endif
+
     std::vector<SipTransportStateCallback> cbs;
     {
         std::lock_guard<std::mutex> lock(stateListenersMutex_);
diff --git a/daemon/src/sip/siptransport.h b/daemon/src/sip/siptransport.h
index 64232882c1..e79c6f706d 100644
--- a/daemon/src/sip/siptransport.h
+++ b/daemon/src/sip/siptransport.h
@@ -39,6 +39,8 @@
 #include "noncopyable.h"
 #include "logger.h"
 
+#include <opendht/crypto.h>
+
 #include <pjsip.h>
 #include <pjnath/stun_config.h>
 
@@ -103,6 +105,13 @@ private:
     pjsip_tpfactory* listener {nullptr};
 };
 
+struct TlsInfos {
+    pj_ssl_cipher cipher;
+    pj_ssl_sock_proto proto;
+    pj_ssl_cert_verify_flag_t verifyStatus;
+    dht::crypto::Certificate peerCert;
+};
+
 using SipTransportStateCallback = std::function<void(pjsip_transport_state, const pjsip_transport_state_info*)>;
 
 /**
@@ -131,6 +140,10 @@ class SipTransport
             return PJSIP_TRANSPORT_IS_SECURE(transport_);
         }
 
+        const TlsInfos& getTlsInfos() const {
+            return tlsInfos_;
+        }
+
         static bool isAlive(const std::shared_ptr<SipTransport>&, pjsip_transport_state state);
 
     private:
@@ -142,6 +155,8 @@ class SipTransport
         std::shared_ptr<TlsListener> tlsListener_;
         std::map<uintptr_t, SipTransportStateCallback> stateListeners_;
         std::mutex stateListenersMutex_;
+
+        TlsInfos tlsInfos_;
 };
 
 class IpAddr;
diff --git a/daemon/src/sip/tlsvalidator.cpp b/daemon/src/sip/tlsvalidator.cpp
index de0adce39c..5bfda9e7a3 100644
--- a/daemon/src/sip/tlsvalidator.cpp
+++ b/daemon/src/sip/tlsvalidator.cpp
@@ -212,8 +212,9 @@ const Matrix2D<TlsValidator::CheckValuesType , TlsValidator::CheckValues , bool>
 
 
 TlsValidator::TlsValidator(const std::string& certificate, const std::string& privatekey) :
-certificatePath_(certificate), privateKeyPath_(privatekey), certificateFound_(false), caCert_(nullptr),
-caChecked_(false)
+    certificatePath_(certificate),
+    privateKeyPath_(privatekey),
+    certificateFound_(false)
 {
     int err = gnutls_global_init();
     if (err != GNUTLS_E_SUCCESS)
@@ -236,6 +237,22 @@ caChecked_(false)
     }
 }
 
+TlsValidator::TlsValidator(const std::vector<uint8_t>& certificate_raw) :
+    certificateFound_(true)
+{
+    int err = gnutls_global_init();
+    if (err != GNUTLS_E_SUCCESS)
+        throw TlsValidatorException(gnutls_strerror(err));
+
+    try {
+        x509crt_ = {certificate_raw};
+        certificateContent_ = x509crt_.getPacked();
+        certificateFound_ = true;
+    } catch (const std::exception& e) {
+        throw TlsValidatorException("Can't load certificate");
+    }
+}
+
 TlsValidator::~TlsValidator()
 {
     gnutls_global_deinit();
@@ -367,11 +384,12 @@ static TlsValidator::CheckResult checkError(int err, char* copy_buffer, size_t s
  * ASCII-hexadecimal representation before being sent to DBus as it will cause the
  * process to assert
  */
-static std::string binaryToHex(const char* input, size_t input_sz)
+static std::string binaryToHex(const uint8_t* input, size_t input_sz)
 {
     std::ostringstream ret;
+    ret << std::hex;
     for (size_t i=0; i<input_sz; i++)
-        ret << std::hex << std::setfill('0') << std::setw(2) << std::uppercase << (unsigned)input[i];
+        ret << std::setfill('0') << std::setw(2) << (unsigned)input[i];
     return ret.str();
 }
 
@@ -394,7 +412,7 @@ static TlsValidator::CheckResult formatDate(const time_t time)
 static TlsValidator::CheckResult checkBinaryError(int err, char* copy_buffer, size_t resultSize)
 {
     if (err == GNUTLS_E_SUCCESS)
-        return TlsValidator::CheckResult(TlsValidator::CheckValues::CUSTOM, binaryToHex(copy_buffer, resultSize));
+        return TlsValidator::CheckResult(TlsValidator::CheckValues::CUSTOM, binaryToHex(reinterpret_cast<uint8_t*>(copy_buffer), resultSize));
     else
         return TlsValidator::CheckResult(TlsValidator::CheckValues::UNSUPPORTED, "");
 }
@@ -970,7 +988,7 @@ TlsValidator::CheckResult TlsValidator::getSerialNumber()
 // gnutls_x509_crt_get_authority_key_gn_serial
     size_t resultSize = sizeof(copy_buffer);
     int err = gnutls_x509_crt_get_serial(x509crt_.cert, copy_buffer, &resultSize);
-    return checkError(err, copy_buffer, resultSize);
+    return checkBinaryError(err, copy_buffer, resultSize);
 }
 
 /**
@@ -1080,8 +1098,8 @@ TlsValidator::CheckResult TlsValidator::getSha1Fingerprint()
  */
 TlsValidator::CheckResult TlsValidator::getPublicKeyId()
 {
-    size_t resultSize = sizeof(copy_buffer);
     static unsigned char unsigned_copy_buffer[4096];
+    size_t resultSize = sizeof(unsigned_copy_buffer);
     int err = gnutls_x509_crt_get_key_id(x509crt_.cert,0,unsigned_copy_buffer,&resultSize);
 
     // TODO check for GNUTLS_E_SHORT_MEMORY_BUFFER and increase the buffer size
diff --git a/daemon/src/sip/tlsvalidator.h b/daemon/src/sip/tlsvalidator.h
index dca99d0caa..123be98479 100644
--- a/daemon/src/sip/tlsvalidator.h
+++ b/daemon/src/sip/tlsvalidator.h
@@ -143,6 +143,8 @@ public:
     TlsValidator(const std::string& certificate,
                  const std::string& privatekey = "");
 
+    TlsValidator(const std::vector<uint8_t>& certificate_raw);
+
     ~TlsValidator();
 
     bool hasCa() const;
@@ -233,9 +235,9 @@ private:
     dht::crypto::Certificate x509crt_;
 
     bool certificateFound_;
-    bool privateKeyFound_;
-    TlsValidator* caCert_;
-    bool caChecked_;
+    bool privateKeyFound_ {false};
+    TlsValidator* caCert_ {nullptr};
+    bool caChecked_ {false};
     unsigned int caValidationOutput_;
 
     mutable char copy_buffer[4096];
-- 
GitLab