mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 992096 - Implement Sub Resource Integrity [1/2]. r=baku,r=ckerschb
Code changes
This commit is contained in:
parent
26e2e34e08
commit
300306be73
1
AUTHORS
1
AUTHORS
@ -359,6 +359,7 @@ Florian Scholz <elchi3@elchi3.de>
|
||||
<flying@dom.natm.ru>
|
||||
France Telecom Research and Development
|
||||
Franck
|
||||
Francois Marier <francois@fmarier.org>
|
||||
Frank Tang <ftang@netscape.com>
|
||||
Frank Yan <fyan@mozilla.com>
|
||||
Franky Braem
|
||||
|
@ -4807,6 +4807,7 @@ var Utils = {
|
||||
case "CORS":
|
||||
case "Iframe Sandbox":
|
||||
case "Tracking Protection":
|
||||
case "Sub-resource Integrity":
|
||||
return CATEGORY_SECURITY;
|
||||
|
||||
default:
|
||||
|
@ -432,6 +432,7 @@ LOCAL_INCLUDES += [
|
||||
'/layout/svg',
|
||||
'/layout/xul',
|
||||
'/netwerk/base',
|
||||
'/security/manager/ssl',
|
||||
'/widget',
|
||||
'/xpcom/ds',
|
||||
]
|
||||
|
@ -51,6 +51,16 @@
|
||||
#include "nsParserConstants.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
|
||||
static PRLogModuleInfo*
|
||||
GetSriLog()
|
||||
{
|
||||
static PRLogModuleInfo *gSriPRLog;
|
||||
if (!gSriPRLog) {
|
||||
gSriPRLog = PR_NewLogModule("SRI");
|
||||
}
|
||||
return gSriPRLog;
|
||||
}
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
PRLogModuleInfo* gContentSinkLogModuleInfo;
|
||||
@ -750,12 +760,23 @@ nsContentSink::ProcessStyleLink(nsIContent* aElement,
|
||||
aElement->NodeType() == nsIDOMNode::PROCESSING_INSTRUCTION_NODE,
|
||||
"We only expect processing instructions here");
|
||||
|
||||
nsAutoString integrity;
|
||||
if (aElement) {
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity, integrity);
|
||||
}
|
||||
if (!integrity.IsEmpty()) {
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("nsContentSink::ProcessStyleLink, integrity=%s",
|
||||
NS_ConvertUTF16toUTF8(integrity).get()));
|
||||
}
|
||||
|
||||
// If this is a fragment parser, we don't want to observe.
|
||||
// We don't support CORS for processing instructions
|
||||
bool isAlternate;
|
||||
rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
|
||||
CORS_NONE, mDocument->GetReferrerPolicy(),
|
||||
mRunsToCompletion ? nullptr : this, &isAlternate);
|
||||
integrity, mRunsToCompletion ? nullptr : this,
|
||||
&isAlternate);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!isAlternate && !mRunsToCompletion) {
|
||||
|
@ -9876,7 +9876,8 @@ NS_IMPL_ISUPPORTS(StubCSSLoaderObserver, nsICSSLoaderObserver)
|
||||
void
|
||||
nsDocument::PreloadStyle(nsIURI* uri, const nsAString& charset,
|
||||
const nsAString& aCrossOriginAttr,
|
||||
const ReferrerPolicy aReferrerPolicy)
|
||||
const ReferrerPolicy aReferrerPolicy,
|
||||
const nsAString& aIntegrity)
|
||||
{
|
||||
// The CSSLoader will retain this object after we return.
|
||||
nsCOMPtr<nsICSSLoaderObserver> obs = new StubCSSLoaderObserver();
|
||||
@ -9886,7 +9887,7 @@ nsDocument::PreloadStyle(nsIURI* uri, const nsAString& charset,
|
||||
NS_LossyConvertUTF16toASCII(charset),
|
||||
obs,
|
||||
Element::StringToCORSMode(aCrossOriginAttr),
|
||||
aReferrerPolicy);
|
||||
aReferrerPolicy, aIntegrity);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -1147,7 +1147,8 @@ public:
|
||||
|
||||
virtual void PreloadStyle(nsIURI* uri, const nsAString& charset,
|
||||
const nsAString& aCrossOriginAttr,
|
||||
ReferrerPolicy aReferrerPolicy) override;
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const nsAString& aIntegrity) override;
|
||||
|
||||
virtual nsresult LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
|
||||
mozilla::CSSStyleSheet** sheet) override;
|
||||
|
@ -489,6 +489,7 @@ GK_ATOM(instanceOf, "instanceOf")
|
||||
GK_ATOM(int32, "int32")
|
||||
GK_ATOM(int64, "int64")
|
||||
GK_ATOM(integer, "integer")
|
||||
GK_ATOM(integrity, "integrity")
|
||||
GK_ATOM(intersection, "intersection")
|
||||
GK_ATOM(is, "is")
|
||||
GK_ATOM(iscontainer, "iscontainer")
|
||||
|
@ -152,8 +152,8 @@ typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0xbbce44c8, 0x22fe, 0x404f, \
|
||||
{ 0x9e, 0x71, 0x23, 0x1d, 0xf4, 0xcc, 0x8e, 0x34 } }
|
||||
{ 0x6d18ec0b, 0x1f68, 0x4ae6, \
|
||||
{ 0x8b, 0x3d, 0x8d, 0x7d, 0x8b, 0x8e, 0x28, 0xd4 } }
|
||||
|
||||
// Enum for requesting a particular type of document when creating a doc
|
||||
enum DocumentFlavor {
|
||||
@ -2023,7 +2023,8 @@ public:
|
||||
*/
|
||||
virtual void PreloadStyle(nsIURI* aURI, const nsAString& aCharset,
|
||||
const nsAString& aCrossOriginAttr,
|
||||
ReferrerPolicyEnum aReferrerPolicy) = 0;
|
||||
ReferrerPolicyEnum aReferrerPolicy,
|
||||
const nsAString& aIntegrity) = 0;
|
||||
|
||||
/**
|
||||
* Called by the chrome registry to load style sheets. Can be put
|
||||
|
@ -53,9 +53,21 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/SRICheck.h"
|
||||
#include "nsIScriptError.h"
|
||||
|
||||
static PRLogModuleInfo* gCspPRLog;
|
||||
|
||||
static PRLogModuleInfo*
|
||||
GetSriLog()
|
||||
{
|
||||
static PRLogModuleInfo *gSriPRLog;
|
||||
if (!gSriPRLog) {
|
||||
gSriPRLog = PR_NewLogModule("SRI");
|
||||
}
|
||||
return gSriPRLog;
|
||||
}
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
@ -606,7 +618,22 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
||||
|
||||
if (!request) {
|
||||
// no usable preload
|
||||
request = new nsScriptLoadRequest(aElement, version, ourCORSMode);
|
||||
|
||||
SRIMetadata sriMetadata;
|
||||
{
|
||||
nsAutoString integrity;
|
||||
scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity,
|
||||
integrity);
|
||||
if (!integrity.IsEmpty()) {
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("nsScriptLoader::ProcessScriptElement, integrity=%s",
|
||||
NS_ConvertUTF16toUTF8(integrity).get()));
|
||||
SRICheck::IntegrityMetadata(integrity, mDocument, &sriMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
request = new nsScriptLoadRequest(aElement, version, ourCORSMode,
|
||||
sriMetadata);
|
||||
request->mURI = scriptURI;
|
||||
request->mIsInline = false;
|
||||
request->mLoading = true;
|
||||
@ -720,7 +747,8 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
||||
}
|
||||
|
||||
// Inline scripts ignore ther CORS mode and are always CORS_NONE
|
||||
request = new nsScriptLoadRequest(aElement, version, CORS_NONE);
|
||||
request = new nsScriptLoadRequest(aElement, version, CORS_NONE,
|
||||
SRIMetadata()); // SRI doesn't apply
|
||||
request->mJSVersion = version;
|
||||
request->mLoading = false;
|
||||
request->mIsInline = true;
|
||||
@ -1408,8 +1436,15 @@ nsScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
NS_ASSERTION(request, "null request in stream complete handler");
|
||||
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = PrepareLoadedRequest(request, aLoader, aStatus, aStringLen,
|
||||
aString);
|
||||
nsresult rv = NS_ERROR_SRI_CORRUPT;
|
||||
if (request->mIntegrity.IsEmpty() ||
|
||||
NS_SUCCEEDED(SRICheck::VerifyIntegrity(request->mIntegrity,
|
||||
request->mURI,
|
||||
request->mCORSMode, aStringLen,
|
||||
aString, mDocument))) {
|
||||
rv = PrepareLoadedRequest(request, aLoader, aStatus, aStringLen, aString);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
/*
|
||||
* Handle script not loading error because source was a tracking URL.
|
||||
@ -1603,6 +1638,7 @@ void
|
||||
nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
|
||||
const nsAString &aType,
|
||||
const nsAString &aCrossOrigin,
|
||||
const nsAString& aIntegrity,
|
||||
bool aScriptFromHead,
|
||||
const mozilla::net::ReferrerPolicy aReferrerPolicy)
|
||||
{
|
||||
@ -1611,9 +1647,18 @@ nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
|
||||
return;
|
||||
}
|
||||
|
||||
SRIMetadata sriMetadata;
|
||||
if (!aIntegrity.IsEmpty()) {
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("nsScriptLoader::PreloadURI, integrity=%s",
|
||||
NS_ConvertUTF16toUTF8(aIntegrity).get()));
|
||||
SRICheck::IntegrityMetadata(aIntegrity, mDocument, &sriMetadata);
|
||||
}
|
||||
|
||||
nsRefPtr<nsScriptLoadRequest> request =
|
||||
new nsScriptLoadRequest(nullptr, 0,
|
||||
Element::StringToCORSMode(aCrossOrigin));
|
||||
Element::StringToCORSMode(aCrossOrigin),
|
||||
sriMetadata);
|
||||
request->mURI = aURI;
|
||||
request->mIsInline = false;
|
||||
request->mLoading = true;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "mozilla/dom/SRIMetadata.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
|
||||
@ -56,7 +57,8 @@ class nsScriptLoadRequest final : public nsISupports,
|
||||
public:
|
||||
nsScriptLoadRequest(nsIScriptElement* aElement,
|
||||
uint32_t aVersion,
|
||||
mozilla::CORSMode aCORSMode)
|
||||
mozilla::CORSMode aCORSMode,
|
||||
const mozilla::dom::SRIMetadata &aIntegrity)
|
||||
: mElement(aElement),
|
||||
mLoading(true),
|
||||
mIsInline(true),
|
||||
@ -71,6 +73,7 @@ public:
|
||||
mJSVersion(aVersion),
|
||||
mLineNo(1),
|
||||
mCORSMode(aCORSMode),
|
||||
mIntegrity(aIntegrity),
|
||||
mReferrerPolicy(mozilla::net::RP_Default)
|
||||
{
|
||||
}
|
||||
@ -122,6 +125,7 @@ public:
|
||||
nsAutoCString mURL; // Keep the URI's filename alive during off thread parsing.
|
||||
int32_t mLineNo;
|
||||
const mozilla::CORSMode mCORSMode;
|
||||
const mozilla::dom::SRIMetadata mIntegrity;
|
||||
mozilla::net::ReferrerPolicy mReferrerPolicy;
|
||||
};
|
||||
|
||||
@ -367,11 +371,13 @@ public:
|
||||
* @param aType The type parameter for the script.
|
||||
* @param aCrossOrigin The crossorigin attribute for the script.
|
||||
* Void if not present.
|
||||
* @param aIntegrity The expect hash url, if avail, of the request
|
||||
* @param aScriptFromHead Whether or not the script was a child of head
|
||||
*/
|
||||
virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
|
||||
const nsAString &aType,
|
||||
const nsAString &aCrossOrigin,
|
||||
const nsAString& aIntegrity,
|
||||
bool aScriptFromHead,
|
||||
const mozilla::net::ReferrerPolicy aReferrerPolicy);
|
||||
|
||||
|
@ -421,13 +421,21 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
|
||||
scopeElement, aObserver, &doneLoading, &isAlternate);
|
||||
}
|
||||
else {
|
||||
nsAutoString integrity;
|
||||
thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity, integrity);
|
||||
if (!integrity.IsEmpty()) {
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("nsStyleLinkElement::DoUpdateStyleSheet, integrity=%s",
|
||||
NS_ConvertUTF16toUTF8(integrity).get()));
|
||||
}
|
||||
|
||||
// XXXbz clone the URI here to work around content policies modifying URIs.
|
||||
nsCOMPtr<nsIURI> clonedURI;
|
||||
uri->Clone(getter_AddRefs(clonedURI));
|
||||
NS_ENSURE_TRUE(clonedURI, NS_ERROR_OUT_OF_MEMORY);
|
||||
rv = doc->CSSLoader()->
|
||||
LoadStyleLink(thisContent, clonedURI, title, media, isAlternate,
|
||||
GetCORSMode(), doc->GetReferrerPolicy(),
|
||||
GetCORSMode(), doc->GetReferrerPolicy(), integrity,
|
||||
aObserver, &isAlternate);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Don't propagate LoadStyleLink() errors further than this, since some
|
||||
|
@ -214,6 +214,11 @@ HTMLLinkElement::ParseAttribute(int32_t aNamespaceID,
|
||||
aResult.ParseAtomArray(aValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::integrity) {
|
||||
aResult.ParseStringOrAtom(aValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
|
@ -143,6 +143,14 @@ public:
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::target, aTarget, aRv);
|
||||
}
|
||||
void GetIntegrity(nsAString& aIntegrity) const
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::integrity, aIntegrity);
|
||||
}
|
||||
void SetIntegrity(const nsAString& aIntegrity, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::integrity, aIntegrity, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDocument> GetImport();
|
||||
already_AddRefed<ImportLoader> GetImportLoader()
|
||||
|
@ -75,10 +75,16 @@ HTMLScriptElement::ParseAttribute(int32_t aNamespaceID,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None &&
|
||||
aAttribute == nsGkAtoms::crossorigin) {
|
||||
ParseCORSValue(aValue, aResult);
|
||||
return true;
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::crossorigin) {
|
||||
ParseCORSValue(aValue, aResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::integrity) {
|
||||
aResult.ParseStringOrAtom(aValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
|
@ -79,6 +79,14 @@ public:
|
||||
{
|
||||
SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError);
|
||||
}
|
||||
void GetIntegrity(nsAString& aIntegrity)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::integrity, aIntegrity);
|
||||
}
|
||||
void SetIntegrity(const nsAString& aIntegrity, ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::integrity, aIntegrity, rv);
|
||||
}
|
||||
bool Async();
|
||||
void SetAsync(bool aValue, ErrorResult& rv);
|
||||
|
||||
|
@ -53,6 +53,21 @@ LoadingMixedDisplayContent2=Loading mixed (insecure) display content "%1$S" on a
|
||||
# LOCALIZATION NOTE: Do not translate "allow-scripts", "allow-same-origin", "sandbox" or "iframe"
|
||||
BothAllowScriptsAndSameOriginPresent=An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can remove its sandboxing.
|
||||
|
||||
# Sub-Resource Integrity
|
||||
# LOCALIZATION NOTE: Do not translate "script" or "integrity"
|
||||
MalformedIntegrityURI=The script element has a malformed URI in its integrity attribute: "%1$S". The correct format is "<hash algorithm>-<hash value>".
|
||||
# LOCALIZATION NOTE: Do not translate "integrity"
|
||||
InvalidIntegrityLength=The hash contained in the integrity attribute has the wrong length.
|
||||
# LOCALIZATION NOTE: Do not translate "integrity"
|
||||
InvalidIntegrityBase64=The hash contained in the integrity attribute could not be decoded.
|
||||
# LOCALIZATION NOTE: Do not translate "integrity"
|
||||
IntegrityMismatch=None of the "%1$S" hashes in the integrity attribute match the content of the subresource.
|
||||
IneligibleResource="%1$S" is not eligible for integrity checks since it's neither CORS-enabled nor same-origin.
|
||||
# LOCALIZATION NOTE: Do not translate "integrity"
|
||||
UnsupportedHashAlg=Unsupported hash algorithm in the integrity attribute: "%1$S"
|
||||
# LOCALIZATION NOTE: Do not translate "integrity"
|
||||
NoValidMetadata=The integrity attribute does not contain any valid metadata.
|
||||
|
||||
# LOCALIZATION NOTE: Do not translate "SSL 3.0".
|
||||
WeakProtocolVersionWarning=This site uses the protocol SSL 3.0 for encryption, which is deprecated and insecure.
|
||||
# LOCALIZATION NOTE: Do not translate "RC4".
|
||||
|
295
dom/security/SRICheck.cpp
Normal file
295
dom/security/SRICheck.cpp
Normal file
@ -0,0 +1,295 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "SRICheck.h"
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsWhitespaceTokenizer.h"
|
||||
|
||||
static PRLogModuleInfo*
|
||||
GetSriLog()
|
||||
{
|
||||
static PRLogModuleInfo *gSriPRLog;
|
||||
if (!gSriPRLog) {
|
||||
gSriPRLog = PR_NewLogModule("SRI");
|
||||
}
|
||||
return gSriPRLog;
|
||||
}
|
||||
|
||||
#define SRILOG(args) MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug, args)
|
||||
#define SRIERROR(args) MOZ_LOG(GetSriLog(), mozilla::LogLevel::Error, args)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* Returns whether or not the sub-resource about to be loaded is eligible
|
||||
* for integrity checks. If it's not, the checks will be skipped and the
|
||||
* sub-resource will be loaded.
|
||||
*/
|
||||
static nsresult
|
||||
IsEligible(nsIURI* aRequestURI, const CORSMode aCORSMode,
|
||||
const nsIDocument* aDocument)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRequestURI);
|
||||
NS_ENSURE_ARG_POINTER(aDocument);
|
||||
|
||||
nsAutoCString requestSpec;
|
||||
nsresult rv = aRequestURI->GetSpec(requestSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ConvertUTF8toUTF16 requestSpecUTF16(requestSpec);
|
||||
|
||||
// Was the sub-resource loaded via CORS?
|
||||
if (aCORSMode != CORS_NONE) {
|
||||
SRILOG(("SRICheck::IsEligible, CORS mode"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Is the sub-resource same-origin?
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
if (NS_SUCCEEDED(ssm->CheckSameOriginURI(aDocument->GetDocumentURI(),
|
||||
aRequestURI, false))) {
|
||||
SRILOG(("SRICheck::IsEligible, same-origin"));
|
||||
return NS_OK;
|
||||
}
|
||||
if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
nsAutoCString documentURI;
|
||||
aDocument->GetDocumentURI()->GetAsciiSpec(documentURI);
|
||||
// documentURI will be empty if GetAsciiSpec failed
|
||||
SRILOG(("SRICheck::IsEligible, NOT same origin: documentURI=%s; requestURI=%s",
|
||||
documentURI.get(), requestSpec.get()));
|
||||
}
|
||||
|
||||
const char16_t* params[] = { requestSpecUTF16.get() };
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
|
||||
NS_LITERAL_CSTRING("Sub-resource Integrity"),
|
||||
aDocument,
|
||||
nsContentUtils::eSECURITY_PROPERTIES,
|
||||
"IneligibleResource",
|
||||
params, ArrayLength(params));
|
||||
return NS_ERROR_SRI_NOT_ELIGIBLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the hash of a sub-resource and compare it with the expected
|
||||
* value.
|
||||
*/
|
||||
static nsresult
|
||||
VerifyHash(const SRIMetadata& aMetadata, uint32_t aHashIndex,
|
||||
uint32_t aStringLen, const uint8_t* aString,
|
||||
const nsIDocument* aDocument)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aString);
|
||||
NS_ENSURE_ARG_POINTER(aDocument);
|
||||
|
||||
nsAutoCString base64Hash;
|
||||
aMetadata.GetHash(aHashIndex, &base64Hash);
|
||||
SRILOG(("SRICheck::VerifyHash, hash[%u]=%s", aHashIndex, base64Hash.get()));
|
||||
|
||||
nsAutoCString binaryHash;
|
||||
if (NS_WARN_IF(NS_FAILED(Base64Decode(base64Hash, binaryHash)))) {
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
|
||||
NS_LITERAL_CSTRING("Sub-resource Integrity"),
|
||||
aDocument,
|
||||
nsContentUtils::eSECURITY_PROPERTIES,
|
||||
"InvalidIntegrityBase64");
|
||||
return NS_ERROR_SRI_CORRUPT;
|
||||
}
|
||||
|
||||
uint32_t hashLength;
|
||||
int8_t hashType;
|
||||
aMetadata.GetHashType(&hashType, &hashLength);
|
||||
if (binaryHash.Length() != hashLength) {
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
|
||||
NS_LITERAL_CSTRING("Sub-resource Integrity"),
|
||||
aDocument,
|
||||
nsContentUtils::eSECURITY_PROPERTIES,
|
||||
"InvalidIntegrityLength");
|
||||
return NS_ERROR_SRI_CORRUPT;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsICryptoHash> cryptoHash =
|
||||
do_CreateInstance("@mozilla.org/security/hash;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = cryptoHash->Init(hashType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = cryptoHash->Update(aString, aStringLen);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString computedHash;
|
||||
rv = cryptoHash->Finish(false, computedHash);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!binaryHash.Equals(computedHash)) {
|
||||
SRILOG(("SRICheck::VerifyHash, hash[%u] did not match", aHashIndex));
|
||||
return NS_ERROR_SRI_CORRUPT;
|
||||
}
|
||||
|
||||
SRILOG(("SRICheck::VerifyHash, hash[%u] verified successfully", aHashIndex));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
SRICheck::IntegrityMetadata(const nsAString& aMetadataList,
|
||||
const nsIDocument* aDocument,
|
||||
SRIMetadata* outMetadata)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(outMetadata);
|
||||
NS_ENSURE_ARG_POINTER(aDocument);
|
||||
MOZ_ASSERT(outMetadata->IsEmpty()); // caller must pass empty metadata
|
||||
|
||||
if (!Preferences::GetBool("security.sri.enable", false)) {
|
||||
SRILOG(("SRICheck::IntegrityMetadata, sri is disabled (pref)"));
|
||||
return NS_ERROR_SRI_DISABLED;
|
||||
}
|
||||
|
||||
// put a reasonable bound on the length of the metadata
|
||||
NS_ConvertUTF16toUTF8 metadataList(aMetadataList);
|
||||
if (metadataList.Length() > SRICheck::MAX_METADATA_LENGTH) {
|
||||
metadataList.Truncate(SRICheck::MAX_METADATA_LENGTH);
|
||||
}
|
||||
MOZ_ASSERT(metadataList.Length() <= aMetadataList.Length());
|
||||
|
||||
// the integrity attribute is a list of whitespace-separated hashes
|
||||
// and options so we need to look at them one by one and pick the
|
||||
// strongest (valid) one
|
||||
nsCWhitespaceTokenizer tokenizer(metadataList);
|
||||
nsAutoCString token;
|
||||
for (uint32_t i=0; tokenizer.hasMoreTokens() &&
|
||||
i < SRICheck::MAX_METADATA_TOKENS; ++i) {
|
||||
token = tokenizer.nextToken();
|
||||
|
||||
SRIMetadata metadata(token);
|
||||
if (metadata.IsMalformed()) {
|
||||
NS_ConvertUTF8toUTF16 tokenUTF16(token);
|
||||
const char16_t* params[] = { tokenUTF16.get() };
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("Sub-resource Integrity"),
|
||||
aDocument,
|
||||
nsContentUtils::eSECURITY_PROPERTIES,
|
||||
"MalformedIntegrityURI",
|
||||
params, ArrayLength(params));
|
||||
} else if (!metadata.IsAlgorithmSupported()) {
|
||||
nsAutoCString alg;
|
||||
metadata.GetAlgorithm(&alg);
|
||||
NS_ConvertUTF8toUTF16 algUTF16(alg);
|
||||
const char16_t* params[] = { algUTF16.get() };
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("Sub-resource Integrity"),
|
||||
aDocument,
|
||||
nsContentUtils::eSECURITY_PROPERTIES,
|
||||
"UnsupportedHashAlg",
|
||||
params, ArrayLength(params));
|
||||
}
|
||||
|
||||
nsAutoCString alg1, alg2;
|
||||
if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
outMetadata->GetAlgorithm(&alg1);
|
||||
metadata.GetAlgorithm(&alg2);
|
||||
}
|
||||
if (*outMetadata == metadata) {
|
||||
SRILOG(("SRICheck::IntegrityMetadata, alg '%s' is the same as '%s'",
|
||||
alg1.get(), alg2.get()));
|
||||
*outMetadata += metadata; // add new hash to strongest metadata
|
||||
} else if (*outMetadata < metadata) {
|
||||
SRILOG(("SRICheck::IntegrityMetadata, alg '%s' is weaker than '%s'",
|
||||
alg1.get(), alg2.get()));
|
||||
*outMetadata = metadata; // replace strongest metadata with current
|
||||
}
|
||||
}
|
||||
|
||||
if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
if (outMetadata->IsValid()) {
|
||||
nsAutoCString alg;
|
||||
outMetadata->GetAlgorithm(&alg);
|
||||
SRILOG(("SRICheck::IntegrityMetadata, using a '%s' hash", alg.get()));
|
||||
} else if (outMetadata->IsEmpty()) {
|
||||
SRILOG(("SRICheck::IntegrityMetadata, no metadata"));
|
||||
} else {
|
||||
SRILOG(("SRICheck::IntegrityMetadata, no valid metadata found"));
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata,
|
||||
nsIURI* aRequestURI,
|
||||
const CORSMode aCORSMode,
|
||||
const nsAString& aString,
|
||||
const nsIDocument* aDocument)
|
||||
{
|
||||
NS_ConvertUTF16toUTF8 utf8Hash(aString);
|
||||
return VerifyIntegrity(aMetadata, aRequestURI, aCORSMode, utf8Hash.Length(),
|
||||
(uint8_t*)utf8Hash.get(), aDocument);
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata,
|
||||
nsIURI* aRequestURI,
|
||||
const CORSMode aCORSMode,
|
||||
uint32_t aStringLen,
|
||||
const uint8_t* aString,
|
||||
const nsIDocument* aDocument)
|
||||
{
|
||||
if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
nsAutoCString requestURL;
|
||||
aRequestURI->GetAsciiSpec(requestURL);
|
||||
// requestURL will be empty if GetAsciiSpec fails
|
||||
SRILOG(("SRICheck::VerifyIntegrity, url=%s (length=%u)",
|
||||
requestURL.get(), aStringLen));
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!aMetadata.IsEmpty()); // should be checked by caller
|
||||
|
||||
// IntegrityMetadata() checks this and returns "no metadata" if
|
||||
// it's disabled so we should never make it this far
|
||||
MOZ_ASSERT(Preferences::GetBool("security.sri.enable", false));
|
||||
|
||||
if (NS_FAILED(IsEligible(aRequestURI, aCORSMode, aDocument))) {
|
||||
return NS_OK; // ignore non-CORS resources for forward-compatibility
|
||||
}
|
||||
if (!aMetadata.IsValid()) {
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("Sub-resource Integrity"),
|
||||
aDocument,
|
||||
nsContentUtils::eSECURITY_PROPERTIES,
|
||||
"NoValidMetadata");
|
||||
return NS_OK; // ignore invalid metadata for forward-compatibility
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aMetadata.HashCount(); i++) {
|
||||
if (NS_SUCCEEDED(VerifyHash(aMetadata, i, aStringLen,
|
||||
aString, aDocument))) {
|
||||
return NS_OK; // stop at the first valid hash
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoCString alg;
|
||||
aMetadata.GetAlgorithm(&alg);
|
||||
NS_ConvertUTF8toUTF16 algUTF16(alg);
|
||||
const char16_t* params[] = { algUTF16.get() };
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
|
||||
NS_LITERAL_CSTRING("Sub-resource Integrity"),
|
||||
aDocument,
|
||||
nsContentUtils::eSECURITY_PROPERTIES,
|
||||
"IntegrityMismatch",
|
||||
params, ArrayLength(params));
|
||||
return NS_ERROR_SRI_CORRUPT;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
62
dom/security/SRICheck.h
Normal file
62
dom/security/SRICheck.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 mozilla_dom_SRICheck_h
|
||||
#define mozilla_dom_SRICheck_h
|
||||
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "SRIMetadata.h"
|
||||
|
||||
class nsIDocument;
|
||||
class nsIHttpChannel;
|
||||
class nsIScriptSecurityManager;
|
||||
class nsIStreamLoader;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SRICheck final
|
||||
{
|
||||
public:
|
||||
static const uint32_t MAX_METADATA_LENGTH = 24*1024;
|
||||
static const uint32_t MAX_METADATA_TOKENS = 512;
|
||||
|
||||
/**
|
||||
* Parse the multiple hashes specified in the integrity attribute and
|
||||
* return the strongest supported hash.
|
||||
*/
|
||||
static nsresult IntegrityMetadata(const nsAString& aMetadataList,
|
||||
const nsIDocument* aDocument,
|
||||
SRIMetadata* outMetadata);
|
||||
|
||||
/**
|
||||
* Process the integrity attribute of the element. A result of false
|
||||
* must prevent the resource from loading.
|
||||
*/
|
||||
static nsresult VerifyIntegrity(const SRIMetadata& aMetadata,
|
||||
nsIURI* aRequestURI,
|
||||
const CORSMode aCORSMode,
|
||||
const nsAString& aString,
|
||||
const nsIDocument* aDocument);
|
||||
|
||||
/**
|
||||
* Process the integrity attribute of the element. A result of false
|
||||
* must prevent the resource from loading.
|
||||
*/
|
||||
static nsresult VerifyIntegrity(const SRIMetadata& aMetadata,
|
||||
nsIURI* aRequestURI,
|
||||
const CORSMode aCORSMode,
|
||||
uint32_t aStringLen,
|
||||
const uint8_t* aString,
|
||||
const nsIDocument* aDocument);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_SRICheck_h
|
172
dom/security/SRIMetadata.cpp
Normal file
172
dom/security/SRIMetadata.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "SRIMetadata.h"
|
||||
|
||||
#include "hasht.h"
|
||||
#include "mozilla/dom/URLSearchParams.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsICryptoHash.h"
|
||||
|
||||
static PRLogModuleInfo*
|
||||
GetSriMetadataLog()
|
||||
{
|
||||
static PRLogModuleInfo *gSriMetadataPRLog;
|
||||
if (!gSriMetadataPRLog) {
|
||||
gSriMetadataPRLog = PR_NewLogModule("SRIMetadata");
|
||||
}
|
||||
return gSriMetadataPRLog;
|
||||
}
|
||||
|
||||
#define SRIMETADATALOG(args) MOZ_LOG(GetSriMetadataLog(), mozilla::LogLevel::Debug, args)
|
||||
#define SRIMETADATAERROR(args) MOZ_LOG(GetSriMetadataLog(), mozilla::LogLevel::Error, args)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
SRIMetadata::SRIMetadata(const nsACString& aToken)
|
||||
: mAlgorithmType(SRIMetadata::UNKNOWN_ALGORITHM), mEmpty(false)
|
||||
{
|
||||
MOZ_ASSERT(!aToken.IsEmpty()); // callers should check this first
|
||||
|
||||
SRIMETADATALOG(("SRIMetadata::SRIMetadata, aToken='%s'",
|
||||
PromiseFlatCString(aToken).get()));
|
||||
|
||||
int32_t hyphen = aToken.FindChar('-');
|
||||
if (hyphen == -1) {
|
||||
SRIMETADATAERROR(("SRIMetadata::SRIMetadata, invalid (no hyphen)"));
|
||||
return; // invalid metadata
|
||||
}
|
||||
|
||||
// split the token into its components
|
||||
mAlgorithm = Substring(aToken, 0, hyphen);
|
||||
uint32_t hashStart = hyphen + 1;
|
||||
if (hashStart >= aToken.Length()) {
|
||||
SRIMETADATAERROR(("SRIMetadata::SRIMetadata, invalid (missing digest)"));
|
||||
return; // invalid metadata
|
||||
}
|
||||
int32_t question = aToken.FindChar('?');
|
||||
if (question == -1) {
|
||||
mHashes.AppendElement(Substring(aToken, hashStart,
|
||||
aToken.Length() - hashStart));
|
||||
} else {
|
||||
MOZ_ASSERT(question > 0);
|
||||
if (static_cast<uint32_t>(question) <= hashStart) {
|
||||
SRIMETADATAERROR(("SRIMetadata::SRIMetadata, invalid (options w/o digest)"));
|
||||
return; // invalid metadata
|
||||
}
|
||||
mHashes.AppendElement(Substring(aToken, hashStart,
|
||||
question - hashStart));
|
||||
}
|
||||
|
||||
if (mAlgorithm.EqualsLiteral("sha256")) {
|
||||
mAlgorithmType = nsICryptoHash::SHA256;
|
||||
} else if (mAlgorithm.EqualsLiteral("sha384")) {
|
||||
mAlgorithmType = nsICryptoHash::SHA384;
|
||||
} else if (mAlgorithm.EqualsLiteral("sha512")) {
|
||||
mAlgorithmType = nsICryptoHash::SHA512;
|
||||
}
|
||||
|
||||
SRIMETADATALOG(("SRIMetadata::SRIMetadata, hash='%s'; alg='%s'",
|
||||
mHashes[0].get(), mAlgorithm.get()));
|
||||
}
|
||||
|
||||
bool
|
||||
SRIMetadata::operator<(const SRIMetadata& aOther) const
|
||||
{
|
||||
static_assert(nsICryptoHash::SHA256 < nsICryptoHash::SHA384,
|
||||
"We rely on the order indicating relative alg strength");
|
||||
static_assert(nsICryptoHash::SHA384 < nsICryptoHash::SHA512,
|
||||
"We rely on the order indicating relative alg strength");
|
||||
MOZ_ASSERT(mAlgorithmType == SRIMetadata::UNKNOWN_ALGORITHM ||
|
||||
mAlgorithmType == nsICryptoHash::SHA256 ||
|
||||
mAlgorithmType == nsICryptoHash::SHA384 ||
|
||||
mAlgorithmType == nsICryptoHash::SHA512);
|
||||
MOZ_ASSERT(aOther.mAlgorithmType == SRIMetadata::UNKNOWN_ALGORITHM ||
|
||||
aOther.mAlgorithmType == nsICryptoHash::SHA256 ||
|
||||
aOther.mAlgorithmType == nsICryptoHash::SHA384 ||
|
||||
aOther.mAlgorithmType == nsICryptoHash::SHA512);
|
||||
|
||||
if (mEmpty) {
|
||||
SRIMETADATALOG(("SRIMetadata::operator<, first metadata is empty"));
|
||||
return true; // anything beats the empty metadata (incl. invalid ones)
|
||||
}
|
||||
|
||||
SRIMETADATALOG(("SRIMetadata::operator<, alg1='%d'; alg2='%d'",
|
||||
mAlgorithmType, aOther.mAlgorithmType));
|
||||
return (mAlgorithmType < aOther.mAlgorithmType);
|
||||
}
|
||||
|
||||
bool
|
||||
SRIMetadata::operator>(const SRIMetadata& aOther) const
|
||||
{
|
||||
MOZ_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
SRIMetadata&
|
||||
SRIMetadata::operator+=(const SRIMetadata& aOther)
|
||||
{
|
||||
MOZ_ASSERT(!aOther.IsEmpty() && !IsEmpty());
|
||||
MOZ_ASSERT(aOther.IsValid() && IsValid());
|
||||
MOZ_ASSERT(mAlgorithmType == aOther.mAlgorithmType);
|
||||
|
||||
// We only pull in the first element of the other metadata
|
||||
MOZ_ASSERT(aOther.mHashes.Length() == 1);
|
||||
if (mHashes.Length() < SRIMetadata::MAX_ALTERNATE_HASHES) {
|
||||
SRIMETADATALOG(("SRIMetadata::operator+=, appending another '%s' hash (new length=%d)",
|
||||
mAlgorithm.get(), mHashes.Length()));
|
||||
mHashes.AppendElement(aOther.mHashes[0]);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mHashes.Length() > 1);
|
||||
MOZ_ASSERT(mHashes.Length() <= SRIMetadata::MAX_ALTERNATE_HASHES);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
SRIMetadata::operator==(const SRIMetadata& aOther) const
|
||||
{
|
||||
if (IsEmpty() || !IsValid()) {
|
||||
return false;
|
||||
}
|
||||
return mAlgorithmType == aOther.mAlgorithmType;
|
||||
}
|
||||
|
||||
void
|
||||
SRIMetadata::GetHash(uint32_t aIndex, nsCString* outHash) const
|
||||
{
|
||||
MOZ_ASSERT(aIndex < SRIMetadata::MAX_ALTERNATE_HASHES);
|
||||
if (NS_WARN_IF(aIndex >= mHashes.Length())) {
|
||||
*outHash = nullptr;
|
||||
return;
|
||||
}
|
||||
*outHash = mHashes[aIndex];
|
||||
}
|
||||
|
||||
void
|
||||
SRIMetadata::GetHashType(int8_t* outType, uint32_t* outLength) const
|
||||
{
|
||||
// these constants are defined in security/nss/lib/util/hasht.h and
|
||||
// netwerk/base/public/nsICryptoHash.idl
|
||||
switch (mAlgorithmType) {
|
||||
case nsICryptoHash::SHA256:
|
||||
*outLength = SHA256_LENGTH;
|
||||
break;
|
||||
case nsICryptoHash::SHA384:
|
||||
*outLength = SHA384_LENGTH;
|
||||
break;
|
||||
case nsICryptoHash::SHA512:
|
||||
*outLength = SHA512_LENGTH;
|
||||
break;
|
||||
default:
|
||||
*outLength = 0;
|
||||
}
|
||||
*outType = mAlgorithmType;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
74
dom/security/SRIMetadata.h
Normal file
74
dom/security/SRIMetadata.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 mozilla_dom_SRIMetadata_h
|
||||
#define mozilla_dom_SRIMetadata_h
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SRIMetadata final
|
||||
{
|
||||
public:
|
||||
static const uint32_t MAX_ALTERNATE_HASHES = 256;
|
||||
static const int8_t UNKNOWN_ALGORITHM = -1;
|
||||
|
||||
/**
|
||||
* Create an empty metadata object.
|
||||
*/
|
||||
SRIMetadata() : mAlgorithmType(UNKNOWN_ALGORITHM), mEmpty(true) {}
|
||||
|
||||
/**
|
||||
* Split a string token into the components of an SRI metadata
|
||||
* attribute.
|
||||
*/
|
||||
explicit SRIMetadata(const nsACString& aToken);
|
||||
|
||||
/**
|
||||
* Returns true when this object's hash algorithm is weaker than the
|
||||
* other object's hash algorithm.
|
||||
*/
|
||||
bool operator<(const SRIMetadata& aOther) const;
|
||||
|
||||
/**
|
||||
* Not implemented. Should not be used.
|
||||
*/
|
||||
bool operator>(const SRIMetadata& aOther) const;
|
||||
|
||||
/**
|
||||
* Add another metadata's hash to this one.
|
||||
*/
|
||||
SRIMetadata& operator+=(const SRIMetadata& aOther);
|
||||
|
||||
/**
|
||||
* Returns true when the two metadata use the same hash algorithm.
|
||||
*/
|
||||
bool operator==(const SRIMetadata& aOther) const;
|
||||
|
||||
bool IsEmpty() const { return mEmpty; }
|
||||
bool IsMalformed() const { return mHashes.IsEmpty() || mAlgorithm.IsEmpty(); }
|
||||
bool IsAlgorithmSupported() const { return mAlgorithmType != UNKNOWN_ALGORITHM; }
|
||||
bool IsValid() const { return !IsMalformed() && IsAlgorithmSupported(); }
|
||||
|
||||
uint32_t HashCount() const { return mHashes.Length(); }
|
||||
void GetHash(uint32_t aIndex, nsCString* outHash) const;
|
||||
void GetAlgorithm(nsCString* outAlg) const { *outAlg = mAlgorithm; }
|
||||
void GetHashType(int8_t* outType, uint32_t* outLength) const;
|
||||
|
||||
private:
|
||||
nsTArray<nsCString> mHashes;
|
||||
nsCString mAlgorithm;
|
||||
int8_t mAlgorithmType;
|
||||
bool mEmpty;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_SRIMetadata_h
|
@ -12,6 +12,8 @@ EXPORTS.mozilla.dom += [
|
||||
'nsCSPService.h',
|
||||
'nsCSPUtils.h',
|
||||
'nsMixedContentBlocker.h',
|
||||
'SRICheck.h',
|
||||
'SRIMetadata.h',
|
||||
]
|
||||
|
||||
EXPORTS += [
|
||||
@ -27,6 +29,8 @@ UNIFIED_SOURCES += [
|
||||
'nsCSPService.cpp',
|
||||
'nsCSPUtils.cpp',
|
||||
'nsMixedContentBlocker.cpp',
|
||||
'SRICheck.cpp',
|
||||
'SRIMetadata.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -48,3 +48,8 @@ partial interface HTMLLinkElement {
|
||||
readonly attribute Document? import;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webappsec/specs/subresourceintegrity/#htmllinkelement-1
|
||||
partial interface HTMLLinkElement {
|
||||
[SetterThrows]
|
||||
attribute DOMString integrity;
|
||||
};
|
||||
|
@ -33,3 +33,8 @@ partial interface HTMLScriptElement {
|
||||
attribute DOMString htmlFor;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webappsec/specs/subresourceintegrity/#htmlscriptelement-1
|
||||
partial interface HTMLScriptElement {
|
||||
[SetterThrows]
|
||||
attribute DOMString integrity;
|
||||
};
|
||||
|
@ -815,10 +815,12 @@ namespace mozilla {
|
||||
|
||||
CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheet* aPrimarySheet,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy)
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const SRIMetadata& aIntegrity)
|
||||
: mSheets()
|
||||
, mCORSMode(aCORSMode)
|
||||
, mReferrerPolicy (aReferrerPolicy)
|
||||
, mIntegrity(aIntegrity)
|
||||
, mComplete(false)
|
||||
#ifdef DEBUG
|
||||
, mPrincipalSet(false)
|
||||
@ -940,6 +942,7 @@ CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
|
||||
mPrincipal(aCopy.mPrincipal),
|
||||
mCORSMode(aCopy.mCORSMode),
|
||||
mReferrerPolicy(aCopy.mReferrerPolicy),
|
||||
mIntegrity(aCopy.mIntegrity),
|
||||
mComplete(aCopy.mComplete)
|
||||
#ifdef DEBUG
|
||||
, mPrincipalSet(aCopy.mPrincipalSet)
|
||||
@ -1080,7 +1083,26 @@ CSSStyleSheet::CSSStyleSheet(CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy)
|
||||
mScopeElement(nullptr),
|
||||
mRuleProcessors(nullptr)
|
||||
{
|
||||
mInner = new CSSStyleSheetInner(this, aCORSMode, aReferrerPolicy);
|
||||
mInner = new CSSStyleSheetInner(this, aCORSMode, aReferrerPolicy,
|
||||
SRIMetadata());
|
||||
}
|
||||
|
||||
CSSStyleSheet::CSSStyleSheet(CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const SRIMetadata& aIntegrity)
|
||||
: mTitle(),
|
||||
mParent(nullptr),
|
||||
mOwnerRule(nullptr),
|
||||
mDocument(nullptr),
|
||||
mOwningNode(nullptr),
|
||||
mDisabled(false),
|
||||
mDirty(false),
|
||||
mInRuleProcessorCache(false),
|
||||
mScopeElement(nullptr),
|
||||
mRuleProcessors(nullptr)
|
||||
{
|
||||
mInner = new CSSStyleSheetInner(this, aCORSMode, aReferrerPolicy,
|
||||
aIntegrity);
|
||||
}
|
||||
|
||||
CSSStyleSheet::CSSStyleSheet(const CSSStyleSheet& aCopy,
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
#include "mozilla/dom/SRIMetadata.h"
|
||||
|
||||
class CSSRuleListImpl;
|
||||
class nsCSSRuleProcessor;
|
||||
@ -63,7 +64,8 @@ public:
|
||||
private:
|
||||
CSSStyleSheetInner(CSSStyleSheet* aPrimarySheet,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy);
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const dom::SRIMetadata& aIntegrity);
|
||||
CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
|
||||
CSSStyleSheet* aPrimarySheet);
|
||||
~CSSStyleSheetInner();
|
||||
@ -96,6 +98,7 @@ private:
|
||||
// The Referrer Policy of a stylesheet is used for its child sheets, so it is
|
||||
// stored here.
|
||||
ReferrerPolicy mReferrerPolicy;
|
||||
dom::SRIMetadata mIntegrity;
|
||||
bool mComplete;
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -123,6 +126,8 @@ class CSSStyleSheet final : public nsIStyleSheet,
|
||||
public:
|
||||
typedef net::ReferrerPolicy ReferrerPolicy;
|
||||
CSSStyleSheet(CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy);
|
||||
CSSStyleSheet(CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy,
|
||||
const dom::SRIMetadata& aIntegrity);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(CSSStyleSheet,
|
||||
@ -259,6 +264,9 @@ public:
|
||||
// Get this style sheet's Referrer Policy
|
||||
ReferrerPolicy GetReferrerPolicy() const { return mInner->mReferrerPolicy; }
|
||||
|
||||
// Get this style sheet's integrity metadata
|
||||
dom::SRIMetadata GetIntegrity() const { return mInner->mIntegrity; }
|
||||
|
||||
dom::Element* GetScopeElement() const { return mScopeElement; }
|
||||
void SetScopeElement(dom::Element* aScopeElement)
|
||||
{
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include "nsError.h"
|
||||
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "mozilla/dom/SRICheck.h"
|
||||
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
using mozilla::dom::EncodingUtils;
|
||||
@ -265,6 +266,16 @@ GetLoaderLog()
|
||||
return sLog;
|
||||
}
|
||||
|
||||
static PRLogModuleInfo*
|
||||
GetSriLog()
|
||||
{
|
||||
static PRLogModuleInfo *gSriPRLog;
|
||||
if (!gSriPRLog) {
|
||||
gSriPRLog = PR_NewLogModule("SRI");
|
||||
}
|
||||
return gSriPRLog;
|
||||
}
|
||||
|
||||
#define LOG_ERROR(args) MOZ_LOG(GetLoaderLog(), mozilla::LogLevel::Error, args)
|
||||
#define LOG_WARN(args) MOZ_LOG(GetLoaderLog(), mozilla::LogLevel::Warning, args)
|
||||
#define LOG_DEBUG(args) MOZ_LOG(GetLoaderLog(), mozilla::LogLevel::Debug, args)
|
||||
@ -928,6 +939,18 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
|
||||
}
|
||||
}
|
||||
|
||||
SRIMetadata sriMetadata = mSheet->GetIntegrity();
|
||||
if (!sriMetadata.IsEmpty() &&
|
||||
NS_FAILED(SRICheck::VerifyIntegrity(sriMetadata, channelURI,
|
||||
mSheet->GetCORSMode(), aBuffer,
|
||||
mLoader->mDocument))) {
|
||||
LOG((" Load was blocked by SRI"));
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("css::Loader::OnStreamComplete, bad metadata"));
|
||||
mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Enough to set the URIs on mSheet, since any sibling datas we have share
|
||||
// the same mInner as mSheet and will thus get the same URI.
|
||||
mSheet->SetURIs(channelURI, originalURI, channelURI);
|
||||
@ -1057,6 +1080,7 @@ Loader::CreateSheet(nsIURI* aURI,
|
||||
nsIPrincipal* aLoaderPrincipal,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const nsAString& aIntegrity,
|
||||
bool aSyncLoad,
|
||||
bool aHasAlternateRel,
|
||||
const nsAString& aTitle,
|
||||
@ -1204,7 +1228,17 @@ Loader::CreateSheet(nsIURI* aURI,
|
||||
originalURI = aURI;
|
||||
}
|
||||
|
||||
nsRefPtr<CSSStyleSheet> sheet = new CSSStyleSheet(aCORSMode, aReferrerPolicy);
|
||||
SRIMetadata sriMetadata;
|
||||
if (!aIntegrity.IsEmpty()) {
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("css::Loader::CreateSheet, integrity=%s",
|
||||
NS_ConvertUTF16toUTF8(aIntegrity).get()));
|
||||
SRICheck::IntegrityMetadata(aIntegrity, mDocument, &sriMetadata);
|
||||
}
|
||||
|
||||
nsRefPtr<CSSStyleSheet> sheet = new CSSStyleSheet(aCORSMode,
|
||||
aReferrerPolicy,
|
||||
sriMetadata);
|
||||
sheet->SetURIs(sheetURI, originalURI, baseURI);
|
||||
sheet.forget(aSheet);
|
||||
}
|
||||
@ -1415,6 +1449,8 @@ Loader::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
|
||||
triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
|
||||
}
|
||||
|
||||
SRIMetadata sriMetadata = aLoadData->mSheet->GetIntegrity();
|
||||
|
||||
if (aLoadData->mSyncLoad) {
|
||||
LOG((" Synchronous load"));
|
||||
NS_ASSERTION(!aLoadData->mObserver, "Observer for a sync load?");
|
||||
@ -1599,7 +1635,7 @@ Loader::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
|
||||
if (httpChannel) {
|
||||
// send a minimal Accept header for text/css
|
||||
// Send a minimal Accept header for text/css
|
||||
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
|
||||
NS_LITERAL_CSTRING("text/css,*/*;q=0.1"),
|
||||
false);
|
||||
@ -1932,8 +1968,10 @@ Loader::LoadInlineStyle(nsIContent* aElement,
|
||||
StyleSheetState state;
|
||||
nsRefPtr<CSSStyleSheet> sheet;
|
||||
nsresult rv = CreateSheet(nullptr, aElement, nullptr, CORS_NONE,
|
||||
mDocument->GetReferrerPolicy(), false, false,
|
||||
aTitle, state, aIsAlternate, getter_AddRefs(sheet));
|
||||
mDocument->GetReferrerPolicy(),
|
||||
EmptyString(), // no inline integrity checks
|
||||
false, false, aTitle, state, aIsAlternate,
|
||||
getter_AddRefs(sheet));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(state == eSheetNeedsParser,
|
||||
"Inline sheets should not be cached");
|
||||
@ -1979,6 +2017,7 @@ Loader::LoadStyleLink(nsIContent* aElement,
|
||||
bool aHasAlternateRel,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const nsAString& aIntegrity,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
bool* aIsAlternate)
|
||||
{
|
||||
@ -2013,7 +2052,7 @@ Loader::LoadStyleLink(nsIContent* aElement,
|
||||
StyleSheetState state;
|
||||
nsRefPtr<CSSStyleSheet> sheet;
|
||||
rv = CreateSheet(aURL, aElement, principal, aCORSMode,
|
||||
aReferrerPolicy, false,
|
||||
aReferrerPolicy, aIntegrity, false,
|
||||
aHasAlternateRel, aTitle, state, aIsAlternate,
|
||||
getter_AddRefs(sheet));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -2177,6 +2216,7 @@ Loader::LoadChildSheet(CSSStyleSheet* aParentSheet,
|
||||
// For now, use CORS_NONE for child sheets
|
||||
rv = CreateSheet(aURL, nullptr, principal, CORS_NONE,
|
||||
aParentSheet->GetReferrerPolicy(),
|
||||
EmptyString(), // integrity is only checked on main sheet
|
||||
parentData ? parentData->mSyncLoad : false,
|
||||
false, empty, state, &isAlternate, getter_AddRefs(sheet));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -2243,13 +2283,14 @@ Loader::LoadSheet(nsIURI* aURL,
|
||||
const nsCString& aCharset,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy)
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const nsAString& aIntegrity)
|
||||
{
|
||||
LOG(("css::Loader::LoadSheet(aURL, aObserver) api call"));
|
||||
return InternalLoadNonDocumentSheet(aURL, false, false,
|
||||
aOriginPrincipal, aCharset,
|
||||
nullptr, aObserver, aCORSMode,
|
||||
aReferrerPolicy);
|
||||
aReferrerPolicy, aIntegrity);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -2261,7 +2302,8 @@ Loader::InternalLoadNonDocumentSheet(nsIURI* aURL,
|
||||
CSSStyleSheet** aSheet,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy)
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const nsAString& aIntegrity)
|
||||
{
|
||||
NS_PRECONDITION(aURL, "Must have a URI to load");
|
||||
NS_PRECONDITION(aSheet || aObserver, "Sheet and observer can't both be null");
|
||||
@ -2292,7 +2334,7 @@ Loader::InternalLoadNonDocumentSheet(nsIURI* aURL,
|
||||
const nsSubstring& empty = EmptyString();
|
||||
|
||||
rv = CreateSheet(aURL, nullptr, aOriginPrincipal, aCORSMode,
|
||||
aReferrerPolicy, syncLoad, false,
|
||||
aReferrerPolicy, aIntegrity, syncLoad, false,
|
||||
empty, state, &isAlternate, getter_AddRefs(sheet));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -223,6 +223,7 @@ public:
|
||||
bool aHasAlternateRel,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const nsAString& aIntegrity,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
bool* aIsAlternate);
|
||||
|
||||
@ -320,7 +321,8 @@ public:
|
||||
const nsCString& aCharset,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
CORSMode aCORSMode = CORS_NONE,
|
||||
ReferrerPolicy aReferrerPolicy = mozilla::net::RP_Default);
|
||||
ReferrerPolicy aReferrerPolicy = mozilla::net::RP_Default,
|
||||
const nsAString& aIntegrity = EmptyString());
|
||||
|
||||
/**
|
||||
* Stop loading all sheets. All nsICSSLoaderObservers involved will be
|
||||
@ -417,6 +419,7 @@ private:
|
||||
nsIPrincipal* aLoaderPrincipal,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const nsAString& aIntegrity,
|
||||
bool aSyncLoad,
|
||||
bool aHasAlternateRel,
|
||||
const nsAString& aTitle,
|
||||
@ -450,7 +453,8 @@ private:
|
||||
CSSStyleSheet** aSheet,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
CORSMode aCORSMode = CORS_NONE,
|
||||
ReferrerPolicy aReferrerPolicy = mozilla::net::RP_Default);
|
||||
ReferrerPolicy aReferrerPolicy = mozilla::net::RP_Default,
|
||||
const nsAString& aIntegrity = EmptyString());
|
||||
|
||||
// Post a load event for aObserver to be notified about aSheet. The
|
||||
// notification will be sent with status NS_OK unless the load event is
|
||||
|
@ -1958,6 +1958,9 @@ pref("security.apps.privileged.CSP.default", "default-src * data: blob:; script-
|
||||
pref("security.mixed_content.block_active_content", false);
|
||||
pref("security.mixed_content.block_display_content", false);
|
||||
|
||||
// Sub-resource integrity
|
||||
pref("security.sri.enable", false);
|
||||
|
||||
// Disable pinning checks by default.
|
||||
pref("security.cert_pinning.enforcement_level", 0);
|
||||
// Do not process hpkp headers rooted by not built in roots by default.
|
||||
|
@ -45,14 +45,14 @@ nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor)
|
||||
break;
|
||||
case eSpeculativeLoadScript:
|
||||
aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSource,
|
||||
mCrossOrigin, false);
|
||||
mCrossOrigin, mIntegrity, false);
|
||||
break;
|
||||
case eSpeculativeLoadScriptFromHead:
|
||||
aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSource,
|
||||
mCrossOrigin, true);
|
||||
mCrossOrigin, mIntegrity, true);
|
||||
break;
|
||||
case eSpeculativeLoadStyle:
|
||||
aExecutor->PreloadStyle(mUrl, mCharset, mCrossOrigin);
|
||||
aExecutor->PreloadStyle(mUrl, mCharset, mCrossOrigin, mIntegrity);
|
||||
break;
|
||||
case eSpeculativeLoadManifest:
|
||||
aExecutor->ProcessOfflineManifest(mUrl);
|
||||
|
@ -105,6 +105,7 @@ class nsHtml5SpeculativeLoad {
|
||||
const nsAString& aCharset,
|
||||
const nsAString& aType,
|
||||
const nsAString& aCrossOrigin,
|
||||
const nsAString& aIntegrity,
|
||||
bool aParserInHead)
|
||||
{
|
||||
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
|
||||
@ -115,10 +116,12 @@ class nsHtml5SpeculativeLoad {
|
||||
mCharset.Assign(aCharset);
|
||||
mTypeOrCharsetSource.Assign(aType);
|
||||
mCrossOrigin.Assign(aCrossOrigin);
|
||||
mIntegrity.Assign(aIntegrity);
|
||||
}
|
||||
|
||||
inline void InitStyle(const nsAString& aUrl, const nsAString& aCharset,
|
||||
const nsAString& aCrossOrigin)
|
||||
const nsAString& aCrossOrigin,
|
||||
const nsAString& aIntegrity)
|
||||
{
|
||||
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
|
||||
"Trying to reinitialize a speculative load!");
|
||||
@ -126,6 +129,7 @@ class nsHtml5SpeculativeLoad {
|
||||
mUrl.Assign(aUrl);
|
||||
mCharset.Assign(aCharset);
|
||||
mCrossOrigin.Assign(aCrossOrigin);
|
||||
mIntegrity.Assign(aIntegrity);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,6 +223,12 @@ class nsHtml5SpeculativeLoad {
|
||||
* attribute. If the attribute is not set, this will be a void string.
|
||||
*/
|
||||
nsString mMedia;
|
||||
/**
|
||||
* If mOpCode is eSpeculativeLoadScript[FromHead], this is the value of the
|
||||
* "integrity" attribute. If the attribute is not set, this will be a void
|
||||
* string.
|
||||
*/
|
||||
nsString mIntegrity;
|
||||
};
|
||||
|
||||
#endif // nsHtml5SpeculativeLoad_h
|
||||
|
@ -165,11 +165,14 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
|
||||
nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
|
||||
nsString* crossOrigin =
|
||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
||||
nsString* integrity =
|
||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
|
||||
mSpeculativeLoadQueue.AppendElement()->
|
||||
InitScript(*url,
|
||||
(charset) ? *charset : EmptyString(),
|
||||
(type) ? *type : EmptyString(),
|
||||
(crossOrigin) ? *crossOrigin : NullString(),
|
||||
(integrity) ? *integrity : NullString(),
|
||||
mode == NS_HTML5TREE_BUILDER_IN_HEAD);
|
||||
mCurrentHtmlScriptIsAsyncOrDefer =
|
||||
aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
|
||||
@ -186,10 +189,13 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
|
||||
nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
|
||||
nsString* crossOrigin =
|
||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
||||
nsString* integrity =
|
||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
|
||||
mSpeculativeLoadQueue.AppendElement()->
|
||||
InitStyle(*url,
|
||||
(charset) ? *charset : EmptyString(),
|
||||
(crossOrigin) ? *crossOrigin : NullString());
|
||||
(crossOrigin) ? *crossOrigin : NullString(),
|
||||
(integrity) ? *integrity : NullString());
|
||||
}
|
||||
} else if (rel->LowerCaseEqualsASCII("preconnect")) {
|
||||
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
|
||||
@ -256,11 +262,14 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
|
||||
nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
|
||||
nsString* crossOrigin =
|
||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
||||
nsString* integrity =
|
||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
|
||||
mSpeculativeLoadQueue.AppendElement()->
|
||||
InitScript(*url,
|
||||
EmptyString(),
|
||||
(type) ? *type : EmptyString(),
|
||||
(crossOrigin) ? *crossOrigin : NullString(),
|
||||
(integrity) ? *integrity : NullString(),
|
||||
mode == NS_HTML5TREE_BUILDER_IN_HEAD);
|
||||
}
|
||||
} else if (nsHtml5Atoms::style == aName) {
|
||||
@ -272,9 +281,12 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
|
||||
if (url) {
|
||||
nsString* crossOrigin =
|
||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
||||
nsString* integrity =
|
||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
|
||||
mSpeculativeLoadQueue.AppendElement()->
|
||||
InitStyle(*url, EmptyString(),
|
||||
(crossOrigin) ? *crossOrigin : NullString());
|
||||
(crossOrigin) ? *crossOrigin : NullString(),
|
||||
(integrity) ? *integrity : NullString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -911,6 +911,7 @@ nsHtml5TreeOpExecutor::PreloadScript(const nsAString& aURL,
|
||||
const nsAString& aCharset,
|
||||
const nsAString& aType,
|
||||
const nsAString& aCrossOrigin,
|
||||
const nsAString& aIntegrity,
|
||||
bool aScriptFromHead)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri = ConvertIfNotPreloadedYet(aURL);
|
||||
@ -918,21 +919,22 @@ nsHtml5TreeOpExecutor::PreloadScript(const nsAString& aURL,
|
||||
return;
|
||||
}
|
||||
mDocument->ScriptLoader()->PreloadURI(uri, aCharset, aType, aCrossOrigin,
|
||||
aScriptFromHead,
|
||||
aIntegrity, aScriptFromHead,
|
||||
mSpeculationReferrerPolicy);
|
||||
}
|
||||
|
||||
void
|
||||
nsHtml5TreeOpExecutor::PreloadStyle(const nsAString& aURL,
|
||||
const nsAString& aCharset,
|
||||
const nsAString& aCrossOrigin)
|
||||
const nsAString& aCrossOrigin,
|
||||
const nsAString& aIntegrity)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri = ConvertIfNotPreloadedYet(aURL);
|
||||
if (!uri) {
|
||||
return;
|
||||
}
|
||||
mDocument->PreloadStyle(uri, aCharset, aCrossOrigin,
|
||||
mSpeculationReferrerPolicy);
|
||||
mSpeculationReferrerPolicy, aIntegrity);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -248,10 +248,12 @@ class nsHtml5TreeOpExecutor final : public nsHtml5DocumentBuilder,
|
||||
const nsAString& aCharset,
|
||||
const nsAString& aType,
|
||||
const nsAString& aCrossOrigin,
|
||||
const nsAString& aIntegrity,
|
||||
bool aScriptFromHead);
|
||||
|
||||
void PreloadStyle(const nsAString& aURL, const nsAString& aCharset,
|
||||
const nsAString& aCrossOrigin);
|
||||
const nsAString& aCrossOrigin,
|
||||
const nsAString& aIntegrity);
|
||||
|
||||
void PreloadImage(const nsAString& aURL,
|
||||
const nsAString& aCrossOrigin,
|
||||
|
@ -657,6 +657,11 @@
|
||||
ERROR(NS_ERROR_CSP_FORM_ACTION_VIOLATION, FAILURE(98)),
|
||||
ERROR(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION, FAILURE(99)),
|
||||
|
||||
/* Error code for Sub-Resource Integrity */
|
||||
ERROR(NS_ERROR_SRI_CORRUPT, FAILURE(200)),
|
||||
ERROR(NS_ERROR_SRI_DISABLED, FAILURE(201)),
|
||||
ERROR(NS_ERROR_SRI_NOT_ELIGIBLE, FAILURE(202)),
|
||||
|
||||
/* CMS specific nsresult error codes. Note: the numbers used here correspond
|
||||
* to the values in nsICMSMessageErrors.idl. */
|
||||
ERROR(NS_ERROR_CMS_VERIFY_NOT_SIGNED, FAILURE(1024)),
|
||||
|
Loading…
Reference in New Issue
Block a user