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
bd8676f33f
commit
6349d3c212
1
AUTHORS
1
AUTHORS
@ -359,6 +359,7 @@ Florian Scholz <elchi3@elchi3.de>
|
|||||||
<flying@dom.natm.ru>
|
<flying@dom.natm.ru>
|
||||||
France Telecom Research and Development
|
France Telecom Research and Development
|
||||||
Franck
|
Franck
|
||||||
|
Francois Marier <francois@fmarier.org>
|
||||||
Frank Tang <ftang@netscape.com>
|
Frank Tang <ftang@netscape.com>
|
||||||
Frank Yan <fyan@mozilla.com>
|
Frank Yan <fyan@mozilla.com>
|
||||||
Franky Braem
|
Franky Braem
|
||||||
|
@ -4807,6 +4807,7 @@ var Utils = {
|
|||||||
case "CORS":
|
case "CORS":
|
||||||
case "Iframe Sandbox":
|
case "Iframe Sandbox":
|
||||||
case "Tracking Protection":
|
case "Tracking Protection":
|
||||||
|
case "Sub-resource Integrity":
|
||||||
return CATEGORY_SECURITY;
|
return CATEGORY_SECURITY;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -432,6 +432,7 @@ LOCAL_INCLUDES += [
|
|||||||
'/layout/svg',
|
'/layout/svg',
|
||||||
'/layout/xul',
|
'/layout/xul',
|
||||||
'/netwerk/base',
|
'/netwerk/base',
|
||||||
|
'/security/manager/ssl',
|
||||||
'/widget',
|
'/widget',
|
||||||
'/xpcom/ds',
|
'/xpcom/ds',
|
||||||
]
|
]
|
||||||
|
@ -51,6 +51,16 @@
|
|||||||
#include "nsParserConstants.h"
|
#include "nsParserConstants.h"
|
||||||
#include "nsSandboxFlags.h"
|
#include "nsSandboxFlags.h"
|
||||||
|
|
||||||
|
static PRLogModuleInfo*
|
||||||
|
GetSriLog()
|
||||||
|
{
|
||||||
|
static PRLogModuleInfo *gSriPRLog;
|
||||||
|
if (!gSriPRLog) {
|
||||||
|
gSriPRLog = PR_NewLogModule("SRI");
|
||||||
|
}
|
||||||
|
return gSriPRLog;
|
||||||
|
}
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
PRLogModuleInfo* gContentSinkLogModuleInfo;
|
PRLogModuleInfo* gContentSinkLogModuleInfo;
|
||||||
@ -750,12 +760,23 @@ nsContentSink::ProcessStyleLink(nsIContent* aElement,
|
|||||||
aElement->NodeType() == nsIDOMNode::PROCESSING_INSTRUCTION_NODE,
|
aElement->NodeType() == nsIDOMNode::PROCESSING_INSTRUCTION_NODE,
|
||||||
"We only expect processing instructions here");
|
"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.
|
// If this is a fragment parser, we don't want to observe.
|
||||||
// We don't support CORS for processing instructions
|
// We don't support CORS for processing instructions
|
||||||
bool isAlternate;
|
bool isAlternate;
|
||||||
rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
|
rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
|
||||||
CORS_NONE, mDocument->GetReferrerPolicy(),
|
CORS_NONE, mDocument->GetReferrerPolicy(),
|
||||||
mRunsToCompletion ? nullptr : this, &isAlternate);
|
integrity, mRunsToCompletion ? nullptr : this,
|
||||||
|
&isAlternate);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!isAlternate && !mRunsToCompletion) {
|
if (!isAlternate && !mRunsToCompletion) {
|
||||||
|
@ -9876,7 +9876,8 @@ NS_IMPL_ISUPPORTS(StubCSSLoaderObserver, nsICSSLoaderObserver)
|
|||||||
void
|
void
|
||||||
nsDocument::PreloadStyle(nsIURI* uri, const nsAString& charset,
|
nsDocument::PreloadStyle(nsIURI* uri, const nsAString& charset,
|
||||||
const nsAString& aCrossOriginAttr,
|
const nsAString& aCrossOriginAttr,
|
||||||
const ReferrerPolicy aReferrerPolicy)
|
const ReferrerPolicy aReferrerPolicy,
|
||||||
|
const nsAString& aIntegrity)
|
||||||
{
|
{
|
||||||
// The CSSLoader will retain this object after we return.
|
// The CSSLoader will retain this object after we return.
|
||||||
nsCOMPtr<nsICSSLoaderObserver> obs = new StubCSSLoaderObserver();
|
nsCOMPtr<nsICSSLoaderObserver> obs = new StubCSSLoaderObserver();
|
||||||
@ -9886,7 +9887,7 @@ nsDocument::PreloadStyle(nsIURI* uri, const nsAString& charset,
|
|||||||
NS_LossyConvertUTF16toASCII(charset),
|
NS_LossyConvertUTF16toASCII(charset),
|
||||||
obs,
|
obs,
|
||||||
Element::StringToCORSMode(aCrossOriginAttr),
|
Element::StringToCORSMode(aCrossOriginAttr),
|
||||||
aReferrerPolicy);
|
aReferrerPolicy, aIntegrity);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -1147,7 +1147,8 @@ public:
|
|||||||
|
|
||||||
virtual void PreloadStyle(nsIURI* uri, const nsAString& charset,
|
virtual void PreloadStyle(nsIURI* uri, const nsAString& charset,
|
||||||
const nsAString& aCrossOriginAttr,
|
const nsAString& aCrossOriginAttr,
|
||||||
ReferrerPolicy aReferrerPolicy) override;
|
ReferrerPolicy aReferrerPolicy,
|
||||||
|
const nsAString& aIntegrity) override;
|
||||||
|
|
||||||
virtual nsresult LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
|
virtual nsresult LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
|
||||||
mozilla::CSSStyleSheet** sheet) override;
|
mozilla::CSSStyleSheet** sheet) override;
|
||||||
|
@ -489,6 +489,7 @@ GK_ATOM(instanceOf, "instanceOf")
|
|||||||
GK_ATOM(int32, "int32")
|
GK_ATOM(int32, "int32")
|
||||||
GK_ATOM(int64, "int64")
|
GK_ATOM(int64, "int64")
|
||||||
GK_ATOM(integer, "integer")
|
GK_ATOM(integer, "integer")
|
||||||
|
GK_ATOM(integrity, "integrity")
|
||||||
GK_ATOM(intersection, "intersection")
|
GK_ATOM(intersection, "intersection")
|
||||||
GK_ATOM(is, "is")
|
GK_ATOM(is, "is")
|
||||||
GK_ATOM(iscontainer, "iscontainer")
|
GK_ATOM(iscontainer, "iscontainer")
|
||||||
|
@ -152,8 +152,8 @@ typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
|
|||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
#define NS_IDOCUMENT_IID \
|
#define NS_IDOCUMENT_IID \
|
||||||
{ 0xbbce44c8, 0x22fe, 0x404f, \
|
{ 0x6d18ec0b, 0x1f68, 0x4ae6, \
|
||||||
{ 0x9e, 0x71, 0x23, 0x1d, 0xf4, 0xcc, 0x8e, 0x34 } }
|
{ 0x8b, 0x3d, 0x8d, 0x7d, 0x8b, 0x8e, 0x28, 0xd4 } }
|
||||||
|
|
||||||
// Enum for requesting a particular type of document when creating a doc
|
// Enum for requesting a particular type of document when creating a doc
|
||||||
enum DocumentFlavor {
|
enum DocumentFlavor {
|
||||||
@ -2023,7 +2023,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void PreloadStyle(nsIURI* aURI, const nsAString& aCharset,
|
virtual void PreloadStyle(nsIURI* aURI, const nsAString& aCharset,
|
||||||
const nsAString& aCrossOriginAttr,
|
const nsAString& aCrossOriginAttr,
|
||||||
ReferrerPolicyEnum aReferrerPolicy) = 0;
|
ReferrerPolicyEnum aReferrerPolicy,
|
||||||
|
const nsAString& aIntegrity) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the chrome registry to load style sheets. Can be put
|
* Called by the chrome registry to load style sheets. Can be put
|
||||||
|
@ -53,9 +53,21 @@
|
|||||||
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/unused.h"
|
#include "mozilla/unused.h"
|
||||||
|
#include "mozilla/dom/SRICheck.h"
|
||||||
|
#include "nsIScriptError.h"
|
||||||
|
|
||||||
static PRLogModuleInfo* gCspPRLog;
|
static PRLogModuleInfo* gCspPRLog;
|
||||||
|
|
||||||
|
static PRLogModuleInfo*
|
||||||
|
GetSriLog()
|
||||||
|
{
|
||||||
|
static PRLogModuleInfo *gSriPRLog;
|
||||||
|
if (!gSriPRLog) {
|
||||||
|
gSriPRLog = PR_NewLogModule("SRI");
|
||||||
|
}
|
||||||
|
return gSriPRLog;
|
||||||
|
}
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
|
||||||
@ -606,7 +618,22 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||||||
|
|
||||||
if (!request) {
|
if (!request) {
|
||||||
// no usable preload
|
// 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->mURI = scriptURI;
|
||||||
request->mIsInline = false;
|
request->mIsInline = false;
|
||||||
request->mLoading = true;
|
request->mLoading = true;
|
||||||
@ -720,7 +747,8 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inline scripts ignore ther CORS mode and are always CORS_NONE
|
// 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->mJSVersion = version;
|
||||||
request->mLoading = false;
|
request->mLoading = false;
|
||||||
request->mIsInline = true;
|
request->mIsInline = true;
|
||||||
@ -1408,8 +1436,15 @@ nsScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader,
|
|||||||
NS_ASSERTION(request, "null request in stream complete handler");
|
NS_ASSERTION(request, "null request in stream complete handler");
|
||||||
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
nsresult rv = PrepareLoadedRequest(request, aLoader, aStatus, aStringLen,
|
nsresult rv = NS_ERROR_SRI_CORRUPT;
|
||||||
aString);
|
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)) {
|
if (NS_FAILED(rv)) {
|
||||||
/*
|
/*
|
||||||
* Handle script not loading error because source was a tracking URL.
|
* Handle script not loading error because source was a tracking URL.
|
||||||
@ -1603,6 +1638,7 @@ void
|
|||||||
nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
|
nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
|
||||||
const nsAString &aType,
|
const nsAString &aType,
|
||||||
const nsAString &aCrossOrigin,
|
const nsAString &aCrossOrigin,
|
||||||
|
const nsAString& aIntegrity,
|
||||||
bool aScriptFromHead,
|
bool aScriptFromHead,
|
||||||
const mozilla::net::ReferrerPolicy aReferrerPolicy)
|
const mozilla::net::ReferrerPolicy aReferrerPolicy)
|
||||||
{
|
{
|
||||||
@ -1611,9 +1647,18 @@ nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
|
|||||||
return;
|
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 =
|
nsRefPtr<nsScriptLoadRequest> request =
|
||||||
new nsScriptLoadRequest(nullptr, 0,
|
new nsScriptLoadRequest(nullptr, 0,
|
||||||
Element::StringToCORSMode(aCrossOrigin));
|
Element::StringToCORSMode(aCrossOrigin),
|
||||||
|
sriMetadata);
|
||||||
request->mURI = aURI;
|
request->mURI = aURI;
|
||||||
request->mIsInline = false;
|
request->mIsInline = false;
|
||||||
request->mLoading = true;
|
request->mLoading = true;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
#include "nsIStreamLoader.h"
|
#include "nsIStreamLoader.h"
|
||||||
#include "mozilla/CORSMode.h"
|
#include "mozilla/CORSMode.h"
|
||||||
|
#include "mozilla/dom/SRIMetadata.h"
|
||||||
#include "mozilla/LinkedList.h"
|
#include "mozilla/LinkedList.h"
|
||||||
#include "mozilla/net/ReferrerPolicy.h"
|
#include "mozilla/net/ReferrerPolicy.h"
|
||||||
|
|
||||||
@ -56,7 +57,8 @@ class nsScriptLoadRequest final : public nsISupports,
|
|||||||
public:
|
public:
|
||||||
nsScriptLoadRequest(nsIScriptElement* aElement,
|
nsScriptLoadRequest(nsIScriptElement* aElement,
|
||||||
uint32_t aVersion,
|
uint32_t aVersion,
|
||||||
mozilla::CORSMode aCORSMode)
|
mozilla::CORSMode aCORSMode,
|
||||||
|
const mozilla::dom::SRIMetadata &aIntegrity)
|
||||||
: mElement(aElement),
|
: mElement(aElement),
|
||||||
mLoading(true),
|
mLoading(true),
|
||||||
mIsInline(true),
|
mIsInline(true),
|
||||||
@ -71,6 +73,7 @@ public:
|
|||||||
mJSVersion(aVersion),
|
mJSVersion(aVersion),
|
||||||
mLineNo(1),
|
mLineNo(1),
|
||||||
mCORSMode(aCORSMode),
|
mCORSMode(aCORSMode),
|
||||||
|
mIntegrity(aIntegrity),
|
||||||
mReferrerPolicy(mozilla::net::RP_Default)
|
mReferrerPolicy(mozilla::net::RP_Default)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -122,6 +125,7 @@ public:
|
|||||||
nsAutoCString mURL; // Keep the URI's filename alive during off thread parsing.
|
nsAutoCString mURL; // Keep the URI's filename alive during off thread parsing.
|
||||||
int32_t mLineNo;
|
int32_t mLineNo;
|
||||||
const mozilla::CORSMode mCORSMode;
|
const mozilla::CORSMode mCORSMode;
|
||||||
|
const mozilla::dom::SRIMetadata mIntegrity;
|
||||||
mozilla::net::ReferrerPolicy mReferrerPolicy;
|
mozilla::net::ReferrerPolicy mReferrerPolicy;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -367,11 +371,13 @@ public:
|
|||||||
* @param aType The type parameter for the script.
|
* @param aType The type parameter for the script.
|
||||||
* @param aCrossOrigin The crossorigin attribute for the script.
|
* @param aCrossOrigin The crossorigin attribute for the script.
|
||||||
* Void if not present.
|
* 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
|
* @param aScriptFromHead Whether or not the script was a child of head
|
||||||
*/
|
*/
|
||||||
virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
|
virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
|
||||||
const nsAString &aType,
|
const nsAString &aType,
|
||||||
const nsAString &aCrossOrigin,
|
const nsAString &aCrossOrigin,
|
||||||
|
const nsAString& aIntegrity,
|
||||||
bool aScriptFromHead,
|
bool aScriptFromHead,
|
||||||
const mozilla::net::ReferrerPolicy aReferrerPolicy);
|
const mozilla::net::ReferrerPolicy aReferrerPolicy);
|
||||||
|
|
||||||
|
@ -421,13 +421,21 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
|
|||||||
scopeElement, aObserver, &doneLoading, &isAlternate);
|
scopeElement, aObserver, &doneLoading, &isAlternate);
|
||||||
}
|
}
|
||||||
else {
|
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.
|
// XXXbz clone the URI here to work around content policies modifying URIs.
|
||||||
nsCOMPtr<nsIURI> clonedURI;
|
nsCOMPtr<nsIURI> clonedURI;
|
||||||
uri->Clone(getter_AddRefs(clonedURI));
|
uri->Clone(getter_AddRefs(clonedURI));
|
||||||
NS_ENSURE_TRUE(clonedURI, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(clonedURI, NS_ERROR_OUT_OF_MEMORY);
|
||||||
rv = doc->CSSLoader()->
|
rv = doc->CSSLoader()->
|
||||||
LoadStyleLink(thisContent, clonedURI, title, media, isAlternate,
|
LoadStyleLink(thisContent, clonedURI, title, media, isAlternate,
|
||||||
GetCORSMode(), doc->GetReferrerPolicy(),
|
GetCORSMode(), doc->GetReferrerPolicy(), integrity,
|
||||||
aObserver, &isAlternate);
|
aObserver, &isAlternate);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
// Don't propagate LoadStyleLink() errors further than this, since some
|
// Don't propagate LoadStyleLink() errors further than this, since some
|
||||||
|
@ -214,6 +214,11 @@ HTMLLinkElement::ParseAttribute(int32_t aNamespaceID,
|
|||||||
aResult.ParseAtomArray(aValue);
|
aResult.ParseAtomArray(aValue);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aAttribute == nsGkAtoms::integrity) {
|
||||||
|
aResult.ParseStringOrAtom(aValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||||
|
@ -143,6 +143,14 @@ public:
|
|||||||
{
|
{
|
||||||
SetHTMLAttr(nsGkAtoms::target, aTarget, aRv);
|
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<nsIDocument> GetImport();
|
||||||
already_AddRefed<ImportLoader> GetImportLoader()
|
already_AddRefed<ImportLoader> GetImportLoader()
|
||||||
|
@ -75,10 +75,16 @@ HTMLScriptElement::ParseAttribute(int32_t aNamespaceID,
|
|||||||
const nsAString& aValue,
|
const nsAString& aValue,
|
||||||
nsAttrValue& aResult)
|
nsAttrValue& aResult)
|
||||||
{
|
{
|
||||||
if (aNamespaceID == kNameSpaceID_None &&
|
if (aNamespaceID == kNameSpaceID_None) {
|
||||||
aAttribute == nsGkAtoms::crossorigin) {
|
if (aAttribute == nsGkAtoms::crossorigin) {
|
||||||
ParseCORSValue(aValue, aResult);
|
ParseCORSValue(aValue, aResult);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aAttribute == nsGkAtoms::integrity) {
|
||||||
|
aResult.ParseStringOrAtom(aValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||||
|
@ -79,6 +79,14 @@ public:
|
|||||||
{
|
{
|
||||||
SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError);
|
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();
|
bool Async();
|
||||||
void SetAsync(bool aValue, ErrorResult& rv);
|
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"
|
# 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.
|
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".
|
# LOCALIZATION NOTE: Do not translate "SSL 3.0".
|
||||||
WeakProtocolVersionWarning=This site uses the protocol SSL 3.0 for encryption, which is deprecated and insecure.
|
WeakProtocolVersionWarning=This site uses the protocol SSL 3.0 for encryption, which is deprecated and insecure.
|
||||||
# LOCALIZATION NOTE: Do not translate "RC4".
|
# 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',
|
'nsCSPService.h',
|
||||||
'nsCSPUtils.h',
|
'nsCSPUtils.h',
|
||||||
'nsMixedContentBlocker.h',
|
'nsMixedContentBlocker.h',
|
||||||
|
'SRICheck.h',
|
||||||
|
'SRIMetadata.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
@ -27,6 +29,8 @@ UNIFIED_SOURCES += [
|
|||||||
'nsCSPService.cpp',
|
'nsCSPService.cpp',
|
||||||
'nsCSPUtils.cpp',
|
'nsCSPUtils.cpp',
|
||||||
'nsMixedContentBlocker.cpp',
|
'nsMixedContentBlocker.cpp',
|
||||||
|
'SRICheck.cpp',
|
||||||
|
'SRIMetadata.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
FAIL_ON_WARNINGS = True
|
FAIL_ON_WARNINGS = True
|
||||||
|
@ -48,3 +48,8 @@ partial interface HTMLLinkElement {
|
|||||||
readonly attribute Document? import;
|
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;
|
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,
|
CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheet* aPrimarySheet,
|
||||||
CORSMode aCORSMode,
|
CORSMode aCORSMode,
|
||||||
ReferrerPolicy aReferrerPolicy)
|
ReferrerPolicy aReferrerPolicy,
|
||||||
|
const SRIMetadata& aIntegrity)
|
||||||
: mSheets()
|
: mSheets()
|
||||||
, mCORSMode(aCORSMode)
|
, mCORSMode(aCORSMode)
|
||||||
, mReferrerPolicy (aReferrerPolicy)
|
, mReferrerPolicy (aReferrerPolicy)
|
||||||
|
, mIntegrity(aIntegrity)
|
||||||
, mComplete(false)
|
, mComplete(false)
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
, mPrincipalSet(false)
|
, mPrincipalSet(false)
|
||||||
@ -940,6 +942,7 @@ CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
|
|||||||
mPrincipal(aCopy.mPrincipal),
|
mPrincipal(aCopy.mPrincipal),
|
||||||
mCORSMode(aCopy.mCORSMode),
|
mCORSMode(aCopy.mCORSMode),
|
||||||
mReferrerPolicy(aCopy.mReferrerPolicy),
|
mReferrerPolicy(aCopy.mReferrerPolicy),
|
||||||
|
mIntegrity(aCopy.mIntegrity),
|
||||||
mComplete(aCopy.mComplete)
|
mComplete(aCopy.mComplete)
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
, mPrincipalSet(aCopy.mPrincipalSet)
|
, mPrincipalSet(aCopy.mPrincipalSet)
|
||||||
@ -1080,7 +1083,26 @@ CSSStyleSheet::CSSStyleSheet(CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy)
|
|||||||
mScopeElement(nullptr),
|
mScopeElement(nullptr),
|
||||||
mRuleProcessors(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,
|
CSSStyleSheet::CSSStyleSheet(const CSSStyleSheet& aCopy,
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
#include "mozilla/net/ReferrerPolicy.h"
|
#include "mozilla/net/ReferrerPolicy.h"
|
||||||
|
#include "mozilla/dom/SRIMetadata.h"
|
||||||
|
|
||||||
class CSSRuleListImpl;
|
class CSSRuleListImpl;
|
||||||
class nsCSSRuleProcessor;
|
class nsCSSRuleProcessor;
|
||||||
@ -63,7 +64,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
CSSStyleSheetInner(CSSStyleSheet* aPrimarySheet,
|
CSSStyleSheetInner(CSSStyleSheet* aPrimarySheet,
|
||||||
CORSMode aCORSMode,
|
CORSMode aCORSMode,
|
||||||
ReferrerPolicy aReferrerPolicy);
|
ReferrerPolicy aReferrerPolicy,
|
||||||
|
const dom::SRIMetadata& aIntegrity);
|
||||||
CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
|
CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
|
||||||
CSSStyleSheet* aPrimarySheet);
|
CSSStyleSheet* aPrimarySheet);
|
||||||
~CSSStyleSheetInner();
|
~CSSStyleSheetInner();
|
||||||
@ -96,6 +98,7 @@ private:
|
|||||||
// The Referrer Policy of a stylesheet is used for its child sheets, so it is
|
// The Referrer Policy of a stylesheet is used for its child sheets, so it is
|
||||||
// stored here.
|
// stored here.
|
||||||
ReferrerPolicy mReferrerPolicy;
|
ReferrerPolicy mReferrerPolicy;
|
||||||
|
dom::SRIMetadata mIntegrity;
|
||||||
bool mComplete;
|
bool mComplete;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -123,6 +126,8 @@ class CSSStyleSheet final : public nsIStyleSheet,
|
|||||||
public:
|
public:
|
||||||
typedef net::ReferrerPolicy ReferrerPolicy;
|
typedef net::ReferrerPolicy ReferrerPolicy;
|
||||||
CSSStyleSheet(CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy);
|
CSSStyleSheet(CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy);
|
||||||
|
CSSStyleSheet(CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy,
|
||||||
|
const dom::SRIMetadata& aIntegrity);
|
||||||
|
|
||||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(CSSStyleSheet,
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(CSSStyleSheet,
|
||||||
@ -259,6 +264,9 @@ public:
|
|||||||
// Get this style sheet's Referrer Policy
|
// Get this style sheet's Referrer Policy
|
||||||
ReferrerPolicy GetReferrerPolicy() const { return mInner->mReferrerPolicy; }
|
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; }
|
dom::Element* GetScopeElement() const { return mScopeElement; }
|
||||||
void SetScopeElement(dom::Element* aScopeElement)
|
void SetScopeElement(dom::Element* aScopeElement)
|
||||||
{
|
{
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
#include "nsError.h"
|
#include "nsError.h"
|
||||||
|
|
||||||
#include "nsIContentSecurityPolicy.h"
|
#include "nsIContentSecurityPolicy.h"
|
||||||
|
#include "mozilla/dom/SRICheck.h"
|
||||||
|
|
||||||
#include "mozilla/dom/EncodingUtils.h"
|
#include "mozilla/dom/EncodingUtils.h"
|
||||||
using mozilla::dom::EncodingUtils;
|
using mozilla::dom::EncodingUtils;
|
||||||
@ -265,6 +266,16 @@ GetLoaderLog()
|
|||||||
return sLog;
|
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_ERROR(args) MOZ_LOG(GetLoaderLog(), mozilla::LogLevel::Error, args)
|
||||||
#define LOG_WARN(args) MOZ_LOG(GetLoaderLog(), mozilla::LogLevel::Warning, args)
|
#define LOG_WARN(args) MOZ_LOG(GetLoaderLog(), mozilla::LogLevel::Warning, args)
|
||||||
#define LOG_DEBUG(args) MOZ_LOG(GetLoaderLog(), mozilla::LogLevel::Debug, 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
|
// 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.
|
// the same mInner as mSheet and will thus get the same URI.
|
||||||
mSheet->SetURIs(channelURI, originalURI, channelURI);
|
mSheet->SetURIs(channelURI, originalURI, channelURI);
|
||||||
@ -1057,6 +1080,7 @@ Loader::CreateSheet(nsIURI* aURI,
|
|||||||
nsIPrincipal* aLoaderPrincipal,
|
nsIPrincipal* aLoaderPrincipal,
|
||||||
CORSMode aCORSMode,
|
CORSMode aCORSMode,
|
||||||
ReferrerPolicy aReferrerPolicy,
|
ReferrerPolicy aReferrerPolicy,
|
||||||
|
const nsAString& aIntegrity,
|
||||||
bool aSyncLoad,
|
bool aSyncLoad,
|
||||||
bool aHasAlternateRel,
|
bool aHasAlternateRel,
|
||||||
const nsAString& aTitle,
|
const nsAString& aTitle,
|
||||||
@ -1204,7 +1228,17 @@ Loader::CreateSheet(nsIURI* aURI,
|
|||||||
originalURI = 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->SetURIs(sheetURI, originalURI, baseURI);
|
||||||
sheet.forget(aSheet);
|
sheet.forget(aSheet);
|
||||||
}
|
}
|
||||||
@ -1415,6 +1449,8 @@ Loader::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
|
|||||||
triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
|
triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SRIMetadata sriMetadata = aLoadData->mSheet->GetIntegrity();
|
||||||
|
|
||||||
if (aLoadData->mSyncLoad) {
|
if (aLoadData->mSyncLoad) {
|
||||||
LOG((" Synchronous load"));
|
LOG((" Synchronous load"));
|
||||||
NS_ASSERTION(!aLoadData->mObserver, "Observer for a sync 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));
|
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
|
||||||
if (httpChannel) {
|
if (httpChannel) {
|
||||||
// send a minimal Accept header for text/css
|
// Send a minimal Accept header for text/css
|
||||||
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
|
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
|
||||||
NS_LITERAL_CSTRING("text/css,*/*;q=0.1"),
|
NS_LITERAL_CSTRING("text/css,*/*;q=0.1"),
|
||||||
false);
|
false);
|
||||||
@ -1932,8 +1968,10 @@ Loader::LoadInlineStyle(nsIContent* aElement,
|
|||||||
StyleSheetState state;
|
StyleSheetState state;
|
||||||
nsRefPtr<CSSStyleSheet> sheet;
|
nsRefPtr<CSSStyleSheet> sheet;
|
||||||
nsresult rv = CreateSheet(nullptr, aElement, nullptr, CORS_NONE,
|
nsresult rv = CreateSheet(nullptr, aElement, nullptr, CORS_NONE,
|
||||||
mDocument->GetReferrerPolicy(), false, false,
|
mDocument->GetReferrerPolicy(),
|
||||||
aTitle, state, aIsAlternate, getter_AddRefs(sheet));
|
EmptyString(), // no inline integrity checks
|
||||||
|
false, false, aTitle, state, aIsAlternate,
|
||||||
|
getter_AddRefs(sheet));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
NS_ASSERTION(state == eSheetNeedsParser,
|
NS_ASSERTION(state == eSheetNeedsParser,
|
||||||
"Inline sheets should not be cached");
|
"Inline sheets should not be cached");
|
||||||
@ -1979,6 +2017,7 @@ Loader::LoadStyleLink(nsIContent* aElement,
|
|||||||
bool aHasAlternateRel,
|
bool aHasAlternateRel,
|
||||||
CORSMode aCORSMode,
|
CORSMode aCORSMode,
|
||||||
ReferrerPolicy aReferrerPolicy,
|
ReferrerPolicy aReferrerPolicy,
|
||||||
|
const nsAString& aIntegrity,
|
||||||
nsICSSLoaderObserver* aObserver,
|
nsICSSLoaderObserver* aObserver,
|
||||||
bool* aIsAlternate)
|
bool* aIsAlternate)
|
||||||
{
|
{
|
||||||
@ -2013,7 +2052,7 @@ Loader::LoadStyleLink(nsIContent* aElement,
|
|||||||
StyleSheetState state;
|
StyleSheetState state;
|
||||||
nsRefPtr<CSSStyleSheet> sheet;
|
nsRefPtr<CSSStyleSheet> sheet;
|
||||||
rv = CreateSheet(aURL, aElement, principal, aCORSMode,
|
rv = CreateSheet(aURL, aElement, principal, aCORSMode,
|
||||||
aReferrerPolicy, false,
|
aReferrerPolicy, aIntegrity, false,
|
||||||
aHasAlternateRel, aTitle, state, aIsAlternate,
|
aHasAlternateRel, aTitle, state, aIsAlternate,
|
||||||
getter_AddRefs(sheet));
|
getter_AddRefs(sheet));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
@ -2177,6 +2216,7 @@ Loader::LoadChildSheet(CSSStyleSheet* aParentSheet,
|
|||||||
// For now, use CORS_NONE for child sheets
|
// For now, use CORS_NONE for child sheets
|
||||||
rv = CreateSheet(aURL, nullptr, principal, CORS_NONE,
|
rv = CreateSheet(aURL, nullptr, principal, CORS_NONE,
|
||||||
aParentSheet->GetReferrerPolicy(),
|
aParentSheet->GetReferrerPolicy(),
|
||||||
|
EmptyString(), // integrity is only checked on main sheet
|
||||||
parentData ? parentData->mSyncLoad : false,
|
parentData ? parentData->mSyncLoad : false,
|
||||||
false, empty, state, &isAlternate, getter_AddRefs(sheet));
|
false, empty, state, &isAlternate, getter_AddRefs(sheet));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
@ -2243,13 +2283,14 @@ Loader::LoadSheet(nsIURI* aURL,
|
|||||||
const nsCString& aCharset,
|
const nsCString& aCharset,
|
||||||
nsICSSLoaderObserver* aObserver,
|
nsICSSLoaderObserver* aObserver,
|
||||||
CORSMode aCORSMode,
|
CORSMode aCORSMode,
|
||||||
ReferrerPolicy aReferrerPolicy)
|
ReferrerPolicy aReferrerPolicy,
|
||||||
|
const nsAString& aIntegrity)
|
||||||
{
|
{
|
||||||
LOG(("css::Loader::LoadSheet(aURL, aObserver) api call"));
|
LOG(("css::Loader::LoadSheet(aURL, aObserver) api call"));
|
||||||
return InternalLoadNonDocumentSheet(aURL, false, false,
|
return InternalLoadNonDocumentSheet(aURL, false, false,
|
||||||
aOriginPrincipal, aCharset,
|
aOriginPrincipal, aCharset,
|
||||||
nullptr, aObserver, aCORSMode,
|
nullptr, aObserver, aCORSMode,
|
||||||
aReferrerPolicy);
|
aReferrerPolicy, aIntegrity);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -2261,7 +2302,8 @@ Loader::InternalLoadNonDocumentSheet(nsIURI* aURL,
|
|||||||
CSSStyleSheet** aSheet,
|
CSSStyleSheet** aSheet,
|
||||||
nsICSSLoaderObserver* aObserver,
|
nsICSSLoaderObserver* aObserver,
|
||||||
CORSMode aCORSMode,
|
CORSMode aCORSMode,
|
||||||
ReferrerPolicy aReferrerPolicy)
|
ReferrerPolicy aReferrerPolicy,
|
||||||
|
const nsAString& aIntegrity)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aURL, "Must have a URI to load");
|
NS_PRECONDITION(aURL, "Must have a URI to load");
|
||||||
NS_PRECONDITION(aSheet || aObserver, "Sheet and observer can't both be null");
|
NS_PRECONDITION(aSheet || aObserver, "Sheet and observer can't both be null");
|
||||||
@ -2292,7 +2334,7 @@ Loader::InternalLoadNonDocumentSheet(nsIURI* aURL,
|
|||||||
const nsSubstring& empty = EmptyString();
|
const nsSubstring& empty = EmptyString();
|
||||||
|
|
||||||
rv = CreateSheet(aURL, nullptr, aOriginPrincipal, aCORSMode,
|
rv = CreateSheet(aURL, nullptr, aOriginPrincipal, aCORSMode,
|
||||||
aReferrerPolicy, syncLoad, false,
|
aReferrerPolicy, aIntegrity, syncLoad, false,
|
||||||
empty, state, &isAlternate, getter_AddRefs(sheet));
|
empty, state, &isAlternate, getter_AddRefs(sheet));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
@ -223,6 +223,7 @@ public:
|
|||||||
bool aHasAlternateRel,
|
bool aHasAlternateRel,
|
||||||
CORSMode aCORSMode,
|
CORSMode aCORSMode,
|
||||||
ReferrerPolicy aReferrerPolicy,
|
ReferrerPolicy aReferrerPolicy,
|
||||||
|
const nsAString& aIntegrity,
|
||||||
nsICSSLoaderObserver* aObserver,
|
nsICSSLoaderObserver* aObserver,
|
||||||
bool* aIsAlternate);
|
bool* aIsAlternate);
|
||||||
|
|
||||||
@ -320,7 +321,8 @@ public:
|
|||||||
const nsCString& aCharset,
|
const nsCString& aCharset,
|
||||||
nsICSSLoaderObserver* aObserver,
|
nsICSSLoaderObserver* aObserver,
|
||||||
CORSMode aCORSMode = CORS_NONE,
|
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
|
* Stop loading all sheets. All nsICSSLoaderObservers involved will be
|
||||||
@ -417,6 +419,7 @@ private:
|
|||||||
nsIPrincipal* aLoaderPrincipal,
|
nsIPrincipal* aLoaderPrincipal,
|
||||||
CORSMode aCORSMode,
|
CORSMode aCORSMode,
|
||||||
ReferrerPolicy aReferrerPolicy,
|
ReferrerPolicy aReferrerPolicy,
|
||||||
|
const nsAString& aIntegrity,
|
||||||
bool aSyncLoad,
|
bool aSyncLoad,
|
||||||
bool aHasAlternateRel,
|
bool aHasAlternateRel,
|
||||||
const nsAString& aTitle,
|
const nsAString& aTitle,
|
||||||
@ -450,7 +453,8 @@ private:
|
|||||||
CSSStyleSheet** aSheet,
|
CSSStyleSheet** aSheet,
|
||||||
nsICSSLoaderObserver* aObserver,
|
nsICSSLoaderObserver* aObserver,
|
||||||
CORSMode aCORSMode = CORS_NONE,
|
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
|
// 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
|
// 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_active_content", false);
|
||||||
pref("security.mixed_content.block_display_content", false);
|
pref("security.mixed_content.block_display_content", false);
|
||||||
|
|
||||||
|
// Sub-resource integrity
|
||||||
|
pref("security.sri.enable", false);
|
||||||
|
|
||||||
// Disable pinning checks by default.
|
// Disable pinning checks by default.
|
||||||
pref("security.cert_pinning.enforcement_level", 0);
|
pref("security.cert_pinning.enforcement_level", 0);
|
||||||
// Do not process hpkp headers rooted by not built in roots by default.
|
// Do not process hpkp headers rooted by not built in roots by default.
|
||||||
|
@ -45,14 +45,14 @@ nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor)
|
|||||||
break;
|
break;
|
||||||
case eSpeculativeLoadScript:
|
case eSpeculativeLoadScript:
|
||||||
aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSource,
|
aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSource,
|
||||||
mCrossOrigin, false);
|
mCrossOrigin, mIntegrity, false);
|
||||||
break;
|
break;
|
||||||
case eSpeculativeLoadScriptFromHead:
|
case eSpeculativeLoadScriptFromHead:
|
||||||
aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSource,
|
aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSource,
|
||||||
mCrossOrigin, true);
|
mCrossOrigin, mIntegrity, true);
|
||||||
break;
|
break;
|
||||||
case eSpeculativeLoadStyle:
|
case eSpeculativeLoadStyle:
|
||||||
aExecutor->PreloadStyle(mUrl, mCharset, mCrossOrigin);
|
aExecutor->PreloadStyle(mUrl, mCharset, mCrossOrigin, mIntegrity);
|
||||||
break;
|
break;
|
||||||
case eSpeculativeLoadManifest:
|
case eSpeculativeLoadManifest:
|
||||||
aExecutor->ProcessOfflineManifest(mUrl);
|
aExecutor->ProcessOfflineManifest(mUrl);
|
||||||
|
@ -105,6 +105,7 @@ class nsHtml5SpeculativeLoad {
|
|||||||
const nsAString& aCharset,
|
const nsAString& aCharset,
|
||||||
const nsAString& aType,
|
const nsAString& aType,
|
||||||
const nsAString& aCrossOrigin,
|
const nsAString& aCrossOrigin,
|
||||||
|
const nsAString& aIntegrity,
|
||||||
bool aParserInHead)
|
bool aParserInHead)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
|
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
|
||||||
@ -115,10 +116,12 @@ class nsHtml5SpeculativeLoad {
|
|||||||
mCharset.Assign(aCharset);
|
mCharset.Assign(aCharset);
|
||||||
mTypeOrCharsetSource.Assign(aType);
|
mTypeOrCharsetSource.Assign(aType);
|
||||||
mCrossOrigin.Assign(aCrossOrigin);
|
mCrossOrigin.Assign(aCrossOrigin);
|
||||||
|
mIntegrity.Assign(aIntegrity);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void InitStyle(const nsAString& aUrl, const nsAString& aCharset,
|
inline void InitStyle(const nsAString& aUrl, const nsAString& aCharset,
|
||||||
const nsAString& aCrossOrigin)
|
const nsAString& aCrossOrigin,
|
||||||
|
const nsAString& aIntegrity)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
|
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
|
||||||
"Trying to reinitialize a speculative load!");
|
"Trying to reinitialize a speculative load!");
|
||||||
@ -126,6 +129,7 @@ class nsHtml5SpeculativeLoad {
|
|||||||
mUrl.Assign(aUrl);
|
mUrl.Assign(aUrl);
|
||||||
mCharset.Assign(aCharset);
|
mCharset.Assign(aCharset);
|
||||||
mCrossOrigin.Assign(aCrossOrigin);
|
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.
|
* attribute. If the attribute is not set, this will be a void string.
|
||||||
*/
|
*/
|
||||||
nsString mMedia;
|
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
|
#endif // nsHtml5SpeculativeLoad_h
|
||||||
|
@ -165,11 +165,14 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
|
|||||||
nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
|
nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
|
||||||
nsString* crossOrigin =
|
nsString* crossOrigin =
|
||||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
||||||
|
nsString* integrity =
|
||||||
|
aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
|
||||||
mSpeculativeLoadQueue.AppendElement()->
|
mSpeculativeLoadQueue.AppendElement()->
|
||||||
InitScript(*url,
|
InitScript(*url,
|
||||||
(charset) ? *charset : EmptyString(),
|
(charset) ? *charset : EmptyString(),
|
||||||
(type) ? *type : EmptyString(),
|
(type) ? *type : EmptyString(),
|
||||||
(crossOrigin) ? *crossOrigin : NullString(),
|
(crossOrigin) ? *crossOrigin : NullString(),
|
||||||
|
(integrity) ? *integrity : NullString(),
|
||||||
mode == NS_HTML5TREE_BUILDER_IN_HEAD);
|
mode == NS_HTML5TREE_BUILDER_IN_HEAD);
|
||||||
mCurrentHtmlScriptIsAsyncOrDefer =
|
mCurrentHtmlScriptIsAsyncOrDefer =
|
||||||
aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
|
aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
|
||||||
@ -186,10 +189,13 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
|
|||||||
nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
|
nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
|
||||||
nsString* crossOrigin =
|
nsString* crossOrigin =
|
||||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
||||||
|
nsString* integrity =
|
||||||
|
aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
|
||||||
mSpeculativeLoadQueue.AppendElement()->
|
mSpeculativeLoadQueue.AppendElement()->
|
||||||
InitStyle(*url,
|
InitStyle(*url,
|
||||||
(charset) ? *charset : EmptyString(),
|
(charset) ? *charset : EmptyString(),
|
||||||
(crossOrigin) ? *crossOrigin : NullString());
|
(crossOrigin) ? *crossOrigin : NullString(),
|
||||||
|
(integrity) ? *integrity : NullString());
|
||||||
}
|
}
|
||||||
} else if (rel->LowerCaseEqualsASCII("preconnect")) {
|
} else if (rel->LowerCaseEqualsASCII("preconnect")) {
|
||||||
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
|
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* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
|
||||||
nsString* crossOrigin =
|
nsString* crossOrigin =
|
||||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
||||||
|
nsString* integrity =
|
||||||
|
aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
|
||||||
mSpeculativeLoadQueue.AppendElement()->
|
mSpeculativeLoadQueue.AppendElement()->
|
||||||
InitScript(*url,
|
InitScript(*url,
|
||||||
EmptyString(),
|
EmptyString(),
|
||||||
(type) ? *type : EmptyString(),
|
(type) ? *type : EmptyString(),
|
||||||
(crossOrigin) ? *crossOrigin : NullString(),
|
(crossOrigin) ? *crossOrigin : NullString(),
|
||||||
|
(integrity) ? *integrity : NullString(),
|
||||||
mode == NS_HTML5TREE_BUILDER_IN_HEAD);
|
mode == NS_HTML5TREE_BUILDER_IN_HEAD);
|
||||||
}
|
}
|
||||||
} else if (nsHtml5Atoms::style == aName) {
|
} else if (nsHtml5Atoms::style == aName) {
|
||||||
@ -272,9 +281,12 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
|
|||||||
if (url) {
|
if (url) {
|
||||||
nsString* crossOrigin =
|
nsString* crossOrigin =
|
||||||
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
|
||||||
|
nsString* integrity =
|
||||||
|
aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
|
||||||
mSpeculativeLoadQueue.AppendElement()->
|
mSpeculativeLoadQueue.AppendElement()->
|
||||||
InitStyle(*url, EmptyString(),
|
InitStyle(*url, EmptyString(),
|
||||||
(crossOrigin) ? *crossOrigin : NullString());
|
(crossOrigin) ? *crossOrigin : NullString(),
|
||||||
|
(integrity) ? *integrity : NullString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -911,6 +911,7 @@ nsHtml5TreeOpExecutor::PreloadScript(const nsAString& aURL,
|
|||||||
const nsAString& aCharset,
|
const nsAString& aCharset,
|
||||||
const nsAString& aType,
|
const nsAString& aType,
|
||||||
const nsAString& aCrossOrigin,
|
const nsAString& aCrossOrigin,
|
||||||
|
const nsAString& aIntegrity,
|
||||||
bool aScriptFromHead)
|
bool aScriptFromHead)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIURI> uri = ConvertIfNotPreloadedYet(aURL);
|
nsCOMPtr<nsIURI> uri = ConvertIfNotPreloadedYet(aURL);
|
||||||
@ -918,21 +919,22 @@ nsHtml5TreeOpExecutor::PreloadScript(const nsAString& aURL,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mDocument->ScriptLoader()->PreloadURI(uri, aCharset, aType, aCrossOrigin,
|
mDocument->ScriptLoader()->PreloadURI(uri, aCharset, aType, aCrossOrigin,
|
||||||
aScriptFromHead,
|
aIntegrity, aScriptFromHead,
|
||||||
mSpeculationReferrerPolicy);
|
mSpeculationReferrerPolicy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsHtml5TreeOpExecutor::PreloadStyle(const nsAString& aURL,
|
nsHtml5TreeOpExecutor::PreloadStyle(const nsAString& aURL,
|
||||||
const nsAString& aCharset,
|
const nsAString& aCharset,
|
||||||
const nsAString& aCrossOrigin)
|
const nsAString& aCrossOrigin,
|
||||||
|
const nsAString& aIntegrity)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIURI> uri = ConvertIfNotPreloadedYet(aURL);
|
nsCOMPtr<nsIURI> uri = ConvertIfNotPreloadedYet(aURL);
|
||||||
if (!uri) {
|
if (!uri) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mDocument->PreloadStyle(uri, aCharset, aCrossOrigin,
|
mDocument->PreloadStyle(uri, aCharset, aCrossOrigin,
|
||||||
mSpeculationReferrerPolicy);
|
mSpeculationReferrerPolicy, aIntegrity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -248,10 +248,12 @@ class nsHtml5TreeOpExecutor final : public nsHtml5DocumentBuilder,
|
|||||||
const nsAString& aCharset,
|
const nsAString& aCharset,
|
||||||
const nsAString& aType,
|
const nsAString& aType,
|
||||||
const nsAString& aCrossOrigin,
|
const nsAString& aCrossOrigin,
|
||||||
|
const nsAString& aIntegrity,
|
||||||
bool aScriptFromHead);
|
bool aScriptFromHead);
|
||||||
|
|
||||||
void PreloadStyle(const nsAString& aURL, const nsAString& aCharset,
|
void PreloadStyle(const nsAString& aURL, const nsAString& aCharset,
|
||||||
const nsAString& aCrossOrigin);
|
const nsAString& aCrossOrigin,
|
||||||
|
const nsAString& aIntegrity);
|
||||||
|
|
||||||
void PreloadImage(const nsAString& aURL,
|
void PreloadImage(const nsAString& aURL,
|
||||||
const nsAString& aCrossOrigin,
|
const nsAString& aCrossOrigin,
|
||||||
|
@ -657,6 +657,11 @@
|
|||||||
ERROR(NS_ERROR_CSP_FORM_ACTION_VIOLATION, FAILURE(98)),
|
ERROR(NS_ERROR_CSP_FORM_ACTION_VIOLATION, FAILURE(98)),
|
||||||
ERROR(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION, FAILURE(99)),
|
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
|
/* CMS specific nsresult error codes. Note: the numbers used here correspond
|
||||||
* to the values in nsICMSMessageErrors.idl. */
|
* to the values in nsICMSMessageErrors.idl. */
|
||||||
ERROR(NS_ERROR_CMS_VERIFY_NOT_SIGNED, FAILURE(1024)),
|
ERROR(NS_ERROR_CMS_VERIFY_NOT_SIGNED, FAILURE(1024)),
|
||||||
|
Loading…
Reference in New Issue
Block a user