This changeset adds dependency injection support for SSL Root Certs.

This extends the API surface so that
custom certificates can be provided by an API user in both the standalone and
factory creation paths for the OpenSSLAdapter. Prior to this change the SSL
roots were hardcoded in a header file and directly included into
openssladapter.cc. This forces the 100 kilobytes of certificates to always be
compiled into the library. This is undesirable in certain linking cases where
these certificates can be shared from another binary that already has an
equivalent set of trusted roots hard coded into the binary.

Support for removing the hard coded SSL roots has also been added through a new
build flag. By default the hard coded SSL roots will be included and will be
used if no other trusted root certificates are provided.

The main goal of this CL is to reduce total binary size requirements of WebRTC
by about 100kb in certain applications where adding these certificates is
redundant.

Change-Id: Ifd36d92b5cb32d1b3098a61ddfc244d76df8f30f

Bug: chromium:526260
Change-Id: Ifd36d92b5cb32d1b3098a61ddfc244d76df8f30f
Reviewed-on: https://webrtc-review.googlesource.com/64841
Commit-Queue: Benjamin Wright <benwright@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23180}
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 552bd2f..6557fca 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -904,8 +904,10 @@
                          "PeerConnectionObserver";
     return false;
   }
+
   observer_ = dependencies.observer;
   port_allocator_ = std::move(dependencies.allocator);
+  tls_cert_verifier_ = std::move(dependencies.tls_cert_verifier);
 
   // The port allocator lives on the network thread and should be initialized
   // there.
@@ -4674,6 +4676,11 @@
       ConvertIceTransportTypeToCandidateFilter(configuration.type));
   port_allocator_->set_max_ipv6_networks(configuration.max_ipv6_networks);
 
