Issue #1280 - Part 1: Remove HPKP components.

This also removes leftover plumbing for storing preload information
in SiteSecurityService since no service still uses it.
This commit is contained in:
wolfbeast 2020-03-28 01:06:56 +01:00 committed by Roy Tam
commit cf5f069080
11 changed files with 32 additions and 2657 deletions

View file

@ -1,333 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PublicKeyPinningService.h"
#include "mozilla/Base64.h"
#include "mozilla/Casting.h"
#include "mozilla/Logging.h"
#include "nsISiteSecurityService.h"
#include "nsServiceManagerUtils.h"
#include "nsSiteSecurityService.h"
#include "nssb64.h"
#include "pkix/pkixtypes.h"
#include "seccomon.h"
#include "sechash.h"
#include "StaticHPKPins.h" // autogenerated by genHPKPStaticpins.js
using namespace mozilla;
using namespace mozilla::pkix;
using namespace mozilla::psm;
LazyLogModule gPublicKeyPinningLog("PublicKeyPinningService");
/**
Computes in the location specified by base64Out the SHA256 digest
of the DER Encoded subject Public Key Info for the given cert
*/
static nsresult
GetBase64HashSPKI(const CERTCertificate* cert, nsACString& hashSPKIDigest)
{
hashSPKIDigest.Truncate();
Digest digest;
nsresult rv = digest.DigestBuf(SEC_OID_SHA256, cert->derPublicKey.data,
cert->derPublicKey.len);
if (NS_FAILED(rv)) {
return rv;
}
return Base64Encode(nsDependentCSubstring(
BitwiseCast<char*, unsigned char*>(digest.get().data),
digest.get().len),
hashSPKIDigest);
}
/*
* Sets certMatchesPinset to true if a given cert matches any fingerprints from
* the given pinset or the dynamicFingerprints array, or to false otherwise.
*/
static nsresult
EvalCert(const CERTCertificate* cert, const StaticFingerprints* fingerprints,
const nsTArray<nsCString>* dynamicFingerprints,
/*out*/ bool& certMatchesPinset)
{
certMatchesPinset = false;
if (!fingerprints && !dynamicFingerprints) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: No hashes found\n"));
return NS_ERROR_INVALID_ARG;
}
nsAutoCString base64Out;
nsresult rv = GetBase64HashSPKI(cert, base64Out);
if (NS_FAILED(rv)) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: GetBase64HashSPKI failed!\n"));
return rv;
}
if (fingerprints) {
for (size_t i = 0; i < fingerprints->size; i++) {
if (base64Out.Equals(fingerprints->data[i])) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: found pin base_64 ='%s'\n", base64Out.get()));
certMatchesPinset = true;
return NS_OK;
}
}
}
if (dynamicFingerprints) {
for (size_t i = 0; i < dynamicFingerprints->Length(); i++) {
if (base64Out.Equals((*dynamicFingerprints)[i])) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: found pin base_64 ='%s'\n", base64Out.get()));
certMatchesPinset = true;
return NS_OK;
}
}
}
return NS_OK;
}
/*
* Sets certListIntersectsPinset to true if a given chain matches any
* fingerprints from the given static fingerprints or the
* dynamicFingerprints array, or to false otherwise.
*/
static nsresult
EvalChain(const UniqueCERTCertList& certList,
const StaticFingerprints* fingerprints,
const nsTArray<nsCString>* dynamicFingerprints,
/*out*/ bool& certListIntersectsPinset)
{
certListIntersectsPinset = false;
CERTCertificate* currentCert;
if (!fingerprints && !dynamicFingerprints) {
MOZ_ASSERT(false, "Must pass in at least one type of pinset");
return NS_ERROR_FAILURE;
}
CERTCertListNode* node;
for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
node = CERT_LIST_NEXT(node)) {
currentCert = node->cert;
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: certArray subject: '%s'\n", currentCert->subjectName));
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: certArray issuer: '%s'\n", currentCert->issuerName));
nsresult rv = EvalCert(currentCert, fingerprints, dynamicFingerprints,
certListIntersectsPinset);
if (NS_FAILED(rv)) {
return rv;
}
if (certListIntersectsPinset) {
return NS_OK;
}
}
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug, ("pkpin: no matches found\n"));
return NS_OK;
}
/**
Comparator for the is public key pinned host.
*/
static int
TransportSecurityPreloadCompare(const void* key, const void* entry) {
auto keyStr = static_cast<const char*>(key);
auto preloadEntry = static_cast<const TransportSecurityPreload*>(entry);
return strcmp(keyStr, preloadEntry->mHost);
}
nsresult
PublicKeyPinningService::ChainMatchesPinset(const UniqueCERTCertList& certList,
const nsTArray<nsCString>& aSHA256keys,
/*out*/ bool& chainMatchesPinset)
{
return EvalChain(certList, nullptr, &aSHA256keys, chainMatchesPinset);
}
// Returns via one of the output parameters the most relevant pinning
// information that is valid for the given host at the given time.
// Dynamic pins are prioritized over static pins.
static nsresult
FindPinningInformation(const char* hostname, mozilla::pkix::Time time,
/*out*/ nsTArray<nsCString>& dynamicFingerprints,
/*out*/ TransportSecurityPreload*& staticFingerprints)
{
if (!hostname || hostname[0] == 0) {
return NS_ERROR_INVALID_ARG;
}
staticFingerprints = nullptr;
dynamicFingerprints.Clear();
nsCOMPtr<nsISiteSecurityService> sssService =
do_GetService(NS_SSSERVICE_CONTRACTID);
if (!sssService) {
return NS_ERROR_FAILURE;
}
TransportSecurityPreload* foundEntry = nullptr;
char* evalHost = const_cast<char*>(hostname);
char* evalPart;
// Notice how the (xx = strchr) prevents pins for unqualified domain names.
while (!foundEntry && (evalPart = strchr(evalHost, '.'))) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Querying pinsets for host: '%s'\n", evalHost));
// Attempt dynamic pins first
nsresult rv;
bool found;
bool includeSubdomains;
nsTArray<nsCString> pinArray;
rv = sssService->GetKeyPinsForHostname(evalHost, time, pinArray,
&includeSubdomains, &found);
if (NS_FAILED(rv)) {
return rv;
}
if (found && (evalHost == hostname || includeSubdomains)) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Found dyn match for host: '%s'\n", evalHost));
dynamicFingerprints = pinArray;
return NS_OK;
}
foundEntry = (TransportSecurityPreload *)bsearch(evalHost,
kPublicKeyPinningPreloadList,
sizeof(kPublicKeyPinningPreloadList) / sizeof(TransportSecurityPreload),
sizeof(TransportSecurityPreload),
TransportSecurityPreloadCompare);
if (foundEntry) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Found pinset for host: '%s'\n", evalHost));
if (evalHost != hostname) {
if (!foundEntry->mIncludeSubdomains) {
// Does not apply to this host, continue iterating
foundEntry = nullptr;
}
}
} else {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Didn't find pinset for host: '%s'\n", evalHost));
}
// Add one for '.'
evalHost = evalPart + 1;
}
if (foundEntry && foundEntry->pinset) {
if (time > TimeFromEpochInSeconds(kPreloadPKPinsExpirationTime /
PR_USEC_PER_SEC)) {
return NS_OK;
}
staticFingerprints = foundEntry;
}
return NS_OK;
}
// Returns true via the output parameter if the given certificate list meets
// pinning requirements for the given host at the given time. It must be the
// case that either there is an intersection between the set of hashes of
// subject public key info data in the list and the most relevant non-expired
// pinset for the host or there is no pinning information for the host.
static nsresult
CheckPinsForHostname(const UniqueCERTCertList& certList, const char* hostname,
bool enforceTestMode, mozilla::pkix::Time time,
/*out*/ bool& chainHasValidPins)
{
chainHasValidPins = false;
if (!certList) {
return NS_ERROR_INVALID_ARG;
}
if (!hostname || hostname[0] == 0) {
return NS_ERROR_INVALID_ARG;
}
nsTArray<nsCString> dynamicFingerprints;
TransportSecurityPreload* staticFingerprints = nullptr;
nsresult rv = FindPinningInformation(hostname, time, dynamicFingerprints,
staticFingerprints);
// If we have no pinning information, the certificate chain trivially
// validates with respect to pinning.
if (dynamicFingerprints.Length() == 0 && !staticFingerprints) {
chainHasValidPins = true;
return NS_OK;
}
if (dynamicFingerprints.Length() > 0) {
return EvalChain(certList, nullptr, &dynamicFingerprints, chainHasValidPins);
}
if (staticFingerprints) {
bool enforceTestModeResult;
rv = EvalChain(certList, staticFingerprints->pinset, nullptr,
enforceTestModeResult);
if (NS_FAILED(rv)) {
return rv;
}
chainHasValidPins = enforceTestModeResult;
if (staticFingerprints->mTestMode) {
if (!enforceTestMode) {
chainHasValidPins = true;
}
}
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Pin check %s for %s host '%s' (mode=%s)\n",
enforceTestModeResult ? "passed" : "failed",
staticFingerprints->mIsMoz ? "mozilla" : "non-mozilla",
hostname, staticFingerprints->mTestMode ? "test" : "production"));
}
return NS_OK;
}
nsresult
PublicKeyPinningService::ChainHasValidPins(const UniqueCERTCertList& certList,
const char* hostname,
mozilla::pkix::Time time,
bool enforceTestMode,
/*out*/ bool& chainHasValidPins)
{
chainHasValidPins = false;
if (!certList) {
return NS_ERROR_INVALID_ARG;
}
if (!hostname || hostname[0] == 0) {
return NS_ERROR_INVALID_ARG;
}
nsAutoCString canonicalizedHostname(CanonicalizeHostname(hostname));
return CheckPinsForHostname(certList, canonicalizedHostname.get(),
enforceTestMode, time, chainHasValidPins);
}
nsresult
PublicKeyPinningService::HostHasPins(const char* hostname,
mozilla::pkix::Time time,
bool enforceTestMode,
/*out*/ bool& hostHasPins)
{
hostHasPins = false;
nsAutoCString canonicalizedHostname(CanonicalizeHostname(hostname));
nsTArray<nsCString> dynamicFingerprints;
TransportSecurityPreload* staticFingerprints = nullptr;
nsresult rv = FindPinningInformation(canonicalizedHostname.get(), time,
dynamicFingerprints, staticFingerprints);
if (NS_FAILED(rv)) {
return rv;
}
if (dynamicFingerprints.Length() > 0) {
hostHasPins = true;
} else if (staticFingerprints) {
hostHasPins = !staticFingerprints->mTestMode || enforceTestMode;
}
return NS_OK;
}
nsAutoCString
PublicKeyPinningService::CanonicalizeHostname(const char* hostname)
{
nsAutoCString canonicalizedHostname(hostname);
ToLowerCase(canonicalizedHostname);
while (canonicalizedHostname.Length() > 0 &&
canonicalizedHostname.Last() == '.') {
canonicalizedHostname.Truncate(canonicalizedHostname.Length() - 1);
}
return canonicalizedHostname;
}

