Index: third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp |
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp |
index 6a1e4bc6a5671ce07de0bd72fa94dbdd849d17f4..cc8bd7826d5e4c71a6a0fe922795e6532205e999 100644 |
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp |
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp |
@@ -45,6 +45,36 @@ inline bool isASCIIAlphanumericOrHyphen(CharType c) { |
return isASCIIAlphanumeric(c) || c == '-'; |
} |
+ContentSecurityPolicyHashAlgorithm convertHashAlgorithmToCSPHashAlgorithm( |
+ HashAlgorithm algorithm) { |
+ switch (algorithm) { |
+ case HashAlgorithmSha1: |
+ // Sha1 is not supported. |
+ return ContentSecurityPolicyHashAlgorithmNone; |
+ case HashAlgorithmSha256: |
+ return ContentSecurityPolicyHashAlgorithmSha256; |
+ case HashAlgorithmSha384: |
+ return ContentSecurityPolicyHashAlgorithmSha384; |
+ case HashAlgorithmSha512: |
+ return ContentSecurityPolicyHashAlgorithmSha512; |
+ } |
+ NOTREACHED(); |
+ return ContentSecurityPolicyHashAlgorithmNone; |
+} |
+ |
+// IntegrityMetadata (from SRI) has base64-encoded digest values, but CSP uses |
+// binary format. This converts from the former to the latter. |
+bool parseBase64Digest(String base64, DigestValue& hash) { |
+ Vector<char> hashVector; |
+ // We accept base64url-encoded data here by normalizing it to base64. |
+ if (!base64Decode(normalizeToBase64(base64), hashVector)) |
+ return false; |
+ if (hashVector.isEmpty() || hashVector.size() > kMaxDigestSize) |
+ return false; |
+ hash.append(reinterpret_cast<uint8_t*>(hashVector.data()), hashVector.size()); |
+ return true; |
+} |
+ |
} // namespace |
CSPDirectiveList::CSPDirectiveList(ContentSecurityPolicy* policy, |
@@ -178,6 +208,24 @@ bool CSPDirectiveList::isMatchingNoncePresent(SourceListDirective* directive, |
return directive && directive->allowNonce(nonce); |
} |
+bool CSPDirectiveList::areAllMatchingHashesPresent( |
+ SourceListDirective* directive, |
+ const IntegrityMetadataSet& hashes) const { |
+ if (!directive || hashes.isEmpty()) |
+ return false; |
+ for (const std::pair<WTF::String, HashAlgorithm>& hash : hashes) { |
+ // Convert the hash from integrity metadata format to CSP format. |
+ CSPHashValue cspHash; |
+ cspHash.first = convertHashAlgorithmToCSPHashAlgorithm(hash.second); |
+ if (!parseBase64Digest(hash.first, cspHash.second)) |
+ return false; |
+ // All integrity hashes must be listed in the CSP. |
+ if (!directive->allowHash(cspHash)) |
+ return false; |
+ } |
+ return true; |
+} |
+ |
bool CSPDirectiveList::checkHash(SourceListDirective* directive, |
const CSPHashValue& hashValue) const { |
return !directive || directive->allowHash(hashValue); |
@@ -633,20 +681,23 @@ bool CSPDirectiveList::allowPluginType( |
bool CSPDirectiveList::allowScriptFromSource( |
const KURL& url, |
const String& nonce, |
+ const IntegrityMetadataSet& hashes, |
ParserDisposition parserDisposition, |
ResourceRequest::RedirectStatus redirectStatus, |
SecurityViolationReportingPolicy reportingPolicy) const { |
- if (isMatchingNoncePresent(operativeDirective(m_scriptSrc.get()), nonce)) |
+ SourceListDirective* directive = operativeDirective(m_scriptSrc.get()); |
+ if (isMatchingNoncePresent(directive, nonce)) |
return true; |
if (parserDisposition == NotParserInserted && allowDynamic()) |
return true; |
+ if (areAllMatchingHashesPresent(directive, hashes)) |
+ return true; |
return reportingPolicy == SecurityViolationReportingPolicy::Report |
? checkSourceAndReportViolation( |
- operativeDirective(m_scriptSrc.get()), url, |
+ directive, url, |
ContentSecurityPolicy::DirectiveType::ScriptSrc, |
redirectStatus) |
- : checkSource(operativeDirective(m_scriptSrc.get()), url, |
- redirectStatus); |
+ : checkSource(directive, url, redirectStatus); |
} |
bool CSPDirectiveList::allowObjectFromSource( |