Bug 772756: Implement sha1 support, import Chrome's pinsets wholesale, add test mode (r=cviecco,keeler)

This commit is contained in:
Monica Chew 2014-05-08 17:18:50 -07:00
parent cd1bc582ed
commit d1eb9b420d
13 changed files with 1239 additions and 255 deletions

View File

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PublicKeyPinningService.h"
#include "pkix/nullptr.h"
#include "StaticHPKPins.h" // autogenerated by genHPKPStaticpins.js
#include "cert.h"
@ -29,11 +30,12 @@ PRLogModuleInfo* gPublicKeyPinningLog =
of the DER Encoded subject Public Key Info for the given cert
*/
static SECStatus
GetBase64SHA256SPKI(const CERTCertificate* cert,
nsACString& aSha256SPKIDigest){
aSha256SPKIDigest.Truncate();
GetBase64HashSPKI(const CERTCertificate* cert, SECOidTag hashType,
nsACString& hashSPKIDigest)
{
hashSPKIDigest.Truncate();
Digest digest;
nsresult rv = digest.DigestBuf(SEC_OID_SHA256, cert->derPublicKey.data,
nsresult rv = digest.DigestBuf(hashType, cert->derPublicKey.data,
cert->derPublicKey.len);
if (NS_WARN_IF(NS_FAILED(rv))) {
return SECFailure;
@ -41,59 +43,100 @@ GetBase64SHA256SPKI(const CERTCertificate* cert,
rv = Base64Encode(nsDependentCSubstring(
reinterpret_cast<const char*>(digest.get().data),
digest.get().len),
aSha256SPKIDigest);
hashSPKIDigest);
if (NS_WARN_IF(NS_FAILED(rv))) {
return SECFailure;
}
return SECSuccess;
}
/**
* Given a Pinset and certlist ensure that there is intersection between them
/*
* Returns true if a given cert matches any hashType fingerprints from the
* given pinset, false otherwise.
*/
static bool
EvalPinWithPinset(const CERTCertList* certList, const StaticPinset* pinSet) {
SECStatus srv;
CERTCertificate* currentCert;
EvalCertWithHashType(const CERTCertificate* cert, SECOidTag hashType,
const StaticFingerprints* fingerprints)
{
if (!fingerprints) {
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: No hashes found for hash type: %d\n", hashType));
return false;
}
nsAutoCString base64Out;
SECStatus srv = GetBase64HashSPKI(cert, hashType, base64Out);
if (srv != SECSuccess) {
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: GetBase64HashSPKI failed!\n"));
return false;
}
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: base_64(hash(key)='%s'\n", base64Out.get()));
for (size_t i = 0; i < fingerprints->size; i++) {
if (base64Out.Equals(fingerprints->data[i])) {
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: found pin base_64(hash(key)='%s'\n", base64Out.get()));
return true;
}
}
return false;
}
/*
* Returns true if a given chain matches any hashType fingerprints from the
* given pinset, false otherwise.
*/
static bool
EvalChainWithHashType(const CERTCertList* certList, SECOidTag hashType,
const StaticPinset* pinset)
{
CERTCertificate* currentCert;
const StaticFingerprints* fingerprints = nullptr;
if (hashType == SEC_OID_SHA256) {
fingerprints = pinset->sha256;
} else if (hashType == SEC_OID_SHA1) {
fingerprints = pinset->sha1;
}
if (!fingerprints) {
return false;
}
CERTCertListNode* node;
for (node = CERT_LIST_HEAD(certList);
!CERT_LIST_END(node, certList);
for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
node = CERT_LIST_NEXT(node)) {
currentCert = node->cert;
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: certArray subject: '%s'\n",
currentCert->subjectName));
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: certArray common_name: '%s'\n",
CERT_GetCommonName(&(currentCert->issuer))));
// I only need sha256fp for builtins (so far)
srv = GetBase64SHA256SPKI(currentCert, base64Out);
if (srv != SECSuccess) {
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: GetBase64SHA256SPKI failed!\n"));
return false;
}
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: base_64(hash(key)='%s'\n", base64Out.get()));
// Compare, linear search for now...
for (size_t j = 0; j < pinSet->size; j++){
if (base64Out.Equals(pinSet->data[j])) {
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: found pin base_64(hash(key)='%s'\n", base64Out.get()));
return true;
}
if (EvalCertWithHashType(currentCert, hashType, fingerprints)) {
return true;
}
}
// We found no intersection, we must fail!
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG, ("pkpin: end of evaluation!\n"));
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG, ("pkpin: no matches found\n"));
return false;
}
/**
* Given a pinset and certlist, return true if one of the certificates on
* the list matches a fingerprint in the pinset, false otherwise.
*/
static bool
EvalChainWithPinset(const CERTCertList* certList,
const StaticPinset* pinset) {
// SHA256 is more trustworthy, try that first.
if (EvalChainWithHashType(certList, SEC_OID_SHA256, pinset)) {
return true;
}
return EvalChainWithHashType(certList, SEC_OID_SHA1, pinset);
}
/**
Comparator for the is public key pinned host.
*/
@ -126,8 +169,7 @@ CheckPinsForHostname(const CERTCertList *certList, const char *hostname,
// Notice how the (xx = strchr) prevents pins for unqualified domain names.
while (!foundEntry && (evalPart = strchr(evalHost, '.'))) {
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: Iteration Querying for pinning for host: '%s'\n",
evalHost));
("pkpin: Querying pinsets for host: '%s'\n", evalHost));
foundEntry = (TransportSecurityPreload *)bsearch(evalHost,
kPublicKeyPinningPreloadList,
kPublicKeyPinningPreloadListLength,
@ -135,21 +177,30 @@ CheckPinsForHostname(const CERTCertList *certList, const char *hostname,
TransportSecurityPreloadCompare);
if (foundEntry) {
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: iteration found pinning for host: '%s'\n", evalHost));
("pkpin: Found pinset for host: '%s'\n", evalHost));
if (evalHost != hostname) {
if (false == foundEntry->mIncludeSubdomains) {
// Does not apply to this host, contninue iterating
if (!foundEntry->mIncludeSubdomains) {
// Does not apply to this host, continue iterating
foundEntry = nullptr;
}
}
} else {
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: Didn't find pinset for host: '%s'\n", evalHost));
}
evalHost = evalPart;
// Advance past the '.'
evalHost++;
} // end while
// Add one for '.'
evalHost = evalPart + 1;
}
if (foundEntry && foundEntry->pinset) {
bool result = EvalPinWithPinset(certList, foundEntry->pinset);
bool result = EvalChainWithPinset(certList, foundEntry->pinset);
if (foundEntry->mTestMode) {
// TODO: Accumulate telemetry in test mode.
PR_LOG(gPublicKeyPinningLog, PR_LOG_DEBUG,
("pkpin: Skipping test mode evaluation for host: '%s'\n",
evalHost));
return true;
}
Telemetry::Accumulate(Telemetry::CERT_PINNING_EVALUATION_RESULTS,
result ? 1 : 0);
return result;

View File

@ -7,146 +7,771 @@
/* PublicKeyPinningService.cpp, you shouldn't be #including it. */
/*****************************************************************************/
#include <stdint.h>
/* AddTrust External Root */
static const char kAddTrust_External_RootFingerprint[] =
"lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=";
/* AddTrust Low-Value Services Root */
static const char kAddTrust_Low_Value_Services_RootFingerprint[] =
"BStocQfshOhzA4JFLsKidFF0XXSFpX1vRk4Np6G2ryo=";
/* AddTrust Public Services Root */
static const char kAddTrust_Public_Services_RootFingerprint[] =
"OGHXtpYfzbISBFb/b8LrdwSxp0G0vZM6g3b14ZFcppg=";
/* AddTrust Qualified Certificates Root */
static const char kAddTrust_Qualified_Certificates_RootFingerprint[] =
"xzr8Lrp3DQy8HuQfJStS6Kk9ErctzOwDHY2DnL+Bink=";
/* Baltimore CyberTrust Root */
static const char kBaltimore_CyberTrust_RootFingerprint[]=
static const char kBaltimore_CyberTrust_RootFingerprint[] =
"Y9mvm0exBk1JoQ57f9Vm28jKo5lFm/woKcVxrYxu80o=";
/* COMODO Certification Authority */
static const char kCOMODO_Certification_AuthorityFingerprint[] =
"AG1751Vd2CAmRCxPGieoDomhmJy4ezREjtIZTBgZbV4=";
/* Comodo AAA Services root */
static const char kComodo_AAA_Services_rootFingerprint[] =
"vRU+17BDT2iGsXvOi76E7TQMcTLXAqj0+jGPdW7L1vM=";
/* Comodo Secure Services root */
static const char kComodo_Secure_Services_rootFingerprint[] =
"RpHL/ehKa2BS3b4VK7DCFq4lqG5XR4E9vA8UfzOFcL4=";
/* Comodo Trusted Services root */
static const char kComodo_Trusted_Services_rootFingerprint[] =
"4tiR77c4ZpEF1TDeXtcuKyrD9KZweLU0mz/ayklvXrg=";
/* DigiCert Assured ID Root CA */
static const char kDigiCert_Assured_ID_Root_CAFingerprint[]=
static const char kDigiCert_Assured_ID_Root_CAFingerprint[] =
"I/Lt/z7ekCWanjD0Cvj5EqXls2lOaThEA0H2Bg4BT/o=";
/* DigiCert Global Root CA */
static const char kDigiCert_Global_Root_CAFingerprint[]=
static const char kDigiCert_Global_Root_CAFingerprint[] =
"r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=";
/* DigiCert High Assurance EV Root CA */
static const char kDigiCert_High_Assurance_EV_Root_CAFingerprint[]=
static const char kDigiCert_High_Assurance_EV_Root_CAFingerprint[] =
"WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=";
/* End Entity Test Cert */
static const char kEnd_Entity_Test_CertFingerprint[]=
"sEIYDccDj1ULE64YxhvqV7ASqc2qfIofVyArzg+62hU=";
static const char kEnd_Entity_Test_CertFingerprint[] =
"a08RrXscTn7kKTSPR8uZVrmc0o3ryPd+o3menqJHJBw=";
/* Entrust Root Certification Authority */
static const char kEntrust_Root_Certification_AuthorityFingerprint[] =
"bb+uANN7nNc/j7R95lkXrwDg3d9C286sIMF8AnXuIJU=";
/* Entrust.net Premium 2048 Secure Server CA */
static const char kEntrust_net_Premium_2048_Secure_Server_CAFingerprint[] =
"HqPF5D7WbC2imDpCpKebHpBnhs6fG1hiFBmgBGOofTg=";
/* Entrust.net Secure Server CA */
static const char kEntrust_net_Secure_Server_CAFingerprint[] =
"nsxRNo6G40YPZsKV5JQt1TCA8nseQQr/LRqp1Oa8fnw=";
/* GOOGLE_PIN_AlphaSSL_G2 */
static const char kGOOGLE_PIN_AlphaSSL_G2Fingerprint[] =
"yxgiWGK++SFB9ySwt3M3qpn5HO0ZLFY5D+h+G/vcT/c=";
/* GOOGLE_PIN_CryptoCat1 */
static const char kGOOGLE_PIN_CryptoCat1Fingerprint[] =
"vKaqtTLWmVuXPVJE+0OqN5sRc4VCcSQHI/W3XTDVR24=";
/* GOOGLE_PIN_Entrust_G2 */
static const char kGOOGLE_PIN_Entrust_G2Fingerprint[] =
"du6FkDdMcVQ3u8prumAo6t3i3G27uMP2EOhR8R0at/U=";
/* GOOGLE_PIN_Libertylavabitcom */
static const char kGOOGLE_PIN_LibertylavabitcomFingerprint[] =
"WnKzsDXgqPtS1KvtImrhQPqcxfpmfssuI2cSJt4LMks=";
/* GOOGLE_PIN_RapidSSL */
static const char kGOOGLE_PIN_RapidSSLFingerprint[] =
"lT09gPUeQfbYrlxRtpsHrjDblj9Rpz+u7ajfCrg4qDM=";
/* GOOGLE_PIN_Tor2web */
static const char kGOOGLE_PIN_Tor2webFingerprint[] =
"99ogQzjMuUTBkG1ZP7FME0K4kvBEti8Buzu4nZjRItM=";
/* GTE CyberTrust Global Root */
static const char kGTE_CyberTrust_Global_RootFingerprint[] =
"EGn6R6CqT4z3ERscrqNl7q7RC//zJmDe9uBhS/rnCHU=";
/* GeoTrust Global CA */
static const char kGeoTrust_Global_CAFingerprint[]=
static const char kGeoTrust_Global_CAFingerprint[] =
"h6801m+z8v3zbgkRHpq6L29Esgfzhj89C1SyUCOQmqU=";
/* GeoTrust Global CA 2 */
static const char kGeoTrust_Global_CA_2Fingerprint[]=
static const char kGeoTrust_Global_CA_2Fingerprint[] =
"F3VaXClfPS1y5vAxofB/QAxYi55YKyLxfq4xoVkNEYU=";
/* GeoTrust Primary Certification Authority */
static const char kGeoTrust_Primary_Certification_AuthorityFingerprint[]=
static const char kGeoTrust_Primary_Certification_AuthorityFingerprint[] =
"SQVGZiOrQXi+kqxcvWWE96HhfydlLVqFr4lQTqI5qqo=";
/* GeoTrust Primary Certification Authority - G2 */
static const char kGeoTrust_Primary_Certification_Authority___G2Fingerprint[]=
static const char kGeoTrust_Primary_Certification_Authority___G2Fingerprint[] =
"vPtEqrmtAhAVcGtBIep2HIHJ6IlnWQ9vlK50TciLePs=";
/* GeoTrust Primary Certification Authority - G3 */
static const char kGeoTrust_Primary_Certification_Authority___G3Fingerprint[]=
static const char kGeoTrust_Primary_Certification_Authority___G3Fingerprint[] =
"q5hJUnat8eyv8o81xTBIeB5cFxjaucjmelBPT2pRMo8=";
/* GeoTrust Universal CA */
static const char kGeoTrust_Universal_CAFingerprint[]=
static const char kGeoTrust_Universal_CAFingerprint[] =
"lpkiXF3lLlbN0y3y6W0c/qWqPKC7Us2JM8I7XCdEOCA=";
/* GeoTrust Universal CA 2 */
static const char kGeoTrust_Universal_CA_2Fingerprint[]=
static const char kGeoTrust_Universal_CA_2Fingerprint[] =
"fKoDRlEkWQxgHlZ+UhSOlSwM/+iQAFMP4NlbbVDqrkE=";
/* GlobalSign Root CA */
static const char kGlobalSign_Root_CAFingerprint[] =
"K87oWBWM9UZfyddvDfoxL+8lpNyoUB2ptGtn0fv6G2Q=";
/* GlobalSign Root CA - R2 */
static const char kGlobalSign_Root_CA___R2Fingerprint[] =
"iie1VXtL7HzAMF+/PVPR9xzT80kQxdZeJ+zduCB3uj0=";
/* GlobalSign Root CA - R3 */
static const char kGlobalSign_Root_CA___R3Fingerprint[] =
"cGuxAXyFXFkWm61cF4HPWX8S0srS9j0aSqN0k4AP+4A=";
/* GoogleBackup2048 */
static const char kGoogleBackup2048Fingerprint[] =
"vq7OyjSnqOco9nyMCDGdy77eijM=";
/* GoogleG2 */
static const char kGoogleG2Fingerprint[] =
"Q9rWMO5T+KmAym79hfRqo3mQ4Oo=";
/* TestSPKI */
static const char kTestSPKIFingerprint[] =
"AAAAAAAAAAAAAAAAAAAAAAAAAAA=";
/* Tor1 */
static const char kTor1Fingerprint[] =
"juNxSTv9UANmpC9kF5GKpmWNx3Y=";
/* Tor2 */
static const char kTor2Fingerprint[] =
"lia43lPolzSPVIq34Dw57uYcLD8=";
/* Tor3 */
static const char kTor3Fingerprint[] =
"rzEyQIKOh77j87n5bjWUNguXF8Y=";
/* Twitter1 */
static const char kTwitter1Fingerprint[] =
"Vv7zwhR9TtOIN/29MFI4cgHld40=";
/* UTN DATACorp SGC Root CA */
static const char kUTN_DATACorp_SGC_Root_CAFingerprint[] =
"QAL80xHQczFWfnG82XHkYEjI3OjRZZcRdTs9qiommvo=";
/* UTN USERFirst Email Root CA */
static const char kUTN_USERFirst_Email_Root_CAFingerprint[] =
"Laj56jRU0hFGRko/nQKNxMf7tXscUsc8KwVyovWZotM=";
/* UTN USERFirst Hardware Root CA */
static const char kUTN_USERFirst_Hardware_Root_CAFingerprint[] =
"TUDnr0MEoJ3of7+YliBMBVFB4/gJsv5zO7IxD9+YoWI=";
/* UTN USERFirst Object Root CA */
static const char kUTN_USERFirst_Object_Root_CAFingerprint[] =
"D+FMJksXu28NZT56cOs2Pb9UvhWAOe3a5cJXEd9IwQM=";
/* VeriSign Class 3 Public Primary Certification Authority - G4 */
static const char kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint[]=
static const char kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint[] =
"UZJDjsNp1+4M5x9cbbdflB779y5YRBcV6Z6rBMLIrO4=";
/* VeriSign Class 3 Public Primary Certification Authority - G5 */
static const char kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint[]=
static const char kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint[] =
"JbQbUG5JMJUoI6brnx0x3vZF6jilxsapbXGVfjhN8Fg=";
/* VeriSign Universal Root Certification Authority */
static const char kVeriSign_Universal_Root_Certification_AuthorityFingerprint[]=
static const char kVeriSign_Universal_Root_Certification_AuthorityFingerprint[] =
"lnsM2T/O9/J84sJFdnrpsFp3awZJ+ZZbYpCWhGloaHI=";
/* Verisign Class 1 Public Primary Certification Authority */
static const char kVerisign_Class_1_Public_Primary_Certification_AuthorityFingerprint[] =
"LclHC+Y+9KzxvYKGCUArt7h72ZY4pkOTTohoLRvowwg=";
/* Verisign Class 1 Public Primary Certification Authority - G3 */
static const char kVerisign_Class_1_Public_Primary_Certification_Authority___G3Fingerprint[]=
static const char kVerisign_Class_1_Public_Primary_Certification_Authority___G3Fingerprint[] =
"IgduWu9Eu5pBaii30cRDItcFn2D+/6XK9sW+hEeJEwM=";
/* Verisign Class 2 Public Primary Certification Authority - G2 */
static const char kVerisign_Class_2_Public_Primary_Certification_Authority___G2Fingerprint[] =
"2oALgLKofTmeZvoZ1y/fSZg7R9jPMix8eVA6DH4o/q8=";
/* Verisign Class 2 Public Primary Certification Authority - G3 */
static const char kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint[]=
static const char kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint[] =
"cAajgxHlj7GTSEIzIYIQxmEloOSoJq7VOaxWHfv72QM=";
/* Verisign Class 3 Public Primary Certification Authority */
static const char kVerisign_Class_3_Public_Primary_Certification_AuthorityFingerprint[] =
"sRJBQqWhpaKIGcc1NA7/jJ4vgWj+47oYfyU7waOS1+I=";
/* Verisign Class 3 Public Primary Certification Authority - G2 */
static const char kVerisign_Class_3_Public_Primary_Certification_Authority___G2Fingerprint[] =
"AjyBzOjnxk+pQtPBUEhwfTXZu1uH9PVExb8bxWQ68vo=";
/* Verisign Class 3 Public Primary Certification Authority - G3 */
static const char kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint[]=
static const char kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint[] =
"SVqWumuteCQHvVIaALrOZXuzVVVeS7f4FGxxu6V+es4=";
/* Verisign Class 4 Public Primary Certification Authority - G3 */
static const char kVerisign_Class_4_Public_Primary_Certification_Authority___G3Fingerprint[]=
static const char kVerisign_Class_4_Public_Primary_Certification_Authority___G3Fingerprint[] =
"VnuCEf0g09KD7gzXzgZyy52ZvFtIeljJ1U7Gf3fUqPU=";
/* thawte Primary Root CA */
static const char kthawte_Primary_Root_CAFingerprint[]=
static const char kthawte_Primary_Root_CAFingerprint[] =
"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=";
/* thawte Primary Root CA - G2 */
static const char kthawte_Primary_Root_CA___G2Fingerprint[]=
static const char kthawte_Primary_Root_CA___G2Fingerprint[] =
"Z9xPMvoQ59AaeaBzqgyeAhLsL/w9d54Kp/nA8OHCyJM=";
/* thawte Primary Root CA - G3 */
static const char kthawte_Primary_Root_CA___G3Fingerprint[]=
static const char kthawte_Primary_Root_CA___G3Fingerprint[] =
"GQbGEk27Q4V40A4GbVBUxsN/D6YCjAVUXgmU7drshik=";
/*Now the pinsets, each is an ordered list by the actual value of the FP*/
typedef struct {
/* Pinsets are each an ordered list by the actual value of the fingerprint */
struct StaticFingerprints {
const size_t size;
const char* const* data;
} StaticPinset;
static const char* const kPinSet_mozilla_Data[] = {
kGeoTrust_Global_CA_2Fingerprint,
kthawte_Primary_Root_CA___G3Fingerprint,
kthawte_Primary_Root_CAFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kVerisign_Class_1_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kGeoTrust_Primary_Certification_AuthorityFingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kVerisign_Class_4_Public_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kBaltimore_CyberTrust_RootFingerprint,
kthawte_Primary_Root_CA___G2Fingerprint,
kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint,
kGeoTrust_Universal_CA_2Fingerprint,
kGeoTrust_Global_CAFingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kGeoTrust_Universal_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
};
const StaticPinset kPinSet_mozilla = { 21, kPinSet_mozilla_Data};
static const char* const kPinSet_mozilla_test_Data[] = {
kEnd_Entity_Test_CertFingerprint,
struct StaticPinset {
const StaticFingerprints* sha1;
const StaticFingerprints* sha256;
};
const StaticPinset kPinSet_mozilla_test = { 1, kPinSet_mozilla_test_Data};
/*Domainlist*/
typedef struct {
const char *mHost;
/* Mozilla static pinsets */
static const char* kPinset_mozilla_sha256_Data[] = {
kGeoTrust_Global_CA_2Fingerprint,
kthawte_Primary_Root_CA___G3Fingerprint,
kthawte_Primary_Root_CAFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kVerisign_Class_1_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kGeoTrust_Primary_Certification_AuthorityFingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kVerisign_Class_4_Public_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kBaltimore_CyberTrust_RootFingerprint,
kthawte_Primary_Root_CA___G2Fingerprint,
kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint,
kGeoTrust_Universal_CA_2Fingerprint,
kGeoTrust_Global_CAFingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kGeoTrust_Universal_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
};
static const StaticFingerprints kPinset_mozilla_sha256 = { 21, kPinset_mozilla_sha256_Data };
static const StaticPinset kPinset_mozilla = {
nullptr,
&kPinset_mozilla_sha256
};
static const char* kPinset_mozilla_test_sha256_Data[] = {
kEnd_Entity_Test_CertFingerprint,
};
static const StaticFingerprints kPinset_mozilla_test_sha256 = { 1, kPinset_mozilla_test_sha256_Data };
static const StaticPinset kPinset_mozilla_test = {
nullptr,
&kPinset_mozilla_test_sha256
};
/* Chrome static pinsets */
static const char* kPinset_test_sha1_Data[] = {
kTestSPKIFingerprint,
};
static const StaticFingerprints kPinset_test_sha1 = { 1, kPinset_test_sha1_Data };
static const StaticPinset kPinset_test = {
&kPinset_test_sha1,
nullptr
};
static const char* kPinset_google_sha1_Data[] = {
kGoogleG2Fingerprint,
kGoogleBackup2048Fingerprint,
};
static const StaticFingerprints kPinset_google_sha1 = { 2, kPinset_google_sha1_Data };
static const StaticPinset kPinset_google = {
&kPinset_google_sha1,
nullptr
};
static const char* kPinset_tor_sha1_Data[] = {
kTor1Fingerprint,
kTor2Fingerprint,
kTor3Fingerprint,
};
static const StaticFingerprints kPinset_tor_sha1 = { 3, kPinset_tor_sha1_Data };
static const char* kPinset_tor_sha256_Data[] = {
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kGOOGLE_PIN_RapidSSLFingerprint,
};
static const StaticFingerprints kPinset_tor_sha256 = { 2, kPinset_tor_sha256_Data };
static const StaticPinset kPinset_tor = {
&kPinset_tor_sha1,
&kPinset_tor_sha256
};
static const char* kPinset_twitterCom_sha1_Data[] = {
kTwitter1Fingerprint,
};
static const StaticFingerprints kPinset_twitterCom_sha1 = { 1, kPinset_twitterCom_sha1_Data };
static const char* kPinset_twitterCom_sha256_Data[] = {
kVerisign_Class_2_Public_Primary_Certification_Authority___G2Fingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G2Fingerprint,
kGeoTrust_Global_CA_2Fingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kVerisign_Class_1_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kVerisign_Class_1_Public_Primary_Certification_AuthorityFingerprint,
kGeoTrust_Primary_Certification_AuthorityFingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kVerisign_Class_4_Public_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint,
kGeoTrust_Universal_CA_2Fingerprint,
kGeoTrust_Global_CAFingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kGeoTrust_Universal_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
kVerisign_Class_3_Public_Primary_Certification_AuthorityFingerprint,
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
};
static const StaticFingerprints kPinset_twitterCom_sha256 = { 21, kPinset_twitterCom_sha256_Data };
static const StaticPinset kPinset_twitterCom = {
&kPinset_twitterCom_sha1,
&kPinset_twitterCom_sha256
};
static const char* kPinset_twitterCDN_sha1_Data[] = {
kTwitter1Fingerprint,
};
static const StaticFingerprints kPinset_twitterCDN_sha1 = { 1, kPinset_twitterCDN_sha1_Data };
static const char* kPinset_twitterCDN_sha256_Data[] = {
kVerisign_Class_2_Public_Primary_Certification_Authority___G2Fingerprint,
kComodo_Trusted_Services_rootFingerprint,
kCOMODO_Certification_AuthorityFingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G2Fingerprint,
kAddTrust_Low_Value_Services_RootFingerprint,
kUTN_USERFirst_Object_Root_CAFingerprint,
kGTE_CyberTrust_Global_RootFingerprint,
kGeoTrust_Global_CA_2Fingerprint,
kEntrust_net_Premium_2048_Secure_Server_CAFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kVerisign_Class_1_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kGlobalSign_Root_CAFingerprint,
kUTN_USERFirst_Email_Root_CAFingerprint,
kVerisign_Class_1_Public_Primary_Certification_AuthorityFingerprint,
kAddTrust_Public_Services_RootFingerprint,
kUTN_DATACorp_SGC_Root_CAFingerprint,
kComodo_Secure_Services_rootFingerprint,
kGeoTrust_Primary_Certification_AuthorityFingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kUTN_USERFirst_Hardware_Root_CAFingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kVerisign_Class_4_Public_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kBaltimore_CyberTrust_RootFingerprint,
kEntrust_Root_Certification_AuthorityFingerprint,
kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint,
kGlobalSign_Root_CA___R3Fingerprint,
kGOOGLE_PIN_Entrust_G2Fingerprint,
kGeoTrust_Universal_CA_2Fingerprint,
kGeoTrust_Global_CAFingerprint,
kGlobalSign_Root_CA___R2Fingerprint,
kAddTrust_External_RootFingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kGeoTrust_Universal_CAFingerprint,
kEntrust_net_Secure_Server_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
kVerisign_Class_3_Public_Primary_Certification_AuthorityFingerprint,
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
kComodo_AAA_Services_rootFingerprint,
kAddTrust_Qualified_Certificates_RootFingerprint,
};
static const StaticFingerprints kPinset_twitterCDN_sha256 = { 42, kPinset_twitterCDN_sha256_Data };
static const StaticPinset kPinset_twitterCDN = {
&kPinset_twitterCDN_sha1,
&kPinset_twitterCDN_sha256
};
static const char* kPinset_tor2web_sha256_Data[] = {
kGOOGLE_PIN_Tor2webFingerprint,
kGOOGLE_PIN_AlphaSSL_G2Fingerprint,
};
static const StaticFingerprints kPinset_tor2web_sha256 = { 2, kPinset_tor2web_sha256_Data };
static const StaticPinset kPinset_tor2web = {
nullptr,
&kPinset_tor2web_sha256
};
static const char* kPinset_cryptoCat_sha256_Data[] = {
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kGOOGLE_PIN_CryptoCat1Fingerprint,
};
static const StaticFingerprints kPinset_cryptoCat_sha256 = { 2, kPinset_cryptoCat_sha256_Data };
static const StaticPinset kPinset_cryptoCat = {
nullptr,
&kPinset_cryptoCat_sha256
};
static const char* kPinset_lavabit_sha256_Data[] = {
kGOOGLE_PIN_LibertylavabitcomFingerprint,
};
static const StaticFingerprints kPinset_lavabit_sha256 = { 1, kPinset_lavabit_sha256_Data };
static const StaticPinset kPinset_lavabit = {
nullptr,
&kPinset_lavabit_sha256
};
/* Domainlist */
struct TransportSecurityPreload {
const char* mHost;
const bool mIncludeSubdomains;
const bool mTestMode;
const StaticPinset *pinset;
} TransportSecurityPreload;
static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "addons.mozilla.net", true, &kPinSet_mozilla },
{ "addons.mozilla.org", true, &kPinSet_mozilla },
{ "cdn.mozilla.net", true, &kPinSet_mozilla },
{ "cdn.mozilla.org", true, &kPinSet_mozilla },
{ "exclude-subdomains.pinning.example.com", false, &kPinSet_mozilla_test },
{ "include-subdomains.pinning.example.com", true, &kPinSet_mozilla_test },
{ "media.mozilla.com", true, &kPinSet_mozilla },
};
static const int kPublicKeyPinningPreloadListLength = 7;
/* Sort hostnames for binary search. */
static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "accounts.google.com", true, true, &kPinset_google },
{ "addons.mozilla.net", true, true, &kPinset_mozilla },
{ "addons.mozilla.org", true, true, &kPinset_mozilla },
{ "admin.google.com", true, true, &kPinset_google },
{ "android.com", true, true, &kPinset_google },
{ "api.twitter.com", true, true, &kPinset_twitterCDN },
{ "apis.google.com", true, true, &kPinset_google },
{ "appengine.google.com", true, true, &kPinset_google },
{ "appspot.com", true, true, &kPinset_google },
{ "blog.torproject.org", true, true, &kPinset_tor },
{ "business.twitter.com", true, true, &kPinset_twitterCom },
{ "cdn.mozilla.net", true, true, &kPinset_mozilla },
{ "cdn.mozilla.org", true, true, &kPinset_mozilla },
{ "chart.apis.google.com", true, true, &kPinset_google },
{ "check.torproject.org", true, true, &kPinset_tor },
{ "checkout.google.com", true, true, &kPinset_google },
{ "chrome-devtools-frontend.appspot.com", true, true, &kPinset_google },
{ "chrome.google.com", true, true, &kPinset_google },
{ "chromiumcodereview.appspot.com", true, true, &kPinset_google },
{ "cloud.google.com", true, true, &kPinset_google },
{ "code.google.com", true, true, &kPinset_google },
{ "codereview.appspot.com", true, true, &kPinset_google },
{ "codereview.chromium.org", true, true, &kPinset_google },
{ "crypto.cat", false, true, &kPinset_cryptoCat },
{ "dev.twitter.com", true, true, &kPinset_twitterCom },
{ "dist.torproject.org", true, true, &kPinset_tor },
{ "dl.google.com", true, true, &kPinset_google },
{ "docs.google.com", true, true, &kPinset_google },
{ "doubleclick.net", true, true, &kPinset_google },
{ "drive.google.com", true, true, &kPinset_google },
{ "encrypted.google.com", true, true, &kPinset_google },
{ "exclude-subdomains.pinning.example.com", false, false, &kPinset_mozilla_test },
{ "g.co", true, true, &kPinset_google },
{ "glass.google.com", true, true, &kPinset_google },
{ "gmail.com", false, true, &kPinset_google },
{ "goo.gl", true, true, &kPinset_google },
{ "google-analytics.com", true, true, &kPinset_google },
{ "google.ac", true, true, &kPinset_google },
{ "google.ad", true, true, &kPinset_google },
{ "google.ae", true, true, &kPinset_google },
{ "google.af", true, true, &kPinset_google },
{ "google.ag", true, true, &kPinset_google },
{ "google.am", true, true, &kPinset_google },
{ "google.as", true, true, &kPinset_google },
{ "google.at", true, true, &kPinset_google },
{ "google.az", true, true, &kPinset_google },
{ "google.ba", true, true, &kPinset_google },
{ "google.be", true, true, &kPinset_google },
{ "google.bf", true, true, &kPinset_google },
{ "google.bg", true, true, &kPinset_google },
{ "google.bi", true, true, &kPinset_google },
{ "google.bj", true, true, &kPinset_google },
{ "google.bs", true, true, &kPinset_google },
{ "google.by", true, true, &kPinset_google },
{ "google.ca", true, true, &kPinset_google },
{ "google.cat", true, true, &kPinset_google },
{ "google.cc", true, true, &kPinset_google },
{ "google.cd", true, true, &kPinset_google },
{ "google.cf", true, true, &kPinset_google },
{ "google.cg", true, true, &kPinset_google },
{ "google.ch", true, true, &kPinset_google },
{ "google.ci", true, true, &kPinset_google },
{ "google.cl", true, true, &kPinset_google },
{ "google.cm", true, true, &kPinset_google },
{ "google.cn", true, true, &kPinset_google },
{ "google.co.ao", true, true, &kPinset_google },
{ "google.co.bw", true, true, &kPinset_google },
{ "google.co.ck", true, true, &kPinset_google },
{ "google.co.cr", true, true, &kPinset_google },
{ "google.co.hu", true, true, &kPinset_google },
{ "google.co.id", true, true, &kPinset_google },
{ "google.co.il", true, true, &kPinset_google },
{ "google.co.im", true, true, &kPinset_google },
{ "google.co.in", true, true, &kPinset_google },
{ "google.co.je", true, true, &kPinset_google },
{ "google.co.jp", true, true, &kPinset_google },
{ "google.co.ke", true, true, &kPinset_google },
{ "google.co.kr", true, true, &kPinset_google },
{ "google.co.ls", true, true, &kPinset_google },
{ "google.co.ma", true, true, &kPinset_google },
{ "google.co.mz", true, true, &kPinset_google },
{ "google.co.nz", true, true, &kPinset_google },
{ "google.co.th", true, true, &kPinset_google },
{ "google.co.tz", true, true, &kPinset_google },
{ "google.co.ug", true, true, &kPinset_google },
{ "google.co.uk", true, true, &kPinset_google },
{ "google.co.uz", true, true, &kPinset_google },
{ "google.co.ve", true, true, &kPinset_google },
{ "google.co.vi", true, true, &kPinset_google },
{ "google.co.za", true, true, &kPinset_google },
{ "google.co.zm", true, true, &kPinset_google },
{ "google.co.zw", true, true, &kPinset_google },
{ "google.com", true, true, &kPinset_google },
{ "google.com.af", true, true, &kPinset_google },
{ "google.com.ag", true, true, &kPinset_google },
{ "google.com.ai", true, true, &kPinset_google },
{ "google.com.ar", true, true, &kPinset_google },
{ "google.com.au", true, true, &kPinset_google },
{ "google.com.bd", true, true, &kPinset_google },
{ "google.com.bh", true, true, &kPinset_google },
{ "google.com.bn", true, true, &kPinset_google },
{ "google.com.bo", true, true, &kPinset_google },
{ "google.com.br", true, true, &kPinset_google },
{ "google.com.by", true, true, &kPinset_google },
{ "google.com.bz", true, true, &kPinset_google },
{ "google.com.cn", true, true, &kPinset_google },
{ "google.com.co", true, true, &kPinset_google },
{ "google.com.cu", true, true, &kPinset_google },
{ "google.com.cy", true, true, &kPinset_google },
{ "google.com.do", true, true, &kPinset_google },
{ "google.com.ec", true, true, &kPinset_google },
{ "google.com.eg", true, true, &kPinset_google },
{ "google.com.et", true, true, &kPinset_google },
{ "google.com.fj", true, true, &kPinset_google },
{ "google.com.ge", true, true, &kPinset_google },
{ "google.com.gh", true, true, &kPinset_google },
{ "google.com.gi", true, true, &kPinset_google },
{ "google.com.gr", true, true, &kPinset_google },
{ "google.com.gt", true, true, &kPinset_google },
{ "google.com.hk", true, true, &kPinset_google },
{ "google.com.iq", true, true, &kPinset_google },
{ "google.com.jm", true, true, &kPinset_google },
{ "google.com.jo", true, true, &kPinset_google },
{ "google.com.kh", true, true, &kPinset_google },
{ "google.com.kw", true, true, &kPinset_google },
{ "google.com.lb", true, true, &kPinset_google },
{ "google.com.ly", true, true, &kPinset_google },
{ "google.com.mt", true, true, &kPinset_google },
{ "google.com.mx", true, true, &kPinset_google },
{ "google.com.my", true, true, &kPinset_google },
{ "google.com.na", true, true, &kPinset_google },
{ "google.com.nf", true, true, &kPinset_google },
{ "google.com.ng", true, true, &kPinset_google },
{ "google.com.ni", true, true, &kPinset_google },
{ "google.com.np", true, true, &kPinset_google },
{ "google.com.nr", true, true, &kPinset_google },
{ "google.com.om", true, true, &kPinset_google },
{ "google.com.pa", true, true, &kPinset_google },
{ "google.com.pe", true, true, &kPinset_google },
{ "google.com.ph", true, true, &kPinset_google },
{ "google.com.pk", true, true, &kPinset_google },
{ "google.com.pl", true, true, &kPinset_google },
{ "google.com.pr", true, true, &kPinset_google },
{ "google.com.py", true, true, &kPinset_google },
{ "google.com.qa", true, true, &kPinset_google },
{ "google.com.ru", true, true, &kPinset_google },
{ "google.com.sa", true, true, &kPinset_google },
{ "google.com.sb", true, true, &kPinset_google },
{ "google.com.sg", true, true, &kPinset_google },
{ "google.com.sl", true, true, &kPinset_google },
{ "google.com.sv", true, true, &kPinset_google },
{ "google.com.tj", true, true, &kPinset_google },
{ "google.com.tn", true, true, &kPinset_google },
{ "google.com.tr", true, true, &kPinset_google },
{ "google.com.tw", true, true, &kPinset_google },
{ "google.com.ua", true, true, &kPinset_google },
{ "google.com.uy", true, true, &kPinset_google },
{ "google.com.vc", true, true, &kPinset_google },
{ "google.com.ve", true, true, &kPinset_google },
{ "google.com.vn", true, true, &kPinset_google },
{ "google.cv", true, true, &kPinset_google },
{ "google.cz", true, true, &kPinset_google },
{ "google.de", true, true, &kPinset_google },
{ "google.dj", true, true, &kPinset_google },
{ "google.dk", true, true, &kPinset_google },
{ "google.dm", true, true, &kPinset_google },
{ "google.dz", true, true, &kPinset_google },
{ "google.ee", true, true, &kPinset_google },
{ "google.es", true, true, &kPinset_google },
{ "google.fi", true, true, &kPinset_google },
{ "google.fm", true, true, &kPinset_google },
{ "google.fr", true, true, &kPinset_google },
{ "google.ga", true, true, &kPinset_google },
{ "google.ge", true, true, &kPinset_google },
{ "google.gg", true, true, &kPinset_google },
{ "google.gl", true, true, &kPinset_google },
{ "google.gm", true, true, &kPinset_google },
{ "google.gp", true, true, &kPinset_google },
{ "google.gr", true, true, &kPinset_google },
{ "google.gy", true, true, &kPinset_google },
{ "google.hk", true, true, &kPinset_google },
{ "google.hn", true, true, &kPinset_google },
{ "google.hr", true, true, &kPinset_google },
{ "google.ht", true, true, &kPinset_google },
{ "google.hu", true, true, &kPinset_google },
{ "google.ie", true, true, &kPinset_google },
{ "google.im", true, true, &kPinset_google },
{ "google.info", true, true, &kPinset_google },
{ "google.iq", true, true, &kPinset_google },
{ "google.is", true, true, &kPinset_google },
{ "google.it", true, true, &kPinset_google },
{ "google.it.ao", true, true, &kPinset_google },
{ "google.je", true, true, &kPinset_google },
{ "google.jo", true, true, &kPinset_google },
{ "google.jobs", true, true, &kPinset_google },
{ "google.jp", true, true, &kPinset_google },
{ "google.kg", true, true, &kPinset_google },
{ "google.ki", true, true, &kPinset_google },
{ "google.kz", true, true, &kPinset_google },
{ "google.la", true, true, &kPinset_google },
{ "google.li", true, true, &kPinset_google },
{ "google.lk", true, true, &kPinset_google },
{ "google.lt", true, true, &kPinset_google },
{ "google.lu", true, true, &kPinset_google },
{ "google.lv", true, true, &kPinset_google },
{ "google.md", true, true, &kPinset_google },
{ "google.me", true, true, &kPinset_google },
{ "google.mg", true, true, &kPinset_google },
{ "google.mk", true, true, &kPinset_google },
{ "google.ml", true, true, &kPinset_google },
{ "google.mn", true, true, &kPinset_google },
{ "google.ms", true, true, &kPinset_google },
{ "google.mu", true, true, &kPinset_google },
{ "google.mv", true, true, &kPinset_google },
{ "google.mw", true, true, &kPinset_google },
{ "google.ne", true, true, &kPinset_google },
{ "google.ne.jp", true, true, &kPinset_google },
{ "google.net", true, true, &kPinset_google },
{ "google.nl", true, true, &kPinset_google },
{ "google.no", true, true, &kPinset_google },
{ "google.nr", true, true, &kPinset_google },
{ "google.nu", true, true, &kPinset_google },
{ "google.off.ai", true, true, &kPinset_google },
{ "google.pk", true, true, &kPinset_google },
{ "google.pl", true, true, &kPinset_google },
{ "google.pn", true, true, &kPinset_google },
{ "google.ps", true, true, &kPinset_google },
{ "google.pt", true, true, &kPinset_google },
{ "google.ro", true, true, &kPinset_google },
{ "google.rs", true, true, &kPinset_google },
{ "google.ru", true, true, &kPinset_google },
{ "google.rw", true, true, &kPinset_google },
{ "google.sc", true, true, &kPinset_google },
{ "google.se", true, true, &kPinset_google },
{ "google.sh", true, true, &kPinset_google },
{ "google.si", true, true, &kPinset_google },
{ "google.sk", true, true, &kPinset_google },
{ "google.sm", true, true, &kPinset_google },
{ "google.sn", true, true, &kPinset_google },
{ "google.so", true, true, &kPinset_google },
{ "google.st", true, true, &kPinset_google },
{ "google.td", true, true, &kPinset_google },
{ "google.tg", true, true, &kPinset_google },
{ "google.tk", true, true, &kPinset_google },
{ "google.tl", true, true, &kPinset_google },
{ "google.tm", true, true, &kPinset_google },
{ "google.tn", true, true, &kPinset_google },
{ "google.to", true, true, &kPinset_google },
{ "google.tp", true, true, &kPinset_google },
{ "google.tt", true, true, &kPinset_google },
{ "google.us", true, true, &kPinset_google },
{ "google.uz", true, true, &kPinset_google },
{ "google.vg", true, true, &kPinset_google },
{ "google.vu", true, true, &kPinset_google },
{ "google.ws", true, true, &kPinset_google },
{ "googleadservices.com", true, true, &kPinset_google },
{ "googleapis.com", true, true, &kPinset_google },
{ "googlecode.com", true, true, &kPinset_google },
{ "googlecommerce.com", true, true, &kPinset_google },
{ "googlegroups.com", true, true, &kPinset_google },
{ "googlemail.com", false, true, &kPinset_google },
{ "googleplex.com", true, true, &kPinset_google },
{ "googlesyndication.com", true, true, &kPinset_google },
{ "googletagmanager.com", true, true, &kPinset_google },
{ "googletagservices.com", true, true, &kPinset_google },
{ "googleusercontent.com", true, true, &kPinset_google },
{ "goto.google.com", true, true, &kPinset_google },
{ "groups.google.com", true, true, &kPinset_google },
{ "gstatic.com", true, true, &kPinset_google },
{ "history.google.com", true, true, &kPinset_google },
{ "hostedtalkgadget.google.com", true, true, &kPinset_google },
{ "include-subdomains.pinning.example.com", true, false, &kPinset_mozilla_test },
{ "liberty.lavabit.com", true, true, &kPinset_lavabit },
{ "mail.google.com", true, true, &kPinset_google },
{ "market.android.com", true, true, &kPinset_google },
{ "media.mozilla.com", true, true, &kPinset_mozilla },
{ "mobile.twitter.com", true, true, &kPinset_twitterCom },
{ "oauth.twitter.com", true, true, &kPinset_twitterCom },
{ "pinningtest.appspot.com", true, true, &kPinset_test },
{ "platform.twitter.com", true, true, &kPinset_twitterCDN },
{ "play.google.com", false, true, &kPinset_google },
{ "plus.google.com", true, true, &kPinset_google },
{ "plus.sandbox.google.com", true, true, &kPinset_google },
{ "profiles.google.com", true, true, &kPinset_google },
{ "script.google.com", true, true, &kPinset_google },
{ "security.google.com", true, true, &kPinset_google },
{ "sites.google.com", true, true, &kPinset_google },
{ "spreadsheets.google.com", true, true, &kPinset_google },
{ "ssl.google-analytics.com", true, true, &kPinset_google },
{ "talk.google.com", true, true, &kPinset_google },
{ "talkgadget.google.com", true, true, &kPinset_google },
{ "test-mode.pinning.example.com", true, true, &kPinset_mozilla_test },
{ "tor2web.org", true, true, &kPinset_tor2web },
{ "torproject.org", false, true, &kPinset_tor },
{ "translate.googleapis.com", true, true, &kPinset_google },
{ "twimg.com", true, true, &kPinset_twitterCDN },
{ "twitter.com", false, true, &kPinset_twitterCom },
{ "urchin.com", true, true, &kPinset_google },
{ "wallet.google.com", true, true, &kPinset_google },
{ "www.gmail.com", false, true, &kPinset_google },
{ "www.googlemail.com", false, true, &kPinset_google },
{ "www.torproject.org", true, true, &kPinset_tor },
{ "www.twitter.com", true, true, &kPinset_twitterCom },
{ "youtu.be", true, true, &kPinset_google },
{ "youtube.com", true, true, &kPinset_google },
{ "ytimg.com", true, true, &kPinset_google },
};
const PRTime kPreloadPKPinsExpirationTime = INT64_C(1410540741649000);
static const int kPublicKeyPinningPreloadListLength = 306;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1410801238668000);

