summaryrefslogtreecommitdiffstats
path: root/dom/security/nsCSPParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/security/nsCSPParser.cpp')
-rw-r--r--dom/security/nsCSPParser.cpp159
1 files changed, 158 insertions, 1 deletions
diff --git a/dom/security/nsCSPParser.cpp b/dom/security/nsCSPParser.cpp
index 07812470a3..44c2131640 100644
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -8,6 +8,7 @@
#include "mozilla/TextUtils.h"
#include "mozilla/dom/Document.h"
#include "mozilla/Preferences.h"
+#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_security.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
@@ -19,6 +20,9 @@
#include "nsServiceManagerUtils.h"
#include "nsUnicharUtils.h"
+#include <cstdint>
+#include <utility>
+
using namespace mozilla;
using namespace mozilla::dom;
@@ -813,6 +817,142 @@ void nsCSPParser::sandboxFlagList(nsCSPDirective* aDir) {
mPolicy->addDirective(aDir);
}
+// https://w3c.github.io/trusted-types/dist/spec/#integration-with-content-security-policy
+static constexpr nsLiteralString kValidRequireTrustedTypesForDirectiveValue =
+ u"'script'"_ns;
+
+static bool IsValidRequireTrustedTypesForDirectiveValue(
+ const nsAString& aToken) {
+ return aToken.Equals(kValidRequireTrustedTypesForDirectiveValue);
+}
+
+void nsCSPParser::handleRequireTrustedTypesForDirective(nsCSPDirective* aDir) {
+ // "srcs" start at index 1. Here "srcs" should represent Trusted Types' sink
+ // groups
+ // (https://w3c.github.io/trusted-types/dist/spec/#require-trusted-types-for-csp-directive).
+
+ if (mCurDir.Length() != 2) {
+ nsString numberOfTokensStr;
+
+ // Casting is required to avoid ambiguous function calls on some platforms.
+ numberOfTokensStr.AppendInt(static_cast<uint64_t>(mCurDir.Length()));
+
+ AutoTArray<nsString, 1> numberOfTokensArr = {std::move(numberOfTokensStr)};
+ logWarningErrorToConsole(nsIScriptError::errorFlag,
+ "invalidNumberOfTrustedTypesForDirectiveValues",
+ numberOfTokensArr);
+ return;
+ }
+
+ mCurToken = mCurDir.LastElement();
+
+ CSPPARSERLOG(
+ ("nsCSPParser::handleRequireTrustedTypesForDirective, mCurToken: %s",
+ NS_ConvertUTF16toUTF8(mCurToken).get()));
+
+ if (!IsValidRequireTrustedTypesForDirectiveValue(mCurToken)) {
+ AutoTArray<nsString, 1> token = {mCurToken};
+ logWarningErrorToConsole(nsIScriptError::errorFlag,
+ "invalidRequireTrustedTypesForDirectiveValue",
+ token);
+ return;
+ }
+
+ nsTArray<nsCSPBaseSrc*> srcs = {
+ new nsCSPRequireTrustedTypesForDirectiveValue(mCurToken)};
+
+ aDir->addSrcs(srcs);
+ mPolicy->addDirective(aDir);
+}
+
+static constexpr auto kTrustedTypesKeywordAllowDuplicates =
+ u"'allow-duplicates'"_ns;
+static constexpr auto kTrustedTypesKeywordNone = u"'none'"_ns;
+
+static bool IsValidTrustedTypesKeyword(const nsAString& aToken) {
+ // tt-keyword = "'allow-duplicates'" / "'none'"
+ return aToken.Equals(kTrustedTypesKeywordAllowDuplicates) ||
+ aToken.Equals(kTrustedTypesKeywordNone);
+}
+
+static bool IsValidTrustedTypesWildcard(const nsAString& aToken) {
+ // tt-wildcard = "*"
+ return aToken.Length() == 1 && aToken.First() == WILDCARD;
+}
+
+static bool IsValidTrustedTypesPolicyNameChar(char16_t aChar) {
+ // tt-policy-name = 1*( ALPHA / DIGIT / "-" / "#" / "=" / "_" / "/" / "@" /
+ // "." / "%")
+ return nsContentUtils::IsAlphanumeric(aChar) || aChar == DASH ||
+ aChar == NUMBER_SIGN || aChar == EQUALS || aChar == UNDERLINE ||
+ aChar == SLASH || aChar == ATSYMBOL || aChar == DOT ||
+ aChar == PERCENT_SIGN;
+}
+
+static bool IsValidTrustedTypesPolicyName(const nsAString& aToken) {
+ // tt-policy-name = 1*( ALPHA / DIGIT / "-" / "#" / "=" / "_" / "/" / "@" /
+ // "." / "%")
+
+ if (aToken.IsEmpty()) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < aToken.Length(); ++i) {
+ if (!IsValidTrustedTypesPolicyNameChar(aToken.CharAt(i))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// https://w3c.github.io/trusted-types/dist/spec/#trusted-types-csp-directive
+static bool IsValidTrustedTypesExpression(const nsAString& aToken) {
+ // tt-expression = tt-policy-name / tt-keyword / tt-wildcard
+ return IsValidTrustedTypesPolicyName(aToken) ||
+ IsValidTrustedTypesKeyword(aToken) ||
+ IsValidTrustedTypesWildcard(aToken);
+}
+
+void nsCSPParser::handleTrustedTypesDirective(nsCSPDirective* aDir) {
+ CSPPARSERLOG(("nsCSPParser::handleTrustedTypesDirective"));
+
+ nsTArray<nsCSPBaseSrc*> trustedTypesExpressions;
+
+ // "srcs" start and index 1. Here they should represent the tt-expressions
+ // (https://w3c.github.io/trusted-types/dist/spec/#trusted-types-csp-directive).
+ for (uint32_t i = 1; i < mCurDir.Length(); ++i) {
+ mCurToken = mCurDir[i];
+
+ CSPPARSERLOG(("nsCSPParser::handleTrustedTypesDirective, mCurToken: %s",
+ NS_ConvertUTF16toUTF8(mCurToken).get()));
+
+ if (!IsValidTrustedTypesExpression(mCurToken)) {
+ AutoTArray<nsString, 1> token = {mCurToken};
+ logWarningErrorToConsole(nsIScriptError::errorFlag,
+ "invalidTrustedTypesExpression", token);
+
+ for (auto* trustedTypeExpression : trustedTypesExpressions) {
+ delete trustedTypeExpression;
+ }
+
+ return;
+ }
+
+ trustedTypesExpressions.AppendElement(
+ new nsCSPTrustedTypesDirectivePolicyName(mCurToken));
+ }
+
+ if (trustedTypesExpressions.IsEmpty()) {
+ // No tt-expression is equivalent to 'none', see
+ // <https://w3c.github.io/trusted-types/dist/spec/#trusted-types-csp-directive>.
+ trustedTypesExpressions.AppendElement(new nsCSPKeywordSrc(CSP_NONE));
+ }
+
+ aDir->addSrcs(trustedTypesExpressions);
+ mPolicy->addDirective(aDir);
+}
+
// directive-value = *( WSP / <VCHAR except ";" and ","> )
void nsCSPParser::directiveValue(nsTArray<nsCSPBaseSrc*>& outSrcs) {
CSPPARSERLOG(("nsCSPParser::directiveValue"));
@@ -829,7 +969,11 @@ nsCSPDirective* nsCSPParser::directiveName() {
// Check if it is a valid directive
CSPDirective directive = CSP_StringToCSPDirective(mCurToken);
- if (directive == nsIContentSecurityPolicy::NO_DIRECTIVE) {
+ if (directive == nsIContentSecurityPolicy::NO_DIRECTIVE ||
+ (!StaticPrefs::dom_security_trusted_types_enabled() &&
+ (directive ==
+ nsIContentSecurityPolicy::REQUIRE_TRUSTED_TYPES_FOR_DIRECTIVE ||
+ directive == nsIContentSecurityPolicy::TRUSTED_TYPES_DIRECTIVE))) {
AutoTArray<nsString, 1> params = {mCurToken};
logWarningErrorToConsole(nsIScriptError::warningFlag,
"couldNotProcessUnknownDirective", params);
@@ -1008,6 +1152,19 @@ void nsCSPParser::directive() {
return;
}
+ // Special case handling since these directives don't contain source lists.
+ if (CSP_IsDirective(
+ mCurDir[0],
+ nsIContentSecurityPolicy::REQUIRE_TRUSTED_TYPES_FOR_DIRECTIVE)) {
+ handleRequireTrustedTypesForDirective(cspDir);
+ return;
+ }
+
+ if (cspDir->equals(nsIContentSecurityPolicy::TRUSTED_TYPES_DIRECTIVE)) {
+ handleTrustedTypesDirective(cspDir);
+ return;
+ }
+
// make sure to reset cache variables when trying to invalidate unsafe-inline;
// unsafe-inline might not only appear in script-src, but also in default-src
mHasHashOrNonce = false;