Allow setting maximum protocol version for SSL stream adapters.

This CL adds an API to SSL stream adapters to set the maximum allowed
protocol version and with that implements support for DTLS 1.2.
With DTLS 1.2 the default cipher changes in the unittests as follows.

BoringSSL
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA -> TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

NSS
TLS_RSA_WITH_AES_128_CBC_SHA -> TLS_RSA_WITH_AES_128_GCM_SHA256

BUG=chromium:428343
R=juberti@google.com

Review URL: https://webrtc-codereview.appspot.com/50989004

Cr-Commit-Position: refs/heads/master@{#9232}
diff --git a/talk/app/webrtc/peerconnection_unittest.cc b/talk/app/webrtc/peerconnection_unittest.cc
index 93793cf..fe712e8 100644
--- a/talk/app/webrtc/peerconnection_unittest.cc
+++ b/talk/app/webrtc/peerconnection_unittest.cc
@@ -1312,8 +1312,10 @@
   ASSERT_TRUE(CreateTestClients());
   LocalP2PTest();
 
+  // TODO(jbauch): this should check for DTLS 1.0 / 1.2 when we have a way to
+  // enable DTLS 1.2 on peer connections.
   EXPECT_EQ_WAIT(
-      rtc::SSLStreamAdapter::GetDefaultSslCipher(),
+      rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_10),
       initializing_client()->GetDtlsCipherStats(),
       kMaxWaitForStatsMs);
 
diff --git a/webrtc/base/nssstreamadapter.cc b/webrtc/base/nssstreamadapter.cc
index fe1692c..de6da81 100644
--- a/webrtc/base/nssstreamadapter.cc
+++ b/webrtc/base/nssstreamadapter.cc
@@ -68,7 +68,8 @@
 
 // Default cipher used between NSS stream adapters.
 // This needs to be updated when the default of the SSL library changes.
-static const char kDefaultSslCipher[] = "TLS_RSA_WITH_AES_128_CBC_SHA";
+static const char kDefaultSslCipher10[] = "TLS_RSA_WITH_AES_128_CBC_SHA";
+static const char kDefaultSslCipher12[] = "TLS_RSA_WITH_AES_128_GCM_SHA256";
 
 
 // Implementation of NSPR methods
@@ -501,10 +502,33 @@
 
   // Set the version range.
   SSLVersionRange vrange;
-  vrange.min =  (ssl_mode_ == SSL_MODE_DTLS) ?
-      SSL_LIBRARY_VERSION_TLS_1_1 :
-      SSL_LIBRARY_VERSION_TLS_1_0;
-  vrange.max = SSL_LIBRARY_VERSION_TLS_1_1;
+  if (ssl_mode_ == SSL_MODE_DTLS) {
+    vrange.min = SSL_LIBRARY_VERSION_TLS_1_1;
+    switch (ssl_max_version_) {
+      case SSL_PROTOCOL_DTLS_10:
+        vrange.max = SSL_LIBRARY_VERSION_TLS_1_1;
+        break;
+      case SSL_PROTOCOL_DTLS_12:
+      default:
+        vrange.max = SSL_LIBRARY_VERSION_TLS_1_2;
+        break;
+    }
+  } else {
+    // SSL_MODE_TLS
+    vrange.min = SSL_LIBRARY_VERSION_TLS_1_0;
+    switch (ssl_max_version_) {
+      case SSL_PROTOCOL_TLS_10:
+        vrange.max = SSL_LIBRARY_VERSION_TLS_1_0;
+        break;
+      case SSL_PROTOCOL_TLS_11:
+        vrange.max = SSL_LIBRARY_VERSION_TLS_1_1;
+        break;
+      case SSL_PROTOCOL_TLS_12:
+      default:
+        vrange.max = SSL_LIBRARY_VERSION_TLS_1_2;
+        break;
+    }
+  }
 
   rv = SSL_VersionRangeSet(ssl_fd_, &vrange);
   if (rv != SECSuccess) {
@@ -1043,8 +1067,15 @@
   return true;
 }
 