View file

@ -1,64 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef PublicKeyPinningService_h
#define PublicKeyPinningService_h
#include "CertVerifier.h"
#include "ScopedNSSTypes.h"
#include "cert.h"
#include "nsString.h"
#include "nsTArray.h"
#include "pkix/Time.h"
namespace mozilla {
namespace psm {
class PublicKeyPinningService
{
public:
/**
* Sets chainHasValidPins to true if the given (host, certList) passes pinning
* checks, or to false otherwise. If the host is pinned, returns true via
* chainHasValidPins if one of the keys in the given certificate chain matches
* the pin set specified by the hostname. The certList's head is the EE cert
* and the tail is the trust anchor.
* Note: if an alt name is a wildcard, it won't necessarily find a pinset
* that would otherwise be valid for it
*/
static nsresult ChainHasValidPins(const UniqueCERTCertList& certList,
const char* hostname,
mozilla::pkix::Time time,
bool enforceTestMode,
/*out*/ bool& chainHasValidPins);
/**
* Sets chainMatchesPinset to true if there is any intersection between the
* certificate list and the pins specified in the aSHA256keys array.
* Values passed in are assumed to be in base64 encoded form.
*/
static nsresult ChainMatchesPinset(const UniqueCERTCertList& certList,
const nsTArray<nsCString>& aSHA256keys,
/*out*/ bool& chainMatchesPinset);
/**
* Returns true via the output parameter hostHasPins if there is pinning
* information for the given host that is valid at the given time, and false
* otherwise.
*/
static nsresult HostHasPins(const char* hostname,
mozilla::pkix::Time time,
bool enforceTestMode,
/*out*/ bool& hostHasPins);
/**
* Given a hostname of potentially mixed case with potentially multiple
* trailing '.' (see bug 1118522), canonicalizes it to lowercase with no
* trailing '.'.
*/
static nsAutoCString CanonicalizeHostname(const char* hostname);
};
}} // namespace mozilla::psm
#endif // PublicKeyPinningService_h

View file

