Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(396)

Side by Side Diff: chrome/browser/net/certificate_error_reporter_unittest.cc

Issue 1212973002: Add net::CertificateReportSender for handling cert report sending (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: style fixes Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/net/certificate_error_reporter.h" 5 #include "chrome/browser/net/certificate_error_reporter.h"
6 6
7 #include <set> 7 #include <set>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
12 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "chrome/browser/net/encrypted_cert_logger.pb.h" 13 #include "chrome/browser/net/encrypted_cert_logger.pb.h"
17 #include "chrome/common/chrome_paths.h" 14 #include "chrome/common/chrome_paths.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "crypto/curve25519.h" 15 #include "crypto/curve25519.h"
20 #include "net/base/load_flags.h" 16 #include "net/http/certificate_report_sender.h"
21 #include "net/base/network_delegate_impl.h"
22 #include "net/base/upload_bytes_element_reader.h"
23 #include "net/base/upload_data_stream.h"
24 #include "net/base/upload_element_reader.h"
25 #include "net/test/url_request/url_request_failed_job.h"
26 #include "net/test/url_request/url_request_mock_data_job.h"
27 #include "net/url_request/url_request_filter.h"
28 #include "net/url_request/url_request_test_util.h"
29 #include "testing/gtest/include/gtest/gtest.h" 17 #include "testing/gtest/include/gtest/gtest.h"
30 18
31 using chrome_browser_net::CertificateErrorReporter; 19 using chrome_browser_net::CertificateErrorReporter;
32 using content::BrowserThread;
33 using net::CertStatus;
34 using net::CompletionCallback;
35 using net::NetworkDelegateImpl;
36 using net::TestURLRequestContext;
37 using net::URLRequest;
38 20
39 namespace { 21 namespace {
40 22
41 const char kDummyReport[] = "test.mail.google.com"; 23 const char kDummyReportUri[] = "http://example.com";
davidben 2015/07/23 00:09:41 Maybe have const char kDummyReportHttpUri[] const
estark 2015/07/23 02:41:21 Done.
42 const char kSecondDummyReport[] = "test2.mail.google.com"; 24 const char kDummyReport[] = "a dummy report";
43 const uint32 kServerPublicKeyVersion = 1; 25 const uint32 kServerPublicKeyVersion = 1;
44 26
45 void EnableUrlRequestMocks(bool enable) { 27 // A mock CertificateReportSender that keeps track of the last report
46 net::URLRequestFilter::GetInstance()->ClearHandlers(); 28 // sent.
47 if (!enable) 29 class MockCertificateReportSender : public net::CertificateReportSender {
48 return; 30 public:
31 MockCertificateReportSender() {}
32 ~MockCertificateReportSender() override {}
49 33
50 net::URLRequestFailedJob::AddUrlHandler(); 34 void Send(const GURL& report_uri, const std::string& report) override {
51 net::URLRequestMockDataJob::AddUrlHandler(); 35 latest_report_uri_ = report_uri;
36 latest_report_ = report;
37 }
38
39 const GURL& latest_report_uri() { return latest_report_uri_; }
40
41 const std::string& latest_report() { return latest_report_; }
42
43 private:
44 GURL latest_report_uri_;
45 std::string latest_report_;
46
47 DISALLOW_COPY_AND_ASSIGN(MockCertificateReportSender);
48 };
49
50 class CertificateErrorReporterTest : public ::testing::Test {
51 public:
52 CertificateErrorReporterTest() {
53 memset(server_private_key_, 1, sizeof(server_private_key_));
54 crypto::curve25519::ScalarBaseMult(server_private_key_, server_public_key_);
55 }
56
57 ~CertificateErrorReporterTest() override {}
58
59 const uint8* server_public_key() { return server_public_key_; }
davidben 2015/07/23 00:09:41 I think uint8_t is preferred for new code. Althoug
estark 2015/07/23 02:41:21 Done.
60 const uint8* server_private_key() { return server_private_key_; }
61
62 private:
63 uint8 server_public_key_[32];
64 uint8 server_private_key_[32];
65 };
66
67 // Test that CertificateErrorReporter::SendReport sends a plaintext
68 // report for pinning violation reports.
69 TEST_F(CertificateErrorReporterTest, PinningViolationSendReport) {
70 GURL url(kDummyReportUri);
71 MockCertificateReportSender* mock_report_sender =
72 new MockCertificateReportSender();
73 CertificateErrorReporter reporter(
74 url, server_public_key(), kServerPublicKeyVersion,
75 scoped_ptr<MockCertificateReportSender>(mock_report_sender));
76 reporter.SendReport(CertificateErrorReporter::REPORT_TYPE_PINNING_VIOLATION,
77 kDummyReport);
78 EXPECT_EQ(mock_report_sender->latest_report_uri(), url);
79 EXPECT_EQ(mock_report_sender->latest_report(), kDummyReport);
52 } 80 }
53 81
54 // Check that data uploaded in the request matches the test report 82 // Test that CertificateErrorReporter::SendReport sends an encrypted or
55 // data. The sent reports will be erased from |expect_reports|. 83 // plaintext extended reporting report as appropriate.
56 void CheckUploadData(URLRequest* request, 84 TEST_F(CertificateErrorReporterTest, ExtendedReportingSendReport) {
57 std::set<std::string>* expect_reports, 85 // Data should not be encrypted when sent to an HTTPS URL.
58 bool encrypted, 86 MockCertificateReportSender* mock_report_sender =
59 const uint8* server_private_key) { 87 new MockCertificateReportSender();
60 const net::UploadDataStream* upload = request->get_upload(); 88 GURL https_url("https://example.com");
61 ASSERT_TRUE(upload); 89 CertificateErrorReporter https_reporter(
62 ASSERT_TRUE(upload->GetElementReaders()); 90 https_url, server_public_key(), kServerPublicKeyVersion,
63 EXPECT_EQ(1u, upload->GetElementReaders()->size()); 91 scoped_ptr<MockCertificateReportSender>(mock_report_sender));
92 https_reporter.SendReport(
93 CertificateErrorReporter::REPORT_TYPE_EXTENDED_REPORTING, kDummyReport);
94 EXPECT_EQ(mock_report_sender->latest_report_uri(), https_url);
95 EXPECT_EQ(mock_report_sender->latest_report(), kDummyReport);
64 96
65 const net::UploadBytesElementReader* reader = 97 // Data should be encrypted when sent to an HTTP URL.
66 (*upload->GetElementReaders())[0]->AsBytesReader(); 98 if (CertificateErrorReporter::IsHttpUploadUrlSupported()) {
67 ASSERT_TRUE(reader); 99 GURL http_url(kDummyReportUri);
68 std::string upload_data(reader->bytes(), reader->length()); 100 CertificateErrorReporter http_reporter(
101 http_url, server_public_key(), kServerPublicKeyVersion,
102 scoped_ptr<MockCertificateReportSender>(mock_report_sender));
103 http_reporter.SendReport(
104 CertificateErrorReporter::REPORT_TYPE_EXTENDED_REPORTING, kDummyReport);
69 105
70 std::string uploaded_report; 106 EXPECT_EQ(mock_report_sender->latest_report_uri(), http_url);
107
108 std::string uploaded_report;
71 #if defined(USE_OPENSSL) 109 #if defined(USE_OPENSSL)
72 if (encrypted) {
73 chrome_browser_net::EncryptedCertLoggerRequest encrypted_request; 110 chrome_browser_net::EncryptedCertLoggerRequest encrypted_request;
74 ASSERT_TRUE(encrypted_request.ParseFromString(upload_data)); 111 ASSERT_TRUE(
112 encrypted_request.ParseFromString(mock_report_sender->latest_report()));
75 EXPECT_EQ(kServerPublicKeyVersion, 113 EXPECT_EQ(kServerPublicKeyVersion,
76 encrypted_request.server_public_key_version()); 114 encrypted_request.server_public_key_version());
77 EXPECT_EQ(chrome_browser_net::EncryptedCertLoggerRequest:: 115 EXPECT_EQ(chrome_browser_net::EncryptedCertLoggerRequest::
78 AEAD_ECDH_AES_128_CTR_HMAC_SHA256, 116 AEAD_ECDH_AES_128_CTR_HMAC_SHA256,
79 encrypted_request.algorithm()); 117 encrypted_request.algorithm());
80 ASSERT_TRUE(CertificateErrorReporter::DecryptCertificateErrorReport( 118 ASSERT_TRUE(CertificateErrorReporter::DecryptCertificateErrorReport(
81 server_private_key, encrypted_request, &uploaded_report)); 119 server_private_key(), encrypted_request, &uploaded_report));
82 } else {
83 uploaded_report = upload_data;
84 }
85 #else 120 #else
86 uploaded_report = upload_data; 121 uploaded_report = mock_report_sender->latest_report();
davidben 2015/07/23 00:09:41 This line can't run, right? Maybe just ADD_FAIL
estark 2015/07/23 02:41:21 Done.
87 #endif 122 #endif
88 123
89 EXPECT_EQ(1u, expect_reports->count(uploaded_report)); 124 EXPECT_EQ(kDummyReport, uploaded_report);
90 expect_reports->erase(uploaded_report);
91 }
92
93 // A network delegate that lets tests check that a certificate error
94 // report was sent. It counts the number of requests and lets tests
95 // register a callback to run when the request is destroyed. It also
96 // checks that the uploaded data is as expected.
97 class TestCertificateErrorReporterNetworkDelegate : public NetworkDelegateImpl {
98 public:
99 TestCertificateErrorReporterNetworkDelegate()
100 : url_request_destroyed_callback_(base::Bind(&base::DoNothing)),
101 all_url_requests_destroyed_callback_(base::Bind(&base::DoNothing)),
102 num_requests_(0),
103 expect_cookies_(false),
104 expect_request_encrypted_(false) {
105 memset(server_private_key_, 1, sizeof(server_private_key_));
106 crypto::curve25519::ScalarBaseMult(server_private_key_, server_public_key_);
107 }
108
109 ~TestCertificateErrorReporterNetworkDelegate() override {}
110
111 void ExpectReport(const std::string& report) {
112 expect_reports_.insert(report);
113 }
114
115 void set_all_url_requests_destroyed_callback(
116 const base::Closure& all_url_requests_destroyed_callback) {
117 all_url_requests_destroyed_callback_ = all_url_requests_destroyed_callback;
118 }
119
120 void set_url_request_destroyed_callback(
121 const base::Closure& url_request_destroyed_callback) {
122 url_request_destroyed_callback_ = url_request_destroyed_callback;
123 }
124
125 void set_expect_url(const GURL& expect_url) { expect_url_ = expect_url; }
126
127 int num_requests() const { return num_requests_; }
128
129 // Sets whether cookies are expected to be sent on requests. If set to
130 // true, then |OnHeadersReceived| will expect a cookie
131 // "cookie_name=cookie_value".
132 void set_expect_cookies(bool expect_cookies) {
133 expect_cookies_ = expect_cookies;
134 }
135
136 void set_expect_request_encrypted(bool expect_request_encrypted) {
137 expect_request_encrypted_ = expect_request_encrypted;
138 }
139
140 // NetworkDelegateImpl implementation
141 int OnBeforeURLRequest(URLRequest* request,
142 const CompletionCallback& callback,
143 GURL* new_url) override {
144 num_requests_++;
145 EXPECT_EQ(expect_url_, request->url());
146 EXPECT_EQ("POST", request->method());
147
148 if (expect_cookies_) {
149 EXPECT_FALSE(request->load_flags() & net::LOAD_DO_NOT_SEND_COOKIES);
150 EXPECT_FALSE(request->load_flags() & net::LOAD_DO_NOT_SAVE_COOKIES);
151 } else {
152 EXPECT_TRUE(request->load_flags() & net::LOAD_DO_NOT_SEND_COOKIES);
153 EXPECT_TRUE(request->load_flags() & net::LOAD_DO_NOT_SAVE_COOKIES);
154 }
155
156 CheckUploadData(request, &expect_reports_, expect_request_encrypted_,
157 server_private_key_);
158 return net::OK;
159 }
160
161 void OnURLRequestDestroyed(URLRequest* request) override {
162 url_request_destroyed_callback_.Run();
163 if (expect_reports_.empty())
164 all_url_requests_destroyed_callback_.Run();
165 }
166
167 const uint8* server_public_key() { return server_public_key_; }
168 const uint8* server_private_key() { return server_private_key_; }
169
170 private:
171 base::Closure url_request_destroyed_callback_;
172 base::Closure all_url_requests_destroyed_callback_;
173 int num_requests_;
174 GURL expect_url_;
175 std::set<std::string> expect_reports_;
176 bool expect_cookies_;
177 bool expect_request_encrypted_;
178
179 uint8 server_public_key_[32];
180 uint8 server_private_key_[32];
181
182 DISALLOW_COPY_AND_ASSIGN(TestCertificateErrorReporterNetworkDelegate);
183 };
184
185 class CertificateErrorReporterTest : public ::testing::Test {
186 public:
187 CertificateErrorReporterTest() : context_(true) {
188 EnableUrlRequestMocks(true);
189 context_.set_network_delegate(&network_delegate_);
190 context_.Init();
191 }
192
193 ~CertificateErrorReporterTest() override { EnableUrlRequestMocks(false); }
194
195 TestCertificateErrorReporterNetworkDelegate* network_delegate() {
196 return &network_delegate_;
197 }
198
199 TestURLRequestContext* context() { return &context_; }
200
201 private:
202 base::MessageLoop message_loop_;
203 TestCertificateErrorReporterNetworkDelegate network_delegate_;
204 TestURLRequestContext context_;
205 };
206
207 void SendReport(CertificateErrorReporter* reporter,
208 TestCertificateErrorReporterNetworkDelegate* network_delegate,
209 const std::string& report,
210 const GURL& url,
211 int request_sequence_number,
212 CertificateErrorReporter::ReportType type) {
213 base::RunLoop run_loop;
214 network_delegate->set_url_request_destroyed_callback(run_loop.QuitClosure());
215
216 network_delegate->set_expect_url(url);
217 network_delegate->ExpectReport(report);
218
219 EXPECT_EQ(request_sequence_number, network_delegate->num_requests());
220
221 reporter->SendReport(type, report);
222 run_loop.Run();
223
224 EXPECT_EQ(request_sequence_number + 1, network_delegate->num_requests());
225 }
226
227 // Test that CertificateErrorReporter::SendReport creates a URLRequest
228 // for the endpoint and sends the expected data.
229 TEST_F(CertificateErrorReporterTest, PinningViolationSendReportSendsRequest) {
230 GURL url = net::URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1);
231 CertificateErrorReporter reporter(
232 context(), url, CertificateErrorReporter::DO_NOT_SEND_COOKIES);
233 SendReport(&reporter, network_delegate(), kDummyReport, url, 0,
234 CertificateErrorReporter::REPORT_TYPE_PINNING_VIOLATION);
235 }
236
237 TEST_F(CertificateErrorReporterTest, ExtendedReportingSendReportSendsRequest) {
238 // Data should not be encrypted when sent to an HTTPS URL.
239 GURL https_url = net::URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1);
240 CertificateErrorReporter https_reporter(
241 context(), https_url, CertificateErrorReporter::DO_NOT_SEND_COOKIES);
242 network_delegate()->set_expect_request_encrypted(false);
243 SendReport(&https_reporter, network_delegate(), kDummyReport, https_url, 0,
244 CertificateErrorReporter::REPORT_TYPE_EXTENDED_REPORTING);
245
246 // Data should be encrypted when sent to an HTTP URL.
247 if (CertificateErrorReporter::IsHttpUploadUrlSupported()) {
248 GURL http_url = net::URLRequestMockDataJob::GetMockHttpUrl("dummy data", 1);
249 CertificateErrorReporter http_reporter(
250 context(), http_url, CertificateErrorReporter::DO_NOT_SEND_COOKIES,
251 network_delegate()->server_public_key(), kServerPublicKeyVersion);
252 network_delegate()->set_expect_request_encrypted(true);
253 SendReport(&http_reporter, network_delegate(), kDummyReport, http_url, 1,
254 CertificateErrorReporter::REPORT_TYPE_EXTENDED_REPORTING);
255 } 125 }
256 } 126 }
257 127
258 TEST_F(CertificateErrorReporterTest, SendMultipleReportsSequentially) {
259 GURL url = net::URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1);
260 CertificateErrorReporter reporter(
261 context(), url, CertificateErrorReporter::DO_NOT_SEND_COOKIES);
262 SendReport(&reporter, network_delegate(), kDummyReport, url, 0,
263 CertificateErrorReporter::REPORT_TYPE_PINNING_VIOLATION);
264 SendReport(&reporter, network_delegate(), kDummyReport, url, 1,
265 CertificateErrorReporter::REPORT_TYPE_PINNING_VIOLATION);
266 }
267
268 TEST_F(CertificateErrorReporterTest, SendMultipleReportsSimultaneously) {
269 base::RunLoop run_loop;
270 network_delegate()->set_all_url_requests_destroyed_callback(
271 run_loop.QuitClosure());
272
273 GURL url = net::URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1);
274 network_delegate()->set_expect_url(url);
275 network_delegate()->ExpectReport(kDummyReport);
276 network_delegate()->ExpectReport(kSecondDummyReport);
277
278 CertificateErrorReporter reporter(
279 context(), url, CertificateErrorReporter::DO_NOT_SEND_COOKIES);
280
281 EXPECT_EQ(0, network_delegate()->num_requests());
282
283 reporter.SendReport(CertificateErrorReporter::REPORT_TYPE_PINNING_VIOLATION,
284 kDummyReport);
285 reporter.SendReport(CertificateErrorReporter::REPORT_TYPE_PINNING_VIOLATION,
286 kSecondDummyReport);
287
288 run_loop.Run();
289
290 EXPECT_EQ(2, network_delegate()->num_requests());
291 }
292
293 // Test that pending URLRequests get cleaned up when the reporter is
294 // deleted.
295 TEST_F(CertificateErrorReporterTest, PendingRequestGetsDeleted) {
296 base::RunLoop run_loop;
297 network_delegate()->set_url_request_destroyed_callback(
298 run_loop.QuitClosure());
299
300 GURL url = net::URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(
301 net::URLRequestFailedJob::START, net::ERR_IO_PENDING);
302 network_delegate()->set_expect_url(url);
303 network_delegate()->ExpectReport(kDummyReport);
304
305 EXPECT_EQ(0, network_delegate()->num_requests());
306
307 scoped_ptr<CertificateErrorReporter> reporter(new CertificateErrorReporter(
308 context(), url, CertificateErrorReporter::DO_NOT_SEND_COOKIES));
309 reporter->SendReport(CertificateErrorReporter::REPORT_TYPE_PINNING_VIOLATION,
310 kDummyReport);
311 reporter.reset();
312
313 run_loop.Run();
314
315 EXPECT_EQ(1, network_delegate()->num_requests());
316 }
317
318 // Test that a request that returns an error gets cleaned up.
319 TEST_F(CertificateErrorReporterTest, ErroredRequestGetsDeleted) {
320 GURL url = net::URLRequestFailedJob::GetMockHttpsUrl(net::ERR_FAILED);
321 CertificateErrorReporter reporter(
322 context(), url, CertificateErrorReporter::DO_NOT_SEND_COOKIES);
323 SendReport(&reporter, network_delegate(), kDummyReport, url, 0,
324 CertificateErrorReporter::REPORT_TYPE_PINNING_VIOLATION);
325 }
326
327 // Test that cookies are sent or not sent according to the error
328 // reporter's cookies preference.
329
330 TEST_F(CertificateErrorReporterTest, SendCookiesPreference) {
331 GURL url = net::URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1);
332 CertificateErrorReporter reporter(context(), url,
333 CertificateErrorReporter::SEND_COOKIES);
334
335 network_delegate()->set_expect_cookies(true);
336 SendReport(&reporter, network_delegate(), kDummyReport, url, 0,
337 CertificateErrorReporter::REPORT_TYPE_PINNING_VIOLATION);
338 }
339
340 TEST_F(CertificateErrorReporterTest, DoNotSendCookiesPreference) {
341 GURL url = net::URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1);
342 CertificateErrorReporter reporter(
343 context(), url, CertificateErrorReporter::DO_NOT_SEND_COOKIES);
344
345 network_delegate()->set_expect_cookies(false);
346 SendReport(&reporter, network_delegate(), kDummyReport, url, 0,
347 CertificateErrorReporter::REPORT_TYPE_PINNING_VIOLATION);
348 }
349
350 #if defined(USE_OPENSSL) 128 #if defined(USE_OPENSSL)
351 // This test decrypts a "known gold" report. It's intentionally brittle 129 // This test decrypts a "known gold" report. It's intentionally brittle
352 // in order to catch changes in report encryption that could cause the 130 // in order to catch changes in report encryption that could cause the
353 // server to no longer be able to decrypt reports that it receives from 131 // server to no longer be able to decrypt reports that it receives from
354 // Chrome. 132 // Chrome.
355 TEST_F(CertificateErrorReporterTest, DecryptExampleReport) { 133 TEST_F(CertificateErrorReporterTest, DecryptExampleReport) {
356 // This data should not be changed without also changing the 134 // This data should not be changed without also changing the
357 // corresponding server-side test. 135 // corresponding server-side test.
358 const unsigned char kSerializedEncryptedReport[] = { 136 const unsigned char kSerializedEncryptedReport[] = {
359 0x0A, 0xFB, 0x0C, 0xD5, 0x44, 0x21, 0x36, 0x4D, 0xFC, 0x29, 0x56, 0xBD, 137 0x0A, 0xFB, 0x0C, 0xD5, 0x44, 0x21, 0x36, 0x4D, 0xFC, 0x29, 0x56, 0xBD,
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 std::string(reinterpret_cast<const char*>(kSerializedEncryptedReport), 283 std::string(reinterpret_cast<const char*>(kSerializedEncryptedReport),
506 sizeof(kSerializedEncryptedReport)))); 284 sizeof(kSerializedEncryptedReport))));
507 ASSERT_TRUE(chrome_browser_net::CertificateErrorReporter:: 285 ASSERT_TRUE(chrome_browser_net::CertificateErrorReporter::
508 DecryptCertificateErrorReport( 286 DecryptCertificateErrorReport(
509 network_delegate()->server_private_key(), 287 network_delegate()->server_private_key(),
510 encrypted_request, &decrypted_serialized_report)); 288 encrypted_request, &decrypted_serialized_report));
511 } 289 }
512 #endif 290 #endif
513 291
514 } // namespace 292 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698