Bug 1316283 - Isolate SSL session cache by origin attributes. r=keeler
authorJonathan Hao <jhao@mozilla.com>
Fri, 25 Nov 2016 20:07:57 +0800
changeset 324580 9aba8184664ddfca0ae5c95d9ab5f7e8daab049e
parent 324579 2e51142370f3412d4db29ef10b8e09d665a06052
child 324581 08264c30352ddcb6c2c98b5def210fbfac6fc983
push id31008
push usercbook@mozilla.com
push dateTue, 29 Nov 2016 15:46:11 +0000
treeherdermozilla-central@9694bdce7680 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler
bugs1316283
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1316283 - Isolate SSL session cache by origin attributes. r=keeler
security/manager/ssl/nsNSSIOLayer.cpp
security/manager/ssl/tests/unit/head_psm.js
security/manager/ssl/tests/unit/test_session_resumption.js
security/nss.symbols
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -2561,16 +2561,19 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, b
     peerId.AppendLiteral("private:");
   }
   if (flags & nsISocketProvider::MITM_OK) {
     peerId.AppendLiteral("bypassAuth:");
   }
   peerId.Append(host);
   peerId.Append(':');
   peerId.AppendInt(port);
+  nsAutoCString suffix;
+  infoObject->GetOriginAttributes().CreateSuffix(suffix);
+  peerId.Append(suffix);
   if (SECSuccess != SSL_SetSockPeerID(fd, peerId.get())) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -204,34 +204,36 @@ function checkCertErrorGeneric(certdb, c
 
 function checkEVStatus(certDB, cert, usage, isEVExpected) {
   let hasEVPolicy = {};
   checkCertErrorGeneric(certDB, cert, PRErrorCodeSuccess, usage, hasEVPolicy);
   Assert.equal(hasEVPolicy.value, isEVExpected,
                "Actual and expected EV status should match");
 }
 
-function _getLibraryFunctionWithNoArguments(functionName, libraryName) {
+function _getLibraryFunctionWithNoArguments(functionName, libraryName,
+                                            returnType) {
   // Open the NSS library. copied from services/crypto/modules/WeaveCrypto.js
   let path = ctypes.libraryName(libraryName);
 
   // XXX really want to be able to pass specific dlopen flags here.
   let nsslib;
   try {
     nsslib = ctypes.open(path);
   } catch (e) {
     // In case opening the library without a full path fails,
     // try again with a full path.
     let file = Services.dirsvc.get("GreBinD", Ci.nsILocalFile);
     file.append(path);
     nsslib = ctypes.open(file.path);
   }
 
   let SECStatus = ctypes.int;
-  let func = nsslib.declare(functionName, ctypes.default_abi, SECStatus);
+  let func = nsslib.declare(functionName, ctypes.default_abi,
+                            returnType || SECStatus);
   return func;
 }
 
 function clearOCSPCache() {
   let certdb = Cc["@mozilla.org/security/x509certdb;1"]
                  .getService(Ci.nsIX509CertDB);
   certdb.clearOCSPCache();
 }
@@ -246,16 +248,49 @@ function clearSessionCache() {
     SSL_ClearSessionCache =
       _getLibraryFunctionWithNoArguments("SSL_ClearSessionCache", "nss3");
   }
   if (!SSL_ClearSessionCache || SSL_ClearSessionCache() != 0) {
     throw new Error("Failed to clear SSL session cache");
   }
 }
 
+function getSSLStatistics() {
+  let SSL3Statistics = new ctypes.StructType("SSL3Statistics",
+                           [ { "sch_sid_cache_hits": ctypes.long },
+                             { "sch_sid_cache_misses": ctypes.long },
+                             { "sch_sid_cache_not_ok": ctypes.long },
+                             { "hsh_sid_cache_hits": ctypes.long },
+                             { "hsh_sid_cache_misses": ctypes.long },
+                             { "hsh_sid_cache_not_ok": ctypes.long },
+                             { "hch_sid_cache_hits": ctypes.long },
+                             { "hch_sid_cache_misses": ctypes.long },
+                             { "hch_sid_cache_not_ok": ctypes.long },
+                             { "sch_sid_stateless_resumes": ctypes.long },
+                             { "hsh_sid_stateless_resumes": ctypes.long },
+                             { "hch_sid_stateless_resumes": ctypes.long },
+                             { "hch_sid_ticket_parse_failures": ctypes.long }]);
+  let SSL3StatisticsPtr = new ctypes.PointerType(SSL3Statistics);
+  let SSL_GetStatistics = null;
+  try {
+    SSL_GetStatistics = _getLibraryFunctionWithNoArguments("SSL_GetStatistics",
+                                                           "ssl3",
+                                                           SSL3StatisticsPtr);
+  } catch(e) {
+    // On Windows, this is actually in the nss3 library.
+    SSL_GetStatistics = _getLibraryFunctionWithNoArguments("SSL_GetStatistics",
+                                                           "nss3",
+                                                           SSL3StatisticsPtr);
+  }
+  if (!SSL_GetStatistics) {
+    throw new Error("Failed to get SSL statistics");
+  }
+  return SSL_GetStatistics();
+}
+
 // Set up a TLS testing environment that has a TLS server running and
 // ready to accept connections. This async function starts the server and
 // waits for the server to indicate that it is ready.
 //
 // Each test should have its own subdomain of example.com, for example
 // my-first-connection-test.example.com. The server can use the server
 // name (passed through the SNI TLS extension) to determine what behavior
 // the server side of the text should exhibit. See TLSServer.h for more
--- a/security/manager/ssl/tests/unit/test_session_resumption.js
+++ b/security/manager/ssl/tests/unit/test_session_resumption.js
@@ -104,14 +104,56 @@ function add_resume_ev_test() {
   // nothing clears the TLS cache in between these two operations.
   add_one_ev_test();
 
   add_test(() => {
     ocspResponder.stop(run_next_test);
   });
 }
 
+const statsPtr = getSSLStatistics();
+const toInt32 = ctypes.Int64.lo;
+const GOOD_DOMAIN = "good.include-subdomains.pinning.example.com";
+
+// Connect to the same domain with two origin attributes and check if any ssl
+// session is resumed.
+function add_origin_attributes_test(originAttributes1, originAttributes2,
+                                    resumeExpected) {
+  add_connection_test(GOOD_DOMAIN, PRErrorCodeSuccess, clearSessionCache, null,
+                      null, originAttributes1);
+
+  let hitsBeforeConnect;
+  let missesBeforeConnect;
+  let expectedHits = resumeExpected ? 1 : 0;
+  let expectedMisses = 1 - expectedHits;
+
+  add_connection_test(GOOD_DOMAIN, PRErrorCodeSuccess,
+                      function() {
+                        // Add the hits and misses before connection.
+                        let stats = statsPtr.contents;
+                        hitsBeforeConnect = toInt32(stats.sch_sid_cache_hits);
+                        missesBeforeConnect =
+                          toInt32(stats.sch_sid_cache_misses);
+                      },
+                      function() {
+                        let stats = statsPtr.contents;
+                        equal(toInt32(stats.sch_sid_cache_hits),
+                              hitsBeforeConnect + expectedHits,
+                              "Unexpected cache hits");
+                        equal(toInt32(stats.sch_sid_cache_misses),
+                              missesBeforeConnect + expectedMisses,
+                              "Unexpected cache misses");
+                      }, null, originAttributes2);
+}
+
 function run_test() {
   add_tls_server_setup("BadCertServer", "bad_certs");
   add_resume_non_ev_with_override_test();
   add_resume_ev_test();
+  add_origin_attributes_test({}, {}, true);
+  add_origin_attributes_test({ userContextId: 1 }, { userContextId: 2 }, false);
+  add_origin_attributes_test({ userContextId: 3 }, { userContextId: 3 }, true);
+  add_origin_attributes_test({ firstPartyDomain: "foo.com" },
+                             { firstPartyDomain: "bar.com" }, false);
+  add_origin_attributes_test({ firstPartyDomain: "baz.com" },
+                             { firstPartyDomain: "baz.com" }, true);
   run_next_test();
 }
--- a/security/nss.symbols
+++ b/security/nss.symbols
@@ -664,16 +664,17 @@ SSL_ExportKeyingMaterial
 SSL_ForceHandshake
 SSL_GetChannelInfo
 SSL_GetCipherSuiteInfo
 SSL_GetClientAuthDataHook
 SSL_GetImplementedCiphers
 SSL_GetNextProto
 SSL_GetNumImplementedCiphers
 SSL_GetSRTPCipher
+SSL_GetStatistics
 SSL_HandshakeCallback
 SSL_HandshakeNegotiatedExtension
 SSL_ImplementedCiphers @DATA@
 SSL_ImportFD
 SSL_NamedGroupConfig
 SSL_NumImplementedCiphers @DATA@
 SSL_OptionSet
 SSL_OptionSetDefault