-std::string NSSStreamAdapter::GetDefaultSslCipher() {
-  return kDefaultSslCipher;
+std::string NSSStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version) {
+  switch (version) {
+    case SSL_PROTOCOL_TLS_10:
+    case SSL_PROTOCOL_TLS_11:
+      return kDefaultSslCipher10;
+    case SSL_PROTOCOL_TLS_12:
+    default:
+      return kDefaultSslCipher12;
+  }
 }
 
 }  // namespace rtc
diff --git a/webrtc/base/nssstreamadapter.h b/webrtc/base/nssstreamadapter.h
index fcacb95..66d381d 100644
--- a/webrtc/base/nssstreamadapter.h
+++ b/webrtc/base/nssstreamadapter.h
@@ -84,7 +84,7 @@
   static bool HaveDtls();
   static bool HaveDtlsSrtp();
   static bool HaveExporter();
-  static std::string GetDefaultSslCipher();
+  static std::string GetDefaultSslCipher(SSLProtocolVersion version);
 
  protected:
   // Override SSLStreamAdapter
diff --git a/webrtc/base/opensslstreamadapter.cc b/webrtc/base/opensslstreamadapter.cc
index f3ad599..3a7e701 100644
--- a/webrtc/base/opensslstreamadapter.cc
+++ b/webrtc/base/opensslstreamadapter.cc
@@ -141,7 +141,21 @@
 
 // Default cipher used between OpenSSL/BoringSSL stream adapters.
 // This needs to be updated when the default of the SSL library changes.
-static const char kDefaultSslCipher[] = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
+static const char kDefaultSslCipher10[] =
+    "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
+
+#ifdef OPENSSL_IS_BORINGSSL
+static const char kDefaultSslCipher12[] =
+    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
+// Fallback cipher for DTLS 1.2 if hardware-accelerated AES-GCM is unavailable.
+static const char kDefaultSslCipher12NoAesGcm[] =
+    "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256";
+#else  // !OPENSSL_IS_BORINGSSL
+// OpenSSL sorts differently than BoringSSL, so the default cipher doesn't
+// change between TLS 1.0 and TLS 1.2 with the current setup.
+static const char kDefaultSslCipher12[] =
+    "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
+#endif
 
 //////////////////////////////////////////////////////////////////////
 // StreamBIO
@@ -262,7 +276,8 @@
       ssl_read_needs_write_(false), ssl_write_needs_read_(false),
       ssl_(NULL), ssl_ctx_(NULL),
       custom_verification_succeeded_(false),
