Commit 73b803d2 authored by Kunihiko Sakamoto's avatar Kunihiko Sakamoto Committed by Commit Bot

Signed Exchange: --ignore-certificate-errors-spki-list ignores signature timestamp error

This patch lets SignedExchangeSignatureVerifier ignore signature
timestamp errors if the Signed Exchange's main certificate is listed in
--ignore-certificate-errors-spki-list flag, and ContentBrowserClient::
CanIgnoreCertificateErrorIfNeeded() returns true.

This enables us to write layout tests and web-platform-tests for signed
exchange loading, without using UA-specific testing API that overrides
signature verification time.

This patch also removes setSignedExchangeVerificationTime() calls from
existing layout tests, because they already run with
--ignore-certificate-errors-spki-list flag. This means we lose layout
test coverage for expired SXG loading, so I added a test case in
signed_exchange_request_handler_browsertest.cc.

Bug: 803774
Change-Id: Ia2f9dc5f28036c30e76acc344137ab8873bfb7c6
Reviewed-on: https://chromium-review.googlesource.com/c/1253167
Commit-Queue: Kunihiko Sakamoto <ksakamoto@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarTsuyoshi Horo <horo@chromium.org>
Reviewed-by: default avatarKouhei Ueno <kouhei@chromium.org>
Cr-Commit-Position: refs/heads/master@{#597045}
parent 64bc6eb9
...@@ -4881,3 +4881,10 @@ ChromeContentBrowserClient::GetOriginPolicyErrorPage( ...@@ -4881,3 +4881,10 @@ ChromeContentBrowserClient::GetOriginPolicyErrorPage(
return security_interstitials::OriginPolicyUI::GetErrorPage(error_reason, return security_interstitials::OriginPolicyUI::GetErrorPage(error_reason,
origin, url); origin, url);
} }
bool ChromeContentBrowserClient::CanIgnoreCertificateErrorIfNeeded() {
// We require --user-data-dir flag too so that no dangerous changes are made
// in the user's regular profile.
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUserDataDir);
}
...@@ -505,6 +505,7 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient { ...@@ -505,6 +505,7 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
content::OriginPolicyErrorReason error_reason, content::OriginPolicyErrorReason error_reason,
const url::Origin& origin, const url::Origin& origin,
const GURL& url) override; const GURL& url) override;
bool CanIgnoreCertificateErrorIfNeeded() override;
protected: protected:
static bool HandleWebUI(GURL* url, content::BrowserContext* browser_context); static bool HandleWebUI(GURL* url, content::BrowserContext* browser_context);
......
...@@ -51,6 +51,7 @@ namespace content { ...@@ -51,6 +51,7 @@ namespace content {
namespace { namespace {
const uint64_t kSignatureHeaderDate = 1520834000; // 2018-03-12T05:53:20Z const uint64_t kSignatureHeaderDate = 1520834000; // 2018-03-12T05:53:20Z
const uint64_t kSignatureHeaderExpires = 1520837600; // 2018-03-12T06:53:20Z
constexpr char kExpectedSXGEnabledAcceptHeaderForPrefetch[] = constexpr char kExpectedSXGEnabledAcceptHeaderForPrefetch[] =
"application/signed-exchange;v=b2;q=0.9,*/*;q=0.8"; "application/signed-exchange;v=b2;q=0.9,*/*;q=0.8";
...@@ -262,6 +263,47 @@ IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest, ...@@ -262,6 +263,47 @@ IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest,
1); 1);
} }
IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest, Expired) {
SignedExchangeHandler::SetVerificationTimeForTesting(
base::Time::UnixEpoch() +
base::TimeDelta::FromSeconds(kSignatureHeaderExpires + 1));
InstallUrlInterceptor(
GURL("https://cert.example.org/cert.msg"),
"content/test/data/sxg/test.example.org.public.pem.cbor");
InstallUrlInterceptor(GURL("https://test.example.org/test/"),
"content/test/data/sxg/fallback.html");
// Make the MockCertVerifier treat the certificate
// "prime256v1-sha256.public.pem" as valid for "test.example.org".
scoped_refptr<net::X509Certificate> original_cert =
LoadCertificate("prime256v1-sha256.public.pem");
net::CertVerifyResult dummy_result;
dummy_result.verified_cert = original_cert;
dummy_result.cert_status = net::OK;
dummy_result.ocsp_result.response_status = net::OCSPVerifyResult::PROVIDED;
dummy_result.ocsp_result.revocation_status = net::OCSPRevocationStatus::GOOD;
mock_cert_verifier()->AddResultForCertAndHost(
original_cert, "test.example.org", dummy_result, net::OK);
embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
ASSERT_TRUE(embedded_test_server()->Start());
GURL url = embedded_test_server()->GetURL("/sxg/test.example.org_test.sxg");
base::string16 title = base::ASCIIToUTF16("Fallback URL response");
TitleWatcher title_watcher(shell()->web_contents(), title);
RedirectObserver redirect_observer(shell()->web_contents());
NavigateToURL(shell(), url);
EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
EXPECT_EQ(303, redirect_observer.response_code());
histogram_tester_.ExpectUniqueSample(
"SignedExchange.LoadResult",
SignedExchangeLoadResult::kSignatureVerificationError, 1);
histogram_tester_.ExpectUniqueSample(
"SignedExchange.SignatureVerificationResult",
SignedExchangeSignatureVerifier::Result::kErrInvalidTimestamp, 1);
}
IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest, IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest,
RedirectBrokenSignedExchanges) { RedirectBrokenSignedExchanges) {
InstallUrlInterceptor(GURL("https://test.example.org/test/"), InstallUrlInterceptor(GURL("https://test.example.org/test/"),
......
...@@ -8,10 +8,13 @@ ...@@ -8,10 +8,13 @@
#include <vector> #include <vector>
#include "base/big_endian.h" #include "base/big_endian.h"
#include "base/command_line.h"
#include "base/containers/span.h" #include "base/containers/span.h"
#include "base/format_macros.h" #include "base/format_macros.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/time/time.h" #include "base/time/time.h"
...@@ -20,9 +23,12 @@ ...@@ -20,9 +23,12 @@
#include "content/browser/web_package/signed_exchange_envelope.h" #include "content/browser/web_package/signed_exchange_envelope.h"
#include "content/browser/web_package/signed_exchange_signature_header_field.h" #include "content/browser/web_package/signed_exchange_signature_header_field.h"
#include "content/browser/web_package/signed_exchange_utils.h" #include "content/browser/web_package/signed_exchange_utils.h"
#include "content/public/browser/content_browser_client.h"
#include "crypto/sha2.h"
#include "crypto/signature_verifier.h" #include "crypto/signature_verifier.h"
#include "net/cert/asn1_util.h" #include "net/cert/asn1_util.h"
#include "net/cert/x509_util.h" #include "net/cert/x509_util.h"
#include "services/network/public/cpp/network_switches.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/bytestring.h"
#include "third_party/boringssl/src/include/openssl/ec.h" #include "third_party/boringssl/src/include/openssl/ec.h"
#include "third_party/boringssl/src/include/openssl/ec_key.h" #include "third_party/boringssl/src/include/openssl/ec_key.h"
...@@ -226,6 +232,17 @@ bool VerifyTimestamps(const SignedExchangeEnvelope& envelope, ...@@ -226,6 +232,17 @@ bool VerifyTimestamps(const SignedExchangeEnvelope& envelope,
return true; return true;
} }
// Returns true if SPKI hash of |certificate| is included in the
// --ignore-certificate-errors-spki-list command line flag, and
// ContentBrowserClient::CanIgnoreCertificateErrorIfNeeded() returns true.
bool ShouldIgnoreTimestampError(
scoped_refptr<net::X509Certificate> certificate) {
static base::NoDestructor<
SignedExchangeSignatureVerifier::IgnoreErrorsSPKIList>
instance(*base::CommandLine::ForCurrentProcess());
return instance->ShouldIgnoreError(certificate);
}
} // namespace } // namespace
SignedExchangeSignatureVerifier::Result SignedExchangeSignatureVerifier::Verify( SignedExchangeSignatureVerifier::Result SignedExchangeSignatureVerifier::Verify(
...@@ -237,7 +254,8 @@ SignedExchangeSignatureVerifier::Result SignedExchangeSignatureVerifier::Verify( ...@@ -237,7 +254,8 @@ SignedExchangeSignatureVerifier::Result SignedExchangeSignatureVerifier::Verify(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"), TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
"SignedExchangeSignatureVerifier::Verify"); "SignedExchangeSignatureVerifier::Verify");
if (!VerifyTimestamps(envelope, verification_time)) { if (!VerifyTimestamps(envelope, verification_time) &&
!ShouldIgnoreTimestampError(certificate)) {
signed_exchange_utils::ReportErrorAndTraceEvent( signed_exchange_utils::ReportErrorAndTraceEvent(
devtools_proxy, devtools_proxy,
base::StringPrintf( base::StringPrintf(
...@@ -302,4 +320,43 @@ SignedExchangeSignatureVerifier::Result SignedExchangeSignatureVerifier::Verify( ...@@ -302,4 +320,43 @@ SignedExchangeSignatureVerifier::Result SignedExchangeSignatureVerifier::Verify(
return Result::kSuccess; return Result::kSuccess;
} }
SignedExchangeSignatureVerifier::IgnoreErrorsSPKIList::IgnoreErrorsSPKIList(
const std::string& spki_list) {
Parse(spki_list);
}
SignedExchangeSignatureVerifier::IgnoreErrorsSPKIList::IgnoreErrorsSPKIList(
const base::CommandLine& command_line) {
if (!GetContentClient()->browser()->CanIgnoreCertificateErrorIfNeeded())
return;
Parse(command_line.GetSwitchValueASCII(
network::switches::kIgnoreCertificateErrorsSPKIList));
}
void SignedExchangeSignatureVerifier::IgnoreErrorsSPKIList::Parse(
const std::string& spki_list) {
hash_set_ =
network::IgnoreErrorsCertVerifier::MakeWhitelist(base::SplitString(
spki_list, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL));
}
SignedExchangeSignatureVerifier::IgnoreErrorsSPKIList::~IgnoreErrorsSPKIList() =
default;
bool SignedExchangeSignatureVerifier::IgnoreErrorsSPKIList::ShouldIgnoreError(
scoped_refptr<net::X509Certificate> certificate) {
if (hash_set_.empty())
return false;
base::StringPiece spki;
if (!net::asn1::ExtractSPKIFromDERCert(
net::x509_util::CryptoBufferAsStringPiece(certificate->cert_buffer()),
&spki)) {
return false;
}
net::SHA256HashValue hash;
crypto::SHA256HashString(spki, &hash, sizeof(net::SHA256HashValue));
return hash_set_.find(hash) != hash_set_.end();
}
} // namespace content } // namespace content
...@@ -9,8 +9,10 @@ ...@@ -9,8 +9,10 @@
#include "base/optional.h" #include "base/optional.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "net/cert/x509_certificate.h" #include "net/cert/x509_certificate.h"
#include "services/network/ignore_errors_cert_verifier.h"
namespace base { namespace base {
class CommandLine;
class Time; class Time;
} // namespace base } // namespace base
...@@ -45,6 +47,27 @@ class CONTENT_EXPORT SignedExchangeSignatureVerifier final { ...@@ -45,6 +47,27 @@ class CONTENT_EXPORT SignedExchangeSignatureVerifier final {
kMaxValue = kErrUnsupportedCertType kMaxValue = kErrUnsupportedCertType
}; };
// An utility class which holds a set of certificates which errors should be
// ignored. It parses a comma-delimited list of base64-encoded SHA-256 SPKI
// fingerprints, and can query if a certificate is included in the set.
// CONTENT_EXPORT since it is used from the unit test.
class CONTENT_EXPORT IgnoreErrorsSPKIList {
public:
explicit IgnoreErrorsSPKIList(const base::CommandLine& command_line);
~IgnoreErrorsSPKIList();
bool ShouldIgnoreError(scoped_refptr<net::X509Certificate> certificate);
private:
FRIEND_TEST_ALL_PREFIXES(SignedExchangeSignatureVerifierTest,
IgnoreErrorsSPKIList);
explicit IgnoreErrorsSPKIList(const std::string& spki_list);
void Parse(const std::string& spki_list);
network::IgnoreErrorsCertVerifier::SPKIHashSet hash_set_;
DISALLOW_COPY_AND_ASSIGN(IgnoreErrorsSPKIList);
};
static Result Verify(const SignedExchangeEnvelope& envelope, static Result Verify(const SignedExchangeEnvelope& envelope,
scoped_refptr<net::X509Certificate> certificate, scoped_refptr<net::X509Certificate> certificate,
const base::Time& verification_time, const base::Time& verification_time,
......
...@@ -118,6 +118,13 @@ DGC2vA1lb2Uy9bgLCYYkZoESjb/JYRQjCmqlwYKOozU7ZbIe3zJPjRWYP1Tuany5 ...@@ -118,6 +118,13 @@ DGC2vA1lb2Uy9bgLCYYkZoESjb/JYRQjCmqlwYKOozU7ZbIe3zJPjRWYP1Tuany5
Xhe5DP7VATeQq3yGV3ps+rCTHDP6qSHDEWP7DqHQdSsxtI0E Xhe5DP7VATeQq3yGV3ps+rCTHDP6qSHDEWP7DqHQdSsxtI0E
-----END CERTIFICATE-----)"; -----END CERTIFICATE-----)";
constexpr char kPEMECDSAP256SPKIHash[] =
"iwtEGagHhL9HbHI38aoFstFPEyB+lzZO5H2ZZAJlYOo=";
constexpr char kPEMECDSAP384SPKIHash[] =
"aGcf7fF/2+mXuHjYen7FZ8HZPR0B6sK6zIsyrCoB6Y8=";
} // namespace
class SignedExchangeSignatureVerifierTest : public ::testing::Test { class SignedExchangeSignatureVerifierTest : public ::testing::Test {
protected: protected:
SignedExchangeSignatureVerifierTest() {} SignedExchangeSignatureVerifierTest() {}
...@@ -326,5 +333,32 @@ TEST_F(SignedExchangeSignatureVerifierTest, VerifyECDSAP384) { ...@@ -326,5 +333,32 @@ TEST_F(SignedExchangeSignatureVerifierTest, VerifyECDSAP384) {
nullptr /* devtools_proxy */)); nullptr /* devtools_proxy */));
} }
} // namespace TEST_F(SignedExchangeSignatureVerifierTest, IgnoreErrorsSPKIList) {
SignedExchangeSignatureVerifier::IgnoreErrorsSPKIList ignore_nothing("");
SignedExchangeSignatureVerifier::IgnoreErrorsSPKIList ignore_ecdsap256(
kPEMECDSAP256SPKIHash);
SignedExchangeSignatureVerifier::IgnoreErrorsSPKIList ignore_ecdsap384(
kPEMECDSAP384SPKIHash);
SignedExchangeSignatureVerifier::IgnoreErrorsSPKIList ignore_both(
std::string(kPEMECDSAP256SPKIHash) + "," + kPEMECDSAP384SPKIHash);
scoped_refptr<net::X509Certificate> cert_ecdsap256 =
net::X509Certificate::CreateCertificateListFromBytes(
kCertPEMECDSAP256, base::size(kCertPEMECDSAP256),
net::X509Certificate::FORMAT_AUTO)[0];
scoped_refptr<net::X509Certificate> cert_ecdsap384 =
net::X509Certificate::CreateCertificateListFromBytes(
kCertPEMECDSAP384, base::size(kCertPEMECDSAP384),
net::X509Certificate::FORMAT_AUTO)[0];
EXPECT_FALSE(ignore_nothing.ShouldIgnoreError(cert_ecdsap256));
EXPECT_FALSE(ignore_nothing.ShouldIgnoreError(cert_ecdsap384));
EXPECT_TRUE(ignore_ecdsap256.ShouldIgnoreError(cert_ecdsap256));
EXPECT_FALSE(ignore_ecdsap256.ShouldIgnoreError(cert_ecdsap384));
EXPECT_FALSE(ignore_ecdsap384.ShouldIgnoreError(cert_ecdsap256));
EXPECT_TRUE(ignore_ecdsap384.ShouldIgnoreError(cert_ecdsap384));
EXPECT_TRUE(ignore_both.ShouldIgnoreError(cert_ecdsap256));
EXPECT_TRUE(ignore_both.ShouldIgnoreError(cert_ecdsap384));
}
} // namespace content } // namespace content
...@@ -815,4 +815,8 @@ base::Optional<std::string> ContentBrowserClient::GetOriginPolicyErrorPage( ...@@ -815,4 +815,8 @@ base::Optional<std::string> ContentBrowserClient::GetOriginPolicyErrorPage(
return base::nullopt; return base::nullopt;
} }
bool ContentBrowserClient::CanIgnoreCertificateErrorIfNeeded() {
return false;
}
} // namespace content } // namespace content
...@@ -1349,6 +1349,12 @@ class CONTENT_EXPORT ContentBrowserClient { ...@@ -1349,6 +1349,12 @@ class CONTENT_EXPORT ContentBrowserClient {
OriginPolicyErrorReason error_reason, OriginPolicyErrorReason error_reason,
const url::Origin& origin, const url::Origin& origin,
const GURL& url); const GURL& url);
// Returns true if it is OK to ignore errors for certificates specified by the
// --ignore-certificate-errors-spki-list command line flag. The embedder may
// perform additional checks, such as requiring --user-data-dir flag too to
// make sure that insecure contents will not persist accidentally.
virtual bool CanIgnoreCertificateErrorIfNeeded();
}; };
} // namespace content } // namespace content
......
...@@ -297,6 +297,11 @@ bool LayoutTestContentBrowserClient::ShouldEnableStrictSiteIsolation() { ...@@ -297,6 +297,11 @@ bool LayoutTestContentBrowserClient::ShouldEnableStrictSiteIsolation() {
return false; return false;
} }
bool LayoutTestContentBrowserClient::CanIgnoreCertificateErrorIfNeeded() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kRunWebTests);
}
void LayoutTestContentBrowserClient::ExposeInterfacesToFrame( void LayoutTestContentBrowserClient::ExposeInterfacesToFrame(
service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>* service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>*
registry) { registry) {
......
...@@ -70,6 +70,7 @@ class LayoutTestContentBrowserClient : public ShellContentBrowserClient { ...@@ -70,6 +70,7 @@ class LayoutTestContentBrowserClient : public ShellContentBrowserClient {
bool opener_suppressed, bool opener_suppressed,
bool* no_javascript_access) override; bool* no_javascript_access) override;
bool ShouldEnableStrictSiteIsolation() override; bool ShouldEnableStrictSiteIsolation() override;
bool CanIgnoreCertificateErrorIfNeeded() override;
// ShellContentBrowserClient overrides. // ShellContentBrowserClient overrides.
void ExposeInterfacesToFrame( void ExposeInterfacesToFrame(
......
...@@ -6,6 +6,13 @@ ...@@ -6,6 +6,13 @@
set -e set -e
dumpSPKIHash() {
openssl x509 -noout -pubkey -in $1 | \
openssl pkey -pubin -outform der | \
openssl dgst -sha256 -binary | \
base64
}
# Generate a "secp256r1 (== prime256v1) ecdsa with sha256" key/cert pair # Generate a "secp256r1 (== prime256v1) ecdsa with sha256" key/cert pair
openssl ecparam -out prime256v1.key -name prime256v1 -genkey openssl ecparam -out prime256v1.key -name prime256v1 -genkey
...@@ -47,4 +54,9 @@ echo 'constexpr char kCertPEMECDSAP384[] = R"(' ...@@ -47,4 +54,9 @@ echo 'constexpr char kCertPEMECDSAP384[] = R"('
cat ./secp384r1-sha256.public.pem cat ./secp384r1-sha256.public.pem
echo ')";' echo ')";'
echo "constexpr char kPEMECDSAP256SPKIHash = "
echo " \"$(dumpSPKIHash ./prime256v1-sha256.public.pem)\";"
echo "constexpr char kPEMECDSAP384SPKIHash = "
echo " \"$(dumpSPKIHash ./secp384r1-sha256.public.pem)\";"
echo "====" echo "===="
...@@ -4691,7 +4691,7 @@ crbug.com/803774 http/tests/devtools/sxg/ [ Skip ] ...@@ -4691,7 +4691,7 @@ crbug.com/803774 http/tests/devtools/sxg/ [ Skip ]
crbug.com/803774 http/tests/loading/sxg/ [ Skip ] crbug.com/803774 http/tests/loading/sxg/ [ Skip ]
# Prefetching Signed Exchange DevTools tests are flaky. # Prefetching Signed Exchange DevTools tests are flaky.
crbug.com/851363 virtual/sxg/http/tests/devtools/sxg/sxg-prefetch-expired.js [ Pass Failure ] crbug.com/851363 virtual/sxg/http/tests/devtools/sxg/sxg-prefetch-fail.js [ Pass Failure ]
crbug.com/851363 virtual/sxg/http/tests/devtools/sxg/sxg-prefetch.js [ Pass Failure ] crbug.com/851363 virtual/sxg/http/tests/devtools/sxg/sxg-prefetch.js [ Pass Failure ]
# Sheriff 2018-03-22 # Sheriff 2018-03-22
......
...@@ -6,11 +6,6 @@ ...@@ -6,11 +6,6 @@
await TestRunner.loadModule('network_test_runner'); await TestRunner.loadModule('network_test_runner');
await TestRunner.loadModule('console_test_runner'); await TestRunner.loadModule('console_test_runner');
await TestRunner.showPanel('network'); await TestRunner.showPanel('network');
await TestRunner.addScriptTag('/loading/sxg/resources/sxg-util.js');
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await TestRunner.evaluateInPageAsync(
'setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"))');
SDK.networkLog.reset(); SDK.networkLog.reset();
await TestRunner.addIframe('/loading/sxg/resources/sxg-cert-not-found.sxg'); await TestRunner.addIframe('/loading/sxg/resources/sxg-cert-not-found.sxg');
ConsoleTestRunner.dumpConsoleMessages(); ConsoleTestRunner.dumpConsoleMessages();
......
...@@ -12,12 +12,6 @@ ...@@ -12,12 +12,6 @@
await TestRunner.loadModule('network_test_runner'); await TestRunner.loadModule('network_test_runner');
await TestRunner.showPanel('network'); await TestRunner.showPanel('network');
await TestRunner.addScriptTag('/loading/sxg/resources/sxg-util.js');
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await TestRunner.evaluateInPageAsync(
'setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"))');
await TestRunner.NetworkAgent.setCacheDisabled(false); await TestRunner.NetworkAgent.setCacheDisabled(false);
// Load the test signed exchange first, to cache the certificate file. // Load the test signed exchange first, to cache the certificate file.
......
Tests the signed exchange information are available when the navigation failed.
inspected-page.html:1 Invalid timestamp. creation_time: 1522540800, expires_time: 1523145600, verification_time: 1523318460
inspected-page.html:1 Failed to verify the signed exchange header.
* http://127.0.0.1:8000/loading/sxg/resources/sxg-location.sxg
failed: false
statusCode: 200
resourceType: signed-exchange
SignedExchangeInfo
Request URL: https://127.0.0.1:8443/loading/sxg/resources/inner-url.html
Certificate URL: https://127.0.0.1:8443/loading/sxg/resources/127.0.0.1.sxg.pem.cbor
Error: {"message":"Invalid timestamp. creation_time: 1522540800, expires_time: 1523145600, verification_time: 1523318460"}
Error: {"message":"Failed to verify the signed exchange header.","signatureIndex":0,"errorField":"signatureTimestamps"}
* https://127.0.0.1:8443/loading/sxg/resources/127.0.0.1.sxg.pem.cbor
failed: false
statusCode: 200
resourceType: other
* https://127.0.0.1:8443/loading/sxg/resources/inner-url.html
failed: false
statusCode: 200
resourceType: document
Tests the signed exchange information are available when the navigation failed.
inspected-page.html:1 Validity URL must be same-origin with request URL.
inspected-page.html:1 Failed to parse SignedExchange header.
* http://127.0.0.1:8000/loading/sxg/resources/sxg-invalid-validity-url.sxg
failed: false
statusCode: 200
resourceType: signed-exchange
SignedExchangeInfo
Error: {"message":"Validity URL must be same-origin with request URL."}
Error: {"message":"Failed to parse SignedExchange header."}
* https://127.0.0.1:8443/loading/sxg/resources/inner-url.html
failed: false
statusCode: 200
resourceType: document
...@@ -6,13 +6,8 @@ ...@@ -6,13 +6,8 @@
await TestRunner.loadModule('network_test_runner'); await TestRunner.loadModule('network_test_runner');
await TestRunner.loadModule('console_test_runner'); await TestRunner.loadModule('console_test_runner');
await TestRunner.showPanel('network'); await TestRunner.showPanel('network');
await TestRunner.addScriptTag('/loading/sxg/resources/sxg-util.js');
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC". So in Apr 10, the page load should fail.
await TestRunner.evaluateInPageAsync(
'setSignedExchangeVerificationTime(new Date("Apr 10 2018 00:01 UTC"))');
SDK.networkLog.reset(); SDK.networkLog.reset();
await TestRunner.addIframe('/loading/sxg/resources/sxg-location.sxg'); await TestRunner.addIframe('/loading/sxg/resources/sxg-invalid-validity-url.sxg');
ConsoleTestRunner.dumpConsoleMessages(); ConsoleTestRunner.dumpConsoleMessages();
NetworkTestRunner.dumpNetworkRequestsWithSignedExchangeInfo(); NetworkTestRunner.dumpNetworkRequestsWithSignedExchangeInfo();
TestRunner.completeTest(); TestRunner.completeTest();
......
...@@ -6,11 +6,6 @@ ...@@ -6,11 +6,6 @@
await TestRunner.loadModule('network_test_runner'); await TestRunner.loadModule('network_test_runner');
await TestRunner.loadModule('console_test_runner'); await TestRunner.loadModule('console_test_runner');
await TestRunner.showPanel('network'); await TestRunner.showPanel('network');
await TestRunner.addScriptTag('/loading/sxg/resources/sxg-util.js');
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await TestRunner.evaluateInPageAsync(
'setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"))');
SDK.networkLog.reset(); SDK.networkLog.reset();
await TestRunner.addIframe('/loading/sxg/resources/sxg-location.sxg'); await TestRunner.addIframe('/loading/sxg/resources/sxg-location.sxg');
ConsoleTestRunner.dumpConsoleMessages(); ConsoleTestRunner.dumpConsoleMessages();
......
Tests the signed exchange information are available when the prefetch failed.
* http://127.0.0.1:8000/loading/sxg/resources/sxg-location.sxg
failed: true
statusCode: 200
resourceType: other
SignedExchangeInfo
Request URL: https://127.0.0.1:8443/loading/sxg/resources/inner-url.html
Certificate URL: https://127.0.0.1:8443/loading/sxg/resources/127.0.0.1.sxg.pem.cbor
Error: {"message":"Invalid timestamp. creation_time: 1522540800, expires_time: 1523145600, verification_time: 1523318460"}
Error: {"message":"Failed to verify the signed exchange header.","signatureIndex":0,"errorField":"signatureTimestamps"}
* https://127.0.0.1:8443/loading/sxg/resources/127.0.0.1.sxg.pem.cbor
failed: false
statusCode: 200
resourceType: other
Tests the signed exchange information are available when the prefetch failed.
* http://127.0.0.1:8000/loading/sxg/resources/sxg-invalid-validity-url.sxg
failed: true
statusCode: 200
resourceType: other
SignedExchangeInfo
Error: {"message":"Validity URL must be same-origin with request URL."}
Error: {"message":"Failed to parse SignedExchange header."}
...@@ -6,18 +6,13 @@ ...@@ -6,18 +6,13 @@
await TestRunner.loadModule('network_test_runner'); await TestRunner.loadModule('network_test_runner');
await TestRunner.loadModule('console_test_runner'); await TestRunner.loadModule('console_test_runner');
await TestRunner.showPanel('network'); await TestRunner.showPanel('network');
await TestRunner.addScriptTag('/loading/sxg/resources/sxg-util.js');
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC". So in Apr 10, the prefetch should fail.
await TestRunner.evaluateInPageAsync(
'setSignedExchangeVerificationTime(new Date("Apr 10 2018 00:01 UTC"))');
SDK.networkLog.reset(); SDK.networkLog.reset();
const promise = new Promise(resolve => { const promise = new Promise(resolve => {
TestRunner.addSniffer(SDK.NetworkDispatcher.prototype, 'loadingFailed', loadingFailed, true); TestRunner.addSniffer(SDK.NetworkDispatcher.prototype, 'loadingFailed', loadingFailed, true);
function loadingFailed(requestId, time, localizedDescription, canceled) { function loadingFailed(requestId, time, localizedDescription, canceled) {
var request = SDK.networkLog.requestByManagerAndId(TestRunner.networkManager, requestId); var request = SDK.networkLog.requestByManagerAndId(TestRunner.networkManager, requestId);
if (/sxg-location\.sxg/.exec(request.url())) if (/sxg-invalid-validity-url\.sxg/.exec(request.url()))
resolve(); resolve();
} }
}); });
...@@ -26,7 +21,7 @@ ...@@ -26,7 +21,7 @@
(function () { (function () {
const link = document.createElement('link'); const link = document.createElement('link');
link.rel = 'prefetch'; link.rel = 'prefetch';
link.href = '/loading/sxg/resources/sxg-location.sxg'; link.href = '/loading/sxg/resources/sxg-invalid-validity-url.sxg';
document.body.appendChild(link); document.body.appendChild(link);
})() })()
`); `);
......
...@@ -6,11 +6,6 @@ ...@@ -6,11 +6,6 @@
await TestRunner.loadModule('network_test_runner'); await TestRunner.loadModule('network_test_runner');
await TestRunner.loadModule('console_test_runner'); await TestRunner.loadModule('console_test_runner');
await TestRunner.showPanel('network'); await TestRunner.showPanel('network');
await TestRunner.addScriptTag('/loading/sxg/resources/sxg-util.js');
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await TestRunner.evaluateInPageAsync(
'setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"))');
SDK.networkLog.reset(); SDK.networkLog.reset();
const promise = new Promise(resolve => { const promise = new Promise(resolve => {
......
...@@ -8,10 +8,6 @@ ...@@ -8,10 +8,6 @@
promise_test(async (t) => { promise_test(async (t) => {
await waitUntilDidFinishLoadForFrame; await waitUntilDidFinishLoadForFrame;
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
const message = await openSXGInIframeAndWaitForMessage(t, 'resources/fallback-to-another-sxg.sxg'); const message = await openSXGInIframeAndWaitForMessage(t, 'resources/fallback-to-another-sxg.sxg');
assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html'); assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html');
assert_false(message.is_fallback); assert_false(message.is_fallback);
......
...@@ -8,10 +8,6 @@ ...@@ -8,10 +8,6 @@
promise_test(async (t) => { promise_test(async (t) => {
await waitUntilDidFinishLoadForFrame; await waitUntilDidFinishLoadForFrame;
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
const message = await openSXGInIframeAndWaitForMessage(t, 'resources/nested-sxg.sxg'); const message = await openSXGInIframeAndWaitForMessage(t, 'resources/nested-sxg.sxg');
assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html?fallback-from-nested-sxg'); assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html?fallback-from-nested-sxg');
assert_true(message.is_fallback); assert_true(message.is_fallback);
......
...@@ -40,24 +40,3 @@ function loadScript(url) { ...@@ -40,24 +40,3 @@ function loadScript(url) {
const waitUntilDidFinishLoadForFrame = new Promise((resolve) => { const waitUntilDidFinishLoadForFrame = new Promise((resolve) => {
window.addEventListener('load', () => setTimeout(resolve, 0)); window.addEventListener('load', () => setTimeout(resolve, 0));
}); });
const mojoBindingsLoaded = (async () => {
await loadScript('/gen/layout_test_data/mojo/public/js/mojo_bindings.js');
mojo.config.autoLoadMojomDeps = false;
const urls = [
'/gen/mojo/public/mojom/base/time.mojom.js',
'/gen/third_party/blink/public/mojom/web_package/web_package_internals.mojom.js',
];
await Promise.all(urls.map(loadScript));
})();
async function setSignedExchangeVerificationTime(time) {
await mojoBindingsLoaded;
const webPackageInternals = new blink.test.mojom.WebPackageInternalsPtr();
Mojo.bindInterface(blink.test.mojom.WebPackageInternals.name,
mojo.makeRequest(webPackageInternals).handle, 'process');
const windowsEpoch = Date.UTC(1601, 0, 1, 0, 0, 0, 0);
return webPackageInternals.setSignedExchangeVerificationTime({
internalValue: (time - windowsEpoch) * 1000
});
}
...@@ -12,9 +12,6 @@ function addPrefetch(url) { ...@@ -12,9 +12,6 @@ function addPrefetch(url) {
document.body.appendChild(link); document.body.appendChild(link);
} }
promise_test(async (t) => { promise_test(async (t) => {
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
const sxg1_url = const sxg1_url =
'http://127.0.0.1:8000/loading/sxg/resources/sxg-location.sxg?1'; 'http://127.0.0.1:8000/loading/sxg/resources/sxg-location.sxg?1';
const sxg2_url = const sxg2_url =
......
<!DOCTYPE html>
<title>Loading expired SignedHTTPExchange must fail</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="./resources/sxg-util.js"></script>
<body>
<script>
promise_test(async (t) => {
await waitUntilDidFinishLoadForFrame;
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC". So in Apr 10, the page load should fail.
await setSignedExchangeVerificationTime(new Date("Apr 10 2018 00:01 UTC"));
const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-location.sxg');
assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html');
assert_true(message.is_fallback);
}, 'Loading expired SignedHTTPExchange must fail');
</script>
</body>
...@@ -8,11 +8,7 @@ ...@@ -8,11 +8,7 @@
promise_test(async (t) => { promise_test(async (t) => {
await waitUntilDidFinishLoadForFrame; await waitUntilDidFinishLoadForFrame;
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-invalid-validity-url.sxg#fragment');
// until "Apr 8 2018 00:00 UTC". So in Apr 10, the page load should fail.
await setSignedExchangeVerificationTime(new Date("Apr 10 2018 00:01 UTC"));
const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-location.sxg#fragment');
assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html#fragment'); assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html#fragment');
assert_true(message.is_fallback); assert_true(message.is_fallback);
}, 'Fallback redirect of SignedHTTPExchange should preserve URL fragment'); }, 'Fallback redirect of SignedHTTPExchange should preserve URL fragment');
......
...@@ -9,10 +9,6 @@ request URL must fail</title> ...@@ -9,10 +9,6 @@ request URL must fail</title>
promise_test(async (t) => { promise_test(async (t) => {
await waitUntilDidFinishLoadForFrame; await waitUntilDidFinishLoadForFrame;
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-invalid-validity-url.sxg'); const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-invalid-validity-url.sxg');
assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html'); assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html');
assert_true(message.is_fallback); assert_true(message.is_fallback);
......
...@@ -8,10 +8,6 @@ ...@@ -8,10 +8,6 @@
promise_test(async (t) => { promise_test(async (t) => {
await waitUntilDidFinishLoadForFrame; await waitUntilDidFinishLoadForFrame;
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-location.sxg#fragment'); const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-location.sxg#fragment');
assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html#fragment'); assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html#fragment');
assert_false(message.is_fallback); assert_false(message.is_fallback);
......
...@@ -8,10 +8,6 @@ ...@@ -8,10 +8,6 @@
promise_test(async (t) => { promise_test(async (t) => {
await waitUntilDidFinishLoadForFrame; await waitUntilDidFinishLoadForFrame;
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-location-origin-trial.php'); const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-location-origin-trial.php');
assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html'); assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html');
assert_false(message.is_fallback); assert_false(message.is_fallback);
......
...@@ -8,10 +8,6 @@ ...@@ -8,10 +8,6 @@
promise_test(async (t) => { promise_test(async (t) => {
await waitUntilDidFinishLoadForFrame; await waitUntilDidFinishLoadForFrame;
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-location.sxg'); const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-location.sxg');
assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html'); assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html');
assert_false(message.is_fallback); assert_false(message.is_fallback);
......
...@@ -8,10 +8,6 @@ ...@@ -8,10 +8,6 @@
promise_test(async (t) => { promise_test(async (t) => {
await waitUntilDidFinishLoadForFrame; await waitUntilDidFinishLoadForFrame;
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
try { try {
await openSXGInIframeAndWaitForMessage( await openSXGInIframeAndWaitForMessage(
t, 'http://example.test:8080/loading/sxg/resources/sxg-location.sxg'); t, 'http://example.test:8080/loading/sxg/resources/sxg-location.sxg');
......
...@@ -8,10 +8,6 @@ ...@@ -8,10 +8,6 @@
promise_test(async (t) => { promise_test(async (t) => {
await waitUntilDidFinishLoadForFrame; await waitUntilDidFinishLoadForFrame;
// The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
// until "Apr 8 2018 00:00 UTC".
await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-usecounter.sxg'); const message = await openSXGInIframeAndWaitForMessage(t, 'resources/sxg-usecounter.sxg');
assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html'); assert_equals(message.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html');
assert_true(message.is_use_counted); assert_true(message.is_use_counted);
......
main frame - didStartProvisionalLoadForFrame
main frame - didCommitLoadForFrame
main frame - didReceiveTitle: Loading expired SignedHTTPExchange must fail
main frame - didFinishDocumentLoadForFrame
main frame - didHandleOnloadEventsForFrame
main frame - didFinishLoadForFrame
frame "sxg_iframe" - didReceiveTitle:
frame "sxg_iframe" - didStartProvisionalLoadForFrame
frame "sxg_iframe" - didFailProvisionalLoadWithError
This is a testharness.js-based test.
FAIL Loading expired SignedHTTPExchange must fail promise_test: Unhandled rejection with value: "timeout"
Harness: the test ran to completion.
main frame - didStartProvisionalLoadForFrame
main frame - didCommitLoadForFrame
main frame - didReceiveTitle: Loading expired SignedHTTPExchange must fail
main frame - didFinishDocumentLoadForFrame
main frame - didHandleOnloadEventsForFrame
main frame - didFinishLoadForFrame
frame "sxg_iframe" - didReceiveTitle:
frame "sxg_iframe" - didStartProvisionalLoadForFrame
frame "sxg_iframe" - didFailProvisionalLoadWithError
This is a testharness.js-based test.
FAIL Loading expired SignedHTTPExchange must fail promise_test: Unhandled rejection with value: "timeout"
Harness: the test ran to completion.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment