connectionmanager: fix certificate pinning and factory lifecycle

1. findCertificate must pin certificate in certificate store
in order to re-use it afterwards.
2. Pass IceTransportFactory in config, else it will be destroyed
before all ICE Transport are closed.

Change-Id: I86398df9e0f26309719ef46989b422cc4b1b7732
diff --git a/include/connectionmanager.h b/include/connectionmanager.h
index e6ad37b..e459eb3 100644
--- a/include/connectionmanager.h
+++ b/include/connectionmanager.h
@@ -18,6 +18,7 @@
 
 #include "ice_options.h"
 #include "multiplexed_socket.h"
+#include "ice_transport_factory.h"
 #include "turn_cache.h"
 
 #include <opendht/dhtrunner.h>
@@ -248,6 +249,8 @@
 
     tls::CertificateStore* certStore;
 
+    dhtnet::IceTransportFactory* factory;
+
     /**
      * UPnP IGD controller and the mutex to access it
      */
diff --git a/src/connectionmanager.cpp b/src/connectionmanager.cpp
index f58910f..928d209 100644
--- a/src/connectionmanager.cpp
+++ b/src/connectionmanager.cpp
@@ -16,7 +16,6 @@
  */
 #include "connectionmanager.h"
 #include "peer_connection.h"
-#include "ice_transport_factory.h"
 #include "upnp/upnp_control.h"
 #include "certstore.h"
 #include "fileutils.h"
@@ -246,6 +245,7 @@
 
     bool findCertificate(const dht::PkId& id,
                          std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb);
+    bool findCertificate(const dht::InfoHash& h, std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb);
 
     /**
      * returns whether or not UPnP is enabled and active
@@ -267,8 +267,6 @@
 
     std::shared_ptr<ConnectionManager::Config> config_;
 
-    IceTransportFactory iceFactory_ {};
-
     mutable std::mt19937_64 rand;
 
     iOSConnectedCallback iOSConnectedCb_ {};
@@ -758,7 +756,7 @@
             ice_config.master = false;
             ice_config.streamsCount = 1;
             ice_config.compCountPerStream = 1;
-            info->ice_ = sthis->iceFactory_.createUTransport("");
+            info->ice_ = sthis->config_->factory->createUTransport("");
             if (!info->ice_) {
                 if (sthis->config_->logger)
                     sthis->config_->logger->error("[device {}] Cannot initialize ICE session.", deviceId);
@@ -868,7 +866,7 @@
                 shared->onPeerResponse(req);
             } else {
                 // Async certificate checking
-                shared->dht()->findCertificate(
+                shared->findCertificate(
                     req.from,
                     [w, req = std::move(req)](
                         const std::shared_ptr<dht::crypto::Certificate>& cert) mutable {
@@ -1157,7 +1155,7 @@
         ice_config.streamsCount = 1;
         ice_config.compCountPerStream = 1; // TCP
         ice_config.master = true;
-        info->ice_ = shared->iceFactory_.createUTransport("");
+        info->ice_ = shared->config_->factory->createUTransport("");
         if (not info->ice_) {
             if (shared->config_->logger)
                 shared->config_->logger->error("[device {}] Cannot initialize ICE session", deviceId);
@@ -1403,7 +1401,7 @@
 ConnectionManager::Impl::getIceOptions() const noexcept
 {
     IceTransportOptions opts;
-    opts.factory = (IceTransportFactory*)&iceFactory_;
+    opts.factory = config_->factory;
     opts.upnpEnable = getUPnPActive();
 
     if (config_->stunEnabled)
@@ -1495,6 +1493,26 @@
     return true;
 }
 
+bool
+ConnectionManager::Impl::findCertificate(const dht::InfoHash& h,
+    std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb)
+{
+    if (auto cert = certStore().getCertificate(h.toString())) {
+        if (cb)
+            cb(cert);
+    } else {
+        dht()->findCertificate(h,
+                              [cb = std::move(cb), this](
+                                  const std::shared_ptr<dht::crypto::Certificate>& crt) {
+                                  if (crt)
+                                      certStore().pinCertificate(crt);
+                                  if (cb)
+                                      cb(crt);
+                              });
+    }
+    return true;
+}
+
 ConnectionManager::ConnectionManager(std::shared_ptr<ConnectionManager::Config> config_)
     : pimpl_ {std::make_shared<Impl>(config_)}
 {}