summaryrefslogtreecommitdiff
path: root/Source/WebCore/page
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/page')
-rw-r--r--Source/WebCore/page/Performance.cpp2
-rw-r--r--Source/WebCore/page/Settings.in4
-rw-r--r--Source/WebCore/page/csp/ContentSecurityPolicy.cpp101
-rw-r--r--Source/WebCore/page/csp/ContentSecurityPolicy.h22
-rw-r--r--Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp94
-rw-r--r--Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.h10
-rw-r--r--Source/WebCore/page/csp/ContentSecurityPolicyHash.h69
-rw-r--r--Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp110
-rw-r--r--Source/WebCore/page/csp/ContentSecurityPolicySourceList.h20
-rw-r--r--Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.cpp10
-rw-r--r--Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.h4
-rw-r--r--Source/WebCore/page/qt/EventHandlerQt.cpp10
12 files changed, 410 insertions, 46 deletions
diff --git a/Source/WebCore/page/Performance.cpp b/Source/WebCore/page/Performance.cpp
index ed39a1d15..1c491da5d 100644
--- a/Source/WebCore/page/Performance.cpp
+++ b/Source/WebCore/page/Performance.cpp
@@ -233,7 +233,7 @@ void Performance::webkitClearMeasures(const String& measureName)
double Performance::now() const
{
double nowSeconds = monotonicallyIncreasingTime() - m_referenceTime;
- const double resolutionSeconds = 0.000005;
+ const double resolutionSeconds = 0.0001;
return 1000.0 * floor(nowSeconds / resolutionSeconds) * resolutionSeconds;
}
diff --git a/Source/WebCore/page/Settings.in b/Source/WebCore/page/Settings.in
index 84a9f0cd0..74d9e0709 100644
--- a/Source/WebCore/page/Settings.in
+++ b/Source/WebCore/page/Settings.in
@@ -79,7 +79,6 @@ needsSiteSpecificQuirks initial=false
domTimersThrottlingEnabled initial=true
webArchiveDebugModeEnabled initial=false, conditional=WEB_ARCHIVE
localFileContentSniffingEnabled initial=false
-offlineStorageDatabaseEnabled initial=false
offlineWebApplicationCacheEnabled initial=false
enforceCSSMIMETypeInNoQuirksMode initial=true
usesEncodingDetector initial=false
@@ -91,6 +90,9 @@ acceleratedFiltersEnabled initial=false
useLegacyTextAlignPositionedElementBehavior initial=false
javaScriptRuntimeFlags type=JSC::RuntimeFlags
+# PLATFORM(QT) only
+offlineStorageDatabaseEnabled initial=true
+
# FIXME: This should really be disabled by default as it makes platforms that don't support the feature download files
# they can't use by. Leaving enabled for now to not change existing behavior.
downloadableBinaryFontsEnabled initial=true
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
index 19bf207fa..9e726d5fe 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
+++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
@@ -29,14 +29,17 @@
#include "ContentSecurityPolicyDirective.h"
#include "ContentSecurityPolicyDirectiveList.h"
+#include "ContentSecurityPolicyHash.h"
#include "ContentSecurityPolicySource.h"
#include "ContentSecurityPolicySourceList.h"
+#include "CryptoDigest.h"
#include "DOMStringList.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "FormData.h"
#include "FormDataList.h"
#include "Frame.h"
+#include "HTMLParserIdioms.h"
#include "InspectorInstrumentation.h"
#include "JSMainThreadExecState.h"
#include "ParsingUtilities.h"
@@ -45,6 +48,7 @@
#include "SchemeRegistry.h"
#include "SecurityOrigin.h"
#include "SecurityPolicyViolationEvent.h"
+#include "TextEncoding.h"
#include <inspector/InspectorValues.h>
#include <inspector/ScriptCallStack.h>
#include <inspector/ScriptCallStackFactory.h>
@@ -193,6 +197,48 @@ bool isAllowedByAllWithContext(const CSPDirectiveListVector& policies, const Str
return true;
}
+template<bool (ContentSecurityPolicyDirectiveList::*allowed)(const String& nonce) const>
+static bool isAllowedByAllWithNonce(const CSPDirectiveListVector& policies, const String& nonce)
+{
+ for (auto& policy : policies) {
+ if (!(policy.get()->*allowed)(nonce))
+ return false;
+ }
+ return true;
+}
+
+static CryptoDigest::Algorithm toCryptoDigestAlgorithm(ContentSecurityPolicyHashAlgorithm algorithm)
+{
+ switch (algorithm) {
+ case ContentSecurityPolicyHashAlgorithm::SHA_256:
+ return CryptoDigest::Algorithm::SHA_256;
+ case ContentSecurityPolicyHashAlgorithm::SHA_384:
+ return CryptoDigest::Algorithm::SHA_384;
+ case ContentSecurityPolicyHashAlgorithm::SHA_512:
+ return CryptoDigest::Algorithm::SHA_512;
+ }
+ ASSERT_NOT_REACHED();
+ return CryptoDigest::Algorithm::SHA_512;
+}
+
+template<bool (ContentSecurityPolicyDirectiveList::*allowed)(const ContentSecurityPolicyHash&) const>
+bool isAllowedByAllWithHashFromContent(const CSPDirectiveListVector& policies, const String& content, const TextEncoding& encoding, OptionSet<ContentSecurityPolicyHashAlgorithm> algorithms)
+{
+ // FIXME: Compute the digest with respect to the raw bytes received from the page.
+ // See <https://bugs.webkit.org/show_bug.cgi?id=155184>.
+ CString contentCString = encoding.encode(content, EntitiesForUnencodables);
+ for (auto algorithm : algorithms) {
+ auto cryptoDigest = CryptoDigest::create(toCryptoDigestAlgorithm(algorithm));
+ cryptoDigest->addBytes(contentCString.data(), contentCString.length());
+ Vector<uint8_t> digest = cryptoDigest->computeHash();
+ for (auto& policy : policies) {
+ if ((policy.get()->*allowed)(std::make_pair(algorithm, digest)))
+ return true;
+ }
+ }
+ return false;
+}
+
template<bool (ContentSecurityPolicyDirectiveList::*allowFromURL)(const URL&, ContentSecurityPolicy::ReportingStatus) const>
bool isAllowedByAllWithURL(const CSPDirectiveListVector& policies, const URL& url, ContentSecurityPolicy::ReportingStatus reportingStatus)
{
@@ -216,14 +262,61 @@ bool ContentSecurityPolicy::allowInlineEventHandlers(const String& contextURL, c
return overrideContentSecurityPolicy || isAllowedByAllWithContext<&ContentSecurityPolicyDirectiveList::allowInlineEventHandlers>(m_policies, contextURL, contextLine, reportingStatus);
}
-bool ContentSecurityPolicy::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+// FIXME: We should compute the document encoding once and cache it instead of computing it on each invocation.
+const TextEncoding& ContentSecurityPolicy::documentEncoding() const
{
- return overrideContentSecurityPolicy || isAllowedByAllWithContext<&ContentSecurityPolicyDirectiveList::allowInlineScript>(m_policies, contextURL, contextLine, reportingStatus);
+ if (!is<Document>(m_scriptExecutionContext))
+ return UTF8Encoding();
+ Document& document = downcast<Document>(*m_scriptExecutionContext);
+ if (TextResourceDecoder* decoder = document.decoder())
+ return decoder->encoding();
+ return UTF8Encoding();
}
-bool ContentSecurityPolicy::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+bool ContentSecurityPolicy::allowScriptWithNonce(const String& nonce, bool overrideContentSecurityPolicy) const
{
- return overrideContentSecurityPolicy || m_overrideInlineStyleAllowed || isAllowedByAllWithContext<&ContentSecurityPolicyDirectiveList::allowInlineStyle>(m_policies, contextURL, contextLine, reportingStatus);
+ if (overrideContentSecurityPolicy)
+ return true;
+ String strippedNonce = stripLeadingAndTrailingHTMLSpaces(nonce);
+ if (strippedNonce.isEmpty())
+ return false;
+ if (isAllowedByAllWithNonce<&ContentSecurityPolicyDirectiveList::allowScriptWithNonce>(m_policies, strippedNonce))
+ return true;
+ return false;
+}
+
+bool ContentSecurityPolicy::allowStyleWithNonce(const String& nonce, bool overrideContentSecurityPolicy) const
+{
+ if (overrideContentSecurityPolicy)
+ return true;
+ String strippedNonce = stripLeadingAndTrailingHTMLSpaces(nonce);
+ if (strippedNonce.isEmpty())
+ return false;
+ if (isAllowedByAllWithNonce<&ContentSecurityPolicyDirectiveList::allowStyleWithNonce>(m_policies, strippedNonce))
+ return true;
+ return false;
+}
+
+bool ContentSecurityPolicy::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, const String& scriptContent, bool overrideContentSecurityPolicy, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ if (overrideContentSecurityPolicy)
+ return true;
+ if (!m_hashAlgorithmsForInlineScripts.isEmpty() && !scriptContent.isEmpty()
+ && isAllowedByAllWithHashFromContent<&ContentSecurityPolicyDirectiveList::allowInlineScriptWithHash>(m_policies, scriptContent, documentEncoding(), m_hashAlgorithmsForInlineScripts))
+ return true;
+ return isAllowedByAllWithContext<&ContentSecurityPolicyDirectiveList::allowInlineScript>(m_policies, contextURL, contextLine, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, const String& styleContent, bool overrideContentSecurityPolicy, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ if (overrideContentSecurityPolicy)
+ return true;
+ if (m_overrideInlineStyleAllowed)
+ return true;
+ if (!m_hashAlgorithmsForInlineStylesheets.isEmpty() && !styleContent.isEmpty()
+ && isAllowedByAllWithHashFromContent<&ContentSecurityPolicyDirectiveList::allowInlineStyleWithHash>(m_policies, styleContent, documentEncoding(), m_hashAlgorithmsForInlineStylesheets))
+ return true;
+ return isAllowedByAllWithContext<&ContentSecurityPolicyDirectiveList::allowInlineStyle>(m_policies, contextURL, contextLine, reportingStatus);
}
bool ContentSecurityPolicy::allowEval(JSC::ExecState* state, bool overrideContentSecurityPolicy, ContentSecurityPolicy::ReportingStatus reportingStatus) const
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.h b/Source/WebCore/page/csp/ContentSecurityPolicy.h
index 14c60f5c4..dcc05a173 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicy.h
+++ b/Source/WebCore/page/csp/ContentSecurityPolicy.h
@@ -29,6 +29,7 @@
#include "ContentSecurityPolicyResponseHeaders.h"
#include "ScriptState.h"
+#include <wtf/OptionSet.h>
#include <wtf/Vector.h>
#include <wtf/text/TextPosition.h>
@@ -43,8 +44,11 @@ class ContentSecurityPolicySource;
class DOMStringList;
class ScriptExecutionContext;
class SecurityOrigin;
+class TextEncoding;
class URL;
+enum class ContentSecurityPolicyHashAlgorithm;
+
typedef Vector<std::unique_ptr<ContentSecurityPolicyDirectiveList>> CSPDirectiveListVector;
typedef int SandboxFlags;
@@ -82,8 +86,10 @@ public:
};
bool allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy = false, ContentSecurityPolicy::ReportingStatus = ContentSecurityPolicy::ReportingStatus::SendReport) const;
bool allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy = false, ContentSecurityPolicy::ReportingStatus = ContentSecurityPolicy::ReportingStatus::SendReport) const;
- bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy = false, ContentSecurityPolicy::ReportingStatus = ContentSecurityPolicy::ReportingStatus::SendReport) const;
- bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy = false, ContentSecurityPolicy::ReportingStatus = ContentSecurityPolicy::ReportingStatus::SendReport) const;
+ bool allowScriptWithNonce(const String& nonce, bool overrideContentSecurityPolicy = false) const;
+ bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, const String& scriptContent, bool overrideContentSecurityPolicy = false, ContentSecurityPolicy::ReportingStatus = ContentSecurityPolicy::ReportingStatus::SendReport) const;
+ bool allowStyleWithNonce(const String& nonce, bool overrideContentSecurityPolicy = false) const;
+ bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, const String& styleContent, bool overrideContentSecurityPolicy = false, ContentSecurityPolicy::ReportingStatus = ContentSecurityPolicy::ReportingStatus::SendReport) const;
bool allowEval(JSC::ExecState* = nullptr, bool overrideContentSecurityPolicy = false, ContentSecurityPolicy::ReportingStatus = ContentSecurityPolicy::ReportingStatus::SendReport) const;
bool allowPluginType(const String& type, const String& typeAttribute, const URL&, bool overrideContentSecurityPolicy = false, ContentSecurityPolicy::ReportingStatus = ContentSecurityPolicy::ReportingStatus::SendReport) const;
bool allowScriptFromSource(const URL&, bool overrideContentSecurityPolicy = false, ContentSecurityPolicy::ReportingStatus = ContentSecurityPolicy::ReportingStatus::SendReport) const;
@@ -134,6 +140,14 @@ public:
void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const URL& blockedURL, const Vector<String>& reportURIs, const String& header, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), JSC::ExecState* = nullptr) const;
void reportBlockedScriptExecutionToInspector(const String& directiveText) const;
void enforceSandboxFlags(SandboxFlags sandboxFlags) { m_sandboxFlags |= sandboxFlags; }
+ void addHashAlgorithmsForInlineScripts(OptionSet<ContentSecurityPolicyHashAlgorithm> hashAlgorithmsForInlineScripts)
+ {
+ m_hashAlgorithmsForInlineScripts |= hashAlgorithmsForInlineScripts;
+ }
+ void addHashAlgorithmsForInlineStylesheets(OptionSet<ContentSecurityPolicyHashAlgorithm> hashAlgorithmsForInlineStylesheets)
+ {
+ m_hashAlgorithmsForInlineStylesheets |= hashAlgorithmsForInlineStylesheets;
+ }
// Used by ContentSecurityPolicySource
bool protocolMatchesSelf(const URL&) const;
@@ -145,6 +159,8 @@ private:
void didReceiveHeader(const String&, ContentSecurityPolicyHeaderType, ContentSecurityPolicy::PolicyFrom);
+ const TextEncoding& documentEncoding() const;
+
ScriptExecutionContext* m_scriptExecutionContext { nullptr };
std::unique_ptr<ContentSecurityPolicySource> m_selfSource;
String m_selfSourceProtocol;
@@ -152,6 +168,8 @@ private:
String m_lastPolicyEvalDisabledErrorMessage;
SandboxFlags m_sandboxFlags;
bool m_overrideInlineStyleAllowed { false };
+ OptionSet<ContentSecurityPolicyHashAlgorithm> m_hashAlgorithmsForInlineScripts;
+ OptionSet<ContentSecurityPolicyHashAlgorithm> m_hashAlgorithmsForInlineStylesheets;
};
}
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp b/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp
index 01cfa5134..47f5da456 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp
+++ b/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp
@@ -105,6 +105,40 @@ static bool isNotASCIISpace(UChar c)
return !isASCIISpace(c);
}
+static inline bool checkEval(ContentSecurityPolicySourceListDirective* directive)
+{
+ return !directive || directive->allowEval();
+}
+
+static inline bool checkInline(ContentSecurityPolicySourceListDirective* directive)
+{
+ return !directive || directive->allowInline();
+}
+
+static inline bool checkSource(ContentSecurityPolicySourceListDirective* directive, const URL& url)
+{
+ return !directive || directive->allows(url);
+}
+
+static inline bool checkHash(ContentSecurityPolicySourceListDirective* directive, const ContentSecurityPolicyHash& hash)
+{
+ return !directive || directive->allows(hash);
+}
+
+static inline bool checkNonce(ContentSecurityPolicySourceListDirective* directive, const String& nonce)
+{
+ return !directive || directive->allows(nonce);
+}
+
+static inline bool checkMediaType(ContentSecurityPolicyMediaListDirective* directive, const String& type, const String& typeAttribute)
+{
+ if (!directive)
+ return true;
+ if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type)
+ return false;
+ return directive->allows(type);
+}
+
ContentSecurityPolicyDirectiveList::ContentSecurityPolicyDirectiveList(ContentSecurityPolicy& policy, ContentSecurityPolicyHeaderType type)
: m_policy(policy)
, m_headerType(type)
@@ -120,7 +154,7 @@ std::unique_ptr<ContentSecurityPolicyDirectiveList> ContentSecurityPolicyDirecti
auto directives = std::make_unique<ContentSecurityPolicyDirectiveList>(policy, type);
directives->parse(header, from);
- if (!directives->checkEval(directives->operativeDirective(directives->m_scriptSrc.get()))) {
+ if (!checkEval(directives->operativeDirective(directives->m_scriptSrc.get()))) {
String message = makeString("Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: \"", directives->operativeDirective(directives->m_scriptSrc.get())->text(), "\".\n");
directives->setEvalDisabledErrorMessage(message);
}
@@ -137,30 +171,6 @@ void ContentSecurityPolicyDirectiveList::reportViolation(const String& directive
m_policy.reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header, contextURL, contextLine, state);
}
-bool ContentSecurityPolicyDirectiveList::checkEval(ContentSecurityPolicySourceListDirective* directive) const
-{
- return !directive || directive->allowEval();
-}
-
-bool ContentSecurityPolicyDirectiveList::checkInline(ContentSecurityPolicySourceListDirective* directive) const
-{
- return !directive || directive->allowInline();
-}
-
-bool ContentSecurityPolicyDirectiveList::checkSource(ContentSecurityPolicySourceListDirective* directive, const URL& url) const
-{
- return !directive || directive->allows(url);
-}
-
-bool ContentSecurityPolicyDirectiveList::checkMediaType(ContentSecurityPolicyMediaListDirective* directive, const String& type, const String& typeAttribute) const
-{
- if (!directive)
- return true;
- if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type)
- return false;
- return directive->allows(type);
-}
-
ContentSecurityPolicySourceListDirective* ContentSecurityPolicyDirectiveList::operativeDirective(ContentSecurityPolicySourceListDirective* directive) const
{
return directive ? directive : m_defaultSrc.get();
@@ -278,6 +288,16 @@ bool ContentSecurityPolicyDirectiveList::allowInlineScript(const String& context
return m_reportOnly || checkInline(operativeDirective(m_scriptSrc.get()));
}
+bool ContentSecurityPolicyDirectiveList::allowInlineScriptWithHash(const ContentSecurityPolicyHash& hash) const
+{
+ return checkHash(operativeDirective(m_scriptSrc.get()), hash);
+}
+
+bool ContentSecurityPolicyDirectiveList::allowScriptWithNonce(const String& nonce) const
+{
+ return checkNonce(operativeDirective(m_scriptSrc.get()), nonce);
+}
+
bool ContentSecurityPolicyDirectiveList::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
static NeverDestroyed<String> consoleMessage(ASCIILiteral("Refused to apply inline style because it violates the following Content Security Policy directive: "));
@@ -286,6 +306,16 @@ bool ContentSecurityPolicyDirectiveList::allowInlineStyle(const String& contextU
return m_reportOnly || checkInline(operativeDirective(m_styleSrc.get()));
}
+bool ContentSecurityPolicyDirectiveList::allowInlineStyleWithHash(const ContentSecurityPolicyHash& hash) const
+{
+ return checkHash(operativeDirective(m_styleSrc.get()), hash);
+}
+
+bool ContentSecurityPolicyDirectiveList::allowStyleWithNonce(const String& nonce) const
+{
+ return checkNonce(operativeDirective(m_styleSrc.get()), nonce);
+}
+
bool ContentSecurityPolicyDirectiveList::allowEval(JSC::ExecState* state, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
static NeverDestroyed<String> consoleMessage(ASCIILiteral("Refused to evaluate script because it violates the following Content Security Policy directive: "));
@@ -579,18 +609,22 @@ void ContentSecurityPolicyDirectiveList::addDirective(const String& name, const
{
ASSERT(!name.isEmpty());
- if (equalLettersIgnoringASCIICase(name, defaultSrc))
+ if (equalLettersIgnoringASCIICase(name, defaultSrc)) {
setCSPDirective<ContentSecurityPolicySourceListDirective>(name, value, m_defaultSrc);
- else if (equalLettersIgnoringASCIICase(name, scriptSrc))
+ m_policy.addHashAlgorithmsForInlineScripts(m_defaultSrc->hashAlgorithmsUsed());
+ m_policy.addHashAlgorithmsForInlineStylesheets(m_defaultSrc->hashAlgorithmsUsed());
+ } else if (equalLettersIgnoringASCIICase(name, scriptSrc)) {
setCSPDirective<ContentSecurityPolicySourceListDirective>(name, value, m_scriptSrc);
- else if (equalLettersIgnoringASCIICase(name, objectSrc))
+ m_policy.addHashAlgorithmsForInlineScripts(m_scriptSrc->hashAlgorithmsUsed());
+ } else if (equalLettersIgnoringASCIICase(name, styleSrc)) {
+ setCSPDirective<ContentSecurityPolicySourceListDirective>(name, value, m_styleSrc);
+ m_policy.addHashAlgorithmsForInlineStylesheets(m_styleSrc->hashAlgorithmsUsed());
+ } else if (equalLettersIgnoringASCIICase(name, objectSrc))
setCSPDirective<ContentSecurityPolicySourceListDirective>(name, value, m_objectSrc);
else if (equalLettersIgnoringASCIICase(name, frameSrc))
setCSPDirective<ContentSecurityPolicySourceListDirective>(name, value, m_frameSrc);
else if (equalLettersIgnoringASCIICase(name, imgSrc))
setCSPDirective<ContentSecurityPolicySourceListDirective>(name, value, m_imgSrc);
- else if (equalLettersIgnoringASCIICase(name, styleSrc))
- setCSPDirective<ContentSecurityPolicySourceListDirective>(name, value, m_styleSrc);
else if (equalLettersIgnoringASCIICase(name, fontSrc))
setCSPDirective<ContentSecurityPolicySourceListDirective>(name, value, m_fontSrc);
else if (equalLettersIgnoringASCIICase(name, mediaSrc))
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.h b/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.h
index 2a98b2d09..997c2a5a6 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.h
+++ b/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.h
@@ -28,6 +28,7 @@
#define ContentSecurityPolicyDirectiveList_h
#include "ContentSecurityPolicy.h"
+#include "ContentSecurityPolicyHash.h"
#include "ContentSecurityPolicyMediaListDirective.h"
#include "ContentSecurityPolicySourceListDirective.h"
#include "URL.h"
@@ -50,7 +51,11 @@ public:
bool allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
bool allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowInlineScriptWithHash(const ContentSecurityPolicyHash&) const;
+ bool allowScriptWithNonce(const String& nonce) const;
bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowInlineStyleWithHash(const ContentSecurityPolicyHash&) const;
+ bool allowStyleWithNonce(const String& nonce) const;
bool allowEval(JSC::ExecState*, ContentSecurityPolicy::ReportingStatus) const;
bool allowPluginType(const String& type, const String& typeAttribute, const URL&, ContentSecurityPolicy::ReportingStatus) const;
@@ -87,11 +92,6 @@ private:
ContentSecurityPolicySourceListDirective* operativeDirective(ContentSecurityPolicySourceListDirective*) const;
void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const URL& blockedURL = URL(), const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), JSC::ExecState* = nullptr) const;
- bool checkEval(ContentSecurityPolicySourceListDirective*) const;
- bool checkInline(ContentSecurityPolicySourceListDirective*) const;
- bool checkSource(ContentSecurityPolicySourceListDirective*, const URL&) const;
- bool checkMediaType(ContentSecurityPolicyMediaListDirective*, const String& type, const String& typeAttribute) const;
-
void setEvalDisabledErrorMessage(const String& errorMessage) { m_evalDisabledErrorMessage = errorMessage; }
bool checkEvalAndReportViolation(ContentSecurityPolicySourceListDirective*, const String& consoleMessage, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), JSC::ExecState* = nullptr) const;
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicyHash.h b/Source/WebCore/page/csp/ContentSecurityPolicyHash.h
new file mode 100644
index 000000000..12a94f261
--- /dev/null
+++ b/Source/WebCore/page/csp/ContentSecurityPolicyHash.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ContentSecurityPolicyHash_h
+#define ContentSecurityPolicyHash_h
+
+#include <wtf/HashTraits.h>
+#include <wtf/Hasher.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+// Keep this synchronized with the constant maximumContentSecurityPolicyDigestLength below.
+enum class ContentSecurityPolicyHashAlgorithm {
+ SHA_256 = 1 << 0,
+ SHA_384 = 1 << 1,
+ SHA_512 = 1 << 2,
+};
+
+const size_t maximumContentSecurityPolicyDigestLength = 64; // bytes to hold SHA-512 digest
+
+typedef Vector<uint8_t> ContentSecurityPolicyDigest;
+typedef std::pair<ContentSecurityPolicyHashAlgorithm, ContentSecurityPolicyDigest> ContentSecurityPolicyHash;
+
+}
+
+namespace WTF {
+
+template<> struct DefaultHash<WebCore::ContentSecurityPolicyHashAlgorithm> { typedef IntHash<WebCore::ContentSecurityPolicyHashAlgorithm> Hash; };
+template<> struct HashTraits<WebCore::ContentSecurityPolicyHashAlgorithm> : StrongEnumHashTraits<WebCore::ContentSecurityPolicyHashAlgorithm> { };
+template<> struct DefaultHash<WebCore::ContentSecurityPolicyDigest> {
+ struct Hash {
+ static unsigned hash(const WebCore::ContentSecurityPolicyDigest& digest)
+ {
+ return StringHasher::computeHashAndMaskTop8Bits(digest.data(), digest.size());
+ }
+ static bool equal(const WebCore::ContentSecurityPolicyDigest& a, const WebCore::ContentSecurityPolicyDigest& b)
+ {
+ return a == b;
+ }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+};
+
+}
+
+#endif // ContentSecurityPolicyHash_h
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp b/Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp
index 408b40e2b..8044ae8bf 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp
+++ b/Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp
@@ -33,6 +33,8 @@
#include "SecurityOrigin.h"
#include "URL.h"
#include <wtf/ASCIICType.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/Base64.h>
namespace WebCore {
@@ -125,6 +127,16 @@ bool ContentSecurityPolicySourceList::matches(const URL& url)
return false;
}
+bool ContentSecurityPolicySourceList::matches(const ContentSecurityPolicyHash& hash) const
+{
+ return m_hashes.contains(hash);
+}
+
+bool ContentSecurityPolicySourceList::matches(const String& nonce) const
+{
+ return m_nonces.contains(nonce);
+}
+
// source-list = *WSP [ source *( 1*WSP source ) *WSP ]
// / *WSP "'none'" *WSP
//
@@ -145,6 +157,12 @@ void ContentSecurityPolicySourceList::parse(const UChar* begin, const UChar* end
bool hostHasWildcard = false;
bool portHasWildcard = false;
+ if (parseNonceSource(beginSource, position))
+ continue;
+
+ if (parseHashSource(beginSource, position))
+ continue;
+
if (parseSource(beginSource, position, scheme, host, port, path, hostHasWildcard, portHasWildcard)) {
// Wildcard hosts and keyword sources ('self', 'unsafe-inline',
// etc.) aren't stored in m_list, but as attributes on the source
@@ -385,4 +403,96 @@ bool ContentSecurityPolicySourceList::parsePort(const UChar* begin, const UChar*
return ok;
}
+static bool isBase64Character(UChar c)
+{
+ return isASCIIAlphanumeric(c) || c == '+' || c == '/' || c == '-' || c == '_';
+}
+
+// Match Blink's behavior of allowing an equal sign to appear anywhere in the value of the nonce
+// even though this does not match the behavior of Content Security Policy Level 3 spec.,
+// <https://w3c.github.io/webappsec-csp/> (29 February 2016).
+static bool isNonceCharacter(UChar c)
+{
+ return isBase64Character(c) || c == '=';
+}
+
+// nonce-source = "'nonce-" nonce-value "'"
+// nonce-value = base64-value
+bool ContentSecurityPolicySourceList::parseNonceSource(const UChar* begin, const UChar* end)
+{
+ static NeverDestroyed<String> noncePrefix("'nonce-", String::ConstructFromLiteral);
+ if (!StringView(begin, end - begin).startsWithIgnoringASCIICase(noncePrefix.get()))
+ return false;
+ const UChar* position = begin + noncePrefix.get().length();
+ const UChar* beginNonceValue = position;
+ skipWhile<UChar, isNonceCharacter>(position, end);
+ if (position >= end || position == beginNonceValue || *position != '\'')
+ return false;
+ m_nonces.add(String(beginNonceValue, position - beginNonceValue));
+ return true;
+}
+
+static bool parseHashAlgorithmAdvancingPosition(const UChar*& position, size_t length, ContentSecurityPolicyHashAlgorithm& algorithm)
+{
+ static struct {
+ NeverDestroyed<String> label;
+ ContentSecurityPolicyHashAlgorithm algorithm;
+ } labelToHashAlgorithmTable[] {
+ { ASCIILiteral("sha256"), ContentSecurityPolicyHashAlgorithm::SHA_256 },
+ { ASCIILiteral("sha384"), ContentSecurityPolicyHashAlgorithm::SHA_384 },
+ { ASCIILiteral("sha512"), ContentSecurityPolicyHashAlgorithm::SHA_512 },
+ };
+
+ StringView stringView(position, length);
+ for (auto& entry : labelToHashAlgorithmTable) {
+ String& label = entry.label.get();
+ if (!stringView.startsWithIgnoringASCIICase(label))
+ continue;
+ position += label.length();
+ algorithm = entry.algorithm;
+ return true;
+ }
+ return false;
+}
+
+// hash-source = "'" hash-algorithm "-" base64-value "'"
+// hash-algorithm = "sha256" / "sha384" / "sha512"
+// base64-value = 1*( ALPHA / DIGIT / "+" / "/" / "-" / "_" )*2( "=" )
+bool ContentSecurityPolicySourceList::parseHashSource(const UChar* begin, const UChar* end)
+{
+ if (begin == end)
+ return false;
+
+ const UChar* position = begin;
+ if (!skipExactly<UChar>(position, end, '\''))
+ return false;
+
+ ContentSecurityPolicyHashAlgorithm algorithm;
+ if (!parseHashAlgorithmAdvancingPosition(position, end - position, algorithm))
+ return false;
+
+ if (!skipExactly<UChar>(position, end, '-'))
+ return false;
+
+ const UChar* beginHashValue = position;
+ skipWhile<UChar, isBase64Character>(position, end);
+ skipExactly<UChar>(position, end, '=');
+ skipExactly<UChar>(position, end, '=');
+ if (position >= end || position == beginHashValue || *position != '\'')
+ return false;
+ Vector<uint8_t> digest;
+ StringView hashValue(beginHashValue, position - beginHashValue); // base64url or base64 encoded
+ // FIXME: Normalize Base64URL to Base64 instead of decoding twice. See <https://bugs.webkit.org/show_bug.cgi?id=155186>.
+ if (!base64Decode(hashValue.toStringWithoutCopying(), digest, Base64ValidatePadding)) {
+ if (!base64URLDecode(hashValue.toStringWithoutCopying(), digest))
+ return false;
+ }
+ if (digest.size() > maximumContentSecurityPolicyDigestLength)
+ return false;
+
+ m_hashes.add(std::make_pair(algorithm, digest));
+ m_hashAlgorithmsUsed |= algorithm;
+ return true;
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicySourceList.h b/Source/WebCore/page/csp/ContentSecurityPolicySourceList.h
index fdb9b7e09..811b6cec1 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicySourceList.h
+++ b/Source/WebCore/page/csp/ContentSecurityPolicySourceList.h
@@ -27,8 +27,11 @@
#ifndef ContentSecurityPolicySourceList_h
#define ContentSecurityPolicySourceList_h
+#include "ContentSecurityPolicyHash.h"
#include "ContentSecurityPolicySource.h"
-#include <wtf/Vector.h>
+#include <wtf/HashSet.h>
+#include <wtf/OptionSet.h>
+#include <wtf/text/StringHash.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -41,8 +44,14 @@ public:
ContentSecurityPolicySourceList(const ContentSecurityPolicy&, const String& directiveName);
void parse(const String&);
+
bool matches(const URL&);
- bool allowInline() const { return m_allowInline; }
+ bool matches(const ContentSecurityPolicyHash&) const;
+ bool matches(const String& nonce) const;
+
+ OptionSet<ContentSecurityPolicyHashAlgorithm> hashAlgorithmsUsed() const { return m_hashAlgorithmsUsed; }
+
+ bool allowInline() const { return m_allowInline && m_hashes.isEmpty() && m_nonces.isEmpty(); }
bool allowEval() const { return m_allowEval; }
bool allowSelf() const { return m_allowSelf; }
@@ -55,10 +64,17 @@ private:
bool parsePort(const UChar* begin, const UChar* end, int& port, bool& portHasWildcard);
bool parsePath(const UChar* begin, const UChar* end, String& path);
+ bool parseNonceSource(const UChar* begin, const UChar* end);
+
bool isProtocolAllowedByStar(const URL&) const;
+ bool parseHashSource(const UChar* begin, const UChar* end);
+
const ContentSecurityPolicy& m_policy;
Vector<ContentSecurityPolicySource> m_list;
+ HashSet<String> m_nonces;
+ HashSet<ContentSecurityPolicyHash> m_hashes;
+ OptionSet<ContentSecurityPolicyHashAlgorithm> m_hashAlgorithmsUsed;
String m_directiveName;
bool m_allowSelf { false };
bool m_allowStar { false };
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.cpp b/Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.cpp
index 89133d4eb..4c4f11c42 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.cpp
+++ b/Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.cpp
@@ -47,4 +47,14 @@ bool ContentSecurityPolicySourceListDirective::allows(const URL& url)
return m_sourceList.matches(url);
}
+bool ContentSecurityPolicySourceListDirective::allows(const String& nonce) const
+{
+ return m_sourceList.matches(nonce);
+}
+
+bool ContentSecurityPolicySourceListDirective::allows(const ContentSecurityPolicyHash& hash) const
+{
+ return m_sourceList.matches(hash);
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.h b/Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.h
index 9d4e2114c..ac650052d 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.h
+++ b/Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.h
@@ -39,9 +39,13 @@ public:
ContentSecurityPolicySourceListDirective(const String& name, const String& value, const ContentSecurityPolicy&);
bool allows(const URL&);
+ bool allows(const ContentSecurityPolicyHash&) const;
+ bool allows(const String& nonce) const;
bool allowInline() const { return m_sourceList.allowInline(); }
bool allowEval() const { return m_sourceList.allowEval(); }
+ OptionSet<ContentSecurityPolicyHashAlgorithm> hashAlgorithmsUsed() const { return m_sourceList.hashAlgorithmsUsed(); }
+
private:
ContentSecurityPolicySourceList m_sourceList;
};
diff --git a/Source/WebCore/page/qt/EventHandlerQt.cpp b/Source/WebCore/page/qt/EventHandlerQt.cpp
index 240ea75eb..b717b1f54 100644
--- a/Source/WebCore/page/qt/EventHandlerQt.cpp
+++ b/Source/WebCore/page/qt/EventHandlerQt.cpp
@@ -49,6 +49,7 @@
#include "PlatformWheelEvent.h"
#include "RenderWidget.h"
#include "Scrollbar.h"
+#include <QCoreApplication>
namespace WebCore {
@@ -123,7 +124,14 @@ bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults&
unsigned EventHandler::accessKeyModifiers()
{
#if OS(DARWIN)
- return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
+ // On macOS, the ControlModifier value corresponds
+ // to the Command keys on the keyboard,
+ // and the MetaModifier value corresponds to the Control keys.
+ // See http://doc.qt.io/qt-5/qt.html#KeyboardModifier-enum
+ if (UNLIKELY(QCoreApplication::testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)))
+ return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
+ else
+ return PlatformEvent::MetaKey | PlatformEvent::AltKey;
#else
return PlatformEvent::AltKey;
#endif