1 // Copyright 2016 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 "services/network/expect_ct_reporter.h"
6
7 #include <string>
8
9 #include "base/base64.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/command_line.h"
13 #include "base/json/json_reader.h"
14 #include "base/run_loop.h"
15 #include "base/test/metrics/histogram_tester.h"
16 #include "base/test/scoped_feature_list.h"
17 #include "base/test/task_environment.h"
18 #include "base/values.h"
19 #include "net/cert/ct_serialization.h"
20 #include "net/cert/signed_certificate_timestamp_and_status.h"
21 #include "net/test/cert_test_util.h"
22 #include "net/test/embedded_test_server/embedded_test_server.h"
23 #include "net/test/embedded_test_server/http_request.h"
24 #include "net/test/embedded_test_server/http_response.h"
25 #include "net/test/test_data_directory.h"
26 #include "net/test/url_request/url_request_failed_job.h"
27 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
28 #include "net/url_request/report_sender.h"
29 #include "net/url_request/url_request_filter.h"
30 #include "net/url_request/url_request_test_util.h"
31 #include "services/network/public/cpp/features.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 #include "url/gurl.h"
34
35 namespace network {
36 namespace {
37
38 const char kSendHistogramName[] = "SSL.ExpectCTReportSendingAttempt";
39 const char kFailureHistogramName[] = "SSL.ExpectCTReportFailure2";
40
41 // A test ReportSender that exposes the latest report URI and
42 // serialized report to be sent.
43 class TestCertificateReportSender : public net::ReportSender {
44 public:
TestCertificateReportSender()45 TestCertificateReportSender()
46 : ReportSender(nullptr, TRAFFIC_ANNOTATION_FOR_TESTS) {}
~TestCertificateReportSender()47 ~TestCertificateReportSender() override {}
48
Send(const GURL & report_uri,base::StringPiece content_type,base::StringPiece serialized_report,const base::RepeatingCallback<void ()> & success_callback,const base::RepeatingCallback<void (const GURL &,int,int)> & error_callback)49 void Send(const GURL& report_uri,
50 base::StringPiece content_type,
51 base::StringPiece serialized_report,
52 const base::RepeatingCallback<void()>& success_callback,
53 const base::RepeatingCallback<void(const GURL&, int, int)>&
54 error_callback) override {
55 sent_report_count_++;
56 latest_report_uri_ = report_uri;
57 latest_serialized_report_.assign(serialized_report.data(),
58 serialized_report.size());
59 latest_content_type_.assign(content_type.data(), content_type.size());
60 if (!report_callback_.is_null()) {
61 EXPECT_EQ(expected_report_uri_, latest_report_uri_);
62 std::move(report_callback_).Run();
63 }
64 }
65
sent_report_count() const66 int sent_report_count() const { return sent_report_count_; }
67
latest_report_uri() const68 const GURL& latest_report_uri() const { return latest_report_uri_; }
69
latest_content_type() const70 const std::string& latest_content_type() const {
71 return latest_content_type_;
72 }
73
latest_serialized_report() const74 const std::string& latest_serialized_report() const {
75 return latest_serialized_report_;
76 }
77
78 // Can be called to wait for a single report, which is expected to be sent to
79 // |report_uri|. Returns immediately if a report has already been sent in the
80 // past.
WaitForReport(const GURL & report_uri)81 void WaitForReport(const GURL& report_uri) {
82 if (!latest_report_uri_.is_empty()) {
83 EXPECT_EQ(report_uri, latest_report_uri_);
84 return;
85 }
86 base::RunLoop run_loop;
87 report_callback_ = run_loop.QuitClosure();
88 expected_report_uri_ = report_uri;
89 run_loop.Run();
90 }
91
92 private:
93 int sent_report_count_ = 0;
94 GURL latest_report_uri_;
95 std::string latest_content_type_;
96 std::string latest_serialized_report_;
97 base::OnceClosure report_callback_;
98 GURL expected_report_uri_;
99 };
100
101 // Constructs a net::SignedCertificateTimestampAndStatus with the given
102 // information and appends it to |sct_list|.
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::Origin origin,const std::string & log_id,const std::string & extensions,const std::string & signature_data,const base::Time & timestamp,net::ct::SCTVerifyStatus status,net::SignedCertificateTimestampAndStatusList * sct_list)103 void MakeTestSCTAndStatus(
104 net::ct::SignedCertificateTimestamp::Origin origin,
105 const std::string& log_id,
106 const std::string& extensions,
107 const std::string& signature_data,
108 const base::Time& timestamp,
109 net::ct::SCTVerifyStatus status,
110 net::SignedCertificateTimestampAndStatusList* sct_list) {
111 scoped_refptr<net::ct::SignedCertificateTimestamp> sct(
112 new net::ct::SignedCertificateTimestamp());
113 sct->version = net::ct::SignedCertificateTimestamp::V1;
114 sct->log_id = log_id;
115 sct->extensions = extensions;
116 sct->timestamp = timestamp;
117 sct->signature.signature_data = signature_data;
118 sct->origin = origin;
119 sct_list->push_back(net::SignedCertificateTimestampAndStatus(sct, status));
120 }
121
122 // Checks that |expected_cert| matches the PEM-encoded certificate chain
123 // in |chain|.
CheckReportCertificateChain(const scoped_refptr<net::X509Certificate> & expected_cert,const base::ListValue & chain)124 void CheckReportCertificateChain(
125 const scoped_refptr<net::X509Certificate>& expected_cert,
126 const base::ListValue& chain) {
127 std::vector<std::string> pem_encoded_chain;
128 expected_cert->GetPEMEncodedChain(&pem_encoded_chain);
129 ASSERT_EQ(pem_encoded_chain.size(), chain.GetSize());
130
131 for (size_t i = 0; i < pem_encoded_chain.size(); i++) {
132 std::string cert_pem;
133 ASSERT_TRUE(chain.GetString(i, &cert_pem));
134 EXPECT_EQ(pem_encoded_chain[i], cert_pem);
135 }
136 }
137
138 // Converts the string value of a reported SCT's origin to a
139 // net::ct::SignedCertificateTimestamp::Origin value.
SCTOriginStringToOrigin(const std::string & origin_string)140 net::ct::SignedCertificateTimestamp::Origin SCTOriginStringToOrigin(
141 const std::string& origin_string) {
142 if (origin_string == "embedded")
143 return net::ct::SignedCertificateTimestamp::SCT_EMBEDDED;
144 if (origin_string == "tls-extension")
145 return net::ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION;
146 if (origin_string == "ocsp")
147 return net::ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE;
148 NOTREACHED();
149 return net::ct::SignedCertificateTimestamp::SCT_EMBEDDED;
150 }
151
152 // Checks that an SCT |sct| appears with status |status| in |report_list|, a
153 // list of SCTs from an Expect-CT report.
FindSCTInReportList(const scoped_refptr<net::ct::SignedCertificateTimestamp> & expected_sct,net::ct::SCTVerifyStatus expected_status,const base::ListValue & report_list)154 ::testing::AssertionResult FindSCTInReportList(
155 const scoped_refptr<net::ct::SignedCertificateTimestamp>& expected_sct,
156 net::ct::SCTVerifyStatus expected_status,
157 const base::ListValue& report_list) {
158 std::string expected_serialized_sct;
159 if (!net::ct::EncodeSignedCertificateTimestamp(expected_sct,
160 &expected_serialized_sct)) {
161 return ::testing::AssertionFailure() << "Failed to serialize SCT";
162 }
163
164 for (size_t i = 0; i < report_list.GetSize(); i++) {
165 const base::DictionaryValue* report_sct;
166 if (!report_list.GetDictionary(i, &report_sct)) {
167 return ::testing::AssertionFailure()
168 << "Failed to get dictionary value from report SCT list";
169 }
170
171 std::string serialized_sct;
172 EXPECT_TRUE(report_sct->GetString("serialized_sct", &serialized_sct));
173 std::string decoded_serialized_sct;
174 EXPECT_TRUE(base::Base64Decode(serialized_sct, &decoded_serialized_sct));
175 if (decoded_serialized_sct != expected_serialized_sct)
176 continue;
177
178 std::string source;
179 EXPECT_TRUE(report_sct->GetString("source", &source));
180 EXPECT_EQ(expected_sct->origin, SCTOriginStringToOrigin(source));
181
182 std::string report_status;
183 EXPECT_TRUE(report_sct->GetString("status", &report_status));
184 switch (expected_status) {
185 case net::ct::SCT_STATUS_LOG_UNKNOWN:
186 EXPECT_EQ("unknown", report_status);
187 break;
188 case net::ct::SCT_STATUS_INVALID_SIGNATURE:
189 case net::ct::SCT_STATUS_INVALID_TIMESTAMP: {
190 EXPECT_EQ("invalid", report_status);
191 break;
192 }
193 case net::ct::SCT_STATUS_OK: {
194 EXPECT_EQ("valid", report_status);
195 break;
196 }
197 case net::ct::SCT_STATUS_NONE:
198 NOTREACHED();
199 }
200 return ::testing::AssertionSuccess();
201 }
202
203 return ::testing::AssertionFailure() << "Failed to find SCT in report list";
204 }
205
206 // Checks that all |expected_scts| appears in the given lists of SCTs
207 // from an Expect CT report.
CheckReportSCTs(const net::SignedCertificateTimestampAndStatusList & expected_scts,const base::ListValue & scts)208 void CheckReportSCTs(
209 const net::SignedCertificateTimestampAndStatusList& expected_scts,
210 const base::ListValue& scts) {
211 EXPECT_EQ(expected_scts.size(), scts.GetSize());
212 for (const auto& expected_sct : expected_scts) {
213 ASSERT_TRUE(
214 FindSCTInReportList(expected_sct.sct, expected_sct.status, scts));
215 }
216 }
217
218 // Checks that the |serialized_report| deserializes properly and
219 // contains the correct information (hostname, port, served and
220 // validated certificate chains, SCTs) for the given |host_port| and
221 // |ssl_info|.
CheckExpectCTReport(const std::string & serialized_report,const net::HostPortPair & host_port,const std::string & expiration,const net::SSLInfo & ssl_info)222 void CheckExpectCTReport(const std::string& serialized_report,
223 const net::HostPortPair& host_port,
224 const std::string& expiration,
225 const net::SSLInfo& ssl_info) {
226 std::unique_ptr<base::Value> value(
227 base::JSONReader::ReadDeprecated(serialized_report));
228 ASSERT_TRUE(value);
229 ASSERT_TRUE(value->is_dict());
230
231 base::DictionaryValue* outer_report_dict;
232 ASSERT_TRUE(value->GetAsDictionary(&outer_report_dict));
233
234 base::DictionaryValue* report_dict;
235 ASSERT_TRUE(
236 outer_report_dict->GetDictionary("expect-ct-report", &report_dict));
237
238 std::string report_hostname;
239 EXPECT_TRUE(report_dict->GetString("hostname", &report_hostname));
240 EXPECT_EQ(host_port.host(), report_hostname);
241 int report_port;
242 EXPECT_TRUE(report_dict->GetInteger("port", &report_port));
243 EXPECT_EQ(host_port.port(), report_port);
244
245 std::string report_expiration;
246 EXPECT_TRUE(
247 report_dict->GetString("effective-expiration-date", &report_expiration));
248 EXPECT_EQ(expiration, report_expiration);
249
250 const base::ListValue* report_served_certificate_chain = nullptr;
251 ASSERT_TRUE(report_dict->GetList("served-certificate-chain",
252 &report_served_certificate_chain));
253 ASSERT_NO_FATAL_FAILURE(CheckReportCertificateChain(
254 ssl_info.unverified_cert, *report_served_certificate_chain));
255
256 const base::ListValue* report_validated_certificate_chain = nullptr;
257 ASSERT_TRUE(report_dict->GetList("validated-certificate-chain",
258 &report_validated_certificate_chain));
259 ASSERT_NO_FATAL_FAILURE(CheckReportCertificateChain(
260 ssl_info.cert, *report_validated_certificate_chain));
261
262 const base::ListValue* report_scts = nullptr;
263 ASSERT_TRUE(report_dict->GetList("scts", &report_scts));
264
265 ASSERT_NO_FATAL_FAILURE(
266 CheckReportSCTs(ssl_info.signed_certificate_timestamps, *report_scts));
267 }
268
269 // A test network delegate that allows the user to specify a callback to
270 // be run whenever a net::URLRequest is destroyed.
271 class TestExpectCTNetworkDelegate : public net::NetworkDelegateImpl {
272 public:
TestExpectCTNetworkDelegate()273 TestExpectCTNetworkDelegate()
274 : url_request_destroyed_callback_(base::NullCallback()) {}
275
set_url_request_destroyed_callback(const base::RepeatingClosure & callback)276 void set_url_request_destroyed_callback(
277 const base::RepeatingClosure& callback) {
278 url_request_destroyed_callback_ = callback;
279 }
280
281 // net::NetworkDelegateImpl:
OnURLRequestDestroyed(net::URLRequest * request)282 void OnURLRequestDestroyed(net::URLRequest* request) override {
283 url_request_destroyed_callback_.Run();
284 }
285
286 private:
287 base::RepeatingClosure url_request_destroyed_callback_;
288
289 DISALLOW_COPY_AND_ASSIGN(TestExpectCTNetworkDelegate);
290 };
291
292 // A test fixture that allows tests to send a report and wait until the
293 // net::URLRequest that sent the report is destroyed.
294 class ExpectCTReporterWaitTest : public ::testing::Test {
295 public:
ExpectCTReporterWaitTest()296 ExpectCTReporterWaitTest()
297 : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
298
SetUp()299 void SetUp() override {
300 // Initializes URLRequestContext after the thread is set up.
301 context_.reset(new net::TestURLRequestContext(true));
302 context_->set_network_delegate(&network_delegate_);
303 context_->Init();
304 net::URLRequestFailedJob::AddUrlHandler();
305 }
306
TearDown()307 void TearDown() override {
308 net::URLRequestFilter::GetInstance()->ClearHandlers();
309 }
310
context()311 net::TestURLRequestContext* context() { return context_.get(); }
312
313 protected:
SendReport(ExpectCTReporter * reporter,const net::HostPortPair & host_port,const GURL & report_uri,base::Time expiration,const net::SSLInfo & ssl_info)314 void SendReport(ExpectCTReporter* reporter,
315 const net::HostPortPair& host_port,
316 const GURL& report_uri,
317 base::Time expiration,
318 const net::SSLInfo& ssl_info) {
319 base::RunLoop run_loop;
320 network_delegate_.set_url_request_destroyed_callback(
321 run_loop.QuitClosure());
322 reporter->OnExpectCTFailed(
323 host_port, report_uri, expiration, ssl_info.cert.get(),
324 ssl_info.unverified_cert.get(), ssl_info.signed_certificate_timestamps);
325 run_loop.Run();
326 }
327
328 private:
329 TestExpectCTNetworkDelegate network_delegate_;
330 std::unique_ptr<net::TestURLRequestContext> context_;
331 base::test::TaskEnvironment task_environment_;
332
333 DISALLOW_COPY_AND_ASSIGN(ExpectCTReporterWaitTest);
334 };
335
ReplyToPostWith200(const net::test_server::HttpRequest & request)336 std::unique_ptr<net::test_server::HttpResponse> ReplyToPostWith200(
337 const net::test_server::HttpRequest& request) {
338 if (request.method != net::test_server::METHOD_POST)
339 return nullptr;
340
341 auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
342 http_response->set_code(net::HTTP_OK);
343 return http_response;
344 }
345
HandleReportPreflight(const std::map<std::string,std::string> & cors_headers,base::RepeatingClosure callback,const net::test_server::HttpRequest & request)346 std::unique_ptr<net::test_server::HttpResponse> HandleReportPreflight(
347 const std::map<std::string, std::string>& cors_headers,
348 base::RepeatingClosure callback,
349 const net::test_server::HttpRequest& request) {
350 if (request.method != net::test_server::METHOD_OPTIONS)
351 return nullptr;
352
353 auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
354 http_response->set_code(net::HTTP_OK);
355 for (const auto& cors_header : cors_headers) {
356 http_response->AddCustomHeader(cors_header.first, cors_header.second);
357 }
358
359 if (!callback.is_null()) {
360 callback.Run();
361 }
362
363 return http_response;
364 }
365
HandleReportPreflightForPath(const std::string & path,const std::map<std::string,std::string> & cors_headers,base::RepeatingClosure callback,const net::test_server::HttpRequest & request)366 std::unique_ptr<net::test_server::HttpResponse> HandleReportPreflightForPath(
367 const std::string& path,
368 const std::map<std::string, std::string>& cors_headers,
369 base::RepeatingClosure callback,
370 const net::test_server::HttpRequest& request) {
371 if (request.relative_url != path)
372 return nullptr;
373 return HandleReportPreflight(cors_headers, callback, request);
374 }
375
376 // A test fixture that responds properly to CORS preflights so that reports can
377 // be successfully sent to test_server().
378 class ExpectCTReporterTest : public ::testing::Test {
379 public:
380 const std::map<std::string, std::string> kGoodCorsHeaders{
381 {"Access-Control-Allow-Origin", "*"},
382 {"Access-Control-Allow-Methods", "GET,POST"},
383 {"Access-Control-Allow-Headers", "content-type,another-header"}};
384
ExpectCTReporterTest()385 ExpectCTReporterTest()
386 : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
~ExpectCTReporterTest()387 ~ExpectCTReporterTest() override {}
388
389 protected:
test_server()390 net::EmbeddedTestServer& test_server() { return report_server_; }
391
392 // Tests that reports are not sent when the CORS preflight request returns the
393 // header field |preflight_header_name| with value given by
394 // |preflight_header_bad_value|, and that reports are successfully sent when
395 // it has value given by |preflight_header_good_value|.
TestForReportPreflightFailure(ExpectCTReporter * reporter,TestCertificateReportSender * sender,const net::HostPortPair & host_port,const net::SSLInfo & ssl_info,const std::string & preflight_header_name,const std::string & preflight_header_bad_value,const std::string & preflight_header_good_value)396 void TestForReportPreflightFailure(
397 ExpectCTReporter* reporter,
398 TestCertificateReportSender* sender,
399 const net::HostPortPair& host_port,
400 const net::SSLInfo& ssl_info,
401 const std::string& preflight_header_name,
402 const std::string& preflight_header_bad_value,
403 const std::string& preflight_header_good_value) {
404 const std::string fail_path = "/report1";
405 const std::string successful_path = "/report2";
406
407 std::map<std::string, std::string> bad_cors_headers = kGoodCorsHeaders;
408 bad_cors_headers[preflight_header_name] = preflight_header_bad_value;
409 std::map<std::string, std::string> good_cors_headers = kGoodCorsHeaders;
410 good_cors_headers[preflight_header_name] = preflight_header_good_value;
411
412 base::RunLoop bad_cors_run_loop;
413 report_server_.RegisterRequestHandler(
414 base::BindRepeating(&HandleReportPreflightForPath, fail_path,
415 bad_cors_headers, bad_cors_run_loop.QuitClosure()));
416 report_server_.RegisterRequestHandler(
417 base::BindRepeating(&HandleReportPreflightForPath, successful_path,
418 good_cors_headers, base::RepeatingClosure()));
419 ASSERT_TRUE(report_server_.Start());
420
421 const GURL fail_report_uri = test_server().GetURL(fail_path);
422 const GURL successful_report_uri = test_server().GetURL(successful_path);
423
424 reporter->OnExpectCTFailed(
425 host_port, fail_report_uri, base::Time(), ssl_info.cert.get(),
426 ssl_info.unverified_cert.get(), ssl_info.signed_certificate_timestamps);
427 bad_cors_run_loop.Run();
428 // The CORS preflight response may not even have been received yet, so
429 // these expectations are mostly aspirational.
430 EXPECT_TRUE(sender->latest_report_uri().is_empty());
431 EXPECT_TRUE(sender->latest_serialized_report().empty());
432
433 // Send a report to the url with good CORS headers. The test will fail
434 // if the previous OnExpectCTFailed() call unexpectedly resulted in a
435 // report, as WaitForReport() would see the previous report to /report1
436 // instead of the expected report to /report2, or sent_report_count() will
437 // be 2.
438 reporter->OnExpectCTFailed(
439 host_port, successful_report_uri, base::Time(), ssl_info.cert.get(),
440 ssl_info.unverified_cert.get(), ssl_info.signed_certificate_timestamps);
441 sender->WaitForReport(successful_report_uri);
442 EXPECT_EQ(successful_report_uri, sender->latest_report_uri());
443 EXPECT_EQ(1, sender->sent_report_count());
444 }
445
446 private:
447 base::test::TaskEnvironment task_environment_;
448 net::EmbeddedTestServer report_server_;
449 };
450
451 } // namespace
452
453 // Test that no report is sent when the feature is not enabled.
TEST_F(ExpectCTReporterTest,FeatureDisabled)454 TEST_F(ExpectCTReporterTest, FeatureDisabled) {
455 test_server().RegisterRequestHandler(base::BindRepeating(
456 &HandleReportPreflight, kGoodCorsHeaders, base::RepeatingClosure()));
457 ASSERT_TRUE(test_server().Start());
458
459 base::HistogramTester histograms;
460 histograms.ExpectTotalCount(kSendHistogramName, 0);
461
462 TestCertificateReportSender* sender = new TestCertificateReportSender();
463 net::TestURLRequestContext context;
464 ExpectCTReporter reporter(&context, base::NullCallback(),
465 base::NullCallback());
466 reporter.report_sender_.reset(sender);
467 EXPECT_TRUE(sender->latest_report_uri().is_empty());
468 EXPECT_TRUE(sender->latest_serialized_report().empty());
469
470 net::SSLInfo ssl_info;
471 ssl_info.cert =
472 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
473 ssl_info.unverified_cert = net::ImportCertFromFile(
474 net::GetTestCertsDirectory(), "localhost_cert.pem");
475
476 net::HostPortPair host_port("example.test", 443);
477
478 {
479 const GURL report_uri = test_server().GetURL("/report1");
480 base::test::ScopedFeatureList scoped_feature_list;
481 scoped_feature_list.InitAndDisableFeature(features::kExpectCTReporting);
482
483 reporter.OnExpectCTFailed(
484 host_port, report_uri, base::Time(), ssl_info.cert.get(),
485 ssl_info.unverified_cert.get(), ssl_info.signed_certificate_timestamps);
486 EXPECT_TRUE(sender->latest_report_uri().is_empty());
487 EXPECT_TRUE(sender->latest_serialized_report().empty());
488
489 histograms.ExpectTotalCount(kSendHistogramName, 0);
490 }
491
492 // Enable the feature and send a dummy report. The test will fail if the
493 // previous OnExpectCTFailed() call unexpectedly resulted in a report, as the
494 // WaitForReport() would see the previous report to /report1 instead of the
495 // expected report to /report2.
496 {
497 const GURL report_uri = test_server().GetURL("/report2");
498 base::test::ScopedFeatureList scoped_feature_list;
499 scoped_feature_list.InitAndEnableFeature(features::kExpectCTReporting);
500 reporter.OnExpectCTFailed(
501 host_port, report_uri, base::Time(), ssl_info.cert.get(),
502 ssl_info.unverified_cert.get(), ssl_info.signed_certificate_timestamps);
503 sender->WaitForReport(report_uri);
504 EXPECT_EQ(report_uri, sender->latest_report_uri());
505 EXPECT_EQ(1, sender->sent_report_count());
506 }
507 }
508
509 // Test that no report is sent if the report URI is empty.
TEST_F(ExpectCTReporterTest,EmptyReportURI)510 TEST_F(ExpectCTReporterTest, EmptyReportURI) {
511 base::HistogramTester histograms;
512 histograms.ExpectTotalCount(kSendHistogramName, 0);
513
514 TestCertificateReportSender* sender = new TestCertificateReportSender();
515 net::TestURLRequestContext context;
516 ExpectCTReporter reporter(&context, base::NullCallback(),
517 base::NullCallback());
518 reporter.report_sender_.reset(sender);
519 EXPECT_TRUE(sender->latest_report_uri().is_empty());
520 EXPECT_TRUE(sender->latest_serialized_report().empty());
521
522 reporter.OnExpectCTFailed(net::HostPortPair(), GURL(), base::Time(), nullptr,
523 nullptr,
524 net::SignedCertificateTimestampAndStatusList());
525 EXPECT_TRUE(sender->latest_report_uri().is_empty());
526 EXPECT_TRUE(sender->latest_serialized_report().empty());
527
528 histograms.ExpectTotalCount(kSendHistogramName, 0);
529 }
530
531 // Test that if a report fails to send, the UMA metric is recorded.
TEST_F(ExpectCTReporterWaitTest,SendReportFailure)532 TEST_F(ExpectCTReporterWaitTest, SendReportFailure) {
533 base::HistogramTester histograms;
534 histograms.ExpectTotalCount(kFailureHistogramName, 0);
535 histograms.ExpectTotalCount(kSendHistogramName, 0);
536
537 ExpectCTReporter reporter(context(), base::NullCallback(),
538 base::NullCallback());
539
540 net::SSLInfo ssl_info;
541 ssl_info.cert =
542 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
543 ssl_info.unverified_cert = net::ImportCertFromFile(
544 net::GetTestCertsDirectory(), "localhost_cert.pem");
545
546 net::HostPortPair host_port("example.test", 443);
547 GURL report_uri(
548 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_FAILED));
549
550 SendReport(&reporter, host_port, report_uri, base::Time(), ssl_info);
551
552 histograms.ExpectTotalCount(kFailureHistogramName, 1);
553 histograms.ExpectBucketCount(kFailureHistogramName,
554 -net::ERR_CONNECTION_FAILED, 1);
555 histograms.ExpectTotalCount(kSendHistogramName, 1);
556 histograms.ExpectBucketCount(kSendHistogramName, true, 1);
557 }
558
559 // Test that if a report fails to send, the failure callback is called.
TEST_F(ExpectCTReporterWaitTest,SendReportFailureCallback)560 TEST_F(ExpectCTReporterWaitTest, SendReportFailureCallback) {
561 base::RunLoop run_loop;
562 ExpectCTReporter reporter(context(), base::NullCallback(),
563 run_loop.QuitClosure());
564
565 net::SSLInfo ssl_info;
566 ssl_info.cert =
567 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
568 ssl_info.unverified_cert = net::ImportCertFromFile(
569 net::GetTestCertsDirectory(), "localhost_cert.pem");
570
571 net::HostPortPair host_port("example.test", 443);
572 GURL report_uri(
573 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_FAILED));
574
575 SendReport(&reporter, host_port, report_uri, base::Time(), ssl_info);
576
577 // Wait to make sure the failure callback is called.
578 run_loop.Run();
579 }
580
581 // Test that a sent report has the right format.
TEST_F(ExpectCTReporterTest,SendReport)582 TEST_F(ExpectCTReporterTest, SendReport) {
583 base::HistogramTester histograms;
584 histograms.ExpectTotalCount(kFailureHistogramName, 0);
585 histograms.ExpectTotalCount(kSendHistogramName, 0);
586
587 TestCertificateReportSender* sender = new TestCertificateReportSender();
588 net::TestURLRequestContext context;
589 ExpectCTReporter reporter(&context, base::NullCallback(),
590 base::NullCallback());
591 reporter.report_sender_.reset(sender);
592 EXPECT_TRUE(sender->latest_report_uri().is_empty());
593 EXPECT_TRUE(sender->latest_serialized_report().empty());
594
595 net::SSLInfo ssl_info;
596 ssl_info.cert =
597 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
598 ssl_info.unverified_cert = net::ImportCertFromFile(
599 net::GetTestCertsDirectory(), "localhost_cert.pem");
600
601 base::Time now = base::Time::Now();
602
603 // Append a variety of SCTs: two of each possible status, with a
604 // mixture of different origins.
605
606 // The particular value of the log ID doesn't matter; it just has to be the
607 // correct length.
608 const unsigned char kTestLogId[] = {
609 0xdf, 0x1c, 0x2e, 0xc1, 0x15, 0x00, 0x94, 0x52, 0x47, 0xa9, 0x61,
610 0x68, 0x32, 0x5d, 0xdc, 0x5c, 0x79, 0x59, 0xe8, 0xf7, 0xc6, 0xd3,
611 0x88, 0xfc, 0x00, 0x2e, 0x0b, 0xbd, 0x3f, 0x74, 0xd7, 0x01};
612 const std::string log_id(reinterpret_cast<const char*>(kTestLogId),
613 sizeof(kTestLogId));
614 // The values of the extensions and signature data don't matter
615 // either. However, each SCT has to be unique for the test expectation to be
616 // checked properly in CheckExpectCTReport(), so each SCT has a unique
617 // extensions value to make sure the serialized SCTs are unique.
618 MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
619 log_id, "extensions1", "signature1", now,
620 net::ct::SCT_STATUS_LOG_UNKNOWN,
621 &ssl_info.signed_certificate_timestamps);
622 MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
623 log_id, "extensions2", "signature2", now,
624 net::ct::SCT_STATUS_LOG_UNKNOWN,
625 &ssl_info.signed_certificate_timestamps);
626
627 MakeTestSCTAndStatus(
628 net::ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, log_id,
629 "extensions3", "signature1", now, net::ct::SCT_STATUS_INVALID_TIMESTAMP,
630 &ssl_info.signed_certificate_timestamps);
631
632 MakeTestSCTAndStatus(
633 net::ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, log_id,
634 "extensions4", "signature1", now, net::ct::SCT_STATUS_INVALID_SIGNATURE,
635 &ssl_info.signed_certificate_timestamps);
636
637 MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
638 log_id, "extensions5", "signature2", now,
639 net::ct::SCT_STATUS_INVALID_SIGNATURE,
640 &ssl_info.signed_certificate_timestamps);
641
642 MakeTestSCTAndStatus(
643 net::ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, log_id,
644 "extensions6", "signature1", now, net::ct::SCT_STATUS_OK,
645 &ssl_info.signed_certificate_timestamps);
646 MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
647 log_id, "extensions7", "signature2", now,
648 net::ct::SCT_STATUS_OK,
649 &ssl_info.signed_certificate_timestamps);
650
651 const char kExpirationTimeStr[] = "2017-01-01T00:00:00.000Z";
652 base::Time expiration;
653 ASSERT_TRUE(
654 base::Time::FromUTCExploded({2017, 1, 0, 1, 0, 0, 0, 0}, &expiration));
655
656 const std::string report_path = "/report";
657 base::RunLoop cors_run_loop;
658 test_server().RegisterRequestHandler(
659 base::BindRepeating(&HandleReportPreflightForPath, report_path,
660 kGoodCorsHeaders, cors_run_loop.QuitClosure()));
661 ASSERT_TRUE(test_server().Start());
662 const GURL report_uri = test_server().GetURL(report_path);
663
664 // Check that the report is sent and contains the correct information.
665 reporter.OnExpectCTFailed(net::HostPortPair::FromURL(report_uri), report_uri,
666 expiration, ssl_info.cert.get(),
667 ssl_info.unverified_cert.get(),
668 ssl_info.signed_certificate_timestamps);
669
670 // A CORS preflight request should be sent before the actual report.
671 cors_run_loop.Run();
672 sender->WaitForReport(report_uri);
673
674 EXPECT_EQ(report_uri, sender->latest_report_uri());
675 EXPECT_FALSE(sender->latest_serialized_report().empty());
676 EXPECT_EQ("application/expect-ct-report+json; charset=utf-8",
677 sender->latest_content_type());
678 ASSERT_NO_FATAL_FAILURE(CheckExpectCTReport(
679 sender->latest_serialized_report(),
680 net::HostPortPair::FromURL(report_uri), kExpirationTimeStr, ssl_info));
681
682 histograms.ExpectTotalCount(kFailureHistogramName, 0);
683 histograms.ExpectTotalCount(kSendHistogramName, 1);
684 histograms.ExpectBucketCount(kSendHistogramName, true, 1);
685 }
686
687 // Test that the success callback is called when a report is successfully sent.
TEST_F(ExpectCTReporterTest,SendReportSuccessCallback)688 TEST_F(ExpectCTReporterTest, SendReportSuccessCallback) {
689 test_server().RegisterRequestHandler(base::BindRepeating(
690 &HandleReportPreflight, kGoodCorsHeaders, base::RepeatingClosure()));
691 // This test actually sends the report to the testserver, so register a
692 // handler that will return OK.
693 test_server().RegisterRequestHandler(
694 base::BindRepeating(&ReplyToPostWith200));
695 ASSERT_TRUE(test_server().Start());
696
697 base::RunLoop run_loop;
698
699 net::TestURLRequestContext context;
700 ExpectCTReporter reporter(&context, run_loop.QuitClosure(),
701 base::NullCallback());
702
703 net::SSLInfo ssl_info;
704 ssl_info.cert =
705 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
706 ssl_info.unverified_cert = net::ImportCertFromFile(
707 net::GetTestCertsDirectory(), "localhost_cert.pem");
708
709 // The particular value of the log ID doesn't matter; it just has to be the
710 // correct length.
711 const unsigned char kTestLogId[] = {
712 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
713 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
714 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
715 const std::string log_id(reinterpret_cast<const char*>(kTestLogId),
716 sizeof(kTestLogId));
717 MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
718 log_id, "extensions1", "signature1", base::Time::Now(),
719 net::ct::SCT_STATUS_LOG_UNKNOWN,
720 &ssl_info.signed_certificate_timestamps);
721
722 base::Time expiration;
723 ASSERT_TRUE(
724 base::Time::FromUTCExploded({2017, 1, 0, 1, 0, 0, 0, 0}, &expiration));
725
726 const GURL report_uri = test_server().GetURL("/report");
727
728 reporter.OnExpectCTFailed(net::HostPortPair::FromURL(report_uri), report_uri,
729 expiration, ssl_info.cert.get(),
730 ssl_info.unverified_cert.get(),
731 ssl_info.signed_certificate_timestamps);
732
733 // Wait to check that the success callback is run.
734 run_loop.Run();
735 }
736
737 // Test that report preflight responses can contain whitespace.
TEST_F(ExpectCTReporterTest,PreflightContainsWhitespace)738 TEST_F(ExpectCTReporterTest, PreflightContainsWhitespace) {
739 const std::string report_path = "/report";
740 std::map<std::string, std::string> cors_headers = kGoodCorsHeaders;
741 cors_headers["Access-Control-Allow-Methods"] = "GET, POST";
742 base::RunLoop cors_run_loop;
743 test_server().RegisterRequestHandler(
744 base::BindRepeating(&HandleReportPreflightForPath, report_path,
745 cors_headers, cors_run_loop.QuitClosure()));
746 ASSERT_TRUE(test_server().Start());
747
748 TestCertificateReportSender* sender = new TestCertificateReportSender();
749 net::TestURLRequestContext context;
750 ExpectCTReporter reporter(&context, base::NullCallback(),
751 base::NullCallback());
752 reporter.report_sender_.reset(sender);
753 EXPECT_TRUE(sender->latest_report_uri().is_empty());
754 EXPECT_TRUE(sender->latest_serialized_report().empty());
755
756 net::SSLInfo ssl_info;
757 ssl_info.cert =
758 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
759 ssl_info.unverified_cert = net::ImportCertFromFile(
760 net::GetTestCertsDirectory(), "localhost_cert.pem");
761
762 const GURL report_uri = test_server().GetURL(report_path);
763 reporter.OnExpectCTFailed(net::HostPortPair::FromURL(report_uri), report_uri,
764 base::Time::Now(), ssl_info.cert.get(),
765 ssl_info.unverified_cert.get(),
766 ssl_info.signed_certificate_timestamps);
767
768 // A CORS preflight request should be sent before the actual report.
769 cors_run_loop.Run();
770 sender->WaitForReport(report_uri);
771
772 EXPECT_EQ(report_uri, sender->latest_report_uri());
773 EXPECT_FALSE(sender->latest_serialized_report().empty());
774 }
775
776 // Test that no report is sent when the CORS preflight returns an invalid
777 // Access-Control-Allow-Origin.
TEST_F(ExpectCTReporterTest,BadCorsPreflightResponseOrigin)778 TEST_F(ExpectCTReporterTest, BadCorsPreflightResponseOrigin) {
779 TestCertificateReportSender* sender = new TestCertificateReportSender();
780 net::TestURLRequestContext context;
781 ExpectCTReporter reporter(&context, base::NullCallback(),
782 base::NullCallback());
783 reporter.report_sender_.reset(sender);
784 EXPECT_TRUE(sender->latest_report_uri().is_empty());
785 EXPECT_TRUE(sender->latest_serialized_report().empty());
786
787 net::SSLInfo ssl_info;
788 ssl_info.cert =
789 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
790 ssl_info.unverified_cert = net::ImportCertFromFile(
791 net::GetTestCertsDirectory(), "localhost_cert.pem");
792
793 base::test::ScopedFeatureList scoped_feature_list;
794 scoped_feature_list.InitAndEnableFeature(features::kExpectCTReporting);
795 EXPECT_TRUE(sender->latest_serialized_report().empty());
796 ASSERT_NO_FATAL_FAILURE(TestForReportPreflightFailure(
797 &reporter, sender, net::HostPortPair("example.test", 443), ssl_info,
798 "Access-Control-Allow-Origin", "https://another-origin.test", "null"));
799 }
800
801 // Test that no report is sent when the CORS preflight returns an invalid
802 // Access-Control-Allow-Methods.
TEST_F(ExpectCTReporterTest,BadCorsPreflightResponseMethods)803 TEST_F(ExpectCTReporterTest, BadCorsPreflightResponseMethods) {
804 TestCertificateReportSender* sender = new TestCertificateReportSender();
805 net::TestURLRequestContext context;
806 ExpectCTReporter reporter(&context, base::NullCallback(),
807 base::NullCallback());
808 reporter.report_sender_.reset(sender);
809 EXPECT_TRUE(sender->latest_report_uri().is_empty());
810 EXPECT_TRUE(sender->latest_serialized_report().empty());
811
812 net::SSLInfo ssl_info;
813 ssl_info.cert =
814 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
815 ssl_info.unverified_cert = net::ImportCertFromFile(
816 net::GetTestCertsDirectory(), "localhost_cert.pem");
817
818 base::test::ScopedFeatureList scoped_feature_list;
819 scoped_feature_list.InitAndEnableFeature(features::kExpectCTReporting);
820 EXPECT_TRUE(sender->latest_serialized_report().empty());
821 ASSERT_NO_FATAL_FAILURE(TestForReportPreflightFailure(
822 &reporter, sender, net::HostPortPair("example.test", 443), ssl_info,
823 "Access-Control-Allow-Methods", "GET,HEAD,POSSSST", "POST"));
824 }
825
826 // Test that no report is sent when the CORS preflight returns an invalid
827 // Access-Control-Allow-Headers.
TEST_F(ExpectCTReporterTest,BadCorsPreflightResponseHeaders)828 TEST_F(ExpectCTReporterTest, BadCorsPreflightResponseHeaders) {
829 TestCertificateReportSender* sender = new TestCertificateReportSender();
830 net::TestURLRequestContext context;
831 ExpectCTReporter reporter(&context, base::NullCallback(),
832 base::NullCallback());
833 reporter.report_sender_.reset(sender);
834 EXPECT_TRUE(sender->latest_report_uri().is_empty());
835 EXPECT_TRUE(sender->latest_serialized_report().empty());
836
837 net::SSLInfo ssl_info;
838 ssl_info.cert =
839 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
840 ssl_info.unverified_cert = net::ImportCertFromFile(
841 net::GetTestCertsDirectory(), "localhost_cert.pem");
842
843 base::test::ScopedFeatureList scoped_feature_list;
844 scoped_feature_list.InitAndEnableFeature(features::kExpectCTReporting);
845 EXPECT_TRUE(sender->latest_serialized_report().empty());
846 ASSERT_NO_FATAL_FAILURE(TestForReportPreflightFailure(
847 &reporter, sender, net::HostPortPair("example.test", 443), ssl_info,
848 "Access-Control-Allow-Headers", "Not-Content-Type", "Content-Type"));
849 }
850
851 } // namespace network
852