@ -1,712 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*****************************************************************************/
/* This is an automatically generated file. If you're not */
/* 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=";
/* AffirmTrust Commercial */
static const char kAffirmTrust_CommercialFingerprint[] =
"bEZLmlsjOl6HTadlwm8EUBDS3c/0V5TwtMfkqvpQFJU=";
/* AffirmTrust Networking */
static const char kAffirmTrust_NetworkingFingerprint[] =
"lAcq0/WPcPkwmOWl9sBMlscQvYSdgxhJGa6Q64kK5AA=";
/* AffirmTrust Premium */
static const char kAffirmTrust_PremiumFingerprint[] =
"x/Q7TPW3FWgpT4IrU3YmBfbd0Vyt7Oc56eLDy6YenWc=";
/* AffirmTrust Premium ECC */
static const char kAffirmTrust_Premium_ECCFingerprint[] =
"MhmwkRT/SVo+tusAwu/qs0ACrl8KVsdnnqCHo/oDfk8=";
/* Baltimore CyberTrust Root */
static const char kBaltimore_CyberTrust_RootFingerprint[] =
"Y9mvm0exBk1JoQ57f9Vm28jKo5lFm/woKcVxrYxu80o=";
/* COMODO Certification Authority */
static const char kCOMODO_Certification_AuthorityFingerprint[] =
"AG1751Vd2CAmRCxPGieoDomhmJy4ezREjtIZTBgZbV4=";
/* COMODO ECC Certification Authority */
static const char kCOMODO_ECC_Certification_AuthorityFingerprint[] =
"58qRu/uxh4gFezqAcERupSkRYBlBAvfcw7mEjGPLnNU=";
/* COMODO RSA Certification Authority */
static const char kCOMODO_RSA_Certification_AuthorityFingerprint[] =
"grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=";
/* 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=";
/* Cybertrust Global Root */
static const char kCybertrust_Global_RootFingerprint[] =
"foeCwVDOOVL4AuY2AjpdPpW7XWjjPoWtsroXgSXOvxU=";
/* DST Root CA X3 */
static const char kDST_Root_CA_X3Fingerprint[] =
"Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=";
/* DigiCert Assured ID Root CA */
static const char kDigiCert_Assured_ID_Root_CAFingerprint[] =
"I/Lt/z7ekCWanjD0Cvj5EqXls2lOaThEA0H2Bg4BT/o=";
/* DigiCert Assured ID Root G2 */
static const char kDigiCert_Assured_ID_Root_G2Fingerprint[] =
"8ca6Zwz8iOTfUpc8rkIPCgid1HQUT+WAbEIAZOFZEik=";
/* DigiCert Assured ID Root G3 */
static const char kDigiCert_Assured_ID_Root_G3Fingerprint[] =
"Fe7TOVlLME+M+Ee0dzcdjW/sYfTbKwGvWJ58U7Ncrkw=";
/* DigiCert Global Root CA */
static const char kDigiCert_Global_Root_CAFingerprint[] =
"r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=";
/* DigiCert Global Root G2 */
static const char kDigiCert_Global_Root_G2Fingerprint[] =
"i7WTqTvh0OioIruIfFR4kMPnBqrS2rdiVPl/s2uC/CY=";
/* DigiCert Global Root G3 */
static const char kDigiCert_Global_Root_G3Fingerprint[] =
"uUwZgwDOxcBXrQcntwu+kYFpkiVkOaezL0WYEZ3anJc=";
/* DigiCert High Assurance EV Root CA */
static const char kDigiCert_High_Assurance_EV_Root_CAFingerprint[] =
"WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=";
/* DigiCert Trusted Root G4 */
static const char kDigiCert_Trusted_Root_G4Fingerprint[] =
"Wd8xe/qfTwq3ylFNd3IpaqLHZbh2ZNCLluVzmeNkcpw=";
/* End Entity Test Cert */
static const char kEnd_Entity_Test_CertFingerprint[] =
"VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
/* Entrust Root Certification Authority */
static const char kEntrust_Root_Certification_AuthorityFingerprint[] =
"bb+uANN7nNc/j7R95lkXrwDg3d9C286sIMF8AnXuIJU=";
/* Entrust Root Certification Authority - EC1 */
static const char kEntrust_Root_Certification_Authority___EC1Fingerprint[] =
"/qK31kX7pz11PB7Jp4cMQOH3sMVh6Se5hb9xGGbjbyI=";
/* Entrust Root Certification Authority - G2 */
static const char kEntrust_Root_Certification_Authority___G2Fingerprint[] =
"du6FkDdMcVQ3u8prumAo6t3i3G27uMP2EOhR8R0at/U=";
/* Entrust.net Premium 2048 Secure Server CA */
static const char kEntrust_net_Premium_2048_Secure_Server_CAFingerprint[] =
"HqPF5D7WbC2imDpCpKebHpBnhs6fG1hiFBmgBGOofTg=";
/* FacebookBackup */
static const char kFacebookBackupFingerprint[] =
"q4PO2G2cbkZhZ82+JgmRUyGMoAeozA+BSXVXQWB8XWQ=";
/* GOOGLE_PIN_COMODORSADomainValidationSecureServerCA */
static const char kGOOGLE_PIN_COMODORSADomainValidationSecureServerCAFingerprint[] =
"klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=";
/* GOOGLE_PIN_DigiCertECCSecureServerCA */
static const char kGOOGLE_PIN_DigiCertECCSecureServerCAFingerprint[] =
"PZXN3lRAy+8tBKk2Ox6F7jIlnzr2Yzmwqc3JnyfXoCw=";
/* GOOGLE_PIN_DigiCertSHA2HighAssuranceServerCA */
static const char kGOOGLE_PIN_DigiCertSHA2HighAssuranceServerCAFingerprint[] =
"k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws=";
/* GOOGLE_PIN_Entrust_SSL */
static const char kGOOGLE_PIN_Entrust_SSLFingerprint[] =
"nsxRNo6G40YPZsKV5JQt1TCA8nseQQr/LRqp1Oa8fnw=";
/* GOOGLE_PIN_GTECyberTrustGlobalRoot */
static const char kGOOGLE_PIN_GTECyberTrustGlobalRootFingerprint[] =
"EGn6R6CqT4z3ERscrqNl7q7RC//zJmDe9uBhS/rnCHU=";
/* GOOGLE_PIN_GoDaddySecure */
static const char kGOOGLE_PIN_GoDaddySecureFingerprint[] =
"MrZLZnJ6IGPkBm87lYywqu5Xal7O/ZUzmbuIdHMdlYc=";
/* GOOGLE_PIN_GoogleG2 */
static const char kGOOGLE_PIN_GoogleG2Fingerprint[] =
"7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=";
/* GOOGLE_PIN_LetsEncryptAuthorityBackup_X2_X4 */
static const char kGOOGLE_PIN_LetsEncryptAuthorityBackup_X2_X4Fingerprint[] =
"sRHdihwgkaib1P1gxX8HFszlD+7/gTfNvuAybgLPNis=";
/* GOOGLE_PIN_LetsEncryptAuthorityPrimary_X1_X3 */
static const char kGOOGLE_PIN_LetsEncryptAuthorityPrimary_X1_X3Fingerprint[] =
"YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=";
/* GOOGLE_PIN_RapidSSL */
static const char kGOOGLE_PIN_RapidSSLFingerprint[] =
"lT09gPUeQfbYrlxRtpsHrjDblj9Rpz+u7ajfCrg4qDM=";
/* GOOGLE_PIN_SymantecClass3EVG3 */
static const char kGOOGLE_PIN_SymantecClass3EVG3Fingerprint[] =
"gMxWOrX4PMQesK9qFNbYBxjBfjUvlkn/vN1n+L9lE5E=";
/* GOOGLE_PIN_UTNDATACorpSGC */
static const char kGOOGLE_PIN_UTNDATACorpSGCFingerprint[] =
"QAL80xHQczFWfnG82XHkYEjI3OjRZZcRdTs9qiommvo=";
/* GOOGLE_PIN_VeriSignClass1 */
static const char kGOOGLE_PIN_VeriSignClass1Fingerprint[] =
"LclHC+Y+9KzxvYKGCUArt7h72ZY4pkOTTohoLRvowwg=";
/* GOOGLE_PIN_VeriSignClass2_G2 */
static const char kGOOGLE_PIN_VeriSignClass2_G2Fingerprint[] =
"2oALgLKofTmeZvoZ1y/fSZg7R9jPMix8eVA6DH4o/q8=";
/* GOOGLE_PIN_VeriSignClass3_G2 */
static const char kGOOGLE_PIN_VeriSignClass3_G2Fingerprint[] =
"AjyBzOjnxk+pQtPBUEhwfTXZu1uH9PVExb8bxWQ68vo=";
/* GOOGLE_PIN_VeriSignClass4_G3 */
static const char kGOOGLE_PIN_VeriSignClass4_G3Fingerprint[] =
"VnuCEf0g09KD7gzXzgZyy52ZvFtIeljJ1U7Gf3fUqPU=";
/* GeoTrust Global CA */
static const char kGeoTrust_Global_CAFingerprint[] =
"h6801m+z8v3zbgkRHpq6L29Esgfzhj89C1SyUCOQmqU=";
/* GeoTrust Global CA 2 */
static const char kGeoTrust_Global_CA_2Fingerprint[] =
"F3VaXClfPS1y5vAxofB/QAxYi55YKyLxfq4xoVkNEYU=";
/* GeoTrust Primary Certification Authority */
static const char kGeoTrust_Primary_Certification_AuthorityFingerprint[] =
"SQVGZiOrQXi+kqxcvWWE96HhfydlLVqFr4lQTqI5qqo=";
/* GeoTrust Primary Certification Authority - G2 */
static const char kGeoTrust_Primary_Certification_Authority___G2Fingerprint[] =
"vPtEqrmtAhAVcGtBIep2HIHJ6IlnWQ9vlK50TciLePs=";
/* GeoTrust Primary Certification Authority - G3 */
static const char kGeoTrust_Primary_Certification_Authority___G3Fingerprint[] =
"q5hJUnat8eyv8o81xTBIeB5cFxjaucjmelBPT2pRMo8=";
/* GeoTrust Universal CA */
static const char kGeoTrust_Universal_CAFingerprint[] =
"lpkiXF3lLlbN0y3y6W0c/qWqPKC7Us2JM8I7XCdEOCA=";
/* GeoTrust Universal CA 2 */
static const char kGeoTrust_Universal_CA_2Fingerprint[] =
"fKoDRlEkWQxgHlZ+UhSOlSwM/+iQAFMP4NlbbVDqrkE=";
/* GlobalSign ECC Root CA - R4 */
static const char kGlobalSign_ECC_Root_CA___R4Fingerprint[] =
"CLOmM1/OXvSPjw5UOYbAf9GKOxImEp9hhku9W90fHMk=";
/* GlobalSign ECC Root CA - R5 */
static const char kGlobalSign_ECC_Root_CA___R5Fingerprint[] =
"fg6tdrtoGdwvVFEahDVPboswe53YIFjqbABPAdndpd8=";
/* 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=";
/* Go Daddy Class 2 CA */
static const char kGo_Daddy_Class_2_CAFingerprint[] =
"VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8=";
/* Go Daddy Root Certificate Authority - G2 */
static const char kGo_Daddy_Root_Certificate_Authority___G2Fingerprint[] =
"Ko8tivDrEjiY90yGasP6ZpBU4jwXvHqVvQI0GS3GNdA=";
/* GoogleBackup2048 */
static const char kGoogleBackup2048Fingerprint[] =
"IPMbDAjLVSGntGO3WP53X/zilCVndez5YJ2+vJvhJsA=";
/* SpiderOak2 */
static const char kSpiderOak2Fingerprint[] =
"7Y3UnxbffL8aFPXsOJBpGasgpDmngpIhAxGKdQRklQQ=";
/* SpiderOak3 */
static const char kSpiderOak3Fingerprint[] =
"LkER54vOdlygpTsbYvlpMq1CE/lDAG1AP9xmdtwvV2A=";
/* Starfield Class 2 CA */
static const char kStarfield_Class_2_CAFingerprint[] =
"FfFKxFycfaIz00eRZOgTf+Ne4POK6FgYPwhBDqgqxLQ=";
/* Starfield Root Certificate Authority - G2 */
static const char kStarfield_Root_Certificate_Authority___G2Fingerprint[] =
"gI1os/q0iEpflxrOfRBVDXqVoWN3Tz7Dav/7IT++THQ=";
/* Swehack */
static const char kSwehackFingerprint[] =
"FdaffE799rVb3oyAuhJ2mBW/XJwD07Uajb2G6YwSAEw=";
/* SwehackBackup */
static const char kSwehackBackupFingerprint[] =
"z6cuswA6E1vgFkCjUsbEYo0Lf3aP8M8YOvwkoiGzDCo=";
/* TestSPKI */
static const char kTestSPKIFingerprint[] =
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
/* Tor1 */
static const char kTor1Fingerprint[] =
"bYz9JTDk89X3qu3fgswG+lBQso5vI0N1f0Rx4go4nLo=";
/* Tor2 */
static const char kTor2Fingerprint[] =
"xXCxhTdn7uxXneJSbQCqoAvuW3ZtQl2pDVTf2sewS8w=";
/* Tor3 */
static const char kTor3Fingerprint[] =
"CleC1qwUR8JPgH1nXvSe2VHxDe5/KfNs96EusbfSOfo=";
/* TumblrBackup */
static const char kTumblrBackupFingerprint[] =
"avlD96PLERV78IN1fD+ab5cupkUDD9wTZWJjHX6VC9w=";
/* Twitter1 */
static const char kTwitter1Fingerprint[] =
"vU9M48LzD/CF34wE5PPf4nBwRyosy06X21J0ap8yS5s=";
/* USERTrust ECC Certification Authority */
static const char kUSERTrust_ECC_Certification_AuthorityFingerprint[] =
"ICGRfpgmOUXIWcQ/HXPLQTkFPEFPoDyjvH7ohhQpjzs=";
/* USERTrust RSA Certification Authority */
static const char kUSERTrust_RSA_Certification_AuthorityFingerprint[] =
"x4QzPSC810K5/cMjb05Qm4k3Bw5zBn4lTdO/nEW/Td4=";
/* 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[] =
"UZJDjsNp1+4M5x9cbbdflB779y5YRBcV6Z6rBMLIrO4=";
/* VeriSign Class 3 Public Primary Certification Authority - G5 */
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[] =
"lnsM2T/O9/J84sJFdnrpsFp3awZJ+ZZbYpCWhGloaHI=";
/* Verisign Class 1 Public Primary Certification Authority - G3 */
static const char kVerisign_Class_1_Public_Primary_Certification_Authority___G3Fingerprint[] =
"IgduWu9Eu5pBaii30cRDItcFn2D+/6XK9sW+hEeJEwM=";
/* Verisign Class 2 Public Primary Certification Authority - G3 */
static const char kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint[] =
"cAajgxHlj7GTSEIzIYIQxmEloOSoJq7VOaxWHfv72QM=";
/* Verisign Class 3 Public Primary Certification Authority - G3 */
static const char kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint[] =
"SVqWumuteCQHvVIaALrOZXuzVVVeS7f4FGxxu6V+es4=";
/* YahooBackup1 */
static const char kYahooBackup1Fingerprint[] =
"2fRAUXyxl4A1/XHrKNBmc8bTkzA7y4FB/GLJuNAzCqY=";
/* YahooBackup2 */
static const char kYahooBackup2Fingerprint[] =
"dolnbtzEBnELx/9lOEQ22e6OZO/QNb6VSSX2XHA3E7A=";
/* thawte Primary Root CA */
static const char kthawte_Primary_Root_CAFingerprint[] =
"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=";
/* thawte Primary Root CA - G2 */
static const char kthawte_Primary_Root_CA___G2Fingerprint[] =
"Z9xPMvoQ59AaeaBzqgyeAhLsL/w9d54Kp/nA8OHCyJM=";
/* thawte Primary Root CA - G3 */
static const char kthawte_Primary_Root_CA___G3Fingerprint[] =
"GQbGEk27Q4V40A4GbVBUxsN/D6YCjAVUXgmU7drshik=";
/* Pinsets are each an ordered list by the actual value of the fingerprint */
struct StaticFingerprints {
const size_t size;
const char* const* data;
};
/* PreloadedHPKPins.json pinsets */
static const char* const kPinset_google_root_pems_Data[] = {
kEntrust_Root_Certification_Authority___EC1Fingerprint,
kComodo_Trusted_Services_rootFingerprint,
kCOMODO_ECC_Certification_AuthorityFingerprint,
kDigiCert_Assured_ID_Root_G2Fingerprint,
kCOMODO_Certification_AuthorityFingerprint,
kAddTrust_Low_Value_Services_RootFingerprint,
kGlobalSign_ECC_Root_CA___R4Fingerprint,
kGeoTrust_Global_CA_2Fingerprint,
kDigiCert_Assured_ID_Root_G3Fingerprint,
kStarfield_Class_2_CAFingerprint,
kthawte_Primary_Root_CA___G3Fingerprint,
kthawte_Primary_Root_CAFingerprint,
kEntrust_net_Premium_2048_Secure_Server_CAFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kUSERTrust_ECC_Certification_AuthorityFingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kGlobalSign_Root_CAFingerprint,
kGo_Daddy_Root_Certificate_Authority___G2Fingerprint,
kAffirmTrust_Premium_ECCFingerprint,
kAddTrust_Public_Services_RootFingerprint,
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,
kGo_Daddy_Class_2_CAFingerprint,
kDigiCert_Trusted_Root_G4Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kBaltimore_CyberTrust_RootFingerprint,
kthawte_Primary_Root_CA___G2Fingerprint,
kAffirmTrust_CommercialFingerprint,
kEntrust_Root_Certification_AuthorityFingerprint,
kGlobalSign_Root_CA___R3Fingerprint,
kEntrust_Root_Certification_Authority___G2Fingerprint,
kGeoTrust_Universal_CA_2Fingerprint,
kGlobalSign_ECC_Root_CA___R5Fingerprint,
kCybertrust_Global_RootFingerprint,
kStarfield_Root_Certificate_Authority___G2Fingerprint,
kCOMODO_RSA_Certification_AuthorityFingerprint,
kGeoTrust_Global_CAFingerprint,
kDigiCert_Global_Root_G2Fingerprint,
kGlobalSign_Root_CA___R2Fingerprint,
kAffirmTrust_NetworkingFingerprint,
kAddTrust_External_RootFingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kGeoTrust_Universal_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
kDigiCert_Global_Root_G3Fingerprint,
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
kComodo_AAA_Services_rootFingerprint,
kAffirmTrust_PremiumFingerprint,
kUSERTrust_RSA_Certification_AuthorityFingerprint,
kAddTrust_Qualified_Certificates_RootFingerprint,
};
static const StaticFingerprints kPinset_google_root_pems = {
sizeof(kPinset_google_root_pems_Data) / sizeof(const char*),
kPinset_google_root_pems_Data
};
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,
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 = {
sizeof(kPinset_mozilla_Data) / sizeof(const char*),
kPinset_mozilla_Data
};
static const char* const kPinset_mozilla_services_Data[] = {
kDigiCert_Global_Root_CAFingerprint,
};
static const StaticFingerprints kPinset_mozilla_services = {
sizeof(kPinset_mozilla_services_Data) / sizeof(const char*),
kPinset_mozilla_services_Data
};
static const char* const kPinset_mozilla_test_Data[] = {
kEnd_Entity_Test_CertFingerprint,
};
static const StaticFingerprints kPinset_mozilla_test = {
sizeof(kPinset_mozilla_test_Data) / sizeof(const char*),
kPinset_mozilla_test_Data
};
/* Chrome static pinsets */
static const char* const kPinset_test_Data[] = {
kTestSPKIFingerprint,
};
static const StaticFingerprints kPinset_test = {
sizeof(kPinset_test_Data) / sizeof(const char*),
kPinset_test_Data
};
static const char* const kPinset_google_Data[] = {
kGOOGLE_PIN_GoogleG2Fingerprint,
kGoogleBackup2048Fingerprint,
kGeoTrust_Global_CAFingerprint,
kGlobalSign_Root_CA___R2Fingerprint,
};
static const StaticFingerprints kPinset_google = {
sizeof(kPinset_google_Data) / sizeof(const char*),
kPinset_google_Data
};
static const char* const kPinset_tor_Data[] = {
kTor3Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityPrimary_X1_X3Fingerprint,
kTor1Fingerprint,
kGOOGLE_PIN_RapidSSLFingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityBackup_X2_X4Fingerprint,
kTor2Fingerprint,
};
static const StaticFingerprints kPinset_tor = {
sizeof(kPinset_tor_Data) / sizeof(const char*),
kPinset_tor_Data
};
static const char* const kPinset_twitterCom_Data[] = {
kGOOGLE_PIN_VeriSignClass2_G2Fingerprint,
kGOOGLE_PIN_VeriSignClass3_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,
kGOOGLE_PIN_VeriSignClass1Fingerprint,
kGeoTrust_Primary_Certification_AuthorityFingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kGOOGLE_PIN_VeriSignClass4_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,
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
kTwitter1Fingerprint,
};
static const StaticFingerprints kPinset_twitterCom = {
sizeof(kPinset_twitterCom_Data) / sizeof(const char*),
kPinset_twitterCom_Data
};
static const char* const kPinset_twitterCDN_Data[] = {
kGOOGLE_PIN_VeriSignClass2_G2Fingerprint,
kComodo_Trusted_Services_rootFingerprint,
kCOMODO_Certification_AuthorityFingerprint,
kGOOGLE_PIN_VeriSignClass3_G2Fingerprint,
kAddTrust_Low_Value_Services_RootFingerprint,
kUTN_USERFirst_Object_Root_CAFingerprint,
kGOOGLE_PIN_GTECyberTrustGlobalRootFingerprint,
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,
kGOOGLE_PIN_VeriSignClass1Fingerprint,
kAddTrust_Public_Services_RootFingerprint,
kGOOGLE_PIN_UTNDATACorpSGCFingerprint,
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,
kGOOGLE_PIN_VeriSignClass4_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,
kEntrust_Root_Certification_Authority___G2Fingerprint,
kGeoTrust_Universal_CA_2Fingerprint,
kGeoTrust_Global_CAFingerprint,
kGlobalSign_Root_CA___R2Fingerprint,
kAddTrust_External_RootFingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kGeoTrust_Universal_CAFingerprint,
kGOOGLE_PIN_Entrust_SSLFingerprint,
kGeoTrust_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
kComodo_AAA_Services_rootFingerprint,
kTwitter1Fingerprint,
kAddTrust_Qualified_Certificates_RootFingerprint,
};
static const StaticFingerprints kPinset_twitterCDN = {
sizeof(kPinset_twitterCDN_Data) / sizeof(const char*),
kPinset_twitterCDN_Data
};
static const char* const kPinset_dropbox_Data[] = {
kEntrust_Root_Certification_Authority___EC1Fingerprint,
kEntrust_net_Premium_2048_Secure_Server_CAFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kGo_Daddy_Root_Certificate_Authority___G2Fingerprint,
kGOOGLE_PIN_GoDaddySecureFingerprint,
kGo_Daddy_Class_2_CAFingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kEntrust_Root_Certification_AuthorityFingerprint,
kEntrust_Root_Certification_Authority___G2Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
};
static const StaticFingerprints kPinset_dropbox = {
sizeof(kPinset_dropbox_Data) / sizeof(const char*),
kPinset_dropbox_Data
};
static const char* const kPinset_facebook_Data[] = {
kGOOGLE_PIN_DigiCertECCSecureServerCAFingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kGOOGLE_PIN_SymantecClass3EVG3Fingerprint,
kFacebookBackupFingerprint,
};
static const StaticFingerprints kPinset_facebook = {
sizeof(kPinset_facebook_Data) / sizeof(const char*),
kPinset_facebook_Data
};
static const char* const kPinset_spideroak_Data[] = {
kSpiderOak2Fingerprint,
kSpiderOak3Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kGeoTrust_Global_CAFingerprint,
};
static const StaticFingerprints kPinset_spideroak = {
sizeof(kPinset_spideroak_Data) / sizeof(const char*),
kPinset_spideroak_Data
};
static const char* const kPinset_yahoo_Data[] = {
kYahooBackup1Fingerprint,
kGOOGLE_PIN_VeriSignClass2_G2Fingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kDigiCert_Trusted_Root_G4Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint,
kYahooBackup2Fingerprint,
kDigiCert_Global_Root_G2Fingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kDigiCert_Global_Root_CAFingerprint,
kDigiCert_Global_Root_G3Fingerprint,
};
static const StaticFingerprints kPinset_yahoo = {
sizeof(kPinset_yahoo_Data) / sizeof(const char*),
kPinset_yahoo_Data
};
static const char* const kPinset_swehackCom_Data[] = {
kSwehackFingerprint,
kDST_Root_CA_X3Fingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityPrimary_X1_X3Fingerprint,
kGOOGLE_PIN_COMODORSADomainValidationSecureServerCAFingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityBackup_X2_X4Fingerprint,
kSwehackBackupFingerprint,
};
static const StaticFingerprints kPinset_swehackCom = {
sizeof(kPinset_swehackCom_Data) / sizeof(const char*),
kPinset_swehackCom_Data
};
static const char* const kPinset_ncsccs_Data[] = {
kCOMODO_ECC_Certification_AuthorityFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kBaltimore_CyberTrust_RootFingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityPrimary_X1_X3Fingerprint,
kCOMODO_RSA_Certification_AuthorityFingerprint,
kAddTrust_External_RootFingerprint,
kDigiCert_Global_Root_CAFingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityBackup_X2_X4Fingerprint,
};
static const StaticFingerprints kPinset_ncsccs = {
sizeof(kPinset_ncsccs_Data) / sizeof(const char*),
kPinset_ncsccs_Data
};
static const char* const kPinset_tumblr_Data[] = {
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kTumblrBackupFingerprint,
kGOOGLE_PIN_DigiCertSHA2HighAssuranceServerCAFingerprint,
};
static const StaticFingerprints kPinset_tumblr = {
sizeof(kPinset_tumblr_Data) / sizeof(const char*),
kPinset_tumblr_Data
};
/* Domainlist */
struct TransportSecurityPreload {
const char* mHost;
const bool mIncludeSubdomains;
const bool mTestMode;
const bool mIsMoz;
const int32_t mId;
const StaticFingerprints* pinset;
};
/* Sort hostnames for binary search. */
static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "exclude-subdomains.pinning.example.com", false, false, false, 0, &kPinset_mozilla_test },
{ "include-subdomains.pinning.example.com", true, false, false, -1, &kPinset_mozilla_test },
{ "test-mode.pinning.example.com", true, true, false, -1, &kPinset_mozilla_test },
};
// Pinning Preload List Length = 3;
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1609459199000000);

