| Index: net/url_request/url_request_unittest.cc
|
| diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
|
| index ecff043877c54d88952a34bbccdcfb1eb4b96ee5..214900aeae9ec1f78377b4d03e63bb92f5a5ddc0 100644
|
| --- a/net/url_request/url_request_unittest.cc
|
| +++ b/net/url_request/url_request_unittest.cc
|
| @@ -20,6 +20,7 @@
|
| #include "base/files/file_util.h"
|
| #include "base/files/scoped_temp_dir.h"
|
| #include "base/format_macros.h"
|
| +#include "base/json/json_reader.h"
|
| #include "base/location.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/memory/weak_ptr.h"
|
| @@ -35,6 +36,7 @@
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/test/histogram_tester.h"
|
| #include "base/thread_task_runner_handle.h"
|
| +#include "base/values.h"
|
| #include "net/base/chunked_upload_data_stream.h"
|
| #include "net/base/elements_upload_data_stream.h"
|
| #include "net/base/load_flags.h"
|
| @@ -618,6 +620,27 @@ class TestURLRequestContextWithProxy : public TestURLRequestContext {
|
| ~TestURLRequestContextWithProxy() override {}
|
| };
|
|
|
| +// A mock ReportSender that just remembers the latest report
|
| +// URI and report to be sent.
|
| +class MockCertificateReportSender
|
| + : public TransportSecurityState::ReportSender {
|
| + public:
|
| + MockCertificateReportSender() {}
|
| + ~MockCertificateReportSender() override {}
|
| +
|
| + void Send(const GURL& report_uri, const std::string& report) override {
|
| + latest_report_uri_ = report_uri;
|
| + latest_report_ = report;
|
| + }
|
| +
|
| + const GURL& latest_report_uri() { return latest_report_uri_; }
|
| + const std::string& latest_report() { return latest_report_; }
|
| +
|
| + private:
|
| + GURL latest_report_uri_;
|
| + std::string latest_report_;
|
| +};
|
| +
|
| } // namespace
|
|
|
| // Inherit PlatformTest since we require the autorelease pool on Mac OS X.
|
| @@ -5361,13 +5384,26 @@ TEST_F(URLRequestTestHTTP, STSNotProcessedOnIP) {
|
| // PKPState present because header rejected).
|
| #if defined(OS_ANDROID)
|
| #define MAYBE_ProcessPKP DISABLED_ProcessPKP
|
| +#define MAYBE_ProcessPKPAndSendReport DISABLED_ProcessPKPAndSendReport
|
| +#define MAYBE_ProcessPKPReportOnly DISABLED_ProcessPKPReportOnly
|
| +#define MAYBE_ProcessPKPReportOnlyWithNoViolation \
|
| + DISABLED_ProcessPKPReportOnlyWithNoViolation
|
| #else
|
| #define MAYBE_ProcessPKP ProcessPKP
|
| +#define MAYBE_ProcessPKPAndSendReport ProcessPKPAndSendReport
|
| +#define MAYBE_ProcessPKPReportOnly ProcessPKPReportOnly
|
| +#define MAYBE_ProcessPKPReportOnlyWithNoViolation \
|
| + ProcessPKPReportOnlyWithNoViolation
|
| #endif
|
|
|
| +namespace {
|
| +const char kHPKPReportUri[] = "https://hpkp-report.test";
|
| +} // namespace
|
| +
|
| // Tests that enabling HPKP on a domain does not affect the HSTS
|
| // validity/expiration.
|
| TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKP) {
|
| + GURL report_uri(kHPKPReportUri);
|
| SpawnedTestServer::SSLOptions ssl_options(
|
| SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
|
| SpawnedTestServer https_test_server(SpawnedTestServer::TYPE_HTTPS,
|
| @@ -5397,9 +5433,188 @@ TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKP) {
|
| EXPECT_FALSE(sts_state.include_subdomains);
|
| EXPECT_FALSE(pkp_state.include_subdomains);
|
| EXPECT_TRUE(pkp_state.HasPublicKeyPins());
|
| + EXPECT_EQ(report_uri, pkp_state.report_uri);
|
| EXPECT_NE(sts_state.expiry, pkp_state.expiry);
|
| }
|
|
|
| +// Tests that reports get sent on HPKP violations when a report-uri is set.
|
| +TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPAndSendReport) {
|
| + GURL report_uri(kHPKPReportUri);
|
| + SpawnedTestServer::SSLOptions ssl_options(
|
| + SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
|
| + SpawnedTestServer https_test_server(SpawnedTestServer::TYPE_HTTPS,
|
| + ssl_options,
|
| + base::FilePath(kTestFilePath));
|
| +
|
| + ASSERT_TRUE(https_test_server.Start());
|
| +
|
| + std::string test_server_hostname = https_test_server.GetURL("").host();
|
| +
|
| + // Set up a pin for |test_server_hostname|.
|
| + TransportSecurityState security_state;
|
| + const base::Time current_time(base::Time::Now());
|
| + const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
|
| + HashValueVector hashes;
|
| + HashValue hash1;
|
| + HashValue hash2;
|
| + // The values here don't matter, as long as they are different from
|
| + // the mocked CertVerifyResult below.
|
| + ASSERT_TRUE(hash1.FromString("sha1/111111111111111111111111111="));
|
| + ASSERT_TRUE(hash2.FromString("sha1/222222222222222222222222222="));
|
| + hashes.push_back(hash1);
|
| + hashes.push_back(hash2);
|
| + security_state.AddHPKP(test_server_hostname, expiry,
|
| + false, /* include subdomains */
|
| + hashes, report_uri);
|
| +
|
| + MockCertificateReportSender mock_report_sender;
|
| + security_state.SetReportSender(&mock_report_sender);
|
| +
|
| + // Set up a MockCertVerifier to trigger a violation of the previously
|
| + // set pin.
|
| + scoped_refptr<X509Certificate> cert = https_test_server.GetCertificate();
|
| + ASSERT_TRUE(cert);
|
| +
|
| + MockCertVerifier cert_verifier;
|
| + CertVerifyResult verify_result;
|
| + verify_result.verified_cert = cert;
|
| + verify_result.is_issued_by_known_root = true;
|
| + HashValue hash3;
|
| + ASSERT_TRUE(hash3.FromString("sha1/333333333333333333333333333="));
|
| + verify_result.public_key_hashes.push_back(hash3);
|
| + cert_verifier.AddResultForCert(cert.get(), verify_result, OK);
|
| +
|
| + TestNetworkDelegate network_delegate;
|
| + TestURLRequestContext context(true);
|
| + context.set_transport_security_state(&security_state);
|
| + context.set_network_delegate(&network_delegate);
|
| + context.set_cert_verifier(&cert_verifier);
|
| + context.Init();
|
| +
|
| + // Now send a request to trigger the violation.
|
| + TestDelegate d;
|
| + scoped_ptr<URLRequest> violating_request(context.CreateRequest(
|
| + https_test_server.GetURL("files/simple.html"), DEFAULT_PRIORITY, &d));
|
| + violating_request->Start();
|
| + base::RunLoop().Run();
|
| +
|
| + // Check that a report was sent.
|
| + EXPECT_EQ(report_uri, mock_report_sender.latest_report_uri());
|
| + ASSERT_FALSE(mock_report_sender.latest_report().empty());
|
| + scoped_ptr<base::Value> value(
|
| + base::JSONReader::Read(mock_report_sender.latest_report()));
|
| + ASSERT_TRUE(value);
|
| + ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY));
|
| + base::DictionaryValue* report_dict;
|
| + ASSERT_TRUE(value->GetAsDictionary(&report_dict));
|
| + std::string report_hostname;
|
| + EXPECT_TRUE(report_dict->GetString("hostname", &report_hostname));
|
| + EXPECT_EQ(test_server_hostname, report_hostname);
|
| +}
|
| +
|
| +// Tests that reports get sent on requests with
|
| +// Public-Key-Pins-Report-Only headers.
|
| +TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPReportOnly) {
|
| + GURL report_uri(kHPKPReportUri);
|
| + SpawnedTestServer::SSLOptions ssl_options(
|
| + SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
|
| + SpawnedTestServer https_test_server(SpawnedTestServer::TYPE_HTTPS,
|
| + ssl_options,
|
| + base::FilePath(kTestFilePath));
|
| +
|
| + ASSERT_TRUE(https_test_server.Start());
|
| +
|
| + std::string test_server_hostname = https_test_server.GetURL("").host();
|
| +
|
| + TransportSecurityState security_state;
|
| + MockCertificateReportSender mock_report_sender;
|
| + security_state.SetReportSender(&mock_report_sender);
|
| +
|
| + // Set up a MockCertVerifier to violate the pin in the Report-Only
|
| + // header.
|
| + scoped_refptr<X509Certificate> cert = https_test_server.GetCertificate();
|
| + ASSERT_TRUE(cert);
|
| +
|
| + MockCertVerifier cert_verifier;
|
| + CertVerifyResult verify_result;
|
| + verify_result.verified_cert = cert;
|
| + verify_result.is_issued_by_known_root = true;
|
| + HashValue hash;
|
| + // This value doesn't matter, as long as it is different from the pins
|
| + // for the request to hpkp-headers-report-only.html.
|
| + ASSERT_TRUE(hash.FromString("sha1/111111111111111111111111111="));
|
| + verify_result.public_key_hashes.push_back(hash);
|
| + cert_verifier.AddResultForCert(cert.get(), verify_result, OK);
|
| +
|
| + TestNetworkDelegate network_delegate;
|
| + TestURLRequestContext context(true);
|
| + context.set_transport_security_state(&security_state);
|
| + context.set_network_delegate(&network_delegate);
|
| + context.set_cert_verifier(&cert_verifier);
|
| + context.Init();
|
| +
|
| + // Now send a request to trigger the violation.
|
| + TestDelegate d;
|
| + scoped_ptr<URLRequest> violating_request(context.CreateRequest(
|
| + https_test_server.GetURL("files/hpkp-headers-report-only.html"),
|
| + DEFAULT_PRIORITY, &d));
|
| + violating_request->Start();
|
| + base::RunLoop().Run();
|
| +
|
| + // Check that a report was sent.
|
| + EXPECT_EQ(report_uri, mock_report_sender.latest_report_uri());
|
| + ASSERT_FALSE(mock_report_sender.latest_report().empty());
|
| + scoped_ptr<base::Value> value(
|
| + base::JSONReader::Read(mock_report_sender.latest_report()));
|
| + ASSERT_TRUE(value);
|
| + ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY));
|
| + base::DictionaryValue* report_dict;
|
| + ASSERT_TRUE(value->GetAsDictionary(&report_dict));
|
| + std::string report_hostname;
|
| + EXPECT_TRUE(report_dict->GetString("hostname", &report_hostname));
|
| + EXPECT_EQ(test_server_hostname, report_hostname);
|
| +}
|
| +
|
| +// Tests that reports do not get sent on requests with
|
| +// Public-Key-Pins-Report-Only headers that don't have pin violations.
|
| +TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPReportOnlyWithNoViolation) {
|
| + GURL report_uri(kHPKPReportUri);
|
| + SpawnedTestServer::SSLOptions ssl_options(
|
| + SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
|
| + SpawnedTestServer https_test_server(SpawnedTestServer::TYPE_HTTPS,
|
| + ssl_options,
|
| + base::FilePath(kTestFilePath));
|
| +
|
| + ASSERT_TRUE(https_test_server.Start());
|
| +
|
| + std::string test_server_hostname = https_test_server.GetURL("").host();
|
| +
|
| + TransportSecurityState security_state;
|
| + MockCertificateReportSender mock_report_sender;
|
| + security_state.SetReportSender(&mock_report_sender);
|
| +
|
| + TestNetworkDelegate network_delegate;
|
| + MockCertVerifier mock_cert_verifier;
|
| + TestURLRequestContext context(true);
|
| + context.set_transport_security_state(&security_state);
|
| + context.set_network_delegate(&network_delegate);
|
| + context.set_cert_verifier(&mock_cert_verifier);
|
| + mock_cert_verifier.set_default_result(OK);
|
| + context.Init();
|
| +
|
| + // Now send a request that does not trigger the violation.
|
| + TestDelegate d;
|
| + scoped_ptr<URLRequest> request(context.CreateRequest(
|
| + https_test_server.GetURL("files/hpkp-headers-report-only.html"),
|
| + DEFAULT_PRIORITY, &d));
|
| + request->Start();
|
| + base::RunLoop().Run();
|
| +
|
| + // Check that a report was not sent.
|
| + EXPECT_EQ(GURL(), mock_report_sender.latest_report_uri());
|
| + EXPECT_EQ(std::string(), mock_report_sender.latest_report());
|
| +}
|
| +
|
| TEST_F(URLRequestTestHTTP, PKPNotProcessedOnIP) {
|
| SpawnedTestServer https_test_server(SpawnedTestServer::TYPE_HTTPS,
|
| SpawnedTestServer::SSLOptions(),
|
|
|