Bug 1283109 - Create a services client for augmenting the STS preload list between releases. r=leplatrem draft
authorMark Goodwin <mgoodwin@mozilla.com>
Wed, 21 Dec 2016 15:36:31 +0000
changeset 452306 ae9f58eea512c020ea96fe293c7825bbcc3ccf15
parent 452146 c36fbe84042debef0a5d58b7fc88185b401762ce
child 540207 6ac798e6ceaf203b3cd9630fdfd0e3a427e66b09
push id39383
push usermgoodwin@mozilla.com
push dateWed, 21 Dec 2016 15:38:13 +0000
reviewersleplatrem
bugs1283109
milestone53.0a1
Bug 1283109 - Create a services client for augmenting the STS preload list between releases. r=leplatrem MozReview-Commit-ID: H9zZpBwJRgi
services/common/blocklist-clients.js
services/common/tests/unit/test_blocklist_pinning.js
--- a/services/common/blocklist-clients.js
+++ b/services/common/blocklist-clients.js
@@ -276,23 +276,29 @@ function* updatePinningList(records) {
 
     // clear the current preload list
     siteSecurityService.clearPreloads();
 
     // write each KeyPin entry to the preload list
     for (let item of records) {
       try {
         const {pinType, pins=[], versions} = item;
-        if (pinType == "KeyPin" && pins.length &&
-            versions.indexOf(appInfo.version) != -1) {
-          siteSecurityService.setKeyPins(item.hostName,
-              item.includeSubdomains,
-              item.expires,
-              pins.length,
-              pins, true);
+        if (versions.indexOf(appInfo.version) != -1) {
+          if (pinType == "KeyPin" && pins.length) {
+            siteSecurityService.setKeyPins(item.hostName,
+                item.includeSubdomains,
+                item.expires,
+                pins.length,
+                pins, true);
+          }
+          if (pinType == "STSPin") {
+            siteSecurityService.setHSTSPreload(item.hostName,
+                                               item.includeSubdomains,
+                                               item.expires);
+          }
         }
       } catch (e) {
         // prevent errors relating to individual preload entries from causing
         // sync to fail. We will accumulate telemetry for such failures in bug
         // 1254099.
       }
     }
   } else {
--- a/services/common/tests/unit/test_blocklist_pinning.js
+++ b/services/common/tests/unit/test_blocklist_pinning.js
@@ -90,16 +90,17 @@ add_task(function* test_something(){
 
   let sss = Cc["@mozilla.org/ssservice;1"]
               .getService(Ci.nsISiteSecurityService);
 
   // ensure our pins are all missing before we start
   ok(!sss.isSecureHost(sss.HEADER_HPKP, "one.example.com", 0));
   ok(!sss.isSecureHost(sss.HEADER_HPKP, "two.example.com", 0));
   ok(!sss.isSecureHost(sss.HEADER_HPKP, "three.example.com", 0));
+  ok(!sss.isSecureHost(sss.HEADER_HSTS, "five.example.com", 0));
 
   // Test an empty db populates
   let result = yield PinningPreloadClient.maybeSync(2000, Date.now());
 
   let connection = yield FirefoxAdapter.openConnection({path: KINTO_STORAGE_PATH});
 
   // Open the collection, verify it's been populated:
   // Our test data has a single record; it should be in the local collection
@@ -109,20 +110,20 @@ add_task(function* test_something(){
 
   // check that a pin exists for one.example.com
   ok(sss.isSecureHost(sss.HEADER_HPKP, "one.example.com", 0));
 
   // Test the db is updated when we call again with a later lastModified value
   result = yield PinningPreloadClient.maybeSync(4000, Date.now());
 
   // Open the collection, verify it's been updated:
-  // Our data now has three new records; all should be in the local collection
+  // Our data now has four new records; all should be in the local collection
   collection = do_get_kinto_collection(connection, COLLECTION_NAME);
   list = yield collection.list();
-  do_check_eq(list.data.length, 4);
+  do_check_eq(list.data.length, 5);
   yield connection.close();
 
   // check that a pin exists for two.example.com and three.example.com
   ok(sss.isSecureHost(sss.HEADER_HPKP, "two.example.com", 0));
   ok(sss.isSecureHost(sss.HEADER_HPKP, "three.example.com", 0));
 
   // check that a pin does not exist for four.example.com - it's in the
   // collection but the version should not match
@@ -139,22 +140,31 @@ add_task(function* test_something(){
 
   // Check the pinning check time pref is modified, even if the collection
   // hasn't changed
   Services.prefs.setIntPref("services.blocklist.onecrl.checked", 0);
   yield PinningPreloadClient.maybeSync(3000, Date.now());
   let newValue = Services.prefs.getIntPref("services.blocklist.pinning.checked");
   do_check_neq(newValue, 0);
 
+  // Check that the HSTS preload added to the collection works...
+  ok(sss.isSecureHost(sss.HEADER_HSTS, "five.example.com", 0));
+  // ...and that includeSubdomains is honored
+  ok(!sss.isSecureHost(sss.HEADER_HSTS, "subdomain.five.example.com", 0));
+
   // Check that a sync completes even when there's bad data in the
   // collection. This will throw on fail, so just calling maybeSync is an
   // acceptible test (the data below with last_modified of 300 is nonsense).
   Services.prefs.setCharPref("services.settings.server",
                              `http://localhost:${server.identity.primaryPort}/v1`);
   yield PinningPreloadClient.maybeSync(5000, Date.now());
+
+  // The STS entry for five.example.com now has includeSubdomains set;
+  // ensure that the new includeSubdomains value is honored.
+  ok(sss.isSecureHost(sss.HEADER_HSTS, "subdomain.five.example.com", 0));
 });
 
 function run_test() {
   // Ensure that signature verification is disabled to prevent interference
   // with basic certificate sync tests
   Services.prefs.setBoolPref("services.blocklist.signing.enforced", false);
 
   // Set up an HTTP Server
@@ -250,16 +260,24 @@ function getSampleResponse(req, port) {
         "hostName": "four.example.com",
         "includeSubdomains": false,
         "expires": new Date().getTime() + 1000000,
         "pins" : ["cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
                   "M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE="],
         "versions" : ["some version that won't match"],
         "id":"dabafde9-df4a-ddba-2548-748da04cc02e",
         "last_modified":4000
+      },{
+        "pinType": "STSPin",
+        "hostName": "five.example.com",
+        "includeSubdomains": false,
+        "expires": new Date().getTime() + 1000000,
+        "versions" : [appInfo.version, "some version that won't match"],
+        "id":"dabafde9-df4a-ddba-2548-748da04cc032",
+        "last_modified":4000
       }]})
     },
     "GET:/v1/buckets/pinning/collections/pins/records?_sort=-last_modified&_since=4000": {
       "sampleHeaders": [
         "Access-Control-Allow-Origin: *",
         "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
         "Content-Type: application/json; charset=UTF-8",
         "Server: waitress",
@@ -284,15 +302,23 @@ function getSampleResponse(req, port) {
         "irrelevant":"this entry is missing the actual pins",
         "pinType": "KeyPin",
         "hostName": "missingpins.example.com",
         "includeSubdomains": false,
         "expires": new Date().getTime() + 1000000,
         "versions" : [appInfo.version],
         "id":"dabafde9-df4a-ddba-2548-748da04cc031",
         "last_modified":5000
+      },{
+        "pinType": "STSPin",
+        "hostName": "five.example.com",
+        "includeSubdomains": true,
+        "expires": new Date().getTime() + 1000000,
+        "versions" : [appInfo.version, "some version that won't match"],
+        "id":"dabafde9-df4a-ddba-2548-748da04cc032",
+        "last_modified":5000
       }]})
     }
   };
   return responses[`${req.method}:${req.path}?${req.queryString}`] ||
          responses[req.method];
 
 }