View file

@ -132,7 +132,6 @@ UNIFIED_SOURCES += [
'nsTLSSocketProvider.cpp',
'PSMContentListener.cpp',
'PSMRunnable.cpp',
'PublicKeyPinningService.cpp',
'SecretDecoderRing.cpp',
'SharedSSLState.cpp',
'SSLServerCertVerification.cpp',

View file

@ -27,7 +27,7 @@ namespace mozilla
interface nsISiteSecurityService : nsISupports
{
const uint32_t HEADER_HSTS = 0;
const uint32_t HEADER_HPKP = 1;
const uint32_t HEADER_HPKP = 1; /* no longer used */
const uint32_t HEADER_OMS = 2;
const uint32_t Success = 0;
@ -39,10 +39,10 @@ interface nsISiteSecurityService : nsISupports
const uint32_t ERROR_INVALID_MAX_AGE = 6;
const uint32_t ERROR_MULTIPLE_INCLUDE_SUBDOMAINS = 7;
const uint32_t ERROR_INVALID_INCLUDE_SUBDOMAINS = 8;
const uint32_t ERROR_INVALID_PIN = 9;
const uint32_t ERROR_MULTIPLE_REPORT_URIS = 10;
const uint32_t ERROR_PINSET_DOES_NOT_MATCH_CHAIN = 11;
const uint32_t ERROR_NO_BACKUP_PIN = 12;
const uint32_t ERROR_INVALID_PIN = 9; /* no longer used */
const uint32_t ERROR_MULTIPLE_REPORT_URIS = 10; /* no longer used */
const uint32_t ERROR_PINSET_DOES_NOT_MATCH_CHAIN = 11; /* no longer used */
const uint32_t ERROR_NO_BACKUP_PIN = 12; /* no longer used */
const uint32_t ERROR_COULD_NOT_SAVE_STATE = 13;
const uint32_t ERROR_ROOT_NOT_BUILT_IN = 14;
@ -150,42 +150,6 @@ interface nsISiteSecurityService : nsISupports
* settings.
*/
void clearAll();
/**
* Returns an array of sha256-hashed key pins for the given domain, if any.
* If these pins also apply to subdomains of the given domain,
* aIncludeSubdomains will be true. Pins returned are only for non-built-in
* pin entries.
*
* @param aHostname the hosname (punycode) to be queried about
* @param the time at which the pins should be valid. This is in
mozilla::pkix::Time which uses internally seconds since 0 AD.
* @param aPinArray the set of sha256-hashed key pins for the given domain
* @param aIncludeSubdomains true if the pins apply to subdomains of the
* given domain
*/
[noscript] boolean getKeyPinsForHostname(in string aHostname,
in mozillaPkixTime evalTime,
out nsCStringTArrayRef aPinArray,
out boolean aIncludeSubdomains);
/**
* Set public-key pins for a host. The resulting pins will be permanent
* and visible from private and non-private contexts. These pins replace
* any already set by this mechanism or those built-in to Gecko.
*
* @param aHost the hostname (punycode) that pins will apply to
* @param aIncludeSubdomains whether these pins also apply to subdomains
* @param aExpires the time this pin should expire (millis since epoch)
* @param aPinCount number of keys being pinnned
* @param aSha256Pins array of hashed key fingerprints (SHA-256, base64)
* @param aIsPreload are these key pins for a preload entry? (false by
* default)
*/
boolean setKeyPins(in string aHost, in boolean aIncludeSubdomains,
in int64_t aExpires, in unsigned long aPinCount,
[array, size_is(aPinCount)] in string aSha256Pins,
[optional] in boolean aIsPreload);
};
%{C++

View file

@ -25,7 +25,6 @@
#include "mozilla/Logging.h"
#include "prnetdb.h"
#include "prprf.h"
#include "PublicKeyPinningService.h"
#include "ScopedNSSTypes.h"
#include "SharedCertVerifier.h"
@ -86,123 +85,31 @@ SiteHSTSState::ToString(nsCString& aString)
aString.AppendInt(static_cast<uint32_t>(mHSTSIncludeSubdomains));
}
////////////////////////////////////////////////////////////////////////////////
static bool
stringIsBase64EncodingOf256bitValue(nsCString& encodedString) {
nsAutoCString binaryValue;
nsresult rv = mozilla::Base64Decode(encodedString, binaryValue);
if (NS_FAILED(rv)) {
return false;
}
if (binaryValue.Length() != SHA256_LENGTH) {
return false;
}
return true;
}
SiteHPKPState::SiteHPKPState()
: mExpireTime(0)
, mState(SecurityPropertyUnset)
, mIncludeSubdomains(false)
{
}
SiteHPKPState::SiteHPKPState(nsCString& aStateString)
: mExpireTime(0)
, mState(SecurityPropertyUnset)
, mIncludeSubdomains(false)
{
uint32_t hpkpState = 0;
uint32_t hpkpIncludeSubdomains = 0; // PR_sscanf doesn't handle bools.
const uint32_t MaxMergedHPKPPinSize = 1024;
char mergedHPKPins[MaxMergedHPKPPinSize];
memset(mergedHPKPins, 0, MaxMergedHPKPPinSize);
if (aStateString.Length() >= MaxMergedHPKPPinSize) {
SSSLOG(("SSS: Cannot parse PKPState string, too large\n"));
return;
}
int32_t matches = PR_sscanf(aStateString.get(), "%lld,%lu,%lu,%s",
&mExpireTime, &hpkpState,
&hpkpIncludeSubdomains, mergedHPKPins);
bool valid = (matches == 4 &&
(hpkpIncludeSubdomains == 0 || hpkpIncludeSubdomains == 1) &&
((SecurityPropertyState)hpkpState == SecurityPropertyUnset ||
(SecurityPropertyState)hpkpState == SecurityPropertySet ||
(SecurityPropertyState)hpkpState == SecurityPropertyKnockout));
SSSLOG(("SSS: loading SiteHPKPState matches=%d\n", matches));
const uint32_t SHA256Base64Len = 44;
if (valid && (SecurityPropertyState)hpkpState == SecurityPropertySet) {
// try to expand the merged PKPins
const char* cur = mergedHPKPins;
nsAutoCString pin;
uint32_t collectedLen = 0;
mergedHPKPins[MaxMergedHPKPPinSize - 1] = 0;
size_t totalLen = strlen(mergedHPKPins);
while (collectedLen + SHA256Base64Len <= totalLen) {
pin.Assign(cur, SHA256Base64Len);
if (stringIsBase64EncodingOf256bitValue(pin)) {
mSHA256keys.AppendElement(pin);
}
cur += SHA256Base64Len;
collectedLen += SHA256Base64Len;
}
if (mSHA256keys.IsEmpty()) {
valid = false;
}
}
if (valid) {
mState = (SecurityPropertyState)hpkpState;
mIncludeSubdomains = (hpkpIncludeSubdomains == 1);
} else {
SSSLOG(("%s is not a valid SiteHPKPState", aStateString.get()));
mExpireTime = 0;
mState = SecurityPropertyUnset;
mIncludeSubdomains = false;
if (!mSHA256keys.IsEmpty()) {
mSHA256keys.Clear();
}
}
}
SiteHPKPState::SiteHPKPState(PRTime aExpireTime,
SecurityPropertyState aState,
bool aIncludeSubdomains,
nsTArray<nsCString>& aSHA256keys)
: mExpireTime(aExpireTime)
, mState(aState)
, mIncludeSubdomains(aIncludeSubdomains)
, mSHA256keys(aSHA256keys)
{
}
void
SiteHPKPState::ToString(nsCString& aString)
{
aString.Truncate();
aString.AppendInt(mExpireTime);
aString.Append(',');
aString.AppendInt(mState);
aString.Append(',');
aString.AppendInt(static_cast<uint32_t>(mIncludeSubdomains));
aString.Append(',');
for (unsigned int i = 0; i < mSHA256keys.Length(); i++) {
aString.Append(mSHA256keys[i]);
}
}
////////////////////////////////////////////////////////////////////////////////
const uint64_t kSixtyDaysInSeconds = 60 * 24 * 60 * 60;
static bool
HostIsIPAddress(const char *hostname)
{
PRNetAddr hostAddr;
return (PR_StringToNetAddr(hostname, &hostAddr) == PR_SUCCESS);
}
nsAutoCString CanonicalizeHostname(const char* hostname)
{
nsAutoCString canonicalizedHostname(hostname);
ToLowerCase(canonicalizedHostname);
while (canonicalizedHostname.Length() > 0 &&
canonicalizedHostname.Last() == '.') {
canonicalizedHostname.Truncate(canonicalizedHostname.Length() - 1);
}
return canonicalizedHostname;
}
nsSiteSecurityService::nsSiteSecurityService()
: mMaxMaxAge(kSixtyDaysInSeconds)
, mUseStsService(true)
: mUseStsService(true)
, mPreloadListTimeOffset(0)
, mHPKPEnabled(false)
{
}
@ -223,30 +130,16 @@ nsSiteSecurityService::Init()
return NS_ERROR_NOT_SAME_THREAD;
}
mMaxMaxAge = mozilla::Preferences::GetInt(
"security.cert_pinning.max_max_age_seconds", kSixtyDaysInSeconds);
mozilla::Preferences::AddStrongObserver(this,
"security.cert_pinning.max_max_age_seconds");
mHPKPEnabled = mozilla::Preferences::GetBool(
"security.cert_pinning.hpkp.enabled", false);
mozilla::Preferences::AddStrongObserver(this,
"security.cert_pinning.hpkp.enabled");
mUseStsService = mozilla::Preferences::GetBool(
"network.stricttransportsecurity.enabled", true);
mozilla::Preferences::AddStrongObserver(this,
"network.stricttransportsecurity.enabled");
mProcessPKPHeadersFromNonBuiltInRoots = mozilla::Preferences::GetBool(
"security.cert_pinning.process_headers_from_non_builtin_roots", false);
mozilla::Preferences::AddStrongObserver(this,
"security.cert_pinning.process_headers_from_non_builtin_roots");
mPreloadListTimeOffset = mozilla::Preferences::GetInt(
"test.currentTimeOffsetSeconds", 0);
mozilla::Preferences::AddStrongObserver(this,
"test.currentTimeOffsetSeconds");
mSiteStateStorage =
mozilla::DataStorage::Get(NS_LITERAL_STRING("SiteSecurityServiceState.txt"));
mPreloadStateStorage =
mozilla::DataStorage::Get(NS_LITERAL_STRING("SecurityPreloadState.txt"));
bool storageWillPersist = false;
nsresult rv = mSiteStateStorage->Init(storageWillPersist);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -276,7 +169,7 @@ nsSiteSecurityService::GetHost(nsIURI* aURI, nsACString& aResult)
return rv;
}
aResult.Assign(PublicKeyPinningService::CanonicalizeHostname(host.get()));
aResult.Assign(CanonicalizeHostname(host.get()));
if (aResult.IsEmpty()) {
return NS_ERROR_UNEXPECTED;
}
@ -292,9 +185,6 @@ SetStorageKey(nsAutoCString& storageKey, nsCString& hostname, uint32_t aType)
case nsISiteSecurityService::HEADER_HSTS:
storageKey.AppendLiteral(":HSTS");
break;
case nsISiteSecurityService::HEADER_HPKP:
storageKey.AppendLiteral(":HPKP");
break;
default:
NS_ASSERTION(false, "SSS:SetStorageKey got invalid type");
}
@ -359,8 +249,7 @@ nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI, uint32_t aFlags
}
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
aType == nsISiteSecurityService::HEADER_HPKP,
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
nsAutoCString hostname;
@ -379,13 +268,6 @@ nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI, uint32_t aFlags
return NS_OK;
}
static bool
HostIsIPAddress(const char *hostname)
{
PRNetAddr hostAddr;
return (PR_StringToNetAddr(hostname, &hostAddr) == PR_SUCCESS);
}
NS_IMETHODIMP
nsSiteSecurityService::ProcessHeader(uint32_t aType,
nsIURI* aSourceURI,
@ -396,11 +278,6 @@ nsSiteSecurityService::ProcessHeader(uint32_t aType,
bool* aIncludeSubdomains,
uint32_t* aFailureResult)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::ProcessHeader");
}
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
}
@ -422,11 +299,6 @@ nsSiteSecurityService::UnsafeProcessHeader(uint32_t aType,
bool* aIncludeSubdomains,
uint32_t* aFailureResult)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::UnsafeProcessHeader");
}
return ProcessHeaderInternal(aType, aSourceURI, aHeader, nullptr, aFlags,
aMaxAge, aIncludeSubdomains, aFailureResult);
}
@ -444,9 +316,8 @@ nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
}
// Only HSTS and HPKP are supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
aType == nsISiteSecurityService::HEADER_HPKP,
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
if (aMaxAge != nullptr) {
@ -494,10 +365,6 @@ nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
rv = ProcessSTSHeader(aSourceURI, aHeader, aFlags, aMaxAge,
aIncludeSubdomains, aFailureResult);
break;
case nsISiteSecurityService::HEADER_HPKP:
rv = ProcessPKPHeader(aSourceURI, aHeader, aSSLStatus, aFlags, aMaxAge,
aIncludeSubdomains, aFailureResult);
break;
default:
MOZ_CRASH("unexpected header type");
}
@ -513,9 +380,6 @@ ParseSSSHeaders(uint32_t aType,
uint64_t& maxAge,
nsTArray<nsCString>& sha256keys)
{
// Strict transport security and Public Key Pinning have very similar
// Header formats.
// "Strict-Transport-Security" ":" OWS
// STS-d *( OWS ";" OWS STS-d OWS)
//
@ -527,26 +391,6 @@ ParseSSSHeaders(uint32_t aType,
// includeSubDomains = [ "includeSubDomains" ]
//
// "Public-Key-Pins ":" OWS
// PKP-d *( OWS ";" OWS PKP-d OWS)
//
// ; PKP directive
// PKP-d = maxAge / includeSubDomains / reportUri / pin-directive
//
// maxAge = "max-age" "=" delta-seconds v-ext
//
// includeSubDomains = [ "includeSubDomains" ]
//
// reportURi = "report-uri" "=" quoted-string
//
// pin-directive = "pin-" token "=" quoted-string
//
// the only valid token currently specified is sha256
// the quoted string for a pin directive is the base64 encoding
// of the hash of the public key of the fingerprint
//
// The order of the directives is not significant.
// All directives must appear only once.
// Directive names are case-insensitive.
// The entire header is invalid if a directive not conforming to the
@ -558,8 +402,6 @@ ParseSSSHeaders(uint32_t aType,
NS_NAMED_LITERAL_CSTRING(max_age_var, "max-age");
NS_NAMED_LITERAL_CSTRING(include_subd_var, "includesubdomains");
NS_NAMED_LITERAL_CSTRING(pin_sha256_var, "pin-sha256");
NS_NAMED_LITERAL_CSTRING(report_uri_var, "report-uri");
nsSecurityHeaderParser parser(aHeader);
nsresult rv = parser.Parse();
@ -614,29 +456,7 @@ ParseSSSHeaders(uint32_t aType,
directive->mValue.get()));
return nsISiteSecurityService::ERROR_INVALID_INCLUDE_SUBDOMAINS;
}
} else if (aType == nsISiteSecurityService::HEADER_HPKP &&
directive->mName.Length() == pin_sha256_var.Length() &&
directive->mName.EqualsIgnoreCase(pin_sha256_var.get(),
pin_sha256_var.Length())) {
SSSLOG(("SSS: found pinning entry '%s' length=%d",
directive->mValue.get(), directive->mValue.Length()));
if (!stringIsBase64EncodingOf256bitValue(directive->mValue)) {
return nsISiteSecurityService::ERROR_INVALID_PIN;
}
sha256keys.AppendElement(directive->mValue);
} else if (aType == nsISiteSecurityService::HEADER_HPKP &&
directive->mName.Length() == report_uri_var.Length() &&
directive->mName.EqualsIgnoreCase(report_uri_var.get(),
report_uri_var.Length())) {
// We don't support the report-uri yet, but to avoid unrecognized
// directive warnings, we still have to handle its presence
if (foundReportURI) {
SSSLOG(("SSS: found two report-uri directives"));
return nsISiteSecurityService::ERROR_MULTIPLE_REPORT_URIS;
}
SSSLOG(("SSS: found report-uri directive"));
foundReportURI = true;
} else {
} else {
SSSLOG(("SSS: ignoring unrecognized directive '%s'",
directive->mName.get()));
foundUnrecognizedDirective = true;
@ -645,194 +465,6 @@ ParseSSSHeaders(uint32_t aType,
return nsISiteSecurityService::Success;
}
nsresult
nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
const char* aHeader,
nsISSLStatus* aSSLStatus,
uint32_t aFlags,
uint64_t* aMaxAge,
bool* aIncludeSubdomains,
uint32_t* aFailureResult)
{
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
}
if (!mHPKPEnabled) {
SSSLOG(("SSS: HPKP disabled: not processing header '%s'", aHeader));
if (aMaxAge) {
*aMaxAge = 0;
}
if (aIncludeSubdomains) {
*aIncludeSubdomains = false;
}
return NS_OK;
}
SSSLOG(("SSS: processing HPKP header '%s'", aHeader));
NS_ENSURE_ARG(aSSLStatus);
const uint32_t aType = nsISiteSecurityService::HEADER_HPKP;
bool foundMaxAge = false;
bool foundIncludeSubdomains = false;
bool foundUnrecognizedDirective = false;
uint64_t maxAge = 0;
nsTArray<nsCString> sha256keys;
uint32_t sssrv = ParseSSSHeaders(aType, aHeader, foundIncludeSubdomains,
foundMaxAge, foundUnrecognizedDirective,
maxAge, sha256keys);
if (sssrv != nsISiteSecurityService::Success) {
if (aFailureResult) {
*aFailureResult = sssrv;
}
return NS_ERROR_FAILURE;
}
// after processing all the directives, make sure we came across max-age
// somewhere.
if (!foundMaxAge) {
SSSLOG(("SSS: did not encounter required max-age directive"));
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_NO_MAX_AGE;
}
return NS_ERROR_FAILURE;
}
// before we add the pin we need to ensure it will not break the site as
// currently visited so:
// 1. recompute a valid chain (no external ocsp)
// 2. use this chain to check if things would have broken!
nsAutoCString host;
nsresult rv = GetHost(aSourceURI, host);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIX509Cert> cert;
rv = aSSLStatus->GetServerCert(getter_AddRefs(cert));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(cert, NS_ERROR_FAILURE);
UniqueCERTCertificate nssCert(cert->GetCert());
NS_ENSURE_TRUE(nssCert, NS_ERROR_FAILURE);
mozilla::pkix::Time now(mozilla::pkix::Now());
UniqueCERTCertList certList;
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
// We don't want this verification to cause any network traffic that would
// block execution. Also, since we don't have access to the original stapled
// OCSP response, we can't enforce this aspect of the TLS Feature extension.
// This is ok, because it will have been enforced when we originally connected
// to the site (or it's disabled, in which case we wouldn't want to enforce it
// anyway).
CertVerifier::Flags flags = CertVerifier::FLAG_LOCAL_ONLY |
CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
if (certVerifier->VerifySSLServerCert(nssCert,
nullptr, // stapledOCSPResponse
nullptr, // sctsFromTLSExtension
now, nullptr, // pinarg
host.get(), // hostname
certList,
false, // don't store intermediates
flags)
!= mozilla::pkix::Success) {
return NS_ERROR_FAILURE;
}
CERTCertListNode* rootNode = CERT_LIST_TAIL(certList);
if (CERT_LIST_END(rootNode, certList)) {
return NS_ERROR_FAILURE;
}
bool isBuiltIn = false;
mozilla::pkix::Result result = IsCertBuiltInRoot(rootNode->cert, isBuiltIn);
if (result != mozilla::pkix::Success) {
return NS_ERROR_FAILURE;
}
if (!isBuiltIn && !mProcessPKPHeadersFromNonBuiltInRoots) {
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_ROOT_NOT_BUILT_IN;
}
return NS_ERROR_FAILURE;
}
// If maxAge == 0, we remove dynamic HPKP state for this host. Due to
// architectural constraints, if this host was preloaded, any future lookups
// will use the preloaded state (i.e. we can't store a "this host is not HPKP"
// entry like we can for HSTS).
if (maxAge == 0) {
return RemoveState(aType, aSourceURI, aFlags);
}
// clamp maxAge to the maximum set by pref
if (maxAge > mMaxMaxAge) {
maxAge = mMaxMaxAge;
}
bool chainMatchesPinset;
rv = PublicKeyPinningService::ChainMatchesPinset(certList, sha256keys,
chainMatchesPinset);
if (NS_FAILED(rv)) {
return rv;
}
if (!chainMatchesPinset) {
// is invalid
SSSLOG(("SSS: Pins provided by %s are invalid no match with certList\n", host.get()));
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_PINSET_DOES_NOT_MATCH_CHAIN;
}
return NS_ERROR_FAILURE;
}
// finally we need to ensure that there is a "backup pin" ie. There must be
// at least one fingerprint hash that does NOT validate against the verified
// chain (Section 2.5 of the spec)
bool hasBackupPin = false;
for (uint32_t i = 0; i < sha256keys.Length(); i++) {
nsTArray<nsCString> singlePin;
singlePin.AppendElement(sha256keys[i]);
rv = PublicKeyPinningService::ChainMatchesPinset(certList, singlePin,
chainMatchesPinset);
if (NS_FAILED(rv)) {
return rv;
}
if (!chainMatchesPinset) {
hasBackupPin = true;
}
}
if (!hasBackupPin) {
// is invalid
SSSLOG(("SSS: Pins provided by %s are invalid no backupPin\n", host.get()));
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_NO_BACKUP_PIN;
}
return NS_ERROR_FAILURE;
}
int64_t expireTime = ExpireTimeFromMaxAge(maxAge);
SiteHPKPState dynamicEntry(expireTime, SecurityPropertySet,
foundIncludeSubdomains, sha256keys);
SSSLOG(("SSS: about to set pins for %s, expires=%ld now=%ld maxAge=%lu\n",
host.get(), expireTime, PR_Now() / PR_USEC_PER_MSEC, maxAge));
rv = SetHPKPState(host.get(), dynamicEntry, aFlags, false);
if (NS_FAILED(rv)) {
SSSLOG(("SSS: failed to set pins for %s\n", host.get()));
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_COULD_NOT_SAVE_STATE;
}
return rv;
}
if (aMaxAge != nullptr) {
*aMaxAge = maxAge;
}
if (aIncludeSubdomains != nullptr) {
*aIncludeSubdomains = foundIncludeSubdomains;
}
return foundUnrecognizedDirective
? NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
: NS_OK;
}
nsresult
nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
const char* aHeader,
@ -902,17 +534,11 @@ nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
uint32_t aFlags, bool* aCached,
bool* aResult)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::IsSecureURI for non-HSTS entries");
}
NS_ENSURE_ARG(aURI);
NS_ENSURE_ARG(aResult);
// Only HSTS and HPKP are supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
aType == nsISiteSecurityService::HEADER_HPKP,
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
nsAutoCString hostname;
@ -939,17 +565,11 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
uint32_t aFlags, bool* aCached,
bool* aResult)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::IsSecureHost for non-HSTS entries");
}
NS_ENSURE_ARG(aHost);
NS_ENSURE_ARG(aResult);
// Only HSTS and HPKP are supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
aType == nsISiteSecurityService::HEADER_HPKP,
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
// set default in case if we can't find any STS information
@ -963,36 +583,14 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
return NS_OK;
}
/* An IP address never qualifies as a secure URI. */
// An IP address never qualifies as a secure URI.
if (HostIsIPAddress(aHost)) {
return NS_OK;
}
if (aType == nsISiteSecurityService::HEADER_HPKP) {
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
if (!certVerifier) {
return NS_ERROR_FAILURE;
}
if (certVerifier->mPinningMode ==
CertVerifier::PinningMode::pinningDisabled) {
return NS_OK;
}
bool enforceTestMode = certVerifier->mPinningMode ==
CertVerifier::PinningMode::pinningEnforceTestMode;
return PublicKeyPinningService::HostHasPins(aHost, mozilla::pkix::Now(),
enforceTestMode, *aResult);
}
// Holepunch chart.apis.google.com and subdomains.
nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHost));
if (host.EqualsLiteral("chart.apis.google.com") ||
StringEndsWith(host, NS_LITERAL_CSTRING(".chart.apis.google.com"))) {
if (aCached) {
*aCached = true;
}
return NS_OK;
}
// Canonicalize the passed host name
nsAutoCString host(CanonicalizeHostname(aHost));
// First check the exact host. This involves first checking for an entry in
// site security storage. If that entry exists, we don't want to check
// in the preload list. We only want to use the stored value if it is not a
@ -1088,144 +686,9 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
NS_IMETHODIMP
nsSiteSecurityService::ClearAll()
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::ClearAll");
}
return mSiteStateStorage->Clear();
}
bool entryStateNotOK(SiteHPKPState& state, mozilla::pkix::Time& aEvalTime) {
return state.mState != SecurityPropertySet || state.IsExpired(aEvalTime) ||
state.mSHA256keys.Length() < 1;
}
NS_IMETHODIMP
nsSiteSecurityService::GetKeyPinsForHostname(const char* aHostname,
mozilla::pkix::Time& aEvalTime,
/*out*/ nsTArray<nsCString>& pinArray,
/*out*/ bool* aIncludeSubdomains,
/*out*/ bool* aFound) {
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::GetKeyPinsForHostname");
}
NS_ENSURE_ARG(aFound);
NS_ENSURE_ARG(aHostname);
if (!mHPKPEnabled) {
SSSLOG(("HPKP disabled - returning 'pins not found' for %s",
aHostname));
*aFound = false;
return NS_OK;
}
SSSLOG(("Top of GetKeyPinsForHostname for %s", aHostname));
*aFound = false;
*aIncludeSubdomains = false;
pinArray.Clear();
nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHostname));
nsAutoCString storageKey;
SetStorageKey(storageKey, host, nsISiteSecurityService::HEADER_HPKP);
SSSLOG(("storagekey '%s'\n", storageKey.get()));
mozilla::DataStorageType storageType = mozilla::DataStorage_Persistent;
nsCString value = mSiteStateStorage->Get(storageKey, storageType);
// decode now
SiteHPKPState foundEntry(value);
if (entryStateNotOK(foundEntry, aEvalTime)) {
// not in permanent storage, try now private
value = mSiteStateStorage->Get(storageKey, mozilla::DataStorage_Private);
SiteHPKPState privateEntry(value);
if (entryStateNotOK(privateEntry, aEvalTime)) {
// not in private storage, try dynamic preload
value = mPreloadStateStorage->Get(storageKey,
mozilla::DataStorage_Persistent);
SiteHPKPState preloadEntry(value);
if (entryStateNotOK(preloadEntry, aEvalTime)) {
return NS_OK;
}
foundEntry = preloadEntry;
} else {
foundEntry = privateEntry;
}
}
pinArray = foundEntry.mSHA256keys;
*aIncludeSubdomains = foundEntry.mIncludeSubdomains;
*aFound = true;
return NS_OK;
}
NS_IMETHODIMP
nsSiteSecurityService::SetKeyPins(const char* aHost, bool aIncludeSubdomains,
int64_t aExpires, uint32_t aPinCount,
const char** aSha256Pins,
bool aIsPreload,
/*out*/ bool* aResult)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::SetKeyPins");
}
NS_ENSURE_ARG_POINTER(aHost);
NS_ENSURE_ARG_POINTER(aResult);
NS_ENSURE_ARG_POINTER(aSha256Pins);
if (!mHPKPEnabled) {
SSSLOG(("SSS: HPKP disabled: not setting pins"));
*aResult = false;
return NS_OK;
}
SSSLOG(("Top of SetPins"));
nsTArray<nsCString> sha256keys;
for (unsigned int i = 0; i < aPinCount; i++) {
nsAutoCString pin(aSha256Pins[i]);
SSSLOG(("SetPins pin=%s\n", pin.get()));
if (!stringIsBase64EncodingOf256bitValue(pin)) {
return NS_ERROR_INVALID_ARG;
}
sha256keys.AppendElement(pin);
}
SiteHPKPState dynamicEntry(aExpires, SecurityPropertySet,
aIncludeSubdomains, sha256keys);
// we always store data in permanent storage (ie no flags)
nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHost));
return SetHPKPState(host.get(), dynamicEntry, 0, aIsPreload);
}
nsresult
nsSiteSecurityService::SetHPKPState(const char* aHost, SiteHPKPState& entry,
uint32_t aFlags, bool aIsPreload)
{
SSSLOG(("Top of SetPKPState"));
nsAutoCString host(aHost);
nsAutoCString storageKey;
SetStorageKey(storageKey, host, nsISiteSecurityService::HEADER_HPKP);
bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
mozilla::DataStorageType storageType = isPrivate
? mozilla::DataStorage_Private
: mozilla::DataStorage_Persistent;
nsAutoCString stateString;
entry.ToString(stateString);
nsresult rv;
if (aIsPreload) {
rv = mPreloadStateStorage->Put(storageKey, stateString, storageType);
} else {
rv = mSiteStateStorage->Put(storageKey, stateString, storageType);
}
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
//------------------------------------------------------------
// nsSiteSecurityService::nsIObserver
//------------------------------------------------------------
@ -1246,12 +709,6 @@ nsSiteSecurityService::Observe(nsISupports *subject,
"network.stricttransportsecurity.enabled", true);
mPreloadListTimeOffset =
mozilla::Preferences::GetInt("test.currentTimeOffsetSeconds", 0);
mHPKPEnabled = mozilla::Preferences::GetBool(
"security.cert_pinning.hpkp.enabled", false);
mProcessPKPHeadersFromNonBuiltInRoots = mozilla::Preferences::GetBool(
"security.cert_pinning.process_headers_from_non_builtin_roots", false);
mMaxMaxAge = mozilla::Preferences::GetInt(
"security.cert_pinning.max_max_age_seconds", kSixtyDaysInSeconds);
}
return NS_OK;

