Remove HPKP.
This commit is contained in:
parent
b63142cf64
commit
a9e1a524b7
|
@ -9828,7 +9828,7 @@ var Debugger =
|
|||
var host = httpActivity.hostname;
|
||||
|
||||
info.hsts = sss.isSecureHost(sss.HEADER_HSTS, host, flags);
|
||||
info.hpkp = sss.isSecureHost(sss.HEADER_HPKP, host, flags);
|
||||
info.hpkp = false;
|
||||
} else {
|
||||
DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo", "Could not get HSTS/HPKP status as hostname is not available.");
|
||||
info.hsts = false;
|
||||
|
|
|
@ -668,7 +668,8 @@ var NetworkHelper = {
|
|||
let host = httpActivity.hostname;
|
||||
|
||||
info.hsts = sss.isSecureHost(sss.HEADER_HSTS, host, flags);
|
||||
info.hpkp = sss.isSecureHost(sss.HEADER_HPKP, host, flags);
|
||||
// HPKP is no longer supported.
|
||||
info.hpkp = false;
|
||||
} else {
|
||||
DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo",
|
||||
"Could not get HSTS/HPKP status as hostname is not available.");
|
||||
|
|
|
@ -4948,13 +4948,11 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
|
|||
if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
|
||||
error.AssignLiteral("nssBadCert");
|
||||
|
||||
// If this is an HTTP Strict Transport Security host or a pinned host
|
||||
// and the certificate is bad, don't allow overrides (RFC 6797 section
|
||||
// 12.1, HPKP draft spec section 2.6).
|
||||
// If this is an HTTP Strict Transport Security host, don't allow
|
||||
// overrides (RFC 6797 section 12.1).
|
||||
uint32_t flags =
|
||||
UsePrivateBrowsing() ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
|
||||
bool isStsHost = false;
|
||||
bool isPinnedHost = false;
|
||||
if (XRE_IsParentProcess()) {
|
||||
nsCOMPtr<nsISiteSecurityService> sss =
|
||||
do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
|
||||
|
@ -4962,9 +4960,6 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
|
|||
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI,
|
||||
flags, nullptr, &isStsHost);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP, aURI,
|
||||
flags, nullptr, &isPinnedHost);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
mozilla::dom::ContentChild* cc =
|
||||
mozilla::dom::ContentChild::GetSingleton();
|
||||
|
@ -4972,8 +4967,6 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
|
|||
SerializeURI(aURI, uri);
|
||||
cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, flags,
|
||||
&isStsHost);
|
||||
cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HPKP, uri, flags,
|
||||
&isPinnedHost);
|
||||
}
|
||||
|
||||
if (Preferences::GetBool(
|
||||
|
@ -4981,11 +4974,9 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
|
|||
cssClass.AssignLiteral("expertBadCert");
|
||||
}
|
||||
|
||||
// HSTS/pinning takes precedence over the expert bad cert pref. We
|
||||
// HSTS takes precedence over the expert bad cert pref. We
|
||||
// never want to show the "Add Exception" button for these sites.
|
||||
// In the future we should differentiate between an HSTS host and a
|
||||
// pinned host and display a more informative message to the user.
|
||||
if (isStsHost || isPinnedHost) {
|
||||
if (isStsHost) {
|
||||
cssClass.AssignLiteral("badStsCert");
|
||||
}
|
||||
|
||||
|
|
|
@ -120,27 +120,6 @@ pref("security.webauth.u2f_enable_usbtoken", false);
|
|||
// OCSP must-staple
|
||||
pref("security.ssl.enable_ocsp_must_staple", true);
|
||||
|
||||
// HPKP settings
|
||||
|
||||
// Enable pinning checks by default.
|
||||
pref("security.cert_pinning.enforcement_level", 2);
|
||||
// Do not process hpkp headers rooted by not built in roots by default.
|
||||
// This is to prevent accidental pinning from MITM devices and is used
|
||||
// for tests.
|
||||
pref("security.cert_pinning.process_headers_from_non_builtin_roots", false);
|
||||
// Impose a maximum age on HPKP headers, to avoid sites getting permanently
|
||||
// blacking themselves out by setting a bad pin. (60 days by default)
|
||||
// https://tools.ietf.org/html/rfc7469#section-4.1
|
||||
pref("security.cert_pinning.max_max_age_seconds", 5184000);
|
||||
// Controls whether or not HPKP (the HTTP Public Key Pinning header) is enabled.
|
||||
// If true, the header is processed and collected HPKP information is consulted
|
||||
// when looking for pinning information.
|
||||
// If false, the header is not processed and collected HPKP information is not
|
||||
// consulted when looking for pinning information. Preloaded pins are not
|
||||
// affected by this preference.
|
||||
// Default: false
|
||||
pref("security.cert_pinning.hpkp.enabled", false);
|
||||
|
||||
// If a request is mixed-content, send an HSTS priming request to attempt to
|
||||
// see if it is available over HTTPS.
|
||||
pref("security.mixed_content.send_hsts_priming", true);
|
||||
|
|
|
@ -1529,7 +1529,7 @@ GetPKPConsoleErrorTag(uint32_t failureResult, nsAString& consoleErrorTag)
|
|||
}
|
||||
|
||||
/**
|
||||
* Process a single security header. Only two types are supported: HSTS and HPKP.
|
||||
* Process a single security header. Only one type is supported: HSTS.
|
||||
*/
|
||||
nsresult
|
||||
nsHttpChannel::ProcessSingleSecurityHeader(uint32_t aType,
|
||||
|
@ -1541,9 +1541,6 @@ nsHttpChannel::ProcessSingleSecurityHeader(uint32_t aType,
|
|||
case nsISiteSecurityService::HEADER_HSTS:
|
||||
atom = nsHttp::ResolveAtom("Strict-Transport-Security");
|
||||
break;
|
||||
case nsISiteSecurityService::HEADER_HPKP:
|
||||
atom = nsHttp::ResolveAtom("Public-Key-Pins");
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Invalid security header type");
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -1567,10 +1564,6 @@ nsHttpChannel::ProcessSingleSecurityHeader(uint32_t aType,
|
|||
GetSTSConsoleErrorTag(failureResult, consoleErrorTag);
|
||||
consoleErrorCategory = NS_LITERAL_STRING("Invalid HSTS Headers");
|
||||
break;
|
||||
case nsISiteSecurityService::HEADER_HPKP:
|
||||
GetPKPConsoleErrorTag(failureResult, consoleErrorTag);
|
||||
consoleErrorCategory = NS_LITERAL_STRING("Invalid HPKP Headers");
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -1640,10 +1633,6 @@ nsHttpChannel::ProcessSecurityHeaders()
|
|||
sslStatus, flags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = ProcessSingleSecurityHeader(nsISiteSecurityService::HEADER_HPKP,
|
||||
sslStatus, flags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "NSSErrorsService.h"
|
||||
#include "OCSPRequestor.h"
|
||||
#include "OCSPVerificationTrustDomain.h"
|
||||
#include "PublicKeyPinningService.h"
|
||||
#include "cert.h"
|
||||
#include "certdb.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
@ -862,24 +861,6 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time)
|
|||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
bool skipPinningChecksBecauseOfMITMMode =
|
||||
(!isBuiltInRoot && mPinningMode == CertVerifier::pinningAllowUserCAMITM);
|
||||
// If mHostname isn't set, we're not verifying in the context of a TLS
|
||||
// handshake, so don't verify HPKP in those cases.
|
||||
if (mHostname && (mPinningMode != CertVerifier::pinningDisabled) &&
|
||||
!skipPinningChecksBecauseOfMITMMode) {
|
||||
bool enforceTestMode =
|
||||
(mPinningMode == CertVerifier::pinningEnforceTestMode);
|
||||
bool chainHasValidPins;
|
||||
nsresult nsrv = PublicKeyPinningService::ChainHasValidPins(
|
||||
certList, mHostname, time, enforceTestMode, chainHasValidPins);
|
||||
if (NS_FAILED(nsrv)) {
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
if (!chainHasValidPins) {
|
||||
return Result::ERROR_KEY_PINNING_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
mBuiltChain = Move(certList);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -425,11 +425,9 @@ CertErrorRunnable::CheckCertOverrides()
|
|||
uint32_t remaining_display_errors = mCollectedErrors;
|
||||
|
||||
|
||||
// If this is an HTTP Strict Transport Security host or a pinned host and the
|
||||
// certificate is bad, don't allow overrides (RFC 6797 section 12.1,
|
||||
// HPKP draft spec section 2.6).
|
||||
// If this is an HTTP Strict Transport Security host, don't allow overrides
|
||||
// RFC 6797 section 12.1.
|
||||
bool strictTransportSecurityEnabled = false;
|
||||
bool hasPinningInformation = false;
|
||||
nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
|
||||
if (!sss) {
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
|
||||
|
@ -449,21 +447,10 @@ CertErrorRunnable::CheckCertOverrides()
|
|||
return new SSLServerCertVerificationResult(mInfoObject,
|
||||
mDefaultErrorCodeToReport);
|
||||
}
|
||||
nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HPKP,
|
||||
mInfoObject->GetHostNameRaw(),
|
||||
mProviderFlags,
|
||||
nullptr,
|
||||
&hasPinningInformation);
|
||||
if (NS_FAILED(nsrv)) {
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
|
||||
("[%p][%p] checking for HPKP failed\n", mFdForLogging, this));
|
||||
return new SSLServerCertVerificationResult(mInfoObject,
|
||||
mDefaultErrorCodeToReport);
|
||||
}
|
||||
|
||||
if (!strictTransportSecurityEnabled && !hasPinningInformation) {
|
||||
if (!strictTransportSecurityEnabled) {
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
|
||||
("[%p][%p] no HSTS or HPKP - overrides allowed\n",
|
||||
("[%p][%p] no HSTS - overrides allowed\n",
|
||||
mFdForLogging, this));
|
||||
nsCOMPtr<nsICertOverrideService> overrideService =
|
||||
do_GetService(NS_CERTOVERRIDE_CONTRACTID);
|
||||
|
@ -497,7 +484,7 @@ CertErrorRunnable::CheckCertOverrides()
|
|||
}
|
||||
} else {
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
|
||||
("[%p][%p] HSTS or HPKP - no overrides allowed\n",
|
||||
("[%p][%p] HSTS - no overrides allowed\n",
|
||||
mFdForLogging, this));
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -132,7 +132,6 @@ UNIFIED_SOURCES += [
|
|||
'nsTLSSocketProvider.cpp',
|
||||
'PSMContentListener.cpp',
|
||||
'PSMRunnable.cpp',
|
||||
'PublicKeyPinningService.cpp',
|
||||
'SecretDecoderRing.cpp',
|
||||
'SharedSSLState.cpp',
|
||||
'SSLServerCertVerification.cpp',
|
||||
|
|
|
@ -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++
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "mozilla/Logging.h"
|
||||
#include "prnetdb.h"
|
||||
#include "prprf.h"
|
||||
#include "PublicKeyPinningService.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "SharedCertVerifier.h"
|
||||
|
||||
|
@ -86,123 +85,31 @@ SiteHSTSState::ToString(nsCString& aString)
|
|||
aString.AppendInt(static_cast<uint32_t>(mHSTSIncludeSubdomains));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static bool
|
||||
stringIsBase64EncodingOf256bitValue(nsCString& encodedString) {
|
||||
nsAutoCString binaryValue;
|
||||
nsresult rv = mozilla::Base64Decode(encodedString, binaryValue);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
if (binaryValue.Length() != SHA256_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SiteHPKPState::SiteHPKPState()
|
||||
: mExpireTime(0)
|
||||
, mState(SecurityPropertyUnset)
|
||||
, mIncludeSubdomains(false)
|
||||
{
|
||||
}
|
||||
|
||||
SiteHPKPState::SiteHPKPState(nsCString& aStateString)
|
||||
: mExpireTime(0)
|
||||
, mState(SecurityPropertyUnset)
|
||||
, mIncludeSubdomains(false)
|
||||
{
|
||||
uint32_t hpkpState = 0;
|
||||
uint32_t hpkpIncludeSubdomains = 0; // PR_sscanf doesn't handle bools.
|
||||
const uint32_t MaxMergedHPKPPinSize = 1024;
|
||||
char mergedHPKPins[MaxMergedHPKPPinSize];
|
||||
memset(mergedHPKPins, 0, MaxMergedHPKPPinSize);
|
||||
|
||||
if (aStateString.Length() >= MaxMergedHPKPPinSize) {
|
||||
SSSLOG(("SSS: Cannot parse PKPState string, too large\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t matches = PR_sscanf(aStateString.get(), "%lld,%lu,%lu,%s",
|
||||
&mExpireTime, &hpkpState,
|
||||
&hpkpIncludeSubdomains, mergedHPKPins);
|
||||
bool valid = (matches == 4 &&
|
||||
(hpkpIncludeSubdomains == 0 || hpkpIncludeSubdomains == 1) &&
|
||||
((SecurityPropertyState)hpkpState == SecurityPropertyUnset ||
|
||||
(SecurityPropertyState)hpkpState == SecurityPropertySet ||
|
||||
(SecurityPropertyState)hpkpState == SecurityPropertyKnockout));
|
||||
|
||||
SSSLOG(("SSS: loading SiteHPKPState matches=%d\n", matches));
|
||||
const uint32_t SHA256Base64Len = 44;
|
||||
|
||||
if (valid && (SecurityPropertyState)hpkpState == SecurityPropertySet) {
|
||||
// try to expand the merged PKPins
|
||||
const char* cur = mergedHPKPins;
|
||||
nsAutoCString pin;
|
||||
uint32_t collectedLen = 0;
|
||||
mergedHPKPins[MaxMergedHPKPPinSize - 1] = 0;
|
||||
size_t totalLen = strlen(mergedHPKPins);
|
||||
while (collectedLen + SHA256Base64Len <= totalLen) {
|
||||
pin.Assign(cur, SHA256Base64Len);
|
||||
if (stringIsBase64EncodingOf256bitValue(pin)) {
|
||||
mSHA256keys.AppendElement(pin);
|
||||
}
|
||||
cur += SHA256Base64Len;
|
||||
collectedLen += SHA256Base64Len;
|
||||
}
|
||||
if (mSHA256keys.IsEmpty()) {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
mState = (SecurityPropertyState)hpkpState;
|
||||
mIncludeSubdomains = (hpkpIncludeSubdomains == 1);
|
||||
} else {
|
||||
SSSLOG(("%s is not a valid SiteHPKPState", aStateString.get()));
|
||||
mExpireTime = 0;
|
||||
mState = SecurityPropertyUnset;
|
||||
mIncludeSubdomains = false;
|
||||
if (!mSHA256keys.IsEmpty()) {
|
||||
mSHA256keys.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SiteHPKPState::SiteHPKPState(PRTime aExpireTime,
|
||||
SecurityPropertyState aState,
|
||||
bool aIncludeSubdomains,
|
||||
nsTArray<nsCString>& aSHA256keys)
|
||||
: mExpireTime(aExpireTime)
|
||||
, mState(aState)
|
||||
, mIncludeSubdomains(aIncludeSubdomains)
|
||||
, mSHA256keys(aSHA256keys)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SiteHPKPState::ToString(nsCString& aString)
|
||||
{
|
||||
aString.Truncate();
|
||||
aString.AppendInt(mExpireTime);
|
||||
aString.Append(',');
|
||||
aString.AppendInt(mState);
|
||||
aString.Append(',');
|
||||
aString.AppendInt(static_cast<uint32_t>(mIncludeSubdomains));
|
||||
aString.Append(',');
|
||||
for (unsigned int i = 0; i < mSHA256keys.Length(); i++) {
|
||||
aString.Append(mSHA256keys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const uint64_t kSixtyDaysInSeconds = 60 * 24 * 60 * 60;
|
||||
|
||||
static bool
|
||||
HostIsIPAddress(const char *hostname)
|
||||
{
|
||||
PRNetAddr hostAddr;
|
||||
return (PR_StringToNetAddr(hostname, &hostAddr) == PR_SUCCESS);
|
||||
}
|
||||
|
||||
nsAutoCString CanonicalizeHostname(const char* hostname)
|
||||
{
|
||||
nsAutoCString canonicalizedHostname(hostname);
|
||||
ToLowerCase(canonicalizedHostname);
|
||||
while (canonicalizedHostname.Length() > 0 &&
|
||||
canonicalizedHostname.Last() == '.') {
|
||||
canonicalizedHostname.Truncate(canonicalizedHostname.Length() - 1);
|
||||
}
|
||||
return canonicalizedHostname;
|
||||
}
|
||||
|
||||
nsSiteSecurityService::nsSiteSecurityService()
|
||||
: mMaxMaxAge(kSixtyDaysInSeconds)
|
||||
, mUseStsService(true)
|
||||
: mUseStsService(true)
|
||||
, mPreloadListTimeOffset(0)
|
||||
, mHPKPEnabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -223,30 +130,16 @@ nsSiteSecurityService::Init()
|
|||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
|
||||
mMaxMaxAge = mozilla::Preferences::GetInt(
|
||||
"security.cert_pinning.max_max_age_seconds", kSixtyDaysInSeconds);
|
||||
mozilla::Preferences::AddStrongObserver(this,
|
||||
"security.cert_pinning.max_max_age_seconds");
|
||||
mHPKPEnabled = mozilla::Preferences::GetBool(
|
||||
"security.cert_pinning.hpkp.enabled", false);
|
||||
mozilla::Preferences::AddStrongObserver(this,
|
||||
"security.cert_pinning.hpkp.enabled");
|
||||
mUseStsService = mozilla::Preferences::GetBool(
|
||||
"network.stricttransportsecurity.enabled", true);
|
||||
mozilla::Preferences::AddStrongObserver(this,
|
||||
"network.stricttransportsecurity.enabled");
|
||||
mProcessPKPHeadersFromNonBuiltInRoots = mozilla::Preferences::GetBool(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots", false);
|
||||
mozilla::Preferences::AddStrongObserver(this,
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots");
|
||||
mPreloadListTimeOffset = mozilla::Preferences::GetInt(
|
||||
"test.currentTimeOffsetSeconds", 0);
|
||||
mozilla::Preferences::AddStrongObserver(this,
|
||||
"test.currentTimeOffsetSeconds");
|
||||
mSiteStateStorage =
|
||||
mozilla::DataStorage::Get(NS_LITERAL_STRING("SiteSecurityServiceState.txt"));
|
||||
mPreloadStateStorage =
|
||||
mozilla::DataStorage::Get(NS_LITERAL_STRING("SecurityPreloadState.txt"));
|
||||
bool storageWillPersist = false;
|
||||
nsresult rv = mSiteStateStorage->Init(storageWillPersist);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -276,7 +169,7 @@ nsSiteSecurityService::GetHost(nsIURI* aURI, nsACString& aResult)
|
|||
return rv;
|
||||
}
|
||||
|
||||
aResult.Assign(PublicKeyPinningService::CanonicalizeHostname(host.get()));
|
||||
aResult.Assign(CanonicalizeHostname(host.get()));
|
||||
if (aResult.IsEmpty()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
@ -292,9 +185,6 @@ SetStorageKey(nsAutoCString& storageKey, nsCString& hostname, uint32_t aType)
|
|||
case nsISiteSecurityService::HEADER_HSTS:
|
||||
storageKey.AppendLiteral(":HSTS");
|
||||
break;
|
||||
case nsISiteSecurityService::HEADER_HPKP:
|
||||
storageKey.AppendLiteral(":HPKP");
|
||||
break;
|
||||
default:
|
||||
NS_ASSERTION(false, "SSS:SetStorageKey got invalid type");
|
||||
}
|
||||
|
@ -359,8 +249,7 @@ nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI, uint32_t aFlags
|
|||
}
|
||||
|
||||
// Only HSTS is supported at the moment.
|
||||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
|
||||
aType == nsISiteSecurityService::HEADER_HPKP,
|
||||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
|
||||
NS_ERROR_NOT_IMPLEMENTED);
|
||||
|
||||
nsAutoCString hostname;
|
||||
|
@ -379,13 +268,6 @@ nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI, uint32_t aFlags
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool
|
||||
HostIsIPAddress(const char *hostname)
|
||||
{
|
||||
PRNetAddr hostAddr;
|
||||
return (PR_StringToNetAddr(hostname, &hostAddr) == PR_SUCCESS);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::ProcessHeader(uint32_t aType,
|
||||
nsIURI* aSourceURI,
|
||||
|
@ -396,11 +278,6 @@ nsSiteSecurityService::ProcessHeader(uint32_t aType,
|
|||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
{
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::ProcessHeader");
|
||||
}
|
||||
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
|
||||
}
|
||||
|
@ -422,11 +299,6 @@ nsSiteSecurityService::UnsafeProcessHeader(uint32_t aType,
|
|||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
{
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::UnsafeProcessHeader");
|
||||
}
|
||||
|
||||
return ProcessHeaderInternal(aType, aSourceURI, aHeader, nullptr, aFlags,
|
||||
aMaxAge, aIncludeSubdomains, aFailureResult);
|
||||
}
|
||||
|
@ -444,9 +316,8 @@ nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
|
|||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
|
||||
}
|
||||
// Only HSTS and HPKP are supported at the moment.
|
||||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
|
||||
aType == nsISiteSecurityService::HEADER_HPKP,
|
||||
// Only HSTS is supported at the moment.
|
||||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
|
||||
NS_ERROR_NOT_IMPLEMENTED);
|
||||
|
||||
if (aMaxAge != nullptr) {
|
||||
|
@ -494,10 +365,6 @@ nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
|
|||
rv = ProcessSTSHeader(aSourceURI, aHeader, aFlags, aMaxAge,
|
||||
aIncludeSubdomains, aFailureResult);
|
||||
break;
|
||||
case nsISiteSecurityService::HEADER_HPKP:
|
||||
rv = ProcessPKPHeader(aSourceURI, aHeader, aSSLStatus, aFlags, aMaxAge,
|
||||
aIncludeSubdomains, aFailureResult);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected header type");
|
||||
}
|
||||
|
@ -513,9 +380,6 @@ ParseSSSHeaders(uint32_t aType,
|
|||
uint64_t& maxAge,
|
||||
nsTArray<nsCString>& sha256keys)
|
||||
{
|
||||
// Strict transport security and Public Key Pinning have very similar
|
||||
// Header formats.
|
||||
|
||||
// "Strict-Transport-Security" ":" OWS
|
||||
// STS-d *( OWS ";" OWS STS-d OWS)
|
||||
//
|
||||
|
@ -527,26 +391,6 @@ ParseSSSHeaders(uint32_t aType,
|
|||
// includeSubDomains = [ "includeSubDomains" ]
|
||||
//
|
||||
|
||||
// "Public-Key-Pins ":" OWS
|
||||
// PKP-d *( OWS ";" OWS PKP-d OWS)
|
||||
//
|
||||
// ; PKP directive
|
||||
// PKP-d = maxAge / includeSubDomains / reportUri / pin-directive
|
||||
//
|
||||
// maxAge = "max-age" "=" delta-seconds v-ext
|
||||
//
|
||||
// includeSubDomains = [ "includeSubDomains" ]
|
||||
//
|
||||
// reportURi = "report-uri" "=" quoted-string
|
||||
//
|
||||
// pin-directive = "pin-" token "=" quoted-string
|
||||
//
|
||||
// the only valid token currently specified is sha256
|
||||
// the quoted string for a pin directive is the base64 encoding
|
||||
// of the hash of the public key of the fingerprint
|
||||
//
|
||||
|
||||
// The order of the directives is not significant.
|
||||
// All directives must appear only once.
|
||||
// Directive names are case-insensitive.
|
||||
// The entire header is invalid if a directive not conforming to the
|
||||
|
@ -558,8 +402,6 @@ ParseSSSHeaders(uint32_t aType,
|
|||
|
||||
NS_NAMED_LITERAL_CSTRING(max_age_var, "max-age");
|
||||
NS_NAMED_LITERAL_CSTRING(include_subd_var, "includesubdomains");
|
||||
NS_NAMED_LITERAL_CSTRING(pin_sha256_var, "pin-sha256");
|
||||
NS_NAMED_LITERAL_CSTRING(report_uri_var, "report-uri");
|
||||
|
||||
nsSecurityHeaderParser parser(aHeader);
|
||||
nsresult rv = parser.Parse();
|
||||
|
@ -614,29 +456,7 @@ ParseSSSHeaders(uint32_t aType,
|
|||
directive->mValue.get()));
|
||||
return nsISiteSecurityService::ERROR_INVALID_INCLUDE_SUBDOMAINS;
|
||||
}
|
||||
} else if (aType == nsISiteSecurityService::HEADER_HPKP &&
|
||||
directive->mName.Length() == pin_sha256_var.Length() &&
|
||||
directive->mName.EqualsIgnoreCase(pin_sha256_var.get(),
|
||||
pin_sha256_var.Length())) {
|
||||
SSSLOG(("SSS: found pinning entry '%s' length=%d",
|
||||
directive->mValue.get(), directive->mValue.Length()));
|
||||
if (!stringIsBase64EncodingOf256bitValue(directive->mValue)) {
|
||||
return nsISiteSecurityService::ERROR_INVALID_PIN;
|
||||
}
|
||||
sha256keys.AppendElement(directive->mValue);
|
||||
} else if (aType == nsISiteSecurityService::HEADER_HPKP &&
|
||||
directive->mName.Length() == report_uri_var.Length() &&
|
||||
directive->mName.EqualsIgnoreCase(report_uri_var.get(),
|
||||
report_uri_var.Length())) {
|
||||
// We don't support the report-uri yet, but to avoid unrecognized
|
||||
// directive warnings, we still have to handle its presence
|
||||
if (foundReportURI) {
|
||||
SSSLOG(("SSS: found two report-uri directives"));
|
||||
return nsISiteSecurityService::ERROR_MULTIPLE_REPORT_URIS;
|
||||
}
|
||||
SSSLOG(("SSS: found report-uri directive"));
|
||||
foundReportURI = true;
|
||||
} else {
|
||||
} else {
|
||||
SSSLOG(("SSS: ignoring unrecognized directive '%s'",
|
||||
directive->mName.get()));
|
||||
foundUnrecognizedDirective = true;
|
||||
|
@ -645,194 +465,6 @@ ParseSSSHeaders(uint32_t aType,
|
|||
return nsISiteSecurityService::Success;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
||||
const char* aHeader,
|
||||
nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
{
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
|
||||
}
|
||||
if (!mHPKPEnabled) {
|
||||
SSSLOG(("SSS: HPKP disabled: not processing header '%s'", aHeader));
|
||||
if (aMaxAge) {
|
||||
*aMaxAge = 0;
|
||||
}
|
||||
if (aIncludeSubdomains) {
|
||||
*aIncludeSubdomains = false;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SSSLOG(("SSS: processing HPKP header '%s'", aHeader));
|
||||
NS_ENSURE_ARG(aSSLStatus);
|
||||
|
||||
const uint32_t aType = nsISiteSecurityService::HEADER_HPKP;
|
||||
bool foundMaxAge = false;
|
||||
bool foundIncludeSubdomains = false;
|
||||
bool foundUnrecognizedDirective = false;
|
||||
uint64_t maxAge = 0;
|
||||
nsTArray<nsCString> sha256keys;
|
||||
uint32_t sssrv = ParseSSSHeaders(aType, aHeader, foundIncludeSubdomains,
|
||||
foundMaxAge, foundUnrecognizedDirective,
|
||||
maxAge, sha256keys);
|
||||
if (sssrv != nsISiteSecurityService::Success) {
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = sssrv;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// after processing all the directives, make sure we came across max-age
|
||||
// somewhere.
|
||||
if (!foundMaxAge) {
|
||||
SSSLOG(("SSS: did not encounter required max-age directive"));
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_NO_MAX_AGE;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// before we add the pin we need to ensure it will not break the site as
|
||||
// currently visited so:
|
||||
// 1. recompute a valid chain (no external ocsp)
|
||||
// 2. use this chain to check if things would have broken!
|
||||
nsAutoCString host;
|
||||
nsresult rv = GetHost(aSourceURI, host);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIX509Cert> cert;
|
||||
rv = aSSLStatus->GetServerCert(getter_AddRefs(cert));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(cert, NS_ERROR_FAILURE);
|
||||
UniqueCERTCertificate nssCert(cert->GetCert());
|
||||
NS_ENSURE_TRUE(nssCert, NS_ERROR_FAILURE);
|
||||
|
||||
mozilla::pkix::Time now(mozilla::pkix::Now());
|
||||
UniqueCERTCertList certList;
|
||||
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
|
||||
NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
|
||||
// We don't want this verification to cause any network traffic that would
|
||||
// block execution. Also, since we don't have access to the original stapled
|
||||
// OCSP response, we can't enforce this aspect of the TLS Feature extension.
|
||||
// This is ok, because it will have been enforced when we originally connected
|
||||
// to the site (or it's disabled, in which case we wouldn't want to enforce it
|
||||
// anyway).
|
||||
CertVerifier::Flags flags = CertVerifier::FLAG_LOCAL_ONLY |
|
||||
CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
|
||||
if (certVerifier->VerifySSLServerCert(nssCert,
|
||||
nullptr, // stapledOCSPResponse
|
||||
nullptr, // sctsFromTLSExtension
|
||||
now, nullptr, // pinarg
|
||||
host.get(), // hostname
|
||||
certList,
|
||||
false, // don't store intermediates
|
||||
flags)
|
||||
!= mozilla::pkix::Success) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CERTCertListNode* rootNode = CERT_LIST_TAIL(certList);
|
||||
if (CERT_LIST_END(rootNode, certList)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
bool isBuiltIn = false;
|
||||
mozilla::pkix::Result result = IsCertBuiltInRoot(rootNode->cert, isBuiltIn);
|
||||
if (result != mozilla::pkix::Success) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!isBuiltIn && !mProcessPKPHeadersFromNonBuiltInRoots) {
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_ROOT_NOT_BUILT_IN;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If maxAge == 0, we remove dynamic HPKP state for this host. Due to
|
||||
// architectural constraints, if this host was preloaded, any future lookups
|
||||
// will use the preloaded state (i.e. we can't store a "this host is not HPKP"
|
||||
// entry like we can for HSTS).
|
||||
if (maxAge == 0) {
|
||||
return RemoveState(aType, aSourceURI, aFlags);
|
||||
}
|
||||
|
||||
// clamp maxAge to the maximum set by pref
|
||||
if (maxAge > mMaxMaxAge) {
|
||||
maxAge = mMaxMaxAge;
|
||||
}
|
||||
|
||||
bool chainMatchesPinset;
|
||||
rv = PublicKeyPinningService::ChainMatchesPinset(certList, sha256keys,
|
||||
chainMatchesPinset);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (!chainMatchesPinset) {
|
||||
// is invalid
|
||||
SSSLOG(("SSS: Pins provided by %s are invalid no match with certList\n", host.get()));
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_PINSET_DOES_NOT_MATCH_CHAIN;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// finally we need to ensure that there is a "backup pin" ie. There must be
|
||||
// at least one fingerprint hash that does NOT validate against the verified
|
||||
// chain (Section 2.5 of the spec)
|
||||
bool hasBackupPin = false;
|
||||
for (uint32_t i = 0; i < sha256keys.Length(); i++) {
|
||||
nsTArray<nsCString> singlePin;
|
||||
singlePin.AppendElement(sha256keys[i]);
|
||||
rv = PublicKeyPinningService::ChainMatchesPinset(certList, singlePin,
|
||||
chainMatchesPinset);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (!chainMatchesPinset) {
|
||||
hasBackupPin = true;
|
||||
}
|
||||
}
|
||||
if (!hasBackupPin) {
|
||||
// is invalid
|
||||
SSSLOG(("SSS: Pins provided by %s are invalid no backupPin\n", host.get()));
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_NO_BACKUP_PIN;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
int64_t expireTime = ExpireTimeFromMaxAge(maxAge);
|
||||
SiteHPKPState dynamicEntry(expireTime, SecurityPropertySet,
|
||||
foundIncludeSubdomains, sha256keys);
|
||||
SSSLOG(("SSS: about to set pins for %s, expires=%ld now=%ld maxAge=%lu\n",
|
||||
host.get(), expireTime, PR_Now() / PR_USEC_PER_MSEC, maxAge));
|
||||
|
||||
rv = SetHPKPState(host.get(), dynamicEntry, aFlags, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
SSSLOG(("SSS: failed to set pins for %s\n", host.get()));
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_COULD_NOT_SAVE_STATE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aMaxAge != nullptr) {
|
||||
*aMaxAge = maxAge;
|
||||
}
|
||||
|
||||
if (aIncludeSubdomains != nullptr) {
|
||||
*aIncludeSubdomains = foundIncludeSubdomains;
|
||||
}
|
||||
|
||||
return foundUnrecognizedDirective
|
||||
? NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
|
||||
: NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
|
||||
const char* aHeader,
|
||||
|
@ -902,17 +534,11 @@ nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
|
|||
uint32_t aFlags, bool* aCached,
|
||||
bool* aResult)
|
||||
{
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
|
||||
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::IsSecureURI for non-HSTS entries");
|
||||
}
|
||||
|
||||
NS_ENSURE_ARG(aURI);
|
||||
NS_ENSURE_ARG(aResult);
|
||||
|
||||
// Only HSTS and HPKP are supported at the moment.
|
||||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
|
||||
aType == nsISiteSecurityService::HEADER_HPKP,
|
||||
// Only HSTS is supported at the moment.
|
||||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
|
||||
NS_ERROR_NOT_IMPLEMENTED);
|
||||
|
||||
nsAutoCString hostname;
|
||||
|
@ -939,17 +565,11 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
|
|||
uint32_t aFlags, bool* aCached,
|
||||
bool* aResult)
|
||||
{
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
|
||||
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::IsSecureHost for non-HSTS entries");
|
||||
}
|
||||
|
||||
NS_ENSURE_ARG(aHost);
|
||||
NS_ENSURE_ARG(aResult);
|
||||
|
||||
// Only HSTS and HPKP are supported at the moment.
|
||||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
|
||||
aType == nsISiteSecurityService::HEADER_HPKP,
|
||||
// Only HSTS is supported at the moment.
|
||||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
|
||||
NS_ERROR_NOT_IMPLEMENTED);
|
||||
|
||||
// set default in case if we can't find any STS information
|
||||
|
@ -963,36 +583,14 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* An IP address never qualifies as a secure URI. */
|
||||
// An IP address never qualifies as a secure URI.
|
||||
if (HostIsIPAddress(aHost)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aType == nsISiteSecurityService::HEADER_HPKP) {
|
||||
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
|
||||
if (!certVerifier) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (certVerifier->mPinningMode ==
|
||||
CertVerifier::PinningMode::pinningDisabled) {
|
||||
return NS_OK;
|
||||
}
|
||||
bool enforceTestMode = certVerifier->mPinningMode ==
|
||||
CertVerifier::PinningMode::pinningEnforceTestMode;
|
||||
return PublicKeyPinningService::HostHasPins(aHost, mozilla::pkix::Now(),
|
||||
enforceTestMode, *aResult);
|
||||
}
|
||||
|
||||
// Holepunch chart.apis.google.com and subdomains.
|
||||
nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHost));
|
||||
if (host.EqualsLiteral("chart.apis.google.com") ||
|
||||
StringEndsWith(host, NS_LITERAL_CSTRING(".chart.apis.google.com"))) {
|
||||
if (aCached) {
|
||||
*aCached = true;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Canonicalize the passed host name
|
||||
nsAutoCString host(CanonicalizeHostname(aHost));
|
||||
|
||||
// First check the exact host. This involves first checking for an entry in
|
||||
// site security storage. If that entry exists, we don't want to check
|
||||
// in the preload list. We only want to use the stored value if it is not a
|
||||
|
@ -1088,144 +686,9 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
|
|||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::ClearAll()
|
||||
{
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::ClearAll");
|
||||
}
|
||||
|
||||
return mSiteStateStorage->Clear();
|
||||
}
|
||||
|
||||
bool entryStateNotOK(SiteHPKPState& state, mozilla::pkix::Time& aEvalTime) {
|
||||
return state.mState != SecurityPropertySet || state.IsExpired(aEvalTime) ||
|
||||
state.mSHA256keys.Length() < 1;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::GetKeyPinsForHostname(const char* aHostname,
|
||||
mozilla::pkix::Time& aEvalTime,
|
||||
/*out*/ nsTArray<nsCString>& pinArray,
|
||||
/*out*/ bool* aIncludeSubdomains,
|
||||
/*out*/ bool* aFound) {
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::GetKeyPinsForHostname");
|
||||
}
|
||||
|
||||
NS_ENSURE_ARG(aFound);
|
||||
NS_ENSURE_ARG(aHostname);
|
||||
|
||||
if (!mHPKPEnabled) {
|
||||
SSSLOG(("HPKP disabled - returning 'pins not found' for %s",
|
||||
aHostname));
|
||||
*aFound = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SSSLOG(("Top of GetKeyPinsForHostname for %s", aHostname));
|
||||
*aFound = false;
|
||||
*aIncludeSubdomains = false;
|
||||
pinArray.Clear();
|
||||
|
||||
nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHostname));
|
||||
nsAutoCString storageKey;
|
||||
SetStorageKey(storageKey, host, nsISiteSecurityService::HEADER_HPKP);
|
||||
|
||||
SSSLOG(("storagekey '%s'\n", storageKey.get()));
|
||||
mozilla::DataStorageType storageType = mozilla::DataStorage_Persistent;
|
||||
nsCString value = mSiteStateStorage->Get(storageKey, storageType);
|
||||
|
||||
// decode now
|
||||
SiteHPKPState foundEntry(value);
|
||||
if (entryStateNotOK(foundEntry, aEvalTime)) {
|
||||
// not in permanent storage, try now private
|
||||
value = mSiteStateStorage->Get(storageKey, mozilla::DataStorage_Private);
|
||||
SiteHPKPState privateEntry(value);
|
||||
if (entryStateNotOK(privateEntry, aEvalTime)) {
|
||||
// not in private storage, try dynamic preload
|
||||
value = mPreloadStateStorage->Get(storageKey,
|
||||
mozilla::DataStorage_Persistent);
|
||||
SiteHPKPState preloadEntry(value);
|
||||
if (entryStateNotOK(preloadEntry, aEvalTime)) {
|
||||
return NS_OK;
|
||||
}
|
||||
foundEntry = preloadEntry;
|
||||
} else {
|
||||
foundEntry = privateEntry;
|
||||
}
|
||||
}
|
||||
pinArray = foundEntry.mSHA256keys;
|
||||
*aIncludeSubdomains = foundEntry.mIncludeSubdomains;
|
||||
*aFound = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::SetKeyPins(const char* aHost, bool aIncludeSubdomains,
|
||||
int64_t aExpires, uint32_t aPinCount,
|
||||
const char** aSha256Pins,
|
||||
bool aIsPreload,
|
||||
/*out*/ bool* aResult)
|
||||
{
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::SetKeyPins");
|
||||
}
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aHost);
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
NS_ENSURE_ARG_POINTER(aSha256Pins);
|
||||
|
||||
|
||||
if (!mHPKPEnabled) {
|
||||
SSSLOG(("SSS: HPKP disabled: not setting pins"));
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SSSLOG(("Top of SetPins"));
|
||||
|
||||
nsTArray<nsCString> sha256keys;
|
||||
for (unsigned int i = 0; i < aPinCount; i++) {
|
||||
nsAutoCString pin(aSha256Pins[i]);
|
||||
SSSLOG(("SetPins pin=%s\n", pin.get()));
|
||||
if (!stringIsBase64EncodingOf256bitValue(pin)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
sha256keys.AppendElement(pin);
|
||||
}
|
||||
SiteHPKPState dynamicEntry(aExpires, SecurityPropertySet,
|
||||
aIncludeSubdomains, sha256keys);
|
||||
// we always store data in permanent storage (ie no flags)
|
||||
nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHost));
|
||||
return SetHPKPState(host.get(), dynamicEntry, 0, aIsPreload);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSiteSecurityService::SetHPKPState(const char* aHost, SiteHPKPState& entry,
|
||||
uint32_t aFlags, bool aIsPreload)
|
||||
{
|
||||
SSSLOG(("Top of SetPKPState"));
|
||||
nsAutoCString host(aHost);
|
||||
nsAutoCString storageKey;
|
||||
SetStorageKey(storageKey, host, nsISiteSecurityService::HEADER_HPKP);
|
||||
bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
|
||||
mozilla::DataStorageType storageType = isPrivate
|
||||
? mozilla::DataStorage_Private
|
||||
: mozilla::DataStorage_Persistent;
|
||||
nsAutoCString stateString;
|
||||
entry.ToString(stateString);
|
||||
|
||||
nsresult rv;
|
||||
if (aIsPreload) {
|
||||
rv = mPreloadStateStorage->Put(storageKey, stateString, storageType);
|
||||
} else {
|
||||
rv = mSiteStateStorage->Put(storageKey, stateString, storageType);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
// nsSiteSecurityService::nsIObserver
|
||||
//------------------------------------------------------------
|
||||
|
@ -1246,12 +709,6 @@ nsSiteSecurityService::Observe(nsISupports *subject,
|
|||
"network.stricttransportsecurity.enabled", true);
|
||||
mPreloadListTimeOffset =
|
||||
mozilla::Preferences::GetInt("test.currentTimeOffsetSeconds", 0);
|
||||
mHPKPEnabled = mozilla::Preferences::GetBool(
|
||||
"security.cert_pinning.hpkp.enabled", false);
|
||||
mProcessPKPHeadersFromNonBuiltInRoots = mozilla::Preferences::GetBool(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots", false);
|
||||
mMaxMaxAge = mozilla::Preferences::GetInt(
|
||||
"security.cert_pinning.max_max_age_seconds", kSixtyDaysInSeconds);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -38,40 +38,6 @@ enum SecurityPropertyState {
|
|||
SecurityPropertyNegative = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* SiteHPKPState: A utility class that encodes/decodes a string describing
|
||||
* the public key pins of a site.
|
||||
* HPKP state consists of:
|
||||
* - Expiry time (PRTime (aka int64_t) in milliseconds)
|
||||
* - A state flag (SecurityPropertyState, default SecurityPropertyUnset)
|
||||
* - An include subdomains flag (bool, default false)
|
||||
* - An array of sha-256 hashed base 64 encoded fingerprints of required keys
|
||||
*/
|
||||
class SiteHPKPState
|
||||
{
|
||||
public:
|
||||
SiteHPKPState();
|
||||
explicit SiteHPKPState(nsCString& aStateString);
|
||||
SiteHPKPState(PRTime aExpireTime, SecurityPropertyState aState,
|
||||
bool aIncludeSubdomains, nsTArray<nsCString>& SHA256keys);
|
||||
|
||||
PRTime mExpireTime;
|
||||
SecurityPropertyState mState;
|
||||
bool mIncludeSubdomains;
|
||||
nsTArray<nsCString> mSHA256keys;
|
||||
|
||||
bool IsExpired(mozilla::pkix::Time aTime)
|
||||
{
|
||||
if (aTime > mozilla::pkix::TimeFromEpochInSeconds(mExpireTime /
|
||||
PR_MSEC_PER_SEC)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ToString(nsCString& aString);
|
||||
};
|
||||
|
||||
/**
|
||||
* SiteHSTSState: A utility class that encodes/decodes a string describing
|
||||
* the security state of a site. Currently only handles HSTS.
|
||||
|
@ -137,20 +103,10 @@ private:
|
|||
nsresult ProcessSTSHeader(nsIURI* aSourceURI, const char* aHeader,
|
||||
uint32_t flags, uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains, uint32_t* aFailureResult);
|
||||
nsresult ProcessPKPHeader(nsIURI* aSourceURI, const char* aHeader,
|
||||
nsISSLStatus* aSSLStatus, uint32_t flags,
|
||||
uint64_t* aMaxAge, bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult);
|
||||
nsresult SetHPKPState(const char* aHost, SiteHPKPState& entry, uint32_t flags,
|
||||
bool aIsPreload);
|
||||
|
||||
uint64_t mMaxMaxAge;
|
||||
bool mUseStsService;
|
||||
int64_t mPreloadListTimeOffset;
|
||||
bool mHPKPEnabled;
|
||||
bool mProcessPKPHeadersFromNonBuiltInRoots;
|
||||
RefPtr<mozilla::DataStorage> mSiteStateStorage;
|
||||
RefPtr<mozilla::DataStorage> mPreloadStateStorage;
|
||||
};
|
||||
|
||||
#endif // __nsSiteSecurityService_h__
|
||||
|
|
|
@ -1,266 +0,0 @@
|
|||
// -*- indent-tabs-mode: nil; js-indent-level: 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/.
|
||||
//
|
||||
// For all cases, the acceptable pinset includes only certificates pinned to
|
||||
// Test End Entity Cert (signed by issuer testCA). Other certificates
|
||||
// are issued by otherCA, which is never in the pinset but is a user-specified
|
||||
// trust anchor. This test covers multiple cases:
|
||||
//
|
||||
// Pinned domain include-subdomains.pinning.example.com includes subdomains
|
||||
// - PASS: include-subdomains.pinning.example.com serves a correct cert
|
||||
// - PASS: good.include-subdomains.pinning.example.com serves a correct cert
|
||||
// - FAIL (strict): bad.include-subdomains.pinning.example.com serves a cert
|
||||
// not in the pinset
|
||||
// - PASS (mitm): bad.include-subdomains.pinning.example.com serves a cert not
|
||||
// in the pinset, but issued by a user-specified trust domain
|
||||
//
|
||||
// Pinned domain exclude-subdomains.pinning.example.com excludes subdomains
|
||||
// - PASS: exclude-subdomains.pinning.example.com serves a correct cert
|
||||
// - FAIL: exclude-subdomains.pinning.example.com serves an incorrect cert
|
||||
// (TODO: test using verifyCertNow)
|
||||
// - PASS: sub.exclude-subdomains.pinning.example.com serves an incorrect cert
|
||||
|
||||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
|
||||
function add_clear_override(host) {
|
||||
add_test(function() {
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.clearValidityOverride(host, 8443);
|
||||
run_next_test();
|
||||
});
|
||||
}
|
||||
|
||||
function test_strict() {
|
||||
// In strict mode, we always evaluate pinning data, regardless of whether the
|
||||
// issuer is a built-in trust anchor. We only enforce pins that are not in
|
||||
// test mode.
|
||||
add_test(function() {
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Normally this is overridable. But, since we have pinning information for
|
||||
// this host, we don't allow overrides.
|
||||
add_prevented_cert_override_test(
|
||||
"unknownissuer.include-subdomains.pinning.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
|
||||
|
||||
// Issued by otherCA, which is not in the pinset for pinning.example.com.
|
||||
add_connection_test("bad.include-subdomains.pinning.example.com",
|
||||
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
|
||||
|
||||
// Check that using a FQDN doesn't bypass pinning.
|
||||
add_connection_test("bad.include-subdomains.pinning.example.com.",
|
||||
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
|
||||
// For some reason this is also navigable (see bug 1118522).
|
||||
add_connection_test("bad.include-subdomains.pinning.example.com..",
|
||||
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
|
||||
|
||||
// These domains serve certs that match the pinset.
|
||||
add_connection_test("include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("good.include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("exclude-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
|
||||
// This domain serves a cert that doesn't match the pinset, but subdomains
|
||||
// are excluded.
|
||||
add_connection_test("sub.exclude-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
|
||||
// This domain's pinset is exactly the same as
|
||||
// include-subdomains.pinning.example.com, serves the same cert as
|
||||
// bad.include-subdomains.pinning.example.com, but it should pass because
|
||||
// it's in test_mode.
|
||||
add_connection_test("test-mode.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
// Similarly, this pin is in test-mode, so it should be overridable.
|
||||
add_cert_override_test("unknownissuer.test-mode.pinning.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_clear_override("unknownissuer.test-mode.pinning.example.com");
|
||||
}
|
||||
|
||||
function test_mitm() {
|
||||
// In MITM mode, we allow pinning to pass if the chain resolves to any
|
||||
// user-specified trust anchor, even if it is not in the pinset.
|
||||
add_test(function() {
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 1);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_connection_test("include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("good.include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
|
||||
// Normally this is overridable. But, since we have pinning information for
|
||||
// this host, we don't allow overrides (since building a trusted chain fails,
|
||||
// we have no reason to believe this was issued by a user-added trust
|
||||
// anchor, so we can't allow overrides for it).
|
||||
add_prevented_cert_override_test(
|
||||
"unknownissuer.include-subdomains.pinning.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
|
||||
|
||||
// In this case, even though otherCA is not in the pinset, it is a
|
||||
// user-specified trust anchor and the pinning check succeeds.
|
||||
add_connection_test("bad.include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
|
||||
add_connection_test("exclude-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("sub.exclude-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("test-mode.pinning.example.com", PRErrorCodeSuccess);
|
||||
add_cert_override_test("unknownissuer.test-mode.pinning.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_clear_override("unknownissuer.test-mode.pinning.example.com");
|
||||
}
|
||||
|
||||
function test_disabled() {
|
||||
// Disable pinning.
|
||||
add_test(function() {
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 0);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_connection_test("include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("good.include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("bad.include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("exclude-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("sub.exclude-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("test-mode.pinning.example.com", PRErrorCodeSuccess);
|
||||
|
||||
add_cert_override_test("unknownissuer.include-subdomains.pinning.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
|
||||
add_cert_override_test("unknownissuer.test-mode.pinning.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_clear_override("unknownissuer.test-mode.pinning.example.com");
|
||||
}
|
||||
|
||||
function test_enforce_test_mode() {
|
||||
// In enforce test mode, we always enforce all pins, even test pins.
|
||||
add_test(function() {
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 3);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Normally this is overridable. But, since we have pinning information for
|
||||
// this host, we don't allow overrides.
|
||||
add_prevented_cert_override_test(
|
||||
"unknownissuer.include-subdomains.pinning.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
|
||||
|
||||
// Issued by otherCA, which is not in the pinset for pinning.example.com.
|
||||
add_connection_test("bad.include-subdomains.pinning.example.com",
|
||||
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
|
||||
|
||||
// These domains serve certs that match the pinset.
|
||||
add_connection_test("include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("good.include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("exclude-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
|
||||
// This domain serves a cert that doesn't match the pinset, but subdomains
|
||||
// are excluded.
|
||||
add_connection_test("sub.exclude-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
|
||||
// This domain's pinset is exactly the same as
|
||||
// include-subdomains.pinning.example.com, serves the same cert as
|
||||
// bad.include-subdomains.pinning.example.com, is in test-mode, but we are
|
||||
// enforcing test mode pins.
|
||||
add_connection_test("test-mode.pinning.example.com",
|
||||
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
|
||||
// Normally this is overridable. But, since we have pinning information for
|
||||
// this host (and since we're enforcing test mode), we don't allow overrides.
|
||||
add_prevented_cert_override_test(
|
||||
"unknownissuer.test-mode.pinning.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_clear_override("unknownissuer.test-mode.pinning.example.com");
|
||||
}
|
||||
|
||||
function check_pinning_telemetry() {
|
||||
let service = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
let prod_histogram = service.getHistogramById("CERT_PINNING_RESULTS")
|
||||
.snapshot();
|
||||
let test_histogram = service.getHistogramById("CERT_PINNING_TEST_RESULTS")
|
||||
.snapshot();
|
||||
// Because all of our test domains are pinned to user-specified trust
|
||||
// anchors, effectively only strict mode and enforce test-mode get evaluated
|
||||
equal(prod_histogram.counts[0], 4,
|
||||
"Actual and expected prod (non-Mozilla) failure count should match");
|
||||
equal(prod_histogram.counts[1], 4,
|
||||
"Actual and expected prod (non-Mozilla) success count should match");
|
||||
equal(test_histogram.counts[0], 2,
|
||||
"Actual and expected test (non-Mozilla) failure count should match");
|
||||
equal(test_histogram.counts[1], 0,
|
||||
"Actual and expected test (non-Mozilla) success count should match");
|
||||
|
||||
let moz_prod_histogram = service.getHistogramById("CERT_PINNING_MOZ_RESULTS")
|
||||
.snapshot();
|
||||
let moz_test_histogram =
|
||||
service.getHistogramById("CERT_PINNING_MOZ_TEST_RESULTS").snapshot();
|
||||
equal(moz_prod_histogram.counts[0], 0,
|
||||
"Actual and expected prod (Mozilla) failure count should match");
|
||||
equal(moz_prod_histogram.counts[1], 0,
|
||||
"Actual and expected prod (Mozilla) success count should match");
|
||||
equal(moz_test_histogram.counts[0], 0,
|
||||
"Actual and expected test (Mozilla) failure count should match");
|
||||
equal(moz_test_histogram.counts[1], 0,
|
||||
"Actual and expected test (Mozilla) success count should match");
|
||||
|
||||
let per_host_histogram =
|
||||
service.getHistogramById("CERT_PINNING_MOZ_RESULTS_BY_HOST").snapshot();
|
||||
equal(per_host_histogram.counts[0], 0,
|
||||
"Actual and expected per host (Mozilla) failure count should match");
|
||||
equal(per_host_histogram.counts[1], 2,
|
||||
"Actual and expected per host (Mozilla) success count should match");
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// Ensure that static pinning works when HPKP is disabled.
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", false);
|
||||
|
||||
add_tls_server_setup("BadCertServer", "bad_certs");
|
||||
|
||||
// Add a user-specified trust anchor.
|
||||
addCertFromFile(certdb, "bad_certs/other-test-ca.pem", "CTu,u,u");
|
||||
|
||||
test_strict();
|
||||
test_mitm();
|
||||
test_disabled();
|
||||
test_enforce_test_mode();
|
||||
|
||||
add_test(function () {
|
||||
check_pinning_telemetry();
|
||||
});
|
||||
run_next_test();
|
||||
}
|
|
@ -1,243 +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/. */
|
||||
"use strict";
|
||||
|
||||
// The purpose of this test is to create a site security service state file
|
||||
// and see that the site security service reads it properly.
|
||||
|
||||
function writeLine(aLine, aOutputStream) {
|
||||
aOutputStream.write(aLine, aLine.length);
|
||||
}
|
||||
|
||||
var gSSService = null;
|
||||
var gSSSStateSeen = false;
|
||||
var gPreloadStateSeen = false;
|
||||
|
||||
var profileDir = do_get_profile();
|
||||
var certdb;
|
||||
|
||||
function certFromFile(cert_name) {
|
||||
return constructCertFromFile("test_pinning_dynamic/" + cert_name + ".pem");
|
||||
}
|
||||
|
||||
function loadCert(cert_name, trust_string) {
|
||||
let cert_filename = "test_pinning_dynamic/" + cert_name + ".pem";
|
||||
addCertFromFile(certdb, cert_filename, trust_string);
|
||||
return constructCertFromFile(cert_filename);
|
||||
}
|
||||
|
||||
function checkOK(cert, hostname) {
|
||||
return checkCertErrorGeneric(certdb, cert, PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer, {}, hostname);
|
||||
}
|
||||
|
||||
function checkFail(cert, hostname) {
|
||||
return checkCertErrorGeneric(certdb, cert, MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE,
|
||||
certificateUsageSSLServer, {}, hostname);
|
||||
}
|
||||
|
||||
const NON_ISSUED_KEY_HASH = "KHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN=";
|
||||
const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
|
||||
let stateFile = profileDir.clone();
|
||||
stateFile.append(SSS_STATE_FILE_NAME);
|
||||
// Assuming we're working with a clean slate, the SSS_STATE file shouldn't
|
||||
// exist until we create it.
|
||||
ok(!stateFile.exists(),
|
||||
"State file should not exist when working with a clean slate");
|
||||
let outputStream = FileUtils.openFileOutputStream(stateFile);
|
||||
let now = (new Date()).getTime();
|
||||
writeLine(`a.pinning2.example.com:HPKP\t0\t0\t${now + 100000},1,0,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
|
||||
writeLine(`b.pinning2.example.com:HPKP\t0\t0\t${now + 100000},1,1,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
|
||||
|
||||
outputStream.close();
|
||||
|
||||
let preloadFile = profileDir.clone();
|
||||
preloadFile.append(PRELOAD_STATE_FILE_NAME);
|
||||
ok(!preloadFile.exists(),
|
||||
"Preload file should not exist when working with a clean slate");
|
||||
|
||||
outputStream = FileUtils.openFileOutputStream(preloadFile);
|
||||
writeLine(`a.preload.example.com:HPKP\t0\t0\t${now + 100000},1,1,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
|
||||
outputStream.close();
|
||||
|
||||
Services.obs.addObserver(checkStateRead, "data-storage-ready", false);
|
||||
do_test_pending();
|
||||
gSSService = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
notEqual(gSSService, null,
|
||||
"SiteSecurityService should have initialized successfully using" +
|
||||
" the generated state file");
|
||||
}
|
||||
|
||||
function checkDefaultSiteHPKPStatus() {
|
||||
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
"a.pinning2.example.com", 0),
|
||||
"a.pinning2.example.com should have HPKP status");
|
||||
ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
"x.a.pinning2.example.com", 0),
|
||||
"x.a.pinning2.example.com should not have HPKP status");
|
||||
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
"b.pinning2.example.com", 0),
|
||||
"b.pinning2.example.com should have HPKP status");
|
||||
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
"x.b.pinning2.example.com", 0),
|
||||
"x.b.pinning2.example.com should have HPKP status");
|
||||
}
|
||||
|
||||
function checkStateRead(aSubject, aTopic, aData) {
|
||||
if (aData == SSS_STATE_FILE_NAME) {
|
||||
gSSSStateSeen = true;
|
||||
} else if (aData == PRELOAD_STATE_FILE_NAME) {
|
||||
gPreloadStateSeen = true;
|
||||
} else {
|
||||
throw new Error("Observed data should either be the Site Security " +
|
||||
"Service state file name or the preload file name");
|
||||
}
|
||||
|
||||
if (!gSSSStateSeen || !gPreloadStateSeen) {
|
||||
return;
|
||||
}
|
||||
|
||||
notEqual(gSSService, null, "SiteSecurityService should be initialized");
|
||||
|
||||
// Initializing the certificate DB will cause NSS-initialization, which in
|
||||
// turn initializes the site security service. Since we're in part testing
|
||||
// that the site security service correctly reads its state file, we have to
|
||||
// make sure it doesn't start up before we've populated the file
|
||||
certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
|
||||
loadCert("pinningroot", "CTu,CTu,CTu");
|
||||
loadCert("badca", "CTu,CTu,CTu");
|
||||
|
||||
// the written entry is for a.pinning2.example.com without subdomains
|
||||
// and b.pinning2.example.com with subdomains
|
||||
checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
|
||||
checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
|
||||
checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
|
||||
checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
|
||||
|
||||
checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
|
||||
checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
|
||||
checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
|
||||
checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
|
||||
|
||||
checkDefaultSiteHPKPStatus();
|
||||
|
||||
|
||||
// add includeSubdomains to a.pinning2.example.com
|
||||
gSSService.setKeyPins("a.pinning2.example.com", true,
|
||||
new Date().getTime() + 1000000, 2,
|
||||
[NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH]);
|
||||
checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
|
||||
checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
|
||||
checkFail(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
|
||||
checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
|
||||
checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
|
||||
checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
|
||||
checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
|
||||
checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
|
||||
|
||||
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
"a.pinning2.example.com", 0),
|
||||
"a.pinning2.example.com should still have HPKP status after adding" +
|
||||
" includeSubdomains to a.pinning2.example.com");
|
||||
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
"x.a.pinning2.example.com", 0),
|
||||
"x.a.pinning2.example.com should now have HPKP status after adding" +
|
||||
" includeSubdomains to a.pinning2.example.com");
|
||||
|
||||
// Now setpins without subdomains
|
||||
gSSService.setKeyPins("a.pinning2.example.com", false,
|
||||
new Date().getTime() + 1000000, 2,
|
||||
[NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH]);
|
||||
checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
|
||||
checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
|
||||
checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
|
||||
checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
|
||||
|
||||
checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
|
||||
checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
|
||||
checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
|
||||
checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
|
||||
|
||||
checkDefaultSiteHPKPStatus();
|
||||
|
||||
// failure to insert new pin entry leaves previous pin behavior
|
||||
throws(() => {
|
||||
gSSService.setKeyPins("a.pinning2.example.com", true,
|
||||
new Date().getTime() + 1000000, 1, ["not a hash"]);
|
||||
}, /NS_ERROR_ILLEGAL_VALUE/, "Attempting to set an invalid pin should fail");
|
||||
checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
|
||||
checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
|
||||
checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
|
||||
checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
|
||||
|
||||
checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
|
||||
checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
|
||||
checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
|
||||
checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
|
||||
|
||||
checkDefaultSiteHPKPStatus();
|
||||
|
||||
// Incorrect size results in failure
|
||||
throws(() => {
|
||||
gSSService.setKeyPins("a.pinning2.example.com", true,
|
||||
new Date().getTime() + 1000000, 2, ["not a hash"]);
|
||||
}, /NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY/,
|
||||
"Attempting to set a pin with an incorrect size should fail");
|
||||
|
||||
// Ensure built-in pins work as expected
|
||||
ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
"nonexistent.example.com", 0),
|
||||
"Not built-in nonexistent.example.com should not have HPKP status");
|
||||
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
"include-subdomains.pinning.example.com", 0),
|
||||
"Built-in include-subdomains.pinning.example.com should have HPKP status");
|
||||
|
||||
gSSService.setKeyPins("a.pinning2.example.com", false, new Date().getTime(),
|
||||
1, [NON_ISSUED_KEY_HASH]);
|
||||
|
||||
// Check that a preload pin loaded from file works as expected
|
||||
checkFail(certFromFile("a.preload.example.com-badca"), "a.preload.example.com");
|
||||
checkOK(certFromFile("a.preload.example.com-pinningroot"), "a.preload.example.com");
|
||||
|
||||
// Check a dynamic addition works as expected
|
||||
// first, it should succeed with the badCA - because there's no pin
|
||||
checkOK(certFromFile('b.preload.example.com-badca'), "b.preload.example.com");
|
||||
// then we add a pin, and we should get a failure (ensuring the expiry is
|
||||
// after the test timeout)
|
||||
gSSService.setKeyPins("b.preload.example.com", false,
|
||||
new Date().getTime() + 1000000, 2,
|
||||
[NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH], true);
|
||||
checkFail(certFromFile('b.preload.example.com-badca'), "b.preload.example.com");
|
||||
|
||||
do_timeout(1250, checkExpiredState);
|
||||
}
|
||||
|
||||
function checkExpiredState() {
|
||||
checkOK(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
|
||||
checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
|
||||
checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
|
||||
checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
|
||||
|
||||
checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
|
||||
checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
|
||||
checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
|
||||
checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
|
||||
checkPreloadClear();
|
||||
}
|
||||
|
||||
function checkPreloadClear() {
|
||||
// Check that the preloaded pins still work after private data is cleared
|
||||
gSSService.clearAll();
|
||||
checkFail(certFromFile('b.preload.example.com-badca'), "b.preload.example.com");
|
||||
|
||||
do_test_finished();
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC3TCCAcegAwIBAgIUXdB7LgBGZoRV1UmEFcsOhMigpB0wCwYJKoZIhvcNAQEL
|
||||
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
|
||||
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
|
||||
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
|
||||
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
|
||||
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
|
||||
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
|
||||
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMlMCMwIQYD
|
||||
VR0RBBowGIIWYS5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEB
|
||||
AAKhpX2t/Bz9//u1DYyLZ6dLSJt121Vb58s8gQvI/7n6MdUP1IniQLbtPW+7wnV0
|
||||
6LYagJQ11ZUJMxYUs6lB91yhwAO9NoN4QJWWB0i23DoZ6cg4dHmYKmQQ/HRndwm+
|
||||
EATkJSnBAk8O2xmIm8CXbJ0W0lvaXEjzRfeoiEjQ0/THeo4hXvGOMPm31d+r4ji5
|
||||
/u2+9jrpTII0kjCwFjqC97lPID14s9QRMqMB1CCV6fgT19EGYi9I7H6mnyukkmfX
|
||||
9wOhLHSk6A2l5+5eJrZYXLOhcS31VBd54sb1Vvg+Bp05HMYjo051JcRlvxoIUsHT
|
||||
JQDn8QrzwZBDBh4Pie3AwOM=
|
||||
-----END CERTIFICATE-----
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:a.pinning2.example.com
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC4zCCAc2gAwIBAgIUPQgjdPeWdWy/0oKRi+5Lr7JJorMwCwYJKoZIhvcNAQEL
|
||||
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
|
||||
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
|
||||
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
|
||||
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
|
||||
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
|
||||
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
|
||||
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMl
|
||||
MCMwIQYDVR0RBBowGIIWYS5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0B
|
||||
AQsDggEBAFUlxnwpxOFbSxtsBthWu6xmDxeFAzP+u5YOfuKeiIGnAx70k8ODQufJ
|
||||
Vm1rXvKtN5r8jR6AZh/hdA+tGhnu4+pGi9/aqWnaF1FEs2mW0saUV8atQZwNGRBO
|
||||
E9FXdAHA8WmGIfRf8TOuWpmEWejjJt5Zsfs+V3ARIxjCrVE7ixyfJ/hYpmthLtYJ
|
||||
5vgp0iiPjzorKeFnqooLVAfzeayRX0bE5H79NISIWq4CN/9J50ZFkRORURlANU95
|
||||
2Dcuw416b3BGrWVmWlKWOpA6NZ+Rj+AI+z9UTDpqCczTfMXMabX4EveW1GKMMYiA
|
||||
eLD8SY4VQ4403eaCp6rxYFrCNOeDczs=
|
||||
-----END CERTIFICATE-----
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:a.pinning2.example.com
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC3DCCAcagAwIBAgIUKUG7kBZ72CvuLQ0uPfjKHLkKDQAwCwYJKoZIhvcNAQEL
|
||||
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
|
||||
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
|
||||
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
|
||||
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
|
||||
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
|
||||
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
|
||||
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMkMCIwIAYD
|
||||
VR0RBBkwF4IVYS5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOCAQEA
|
||||
tx5YO8uvYac92scnMEswv4ZIslou8UYV/2mtxA+MaXf/g+MizOKeZgTI1+b9hR48
|
||||
IDOgvrqPCbn1hKY6gb2gtRI1mC5dg9T8EYEXcC1TM+ncY/l4SZUjfMhzY2iOf62x
|
||||
jhDqMMt4V5uaHUxVmJQI82X5qpxH3yJ3WOC87iGZNfMB8MSbLM3lxor9OHeTlTHQ
|
||||
vPb/r7cLW+ikxirDGyBBvThkvDA/8qyN5Qp6Ae1BiPeEMoScNf3fChvNV6Jyb8g8
|
||||
e9q0LnTlTuVgaDWtg7PVOxeiI+wf3Jhv9uqXQLX8JHZDKebLbQEkNcbR4DK/8wsP
|
||||
uFhj0j8DY6+/YZbcF7Jgfw==
|
||||
-----END CERTIFICATE-----
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:a.preload.example.com
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC4jCCAcygAwIBAgIURV3mf9Dz42lALe31OAm2SYbpFaEwCwYJKoZIhvcNAQEL
|
||||
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
|
||||
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
|
||||
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
|
||||
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
|
||||
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
|
||||
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
|
||||
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMk
|
||||
MCIwIAYDVR0RBBkwF4IVYS5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEB
|
||||
CwOCAQEATOA0bbfg81JieQkTzr4oxBqPuFamtLSAsLpbKakikYQo2znMGNnHV7Xe
|
||||
uxMGMhCIPRsiJ6jj6ZTQJNqQRKzXWEiBgREsarmJxA53ITIcO2cK2rqyetNAAwzZ
|
||||
oViENmK3tLA5KT2VC9IGgMXdSE7IfXn+5yCdpKZ2ohwtkYHNkCbQIU+4KaCPa/dB
|
||||
yAelZZPE0mVHJLkd5HoOsFmjFOBQuOkn9/AAOmkgBZIk1Dp833ywn/mnwLZdVsdV
|
||||
+TjqWKenDJXxhO2+aCCtZbUVxKMn0TACpAA+rhjS5vigCyIZh7V4rxki9UXaOfVq
|
||||
EVy4rFlRIYYtXV40HavDZoPgxuCHDw==
|
||||
-----END CERTIFICATE-----
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:a.preload.example.com
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC3TCCAcegAwIBAgIUV89JsAhywp3graSGqjeSpMzd1B0wCwYJKoZIhvcNAQEL
|
||||
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
|
||||
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
|
||||
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
|
||||
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
|
||||
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
|
||||
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
|
||||
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMlMCMwIQYD
|
||||
VR0RBBowGIIWYi5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEB
|
||||
ABevzhH9/hjTBgTtUk4ytZX0A7Tu0DR5F9ooFnlUwzupHFihO+9NzEoCSIvCy3L9
|
||||
+i3LbkaiUWEHQItLjIg+aice13ZkuMp+DeZ+D/YR9ulxyY1QBYeZLQj/gSdkj/fK
|
||||
uDm0Izgt8OBsgP+KFX2c2cGZyOcXmFFAwSfkLz7p2qzrmuM7r5ploNpxeHBUIxUW
|
||||
jJzSFeQMfy5wflcKDBY+PDejzN9Ik4weRyERsckVgmZSJXuodb8xgYkNPvl/GOVJ
|
||||
o+eDw+E3uOsdBIDrsyb+bcQTG7nBkQoSqG8M0610h0OqFhksfv/0HcB/wfW8VdU+
|
||||
+C4+tR2KfvqTCm3T6gzRWX8=
|
||||
-----END CERTIFICATE-----
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:b.pinning2.example.com
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC4zCCAc2gAwIBAgIUVQNTrx+mRE96ggRLuZeFm+9uBdcwCwYJKoZIhvcNAQEL
|
||||
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
|
||||
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
|
||||
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
|
||||
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
|
||||
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
|
||||
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
|
||||
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMl
|
||||
MCMwIQYDVR0RBBowGIIWYi5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0B
|
||||
AQsDggEBAHYCfQaolF6z4IicBDTEQQVfYi4A3BcCNLTdInQlal/DHNytNRufM5TB
|
||||
ccNpau5U9e10NBYWbMqRUBb/7wtYE4O7jhEWxjaHBOz5KTYLv8hjEc2wcHXfhlYM
|
||||
QKmxOnA7SguSNYBdfXywav//ssLmDnB06nc2vv5NaKvIWbUv3HvfM8oRAr+NICUs
|
||||
UMcIb+hjY+u/qrnOeFJxXzeqPYKMa7H+33baRgy7xnL95PxAwkz0XL8vcMFupTX5
|
||||
dL5HsSKku23C0BoE6pK39TVh758fQjCAnD+QRTH/o+dfE2sIFpRiyszdXGmh2IRR
|
||||
gMSy+gJbH+zh0D9ncL0Kev0PyEuBYR4=
|
||||
-----END CERTIFICATE-----
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:b.pinning2.example.com
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC3DCCAcagAwIBAgIUf2T4BVvxeCgWVp/FL3tCFNjuZYQwCwYJKoZIhvcNAQEL
|
||||
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
|
||||
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
|
||||
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
|
||||
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
|
||||
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
|
||||
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
|
||||
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMkMCIwIAYD
|
||||
VR0RBBkwF4IVYi5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOCAQEA
|
||||
okmxK2NDRYWSAn6b1YZpLiZnoaNrM0HXHY6fkARY/9EiAApvNPxT663EKtTZn27a
|
||||
JtwXP2zzlYQDRc9cxa1zBX9Tp+0sn5aqokqzoVWx4VIe/emzi9FDf3lgaYewHLez
|
||||
RINv3kUZmqlw6tmMQxjd51UGyvNsi52+gcet1cPr5kBzGQv/q7iNs/lcetL3+KQF
|
||||
klJ3PfI4VjFwRRYNhScxiRczklPVDySvxSNw+csUxNRunFLXIi3+WqQzYhw7R8ga
|
||||
ASwozTfvVAUySOmDipCZZXAHFtlpBr6vAllfD9v8hAsrE7Bkivafr+i5HMD3DtJE
|
||||
4ZedqFCkTkqKvd0fMIbOIA==
|
||||
-----END CERTIFICATE-----
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:b.preload.example.com
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC4jCCAcygAwIBAgIUI5rdRX/x0w0bDx6hQhc8ZhGLfqQwCwYJKoZIhvcNAQEL
|
||||
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
|
||||
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
|
||||
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
|
||||
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
|
||||
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
|
||||
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
|
||||
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMk
|
||||
MCIwIAYDVR0RBBkwF4IVYi5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEB
|
||||
CwOCAQEAg2VdHBLmFLJ03N9VT4uUrnpjuYY9bsvPJF2JCk9817nxBbeMf+Qn0C/o
|
||||
OeoQnZRqsaFbKZ80JXmh/j4RO6T/aaQUMpk+NXrdSPddy2B3eUByF/NJqipV3M2a
|
||||
CRNWUUVF+msjRWwbzJafju2nEZcD4d4cUkHHYAaRRxAHH3ylEvWmdv/brgfAPCPH
|
||||
WDVaCMc3OXgHkyrLAfkMKSYTNPJ7DJn/BXET5tCzqYGRUgRnME4ON2Mmp19lsdig
|
||||
dIFbm76wg6l5M+s9pqiYzODUxJXUOd6BkAR5pqB9WyIRVfBr5LGT72nv00LHVcSm
|
||||
hnsti9nAtFdJx4E1lJilrnQwu0q4Iw==
|
||||
-----END CERTIFICATE-----
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:b.preload.example.com
|
|
@ -1,17 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICyzCCAbWgAwIBAgIUXQevdaeXMieCrG6ZqhI2yfACBq4wCwYJKoZIhvcNAQEL
|
||||
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
|
||||
MDAwMDBaMBAxDjAMBgNVBAMMBWJhZGNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAwXXGUmYJn3cIKmeR8bh2w39c5TiwbErNIrHL1G+mWtoq3UHIwkmK
|
||||
xKOzwfYUh/QbaYlBvYClHDwSAkTFhKTESDMF5ROMAQbPCL6ahidguuai6PNvI8XZ
|
||||
gxO53683g0XazlHU1tzSpss8xwbrzTBw7JjM5AqlkdcpWn9xxb5maR0rLf7ISURZ
|
||||
C8Wj6kn9k7HXU0BfF3N2mZWGZiVHl+1CaQiICBFCIGmYikP+5Izmh4HdIramnNKD
|
||||
dRMfkysSjOKG+n0lHAYq0n7wFvGHzdVOgys1uJMPdLqQqovHYWckKrH9bWIUDRjE
|
||||
wLjGj8N0hFcyStfehuZVLx0eGR1xIWjTuwIDAQABox0wGzAMBgNVHRMEBTADAQH/
|
||||
MAsGA1UdDwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAHitWfZzPxR/UWEKQgz9zzm2
|
||||
NXszG7nV82w8qfC9pq8mU3f7eqbHJ2HNFkZzttJsH9DNl30OK2Y5IVLUiZHckz2e
|
||||
OFUyxK0tBCCBYd79FiK4BgP/Ys/7LK+4UaDhbRQP//MGuofwjsrNxgPgtkNaeKtF
|
||||
EXKCuDrHoa4ua7afrkUWKzPZ6JbDOEjJIyuJ3ISI0Q20Oc3ERxGwG1SQ1EldgWBr
|
||||
0dJJWBHZtNpIVvSm1dRfjMYtSrBoUXwbn6kDrdk4T98OHnFP0V0KW4j4umLHK7Gi
|
||||
OSAwvWtir3fSJaLJClTCFe1XoNvJnQ53PJs0JR26mAixV2VuylStO2KlbYy7fOc=
|
||||
-----END CERTIFICATE-----
|
|
@ -1,6 +0,0 @@
|
|||
issuer:badca
|
||||
subject:badca
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:keyCertSign,cRLSign
|
|
@ -1,26 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
# Temporarily disabled. See bug 1256495.
|
||||
#test_certificates = (
|
||||
# 'badca.pem',
|
||||
# 'a.pinning2.example.com-badca.pem',
|
||||
# 'a.pinning2.example.com-pinningroot.pem',
|
||||
# 'a.preload.example.com-badca.pem',
|
||||
# 'a.preload.example.com-pinningroot.pem',
|
||||
# 'b.pinning2.example.com-badca.pem',
|
||||
# 'b.pinning2.example.com-pinningroot.pem',
|
||||
# 'b.preload.example.com-badca.pem',
|
||||
# 'b.preload.example.com-pinningroot.pem',
|
||||
# 'x.a.pinning2.example.com-badca.pem',
|
||||
# 'x.a.pinning2.example.com-pinningroot.pem',
|
||||
# 'x.b.pinning2.example.com-badca.pem',
|
||||
# 'x.b.pinning2.example.com-pinningroot.pem',
|
||||
# 'pinningroot.pem',
|
||||
#)
|
||||
#
|
||||
#for test_certificate in test_certificates:
|
||||
# GeneratedTestCertificate(test_certificate)
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC1zCCAcGgAwIBAgIUMwSUmBShbg5sMNZSTiPd5Tb1udkwCwYJKoZIhvcNAQEL
|
||||
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
|
||||
ODAyMDUwMDAwMDBaMBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
|
||||
aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
|
||||
adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
|
||||
pH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62W
|
||||
YVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauR
|
||||
CE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAM
|
||||
BgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjALBgkqhkiG9w0BAQsDggEBADNuQnKg
|
||||
y8zWnKlfBq/50UOtdSlvevg6u6tsUTvay2kVgB8BRTvm76aw4yOLgk84eHHkrX5c
|
||||
TqdutWh2JZarUWbO7JnPTdDE2CAkDh1smSe9L/XJENbgVXleg/VYLgnfnuSQCCnK
|
||||
WjjExcorX6IKDks1ZoBJ1HIvBzMRMWzIQgBL9B2Y1V05lgfn0bwZD+TjUJBmN1w0
|
||||
NTaPgrxE7FWZ2CTcowrYRKEEDAUX4cTFoce5YMwALCgW59KfVQfQdHaiCCcdNbfi
|
||||
qSQGZu+59JrrasmgK9VTahukYWcaQCz8HBCasdknGodLAzThuWMkjXU3D2IZYl15
|
||||
GfE5yrRFop/89xo=
|
||||
-----END CERTIFICATE-----
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:pinningroot
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:keyCertSign,cRLSign
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC3zCCAcmgAwIBAgIUe11LKIzCrdnRTgrLsfuGMoOpL1QwCwYJKoZIhvcNAQEL
|
||||
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
|
||||
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
|
||||
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
|
||||
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
|
||||
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
|
||||
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
|
||||
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMnMCUwIwYD
|
||||
VR0RBBwwGoIYeC5hLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOC
|
||||
AQEAgdFC/SwBLRp6A+n3znR+sEuU8UvmbgbXp7pIFVh6cbC6lNF0nXk9ywPeIWyh
|
||||
B7TCn3YHj4uc/PbvzRj9Py0gQLXcimKpmLoxclV5g1uTAydgXPiPulv/kaL9NOME
|
||||
lm88pyQeDwfEkUz7VijabIzFRTEVRmOudb8mX4SuzjhxsdzSMjffpae335beJ4Im
|
||||
lxgJgMsuJdEoK0WyG5nlBhVdzrT/kwdiwULeVNV//UHid1YZy56G5Lo22Hgd4wT3
|
||||
1W3LXQelBdHhee7Hf7mg4rjCUPulFAr8qBLdywf1Hnu1o7rXUcn46PLwKLOWJPOM
|
||||
SKpiqRKqvzlrzLaHPejfT0IMrw==
|
||||
-----END CERTIFICATE-----
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:x.a.pinning2.example.com
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC5TCCAc+gAwIBAgIUefEeE+Sj5fBSec+97B6UmZFQEncwCwYJKoZIhvcNAQEL
|
||||
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
|
||||
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
|
||||
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
|
||||
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
|
||||
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
|
||||
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
|
||||
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMn
|
||||
MCUwIwYDVR0RBBwwGoIYeC5hLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3
|
||||
DQEBCwOCAQEAT2fxisiLJvVdFTba07a2Pc6UHBE+O0tOaLfMmHx/ET2FZdd9sLTL
|
||||
X2f+hQCmXEBQ7Au2eYTew8hTyXYGYFauMJNk+XHHUIaSOhmnYTccye4d6j5bXRCp
|
||||
7zA1qPlReCDLjp7o/34whkvngvdgdLYf60EkBO/NJfj+zsR1JTVfyVzIKXl6veLz
|
||||
0xKicBAq9vS0Yqq10japVYKKqAw6gDpbNkSAd3xsl4+EbMRq+BnMB4W2anw1gM/e
|
||||
hV11JQVA/MREtmUiTkvJFF6chHVCn5aL7JzVM2miZjZC8Ix59LUBoyO3SrxgrzZw
|
||||
xeYuwoDhzTCrcFxn8gdKNajbGHuW5ekQpg==
|
||||
-----END CERTIFICATE-----
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:x.a.pinning2.example.com
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC3zCCAcmgAwIBAgIUYcTc5Pz7KlQldGOO+KzbuBdf8TswCwYJKoZIhvcNAQEL
|
||||
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
|
||||
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
|
||||
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
|
||||
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
|
||||
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
|
||||
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
|
||||
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMnMCUwIwYD
|
||||
VR0RBBwwGoIYeC5iLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOC
|
||||
AQEAd6HusXqftFBpSUzivIY6icTZ95+wY+xIOsf1QOgyzZ/CDx4Tly+rgue2xSNT
|
||||
59FmnFvh8jW202K8TykamsAX20A8ArzubNoc/+soA752YEvrMmOgWjmH2arqTfqg
|
||||
zcfNdgUDESwnOoy123F+PkT3rRDXwINzCwftxhKbvmqhO6YENteqyWWmSZoMClsJ
|
||||
xtm+bmPN+m26k6zMMYWzIu2HIXI3CgqOmJltfyqea02Y58S1+XlajrcewPpC17xD
|
||||
r5a1sizecCFrmV0ssbK8wvEYo9Xs+PNj8Vhi1DUwGjtnjrYn/WQ6v/luMEEO7EMD
|
||||
b3BbEziS3Pqej2JyprUKqOjv1g==
|
||||
-----END CERTIFICATE-----
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:x.b.pinning2.example.com
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC5TCCAc+gAwIBAgIUNXGolw8M2HU/gP4dOSMD2bdTQ+MwCwYJKoZIhvcNAQEL
|
||||
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
|
||||
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
|
||||
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
|
||||
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
|
||||
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
|
||||
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
|
||||
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMn
|
||||
MCUwIwYDVR0RBBwwGoIYeC5iLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3
|
||||
DQEBCwOCAQEAevN1gW64H2kCjW5W4wbQFkJIITjcdEUsw+8GPzDuBDJCvgGirhOi
|
||||
ArBie8Bz+JlqzgNCXSe6pFVLoNfLosG5xksLwHljEit/7gFQ5twFazdg7dwPXs9Z
|
||||
MIV2iv3vHmKYTFTcjfw07UWy0rHHt6EH+zXqpZFtFkJHqSgngKxAHgQlvSKeyynM
|
||||
albu5YAX/hzJ7TyAVGxVN8uxnvYqPbLCy3wKf9ILFiDer6B9pE4Ii+dUyUbqVQFZ
|
||||
tY2ac1474nkcfj3uj5qbV0TTpd9EL9HMvixTnoUrT3bqkRX7orvL4gXpnJJyRjvC
|
||||
/LvTh/Vt1mYKkNLc/ruOj7WfUUC0SJIDzQ==
|
||||
-----END CERTIFICATE-----
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:x.b.pinning2.example.com
|
|
@ -1,147 +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/. */
|
||||
"use strict";
|
||||
|
||||
// The purpose of this test is to check that parsing of HPKP headers
|
||||
// is correct.
|
||||
|
||||
var profileDir = do_get_profile();
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
var gSSService = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
|
||||
function certFromFile(cert_name) {
|
||||
return constructCertFromFile("test_pinning_dynamic/" + cert_name + ".pem");
|
||||
}
|
||||
|
||||
function loadCert(cert_name, trust_string) {
|
||||
let cert_filename = "test_pinning_dynamic/" + cert_name + ".pem";
|
||||
addCertFromFile(certdb, cert_filename, trust_string);
|
||||
return constructCertFromFile(cert_filename);
|
||||
}
|
||||
|
||||
function checkFailParseInvalidPin(pinValue) {
|
||||
let sslStatus = new FakeSSLStatus(
|
||||
certFromFile('a.pinning2.example.com-pinningroot'));
|
||||
let uri = Services.io.newURI("https://a.pinning2.example.com", null, null);
|
||||
throws(() => {
|
||||
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
|
||||
pinValue, sslStatus, 0);
|
||||
}, /NS_ERROR_FAILURE/, `Invalid pin "${pinValue}" should be rejected`);
|
||||
}
|
||||
|
||||
function checkPassValidPin(pinValue, settingPin, expectedMaxAge) {
|
||||
let sslStatus = new FakeSSLStatus(
|
||||
certFromFile('a.pinning2.example.com-pinningroot'));
|
||||
let uri = Services.io.newURI("https://a.pinning2.example.com", null, null);
|
||||
let maxAge = {};
|
||||
|
||||
// setup preconditions for the test, if setting ensure there is no previous
|
||||
// state, if removing ensure there is a valid pin in place.
|
||||
if (settingPin) {
|
||||
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
} else {
|
||||
// add a known valid pin!
|
||||
let validPinValue = "max-age=5000;" + VALID_PIN1 + BACKUP_PIN1;
|
||||
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
|
||||
validPinValue, sslStatus, 0);
|
||||
}
|
||||
try {
|
||||
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
|
||||
pinValue, sslStatus, 0, maxAge);
|
||||
ok(true, "Valid pin should be accepted");
|
||||
} catch (e) {
|
||||
ok(false, "Valid pin should have been accepted");
|
||||
}
|
||||
|
||||
// check that maxAge was processed correctly
|
||||
if (settingPin && expectedMaxAge) {
|
||||
ok(maxAge.value == expectedMaxAge, `max-age value should be ${expectedMaxAge}`);
|
||||
}
|
||||
|
||||
// after processing ensure that the postconditions are true, if setting
|
||||
// the host must be pinned, if removing the host must not be pinned
|
||||
let hostIsPinned = gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
"a.pinning2.example.com", 0);
|
||||
if (settingPin) {
|
||||
ok(hostIsPinned, "Host should be considered pinned");
|
||||
} else {
|
||||
ok(!hostIsPinned, "Host should not be considered pinned");
|
||||
}
|
||||
}
|
||||
|
||||
function checkPassSettingPin(pinValue, expectedMaxAge) {
|
||||
return checkPassValidPin(pinValue, true, expectedMaxAge);
|
||||
}
|
||||
|
||||
function checkPassRemovingPin(pinValue) {
|
||||
return checkPassValidPin(pinValue, false);
|
||||
}
|
||||
|
||||
const MAX_MAX_AGE_SECONDS = 100000;
|
||||
const GOOD_MAX_AGE_SECONDS = 69403;
|
||||
const LONG_MAX_AGE_SECONDS = 2 * MAX_MAX_AGE_SECONDS;
|
||||
const NON_ISSUED_KEY_HASH1 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
||||
const NON_ISSUED_KEY_HASH2 = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ=";
|
||||
const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
|
||||
const MAX_AGE_ZERO = "max-age=0;";
|
||||
const VALID_PIN1 = `pin-sha256="${PINNING_ROOT_KEY_HASH}";`;
|
||||
const BACKUP_PIN1 = `pin-sha256="${NON_ISSUED_KEY_HASH1}";`;
|
||||
const BACKUP_PIN2 = `pin-sha256="${NON_ISSUED_KEY_HASH2}";`;
|
||||
const BROKEN_PIN1 = "pin-sha256=\"jdjsjsjs\";";
|
||||
const GOOD_MAX_AGE = `max-age=${GOOD_MAX_AGE_SECONDS};`;
|
||||
const LONG_MAX_AGE = `max-age=${LONG_MAX_AGE_SECONDS};`;
|
||||
const INCLUDE_SUBDOMAINS = "includeSubdomains;";
|
||||
const REPORT_URI = "report-uri=\"https://www.example.com/report/\";";
|
||||
const UNRECOGNIZED_DIRECTIVE = "unreconized-dir=12343;";
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
Services.prefs.setIntPref("security.cert_pinning.max_max_age_seconds", MAX_MAX_AGE_SECONDS);
|
||||
Services.prefs.setBoolPref("security.cert_pinning.process_headers_from_non_builtin_roots", true);
|
||||
|
||||
loadCert("pinningroot", "CTu,CTu,CTu");
|
||||
loadCert("badca", "CTu,CTu,CTu");
|
||||
|
||||
checkFailParseInvalidPin("max-age=INVALID");
|
||||
// check that incomplete headers are failure
|
||||
checkFailParseInvalidPin(GOOD_MAX_AGE);
|
||||
checkFailParseInvalidPin(VALID_PIN1);
|
||||
checkFailParseInvalidPin(REPORT_URI);
|
||||
checkFailParseInvalidPin(UNRECOGNIZED_DIRECTIVE);
|
||||
checkFailParseInvalidPin(VALID_PIN1 + BACKUP_PIN1);
|
||||
checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1);
|
||||
checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + BROKEN_PIN1);
|
||||
// next ensure a backup pin is present
|
||||
checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + VALID_PIN1);
|
||||
// next section ensure duplicate directives result in failure
|
||||
checkFailParseInvalidPin(GOOD_MAX_AGE + GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1);
|
||||
checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1 + INCLUDE_SUBDOMAINS + INCLUDE_SUBDOMAINS);
|
||||
checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1 + REPORT_URI + REPORT_URI);
|
||||
checkFailParseInvalidPin("thisisinvalidtest");
|
||||
checkFailParseInvalidPin("invalid" + GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1);
|
||||
|
||||
checkPassRemovingPin("max-age=0"); //test removal without terminating ';'
|
||||
checkPassRemovingPin(MAX_AGE_ZERO);
|
||||
checkPassRemovingPin(MAX_AGE_ZERO + VALID_PIN1);
|
||||
|
||||
checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1, GOOD_MAX_AGE_SECONDS);
|
||||
checkPassSettingPin(LONG_MAX_AGE + VALID_PIN1 + BACKUP_PIN1, MAX_MAX_AGE_SECONDS);
|
||||
|
||||
checkPassRemovingPin(VALID_PIN1 + MAX_AGE_ZERO + VALID_PIN1);
|
||||
checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1);
|
||||
checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN2);
|
||||
checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN2 + INCLUDE_SUBDOMAINS);
|
||||
checkPassSettingPin(VALID_PIN1 + GOOD_MAX_AGE + BACKUP_PIN2 + INCLUDE_SUBDOMAINS);
|
||||
checkPassSettingPin(VALID_PIN1 + GOOD_MAX_AGE + BACKUP_PIN2 + REPORT_URI + INCLUDE_SUBDOMAINS);
|
||||
checkPassSettingPin(INCLUDE_SUBDOMAINS + VALID_PIN1 + GOOD_MAX_AGE + BACKUP_PIN2);
|
||||
checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1 + UNRECOGNIZED_DIRECTIVE);
|
||||
|
||||
Services.prefs.clearUserPref("security.cert_pinning.hpkp.enabled");
|
||||
Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
|
||||
Services.prefs.clearUserPref("security.cert_pinning.max_max_age_seconds");
|
||||
Services.prefs.clearUserPref("security.cert_pinning.process_headers_from_non_builtin_roots");
|
||||
}
|
|
@ -1,34 +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/.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
// bug 961528: chart.apis.google.com doesn't handle https. Check that
|
||||
// it isn't considered HSTS (other example.apis.google.com hosts should be
|
||||
// HSTS as long as they're on the preload list, however).
|
||||
function run_test() {
|
||||
let SSService = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
"chart.apis.google.com", 0));
|
||||
ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
"CHART.APIS.GOOGLE.COM", 0));
|
||||
ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
"sub.chart.apis.google.com", 0));
|
||||
ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
"SUB.CHART.APIS.GOOGLE.COM", 0));
|
||||
ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
"example.apis.google.com", 0));
|
||||
ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
"EXAMPLE.APIS.GOOGLE.COM", 0));
|
||||
ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
"sub.example.apis.google.com", 0));
|
||||
ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
"SUB.EXAMPLE.APIS.GOOGLE.COM", 0));
|
||||
// also check isSecureURI
|
||||
let chartURI = Services.io.newURI("http://chart.apis.google.com", null, null);
|
||||
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, chartURI, 0));
|
||||
let otherURI = Services.io.newURI("http://other.apis.google.com", null, null);
|
||||
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, otherURI, 0));
|
||||
}
|
|
@ -26,7 +26,6 @@ support-files =
|
|||
test_ocsp_fetch_method/**
|
||||
test_ocsp_url/**
|
||||
test_onecrl/**
|
||||
test_pinning_dynamic/**
|
||||
test_signed_apps/**
|
||||
test_signed_dir/**
|
||||
test_startcom_wosign/**
|
||||
|
@ -111,13 +110,6 @@ run-sequentially = hardcoded ports
|
|||
[test_ocsp_url.js]
|
||||
run-sequentially = hardcoded ports
|
||||
[test_password_prompt.js]
|
||||
[test_pinning.js]
|
||||
run-sequentially = hardcoded ports
|
||||
# This test can take longer than 300 seconds on B2G emulator debug builds, so
|
||||
# give it enough time to finish. See bug 1081128.
|
||||
requesttimeoutfactor = 2
|
||||
[test_pinning_dynamic.js]
|
||||
[test_pinning_header_parsing.js]
|
||||
[test_sdr.js]
|
||||
[test_session_resumption.js]
|
||||
run-sequentially = hardcoded ports
|
||||
|
@ -137,7 +129,6 @@ skip-if = toolkit == 'android'
|
|||
[test_sss_savestate.js]
|
||||
[test_startcom_wosign.js]
|
||||
[test_sts_fqdn.js]
|
||||
[test_sts_holepunch.js]
|
||||
[test_sts_ipv4_ipv6.js]
|
||||
[test_sts_preloadlist_perwindowpb.js]
|
||||
[test_sts_preloadlist_selfdestruct.js]
|
||||
|
|
|
@ -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": []
|
||||
}
|
|
@ -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);
|
|
@ -218,8 +218,8 @@ this.ForgetAboutSite = {
|
|||
});
|
||||
}));
|
||||
|
||||
// HSTS and HPKP
|
||||
// TODO (bug 1290529): also remove HSTS/HPKP information for subdomains.
|
||||
// HSTS
|
||||
// TODO (bug 1290529): also remove HSTS information for subdomains.
|
||||
// Since we can't enumerate the information in the site security service
|
||||
// (bug 1115712), we can't implement this right now.
|
||||
promises.push(Task.spawn(function*() {
|
||||
|
@ -227,9 +227,8 @@ this.ForgetAboutSite = {
|
|||
getService(Ci.nsISiteSecurityService);
|
||||
let httpsURI = NetUtil.newURI("https://" + aDomain);
|
||||
sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, httpsURI, 0);
|
||||
sss.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, httpsURI, 0);
|
||||
}).catch(ex => {
|
||||
throw new Error("Exception thrown while clearing HSTS/HPKP: " + ex);
|
||||
throw new Error("Exception thrown while clearing HSTS: " + ex);
|
||||
}));
|
||||
|
||||
let ErrorCount = 0;
|
||||
|
|
Loading…
Reference in New Issue