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

Side by Side Diff: components/network_time/network_time_tracker.cc

Issue 1835823002: network_time_tracker: add temporary time protocol. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add test of signed bad data Created 4 years, 7 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/network_time/network_time_tracker.h" 5 #include "components/network_time/network_time_tracker.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/i18n/time_formatting.h" 10 #include "base/i18n/time_formatting.h"
11 #include "base/json/json_reader.h"
11 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
12 #include "base/strings/utf_string_conversions.h" 14 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/tick_clock.h" 15 #include "base/time/tick_clock.h"
14 #include "build/build_config.h" 16 #include "build/build_config.h"
17 #include "components/client_update_protocol/ecdsa.h"
15 #include "components/network_time/network_time_pref_names.h" 18 #include "components/network_time/network_time_pref_names.h"
16 #include "components/prefs/pref_registry_simple.h" 19 #include "components/prefs/pref_registry_simple.h"
17 #include "components/prefs/pref_service.h" 20 #include "components/prefs/pref_service.h"
21 #include "net/base/load_flags.h"
22 #include "net/base/net_errors.h"
23 #include "net/http/http_response_headers.h"
24 #include "net/url_request/url_fetcher.h"
25 #include "net/url_request/url_fetcher_response_writer.h"
26 #include "net/url_request/url_request_context_getter.h"
18 27
19 namespace network_time { 28 namespace network_time {
20 29
21 namespace { 30 namespace {
22 31
32 // Minimum number of minutes between time queries.
33 const uint32_t kMinimumQueryDelayMinutes = 60;
34
23 // Number of time measurements performed in a given network time calculation. 35 // Number of time measurements performed in a given network time calculation.
24 const uint32_t kNumTimeMeasurements = 7; 36 const uint32_t kNumTimeMeasurements = 7;
25 37
26 // Amount of divergence allowed between wall clock and tick clock. 38 // Amount of divergence allowed between wall clock and tick clock.
27 const uint32_t kClockDivergenceSeconds = 60; 39 const uint32_t kClockDivergenceSeconds = 60;
28 40
29 // Maximum time lapse before deserialized data are considered stale. 41 // Maximum time lapse before deserialized data are considered stale.
30 const uint32_t kSerializedDataMaxAgeDays = 7; 42 const uint32_t kSerializedDataMaxAgeDays = 7;
31 43
32 // Name of a pref that stores the wall clock time, via |ToJsTime|. 44 // Name of a pref that stores the wall clock time, via |ToJsTime|.
33 const char kPrefTime[] = "local"; 45 const char kPrefTime[] = "local";
34 46
35 // Name of a pref that stores the tick clock time, via |ToInternalValue|. 47 // Name of a pref that stores the tick clock time, via |ToInternalValue|.
36 const char kPrefTicks[] = "ticks"; 48 const char kPrefTicks[] = "ticks";
37 49
38 // Name of a pref that stores the time uncertainty, via |ToInternalValue|. 50 // Name of a pref that stores the time uncertainty, via |ToInternalValue|.
39 const char kPrefUncertainty[] = "uncertainty"; 51 const char kPrefUncertainty[] = "uncertainty";
40 52
41 // Name of a pref that stores the network time via |ToJsTime|. 53 // Name of a pref that stores the network time via |ToJsTime|.
42 const char kPrefNetworkTime[] = "network"; 54 const char kPrefNetworkTime[] = "network";
43 55
56 // Time server's maximum allowable clock skew, in seconds. (This is a property
57 // of the time server that we happen to know. It's unlikely that it would ever
58 // be that badly wrong, but all the same it's included here to document the very
59 // rough nature of the time service provided by this class.)
60 const uint32_t kTimeServerMaxSkewSeconds = 10;
61
62 const char kTimeServiceURL[] = "http://clients2.google.com/time/1/current";
63
64 // This is an ECDSA prime256v1 named-curve key.
65 const int kKeyVersion = 1;
66 const uint8_t kKeyPubBytes[] = {
67 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
68 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
69 0x42, 0x00, 0x04, 0xeb, 0xd8, 0xad, 0x0b, 0x8f, 0x75, 0xe8, 0x84, 0x36,
70 0x23, 0x48, 0x14, 0x24, 0xd3, 0x93, 0x42, 0x25, 0x43, 0xc1, 0xde, 0x36,
71 0x29, 0xc6, 0x95, 0xca, 0xeb, 0x28, 0x85, 0xff, 0x09, 0xdc, 0x08, 0xec,
72 0x45, 0x74, 0x6e, 0x4b, 0xc3, 0xa5, 0xfd, 0x8a, 0x2f, 0x02, 0xa0, 0x4b,
73 0xc3, 0xc6, 0xa4, 0x7b, 0xa4, 0x41, 0xfc, 0xa7, 0x02, 0x54, 0xab, 0xe3,
74 0xe4, 0xb1, 0x00, 0xf5, 0xd5, 0x09, 0x11};
75
76 std::string GetServerProof(const net::URLFetcher* source) {
77 const net::HttpResponseHeaders* response_headers =
78 source->GetResponseHeaders();
79 if (!response_headers) {
80 return std::string();
81 }
82 std::string proof;
83 return response_headers->EnumerateHeader(nullptr, "x-cup-server-proof",
84 &proof)
85 ? proof
86 : std::string();
87 }
88
89 // Limits the amount of data that will be buffered from the server's response.
90 class SizeLimitingStringWriter : public net::URLFetcherStringWriter {
91 public:
92 SizeLimitingStringWriter(size_t limit) : limit_(limit) {}
93
94 int Write(net::IOBuffer* buffer,
95 int num_bytes,
96 const net::CompletionCallback& callback) override {
97 if (data().length() + num_bytes > limit_) {
98 return net::ERR_FILE_TOO_BIG;
99 }
100 return net::URLFetcherStringWriter::Write(buffer, num_bytes, callback);
101 }
102
103 private:
104 size_t limit_;
105 };
106
44 } // namespace 107 } // namespace
45 108
46 // static 109 // static
47 void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) { 110 void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) {
48 registry->RegisterDictionaryPref(prefs::kNetworkTimeMapping, 111 registry->RegisterDictionaryPref(prefs::kNetworkTimeMapping,
49 new base::DictionaryValue()); 112 new base::DictionaryValue());
50 } 113 }
51 114
52 NetworkTimeTracker::NetworkTimeTracker( 115 NetworkTimeTracker::NetworkTimeTracker(
53 std::unique_ptr<base::Clock> clock, 116 std::unique_ptr<base::Clock> clock,
54 std::unique_ptr<base::TickClock> tick_clock, 117 std::unique_ptr<base::TickClock> tick_clock,
55 PrefService* pref_service) 118 PrefService* pref_service,
56 : clock_(std::move(clock)), 119 scoped_refptr<net::URLRequestContextGetter> getter)
120 : server_url_(kTimeServiceURL),
121 max_response_size_(1024),
122 getter_(std::move(getter)),
123 clock_(std::move(clock)),
57 tick_clock_(std::move(tick_clock)), 124 tick_clock_(std::move(tick_clock)),
58 pref_service_(pref_service) { 125 pref_service_(pref_service) {
59 const base::DictionaryValue* time_mapping = 126 const base::DictionaryValue* time_mapping =
60 pref_service_->GetDictionary(prefs::kNetworkTimeMapping); 127 pref_service_->GetDictionary(prefs::kNetworkTimeMapping);
61 double time_js = 0; 128 double time_js = 0;
62 double ticks_js = 0; 129 double ticks_js = 0;
63 double network_time_js = 0; 130 double network_time_js = 0;
64 double uncertainty_js = 0; 131 double uncertainty_js = 0;
65 if (time_mapping->GetDouble(kPrefTime, &time_js) && 132 if (time_mapping->GetDouble(kPrefTime, &time_js) &&
66 time_mapping->GetDouble(kPrefTicks, &ticks_js) && 133 time_mapping->GetDouble(kPrefTicks, &ticks_js) &&
67 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) && 134 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) &&
68 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) { 135 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) {
69 time_at_last_measurement_ = base::Time::FromJsTime(time_js); 136 time_at_last_measurement_ = base::Time::FromJsTime(time_js);
70 ticks_at_last_measurement_ = base::TimeTicks::FromInternalValue( 137 ticks_at_last_measurement_ = base::TimeTicks::FromInternalValue(
71 static_cast<int64_t>(ticks_js)); 138 static_cast<int64_t>(ticks_js));
72 network_time_uncertainty_ = base::TimeDelta::FromInternalValue( 139 network_time_uncertainty_ = base::TimeDelta::FromInternalValue(
73 static_cast<int64_t>(uncertainty_js)); 140 static_cast<int64_t>(uncertainty_js));
74 network_time_at_last_measurement_ = base::Time::FromJsTime(network_time_js); 141 network_time_at_last_measurement_ = base::Time::FromJsTime(network_time_js);
75 } 142 }
76 base::Time now = clock_->Now(); 143 base::Time now = clock_->Now();
77 if (ticks_at_last_measurement_ > tick_clock_->NowTicks() || 144 if (ticks_at_last_measurement_ > tick_clock_->NowTicks() ||
78 time_at_last_measurement_ > now || 145 time_at_last_measurement_ > now ||
79 now - time_at_last_measurement_ > 146 now - time_at_last_measurement_ >
80 base::TimeDelta::FromDays(kSerializedDataMaxAgeDays)) { 147 base::TimeDelta::FromDays(kSerializedDataMaxAgeDays)) {
81 // Drop saved mapping if either clock has run backward, or the data are too 148 // Drop saved mapping if either clock has run backward, or the data are too
82 // old. 149 // old.
83 pref_service_->ClearPref(prefs::kNetworkTimeMapping); 150 pref_service_->ClearPref(prefs::kNetworkTimeMapping);
84 network_time_at_last_measurement_ = base::Time(); // Reset. 151 network_time_at_last_measurement_ = base::Time(); // Reset.
85 } 152 }
153
154 base::StringPiece public_key = {reinterpret_cast<const char*>(kKeyPubBytes),
155 sizeof(kKeyPubBytes)};
156 query_signer_ =
157 client_update_protocol::Ecdsa::Create(kKeyVersion, public_key);
158
159 QueueTimeQuery(base::TimeDelta::FromMinutes(kMinimumQueryDelayMinutes));
86 } 160 }
87 161
88 NetworkTimeTracker::~NetworkTimeTracker() { 162 NetworkTimeTracker::~NetworkTimeTracker() {
89 DCHECK(thread_checker_.CalledOnValidThread()); 163 DCHECK(thread_checker_.CalledOnValidThread());
90 } 164 }
91 165
92 void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time, 166 void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time,
93 base::TimeDelta resolution, 167 base::TimeDelta resolution,
94 base::TimeDelta latency, 168 base::TimeDelta latency,
95 base::TimeTicks post_time) { 169 base::TimeTicks post_time) {
(...skipping 29 matching lines...) Expand all
125 199
126 base::DictionaryValue time_mapping; 200 base::DictionaryValue time_mapping;
127 time_mapping.SetDouble(kPrefTime, time_at_last_measurement_.ToJsTime()); 201 time_mapping.SetDouble(kPrefTime, time_at_last_measurement_.ToJsTime());
128 time_mapping.SetDouble(kPrefTicks, static_cast<double>( 202 time_mapping.SetDouble(kPrefTicks, static_cast<double>(
129 ticks_at_last_measurement_.ToInternalValue())); 203 ticks_at_last_measurement_.ToInternalValue()));
130 time_mapping.SetDouble(kPrefUncertainty, static_cast<double>( 204 time_mapping.SetDouble(kPrefUncertainty, static_cast<double>(
131 network_time_uncertainty_.ToInternalValue())); 205 network_time_uncertainty_.ToInternalValue()));
132 time_mapping.SetDouble(kPrefNetworkTime, 206 time_mapping.SetDouble(kPrefNetworkTime,
133 network_time_at_last_measurement_.ToJsTime()); 207 network_time_at_last_measurement_.ToJsTime());
134 pref_service_->Set(prefs::kNetworkTimeMapping, time_mapping); 208 pref_service_->Set(prefs::kNetworkTimeMapping, time_mapping);
209
210 // Calls to update the network time can (as of this writing) come from various
211 // sources, e.g. organically from Omaha update checks. In that even, we may
212 // as well delay the next time server query. If |UpdateNetworkTime| is ever
213 // made into a private method, this can be removed.
214 query_timer_.Reset();
215 }
216
217 void NetworkTimeTracker::SetTimeServerURLForTesting(const GURL& url) {
218 server_url_ = url;
219 }
220
221 void NetworkTimeTracker::SetMaxResponseSizeForTesting(size_t limit) {
222 max_response_size_ = limit;
223 }
224
225 void NetworkTimeTracker::SetPublicKeyForTesting(base::StringPiece key) {
226 query_signer_ = client_update_protocol::Ecdsa::Create(kKeyVersion, key);
227 }
228
229 bool NetworkTimeTracker::QueryTimeServiceForTesting() {
230 QueryTimeService();
231 return time_fetcher_ != nullptr;
232 }
233
234 void NetworkTimeTracker::WaitForFetchForTesting(uint32_t nonce) {
235 query_signer_->OverrideNonceForTesting(kKeyVersion, nonce);
236 while (time_fetcher_) {
237 base::MessageLoop::current()->RunUntilIdle();
238 }
239 }
240
241 base::TimeDelta NetworkTimeTracker::GetTimerDelayForTesting() const {
242 DCHECK(query_timer_.IsRunning());
243 return query_timer_.GetCurrentDelay();
135 } 244 }
136 245
137 bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time, 246 bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time,
138 base::TimeDelta* uncertainty) const { 247 base::TimeDelta* uncertainty) const {
139 DCHECK(thread_checker_.CalledOnValidThread()); 248 DCHECK(thread_checker_.CalledOnValidThread());
140 DCHECK(network_time); 249 DCHECK(network_time);
141 if (network_time_at_last_measurement_.is_null()) { 250 if (network_time_at_last_measurement_.is_null()) {
142 return false; 251 return false;
143 } 252 }
144 DCHECK(!ticks_at_last_measurement_.is_null()); 253 DCHECK(!ticks_at_last_measurement_.is_null());
(...skipping 15 matching lines...) Expand all
160 network_time_at_last_measurement_ = base::Time(); 269 network_time_at_last_measurement_ = base::Time();
161 return false; 270 return false;
162 } 271 }
163 *network_time = network_time_at_last_measurement_ + tick_delta; 272 *network_time = network_time_at_last_measurement_ + tick_delta;
164 if (uncertainty) { 273 if (uncertainty) {
165 *uncertainty = network_time_uncertainty_ + divergence; 274 *uncertainty = network_time_uncertainty_ + divergence;
166 } 275 }
167 return true; 276 return true;
168 } 277 }
169 278
279 void NetworkTimeTracker::QueryTimeService() {
280 DCHECK(thread_checker_.CalledOnValidThread());
281
282 // If GetNetworkTime() returns true, the NetworkTimeTracker thinks it is in
283 // sync, so there is no need to query.
284 base::Time network_time;
285 if (GetNetworkTime(&network_time, nullptr)) {
286 return;
287 }
288
289 std::string query_string;
290 query_signer_->SignRequest(nullptr, &query_string);
291 GURL url = server_url_;
292 GURL::Replacements replacements;
293 replacements.SetQueryStr(query_string);
294 url = url.ReplaceComponents(replacements);
295
296 // This cancels any outstanding fetch.
297 time_fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
298 if (!time_fetcher_) {
299 DVLOG(1) << "tried to make fetch happen; failed";
300 return;
301 }
302 time_fetcher_->SaveResponseWithWriter(
303 std::unique_ptr<net::URLFetcherResponseWriter>(
304 new SizeLimitingStringWriter(max_response_size_)));
305 DCHECK(getter_);
306 time_fetcher_->SetRequestContext(getter_.get());
307 // Not expecting any cookies, but just in case.
308 time_fetcher_->SetLoadFlags(net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
309 net::LOAD_DO_NOT_SAVE_COOKIES |
310 net::LOAD_DO_NOT_SEND_COOKIES |
311 net::LOAD_DO_NOT_SEND_AUTH_DATA);
312 time_fetcher_->Start();
313 fetch_started_ = tick_clock_->NowTicks();
314 }
315
316 bool NetworkTimeTracker::UpdateTimeFromResponse() {
317 if (time_fetcher_->GetStatus().status() != net::URLRequestStatus::SUCCESS &&
318 time_fetcher_->GetResponseCode() != 200) {
319 DVLOG(1) << "fetch failed, status=" << time_fetcher_->GetStatus().status()
320 << ",code=" << time_fetcher_->GetResponseCode();
321 return false;
322 }
323
324 std::string response_body;
325 if (!time_fetcher_->GetResponseAsString(&response_body)) {
326 DVLOG(1) << "failed to get response";
327 return false;
328 }
329 DCHECK(query_signer_);
330 if (!query_signer_->ValidateResponse(response_body,
331 GetServerProof(time_fetcher_.get()))) {
332 DVLOG(1) << "invalid signature";
333 return false;
334 }
335 response_body = response_body.substr(5); // Skips leading )]}'\n
336 std::unique_ptr<base::Value> value = base::JSONReader::Read(response_body);
337 if (!value) {
338 DVLOG(1) << "bad JSON";
339 return false;
340 }
341 const base::DictionaryValue* dict;
342 if (!value->GetAsDictionary(&dict)) {
343 DVLOG(1) << "not a dictionary";
344 return false;
345 }
346 double current_time_millis;
347 if (!dict->GetDouble("current_time_millis", &current_time_millis)) {
348 DVLOG(1) << "no current_time_millis";
349 return false;
350 }
351 // There is a "server_nonce" key here too, but it serves no purpose other than
352 // to make the server's response unpredictable.
353 base::Time current_time = base::Time::FromJsTime(current_time_millis);
354 base::TimeDelta resolution =
355 base::TimeDelta::FromMilliseconds(1) +
356 base::TimeDelta::FromSeconds(kTimeServerMaxSkewSeconds);
357 base::TimeDelta latency = tick_clock_->NowTicks() - fetch_started_;
358 UpdateNetworkTime(current_time, resolution, latency, tick_clock_->NowTicks());
359 return true;
360 }
361
362 void NetworkTimeTracker::OnURLFetchComplete(const net::URLFetcher* source) {
363 DCHECK(thread_checker_.CalledOnValidThread());
364 DCHECK(time_fetcher_);
365 DCHECK_EQ(source, time_fetcher_.get());
366
367 if (!UpdateTimeFromResponse()) { // On error, back off.
368 DCHECK(query_timer_.IsRunning());
369 base::TimeDelta delay = query_timer_.GetCurrentDelay();
370 if (delay < base::TimeDelta::FromDays(2)) {
371 delay *= 2;
372 }
373 QueueTimeQuery(delay);
374 }
375 time_fetcher_.reset();
376 }
377
378 void NetworkTimeTracker::QueueTimeQuery(base::TimeDelta delay) {
379 query_timer_.Start(FROM_HERE, delay, this,
380 &NetworkTimeTracker::QueryTimeService);
381 }
382
170 } // namespace network_time 383 } // namespace network_time
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698