[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