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

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

Powered by Google App Engine
This is Rietveld 408576698