static bool DigestsEqual(const DigestValue& digest1, const DigestValue& digest2)
{
    if (digest1.size() != digest2.size())
        return false;

    for (size_t i = 0; i < digest1.size(); i++) {
        if (digest1[i] != digest2[i])
            return false;
    }

    return true;
}
String WebSocketHandshake::getExpectedWebSocketAccept(const String& secWebSocketKey)
{
    static const char webSocketKeyGUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    CString keyData = secWebSocketKey.ascii();

    StringBuilder digestable;
    digestable.append(secWebSocketKey);
    digestable.append(webSocketKeyGUID, strlen(webSocketKeyGUID));
    CString digestableCString = digestable.toString().utf8();
    DigestValue digest;
    bool digestSuccess = computeDigest(HashAlgorithmSha1, digestableCString.data(), digestableCString.length(), digest);
    RELEASE_ASSERT(digestSuccess);

    return base64Encode(reinterpret_cast<const char*>(digest.data()), sha1HashSize);
}
Esempio n. 3
0
// 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;
}
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);
}
Esempio n. 6
0
// 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 algorithm;
    } kSupportedPrefixes[] = {
        { "'sha1-", ContentSecurityPolicyHashAlgorithmSha1 },
        { "'sha256-", ContentSecurityPolicyHashAlgorithmSha256 },
        { "'sha384-", ContentSecurityPolicyHashAlgorithmSha384 },
        { "'sha512-", ContentSecurityPolicyHashAlgorithmSha512 }
    };

    String prefix;
    hashAlgorithm = ContentSecurityPolicyHashAlgorithmNone;

    // 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.
    for (size_t i = 0; i < (sizeof(kSupportedPrefixes) / sizeof(kSupportedPrefixes[0])); i++) {
        if (equalIgnoringCase(kSupportedPrefixes[i].prefix, begin, strlen(kSupportedPrefixes[i].prefix))) {
            prefix = kSupportedPrefixes[i].prefix;
            hashAlgorithm = kSupportedPrefixes[i].algorithm;
            break;
        }
    }

    if (hashAlgorithm == ContentSecurityPolicyHashAlgorithmNone)
        return true;

    const UChar* position = begin + prefix.length();
    const UChar* hashBegin = position;

    skipWhile<UChar, isBase64EncodedCharacter>(position, end);
    ASSERT(hashBegin <= position);

    // Base64 encodings may end with exactly one or two '=' characters
    skipExactly<UChar>(position, position + 1, '=');
    skipExactly<UChar>(position, position + 1, '=');

    if ((position + 1) != end || *position != '\'' || !(position - hashBegin))
        return false;

    Vector<char> hashVector;
    base64Decode(hashBegin, position - hashBegin, hashVector);
    if (hashVector.size() > kMaxDigestSize)
        return false;
    hash.append(reinterpret_cast<uint8_t*>(hashVector.data()), hashVector.size());
    return true;
}
void finishDigestor(WebCryptoDigestor* digestor, DigestValue& digestResult)
{
    unsigned char* result = 0;
    unsigned resultSize = 0;

    if (!digestor->finish(result, resultSize))
        return;

    ASSERT(result);

    digestResult.append(static_cast<uint8_t*>(result), resultSize);
}
String InspectorAnimationAgent::createCSSId(blink::Animation& animation) {
  String type =
      m_idToAnimationType.get(String::number(animation.sequenceNumber()));
  ASSERT(type != AnimationType::WebAnimation);

  KeyframeEffect* effect = toKeyframeEffect(animation.effect());
  Vector<CSSPropertyID> cssProperties;
  if (type == AnimationType::CSSAnimation) {
    for (CSSPropertyID property : animationProperties)
      cssProperties.append(property);
  } else {
    for (CSSPropertyID property : transitionProperties)
      cssProperties.append(property);
    cssProperties.append(cssPropertyID(animation.id()));
  }

  Element* element = effect->target();
  HeapVector<Member<CSSStyleDeclaration>> styles =
      m_cssAgent->matchingStyles(element);
  std::unique_ptr<WebCryptoDigestor> digestor =
      createDigestor(HashAlgorithmSha1);
  addStringToDigestor(digestor.get(), type);
  addStringToDigestor(digestor.get(), animation.id());
  for (CSSPropertyID property : cssProperties) {
    CSSStyleDeclaration* style =
        m_cssAgent->findEffectiveDeclaration(property, styles);
    // Ignore inline styles.
    if (!style || !style->parentStyleSheet() || !style->parentRule() ||
        style->parentRule()->type() != CSSRule::kStyleRule)
      continue;
    addStringToDigestor(digestor.get(), getPropertyNameString(property));
    addStringToDigestor(digestor.get(),
                        m_cssAgent->styleSheetId(style->parentStyleSheet()));
    addStringToDigestor(digestor.get(),
                        toCSSStyleRule(style->parentRule())->selectorText());
  }
  DigestValue digestResult;
  finishDigestor(digestor.get(), digestResult);
  return base64Encode(reinterpret_cast<const char*>(digestResult.data()), 10);
}
bool computeDigest(HashAlgorithm algorithm, const char* digestable, size_t length, DigestValue& digestResult)
{
    WebCryptoAlgorithmId algorithmId = toWebCryptoAlgorithmId(algorithm);
    WebCrypto* crypto = Platform::current()->crypto();
    unsigned char* result;
    unsigned resultSize;

    ASSERT(crypto);

    OwnPtr<WebCryptoDigestor> digestor = adoptPtr(crypto->createDigestor(algorithmId));
    if (!digestor.get() || !digestor->consume(reinterpret_cast<const unsigned char*>(digestable), length) || !digestor->finish(result, resultSize))
        return false;

    digestResult.append(static_cast<uint8_t*>(result), resultSize);
    return true;
}
static String digestToString(const DigestValue& digest)
{
    return base64Encode(reinterpret_cast<const char*>(digest.data()), digest.size(), Base64DoNotInsertLFs);
}
Esempio n. 11
0
// source            = scheme ":"
//                   / ( [ scheme "://" ] host [ port ] [ path ] )
//                   / "'self'"
bool CSPSourceList::parseSource(const UChar* begin, const UChar* end, String& scheme, String& host, int& port, String& path, CSPSource::WildcardDisposition& hostWildcard, CSPSource::WildcardDisposition& portWildcard)
{
    if (begin == end)
        return false;

    if (equalIgnoringCase("'none'", begin, end - begin))
        return false;

    if (end - begin == 1 && *begin == '*') {
        addSourceStar();
        return true;
    }

    if (equalIgnoringCase("'self'", begin, end - begin)) {
        addSourceSelf();
        return true;
    }

    if (equalIgnoringCase("'unsafe-inline'", begin, end - begin)) {
        addSourceUnsafeInline();
        return true;
    }

    if (equalIgnoringCase("'unsafe-eval'", begin, end - begin)) {
        addSourceUnsafeEval();
        return true;
    }

    String nonce;
    if (!parseNonce(begin, end, nonce))
        return false;

    if (!nonce.isNull()) {
        addSourceNonce(nonce);
        return true;
    }

    DigestValue hash;
    ContentSecurityPolicyHashAlgorithm algorithm = ContentSecurityPolicyHashAlgorithmNone;
    if (!parseHash(begin, end, hash, algorithm))
        return false;

    if (hash.size() > 0) {
        addSourceHash(algorithm, hash);
        return true;
    }

    const UChar* position = begin;
    const UChar* beginHost = begin;
    const UChar* beginPath = end;
    const UChar* beginPort = 0;

    skipWhile<UChar, isNotColonOrSlash>(position, end);

    if (position == end) {
        // host
        //     ^
        return parseHost(beginHost, position, host, hostWildcard);
    }

    if (position < end && *position == '/') {
        // host/path || host/ || /
        //     ^            ^    ^
        return parseHost(beginHost, position, host, hostWildcard) && parsePath(position, end, path);
    }

    if (position < end && *position == ':') {
        if (end - position == 1) {
            // scheme:
            //       ^
            return parseScheme(begin, position, scheme);
        }

        if (position[1] == '/') {
            // scheme://host || scheme://
            //       ^                ^
            if (!parseScheme(begin, position, scheme)
                || !skipExactly<UChar>(position, end, ':')
                || !skipExactly<UChar>(position, end, '/')
                || !skipExactly<UChar>(position, end, '/'))
                return false;
            if (position == end)
                return false;
            beginHost = position;
            skipWhile<UChar, isNotColonOrSlash>(position, end);
        }

        if (position < end && *position == ':') {
            // host:port || scheme://host:port
            //     ^                     ^
            beginPort = position;
            skipUntil<UChar>(position, end, '/');
        }
    }

    if (position < end && *position == '/') {
        // scheme://host/path || scheme://host:port/path
        //              ^                          ^
        if (position == beginHost)
            return false;
        beginPath = position;
    }

    if (!parseHost(beginHost, beginPort ? beginPort : beginPath, host, hostWildcard))
        return false;

    if (beginPort) {
        if (!parsePort(beginPort, beginPath, port, portWildcard))
            return false;
    } else {
        port = 0;
    }

    if (beginPath != end) {
        if (!parsePath(beginPath, end, path))
            return false;
    }

    return true;
}