| Index: Source/core/frame/SubresourceIntegrity.cpp
|
| diff --git a/Source/core/frame/SubresourceIntegrity.cpp b/Source/core/frame/SubresourceIntegrity.cpp
|
| index f1b9eb44ec217f14c4415cdf2c992e5d3b93643b..ac8d38f0e5ff0ad54ed9dda26bdb389f2c1cf0a4 100644
|
| --- a/Source/core/frame/SubresourceIntegrity.cpp
|
| +++ b/Source/core/frame/SubresourceIntegrity.cpp
|
| @@ -28,6 +28,8 @@ namespace blink {
|
| // FIXME: This should probably use common functions with ContentSecurityPolicy.
|
| static bool isIntegrityCharacter(UChar c)
|
| {
|
| + // FIXME: This should be checking base64url encoding, not base64 encoding.
|
| +
|
| // Check if it's a base64 encoded value.
|
| return isASCIIAlphanumeric(c) || c == '+' || c == '/' || c == '=';
|
| }
|
| @@ -112,9 +114,9 @@ bool SubresourceIntegrity::CheckSubresourceIntegrity(const Element& element, con
|
| String integrity;
|
| HashAlgorithm algorithm;
|
| String attribute = element.fastGetAttribute(HTMLNames::integrityAttr);
|
| - if (!parseIntegrityAttribute(attribute, integrity, algorithm)) {
|
| + if (!parseIntegrityAttribute(attribute, integrity, algorithm, document)) {
|
| + // An error is logged to the console during parsing; we don't need to log one here.
|
| UseCounter::count(document, UseCounter::SRIElementWithUnparsableIntegrityAttribute);
|
| - logErrorToConsole("The 'integrity' attribute's value '" + attribute + "' is not valid integrity metadata.", document);
|
| return false;
|
| }
|
|
|
| @@ -148,9 +150,19 @@ bool SubresourceIntegrity::CheckSubresourceIntegrity(const Element& element, con
|
| return false;
|
| }
|
|
|
| -bool SubresourceIntegrity::parseIntegrityAttribute(const String& attribute, String& integrity, HashAlgorithm& algorithm)
|
| +// Before:
|
| +//
|
| +// ni:///[algorithm];[hash]
|
| +// ^ ^
|
| +// position end
|
| +//
|
| +// After:
|
| +//
|
| +// ni:///[algorithm];[hash]
|
| +// ^ ^
|
| +// position end
|
| +bool SubresourceIntegrity::parseAlgorithm(const UChar*& position, const UChar* end, HashAlgorithm& algorithm)
|
| {
|
| - DEFINE_STATIC_LOCAL(const String, integrityPrefix, ("ni://"));
|
| // Any additions or subtractions from this struct should also modify the
|
| // respective entries in the kAlgorithmMap array in checkDigest() as well
|
| // as the array in algorithmToString().
|
| @@ -162,50 +174,71 @@ bool SubresourceIntegrity::parseIntegrityAttribute(const String& attribute, Stri
|
| { "sha384", HashAlgorithmSha384 },
|
| { "sha512", HashAlgorithmSha512 }
|
| };
|
| - Vector<UChar> characters;
|
| - attribute.stripWhiteSpace().appendTo(characters);
|
| - UChar* begin = characters.data();
|
| - UChar* end = characters.end();
|
|
|
| - if (characters.size() < 1)
|
| - return false;
|
| + for (auto& prefix : kSupportedPrefixes) {
|
| + if (skipToken<UChar>(position, end, prefix.prefix)) {
|
| + algorithm = prefix.algorithm;
|
| + return true;
|
| + }
|
| + }
|
|
|
| - if (!equalIgnoringCase(integrityPrefix.characters8(), begin, integrityPrefix.length()))
|
| + return false;
|
| +}
|
| +
|
| +// Before:
|
| +//
|
| +// ni:///[algorithm];[hash] OR ni:///[algorithm];[hash]?[params]
|
| +// ^ ^ ^ ^
|
| +// position end position end
|
| +//
|
| +// After:
|
| +//
|
| +// ni:///[algorithm];[hash] OR ni:///[algorithm];[hash]?[params]
|
| +// ^ ^ ^
|
| +// position/end position end
|
| +bool SubresourceIntegrity::parseDigest(const UChar*& position, const UChar* end, String& digest)
|
| +{
|
| + const UChar* begin = position;
|
| + skipWhile<UChar, isIntegrityCharacter>(position, end);
|
| +
|
| + if (position == begin || (position != end && *position != '?')) {
|
| + digest = emptyString();
|
| return false;
|
| + }
|
|
|
| - const UChar* algorithmStart = begin + integrityPrefix.length();
|
| - const UChar* algorithmEnd = algorithmStart;
|
| + digest = String(begin, position - begin);
|
| + return true;
|
| +}
|
|
|
| - skipUntil<UChar>(algorithmEnd, end, ';');
|
| +bool SubresourceIntegrity::parseIntegrityAttribute(const String& attribute, String& digest, HashAlgorithm& algorithm, Document& document)
|
| +{
|
| + Vector<UChar> characters;
|
| + attribute.stripWhiteSpace().appendTo(characters);
|
| + const UChar* position = characters.data();
|
| + const UChar* end = characters.end();
|
|
|
| - // Instead of this sizeof() calculation to get the length of this array,
|
| - // it would be preferable to use WTF_ARRAY_LENGTH for simplicity and to
|
| - // guarantee a compile time calculation. Unfortunately, on some
|
| - // compliers, the call to WTF_ARRAY_LENGTH fails on arrays of anonymous
|
| - // stucts, so, for now, it is necessary to resort to this sizeof
|
| - // calculation.
|
| - size_t i = 0;
|
| - size_t kSupportedPrefixesLength = sizeof(kSupportedPrefixes) / sizeof(kSupportedPrefixes[0]);
|
| - for (; i < kSupportedPrefixesLength; i++) {
|
| - if (equalIgnoringCase(kSupportedPrefixes[i].prefix, algorithmStart, strlen(kSupportedPrefixes[i].prefix))) {
|
| - algorithm = kSupportedPrefixes[i].algorithm;
|
| - break;
|
| - }
|
| + if (!skipToken<UChar>(position, end, "ni:///")) {
|
| + logErrorToConsole("Error parsing 'integrity' attribute ('" + attribute + "'). The value must begin with 'ni:///'.", document);
|
| + return false;
|
| }
|
|
|
| - if (i == kSupportedPrefixesLength)
|
| + if (!parseAlgorithm(position, end, algorithm)) {
|
| + logErrorToConsole("Error parsing 'integrity' attribute ('" + attribute + "'). The specified hash algorithm must be one of 'sha256', 'sha384', or 'sha512'.", document);
|
| return false;
|
| + }
|
|
|
| - const UChar* integrityStart = algorithmEnd;
|
| - if (!skipExactly<UChar>(integrityStart, end, ';'))
|
| + if (!skipExactly<UChar>(position, end, ';')) {
|
| + logErrorToConsole("Error parsing 'integrity' attribute ('" + attribute + "'). The hash algorithm must be followed by a ';' character.", document);
|
| return false;
|
| + }
|
|
|
| - const UChar* integrityEnd = integrityStart;
|
| - skipWhile<UChar, isIntegrityCharacter>(integrityEnd, end);
|
| - if (integrityEnd != end)
|
| + if (!parseDigest(position, end, digest)) {
|
| + logErrorToConsole("Error parsing 'integrity' attribute ('" + attribute + "'). The digest must be a valid, base64-encoded value.", document);
|
| return false;
|
| + }
|
| +
|
| + // FIXME: Parse params in order to get content type (e.g. "?ct=application/javascript")
|
|
|
| - integrity = String(integrityStart, integrityEnd - integrityStart);
|
| return true;
|
| }
|
|
|
|
|