-      ssl_mode_(SSL_MODE_TLS) {
+      ssl_mode_(SSL_MODE_TLS),
+      ssl_max_version_(SSL_PROTOCOL_TLS_11) {
 }
 
 OpenSSLStreamAdapter::~OpenSSLStreamAdapter() {
@@ -455,6 +470,11 @@
   ssl_mode_ = mode;
 }
 
+void OpenSSLStreamAdapter::SetMaxProtocolVersion(SSLProtocolVersion version) {
+  ASSERT(ssl_ctx_ == NULL);
+  ssl_max_version_ = version;
+}
+
 //
 // StreamInterface Implementation
 //
@@ -864,16 +884,92 @@
 SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {
   SSL_CTX *ctx = NULL;
 
-  if (role_ == SSL_CLIENT) {
+#ifdef OPENSSL_IS_BORINGSSL
     ctx = SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ?
-        DTLSv1_client_method() : TLSv1_client_method());
-  } else {
-    ctx = SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ?
-        DTLSv1_server_method() : TLSv1_server_method());
+        DTLS_method() : TLS_method());
+    // Version limiting for BoringSSL will be done below.
+#else
+  const SSL_METHOD* method;
+  switch (ssl_max_version_) {
+    case SSL_PROTOCOL_TLS_10:
+    case SSL_PROTOCOL_TLS_11:
+      // OpenSSL doesn't support setting min/max versions, so we always use
+      // (D)TLS 1.0 if a max. version below the max. available is requested.
+      if (ssl_mode_ == SSL_MODE_DTLS) {
+        if (role_ == SSL_CLIENT) {
+          method = DTLSv1_client_method();
+        } else {
+          method = DTLSv1_server_method();
+        }
+      } else {
+        if (role_ == SSL_CLIENT) {
+          method = TLSv1_client_method();
+        } else {
+          method = TLSv1_server_method();
+        }
+      }
+      break;
+    case SSL_PROTOCOL_TLS_12:
+    default:
+      if (ssl_mode_ == SSL_MODE_DTLS) {
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L)
+        // DTLS 1.2 only available starting from OpenSSL 1.0.2
+        if (role_ == SSL_CLIENT) {
+          method = DTLS_client_method();
+        } else {
+          method = DTLS_server_method();
+        }
+#else
+        if (role_ == SSL_CLIENT) {
+          method = DTLSv1_client_method();
+        } else {
+          method = DTLSv1_server_method();
+        }
+#endif
+      } else {
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+        // New API only available starting from OpenSSL 1.1.0
+        if (role_ == SSL_CLIENT) {
+          method = TLS_client_method();
+        } else {
+          method = TLS_server_method();
+        }
+#else
+        if (role_ == SSL_CLIENT) {
+          method = SSLv23_client_method();
+        } else {
+          method = SSLv23_server_method();
+        }
+#endif
+      }
+      break;
   }
+  ctx = SSL_CTX_new(method);
+#endif  // OPENSSL_IS_BORINGSSL
+
   if (ctx == NULL)
     return NULL;
 
