Do not use HTTP/2 without adequate security.

Stop using HTTP/2 in case TLS 1.2 is not supported, connection has been
downgraded to below TLS 1.2, or AES-GCM cipher required by HTTP/2 draft
specification is not supported.

BUG=436835

Review URL: https://codereview.chromium.org/757033004

Cr-Commit-Position: refs/heads/master@{#308226}
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index e39920e4..405c88c 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -26,6 +26,7 @@
 #include "net/socket/client_socket_factory.h"
 #include "net/socket/client_socket_pool_manager_impl.h"
 #include "net/socket/next_proto.h"
+#include "net/socket/ssl_client_socket.h"
 #include "net/spdy/hpack_huffman_aggregator.h"
 #include "net/spdy/spdy_session_pool.h"
 
diff --git a/net/net.gypi b/net/net.gypi
index 1350edd..5ca70f7 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -153,6 +153,8 @@
       'ssl/signed_certificate_timestamp_and_status.h',
       'ssl/ssl_cert_request_info.cc',
       'ssl/ssl_cert_request_info.h',
+      'ssl/ssl_cipher_suite_names.cc',
+      'ssl/ssl_cipher_suite_names.h',
       'ssl/ssl_client_auth_cache.cc',
       'ssl/ssl_client_auth_cache.h',
       'ssl/ssl_client_cert_type.h',
@@ -1107,8 +1109,6 @@
       'ssl/client_cert_store_nss.h',
       'ssl/client_cert_store_win.cc',
       'ssl/client_cert_store_win.h',
-      'ssl/ssl_cipher_suite_names.cc',
-      'ssl/ssl_cipher_suite_names.h',
       'ssl/ssl_config_service_defaults.cc',
       'ssl/ssl_config_service_defaults.h',
       'third_party/mozilla_security_manager/nsKeygenHandler.cpp',
diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc
index e0a6d8d..2ea403f7 100644
--- a/net/socket/ssl_client_socket.cc
+++ b/net/socket/ssl_client_socket.cc
@@ -11,6 +11,7 @@
 #include "net/base/connection_type_histograms.h"
 #include "net/base/host_port_pair.h"
 #include "net/ssl/channel_id_service.h"
+#include "net/ssl/ssl_cipher_suite_names.h"
 #include "net/ssl/ssl_config_service.h"
 #include "net/ssl/ssl_connection_status_flags.h"
 
@@ -234,10 +235,31 @@
 }
 
 // static
+bool SSLClientSocket::HasCipherAdequateForHTTP2(
+    const std::vector<uint16>& cipher_suites) {
+  for (uint16 cipher : cipher_suites) {
+    if (IsSecureTLSCipherSuite(cipher))
+      return true;
+  }
+  return false;
+}
+
+// static
+bool SSLClientSocket::IsTLSVersionAdequateForHTTP2(
+    const SSLConfig& ssl_config) {
+  return ssl_config.version_max >= SSL_PROTOCOL_VERSION_TLS1_2;
+}
+
+// static
 std::vector<uint8_t> SSLClientSocket::SerializeNextProtos(
-    const NextProtoVector& next_protos) {
+    const NextProtoVector& next_protos,
+    bool can_advertise_http2) {
   std::vector<uint8_t> wire_protos;
   for (const NextProto next_proto : next_protos) {
+    if (!can_advertise_http2 && kProtoSPDY4MinimumVersion <= next_proto &&
+        next_proto <= kProtoSPDY4MaximumVersion) {
+      continue;
+    }
     const std::string proto = NextProtoToString(next_proto);
     if (proto.size() > 255) {
       LOG(WARNING) << "Ignoring overlong NPN/ALPN protocol: " << proto;
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index d72dee5..46461df 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -209,10 +209,23 @@
       const SSLConfig& ssl_config,
       ChannelIDService* channel_id_service);
 
+  // Determine if there is at least one enabled cipher suite that satisfies
+  // Section 9.2 of the HTTP/2 specification.  Note that the server might still
+  // pick an inadequate cipher suite.
+  static bool HasCipherAdequateForHTTP2(
+      const std::vector<uint16>& cipher_suites);
+
+  // Determine if the TLS version required by Section 9.2 of the HTTP/2
+  // specification is enabled.  Note that the server might still pick an
+  // inadequate TLS version.
+  static bool IsTLSVersionAdequateForHTTP2(const SSLConfig& ssl_config);
+
   // Serializes |next_protos| in the wire format for ALPN: protocols are listed
-  // in order, each prefixed by a one-byte length.
+  // in order, each prefixed by a one-byte length.  Any HTTP/2 protocols in
+  // |next_protos| are ignored if |can_advertise_http2| is false.
   static std::vector<uint8_t> SerializeNextProtos(
-      const NextProtoVector& next_protos);
+      const NextProtoVector& next_protos,
+      bool can_advertise_http2);
 
   // For unit testing only.
   // Returns the unverified certificate chain as presented by server.
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 3651e8d..5e33e12 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -149,6 +149,14 @@
     } while (0)
 #endif
 
