Bug 1121706 - Don't offer h2 in alpn if w/out mandatory suite. r=hurley, a=sledru
authorPatrick McManus <mcmanus@ducksong.com>
Thu, 15 Jan 2015 22:11:14 -0500
changeset 242949 131919c0babd
parent 242948 c703f90c5b80
child 242950 506cfb41b8f3
push id4344
push userryanvm@gmail.com
push date2015-01-20 17:02 +0000
treeherdermozilla-beta@ea7deca21c27 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershurley, sledru
bugs1121706
milestone36.0
Bug 1121706 - Don't offer h2 in alpn if w/out mandatory suite. r=hurley, a=sledru
netwerk/protocol/http/Http2Session.cpp
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/http/nsHttpHandler.h
netwerk/test/unit/test_http2.js
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -3234,16 +3234,21 @@ Http2Session::BufferOutput(const char *b
   nsresult rv = OnReadSegment(buf, count, countRead);
   mSegmentReader = old;
   return rv;
 }
 
 bool // static
 Http2Session::ALPNCallback(nsISupports *securityInfo)
 {
+  if (!gHttpHandler->IsH2MandatorySuiteEnabled()) {
+    LOG3(("Http2Session::ALPNCallback Mandatory Cipher Suite Unavailable\n"));
+    return false;
+  }
+
   nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(securityInfo);
   LOG3(("Http2Session::ALPNCallback sslsocketcontrol=%p\n", ssl.get()));
   if (ssl) {
     int16_t version = ssl->GetSSLVersionOffered();
     LOG3(("Http2Session::ALPNCallback version=%x\n", version));
     if (version >= nsISSLSocketControl::TLS_VERSION_1_2) {
       return true;
     }
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -78,16 +78,17 @@ extern PRThread *gSocketThread;
 #ifdef XP_WIN
 #define UA_SPARE_PLATFORM
 #endif
 
 #define HTTP_PREF_PREFIX        "network.http."
 #define INTL_ACCEPT_LANGUAGES   "intl.accept_languages"
 #define BROWSER_PREF_PREFIX     "browser.cache."
 #define DONOTTRACK_HEADER_ENABLED "privacy.donottrackheader.enabled"
+#define H2MANDATORY_SUITE        "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256"
 #define TELEMETRY_ENABLED        "toolkit.telemetry.enabled"
 #define ALLOW_EXPERIMENTS        "network.allow-experiments"
 #define SAFE_HINT_HEADER_VALUE   "safeHint.enabled"
 
 #define UA_PREF(_pref) UA_PREF_PREFIX _pref
 #define HTTP_PREF(_pref) HTTP_PREF_PREFIX _pref
 #define BROWSER_PREF(_pref) BROWSER_PREF_PREFIX _pref
 
@@ -141,16 +142,17 @@ nsHttpHandler::nsHttpHandler()
     , mIdleTimeout(PR_SecondsToInterval(10))
     , mSpdyTimeout(PR_SecondsToInterval(180))
     , mResponseTimeout(PR_SecondsToInterval(300))
     , mResponseTimeoutEnabled(false)
     , mNetworkChangedTimeout(5000)
     , mMaxRequestAttempts(10)
     , mMaxRequestDelay(10)
     , mIdleSynTimeout(250)
+    , mH2MandatorySuiteEnabled(false)
     , mPipeliningEnabled(false)
     , mMaxConnections(24)
     , mMaxPersistentConnectionsPerServer(2)
     , mMaxPersistentConnectionsPerProxy(4)
     , mMaxPipelinedRequests(32)
     , mMaxOptimisticPipelinedRequests(4)
     , mPipelineAggressive(false)
     , mMaxPipelineObjectSize(300000)
@@ -267,16 +269,17 @@ nsHttpHandler::Init()
     nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (prefBranch) {
         prefBranch->AddObserver(HTTP_PREF_PREFIX, this, true);
         prefBranch->AddObserver(UA_PREF_PREFIX, this, true);
         prefBranch->AddObserver(INTL_ACCEPT_LANGUAGES, this, true);
         prefBranch->AddObserver(BROWSER_PREF("disk_cache_ssl"), this, true);
         prefBranch->AddObserver(DONOTTRACK_HEADER_ENABLED, this, true);
         prefBranch->AddObserver(TELEMETRY_ENABLED, this, true);
+        prefBranch->AddObserver(H2MANDATORY_SUITE, this, true);
         prefBranch->AddObserver(HTTP_PREF("tcp_keepalive.short_lived_connections"), this, true);
         prefBranch->AddObserver(HTTP_PREF("tcp_keepalive.long_lived_connections"), this, true);
         prefBranch->AddObserver(SAFE_HINT_HEADER_VALUE, this, true);
         PrefsChanged(prefBranch, nullptr);
     }
 
     mMisc.AssignLiteral("rv:" MOZILLA_UAVERSION);
 
@@ -1366,16 +1369,27 @@ nsHttpHandler::PrefsChanged(nsIPrefBranc
         cVar = false;
         requestTokenBucketUpdated = true;
         rv = prefs->GetBoolPref(TELEMETRY_ENABLED, &cVar);
         if (NS_SUCCEEDED(rv)) {
             mTelemetryEnabled = cVar;
         }
     }
 
+    // "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256" is the required h2 interop
+    // suite.
+
+    if (PREF_CHANGED(H2MANDATORY_SUITE)) {
+        cVar = false;
+        rv = prefs->GetBoolPref(H2MANDATORY_SUITE, &cVar);
+        if (NS_SUCCEEDED(rv)) {
+            mH2MandatorySuiteEnabled = cVar;
+        }
+    }
+
     //
     // network.allow-experiments
     //
     if (PREF_CHANGED(ALLOW_EXPERIMENTS)) {
         cVar = true;
         requestTokenBucketUpdated = true;
         rv = prefs->GetBoolPref(ALLOW_EXPERIMENTS, &cVar);
         if (NS_SUCCEEDED(rv)) {
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -312,16 +312,17 @@ public:
     PRIntervalTime GetPipelineRescheduleTimeout()
     {
         return mPipelineRescheduleTimeout;
     }
 
     PRIntervalTime GetPipelineTimeout()   { return mPipelineReadTimeout; }
 
     SpdyInformation *SpdyInfo() { return &mSpdyInfo; }
+    bool IsH2MandatorySuiteEnabled() { return mH2MandatorySuiteEnabled; }
 
     // returns true in between Init and Shutdown states
     bool Active() { return mHandlerActive; }
 
     // When the disk cache is responding slowly its use is suppressed
     // for 1 minute for most requests. Callable from main thread only.
     TimeStamp GetCacheSkippedUntil() { return mCacheSkippedUntil; }
     void SetCacheSkippedUntil(TimeStamp arg) { mCacheSkippedUntil = arg; }
@@ -380,16 +381,17 @@ private:
     PRIntervalTime mSpdyTimeout;
     PRIntervalTime mResponseTimeout;
     bool mResponseTimeoutEnabled;
     uint32_t mNetworkChangedTimeout; // milliseconds
     uint16_t mMaxRequestAttempts;
     uint16_t mMaxRequestDelay;
     uint16_t mIdleSynTimeout;
 
+    bool     mH2MandatorySuiteEnabled;
     bool     mPipeliningEnabled;
     uint16_t mMaxConnections;
     uint8_t  mMaxPersistentConnectionsPerServer;
     uint8_t  mMaxPersistentConnectionsPerProxy;
     uint16_t mMaxPipelinedRequests;
     uint16_t mMaxOptimisticPipelinedRequests;
     bool     mPipelineAggressive;
     int64_t  mMaxPipelineObjectSize;
--- a/netwerk/test/unit/test_http2.js
+++ b/netwerk/test/unit/test_http2.js
@@ -468,16 +468,33 @@ Http2PushApiListener.prototype = {
 function test_http2_pushapi_1() {
   var chan = makeChan("https://localhost:6944/pushapi1");
   chan.loadGroup = loadGroup;
   var listener = new Http2PushApiListener();
   chan.notificationCallbacks = listener;
   chan.asyncOpen(listener, chan);
 }
 
+var WrongSuiteListener = function() {};
+WrongSuiteListener.prototype = new Http2CheckListener();
+WrongSuiteListener.prototype.shouldBeHttp2 = false;
+WrongSuiteListener.prototype.onStopRequest = function(request, ctx, status) {
+  prefs.setBoolPref("security.ssl3.ecdhe_rsa_aes_128_gcm_sha256", true);
+  Http2CheckListener.prototype.onStopRequest.call(this);
+};
+
+// test that we use h1 without the mandatory cipher suite available
+function test_http2_wrongsuite() {
+  prefs.setBoolPref("security.ssl3.ecdhe_rsa_aes_128_gcm_sha256", false);
+  var chan = makeChan("https://localhost:6944/wrongsuite");
+  chan.loadFlags = Ci.nsIRequest.LOAD_FRESH_CONNECTION | Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
+  var listener = new WrongSuiteListener();
+  chan.asyncOpen(listener, null);
+}
+
 function test_http2_h11required_stream() {
   var chan = makeChan("https://localhost:6944/h11required_stream");
   var listener = new Http2CheckListener();
   listener.shouldBeHttp2 = false;
   chan.asyncOpen(listener, null);
 }
 
 function H11RequiredSessionListener () { }
@@ -534,16 +551,17 @@ var tests = [ test_http2_post_big
             , test_http2_multiplex
             , test_http2_big
             , test_http2_post
             , test_http2_pushapi_1
             // These next two must always come in this order
             , test_http2_h11required_stream
             , test_http2_h11required_session
             , test_http2_retry_rst
+            , test_http2_wrongsuite
 
             // cleanup
             , test_complete
             ];
 var current_test = 0;
 
 function run_next_test() {
   if (current_test < tests.length) {