+#ifdef OPENSSL_IS_BORINGSSL
+  SSL_CTX_set_min_version(ctx, ssl_mode_ == SSL_MODE_DTLS ?
+      DTLS1_VERSION : TLS1_VERSION);
+  switch (ssl_max_version_) {
+    case SSL_PROTOCOL_TLS_10:
+      SSL_CTX_set_max_version(ctx, ssl_mode_ == SSL_MODE_DTLS ?
+          DTLS1_VERSION : TLS1_VERSION);
+      break;
+    case SSL_PROTOCOL_TLS_11:
+      SSL_CTX_set_max_version(ctx, ssl_mode_ == SSL_MODE_DTLS ?
+          DTLS1_VERSION : TLS1_1_VERSION);
+      break;
+    case SSL_PROTOCOL_TLS_12:
+    default:
+      SSL_CTX_set_max_version(ctx, ssl_mode_ == SSL_MODE_DTLS ?
+          DTLS1_2_VERSION : TLS1_2_VERSION);
+      break;
+  }
+#endif
+
   if (identity_ && !identity_->ConfigureIdentity(ctx)) {
     SSL_CTX_free(ctx);
     return NULL;
@@ -893,7 +989,12 @@
 
   SSL_CTX_set_verify(ctx, mode, SSLVerifyCallback);
   SSL_CTX_set_verify_depth(ctx, 4);
-  SSL_CTX_set_cipher_list(ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
+  // Select list of available ciphers. Note that !SHA256 and !SHA384 only
+  // remove HMAC-SHA256 and HMAC-SHA384 cipher suites, not GCM cipher suites
+  // with SHA256 or SHA384 as the handshake hash.
+  // This matches the list of SSLClientSocketOpenSSL in Chromium.
+  SSL_CTX_set_cipher_list(ctx,
+      "DEFAULT:!NULL:!aNULL:!SHA256:!SHA384:!aECDH:!AESGCM+AES256:!aPSK");
 
 #ifdef HAVE_DTLS_SRTP
   if (!srtp_ciphers_.empty()) {
@@ -1009,8 +1110,24 @@
 #endif
 }
 
-std::string OpenSSLStreamAdapter::GetDefaultSslCipher() {
-  return kDefaultSslCipher;
+std::string OpenSSLStreamAdapter::GetDefaultSslCipher(
+    SSLProtocolVersion version) {
+  switch (version) {
+    case SSL_PROTOCOL_TLS_10:
+    case SSL_PROTOCOL_TLS_11:
+      return kDefaultSslCipher10;
+    case SSL_PROTOCOL_TLS_12:
+    default:
+#ifdef OPENSSL_IS_BORINGSSL
+      if (EVP_has_aes_hardware()) {
+        return kDefaultSslCipher12;
+      } else {
+        return kDefaultSslCipher12NoAesGcm;
+      }
+#else  // !OPENSSL_IS_BORINGSSL
+      return kDefaultSslCipher12;
+#endif
+  }
 }
 
 }  // namespace rtc
diff --git a/webrtc/base/opensslstreamadapter.h b/webrtc/base/opensslstreamadapter.h
index 6b24c9b..5cad3a1 100644
--- a/webrtc/base/opensslstreamadapter.h
+++ b/webrtc/base/opensslstreamadapter.h
@@ -74,6 +74,7 @@
   int StartSSLWithServer(const char* server_name) override;
   int StartSSLWithPeer() override;
   void SetMode(SSLMode mode) override;
+  void SetMaxProtocolVersion(SSLProtocolVersion version) override;
 
   StreamResult Read(void* data,
                     size_t data_len,
@@ -109,7 +110,7 @@
   static bool HaveDtls();
   static bool HaveDtlsSrtp();
   static bool HaveExporter();
-  static std::string GetDefaultSslCipher();
+  static std::string GetDefaultSslCipher(SSLProtocolVersion version);
 
  protected:
   void OnEvent(StreamInterface* stream, int events, int err) override;
@@ -201,6 +202,9 @@
 
   // Do DTLS or not
   SSLMode ssl_mode_;
+
+  // Max. allowed protocol version
+  SSLProtocolVersion ssl_max_version_;
 };
 
 /////////////////////////////////////////////////////////////////////////////
diff --git a/webrtc/base/sslstreamadapter.cc b/webrtc/base/sslstreamadapter.cc
index a592283..3c27b10 100644
--- a/webrtc/base/sslstreamadapter.cc
+++ b/webrtc/base/sslstreamadapter.cc
@@ -72,7 +72,7 @@
 bool SSLStreamAdapter::HaveDtls() { return false; }
 bool SSLStreamAdapter::HaveDtlsSrtp() { return false; }
 bool SSLStreamAdapter::HaveExporter() { return false; }
-std::string SSLStreamAdapter::GetDefaultSslCipher() {
+std::string SSLStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version) {
   return std::string();
 }
 #elif SSL_USE_OPENSSL
@@ -85,8 +85,8 @@
 bool SSLStreamAdapter::HaveExporter() {
   return OpenSSLStreamAdapter::HaveExporter();
 }
-std::string SSLStreamAdapter::GetDefaultSslCipher() {
-  return OpenSSLStreamAdapter::GetDefaultSslCipher();
+std::string SSLStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version) {
+  return OpenSSLStreamAdapter::GetDefaultSslCipher(version);
 }
 #elif SSL_USE_NSS
 bool SSLStreamAdapter::HaveDtls() {
@@ -98,8 +98,8 @@
 bool SSLStreamAdapter::HaveExporter() {
   return NSSStreamAdapter::HaveExporter();
 }
-std::string SSLStreamAdapter::GetDefaultSslCipher() {
-  return NSSStreamAdapter::GetDefaultSslCipher();
+std::string SSLStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version) {
+  return NSSStreamAdapter::GetDefaultSslCipher(version);
 }
 #endif  // !SSL_USE_SCHANNEL && !SSL_USE_OPENSSL && !SSL_USE_NSS
 
diff --git a/webrtc/base/sslstreamadapter.h b/webrtc/base/sslstreamadapter.h
index 2f819c8..dcb8029 100644
--- a/webrtc/base/sslstreamadapter.h
+++ b/webrtc/base/sslstreamadapter.h
@@ -36,6 +36,13 @@
 
 enum SSLRole { SSL_CLIENT, SSL_SERVER };
 enum SSLMode { SSL_MODE_TLS, SSL_MODE_DTLS };
+enum SSLProtocolVersion {
+  SSL_PROTOCOL_TLS_10,
+  SSL_PROTOCOL_TLS_11,
+  SSL_PROTOCOL_TLS_12,
+  SSL_PROTOCOL_DTLS_10 = SSL_PROTOCOL_TLS_11,
+  SSL_PROTOCOL_DTLS_12 = SSL_PROTOCOL_TLS_12,
+};
 
 // Errors for Read -- in the high range so no conflict with OpenSSL.
 enum { SSE_MSG_TRUNC = 0xff0001 };
@@ -74,6 +81,13 @@
   // Do DTLS or TLS
   virtual void SetMode(SSLMode mode) = 0;
 
+  // Set maximum supported protocol version. The highest version supported by
+  // both ends will be used for the connection, i.e. if one party supports
+  // DTLS 1.0 and the other DTLS 1.2, DTLS 1.0 will be used.
+  // If requested version is not supported by underlying crypto library, the
+  // next lower will be used.
+  virtual void SetMaxProtocolVersion(SSLProtocolVersion version) = 0;
+
   // The mode of operation is selected by calling either
   // StartSSLWithServer or StartSSLWithPeer.
   // Use of the stream prior to calling either of these functions will
@@ -151,9 +165,9 @@
   static bool HaveDtlsSrtp();
   static bool HaveExporter();
 
-  // Returns the default Ssl cipher used between streams of this class.
-  // This is used by the unit tests.
-  static std::string GetDefaultSslCipher();
+  // Returns the default Ssl cipher used between streams of this class
+  // for the given protocol version. This is used by the unit tests.
+  static std::string GetDefaultSslCipher(SSLProtocolVersion version);
 
  private:
   // If true, the server certificate need not match the configured
diff --git a/webrtc/base/sslstreamadapter_unittest.cc b/webrtc/base/sslstreamadapter_unittest.cc
index 677be35..6abaaa3 100644
--- a/webrtc/base/sslstreamadapter_unittest.cc
+++ b/webrtc/base/sslstreamadapter_unittest.cc
@@ -271,6 +271,12 @@
     identities_set_ = true;
   }
 
+  void SetupProtocolVersions(rtc::SSLProtocolVersion server_version,
+                             rtc::SSLProtocolVersion client_version) {
+    server_ssl_->SetMaxProtocolVersion(server_version);
+    client_ssl_->SetMaxProtocolVersion(client_version);
+  }
+
   void TestHandshake(bool expect_success = true) {
     server_ssl_->SetMode(dtls_ ? rtc::SSL_MODE_DTLS :
                          rtc::SSL_MODE_TLS);
@@ -948,8 +954,10 @@
 }
 
 // Test getting the used DTLS ciphers.
+// DTLS 1.2 enabled for neither client nor server -> DTLS 1.0 will be used.
 TEST_F(SSLStreamAdapterTestDTLS, TestGetSslCipher) {
   MAYBE_SKIP_TEST(HaveDtls);
+  SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10);
   TestHandshake();
 
   std::string client_cipher;
@@ -958,5 +966,59 @@
   ASSERT_TRUE(GetSslCipher(false, &server_cipher));
 
   ASSERT_EQ(client_cipher, server_cipher);
-  ASSERT_EQ(rtc::SSLStreamAdapter::GetDefaultSslCipher(), client_cipher);
+  ASSERT_EQ(
+      rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_10),
+      client_cipher);
+}
+
+// Test getting the used DTLS 1.2 ciphers.
+// DTLS 1.2 enabled for client and server -> DTLS 1.2 will be used.
+TEST_F(SSLStreamAdapterTestDTLS, TestGetSslCipherDtls12Both) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_12);
+  TestHandshake();
+
+  std::string client_cipher;
+  ASSERT_TRUE(GetSslCipher(true, &client_cipher));
+  std::string server_cipher;
+  ASSERT_TRUE(GetSslCipher(false, &server_cipher));
+
+  ASSERT_EQ(client_cipher, server_cipher);
+  ASSERT_EQ(
+      rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_12),
+      client_cipher);
+}
+
+// DTLS 1.2 enabled for client only -> DTLS 1.0 will be used.
+TEST_F(SSLStreamAdapterTestDTLS, TestGetSslCipherDtls12Client) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_12);
+  TestHandshake();
+
+  std::string client_cipher;
+  ASSERT_TRUE(GetSslCipher(true, &client_cipher));
+  std::string server_cipher;
+  ASSERT_TRUE(GetSslCipher(false, &server_cipher));
+
+  ASSERT_EQ(client_cipher, server_cipher);
+  ASSERT_EQ(
+      rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_10),
+      client_cipher);
+}
+
+// DTLS 1.2 enabled for server only -> DTLS 1.0 will be used.
+TEST_F(SSLStreamAdapterTestDTLS, TestGetSslCipherDtls12Server) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_10);
+  TestHandshake();
+
+  std::string client_cipher;
+  ASSERT_TRUE(GetSslCipher(true, &client_cipher));
+  std::string server_cipher;
+  ASSERT_TRUE(GetSslCipher(false, &server_cipher));
+
+  ASSERT_EQ(client_cipher, server_cipher);
+  ASSERT_EQ(
+      rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_10),
+      client_cipher);
 }