+#if !defined(CKM_AES_GCM)
+#define CKM_AES_GCM 0x00001087
+#endif
+
+#if !defined(CKM_NSS_CHACHA20_POLY1305)
+#define CKM_NSS_CHACHA20_POLY1305 (CKM_NSS + 26)
+#endif
+
 namespace {
 
 // SSL plaintext fragments are shorter than 16KB. Although the record layer
@@ -973,8 +981,16 @@
   SECStatus rv = SECSuccess;
 
   if (!ssl_config_.next_protos.empty()) {
+    // TODO(bnc): Check ssl_config_.disabled_cipher_suites.
+    const bool adequate_encryption =
+        PK11_TokenExists(CKM_AES_GCM) ||
+        PK11_TokenExists(CKM_NSS_CHACHA20_POLY1305);
+    const bool adequate_key_agreement = PK11_TokenExists(CKM_DH_PKCS_DERIVE) ||
+                                        PK11_TokenExists(CKM_ECDH1_DERIVE);
     std::vector<uint8_t> wire_protos =
-        SerializeNextProtos(ssl_config_.next_protos);
+        SerializeNextProtos(ssl_config_.next_protos,
+                            adequate_encryption && adequate_key_agreement &&
+                                IsTLSVersionAdequateForHTTP2(ssl_config_));
     rv = SSL_SetNextProtoNego(
         nss_fd_, wire_protos.empty() ? NULL : &wire_protos[0],
         wire_protos.size());
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 5415755f..c78a9742 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -788,8 +788,8 @@
   // disabled by default. 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.
-  std::string command("DEFAULT:!NULL:!aNULL:!IDEA:!FZA:!SRP:!SHA256:!SHA384:"
-                      "!aECDH:!AESGCM+AES256");
+  std::string command(
+      "DEFAULT:!NULL:!aNULL:!SHA256:!SHA384:!aECDH:!AESGCM+AES256:!aPSK");
   // Walk through all the installed ciphers, seeing if any need to be
   // appended to the cipher removal |command|.
   for (size_t i = 0; i < sk_SSL_CIPHER_num(ciphers); ++i) {
@@ -838,8 +838,20 @@
   }
 
   if (!ssl_config_.next_protos.empty()) {
+    // Get list of ciphers that are enabled.
+    STACK_OF(SSL_CIPHER)* enabled_ciphers = SSL_get_ciphers(ssl_);
+    DCHECK(enabled_ciphers);
+    std::vector<uint16> enabled_ciphers_vector;
+    for (size_t i = 0; i < sk_SSL_CIPHER_num(enabled_ciphers); ++i) {
+      const SSL_CIPHER* cipher = sk_SSL_CIPHER_value(enabled_ciphers, i);
+      const uint16 id = static_cast<uint16>(SSL_CIPHER_get_id(cipher));
+      enabled_ciphers_vector.push_back(id);
+    }
+
     std::vector<uint8_t> wire_protos =
-        SerializeNextProtos(ssl_config_.next_protos);
+        SerializeNextProtos(ssl_config_.next_protos,
+                            HasCipherAdequateForHTTP2(enabled_ciphers_vector) &&
+                                IsTLSVersionAdequateForHTTP2(ssl_config_));
     SSL_set_alpn_protos(ssl_, wire_protos.empty() ? NULL : &wire_protos[0],
                         wire_protos.size());
   }
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index d650f627df..d14f1fd 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -2356,7 +2356,7 @@
   next_protos.push_back(kProtoHTTP11);
   next_protos.push_back(kProtoSPDY31);
   static std::vector<uint8_t> serialized =
-      SSLClientSocket::SerializeNextProtos(next_protos);
+      SSLClientSocket::SerializeNextProtos(next_protos, true);
   ASSERT_EQ(18u, serialized.size());
   EXPECT_EQ(8, serialized[0]);  // length("http/1.1")
   EXPECT_EQ('h', serialized[1]);