View file

@ -38,40 +38,6 @@ enum SecurityPropertyState {
SecurityPropertyNegative = 3,
};
/**
* SiteHPKPState: A utility class that encodes/decodes a string describing
* the public key pins of a site.
* HPKP state consists of:
* - Expiry time (PRTime (aka int64_t) in milliseconds)
* - A state flag (SecurityPropertyState, default SecurityPropertyUnset)
* - An include subdomains flag (bool, default false)
* - An array of sha-256 hashed base 64 encoded fingerprints of required keys
*/
class SiteHPKPState
{
public:
SiteHPKPState();
explicit SiteHPKPState(nsCString& aStateString);
SiteHPKPState(PRTime aExpireTime, SecurityPropertyState aState,
bool aIncludeSubdomains, nsTArray<nsCString>& SHA256keys);
PRTime mExpireTime;
SecurityPropertyState mState;
bool mIncludeSubdomains;
nsTArray<nsCString> mSHA256keys;
bool IsExpired(mozilla::pkix::Time aTime)
{
if (aTime > mozilla::pkix::TimeFromEpochInSeconds(mExpireTime /
PR_MSEC_PER_SEC)) {
return true;
}
return false;
}
void ToString(nsCString& aString);
};
/**
* SiteHSTSState: A utility class that encodes/decodes a string describing
* the security state of a site. Currently only handles HSTS.
@ -137,20 +103,10 @@ private:
nsresult ProcessSTSHeader(nsIURI* aSourceURI, const char* aHeader,
uint32_t flags, uint64_t* aMaxAge,
bool* aIncludeSubdomains, uint32_t* aFailureResult);
nsresult ProcessPKPHeader(nsIURI* aSourceURI, const char* aHeader,
nsISSLStatus* aSSLStatus, uint32_t flags,
uint64_t* aMaxAge, bool* aIncludeSubdomains,
uint32_t* aFailureResult);
nsresult SetHPKPState(const char* aHost, SiteHPKPState& entry, uint32_t flags,
bool aIsPreload);
uint64_t mMaxMaxAge;
bool mUseStsService;
int64_t mPreloadListTimeOffset;
bool mHPKPEnabled;
bool mProcessPKPHeadersFromNonBuiltInRoots;
RefPtr<mozilla::DataStorage> mSiteStateStorage;
RefPtr<mozilla::DataStorage> mPreloadStateStorage;
};
#endif // __nsSiteSecurityService_h__