OLD | NEW |
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 Loading... |
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 Loading... |
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", ¤t_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 |
OLD | NEW |