diff options
Diffstat (limited to 'security/manager')
-rw-r--r-- | security/manager/ssl/PublicKeyPinningService.cpp | 333 | ||||
-rw-r--r-- | security/manager/ssl/PublicKeyPinningService.h | 64 | ||||
-rw-r--r-- | security/manager/ssl/StaticHPKPins.h | 712 | ||||
-rw-r--r-- | security/manager/ssl/moz.build | 1 | ||||
-rw-r--r-- | security/manager/ssl/nsISiteSecurityService.idl | 46 | ||||
-rw-r--r-- | security/manager/ssl/nsSiteSecurityService.cpp | 595 | ||||
-rw-r--r-- | security/manager/ssl/nsSiteSecurityService.h | 46 | ||||
-rw-r--r-- | security/manager/tools/PreloadedHPKPins.json | 222 | ||||
-rw-r--r-- | security/manager/tools/genHPKPStaticPins.js | 630 |
9 files changed, 32 insertions, 2617 deletions
diff --git a/security/manager/ssl/PublicKeyPinningService.cpp b/security/manager/ssl/PublicKeyPinningService.cpp deleted file mode 100644 index ffee8ba48..000000000 --- a/security/manager/ssl/PublicKeyPinningService.cpp +++ /dev/null @@ -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; -} diff --git a/security/manager/ssl/PublicKeyPinningService.h b/security/manager/ssl/PublicKeyPinningService.h deleted file mode 100644 index 09fdd8474..000000000 --- a/security/manager/ssl/PublicKeyPinningService.h +++ /dev/null @@ -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 diff --git a/security/manager/ssl/StaticHPKPins.h b/security/manager/ssl/StaticHPKPins.h deleted file mode 100644 index a2313ea72..000000000 --- a/security/manager/ssl/StaticHPKPins.h +++ /dev/null @@ -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); diff --git a/security/manager/ssl/moz.build b/security/manager/ssl/moz.build index 8f4c6e9da..151c5b88a 100644 --- a/security/manager/ssl/moz.build +++ b/security/manager/ssl/moz.build @@ -132,7 +132,6 @@ UNIFIED_SOURCES += [ 'nsTLSSocketProvider.cpp', 'PSMContentListener.cpp', 'PSMRunnable.cpp', - 'PublicKeyPinningService.cpp', 'SecretDecoderRing.cpp', 'SharedSSLState.cpp', 'SSLServerCertVerification.cpp', diff --git a/security/manager/ssl/nsISiteSecurityService.idl b/security/manager/ssl/nsISiteSecurityService.idl index 4286848a9..d0e5f61ed 100644 --- a/security/manager/ssl/nsISiteSecurityService.idl +++ b/security/manager/ssl/nsISiteSecurityService.idl @@ -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++ diff --git a/security/manager/ssl/nsSiteSecurityService.cpp b/security/manager/ssl/nsSiteSecurityService.cpp index f78be1bad..fa2619414 100644 --- a/security/manager/ssl/nsSiteSecurityService.cpp +++ b/security/manager/ssl/nsSiteSecurityService.cpp @@ -25,7 +25,6 @@ #include "mozilla/Logging.h" #include "prnetdb.h" #include "prprf.h" -#include "PublicKeyPinningService.h" #include "ScopedNSSTypes.h" #include "SharedCertVerifier.h" @@ -87,122 +86,30 @@ SiteHSTSState::ToString(nsCString& aString) } //////////////////////////////////////////////////////////////////////////////// -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(); - } - } -} +const uint64_t kSixtyDaysInSeconds = 60 * 24 * 60 * 60; -SiteHPKPState::SiteHPKPState(PRTime aExpireTime, - SecurityPropertyState aState, - bool aIncludeSubdomains, - nsTArray<nsCString>& aSHA256keys) - : mExpireTime(aExpireTime) - , mState(aState) - , mIncludeSubdomains(aIncludeSubdomains) - , mSHA256keys(aSHA256keys) +static bool +HostIsIPAddress(const char *hostname) { + PRNetAddr hostAddr; + return (PR_StringToNetAddr(hostname, &hostAddr) == PR_SUCCESS); } -void -SiteHPKPState::ToString(nsCString& aString) +nsAutoCString CanonicalizeHostname(const char* hostname) { - 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]); + nsAutoCString canonicalizedHostname(hostname); + ToLowerCase(canonicalizedHostname); + while (canonicalizedHostname.Length() > 0 && + canonicalizedHostname.Last() == '.') { + canonicalizedHostname.Truncate(canonicalizedHostname.Length() - 1); } + return canonicalizedHostname; } -//////////////////////////////////////////////////////////////////////////////// - -const uint64_t kSixtyDaysInSeconds = 60 * 24 * 60 * 60; - 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; @@ -646,194 +466,6 @@ ParseSSSHeaders(uint32_t aType, } 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, uint32_t aFlags, @@ -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; diff --git a/security/manager/ssl/nsSiteSecurityService.h b/security/manager/ssl/nsSiteSecurityService.h index 3cc428e2e..9395cd092 100644 --- a/security/manager/ssl/nsSiteSecurityService.h +++ b/security/manager/ssl/nsSiteSecurityService.h @@ -39,40 +39,6 @@ enum SecurityPropertyState { }; /** - * 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. * HSTS state consists of: @@ -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__ diff --git a/security/manager/tools/PreloadedHPKPins.json b/security/manager/tools/PreloadedHPKPins.json deleted file mode 100644 index d9c394a1d..000000000 --- a/security/manager/tools/PreloadedHPKPins.json +++ /dev/null @@ -1,222 +0,0 @@ -// -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- -// 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/. - -// The top-level element is a dictionary with two keys: "pinsets" maps details -// of certificate pinning to a name and "entries" contains the HPKP details for -// each host. -// -// "pinsets" is a list of objects. Each object has the following members: -// name: (string) the name of the pinset -// sha256_hashes: (list of strings) the set of allowed SPKIs hashes -// -// For a given pinset, a certificate is accepted if at least one of the -// Subject Public Key Infos (SPKIs) is found in the chain. SPKIs are specified -// as names, which must match up with the name given in the Mozilla root store. -// -// "entries" is a list of objects. Each object has the following members: -// name: (string) the DNS name of the host in question -// include_subdomains: (optional bool) whether subdomains of |name| are also covered -// pins: (string) the |name| member of an object in |pinsets| -// -// "extra_certs" is a list of base64-encoded certificates. These are used in -// pinsets that reference certificates not in our root program (for example, -// Facebook). - -// equifax -> aus3 -// Geotrust Primary -> www.mozilla.org -// Geotrust Global -> *. addons.mozilla.org -{ - "chromium_data" : { - "cert_file_url": "https://chromium.googlesource.com/chromium/src/net/+/master/http/transport_security_state_static.pins?format=TEXT", - "json_file_url": "https://chromium.googlesource.com/chromium/src/net/+/master/http/transport_security_state_static.json?format=TEXT", - "substitute_pinsets": { - // Use the larger google_root_pems pinset instead of google - "google": "google_root_pems" - }, - "production_pinsets": [ - "google_root_pems", - "facebook" - ], - "production_domains": [ - // Chrome's test domains. - "pinningtest.appspot.com", - "pinning-test.badssl.com", - // Dropbox - "dropbox.com", - "www.dropbox.com", - // Twitter - "api.twitter.com", - "business.twitter.com", - "dev.twitter.com", - "mobile.twitter.com", - "oauth.twitter.com", - "platform.twitter.com", - "twimg.com", - "www.twitter.com", - // Tor - "torproject.org", - "blog.torproject.org", - "check.torproject.org", - "dist.torproject.org", - "www.torproject.org", - // SpiderOak - "spideroak.com" - ], - "exclude_domains" : [ - // Chrome's entry for twitter.com doesn't include subdomains, so replace - // it with our own entry below which also uses an expanded pinset. - "twitter.com" - ] - }, - "pinsets": [ - { - // 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", - "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", - "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" - ] - }, - { - "name": "mozilla_services", - "sha256_hashes": [ - "DigiCert Global Root CA" - ] - }, - // For pinning tests on pinning.example.com, the certificate must be 'End - // Entity Test Cert' - { - "name": "mozilla_test", - "sha256_hashes": [ - "End Entity Test Cert" - ] - }, - // Google's root PEMs. Chrome pins only to their intermediate certs, but - // they'd like us to be more liberal. For the initial list, we are using - // the certs from http://pki.google.com/roots.pem. - // We have no built-in for commented out CAs. - { - "name": "google_root_pems", - "sha256_hashes": [ - "AddTrust External Root", - "AddTrust Low-Value Services Root", - "AddTrust Public Services Root", - "AddTrust Qualified Certificates Root", - "AffirmTrust Commercial", - "AffirmTrust Networking", - "AffirmTrust Premium", - "AffirmTrust Premium ECC", - "Baltimore CyberTrust Root", - "Comodo AAA Services root", - "COMODO Certification Authority", - "COMODO ECC Certification Authority", - "COMODO RSA Certification Authority", - "Comodo Secure Services root", - "Comodo Trusted Services root", - "Cybertrust Global Root", - "DigiCert Assured ID Root CA", - "DigiCert Assured ID Root G2", - "DigiCert Assured ID Root G3", - "DigiCert Global Root CA", - "DigiCert Global Root G2", - "DigiCert Global Root G3", - "DigiCert High Assurance EV Root CA", - "DigiCert Trusted Root G4", - "Entrust Root Certification Authority", - "Entrust Root Certification Authority - EC1", - "Entrust Root Certification Authority - G2", - "Entrust.net Premium 2048 Secure Server CA", - // "Equifax Secure Certificate Authority", - "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", - "GlobalSign ECC Root CA - R4", - "GlobalSign ECC Root CA - R5", - "GlobalSign Root CA", - "GlobalSign Root CA - R2", - "GlobalSign Root CA - R3", - "Go Daddy Class 2 CA", - "Go Daddy Root Certificate Authority - G2", - "Starfield Class 2 CA", - "Starfield Root Certificate Authority - G2", - "thawte Primary Root CA", - "thawte Primary Root CA - G2", - "thawte Primary Root CA - G3", - "USERTrust ECC Certification Authority", - "USERTrust RSA Certification Authority", - "UTN USERFirst Hardware Root CA", - "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 Universal Root Certification Authority" - ] - } - ], - - "entries": [ - // Only domains that are operationally crucial to Firefox can have per-host - // telemetry reporting (the "id") field - { "name": "addons.mozilla.org", "include_subdomains": true, - "pins": "mozilla", "test_mode": false, "id": 1 }, - { "name": "addons.mozilla.net", "include_subdomains": true, - "pins": "mozilla", "test_mode": false, "id": 2 }, - { "name": "aus4.mozilla.org", "include_subdomains": true, - "pins": "mozilla", "test_mode": true, "id": 3 }, - { "name": "accounts.firefox.com", "include_subdomains": true, - "pins": "mozilla_services", "test_mode": false, "id": 4 }, - { "name": "api.accounts.firefox.com", "include_subdomains": true, - "pins": "mozilla_services", "test_mode": false, "id": 5 }, - { "name": "cdn.mozilla.net", "include_subdomains": true, - "pins": "mozilla", "test_mode": false }, - { "name": "cdn.mozilla.org", "include_subdomains": true, - "pins": "mozilla", "test_mode": false }, - { "name": "services.mozilla.com", "include_subdomains": true, - "pins": "mozilla_services", "test_mode": false, "id": 6 }, - { "name": "include-subdomains.pinning.example.com", - "include_subdomains": true, "pins": "mozilla_test", - "test_mode": false }, - // Example domain to collect per-host stats for telemetry tests. - { "name": "exclude-subdomains.pinning.example.com", - "include_subdomains": false, "pins": "mozilla_test", - "test_mode": false, "id": 0 }, - { "name": "test-mode.pinning.example.com", "include_subdomains": true, - "pins": "mozilla_test", "test_mode": true }, - // Expand twitter's pinset to include all of *.twitter.com and use - // twitterCDN. More specific rules take precedence because we search for - // exact domain name first. - { "name": "twitter.com", "include_subdomains": true, - "pins": "twitterCDN", "test_mode": false }, - { "name": "aus5.mozilla.org", "include_subdomains": true, - "pins": "mozilla", "test_mode": true, "id": 7 } - ], - - "extra_certificates": [] -} diff --git a/security/manager/tools/genHPKPStaticPins.js b/security/manager/tools/genHPKPStaticPins.js deleted file mode 100644 index f2b9dbdda..000000000 --- a/security/manager/tools/genHPKPStaticPins.js +++ /dev/null @@ -1,630 +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/. */ - -// How to run this file: -// 1. [obtain firefox source code] -// 2. [build/obtain firefox binaries] -// 3. run `[path to]/run-mozilla.sh [path to]/xpcshell \ -// [path to]/genHPKPStaticpins.js \ -// [absolute path to]/PreloadedHPKPins.json \ -// [an unused argument - see bug 1205406] \ -// [absolute path to]/StaticHPKPins.h -"use strict"; - -if (arguments.length != 3) { - throw new Error("Usage: genHPKPStaticPins.js " + - "<absolute path to PreloadedHPKPins.json> " + - "<an unused argument - see bug 1205406> " + - "<absolute path to StaticHPKPins.h>"); -} - -var { 'classes': Cc, 'interfaces': Ci, 'utils': Cu, 'results': Cr } = Components; - -var { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {}); -var { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {}); -var { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); - -var gCertDB = Cc["@mozilla.org/security/x509certdb;1"] - .getService(Ci.nsIX509CertDB); - -const BUILT_IN_NICK_PREFIX = "Builtin Object Token:"; -const SHA256_PREFIX = "sha256/"; -const GOOGLE_PIN_PREFIX = "GOOGLE_PIN_"; - -// Pins expire in 14 weeks (6 weeks on Beta + 8 weeks on stable) -const PINNING_MINIMUM_REQUIRED_MAX_AGE = 60 * 60 * 24 * 7 * 14; - -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" + -"\n" + -"/*****************************************************************************/\n" + -"/* This is an automatically generated file. If you're not */\n" + -"/* PublicKeyPinningService.cpp, you shouldn't be #including it. */\n" + -"/*****************************************************************************/\n" + -"#include <stdint.h>" + -"\n"; - -const DOMAINHEADER = "/* Domainlist */\n" + - "struct TransportSecurityPreload {\n" + - " const char* mHost;\n" + - " const bool mIncludeSubdomains;\n" + - " const bool mTestMode;\n" + - " const bool mIsMoz;\n" + - " const int32_t mId;\n" + - " const StaticFingerprints* 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"; - -// Command-line arguments -var gStaticPins = parseJson(arguments[0]); - -// arguments[1] is ignored for now. See bug 1205406. - -// Open the output file. -var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); -file.initWithPath(arguments[2]); -var gFileOutputStream = FileUtils.openSafeFileOutputStream(file); - -function writeString(string) { - gFileOutputStream.write(string, string.length); -} - -function readFileToString(filename) { - let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); - file.initWithPath(filename); - let stream = Cc["@mozilla.org/network/file-input-stream;1"] - .createInstance(Ci.nsIFileInputStream); - stream.init(file, -1, 0, 0); - let buf = NetUtil.readInputStreamToString(stream, stream.available()); - return buf; -} - -function stripComments(buf) { - let lines = buf.split("\n"); - let entryRegex = /^\s*\/\//; - let data = ""; - for (let i = 0; i < lines.length; ++i) { - let match = entryRegex.exec(lines[i]); - if (!match) { - data = data + lines[i]; - } - } - return data; -} - -function isBuiltinToken(tokenName) { - return tokenName == "Builtin Object Token"; -} - -function isCertBuiltIn(cert) { - let tokenNames = cert.getAllTokenNames({}); - if (!tokenNames) { - return false; - } - if (tokenNames.some(isBuiltinToken)) { - return true; - } - return false; -} - -function download(filename) { - let 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 new Error(`ERROR: problem downloading '${filename}': ${e}`); - } - - if (req.status != 200) { - throw new Error("ERROR: problem downloading '" + filename + "': status " + - req.status); - } - - let resultDecoded; - try { - resultDecoded = atob(req.responseText); - } - catch (e) { - throw new Error("ERROR: could not decode data as base64 from '" + filename + - "': " + e); - } - return resultDecoded; -} - -function downloadAsJson(filename) { - // we have to filter out '//' comments, while not mangling the json - let result = download(filename).replace(/^(\s*)?\/\/[^\n]*\n/mg, ""); - let data = null; - try { - data = JSON.parse(result); - } - catch (e) { - throw new Error("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; -} - -/** - * Hashes |input| using the SHA-256 algorithm in the following manner: - * btoa(sha256(atob(input))) - * - * @argument {String} input Base64 string to decode and return the hash of. - * @returns {String} Base64 encoded SHA-256 hash. - */ -function sha256Base64(input) { - let decodedValue; - try { - decodedValue = atob(input); - } - catch (e) { - throw new Error(`ERROR: could not decode as base64: '${input}': ${e}`); - } - - // Convert |decodedValue| to an array so that it can be hashed by the - // nsICryptoHash instance below. - // In most cases across the code base, convertToByteArray() of - // nsIScriptableUnicodeConverter is used to do this, but the method doesn't - // seem to work here. - let data = []; - for (let i = 0; i < decodedValue.length; i++) { - data[i] = decodedValue.charCodeAt(i); - } - - let hasher = Cc["@mozilla.org/security/hash;1"] - .createInstance(Ci.nsICryptoHash); - hasher.init(hasher.SHA256); - hasher.update(data, data.length); - - // true is passed so that the hasher returns a Base64 encoded string. - return hasher.finish(true); -} - -// 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 "sha256/" + base64(hash), -// a PEM encoded public key, or a PEM encoded certificate. -// For certificates that we have in our database, -// return a map of Google's nickname to ours. For ones that aren't return a -// map of Google's nickname to SHA-256 values. This code is modeled after agl's -// https://github.com/agl/transport-security-state-generate, which doesn't -// live in the Chromium repo because go is not an official language in -// Chromium. -// 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, certNameToSKD, certSKDToName) { - // Prefixes that we care about. - const BEGIN_CERT = "-----BEGIN CERTIFICATE-----"; - const END_CERT = "-----END CERTIFICATE-----"; - const BEGIN_PUB_KEY = "-----BEGIN PUBLIC KEY-----"; - const END_PUB_KEY = "-----END PUBLIC KEY-----"; - - // Parsing states. - const PRE_NAME = 0; - const POST_NAME = 1; - const IN_CERT = 2; - const IN_PUB_KEY = 3; - let state = PRE_NAME; - - let lines = download(filename).split("\n"); - let name = ""; - let pemCert = ""; - let pemPubKey = ""; - let hash = ""; - let chromeNameToHash = {}; - let chromeNameToMozName = {}; - let chromeName; - for (let line of lines) { - // 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(SHA256_PREFIX)) { - hash = line.substring(SHA256_PREFIX.length); - chromeNameToHash[chromeName] = hash; - certNameToSKD[chromeName] = hash; - certSKDToName[hash] = chromeName; - state = PRE_NAME; - } else if (line.startsWith(BEGIN_CERT)) { - state = IN_CERT; - } else if (line.startsWith(BEGIN_PUB_KEY)) { - state = IN_PUB_KEY; - } else { - throw new Error("ERROR: couldn't parse Chrome certificate file " + - "line: " + line); - } - break; - case IN_CERT: - if (line.startsWith(END_CERT)) { - state = PRE_NAME; - hash = getSKDFromPem(pemCert); - pemCert = ""; - let mozName; - 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; - case IN_PUB_KEY: - if (line.startsWith(END_PUB_KEY)) { - state = PRE_NAME; - hash = sha256Base64(pemPubKey); - pemPubKey = ""; - chromeNameToHash[chromeName] = hash; - certNameToSKD[chromeName] = hash; - certSKDToName[hash] = chromeName; - } else { - pemPubKey += line; - } - break; - default: - throw new Error("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 -// 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, sha256_hashes: [] }; - // Translate the Chrome pinset format to ours - pin.static_spki_hashes.forEach(function(name) { - if (name in chromeNameToHash) { - let hash = chromeNameToHash[name]; - pinset.sha256_hashes.push(certSKDToName[hash]); - - // We should have already added hashes for all of these when we - // imported the certificate file. - if (!certNameToSKD[name]) { - throw new Error("ERROR: 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. - const cData = gStaticPins.chromium_data; - let entries = chromePreloads.entries; - entries.forEach(function(entry) { - // HSTS entry only - if (!entry.pins) { - return; - } - let pinsetName = cData.substitute_pinsets[entry.pins]; - if (!pinsetName) { - pinsetName = entry.pins; - } - - // We trim the entry name here to avoid breaking hostname comparisons in the - // HPKP implementation. - entry.name = entry.name.trim(); - - let isProductionDomain = - (cData.production_domains.indexOf(entry.name) != -1); - let isProductionPinset = - (cData.production_pinsets.indexOf(pinsetName) != -1); - let excludeDomain = - (cData.exclude_domains.indexOf(entry.name) != -1); - let isTestMode = !isProductionPinset && !isProductionDomain; - if (entry.pins && !excludeDomain && chromeImportedPinsets[entry.pins]) { - chromeImportedEntries.push({ - name: entry.name, - include_subdomains: entry.include_subdomains, - test_mode: isTestMode, - is_moz: false, - pins: pinsetName }); - } - }); - 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(extraCertificates) { - let allCerts = gCertDB.getCerts(); - let enumerator = allCerts.getEnumerator(); - let certNameToSKD = {}; - 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 SKD = cert.sha256SubjectPublicKeyInfoDigest; - certNameToSKD[name] = SKD; - certSKDToName[SKD] = name; - } - - for (let cert of extraCertificates) { - let name = cert.commonName; - let SKD = cert.sha256SubjectPublicKeyInfoDigest; - certNameToSKD[name] = SKD; - certSKDToName[SKD] = name; - } - - { - // This is the pinning test certificate. The key hash identifies the - // default RSA key from pykey. - let name = "End Entity Test Cert"; - let SKD = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8="; - certNameToSKD[name] = SKD; - certSKDToName[SKD] = name; - } - return [certNameToSKD, certSKDToName]; -} - -function parseJson(filename) { - let json = stripComments(readFileToString(filename)); - return JSON.parse(json); -} - -function nameToAlias(certName) { - // change the name to a string valid as a c identifier - // remove non-ascii characters - certName = certName.replace(/[^[:ascii:]]/g, "_"); - // replace non word characters - certName = certName.replace(/[^A-Za-z0-9]/g, "_"); - - return "k" + certName + "Fingerprint"; -} - -function compareByName (a, b) { - return a.name.localeCompare(b.name); -} - -function genExpirationTime() { - let now = new Date(); - let nowMillis = now.getTime(); - let expirationMillis = nowMillis + (PINNING_MINIMUM_REQUIRED_MAX_AGE * 1000); - let expirationMicros = expirationMillis * 1000; - return "static const PRTime kPreloadPKPinsExpirationTime = INT64_C(" + - expirationMicros + ");\n"; -} - -function writeFullPinset(certNameToSKD, certSKDToName, pinset) { - let prefix = "kPinset_" + pinset.name; - if (!pinset.sha256_hashes || pinset.sha256_hashes.length == 0) { - throw new Error(`ERROR: Pinset ${pinset.name} does not contain any hashes`); - } - writeFingerprints(certNameToSKD, certSKDToName, pinset.name, - pinset.sha256_hashes); -} - -function writeFingerprints(certNameToSKD, certSKDToName, name, hashes) { - let varPrefix = "kPinset_" + name; - writeString("static const char* const " + varPrefix + "_Data[] = {\n"); - let SKDList = []; - for (let certName of hashes) { - if (!(certName in certNameToSKD)) { - throw new Error(`ERROR: Can't find '${certName}' in certNameToSKD`); - } - 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 + " = {\n " + - "sizeof(" + varPrefix + "_Data) / sizeof(const char*),\n " + varPrefix + - "_Data\n};\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, "; - } - if (entry.is_moz || (entry.pins.indexOf("mozilla") != -1 && - entry.pins != "mozilla_test")) { - printVal += "true, "; - } else { - printVal += "false, "; - } - if ("id" in entry) { - if (entry.id >= 256) { - throw new Error("ERROR: Not enough buckets in histogram"); - } - if (entry.id >= 0) { - printVal += entry.id + ", "; - } - } else { - printVal += "-1, "; - } - 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 mozillaDomains = {}; - gStaticPins.entries.forEach(function(entry) { - mozillaDomains[entry.name] = true; - }); - // For any domain for which we have set pins, exclude them from - // chromeImportedEntries. - for (let i = chromeImportedEntries.length - 1; i >= 0; i--) { - if (mozillaDomains[chromeImportedEntries[i].name]) { - dump("Skipping duplicate pinset for domain " + - JSON.stringify(chromeImportedEntries[i], undefined, 2) + "\n"); - chromeImportedEntries.splice(i, 1); - } - } - let sortedEntries = gStaticPins.entries; - sortedEntries.push.apply(sortedEntries, chromeImportedEntries); - for (let entry of sortedEntries.sort(compareByName)) { - count++; - writeEntry(entry); - } - writeString("};\n"); - - writeString("\n// Pinning Preload List Length = " + count + ";\n"); - writeString("\nstatic const int32_t kUnknownId = -1;\n"); -} - -function writeFile(certNameToSKD, certSKDToName, - chromeImportedPinsets, chromeImportedEntries) { - // Compute used pins from both Chrome's and our pinsets, so we can output - // them later. - let usedFingerprints = {}; - let mozillaPins = {}; - gStaticPins.pinsets.forEach(function(pinset) { - mozillaPins[pinset.name] = true; - pinset.sha256_hashes.forEach(function (name) { - usedFingerprints[name] = true; - }); - }); - for (let key in chromeImportedPinsets) { - let pinset = chromeImportedPinsets[key]; - 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("/* PreloadedHPKPins.json pinsets */\n"); - gStaticPins.pinsets.sort(compareByName).forEach(function(pinset) { - writeFullPinset(certNameToSKD, certSKDToName, pinset); - }); - writeString("/* Chrome static pinsets */\n"); - for (let key in chromeImportedPinsets) { - if (mozillaPins[key]) { - dump("Skipping duplicate pinset " + key + "\n"); - } else { - dump("Writing pinset " + key + "\n"); - writeFullPinset(certNameToSKD, certSKDToName, chromeImportedPinsets[key]); - } - } - - // Write the domainlist entries. - writeString(DOMAINHEADER); - writeDomainList(chromeImportedEntries); - writeString("\n"); - writeString(genExpirationTime()); -} - -function loadExtraCertificates(certStringList) { - let constructedCerts = []; - for (let certString of certStringList) { - constructedCerts.push(gCertDB.constructX509FromBase64(certString)); - } - return constructedCerts; -} - -var extraCertificates = loadExtraCertificates(gStaticPins.extra_certificates); -var [ certNameToSKD, certSKDToName ] = loadNSSCertinfo(extraCertificates); -var [ chromeNameToHash, chromeNameToMozName ] = downloadAndParseChromeCerts( - gStaticPins.chromium_data.cert_file_url, certNameToSKD, certSKDToName); -var [ chromeImportedPinsets, chromeImportedEntries ] = - downloadAndParseChromePins(gStaticPins.chromium_data.json_file_url, - chromeNameToHash, chromeNameToMozName, certNameToSKD, certSKDToName); - -writeFile(certNameToSKD, certSKDToName, chromeImportedPinsets, - chromeImportedEntries); - -FileUtils.closeSafeFileOutputStream(gFileOutputStream); |