+  if (tls_cert_verifier_ != nullptr) {
+    for (auto& turn_server : turn_servers) {
+      turn_server.tls_cert_verifier = tls_cert_verifier_.get();
+    }
+  }
   // Call this last since it may create pooled allocator sessions using the
   // properties set above.
   port_allocator_->SetConfiguration(
diff --git a/pc/peerconnection.h b/pc/peerconnection.h
index 1c8c3e0..7549131 100644
--- a/pc/peerconnection.h
+++ b/pc/peerconnection.h
@@ -906,6 +906,7 @@
   PeerConnectionInterface::RTCConfiguration configuration_;
 
   std::unique_ptr<cricket::PortAllocator> port_allocator_;
+  std::unique_ptr<rtc::SSLCertificateVerifier> tls_cert_verifier_;
   int port_allocator_flags_ = 0;
 
   // One PeerConnection has only one RTCP CNAME.
diff --git a/pc/peerconnection_integrationtest.cc b/pc/peerconnection_integrationtest.cc
index 6616243..969fc80 100644
--- a/pc/peerconnection_integrationtest.cc
+++ b/pc/peerconnection_integrationtest.cc
@@ -55,6 +55,7 @@
 #include "rtc_base/fakenetwork.h"
 #include "rtc_base/firewallsocketserver.h"
 #include "rtc_base/gunit.h"
+#include "rtc_base/testcertificateverifier.h"
 #include "rtc_base/virtualsocketserver.h"
 #include "test/gmock.h"
 
@@ -227,7 +228,9 @@
       rtc::Thread* network_thread,
       rtc::Thread* worker_thread) {
     PeerConnectionWrapper* client(new PeerConnectionWrapper(debug_name));
-    if (!client->Init(nullptr, nullptr, nullptr, std::move(cert_generator),
+    webrtc::PeerConnectionDependencies dependencies(nullptr);
+    dependencies.cert_generator = std::move(cert_generator);
+    if (!client->Init(nullptr, nullptr, nullptr, std::move(dependencies),
                       network_thread, worker_thread)) {
       delete client;
       return nullptr;
@@ -579,13 +582,12 @@
   explicit PeerConnectionWrapper(const std::string& debug_name)
       : debug_name_(debug_name) {}
 
-  bool Init(
-      const MediaConstraintsInterface* constraints,
-      const PeerConnectionFactory::Options* options,
-      const PeerConnectionInterface::RTCConfiguration* config,
-      std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
-      rtc::Thread* network_thread,
-      rtc::Thread* worker_thread) {
+  bool Init(const MediaConstraintsInterface* constraints,
+            const PeerConnectionFactory::Options* options,
+            const PeerConnectionInterface::RTCConfiguration* config,
+            webrtc::PeerConnectionDependencies dependencies,
+            rtc::Thread* network_thread,
+            rtc::Thread* worker_thread) {
     // There's an error in this test code if Init ends up being called twice.
     RTC_DCHECK(!peer_connection_);
     RTC_DCHECK(!peer_connection_factory_);
@@ -625,17 +627,17 @@
     if (config) {
       sdp_semantics_ = config->sdp_semantics;
     }
+
+    dependencies.allocator = std::move(port_allocator);
     peer_connection_ =
-        CreatePeerConnection(std::move(port_allocator), constraints, config,
-                             std::move(cert_generator));
+        CreatePeerConnection(constraints, config, std::move(dependencies));
     return peer_connection_.get() != nullptr;
   }
 
   rtc::scoped_refptr<webrtc::PeerConnectionInterface> CreatePeerConnection(
-      std::unique_ptr<cricket::PortAllocator> port_allocator,
       const MediaConstraintsInterface* constraints,
       const PeerConnectionInterface::RTCConfiguration* config,
-      std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator) {
+      webrtc::PeerConnectionDependencies dependencies) {
     PeerConnectionInterface::RTCConfiguration modified_config;
     // If |config| is null, this will result in a default configuration being
     // used.
@@ -648,9 +650,15 @@
     // ratios and not specific resolutions, is this even necessary?
     modified_config.set_cpu_adaptation(false);
 
+    // Use the legacy interface.
+    if (constraints != nullptr) {
+      return peer_connection_factory_->CreatePeerConnection(
+          modified_config, constraints, std::move(dependencies.allocator),
+          std::move(dependencies.cert_generator), this);
+    }
+    dependencies.observer = this;
     return peer_connection_factory_->CreatePeerConnection(
-        modified_config, constraints, std::move(port_allocator),
-        std::move(cert_generator), this);
+        modified_config, std::move(dependencies));
   }
 
   void set_signaling_message_receiver(
@@ -1156,19 +1164,21 @@
       const MediaConstraintsInterface* constraints,
       const PeerConnectionFactory::Options* options,
       const RTCConfiguration* config,
-      std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator) {
+      webrtc::PeerConnectionDependencies dependencies) {
     RTCConfiguration modified_config;
     if (config) {
       modified_config = *config;
     }
     modified_config.sdp_semantics = sdp_semantics_;
-    if (!cert_generator) {
-      cert_generator = rtc::MakeUnique<FakeRTCCertificateGenerator>();
+    if (!dependencies.cert_generator) {
+      dependencies.cert_generator =
+          rtc::MakeUnique<FakeRTCCertificateGenerator>();
     }
     std::unique_ptr<PeerConnectionWrapper> client(
         new PeerConnectionWrapper(debug_name));
+
     if (!client->Init(constraints, options, &modified_config,
-                      std::move(cert_generator), network_thread_.get(),
+                      std::move(dependencies), network_thread_.get(),
                       worker_thread_.get())) {
       return nullptr;
     }
@@ -1191,11 +1201,13 @@
     // callee PeerConnections.
     SdpSemantics original_semantics = sdp_semantics_;
     sdp_semantics_ = caller_semantics;
-    caller_ = CreatePeerConnectionWrapper("Caller", nullptr, nullptr, nullptr,
-                                          nullptr);
+    caller_ = CreatePeerConnectionWrapper(
+        "Caller", nullptr, nullptr, nullptr,
+        webrtc::PeerConnectionDependencies(nullptr));
     sdp_semantics_ = callee_semantics;
-    callee_ = CreatePeerConnectionWrapper("Callee", nullptr, nullptr, nullptr,
-                                          nullptr);
+    callee_ = CreatePeerConnectionWrapper(
+        "Callee", nullptr, nullptr, nullptr,
+        webrtc::PeerConnectionDependencies(nullptr));
     sdp_semantics_ = original_semantics;
     return caller_ && callee_;
   }
@@ -1203,30 +1215,51 @@
   bool CreatePeerConnectionWrappersWithConstraints(
       MediaConstraintsInterface* caller_constraints,
       MediaConstraintsInterface* callee_constraints) {
-    caller_ = CreatePeerConnectionWrapper("Caller", caller_constraints, nullptr,
-                                          nullptr, nullptr);
-    callee_ = CreatePeerConnectionWrapper("Callee", callee_constraints, nullptr,
-                                          nullptr, nullptr);
+    caller_ = CreatePeerConnectionWrapper(
+        "Caller", caller_constraints, nullptr, nullptr,
+        webrtc::PeerConnectionDependencies(nullptr));
+    callee_ = CreatePeerConnectionWrapper(
+        "Callee", callee_constraints, nullptr, nullptr,
+        webrtc::PeerConnectionDependencies(nullptr));
+
     return caller_ && callee_;
   }
 
   bool CreatePeerConnectionWrappersWithConfig(
       const PeerConnectionInterface::RTCConfiguration& caller_config,
       const PeerConnectionInterface::RTCConfiguration& callee_config) {
-    caller_ = CreatePeerConnectionWrapper("Caller", nullptr, nullptr,
-                                          &caller_config, nullptr);
-    callee_ = CreatePeerConnectionWrapper("Callee", nullptr, nullptr,
-                                          &callee_config, nullptr);
+    caller_ = CreatePeerConnectionWrapper(
+        "Caller", nullptr, nullptr, &caller_config,
+        webrtc::PeerConnectionDependencies(nullptr));
+    callee_ = CreatePeerConnectionWrapper(
+        "Callee", nullptr, nullptr, &callee_config,
+        webrtc::PeerConnectionDependencies(nullptr));
+    return caller_ && callee_;
+  }
+
+  bool CreatePeerConnectionWrappersWithConfigAndDeps(
+      const PeerConnectionInterface::RTCConfiguration& caller_config,
+      webrtc::PeerConnectionDependencies caller_dependencies,
+      const PeerConnectionInterface::RTCConfiguration& callee_config,
+      webrtc::PeerConnectionDependencies callee_dependencies) {
+    caller_ =
+        CreatePeerConnectionWrapper("Caller", nullptr, nullptr, &caller_config,
+                                    std::move(caller_dependencies));
+    callee_ =
+        CreatePeerConnectionWrapper("Callee", nullptr, nullptr, &callee_config,
+                                    std::move(callee_dependencies));
     return caller_ && callee_;
   }
 
   bool CreatePeerConnectionWrappersWithOptions(
       const PeerConnectionFactory::Options& caller_options,
       const PeerConnectionFactory::Options& callee_options) {
-    caller_ = CreatePeerConnectionWrapper("Caller", nullptr, &caller_options,
-                                          nullptr, nullptr);
-    callee_ = CreatePeerConnectionWrapper("Callee", nullptr, &callee_options,
-                                          nullptr, nullptr);
+    caller_ = CreatePeerConnectionWrapper(
+        "Caller", nullptr, &caller_options, nullptr,
+        webrtc::PeerConnectionDependencies(nullptr));
+    callee_ = CreatePeerConnectionWrapper(
+        "Callee", nullptr, &callee_options, nullptr,
+        webrtc::PeerConnectionDependencies(nullptr));
     return caller_ && callee_;
   }
 
@@ -1236,8 +1269,10 @@
         new FakeRTCCertificateGenerator());
     cert_generator->use_alternate_key();
 
+    webrtc::PeerConnectionDependencies dependencies(nullptr);
+    dependencies.cert_generator = std::move(cert_generator);
     return CreatePeerConnectionWrapper("New Peer", nullptr, nullptr, nullptr,
-                                       std::move(cert_generator));
+                                       std::move(dependencies));
   }
 
   // Once called, SDP blobs and ICE candidates will be automatically signaled
@@ -3925,6 +3960,150 @@
   delete SetCalleePcWrapperAndReturnCurrent(nullptr);
 }
 
+// Verify that a SSLCertificateVerifier passed in through
+// PeerConnectionDependencies is actually used by the underlying SSL
+// implementation to determine whether a certificate presented by the TURN
+// server is accepted by the client. Note that openssladapter_unittest.cc
+// contains more detailed, lower-level tests.
+TEST_P(PeerConnectionIntegrationTest,
+       SSLCertificateVerifierUsedForTurnConnections) {
+  static const rtc::SocketAddress turn_server_internal_address{"88.88.88.0",
+                                                               3478};
+  static const rtc::SocketAddress turn_server_external_address{"88.88.88.1", 0};
+
+  // Enable TCP-TLS for the fake turn server. We need to pass in 88.88.88.0 so
+  // that host name verification passes on the fake certificate.
+  cricket::TestTurnServer turn_server(
+      network_thread(), turn_server_internal_address,
+      turn_server_external_address, cricket::PROTO_TLS,
+      /*ignore_bad_certs=*/true, "88.88.88.0");
+
+  webrtc::PeerConnectionInterface::IceServer ice_server;
+  ice_server.urls.push_back("turns:88.88.88.0:3478?transport=tcp");
+  ice_server.username = "test";
+  ice_server.password = "test";
+
+  PeerConnectionInterface::RTCConfiguration client_1_config;
+  client_1_config.servers.push_back(ice_server);
+  client_1_config.type = webrtc::PeerConnectionInterface::kRelay;
+
+  PeerConnectionInterface::RTCConfiguration client_2_config;
+  client_2_config.servers.push_back(ice_server);
+  // Setting the type to kRelay forces the connection to go through a TURN
+  // server.
+  client_2_config.type = webrtc::PeerConnectionInterface::kRelay;
+
+  // Get a copy to the pointer so we can verify calls later.
+  rtc::TestCertificateVerifier* client_1_cert_verifier =
+      new rtc::TestCertificateVerifier();
+  client_1_cert_verifier->verify_certificate_ = true;
+  rtc::TestCertificateVerifier* client_2_cert_verifier =
+      new rtc::TestCertificateVerifier();
+  client_2_cert_verifier->verify_certificate_ = true;
+
+  // Create the dependencies with the test certificate verifier.
+  webrtc::PeerConnectionDependencies client_1_deps(nullptr);
+  client_1_deps.tls_cert_verifier =
+      std::unique_ptr<rtc::TestCertificateVerifier>(client_1_cert_verifier);
+  webrtc::PeerConnectionDependencies client_2_deps(nullptr);
+  client_2_deps.tls_cert_verifier =
+      std::unique_ptr<rtc::TestCertificateVerifier>(client_2_cert_verifier);
+
+  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfigAndDeps(
+      client_1_config, std::move(client_1_deps), client_2_config,
+      std::move(client_2_deps)));
+  ConnectFakeSignaling();
+
+  // Set "offer to receive audio/video" without adding any tracks, so we just
+  // set up ICE/DTLS with no media.
+  PeerConnectionInterface::RTCOfferAnswerOptions options;
+  options.offer_to_receive_audio = 1;
+  options.offer_to_receive_video = 1;
+  caller()->SetOfferAnswerOptions(options);
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(DtlsConnected(), kDefaultTimeout);
+
+  EXPECT_GT(client_1_cert_verifier->call_count_, 0u);
+  EXPECT_GT(client_2_cert_verifier->call_count_, 0u);
+
+  // Need to free the clients here since they're using things we created on
+  // the stack.
+  delete SetCallerPcWrapperAndReturnCurrent(nullptr);
+  delete SetCalleePcWrapperAndReturnCurrent(nullptr);
+}
+
+TEST_P(PeerConnectionIntegrationTest,
+       SSLCertificateVerifierFailureUsedForTurnConnectionsFailsConnection) {
+  static const rtc::SocketAddress turn_server_internal_address{"88.88.88.0",
+                                                               3478};
+  static const rtc::SocketAddress turn_server_external_address{"88.88.88.1", 0};
+
+  // Enable TCP-TLS for the fake turn server. We need to pass in 88.88.88.0 so
+  // that host name verification passes on the fake certificate.
+  cricket::TestTurnServer turn_server(
+      network_thread(), turn_server_internal_address,
+      turn_server_external_address, cricket::PROTO_TLS,
+      /*ignore_bad_certs=*/true, "88.88.88.0");
+
+  webrtc::PeerConnectionInterface::IceServer ice_server;
+  ice_server.urls.push_back("turns:88.88.88.0:3478?transport=tcp");
+  ice_server.username = "test";
+  ice_server.password = "test";
+
+  PeerConnectionInterface::RTCConfiguration client_1_config;
+  client_1_config.servers.push_back(ice_server);
+  client_1_config.type = webrtc::PeerConnectionInterface::kRelay;
+
+  PeerConnectionInterface::RTCConfiguration client_2_config;
+  client_2_config.servers.push_back(ice_server);
+  // Setting the type to kRelay forces the connection to go through a TURN
+  // server.
+  client_2_config.type = webrtc::PeerConnectionInterface::kRelay;
+
+  // Get a copy to the pointer so we can verify calls later.
+  rtc::TestCertificateVerifier* client_1_cert_verifier =
+      new rtc::TestCertificateVerifier();
+  client_1_cert_verifier->verify_certificate_ = false;
+  rtc::TestCertificateVerifier* client_2_cert_verifier =
+      new rtc::TestCertificateVerifier();
+  client_2_cert_verifier->verify_certificate_ = false;
+
+  // Create the dependencies with the test certificate verifier.
+  webrtc::PeerConnectionDependencies client_1_deps(nullptr);
+  client_1_deps.tls_cert_verifier =
+      std::unique_ptr<rtc::TestCertificateVerifier>(client_1_cert_verifier);
+  webrtc::PeerConnectionDependencies client_2_deps(nullptr);
+  client_2_deps.tls_cert_verifier =
+      std::unique_ptr<rtc::TestCertificateVerifier>(client_2_cert_verifier);
+
+  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfigAndDeps(
+      client_1_config, std::move(client_1_deps), client_2_config,
+      std::move(client_2_deps)));
+  ConnectFakeSignaling();
+
+  // Set "offer to receive audio/video" without adding any tracks, so we just
+  // set up ICE/DTLS with no media.
+  PeerConnectionInterface::RTCOfferAnswerOptions options;
+  options.offer_to_receive_audio = 1;
+  options.offer_to_receive_video = 1;
+  caller()->SetOfferAnswerOptions(options);
+  caller()->CreateAndSetAndSignalOffer();
+  bool wait_res = true;
+  // TODO(bugs.webrtc.org/9219): When IceConnectionState is implemented
+  // properly, should be able to just wait for a state of "failed" instead of
+  // waiting a fixed 10 seconds.
+  WAIT_(DtlsConnected(), kDefaultTimeout, wait_res);
+  ASSERT_FALSE(wait_res);
+
+  EXPECT_GT(client_1_cert_verifier->call_count_, 0u);
+  EXPECT_GT(client_2_cert_verifier->call_count_, 0u);
+
+  // Need to free the clients here since they're using things we created on
+  // the stack.
+  delete SetCallerPcWrapperAndReturnCurrent(nullptr);
+  delete SetCalleePcWrapperAndReturnCurrent(nullptr);
+}
+
 // Test that audio and video flow end-to-end when codec names don't use the
 // expected casing, given that they're supposed to be case insensitive. To test
 // this, all but one codec is removed from each media description, and its