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