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