// hash-source = "'" hash-algorithm "-" hash-value "'" // hash-algorithm = "sha1" / "sha256" / "sha384" / "sha512" // hash-value = 1*( ALPHA / DIGIT / "+" / "/" / "=" ) // bool CSPSourceList::parseHash(const UChar* begin, const UChar* end, DigestValue& hash, ContentSecurityPolicyHashAlgorithm& hashAlgorithm) { // Any additions or subtractions from this struct should also modify the // respective entries in the kAlgorithmMap array in checkDigest(). static const struct { const char* prefix; ContentSecurityPolicyHashAlgorithm type; } kSupportedPrefixes[] = { // FIXME: Drop support for SHA-1. It's not in the spec. { "'sha1-", ContentSecurityPolicyHashAlgorithmSha1 }, { "'sha256-", ContentSecurityPolicyHashAlgorithmSha256 }, { "'sha384-", ContentSecurityPolicyHashAlgorithmSha384 }, { "'sha512-", ContentSecurityPolicyHashAlgorithmSha512 }, { "'sha-256-", ContentSecurityPolicyHashAlgorithmSha256 }, { "'sha-384-", ContentSecurityPolicyHashAlgorithmSha384 }, { "'sha-512-", ContentSecurityPolicyHashAlgorithmSha512 } }; String prefix; hashAlgorithm = ContentSecurityPolicyHashAlgorithmNone; size_t hashLength = end - begin; for (const auto& algorithm : kSupportedPrefixes) { if (hashLength > strlen(algorithm.prefix) && equalIgnoringCase(algorithm.prefix, begin, strlen(algorithm.prefix))) { prefix = algorithm.prefix; hashAlgorithm = algorithm.type; break; } } if (hashAlgorithm == ContentSecurityPolicyHashAlgorithmNone) return true; const UChar* position = begin + prefix.length(); const UChar* hashBegin = position; ASSERT(position < end); skipWhile<UChar, isBase64EncodedCharacter>(position, end); ASSERT(hashBegin <= position); // Base64 encodings may end with exactly one or two '=' characters if (position < end) skipExactly<UChar>(position, position + 1, '='); if (position < end) skipExactly<UChar>(position, position + 1, '='); if (position + 1 != end || *position != '\'' || position == hashBegin) return false; Vector<char> hashVector; // We accept base64url-encoded data here by normalizing it to base64. base64Decode(normalizeToBase64(String(hashBegin, position - hashBegin)), hashVector); if (hashVector.size() > kMaxDigestSize) return false; hash.append(reinterpret_cast<uint8_t*>(hashVector.data()), hashVector.size()); return true; }
// Before: // // [algorithm]-[hash] OR [algorithm]-[hash]?[options] // ^ ^ ^ ^ // position end position end // // After (if successful: if the method returns false, we make no promises and the caller should exit early): // // [algorithm]-[hash] OR [algorithm]-[hash]?[options] // ^ ^ ^ // 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; } // We accept base64url encoding, but normalize to "normal" base64 internally: digest = normalizeToBase64(String(begin, position - begin)); return true; }