diff --git a/webrtc/base/sslstreamadapterhelper.cc b/webrtc/base/sslstreamadapterhelper.cc
index 1ab7369..c3be4ea 100644
--- a/webrtc/base/sslstreamadapterhelper.cc
+++ b/webrtc/base/sslstreamadapterhelper.cc
@@ -28,7 +28,8 @@
       state_(SSL_NONE),
       role_(SSL_CLIENT),
       ssl_error_code_(0),  // Not meaningful yet
-      ssl_mode_(SSL_MODE_TLS) {
+      ssl_mode_(SSL_MODE_TLS),
+      ssl_max_version_(SSL_PROTOCOL_TLS_11) {
 }
 
 SSLStreamAdapterHelper::~SSLStreamAdapterHelper() = default;
@@ -59,6 +60,10 @@
   ssl_mode_ = mode;
 }
 
+void SSLStreamAdapterHelper::SetMaxProtocolVersion(SSLProtocolVersion version) {
+  ssl_max_version_ = version;
+}
+
 StreamState SSLStreamAdapterHelper::GetState() const {
   switch (state_) {
     case SSL_WAIT:
diff --git a/webrtc/base/sslstreamadapterhelper.h b/webrtc/base/sslstreamadapterhelper.h
index 1c856e8..a28dba4 100644
--- a/webrtc/base/sslstreamadapterhelper.h
+++ b/webrtc/base/sslstreamadapterhelper.h
@@ -33,6 +33,7 @@
   void SetIdentity(SSLIdentity* identity) override;
   void SetServerRole(SSLRole role = SSL_SERVER) override;
   void SetMode(SSLMode mode) override;
+  void SetMaxProtocolVersion(SSLProtocolVersion version) override;
 
   int StartSSLWithServer(const char* server_name) override;
   int StartSSLWithPeer() override;
@@ -101,6 +102,9 @@
   // Do DTLS or not
   SSLMode ssl_mode_;
 
+  // Maximum allowed protocol version.
+  SSLProtocolVersion ssl_max_version_;
+
  private:
   // Go from state SSL_NONE to either SSL_CONNECTING or SSL_WAIT,
   // depending on whether the underlying stream is already open or
diff --git a/webrtc/p2p/base/dtlstransportchannel.cc b/webrtc/p2p/base/dtlstransportchannel.cc
index 4388408..cb1575d 100644
--- a/webrtc/p2p/base/dtlstransportchannel.cc
+++ b/webrtc/p2p/base/dtlstransportchannel.cc
@@ -87,7 +87,8 @@
       downward_(NULL),
       dtls_state_(STATE_NONE),
       local_identity_(NULL),
-      ssl_role_(rtc::SSL_CLIENT) {
+      ssl_role_(rtc::SSL_CLIENT),
+      ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10) {
   channel_->SignalReadableState.connect(this,
       &DtlsTransportChannelWrapper::OnReadableState);
   channel_->SignalWritableState.connect(this,
@@ -153,6 +154,17 @@
   return true;
 }
 
+void DtlsTransportChannelWrapper::SetMaxProtocolVersion(
+    rtc::SSLProtocolVersion version) {
+  if (dtls_state_ != STATE_NONE) {
+    LOG(LS_ERROR) << "Not changing max. protocol version "
+                  << "while DTLS is negotiating";
+    return;
+  }
+
+  ssl_max_version_ = version;
+}
+
 bool DtlsTransportChannelWrapper::SetSslRole(rtc::SSLRole role) {
   if (dtls_state_ == STATE_OPEN) {
     if (ssl_role_ != role) {
@@ -244,6 +256,7 @@
 
   dtls_->SetIdentity(local_identity_->GetReference());
   dtls_->SetMode(rtc::SSL_MODE_DTLS);
+  dtls_->SetMaxProtocolVersion(ssl_max_version_);
   dtls_->SetServerRole(ssl_role_);
   dtls_->SignalEvent.connect(this, &DtlsTransportChannelWrapper::OnDtlsEvent);
   if (!dtls_->SetPeerCertificateDigest(
diff --git a/webrtc/p2p/base/dtlstransportchannel.h b/webrtc/p2p/base/dtlstransportchannel.h
index a5fd035..5469b88 100644
--- a/webrtc/p2p/base/dtlstransportchannel.h
+++ b/webrtc/p2p/base/dtlstransportchannel.h
@@ -139,6 +139,8 @@
     return channel_->SessionId();
   }
 
+  virtual void SetMaxProtocolVersion(rtc::SSLProtocolVersion version);
+
   // Set up the ciphers to use for DTLS-SRTP. If this method is not called
   // before DTLS starts, or |ciphers| is empty, SRTP keys won't be negotiated.
   // This method should be called before SetupDtls.
@@ -241,6 +243,7 @@
   State dtls_state_;
   rtc::SSLIdentity* local_identity_;
   rtc::SSLRole ssl_role_;
+  rtc::SSLProtocolVersion ssl_max_version_;
   rtc::Buffer remote_fingerprint_value_;
   std::string remote_fingerprint_algorithm_;
 
diff --git a/webrtc/p2p/base/dtlstransportchannel_unittest.cc b/webrtc/p2p/base/dtlstransportchannel_unittest.cc
index acb9d09..670f8f9 100644
--- a/webrtc/p2p/base/dtlstransportchannel_unittest.cc
+++ b/webrtc/p2p/base/dtlstransportchannel_unittest.cc
@@ -54,6 +54,7 @@
       protocol_(cricket::ICEPROTO_GOOGLE),
       packet_size_(0),
       use_dtls_srtp_(false),
+      ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10),
       negotiated_dtls_(false),
       received_dtls_client_hello_(false),
       received_dtls_server_hello_(false) {
@@ -69,6 +70,10 @@
     ASSERT(identity_.get() != NULL);
     use_dtls_srtp_ = true;
   }
+  void SetupMaxProtocolVersion(rtc::SSLProtocolVersion version) {
+    ASSERT(transport_.get() == NULL);
+    ssl_max_version_ = version;
+  }
   void SetupChannels(int count, cricket::IceRole role) {
     transport_.reset(new cricket::DtlsTransport<cricket::FakeTransport>(
         signaling_thread_, worker_thread_, "dtls content name", NULL,
@@ -85,6 +90,7 @@
           static_cast<cricket::DtlsTransportChannelWrapper*>(
               transport_->CreateChannel(i));
       ASSERT_TRUE(channel != NULL);
+      channel->SetMaxProtocolVersion(ssl_max_version_);
       channel->SignalWritableState.connect(this,
         &DtlsTestClient::OnTransportChannelWritableState);
       channel->SignalReadPacket.connect(this,
@@ -377,6 +383,7 @@
   size_t packet_size_;
   std::set<int> received_;
   bool use_dtls_srtp_;
+  rtc::SSLProtocolVersion ssl_max_version_;
   bool negotiated_dtls_;
   bool received_dtls_client_hello_;
   bool received_dtls_server_hello_;
@@ -392,12 +399,19 @@
                rtc::Thread::Current()),
       channel_ct_(1),
       use_dtls_(false),
-      use_dtls_srtp_(false) {
+      use_dtls_srtp_(false),
+      ssl_expected_version_(rtc::SSL_PROTOCOL_DTLS_10) {
   }
 
   void SetChannelCount(size_t channel_ct) {
     channel_ct_ = static_cast<int>(channel_ct);
   }
+  void SetMaxProtocolVersions(rtc::SSLProtocolVersion c1,
+                              rtc::SSLProtocolVersion c2) {
+    client1_.SetupMaxProtocolVersion(c1);
+    client2_.SetupMaxProtocolVersion(c2);
+    ssl_expected_version_ = std::min(c1, c2);
+  }
   void PrepareDtls(bool c1, bool c2) {
     if (c1) {
       client1_.CreateIdentity();
@@ -459,8 +473,10 @@
       client1_.CheckSrtp("");
       client2_.CheckSrtp("");
     }
-    client1_.CheckSsl(rtc::SSLStreamAdapter::GetDefaultSslCipher());
-    client2_.CheckSsl(rtc::SSLStreamAdapter::GetDefaultSslCipher());
+    client1_.CheckSsl(
+        rtc::SSLStreamAdapter::GetDefaultSslCipher(ssl_expected_version_));
+    client2_.CheckSsl(
+        rtc::SSLStreamAdapter::GetDefaultSslCipher(ssl_expected_version_));
 
     return true;
   }
@@ -528,6 +544,7 @@
   int channel_ct_;
   bool use_dtls_;
   bool use_dtls_srtp_;
+  rtc::SSLProtocolVersion ssl_expected_version_;
 };
 
 // Test that transport negotiation of ICE, no DTLS works properly.
@@ -628,6 +645,42 @@
   TestTransfer(0, 1000, 100, false);
 }
 
+// Create two channels with DTLS 1.0 and check ciphers.
+TEST_F(DtlsTransportChannelTest, TestDtls12None) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  SetMaxProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10);
+  ASSERT_TRUE(Connect());
+}
+
+// Create two channels with DTLS 1.2 and check ciphers.
+TEST_F(DtlsTransportChannelTest, TestDtls12Both) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  SetMaxProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_12);
+  ASSERT_TRUE(Connect());
+}
+
+// Create two channels with DTLS 1.0 / DTLS 1.2 and check ciphers.
+TEST_F(DtlsTransportChannelTest, TestDtls12Client1) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  SetMaxProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_10);
+  ASSERT_TRUE(Connect());
+}
+
+// Create two channels with DTLS 1.2 / DTLS 1.0 and check ciphers.
+TEST_F(DtlsTransportChannelTest, TestDtls12Client2) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  SetMaxProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_12);
+  ASSERT_TRUE(Connect());
+}
+
 // Connect with DTLS, negotiate DTLS-SRTP, and transfer SRTP using bypass.
 TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtp) {
   MAYBE_SKIP_TEST(HaveDtlsSrtp);