bool SubresourceIntegrity::CheckSubresourceIntegrity(const IntegrityMetadataSet& metadataSet, const char* content, size_t size, const KURL& resourceUrl, Document& document, String& errorMessage) { if (!metadataSet.size()) return true; HashAlgorithm strongestAlgorithm = HashAlgorithmSha256; for (const IntegrityMetadata& metadata : metadataSet) strongestAlgorithm = getPrioritizedHashFunction(metadata.algorithm(), strongestAlgorithm); DigestValue digest; for (const IntegrityMetadata& metadata : metadataSet) { if (metadata.algorithm() != strongestAlgorithm) continue; digest.clear(); bool digestSuccess = computeDigest(metadata.algorithm(), content, size, digest); if (digestSuccess) { Vector<char> hashVector; base64Decode(metadata.digest(), hashVector); DigestValue convertedHashVector; convertedHashVector.append(reinterpret_cast<uint8_t*>(hashVector.data()), hashVector.size()); if (DigestsEqual(digest, convertedHashVector)) { UseCounter::count(document, UseCounter::SRIElementWithMatchingIntegrityAttribute); return true; } } } digest.clear(); if (computeDigest(HashAlgorithmSha256, content, size, digest)) { // This message exposes the digest of the resource to the console. // Because this is only to the console, that's okay for now, but we // need to be very careful not to expose this in exceptions or // JavaScript, otherwise it risks exposing information about the // resource cross-origin. errorMessage = "Failed to find a valid digest in the 'integrity' attribute for resource '" + resourceUrl.elidedString() + "' with computed SHA-256 integrity '" + digestToString(digest) + "'. The resource has been blocked."; } else { errorMessage = "There was an error computing an integrity value for resource '" + resourceUrl.elidedString() + "'. The resource has been blocked."; } UseCounter::count(document, UseCounter::SRIElementWithNonMatchingIntegrityAttribute); return false; }
PassOwnPtr<DOMPatchSupport::Digest> DOMPatchSupport::createDigest(Node* node, UnusedNodesMap* unusedNodesMap) { Digest* digest = new Digest(node); OwnPtr<blink::WebCryptoDigestor> digestor = createDigestor(HashAlgorithmSha1); DigestValue digestResult; Node::NodeType nodeType = node->nodeType(); digestor->consume(reinterpret_cast<const unsigned char*>(&nodeType), sizeof(nodeType)); addStringToDigestor(digestor.get(), node->nodeName()); addStringToDigestor(digestor.get(), node->nodeValue()); if (node->isElementNode()) { Element& element = toElement(*node); Node* child = element.firstChild(); while (child) { OwnPtr<Digest> childInfo = createDigest(child, unusedNodesMap); addStringToDigestor(digestor.get(), childInfo->m_sha1); child = child->nextSibling(); digest->m_children.append(childInfo.release()); } if (element.hasAttributesWithoutUpdate()) { OwnPtr<blink::WebCryptoDigestor> attrsDigestor = createDigestor(HashAlgorithmSha1); AttributeCollection attributes = element.attributes(); AttributeCollection::const_iterator end = attributes.end(); for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it) { addStringToDigestor(attrsDigestor.get(), it->name().toString()); addStringToDigestor(attrsDigestor.get(), it->value().string()); } finishDigestor(attrsDigestor.get(), digestResult); digest->m_attrsSHA1 = base64Encode(reinterpret_cast<const char*>(digestResult.data()), 10); addStringToDigestor(digestor.get(), digest->m_attrsSHA1); digestResult.clear(); } } finishDigestor(digestor.get(), digestResult); digest->m_sha1 = base64Encode(reinterpret_cast<const char*>(digestResult.data()), 10); if (unusedNodesMap) unusedNodesMap->add(digest->m_sha1, digest); return adoptPtr(digest); }