1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "config.h"
6#include "core/frame/SubresourceIntegrity.h"
7
8#include "core/HTMLNames.h"
9#include "core/dom/Document.h"
10#include "core/html/HTMLScriptElement.h"
11#include "platform/Crypto.h"
12#include "platform/weborigin/KURL.h"
13#include "platform/weborigin/SecurityOrigin.h"
14#include "wtf/RefPtr.h"
15#include "wtf/text/WTFString.h"
16#include <gtest/gtest.h>
17
18namespace blink {
19
20static const char kBasicScript[] = "alert('test');";
21static const char kSha256Integrity[] = "ni://sha256;GAF48QOoxRvu0gZAmQivUdJPyBacqznBAXwnkfpmQX4=";
22static const char kSha384Intgrity[] = "ni://sha384;nep3XpvhUxpCMOVXIFPecThAqdY/uVeiD4kXSqXpx0YJUWU4fTTaFgciTuZk7fmE";
23static const char kSha512Integrity[] = "ni://sha512;TXkJw18PqlVlEUXXjeXbGetop1TKB3wYQIp1/ihxCOFGUfG9TYOaA1MlkpTAqSV6yaevLO8Tj5pgH1JmZ++ItA==";
24static const char kSha384IntegrityLabeledAs256[] = "ni://sha256;nep3XpvhUxpCMOVXIFPecThAqdY/uVeiD4kXSqXpx0YJUWU4fTTaFgciTuZk7fmE";
25static const char kUnsupportedHashFunctionIntegrity[] = "ni://sha1;JfLW308qMPKfb4DaHpUBEESwuPc=";
26
27TEST(SubresourceIntegrityTest, CheckSubresourceIntegrity)
28{
29    KURL secureKURL(KURL(), "https://foobar.com:443");
30    KURL insecureKURL(KURL(), "http://foobar.com:80");
31    RefPtr<SecurityOrigin> secureOrigin = SecurityOrigin::create(secureKURL);
32    RefPtr<SecurityOrigin> insecureOrigin = SecurityOrigin::create(insecureKURL);
33    RefPtrWillBeRawPtr<Document> document = Document::create();
34    RefPtrWillBeRawPtr<HTMLScriptElement> scriptElement = HTMLScriptElement::create(*document, true);
35
36    // Verify basic sha256, sha384, and sha512 integrity checks.
37    document->updateSecurityOrigin(secureOrigin->isolatedCopy());
38    scriptElement->setAttribute(HTMLNames::integrityAttr, kSha256Integrity);
39    EXPECT_TRUE(SubresourceIntegrity::CheckSubresourceIntegrity(*scriptElement, kBasicScript, secureKURL));
40    scriptElement->setAttribute(HTMLNames::integrityAttr, kSha384Intgrity);
41    EXPECT_TRUE(SubresourceIntegrity::CheckSubresourceIntegrity(*scriptElement, kBasicScript, secureKURL));
42    scriptElement->setAttribute(HTMLNames::integrityAttr, kSha512Integrity);
43    EXPECT_TRUE(SubresourceIntegrity::CheckSubresourceIntegrity(*scriptElement, kBasicScript, secureKURL));
44
45    // The hash label must match the hash value.
46    scriptElement->setAttribute(HTMLNames::integrityAttr, kSha384IntegrityLabeledAs256);
47    EXPECT_FALSE(SubresourceIntegrity::CheckSubresourceIntegrity(*scriptElement, kBasicScript, secureKURL));
48
49    scriptElement->setAttribute(HTMLNames::integrityAttr, kSha256Integrity);
50    // Check should fail if the document is not on an authenticated origin or
51    // if the resource is not on an authenticated origin.
52    document->updateSecurityOrigin(insecureOrigin->isolatedCopy());
53    EXPECT_FALSE(SubresourceIntegrity::CheckSubresourceIntegrity(*scriptElement, kBasicScript, secureKURL));
54    document->updateSecurityOrigin(secureOrigin->isolatedCopy());
55    EXPECT_FALSE(SubresourceIntegrity::CheckSubresourceIntegrity(*scriptElement, kBasicScript, insecureKURL));
56
57    scriptElement->setAttribute(HTMLNames::integrityAttr, kUnsupportedHashFunctionIntegrity);
58    EXPECT_FALSE(SubresourceIntegrity::CheckSubresourceIntegrity(*scriptElement, kBasicScript, insecureKURL));
59}
60
61TEST(SubresourceIntegrityTest, Parsing)
62{
63    String attribute;
64    String integrity;
65    HashAlgorithm algorithm;
66
67    // Verify that empty attribute is not valid.
68    EXPECT_FALSE(SubresourceIntegrity::parseIntegrityAttribute(attribute, integrity, algorithm));
69
70    // Valid sha256 attribute
71    attribute = "ni://sha256;BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=";
72    EXPECT_TRUE(SubresourceIntegrity::parseIntegrityAttribute(attribute, integrity, algorithm));
73    EXPECT_EQ(integrity, "BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=");
74    EXPECT_EQ(algorithm, HashAlgorithmSha256);
75
76    // Another valid sha256 attribute, but this time with whitespace
77    attribute = "    ni://sha256;BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=    ";
78    EXPECT_TRUE(SubresourceIntegrity::parseIntegrityAttribute(attribute, integrity, algorithm));
79    EXPECT_EQ(integrity, "BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=");
80    EXPECT_EQ(algorithm, HashAlgorithmSha256);
81
82    // Valid sha384 attribute
83    attribute = "ni://sha384;XVVXBGoYw6AJOh9J/Z8pBDMVVPfkBpngexkA7JqZu8d5GENND6TEIup/tA1v5GPr";
84    EXPECT_TRUE(SubresourceIntegrity::parseIntegrityAttribute(attribute, integrity, algorithm));
85    EXPECT_EQ(integrity, "XVVXBGoYw6AJOh9J/Z8pBDMVVPfkBpngexkA7JqZu8d5GENND6TEIup/tA1v5GPr");
86    EXPECT_EQ(algorithm, HashAlgorithmSha384);
87
88    // Valid sha512 attribute
89    attribute = "ni://sha512;tbUPioKbVBplr0b1ucnWB57SJWt4x9dOE0Vy2mzCXvH3FepqDZ+07yMK81ytlg0MPaIrPAjcHqba5csorDWtKg==";
90    EXPECT_TRUE(SubresourceIntegrity::parseIntegrityAttribute(attribute, integrity, algorithm));
91    EXPECT_EQ(integrity, "tbUPioKbVBplr0b1ucnWB57SJWt4x9dOE0Vy2mzCXvH3FepqDZ+07yMK81ytlg0MPaIrPAjcHqba5csorDWtKg==");
92    EXPECT_EQ(algorithm, HashAlgorithmSha512);
93
94    // Invalid prefix
95    attribute = "foobar://sha256;BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=";
96    EXPECT_FALSE(SubresourceIntegrity::parseIntegrityAttribute(attribute, integrity, algorithm));
97
98    // Invalid hash function
99    attribute = "ni://not_a_hash_function;BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=";
100    EXPECT_FALSE(SubresourceIntegrity::parseIntegrityAttribute(attribute, integrity, algorithm));
101
102    // Invalid integrity (not base64)
103    attribute = "ni://sha256;&&&foobar&&&";
104    EXPECT_FALSE(SubresourceIntegrity::parseIntegrityAttribute(attribute, integrity, algorithm));
105    attribute = "ni://sha256;\x01\x02\x03\x04";
106    EXPECT_FALSE(SubresourceIntegrity::parseIntegrityAttribute(attribute, integrity, algorithm));
107
108    // Just integrity
109    attribute = "BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=";
110    EXPECT_FALSE(SubresourceIntegrity::parseIntegrityAttribute(attribute, integrity, algorithm));
111}
112
113} // namespace blink
114