[tbb-commits] [tor-browser/tor-browser-45.2.0esr-6.5-1] Bug 1229284 - Remove support for SHA-1 hashes in genHPKPStaticPins.js. r=keeler

gk at torproject.org gk at torproject.org
Fri Jun 3 20:52:32 UTC 2016


commit 877657a30dd959d33921225260afe73d18aef977
Author: Cykesiopka <cykesiopka.bmo at gmail.com>
Date:   Thu Dec 17 07:52:00 2015 +0100

    Bug 1229284 - Remove support for SHA-1 hashes in genHPKPStaticPins.js. r=keeler
---
 security/manager/tools/genHPKPStaticPins.js | 104 +++++++++-------------------
 1 file changed, 32 insertions(+), 72 deletions(-)

diff --git a/security/manager/tools/genHPKPStaticPins.js b/security/manager/tools/genHPKPStaticPins.js
index c9e3472..8a91fff 100644
--- a/security/manager/tools/genHPKPStaticPins.js
+++ b/security/manager/tools/genHPKPStaticPins.js
@@ -10,6 +10,7 @@
 //                                  [absolute path to]/PreloadedHPKPins.json \
 //                                  [an unused argument - see bug 1205406] \
 //                                  [absolute path to]/StaticHPKPins.h
+"use strict";
 
 if (arguments.length != 3) {
   throw "Usage: genHPKPStaticPins.js " +
@@ -28,7 +29,6 @@ var gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
                 .getService(Ci.nsIX509CertDB);
 
 const BUILT_IN_NICK_PREFIX = "Builtin Object Token:";
-const SHA1_PREFIX = "sha1/";
 const SHA256_PREFIX = "sha256/";
 const GOOGLE_PIN_PREFIX = "GOOGLE_PIN_";
 
@@ -53,7 +53,7 @@ const DOMAINHEADER = "/* Domainlist */\n" +
   "  const bool mTestMode;\n" +
   "  const bool mIsMoz;\n" +
   "  const int32_t mId;\n" +
-  "  const StaticPinset *pinset;\n" +
+  "  const StaticPinset* pinset;\n" +
   "};\n\n";
 
 const PINSETDEF = "/* Pinsets are each an ordered list by the actual value of the fingerprint */\n" +
@@ -164,13 +164,13 @@ function getSKDFromPem(pem) {
 }
 
 /**
- * Hashes |input| using the SHA1 algorithm in the following manner:
- *   btoa(sha1(atob(input)))
+ * Hashes |input| using the SHA-256 algorithm in the following manner:
+ *   btoa(sha256(atob(input)))
  *
  * @argument {String} input Base64 string to decode and return the hash of.
- * @returns {String} Base64 encoded SHA1 hash.
+ * @returns {String} Base64 encoded SHA-256 hash.
  */
-function sha1Base64(input) {
+function sha256Base64(input) {
   let decodedValue;
   try {
     decodedValue = atob(input);
@@ -191,7 +191,7 @@ function sha1Base64(input) {
 
   let hasher = Cc["@mozilla.org/security/hash;1"]
                  .createInstance(Ci.nsICryptoHash);
-  hasher.init(hasher.SHA1);
+  hasher.init(hasher.SHA256);
   hasher.update(data, data.length);
 
   // true is passed so that the hasher returns a Base64 encoded string.
@@ -201,11 +201,11 @@ function sha1Base64(input) {
 // Downloads the static certs file and tries to map Google Chrome nicknames
 // to Mozilla nicknames, as well as storing any hashes for pins for which we
 // don't have root PEMs. Each entry consists of a line containing the name of
-// the pin followed either by a hash in the format "sha1/" + base64(hash), a
-// hash in the format "sha256/" + base64(hash), a PEM encoded public key, or
-// a PEM encoded certificate. For certificates that we have in our database,
+// the pin followed either by a hash in the format "sha256/" + base64(hash),
+// a PEM encoded public key, or a PEM encoded certificate.
+// For certificates that we have in our database,
 // return a map of Google's nickname to ours. For ones that aren't return a
-// map of Google's nickname to sha1 values. This code is modeled after agl's
+// map of Google's nickname to SHA-256 values. This code is modeled after agl's
 // https://github.com/agl/transport-security-state-generate, which doesn't
 // live in the Chromium repo because go is not an official language in
 // Chromium.
@@ -216,7 +216,7 @@ function sha1Base64(input) {
 // and stick the hash in certSKDToName
 // We MUST be able to find a corresponding cert nickname for the Chrome names,
 // otherwise we skip all pinsets referring to that Chrome name.
-function downloadAndParseChromeCerts(filename, certSKDToName) {
+function downloadAndParseChromeCerts(filename, certNameToSKD, certSKDToName) {
   // Prefixes that we care about.
   const BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
   const END_CERT = "-----END CERTIFICATE-----";
@@ -238,8 +238,7 @@ function downloadAndParseChromeCerts(filename, certSKDToName) {
   let chromeNameToHash = {};
   let chromeNameToMozName = {};
   let chromeName;
-  for (let i = 0; i < lines.length; ++i) {
-    let line = lines[i];
+  for (let line of lines) {
     // Skip comments and newlines.
     if (line.length == 0 || line[0] == '#') {
       continue;
@@ -250,18 +249,9 @@ function downloadAndParseChromeCerts(filename, certSKDToName) {
         state = POST_NAME;
         break;
       case POST_NAME:
-        // TODO(bug 1229284): Chromium no longer uses SHA1 hashes, so remove
-        // code like this supporting SHA1.
-        if (line.startsWith(SHA1_PREFIX) ||
-            line.startsWith(SHA256_PREFIX)) {
-          if (line.startsWith(SHA1_PREFIX)) {
-            hash = line.substring(SHA1_PREFIX.length);
-          } else if (line.startsWith(SHA256_PREFIX)) {
-            hash = line.substring(SHA256_PREFIX.length);
-          }
-          // Store the entire prefixed hash, so we can disambiguate sha1 from
-          // sha256 later.
-          chromeNameToHash[chromeName] = line;
+        if (line.startsWith(SHA256_PREFIX)) {
+          hash = line.substring(SHA256_PREFIX.length);
+          chromeNameToHash[chromeName] = hash;
           certNameToSKD[chromeName] = hash;
           certSKDToName[hash] = chromeName;
           state = PRE_NAME;
@@ -298,12 +288,9 @@ function downloadAndParseChromeCerts(filename, certSKDToName) {
       case IN_PUB_KEY:
         if (line.startsWith(END_PUB_KEY)) {
           state = PRE_NAME;
-          // TODO(bug 1229284): Switch to SHA-256 instead. SHA1 is used here
-          // mainly to confirm that the changes made to support public keys are
-          // correct and don't change any hashes.
-          hash = sha1Base64(pemPubKey);
+          hash = sha256Base64(pemPubKey);
           pemPubKey = "";
-          chromeNameToHash[chromeName] = SHA1_PREFIX + hash;
+          chromeNameToHash[chromeName] = hash;
           certNameToSKD[chromeName] = hash;
           certSKDToName[hash] = chromeName;
         } else {
@@ -325,7 +312,6 @@ function downloadAndParseChromeCerts(filename, certSKDToName) {
 // {
 //   pinset_name : {
 //     // Array of names with entries in certNameToSKD
-//     sha1_hashes: [],
 //     sha256_hashes: []
 //   }
 // }
@@ -344,20 +330,13 @@ function downloadAndParseChromePins(filename,
 
   chromePins.forEach(function(pin) {
     let valid = true;
-    let pinset = { name: pin.name, sha1_hashes: [], sha256_hashes: [] };
+    let pinset = { name: pin.name, sha256_hashes: [] };
     // Translate the Chrome pinset format to ours
     pin.static_spki_hashes.forEach(function(name) {
       if (name in chromeNameToHash) {
         let hash = chromeNameToHash[name];
-        if (hash.startsWith(SHA1_PREFIX)) {
-          hash = hash.substring(SHA1_PREFIX.length);
-          pinset.sha1_hashes.push(certSKDToName[hash]);
-        } else if (hash.startsWith(SHA256_PREFIX)) {
-          hash = hash.substring(SHA256_PREFIX.length);
-          pinset.sha256_hashes.push(certSKDToName[hash]);
-        } else {
-          throw("Unsupported hash type: " + chromeNameToHash[name]);
-        }
+        pinset.sha256_hashes.push(certSKDToName[hash]);
+
         // We should have already added hashes for all of these when we
         // imported the certificate file.
         if (!certNameToSKD[name]) {
@@ -478,26 +457,18 @@ function genExpirationTime() {
 }
 
 function writeFullPinset(certNameToSKD, certSKDToName, pinset) {
-  // We aren't guaranteed to have sha1 hashes in our own imported pins.
   let prefix = "kPinset_" + pinset.name;
-  let sha1Name = "nullptr";
-  let sha256Name = "nullptr";
-  if (pinset.sha1_hashes && pinset.sha1_hashes.length > 0) {
-    writeFingerprints(certNameToSKD, certSKDToName, pinset.name,
-                      pinset.sha1_hashes, "sha1");
-    sha1Name = "&" + prefix + "_sha1";
-  }
-  if (pinset.sha256_hashes && pinset.sha256_hashes.length > 0) {
-    writeFingerprints(certNameToSKD, certSKDToName, pinset.name,
-                      pinset.sha256_hashes, "sha256");
-    sha256Name = "&" + prefix + "_sha256";
+  if (!pinset.sha256_hashes || pinset.sha256_hashes.length == 0) {
+    throw `ERROR: Pinset ${pinset.name} does not contain any hashes.`;
   }
+  writeFingerprints(certNameToSKD, certSKDToName, pinset.name,
+                    pinset.sha256_hashes);
   writeString("static const StaticPinset " + prefix + " = {\n" +
-          "  " + sha1Name + ",\n  " + sha256Name + "\n};\n\n");
+              "  nullptr,\n  &" + prefix + "_sha256\n};\n\n");
 }
 
-function writeFingerprints(certNameToSKD, certSKDToName, name, hashes, type) {
-  let varPrefix = "kPinset_" + name + "_" + type;
+function writeFingerprints(certNameToSKD, certSKDToName, name, hashes) {
+  let varPrefix = "kPinset_" + name + "_sha256";
   writeString("static const char* " + varPrefix + "_Data[] = {\n");
   let SKDList = [];
   for (let certName of hashes) {
@@ -595,23 +566,12 @@ function writeFile(certNameToSKD, certSKDToName,
   let mozillaPins = {};
   gStaticPins.pinsets.forEach(function(pinset) {
     mozillaPins[pinset.name] = true;
-    // We aren't guaranteed to have sha1_hashes in our own JSON.
-    if (pinset.sha1_hashes) {
-      pinset.sha1_hashes.forEach(function(name) {
-        usedFingerprints[name] = true;
-      });
-    }
-    if (pinset.sha256_hashes) {
-      pinset.sha256_hashes.forEach(function(name) {
-        usedFingerprints[name] = true;
-      });
-    }
+    pinset.sha256_hashes.forEach(function (name) {
+      usedFingerprints[name] = true;
+    });
   });
   for (let key in chromeImportedPinsets) {
     let pinset = chromeImportedPinsets[key];
-    pinset.sha1_hashes.forEach(function(name) {
-      usedFingerprints[name] = true;
-    });
     pinset.sha256_hashes.forEach(function(name) {
       usedFingerprints[name] = true;
     });
@@ -663,7 +623,7 @@ function loadExtraCertificates(certStringList) {
 var extraCertificates = loadExtraCertificates(gStaticPins.extra_certificates);
 var [ certNameToSKD, certSKDToName ] = loadNSSCertinfo(extraCertificates);
 var [ chromeNameToHash, chromeNameToMozName ] = downloadAndParseChromeCerts(
-  gStaticPins.chromium_data.cert_file_url, certSKDToName);
+  gStaticPins.chromium_data.cert_file_url, certNameToSKD, certSKDToName);
 var [ chromeImportedPinsets, chromeImportedEntries ] =
   downloadAndParseChromePins(gStaticPins.chromium_data.json_file_url,
     chromeNameToHash, chromeNameToMozName, certNameToSKD, certSKDToName);





More information about the tbb-commits mailing list