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

Side by Side Diff: components/certificate_transparency/log_proof_fetcher_unittest.cc

Issue 1405293009: Certificate Transparency: Fetching consistency proofs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressing review comments. Created 5 years, 1 month 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 "components/certificate_transparency/log_proof_fetcher.h" 5 #include "components/certificate_transparency/log_proof_fetcher.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/strings/stringprintf.h" 9 #include "base/strings/stringprintf.h"
10 #include "components/safe_json/testing_json_parser.h" 10 #include "components/safe_json/testing_json_parser.h"
11 #include "net/base/net_errors.h" 11 #include "net/base/net_errors.h"
12 #include "net/base/network_delegate.h" 12 #include "net/base/network_delegate.h"
13 #include "net/cert/signed_tree_head.h" 13 #include "net/cert/signed_tree_head.h"
14 #include "net/http/http_status_code.h" 14 #include "net/http/http_status_code.h"
15 #include "net/test/ct_test_util.h" 15 #include "net/test/ct_test_util.h"
16 #include "net/url_request/url_request_context.h" 16 #include "net/url_request/url_request_context.h"
17 #include "net/url_request/url_request_filter.h" 17 #include "net/url_request/url_request_filter.h"
18 #include "net/url_request/url_request_interceptor.h" 18 #include "net/url_request/url_request_interceptor.h"
19 #include "net/url_request/url_request_job.h" 19 #include "net/url_request/url_request_job.h"
20 #include "net/url_request/url_request_test_job.h" 20 #include "net/url_request/url_request_test_job.h"
21 #include "net/url_request/url_request_test_util.h" 21 #include "net/url_request/url_request_test_util.h"
22 #include "testing/gtest/include/gtest/gtest.h" 22 #include "testing/gtest/include/gtest/gtest.h"
23 23
24 namespace certificate_transparency { 24 namespace certificate_transparency {
25 25
26 namespace { 26 namespace {
27 27
28 const char kGetSTHHeaders[] = 28 const char kGetResponseHeaders[] =
29 "HTTP/1.1 200 OK\n" 29 "HTTP/1.1 200 OK\n"
30 "Content-Type: application/json; charset=ISO-8859-1\n"; 30 "Content-Type: application/json; charset=ISO-8859-1\n";
31 31
32 const char kGetSTHNotFoundHeaders[] = 32 const char kGetResponseNotFoundHeaders[] =
33 "HTTP/1.1 404 Not Found\n" 33 "HTTP/1.1 404 Not Found\n"
34 "Content-Type: text/html; charset=iso-8859-1\n"; 34 "Content-Type: text/html; charset=iso-8859-1\n";
35 35
36 const char kLogSchema[] = "https"; 36 const char kLogSchema[] = "https";
37 const char kLogHost[] = "ct.log.example.com"; 37 const char kLogHost[] = "ct.log.example.com";
38 const char kLogPathPrefix[] = "somelog"; 38 const char kLogPathPrefix[] = "somelog";
39 const char kLogID[] = "some_id"; 39 const char kLogID[] = "some_id";
40 40
41 class FetchSTHTestJob : public net::URLRequestTestJob { 41 // Nodes returned will be 'a' * 32 for node_id 0, 'b' * 32 for node_id 1 and
42 // so forth.
svaldez 2015/11/16 17:33:07 Fix comment.
Eran Messeri 2015/11/17 10:47:31 D'oh, done.
43 std::string GetDummyConsistencyProofNode(size_t node_id) {
44 return std::string(32, static_cast<char>(node_id));
45 }
46
47 const size_t kDummyConsistencyProofLength = 4;
48
49 class LogFetchTestJob : public net::URLRequestTestJob {
42 public: 50 public:
43 FetchSTHTestJob(const std::string& get_sth_data, 51 LogFetchTestJob(const std::string& get_log_data,
44 const std::string& get_sth_headers, 52 const std::string& get_log_headers,
45 net::URLRequest* request, 53 net::URLRequest* request,
46 net::NetworkDelegate* network_delegate) 54 net::NetworkDelegate* network_delegate)
47 : URLRequestTestJob(request, 55 : URLRequestTestJob(request,
48 network_delegate, 56 network_delegate,
49 get_sth_headers, 57 get_log_headers,
50 get_sth_data, 58 get_log_data,
51 true), 59 true),
52 async_io_(false) {} 60 async_io_(false) {}
53 61
54 void set_async_io(bool async_io) { async_io_ = async_io; } 62 void set_async_io(bool async_io) { async_io_ = async_io; }
55 63
56 private: 64 private:
57 ~FetchSTHTestJob() override {} 65 ~LogFetchTestJob() override {}
58 66
59 bool NextReadAsync() override { 67 bool NextReadAsync() override {
60 // Response with indication of async IO only once, otherwise the final 68 // Response with indication of async IO only once, otherwise the final
61 // Read would (incorrectly) be classified as async, causing the 69 // Read would (incorrectly) be classified as async, causing the
62 // URLRequestJob to try reading another time and failing on a CHECK 70 // URLRequestJob to try reading another time and failing on a CHECK
63 // that the raw_read_buffer_ is not null. 71 // that the raw_read_buffer_ is not null.
64 // According to mmenke@, this is a bug in the URLRequestTestJob code. 72 // According to mmenke@, this is a bug in the URLRequestTestJob code.
65 // TODO(eranm): Once said bug is fixed, switch most tests to using async 73 // TODO(eranm): Once said bug is fixed, switch most tests to using async
66 // IO. 74 // IO.
67 if (async_io_) { 75 if (async_io_) {
68 async_io_ = false; 76 async_io_ = false;
69 return true; 77 return true;
70 } 78 }
71 return false; 79 return false;
72 } 80 }
73 81
74 bool async_io_; 82 bool async_io_;
75 83
76 DISALLOW_COPY_AND_ASSIGN(FetchSTHTestJob); 84 DISALLOW_COPY_AND_ASSIGN(LogFetchTestJob);
77 }; 85 };
78 86
79 class GetSTHResponseHandler : public net::URLRequestInterceptor { 87 class LogGetResponseHandler : public net::URLRequestInterceptor {
80 public: 88 public:
81 GetSTHResponseHandler() 89 LogGetResponseHandler()
82 : async_io_(false), 90 : async_io_(false),
83 response_body_(""), 91 response_body_(""),
84 response_headers_( 92 response_headers_(
svaldez 2015/11/16 17:33:08 Consider setting default expected_*_tree_size_ and
Eran Messeri 2015/11/17 10:47:31 Done.
85 std::string(kGetSTHHeaders, arraysize(kGetSTHHeaders))) {} 93 std::string(kGetResponseHeaders, arraysize(kGetResponseHeaders))) {}
86 ~GetSTHResponseHandler() override {} 94 ~LogGetResponseHandler() override {}
87 95
88 // URLRequestInterceptor implementation: 96 // URLRequestInterceptor implementation:
89 net::URLRequestJob* MaybeInterceptRequest( 97 net::URLRequestJob* MaybeInterceptRequest(
90 net::URLRequest* request, 98 net::URLRequest* request,
91 net::NetworkDelegate* network_delegate) const override { 99 net::NetworkDelegate* network_delegate) const override {
92 std::string expected_url = base::StringPrintf( 100 std::string base_expected_url = base::StringPrintf(
93 "%s://%s/%s/ct/v1/get-sth", kLogSchema, kLogHost, kLogPathPrefix); 101 "%s://%s/%s/ct/v1/", kLogSchema, kLogHost, kLogPathPrefix);
102
103 std::string expected_url;
104 if (expected_old_tree_size_ == 0 && expected_new_tree_size_ == 0) {
105 // Expecting get-sth
106 expected_url = base_expected_url + std::string("get-sth");
107 } else {
108 // Expecting get-consistency-proof
109 expected_url =
110 base_expected_url +
111 base::StringPrintf("get-sth-consistency?first=%lu&second=%lu",
112 expected_old_tree_size_, expected_new_tree_size_);
113 }
94 EXPECT_EQ(GURL(expected_url), request->url()); 114 EXPECT_EQ(GURL(expected_url), request->url());
95 FetchSTHTestJob* job = new FetchSTHTestJob( 115 LogFetchTestJob* job = new LogFetchTestJob(
96 response_body_, response_headers_, request, network_delegate); 116 response_body_, response_headers_, request, network_delegate);
97 job->set_async_io(async_io_); 117 job->set_async_io(async_io_);
98 return job; 118 return job;
99 } 119 }
100 120
101 void set_response_body(const std::string& response_body) { 121 void set_response_body(const std::string& response_body) {
102 response_body_ = response_body; 122 response_body_ = response_body;
103 } 123 }
104 124
105 void set_response_headers(const std::string& response_headers) { 125 void set_response_headers(const std::string& response_headers) {
106 response_headers_ = response_headers; 126 response_headers_ = response_headers;
107 } 127 }
108 128
129 void set_expect_get_consistency_proof(size_t expected_old_tree_size,
130 size_t expected_new_tree_size) {
131 expected_old_tree_size_ = expected_old_tree_size;
132 expected_new_tree_size_ = expected_new_tree_size;
133 }
134
109 void set_async_io(bool async_io) { async_io_ = async_io; } 135 void set_async_io(bool async_io) { async_io_ = async_io; }
110 136
111 private: 137 private:
112 bool async_io_; 138 bool async_io_;
113 std::string response_body_; 139 std::string response_body_;
114 std::string response_headers_; 140 std::string response_headers_;
115 141
116 DISALLOW_COPY_AND_ASSIGN(GetSTHResponseHandler); 142 size_t expected_old_tree_size_;
143 size_t expected_new_tree_size_;
144
145 DISALLOW_COPY_AND_ASSIGN(LogGetResponseHandler);
117 }; 146 };
118 147
119 class RecordFetchCallbackInvocations { 148 class RecordFetchCallbackInvocations {
120 public: 149 public:
121 RecordFetchCallbackInvocations(bool expect_success) 150 RecordFetchCallbackInvocations(bool expect_success)
122 : expect_success_(expect_success), 151 : expect_success_(expect_success),
123 invoked_(false), 152 invoked_(false),
124 net_error_(net::OK), 153 net_error_(net::OK),
125 http_response_code_(-1) {} 154 http_response_code_(-1) {}
126 155
(...skipping 12 matching lines...) Expand all
139 EXPECT_EQ(expected_sth.tree_size, sth.tree_size); 168 EXPECT_EQ(expected_sth.tree_size, sth.tree_size);
140 EXPECT_STREQ(expected_sth.sha256_root_hash, sth.sha256_root_hash); 169 EXPECT_STREQ(expected_sth.sha256_root_hash, sth.sha256_root_hash);
141 EXPECT_EQ(expected_sth.signature.hash_algorithm, 170 EXPECT_EQ(expected_sth.signature.hash_algorithm,
142 sth.signature.hash_algorithm); 171 sth.signature.hash_algorithm);
143 EXPECT_EQ(expected_sth.signature.signature_algorithm, 172 EXPECT_EQ(expected_sth.signature.signature_algorithm,
144 sth.signature.signature_algorithm); 173 sth.signature.signature_algorithm);
145 EXPECT_EQ(expected_sth.signature.signature_data, 174 EXPECT_EQ(expected_sth.signature.signature_data,
146 sth.signature.signature_data); 175 sth.signature.signature_data);
147 } 176 }
148 177
178 void ConsistencyProofFetched(
179 const std::string& log_id,
180 const std::vector<std::string>& consistency_proof) {
181 ASSERT_TRUE(expect_success_);
182 ASSERT_FALSE(invoked_);
183 invoked_ = true;
184 EXPECT_EQ(kDummyConsistencyProofLength, consistency_proof.size());
185 for (size_t i = 0; i < kDummyConsistencyProofLength; ++i) {
186 EXPECT_EQ(GetDummyConsistencyProofNode(i), consistency_proof[i])
187 << " node: " << i;
188 }
189 }
190
149 void FetchingFailed(const std::string& log_id, 191 void FetchingFailed(const std::string& log_id,
150 int net_error, 192 int net_error,
151 int http_response_code) { 193 int http_response_code) {
152 ASSERT_FALSE(expect_success_); 194 ASSERT_FALSE(expect_success_);
153 ASSERT_FALSE(invoked_); 195 ASSERT_FALSE(invoked_);
154 invoked_ = true; 196 invoked_ = true;
155 net_error_ = net_error; 197 net_error_ = net_error;
156 http_response_code_ = http_response_code; 198 http_response_code_ = http_response_code;
157 if (net_error_ == net::OK) { 199 if (net_error_ == net::OK) {
158 EXPECT_NE(net::HTTP_OK, http_response_code_); 200 EXPECT_NE(net::HTTP_OK, http_response_code_);
(...skipping 13 matching lines...) Expand all
172 int http_response_code_; 214 int http_response_code_;
173 }; 215 };
174 216
175 class LogProofFetcherTest : public ::testing::Test { 217 class LogProofFetcherTest : public ::testing::Test {
176 public: 218 public:
177 LogProofFetcherTest() 219 LogProofFetcherTest()
178 : log_url_(base::StringPrintf("%s://%s/%s/", 220 : log_url_(base::StringPrintf("%s://%s/%s/",
179 kLogSchema, 221 kLogSchema,
180 kLogHost, 222 kLogHost,
181 kLogPathPrefix)) { 223 kLogPathPrefix)) {
182 scoped_ptr<GetSTHResponseHandler> handler(new GetSTHResponseHandler()); 224 scoped_ptr<LogGetResponseHandler> handler(new LogGetResponseHandler());
183 handler_ = handler.get(); 225 handler_ = handler.get();
184 226
185 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( 227 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
186 kLogSchema, kLogHost, handler.Pass()); 228 kLogSchema, kLogHost, handler.Pass());
187 229
188 fetcher_.reset(new LogProofFetcher(&context_)); 230 fetcher_.reset(new LogProofFetcher(&context_));
189 } 231 }
190 232
191 ~LogProofFetcherTest() override { 233 ~LogProofFetcherTest() override {
192 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(kLogSchema, 234 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(kLogSchema,
193 kLogHost); 235 kLogHost);
194 } 236 }
195 237
196 protected: 238 protected:
197 void SetValidSTHJSONResponse() { 239 void SetValidSTHJSONResponse() {
198 std::string sth_json_reply_data = net::ct::GetSampleSTHAsJson(); 240 std::string sth_json_reply_data = net::ct::GetSampleSTHAsJson();
199 handler_->set_response_body(sth_json_reply_data); 241 handler_->set_response_body(sth_json_reply_data);
200 } 242 }
201 243
202 void RunFetcherWithCallback(RecordFetchCallbackInvocations* callback) { 244 void RunFetcherWithCallback(RecordFetchCallbackInvocations* callback) {
245 handler_->set_expect_get_consistency_proof(0, 0);
203 fetcher_->FetchSignedTreeHead( 246 fetcher_->FetchSignedTreeHead(
204 log_url_, kLogID, 247 log_url_, kLogID,
205 base::Bind(&RecordFetchCallbackInvocations::STHFetched, 248 base::Bind(&RecordFetchCallbackInvocations::STHFetched,
206 base::Unretained(callback)), 249 base::Unretained(callback)),
207 base::Bind(&RecordFetchCallbackInvocations::FetchingFailed, 250 base::Bind(&RecordFetchCallbackInvocations::FetchingFailed,
208 base::Unretained(callback))); 251 base::Unretained(callback)));
209 message_loop_.RunUntilIdle(); 252 message_loop_.RunUntilIdle();
210 } 253 }
211 254
255 void RunGetConsistencyFetcherWithCallback(
256 RecordFetchCallbackInvocations* callback) {
257 const size_t kOldTree = 5;
258 const size_t kNewTree = 8;
259 handler_->set_expect_get_consistency_proof(kOldTree, kNewTree);
260 fetcher_->FetchConsistencyProof(
261 log_url_, kLogID, kOldTree, kNewTree,
262 base::Bind(&RecordFetchCallbackInvocations::ConsistencyProofFetched,
263 base::Unretained(callback)),
264 base::Bind(&RecordFetchCallbackInvocations::FetchingFailed,
265 base::Unretained(callback)));
266 message_loop_.RunUntilIdle();
267 }
268
212 base::MessageLoopForIO message_loop_; 269 base::MessageLoopForIO message_loop_;
213 net::TestURLRequestContext context_; 270 net::TestURLRequestContext context_;
214 safe_json::TestingJsonParser::ScopedFactoryOverride factory_override_; 271 safe_json::TestingJsonParser::ScopedFactoryOverride factory_override_;
215 scoped_ptr<LogProofFetcher> fetcher_; 272 scoped_ptr<LogProofFetcher> fetcher_;
216 const GURL log_url_; 273 const GURL log_url_;
217 GetSTHResponseHandler* handler_; 274 LogGetResponseHandler* handler_;
218 }; 275 };
219 276
220 TEST_F(LogProofFetcherTest, TestValidGetReply) { 277 TEST_F(LogProofFetcherTest, TestValidGetReply) {
221 SetValidSTHJSONResponse(); 278 SetValidSTHJSONResponse();
222 279
223 RecordFetchCallbackInvocations callback(true); 280 RecordFetchCallbackInvocations callback(true);
224 281
225 RunFetcherWithCallback(&callback); 282 RunFetcherWithCallback(&callback);
226 283
227 ASSERT_TRUE(callback.invoked()); 284 ASSERT_TRUE(callback.invoked());
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 ' ')); 341 ' '));
285 handler_->set_response_body(sth_json_reply_data); 342 handler_->set_response_body(sth_json_reply_data);
286 343
287 RecordFetchCallbackInvocations callback(true); 344 RecordFetchCallbackInvocations callback(true);
288 RunFetcherWithCallback(&callback); 345 RunFetcherWithCallback(&callback);
289 346
290 ASSERT_TRUE(callback.invoked()); 347 ASSERT_TRUE(callback.invoked());
291 } 348 }
292 349
293 TEST_F(LogProofFetcherTest, TestLogRepliesWithHttpError) { 350 TEST_F(LogProofFetcherTest, TestLogRepliesWithHttpError) {
294 handler_->set_response_headers( 351 handler_->set_response_headers(std::string(
295 std::string(kGetSTHNotFoundHeaders, arraysize(kGetSTHNotFoundHeaders))); 352 kGetResponseNotFoundHeaders, arraysize(kGetResponseNotFoundHeaders)));
296 353
297 RecordFetchCallbackInvocations callback(false); 354 RecordFetchCallbackInvocations callback(false);
298 RunFetcherWithCallback(&callback); 355 RunFetcherWithCallback(&callback);
299 356
300 ASSERT_TRUE(callback.invoked()); 357 ASSERT_TRUE(callback.invoked());
301 EXPECT_EQ(net::OK, callback.net_error()); 358 EXPECT_EQ(net::OK, callback.net_error());
302 EXPECT_EQ(net::HTTP_NOT_FOUND, callback.http_response_code()); 359 EXPECT_EQ(net::HTTP_NOT_FOUND, callback.http_response_code());
303 } 360 }
304 361
362 TEST_F(LogProofFetcherTest, TestValidGetConsistencyValidReply) {
363 std::vector<std::string> proof;
364 for (size_t i = 0; i < kDummyConsistencyProofLength; ++i)
365 proof.push_back(GetDummyConsistencyProofNode(i));
366
367 std::string consistency_proof_reply_data =
368 net::ct::CreateConsistencyProofJsonString(proof);
369 handler_->set_response_body(consistency_proof_reply_data);
370
371 RecordFetchCallbackInvocations callback(true);
372 RunGetConsistencyFetcherWithCallback(&callback);
373
374 ASSERT_TRUE(callback.invoked());
375 }
376
377 TEST_F(LogProofFetcherTest, TestInvalidGetConsistencyReplyInvalidJSON) {
378 std::string consistency_proof_reply_data = "{\"consistency\": [1,2]}";
379 handler_->set_response_body(consistency_proof_reply_data);
380
381 RecordFetchCallbackInvocations callback(false);
382 RunGetConsistencyFetcherWithCallback(&callback);
383
384 ASSERT_TRUE(callback.invoked());
385 EXPECT_EQ(net::ERR_CT_CONSISTENCY_PROOF_PARSING_FAILED, callback.net_error());
386 EXPECT_EQ(net::HTTP_OK, callback.http_response_code());
387 }
388
305 } // namespace 389 } // namespace
306 390
307 } // namespace certificate_transparency 391 } // namespace certificate_transparency
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698