View File

@ -48,6 +48,12 @@ function test_strict() {
// This domain serves a cert that doesn't match the pinset, but subdomains
// are excluded.
add_connection_test("sub.exclude-subdomains.pinning.example.com", Cr.NS_OK);
// This domain's pinset is exactly the same as
// include-subdomains.pinning.example.com, serves the same cert as
// bad.include-subdomains.pinning.example.com, but it should pass because
// it's in test_mode.
add_connection_test("test-mode.pinning.example.com", Cr.NS_OK);
};
function test_mitm() {
@ -67,6 +73,7 @@ function test_mitm() {
add_connection_test("exclude-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("sub.exclude-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("test-mode.pinning.example.com", Cr.NS_OK);
};
function test_disabled() {
@ -81,6 +88,7 @@ function test_disabled() {
add_connection_test("bad.include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("exclude-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("sub.exclude-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("test-mode.pinning.example.com", Cr.NS_OK);
};
function check_pinning_telemetry() {

View File

@ -43,15 +43,16 @@ const BadCertHost sBadCertHosts[] =
{ "inadequatekeyusage.example.com", "inadequatekeyusage" },
{ "selfsigned-inadequateEKU.example.com", "selfsigned-inadequateEKU" },
{ "self-signed-end-entity-with-cA-true.example.com", "self-signed-EE-with-cA-true" },
// All of include-subdomains.pinning.example.com is pinned to End Entity Test
// Cert with nick localhostAndExampleCom. Any other nick will only pass
// pinning when security.cert_pinning.enforcement.level != strict and otherCA
// is added as a user-specified trust anchor. See StaticHPKPins.h.
// All of include-subdomains.pinning.example.com is pinned to End Entity
// Test Cert with nick localhostAndExampleCom. Any other nick will only
// pass pinning when security.cert_pinning.enforcement.level != strict and
// otherCA is added as a user-specified trust anchor. See StaticHPKPins.h.
{ "include-subdomains.pinning.example.com", "localhostAndExampleCom" },
{ "good.include-subdomains.pinning.example.com", "localhostAndExampleCom" },
{ "bad.include-subdomains.pinning.example.com", "otherIssuerEE" },
{ "exclude-subdomains.pinning.example.com", "localhostAndExampleCom" },
{ "sub.exclude-subdomains.pinning.example.com", "otherIssuerEE" },
{ "test-mode.pinning.example.com", "otherIssuerEE" },
{ nullptr, nullptr }
};

View File

@ -144,7 +144,7 @@ make_CA otherCA 'CN=Other test CA' other-test-ca.der
make_EE localhostAndExampleCom 'CN=Test End-entity' testCA "localhost,*.example.com,*.pinning.example.com,*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com"
# Make an EE cert issued by otherCA
make_EE otherIssuerEE 'CN=Wrong CA Pin Test End-Entity' otherCA "*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com"
make_EE otherIssuerEE 'CN=Wrong CA Pin Test End-Entity' otherCA "*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com,*.pinning.example.com"
$RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -L -n localhostAndExampleCom -r > $OUTPUT_DIR/default-ee.der
# A cert that is like localhostAndExampleCom, but with a different serial number for

View File

@ -1,5 +1,5 @@
library=
name=NSS Internal PKCS #11 Module
parameters=configdir='sql:security/manager/ssl/tests/unit/tlsserver' certPrefix='' keyPrefix='' secmod='secmod.db' flags= updatedir='security/manager/ssl/tests/unit/tlsserver/' updateCertPrefix='' updateKeyPrefix='' updateid='0' updateTokenDescription=''
NSS=trustOrder=75 cipherOrder=100 slotParams={0x00000001=[slotFlags=RSA,RC4,RC2,DES,DH,SHA1,MD5,MD2,SSL,TLS,AES,SHA256,SHA512,Camellia,SEED,RANDOM askpw=any timeout=30 ] } Flags=internal,critical
parameters=configdir='sql:./security/manager/ssl/tests/unit/tlsserver' certPrefix='' keyPrefix='' secmod='secmod.db' flags= updatedir='' updateCertPrefix='' updateKeyPrefix='' updateid='' updateTokenDescription=''
NSS=Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={slotFlags=[RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512] askpw=any timeout=30})

View File

@ -21,61 +21,69 @@
// include_subdomains: (optional bool) whether subdomains of |name| are also covered
// pins: (string) the |name| member of an object in |pinsets|
// equifax -> aus3
// Geotrust Primary -> www.mozilla.org
// Geotrust Global -> *. addons.mozilla.org
{
"pinsets": [
{
// From bug 772756, mozilla uses GeoTrust, Digicert and Thawte
// geotrust ca info: http://www.geotrust.com/resources/root-certificates/index.html
// In that same bug we also notice that our cdn sites use Verisign and
// Baltimore
// This list does not contain any 1024 bit roots for those providers
// From bug 772756, mozilla uses GeoTrust, Digicert and Thawte. Our
// cdn sites use Verisign and Baltimore. We exclude 1024-bit root certs
// from all providers. geotrust ca info:
// http://www.geotrust.com/resources/root-certificates/index.html
"name": "mozilla",
"static_spki_hashes": [
"Verisign Class 1 Public Primary Certification Authority - G3",
"Verisign Class 2 Public Primary Certification Authority - G3",
"Verisign Class 3 Public Primary Certification Authority - G3",
"Verisign Class 4 Public Primary Certification Authority - G3",
"VeriSign Class 3 Public Primary Certification Authority - G5",
"VeriSign Universal Root Certification Authority",
"VeriSign Class 3 Public Primary Certification Authority - G4",
"GeoTrust Primary Certification Authority",
"GeoTrust Global CA",
"GeoTrust Global CA 2",
"GeoTrust Universal CA",
"GeoTrust Universal CA 2",
"GeoTrust Primary Certification Authority - G2",
"GeoTrust Primary Certification Authority - G3",
"DigiCert High Assurance EV Root CA",
"sha256_hashes": [
"Baltimore CyberTrust Root",
"DigiCert Assured ID Root CA",
"DigiCert Global Root CA",
"DigiCert High Assurance EV Root CA",
"GeoTrust Global CA",
"GeoTrust Global CA 2",
"GeoTrust Primary Certification Authority",
"GeoTrust Primary Certification Authority - G2",
"GeoTrust Primary Certification Authority - G3",
"GeoTrust Universal CA",
"GeoTrust Universal CA 2",
"thawte Primary Root CA",
"thawte Primary Root CA - G2",
"thawte Primary Root CA - G3",
"Baltimore CyberTrust Root"
"Verisign Class 1 Public Primary Certification Authority - G3",
"Verisign Class 2 Public Primary Certification Authority - G3",
"Verisign Class 3 Public Primary Certification Authority - G3",
"VeriSign Class 3 Public Primary Certification Authority - G4",
"VeriSign Class 3 Public Primary Certification Authority - G5",
"Verisign Class 4 Public Primary Certification Authority - G3",
"VeriSign Universal Root Certification Authority"
]
},
// For pinning tests on pinning.example.com, the certificate must be 'End
// Entity Test Cert'
{
"name": "mozilla_test",
"static_spki_hashes": [
"sha256_hashes": [
"End Entity Test Cert"
]
}
],
"entries": [
// from bug 1005653 we learned that addon subdomains include cdn sites
{ "name": "addons.mozilla.org", "include_subdomains": true, "pins": "mozilla" },
{ "name": "addons.mozilla.net", "include_subdomains": true, "pins": "mozilla" },
{ "name": "cdn.mozilla.net", "include_subdomains": true, "pins": "mozilla" },
{ "name": "cdn.mozilla.org", "include_subdomains": true, "pins": "mozilla" },
{ "name": "media.mozilla.com", "include_subdomains": true, "pins": "mozilla" },
{ "name": "include-subdomains.pinning.example.com", "include_subdomains": true, "pins": "mozilla_test" },
{ "name": "exclude-subdomains.pinning.example.com", "include_subdomains": false, "pins": "mozilla_test" }
{ "name": "addons.mozilla.org", "include_subdomains": true,
"pins": "mozilla", "test_mode": true },
{ "name": "addons.mozilla.net", "include_subdomains": true,
"pins": "mozilla", "test_mode": true },
{ "name": "cdn.mozilla.net", "include_subdomains": true,
"pins": "mozilla", "test_mode": true},
{ "name": "cdn.mozilla.org", "include_subdomains": true,
"pins": "mozilla", "test_mode": true },
{ "name": "media.mozilla.com", "include_subdomains": true,
"pins": "mozilla", "test_mode": true },
{ "name": "include-subdomains.pinning.example.com",
"include_subdomains": true, "pins": "mozilla_test",
"test_mode": false },
{ "name": "exclude-subdomains.pinning.example.com",
"include_subdomains": false, "pins": "mozilla_test",
"test_mode": false },
{ "name": "test-mode.pinning.example.com", "include_subdomains": true,
"pins": "mozilla_test", "test_mode": true }
]
}

View File

@ -12,7 +12,8 @@
// [absolute path to]/StaticHPKPins.h
if (arguments.length != 3) {
throw "Usage: genHPKPins.js <absolute path to PreloadedHPKPins.json> " +
throw "Usage: genHPKPStaticPins.js " +
"<absolute path to PreloadedHPKPins.json> " +
"<absolute path to default-ee.der> " +
"<absolute path to StaticHPKPins.h>";
}
@ -23,11 +24,20 @@ let { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
let { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
const certdb2 = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB2);
let gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB2);
gCertDB.QueryInterface(Ci.nsIX509CertDB);
const BUILT_IN_NICK_PREFIX = "Builtin Object Token:";
const SHA1_PREFIX = "sha1/";
const SHA256_PREFIX = "sha256/";
const GOOGLE_PIN_PREFIX = "GOOGLE_PIN_";
// Pins expire in 18 weeks
const PINNING_MINIMUM_REQUIRED_MAX_AGE = 60 * 60 * 24 * 7 * 18;
const CHROME_JSON_SOURCE = "https://src.chromium.org/chrome/trunk/src/net/http/transport_security_state_static.json";
const CHROME_CERT_SOURCE = "https://src.chromium.org/chrome/trunk/src/net/http/transport_security_state_static.certs";
const FILE_HEADER = "/* This Source Code Form is subject to the terms of the Mozilla Public\n" +
" * License, v. 2.0. If a copy of the MPL was not distributed with this\n" +
" * file, You can obtain one at http://mozilla.org/MPL/2.0/. */\n" +
@ -38,26 +48,36 @@ const FILE_HEADER = "/* This Source Code Form is subject to the terms of the Moz
"/*****************************************************************************/\n" +
"#include <stdint.h>" +
"\n";
const DOMAINHEADER ="/*Domainlist*/\n" +
"typedef struct {\n"+
" const char *mHost;\n"+
" const bool mIncludeSubdomains;\n"+
" const StaticPinset *pinset;\n"+
"} TransportSecurityPreload;\n"+
"\nstatic const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {\n";
const PINSETDEF ="/*Now the pinsets, each is an ordered list by the actual value of the FP*/\n"+
"typedef struct {\n"+
" const size_t size;\n"+
" const char* const* data;\n"+
"} StaticPinset;\n";
const DOMAINHEADER = "/* Domainlist */\n" +
"struct TransportSecurityPreload {\n" +
" const char* mHost;\n" +
" const bool mIncludeSubdomains;\n" +
" const bool mTestMode;\n" +
" const StaticPinset *pinset;\n" +
"};\n\n";
const PINSETDEF = "/* Pinsets are each an ordered list by the actual value of the fingerprint */\n" +
"struct StaticFingerprints {\n" +
" const size_t size;\n" +
" const char* const* data;\n" +
"};\n\n" +
"struct StaticPinset {\n" +
" const StaticFingerprints* sha1;\n" +
" const StaticFingerprints* sha256;\n" +
"};\n\n";
// Command-line arguments
var gStaticPins = parseJson(arguments[0]);
var gTestCertFile = arguments[1];
var gOutputFile = arguments[2];
function writeTo(string, fos) {
fos.write(string, string.length);
// Open the output file.
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
file.initWithPath(arguments[2]);
let gFileOutputStream = FileUtils.openSafeFileOutputStream(file);
function writeString(string) {
gFileOutputStream.write(string, string.length);
}
function readFileToString(filename) {
@ -99,39 +119,239 @@ function isCertBuiltIn(cert) {
return false;
}
// Returns a pair of maps [certNameToSKD, certSDKToName] between cert
function download(filename) {
var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
req.open("GET", filename, false); // doing the request synchronously
try {
req.send();
}
catch (e) {
throw "ERROR: problem downloading '" + filename + "': " + e;
}
if (req.status != 200) {
throw("ERROR: problem downloading '" + filename + "': status " +
req.status);
}
return req.responseText;
}
function downloadAsJson(filename) {
// we have to filter out '//' comments
var result = download(filename).replace(/\/\/[^\n]*\n/g, "");
var data = null;
try {
data = JSON.parse(result);
}
catch (e) {
throw "ERROR: could not parse data from '" + filename + "': " + e;
}
return data;
}
// Returns a Subject Public Key Digest from the given pem, if it exists.
function getSKDFromPem(pem) {
let cert = gCertDB.constructX509FromBase64(pem, pem.length);
return cert.sha256SubjectPublicKeyInfoDigest;
}
// 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), 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
// 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.
// For all of the entries in this file:
// - If the entry has a hash format, find the Mozilla pin name (cert nickname)
// and stick the hash into certSKDToName
// - If the entry has a PEM format, parse the PEM, find the Mozilla pin name
// 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) {
// Prefixes that we care about.
const BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
const END_CERT = "-----END CERTIFICATE-----";
// Parsing states.
const PRE_NAME = 0;
const POST_NAME = 1;
const IN_CERT = 2;
let state = PRE_NAME;
let lines = download(filename).split("\n");
let name = "";
let pemCert = "";
let hash = "";
let chromeNameToHash = {};
let chromeNameToMozName = {}
for (let i = 0; i < lines.length; ++i) {
let line = lines[i];
// Skip comments and newlines.
if (line.length == 0 || line[0] == '#') {
continue;
}
switch(state) {
case PRE_NAME:
chromeName = line;
state = POST_NAME;
break;
case POST_NAME:
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);
}
// Store the entire prefixed hash, so we can disambiguate sha1 from
// sha256 later.
chromeNameToHash[chromeName] = line;
certNameToSKD[chromeName] = hash;
certSKDToName[hash] = chromeName;
state = PRE_NAME;
} else if (line.startsWith(BEGIN_CERT)) {
state = IN_CERT;
} else {
throw "ERROR: couldn't parse Chrome certificate file " + line;
}
break;
case IN_CERT:
if (line.startsWith(END_CERT)) {
state = PRE_NAME;
hash = getSKDFromPem(pemCert);
pemCert = "";
if (hash in certSKDToName) {
mozName = certSKDToName[hash];
} else {
// Not one of our built-in certs. Prefix the name with
// GOOGLE_PIN_.
mozName = GOOGLE_PIN_PREFIX + chromeName;
dump("Can't find hash in builtin certs for Chrome nickname " +
chromeName + ", inserting " + mozName + "\n");
certSKDToName[hash] = mozName;
certNameToSKD[mozName] = hash;
}
chromeNameToMozName[chromeName] = mozName;
} else {
pemCert += line;
}
break;
default:
throw "ERROR: couldn't parse Chrome certificate file " + line;
}
}
return [ chromeNameToHash, chromeNameToMozName ];
}
// We can only import pinsets from chrome if for every name in the pinset:
// - We have a hash from Chrome's static certificate file
// - We have a builtin cert
// If the pinset meets these requirements, we store a map array of pinset
// objects:
// {
// pinset_name : {
// // Array of names with entries in certNameToSKD
// sha1_hashes: [],
// sha256_hashes: []
// }
// }
// and an array of imported pinset entries:
// { name: string, include_subdomains: boolean, test_mode: boolean,
// pins: pinset_name }
function downloadAndParseChromePins(filename,
chromeNameToHash,
chromeNameToMozName,
certNameToSKD,
certSKDToName) {
let chromePreloads = downloadAsJson(filename);
let chromePins = chromePreloads.pinsets;
let chromeImportedPinsets = {};
let chromeImportedEntries = [];
chromePins.forEach(function(pin) {
let valid = true;
let pinset = { name: pin.name, sha1_hashes: [], 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]);
}
// We should have already added hashes for all of these when we
// imported the certificate file.
if (!certNameToSKD[name]) {
throw("No hash for name: " + name);
}
} else if (name in chromeNameToMozName) {
pinset.sha256_hashes.push(chromeNameToMozName[name]);
} else {
dump("Skipping Chrome pinset " + pinset.name + ", couldn't find " +
"builtin " + name + " from cert file\n");
valid = false;
}
});
if (valid) {
chromeImportedPinsets[pinset.name] = pinset;
}
});
// Grab the domain entry lists. Chrome's entry format is similar to
// ours, except theirs includes a HSTS mode.
let entries = chromePreloads.entries;
entries.forEach(function(entry) {
if (entry.pins && chromeImportedPinsets[entry.pins]) {
chromeImportedEntries.push({
name: entry.name,
include_subdomains: entry.include_subdomains,
test_mode: true,
pins: entry.pins });
}
});
return [ chromeImportedPinsets, chromeImportedEntries ];
}
// Returns a pair of maps [certNameToSKD, certSKDToName] between cert
// nicknames and digests of the SPKInfo for the mozilla trust store
function loadNSSCertinfo(derTestFile) {
let allCerts = certdb2.getCerts();
let allCerts = gCertDB.getCerts();
let enumerator = allCerts.getEnumerator();
let certNameToSKD = {};
let certSDKToName = {};
const BUILT_IN_NICK_PREFIX = "Builtin Object Token:";
let certSKDToName = {};
while (enumerator.hasMoreElements()) {
let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);
if (!isCertBuiltIn(cert)) {
continue;
}
let name = cert.nickname.substr(BUILT_IN_NICK_PREFIX.length);
let SDK = cert.sha256SubjectPublicKeyInfoDigest;
certNameToSKD[name] = SDK;
certSDKToName[SDK] = name;
let SKD = cert.sha256SubjectPublicKeyInfoDigest;
certNameToSKD[name] = SKD;
certSKDToName[SKD] = name;
}
{
// A certificate for *.example.com.
let der = readFileToString(derTestFile);
// XPCOM is too dumb to automatically query the parent interface of
// nsIX509CertDB2 without a hint.
let certdb = certdb2.QueryInterface(Ci.nsIX509CertDB);
let testCert = certdb.constructX509(der, der.length);
let testCert = gCertDB.constructX509(der, der.length);
// We can't include this cert in the previous loop, because it skips
// non-builtin certs and the nickname is not built-in to the cert.
let name = "End Entity Test Cert";
let SDK = testCert.sha256SubjectPublicKeyInfoDigest;
certNameToSKD[name] = SDK;
certSDKToName[SDK] = name;
let SKD = testCert.sha256SubjectPublicKeyInfoDigest;
certNameToSKD[name] = SKD;
certSKDToName[SKD] = name;
}
return [certNameToSKD, certSDKToName];
return [certNameToSKD, certSKDToName];
}
function parseJson(filename) {
@ -158,82 +378,153 @@ function genExpirationTime() {
let nowMillis = now.getTime();
let expirationMillis = nowMillis + (PINNING_MINIMUM_REQUIRED_MAX_AGE * 1000);
let expirationMicros = expirationMillis * 1000;
return "const PRTime kPreloadPKPinsExpirationTime = INT64_C(" +
return "static const PRTime kPreloadPKPinsExpirationTime = INT64_C(" +
expirationMicros +");\n";
}
function writeFile(certNameToSDK, certSDKToName, jsonPins) {
try {
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
file.initWithPath(gOutputFile);
let fos = FileUtils.openSafeFileOutputStream(file);
writeTo(FILE_HEADER, fos);
// compute used keys
let usedFingerPrints = {};
let pinset = jsonPins["pinsets"];
for (let pinsetEntry of pinset) {
for (let certName of pinsetEntry.static_spki_hashes) {
usedFingerPrints[certName] = true;
}
}
for (let certName of Object.keys(usedFingerPrints).sort()) {
writeTo("/* "+ certName + " */\n", fos);
writeTo("static const char " + nameToAlias(certName) + "[]=\n", fos);
writeTo(" \"" + certNameToSDK[certName] + "\";\n", fos);
writeTo("\n", fos);
}
writeTo(PINSETDEF, fos);
for (let pinset of jsonPins["pinsets"].sort(compareByName)) {
writeTo("static const char* const kPinSet_" + pinset.name + "_Data[] = {\n", fos);
let certNameList = pinset.static_spki_hashes;
let SKDList = [];
for (let certName of pinset.static_spki_hashes) {
SKDList.push(certNameToSDK[certName]);
}
for (let sdk of SKDList.sort() ) {
writeTo(" " + nameToAlias(certSDKToName[sdk]) + ",\n", fos);
}
writeTo("};\n", fos);
writeTo("const StaticPinset kPinSet_"+ pinset.name +" = { " +
pinset.static_spki_hashes.length + ", kPinSet_"+pinset.name +
"_Data};\n", fos);
writeTo("\n", fos);
}
// now the domainlist entries
writeTo(DOMAINHEADER, fos);
for (let entry of jsonPins["entries"].sort(compareByName)) {
let printVal = " { \""+ entry.name +"\",\t";
if (entry.include_subdomains) {
printVal += "true,\t";
} else {
printVal += "false,\t";
}
printVal += "&kPinSet_"+entry.pins;
printVal += " },\n";
writeTo(printVal, fos);
}
writeTo("};\n", fos);
writeTo("\n", fos);
let domainFooter = "static const int " +
"kPublicKeyPinningPreloadListLength = " +
jsonPins["entries"].length + ";\n";
writeTo(domainFooter, fos);
writeTo("\n", fos);
writeTo(genExpirationTime(), fos);
FileUtils.closeSafeFileOutputStream(fos);
} catch (e) {
dump("ERROR: problem writing output to '" + gOutputFile + "': " + e + "\n");
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";
}
writeString("static const StaticPinset " + prefix + " = {\n" +
" " + sha1Name + ",\n " + sha256Name + "\n};\n\n");
}
// ****************************************************************************
// This is where the action happens:
let [ certNameToSKD, certSDKToName ] = loadNSSCertinfo(gTestCertFile);
writeFile(certNameToSKD, certSDKToName, gStaticPins);
function writeFingerprints(certNameToSKD, certSKDToName, name, hashes, type) {
let varPrefix = "kPinset_" + name + "_" + type;
writeString("static const char* " + varPrefix + "_Data[] = {\n");
let SKDList = [];
for (let certName of hashes) {
SKDList.push(certNameToSKD[certName]);
}
for (let skd of SKDList.sort()) {
writeString(" " + nameToAlias(certSKDToName[skd]) + ",\n");
}
if (hashes.length == 0) {
// ANSI C requires that an initialiser list be non-empty.
writeString(" 0\n");
}
writeString("};\n");
writeString("static const StaticFingerprints " + varPrefix + " = { " +
hashes.length + ", " + varPrefix + "_Data };\n\n");
}
function writeEntry(entry) {
let printVal = " { \"" + entry.name + "\",\ ";
if (entry.include_subdomains) {
printVal += "true, ";
} else {
printVal += "false, ";
}
// Default to test mode if not specified.
let testMode = true;
if (entry.hasOwnProperty("test_mode")) {
testMode = entry.test_mode;
}
if (testMode) {
printVal += "true, ";
} else {
printVal += "false, ";
}
printVal += "&kPinset_" + entry.pins;
printVal += " },\n";
writeString(printVal);
}
function writeDomainList(chromeImportedEntries) {
writeString("/* Sort hostnames for binary search. */\n");
writeString("static const TransportSecurityPreload " +
"kPublicKeyPinningPreloadList[] = {\n");
let count = 0;
let sortedEntries = gStaticPins.entries;
sortedEntries.push.apply(sortedEntries, chromeImportedEntries);
for (let entry of sortedEntries.sort(compareByName)) {
count++;
writeEntry(entry);
}
writeString("};\n");
writeString("\nstatic const int kPublicKeyPinningPreloadListLength = " +
count + ";\n");
}
function writeFile(certNameToSKD, certSKDToName,
chromeImportedPinsets, chromeImportedEntries) {
// Compute used pins from both Chrome's and our pinsets, so we can output
// them later.
usedFingerprints = {};
gStaticPins.pinsets.forEach(function(pinset) {
// 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;
});
}
});
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;
});
}
writeString(FILE_HEADER);
// Write actual fingerprints.
Object.keys(usedFingerprints).sort().forEach(function(certName) {
if (certName) {
writeString("/* " + certName + " */\n");
writeString("static const char " + nameToAlias(certName) + "[] =\n");
writeString(" \"" + certNameToSKD[certName] + "\";\n");
writeString("\n");
}
});
// Write the pinsets
writeString(PINSETDEF);
writeString("/* Mozilla static pinsets */\n");
gStaticPins.pinsets.sort(compareByName).forEach(function(pinset) {
writeFullPinset(certNameToSKD, certSKDToName, pinset);
});
writeString("/* Chrome static pinsets */\n");
for (let key in chromeImportedPinsets) {
writeFullPinset(certNameToSKD, certSKDToName, chromeImportedPinsets[key]);
}
// Write the domainlist entries.
writeString(DOMAINHEADER);
writeDomainList(chromeImportedEntries);
writeString("\n");
writeString(genExpirationTime());
}
let [ certNameToSKD, certSKDToName ] = loadNSSCertinfo(gTestCertFile);
let [ chromeNameToHash, chromeNameToMozName ] = downloadAndParseChromeCerts(
CHROME_CERT_SOURCE, certSKDToName);
let [ chromeImportedPinsets, chromeImportedEntries ] =
downloadAndParseChromePins(CHROME_JSON_SOURCE, chromeNameToHash,
chromeNameToMozName, certNameToSKD, certSKDToName);
writeFile(certNameToSKD, certSKDToName, chromeImportedPinsets,
chromeImportedEntries);
FileUtils.closeSafeFileOutputStream(gFileOutputStream);