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

Side by Side Diff: components/variations/variations_seed_store.cc

Issue 2935623004: [Cleanup] Clean up the VariationsSeedStore's histograms. (Closed)
Patch Set: Fix tests on iOS and Android Created 3 years, 6 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/variations/variations_seed_store.h" 5 #include "components/variations/variations_seed_store.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/macros.h" 10 #include "base/macros.h"
(...skipping 11 matching lines...) Expand all
22 #include "third_party/zlib/google/compression_utils.h" 22 #include "third_party/zlib/google/compression_utils.h"
23 23
24 #if defined(OS_ANDROID) 24 #if defined(OS_ANDROID)
25 #include "components/variations/android/variations_seed_bridge.h" 25 #include "components/variations/android/variations_seed_bridge.h"
26 #endif // OS_ANDROID 26 #endif // OS_ANDROID
27 27
28 namespace variations { 28 namespace variations {
29 29
30 namespace { 30 namespace {
31 31
32 // Signature verification is disabled on mobile platforms for now, since it
33 // adds about ~15ms to the startup time on mobile (vs. a couple ms on desktop).
34 bool SignatureVerificationEnabled() {
35 #if defined(OS_IOS) || defined(OS_ANDROID)
36 return false;
37 #else
38 return true;
39 #endif
40 }
41
42 // The ECDSA public key of the variations server for verifying variations seed 32 // The ECDSA public key of the variations server for verifying variations seed
43 // signatures. 33 // signatures.
44 const uint8_t kPublicKey[] = { 34 const uint8_t kPublicKey[] = {
45 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 35 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
46 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 36 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
47 0x04, 0x51, 0x7c, 0x31, 0x4b, 0x50, 0x42, 0xdd, 0x59, 0xda, 0x0b, 0xfa, 0x43, 37 0x04, 0x51, 0x7c, 0x31, 0x4b, 0x50, 0x42, 0xdd, 0x59, 0xda, 0x0b, 0xfa, 0x43,
48 0x44, 0x33, 0x7c, 0x5f, 0xa1, 0x0b, 0xd5, 0x82, 0xf6, 0xac, 0x04, 0x19, 0x72, 38 0x44, 0x33, 0x7c, 0x5f, 0xa1, 0x0b, 0xd5, 0x82, 0xf6, 0xac, 0x04, 0x19, 0x72,
49 0x6c, 0x40, 0xd4, 0x3e, 0x56, 0xe2, 0xa0, 0x80, 0xa0, 0x41, 0xb3, 0x23, 0x7b, 39 0x6c, 0x40, 0xd4, 0x3e, 0x56, 0xe2, 0xa0, 0x80, 0xa0, 0x41, 0xb3, 0x23, 0x7b,
50 0x71, 0xc9, 0x80, 0x87, 0xde, 0x35, 0x0d, 0x25, 0x71, 0x09, 0x7f, 0xb4, 0x15, 40 0x71, 0xc9, 0x80, 0x87, 0xde, 0x35, 0x0d, 0x25, 0x71, 0x09, 0x7f, 0xb4, 0x15,
51 0x2b, 0xff, 0x82, 0x4d, 0xd3, 0xfe, 0xc5, 0xef, 0x20, 0xc6, 0xa3, 0x10, 0xbf, 41 0x2b, 0xff, 0x82, 0x4d, 0xd3, 0xfe, 0xc5, 0xef, 0x20, 0xc6, 0xa3, 0x10, 0xbf,
52 }; 42 };
53 43
54 // Note: UMA histogram enum - don't re-order or remove entries. 44 // Verifies a variations seed (the serialized proto bytes) with the specified
55 enum VariationSeedEmptyState { 45 // base-64 encoded signature that was received from the server and returns the
56 VARIATIONS_SEED_NOT_EMPTY, 46 // result. The signature is assumed to be an "ECDSA with SHA-256" signature
57 VARIATIONS_SEED_EMPTY, 47 // (see kECDSAWithSHA256AlgorithmID in the .cc file). Returns the result of
58 VARIATIONS_SEED_CORRUPT, 48 // signature verification.
59 VARIATIONS_SEED_INVALID_SIGNATURE, 49 VerifySignatureResult VerifySeedSignature(
60 VARIATIONS_SEED_CORRUPT_BASE64, 50 const std::string& seed_bytes,
61 VARIATIONS_SEED_CORRUPT_PROTOBUF, 51 const std::string& base64_seed_signature) {
62 VARIATIONS_SEED_CORRUPT_GZIP, 52 if (base64_seed_signature.empty())
63 VARIATIONS_SEED_EMPTY_ENUM_SIZE, 53 return VerifySignatureResult::MISSING_SIGNATURE;
64 };
65 54
66 void RecordVariationSeedEmptyHistogram(VariationSeedEmptyState state) { 55 std::string signature;
67 UMA_HISTOGRAM_ENUMERATION("Variations.SeedEmpty", state, 56 if (!base::Base64Decode(base64_seed_signature, &signature))
68 VARIATIONS_SEED_EMPTY_ENUM_SIZE); 57 return VerifySignatureResult::DECODE_FAILED;
58
59 crypto::SignatureVerifier verifier;
60 if (!verifier.VerifyInit(crypto::SignatureVerifier::ECDSA_SHA256,
61 reinterpret_cast<const uint8_t*>(signature.data()),
62 signature.size(), kPublicKey,
63 arraysize(kPublicKey))) {
64 return VerifySignatureResult::INVALID_SIGNATURE;
65 }
66
67 verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(seed_bytes.data()),
68 seed_bytes.size());
69 if (!verifier.VerifyFinal())
70 return VerifySignatureResult::INVALID_SEED;
71
72 return VerifySignatureResult::VALID_SIGNATURE;
69 } 73 }
70 74
71 enum VariationsSeedStoreResult {
72 VARIATIONS_SEED_STORE_SUCCESS,
73 VARIATIONS_SEED_STORE_FAILED_EMPTY,
74 VARIATIONS_SEED_STORE_FAILED_PARSE,
75 VARIATIONS_SEED_STORE_FAILED_SIGNATURE,
76 VARIATIONS_SEED_STORE_FAILED_GZIP,
77 // DELTA_COUNT is not so much a result of the seed store, but rather counting
78 // the number of delta-compressed seeds the SeedStore() function saw. Kept in
79 // the same histogram for convenience of comparing against the other values.
80 VARIATIONS_SEED_STORE_DELTA_COUNT,
81 VARIATIONS_SEED_STORE_FAILED_DELTA_READ_SEED,
82 VARIATIONS_SEED_STORE_FAILED_DELTA_APPLY,
83 VARIATIONS_SEED_STORE_FAILED_DELTA_STORE,
84 VARIATIONS_SEED_STORE_FAILED_UNGZIP,
85 VARIATIONS_SEED_STORE_FAILED_EMPTY_GZIP_CONTENTS,
86 VARIATIONS_SEED_STORE_FAILED_UNSUPPORTED_SEED_FORMAT,
87 VARIATIONS_SEED_STORE_RESULT_ENUM_SIZE,
88 };
89
90 void RecordSeedStoreHistogram(VariationsSeedStoreResult result) {
91 UMA_HISTOGRAM_ENUMERATION("Variations.SeedStoreResult", result,
92 VARIATIONS_SEED_STORE_RESULT_ENUM_SIZE);
93 }
94
95 // Note: UMA histogram enum - don't re-order or remove entries.
96 enum VariationsSeedDateChangeState {
97 SEED_DATE_NO_OLD_DATE,
98 SEED_DATE_NEW_DATE_OLDER,
99 SEED_DATE_SAME_DAY,
100 SEED_DATE_NEW_DAY,
101 SEED_DATE_ENUM_SIZE,
102 };
103
104 // Truncates a time to the start of the day in UTC. If given a time representing 75 // Truncates a time to the start of the day in UTC. If given a time representing
105 // 2014-03-11 10:18:03.1 UTC, it will return a time representing 76 // 2014-03-11 10:18:03.1 UTC, it will return a time representing
106 // 2014-03-11 00:00:00.0 UTC. 77 // 2014-03-11 00:00:00.0 UTC.
107 base::Time TruncateToUTCDay(const base::Time& time) { 78 base::Time TruncateToUTCDay(const base::Time& time) {
108 base::Time::Exploded exploded; 79 base::Time::Exploded exploded;
109 time.UTCExplode(&exploded); 80 time.UTCExplode(&exploded);
110 exploded.hour = 0; 81 exploded.hour = 0;
111 exploded.minute = 0; 82 exploded.minute = 0;
112 exploded.second = 0; 83 exploded.second = 0;
113 exploded.millisecond = 0; 84 exploded.millisecond = 0;
114 85
115 base::Time out_time; 86 base::Time out_time;
116 bool conversion_success = base::Time::FromUTCExploded(exploded, &out_time); 87 bool conversion_success = base::Time::FromUTCExploded(exploded, &out_time);
117 DCHECK(conversion_success); 88 DCHECK(conversion_success);
118 return out_time; 89 return out_time;
119 } 90 }
120 91
121 VariationsSeedDateChangeState GetSeedDateChangeState( 92 UpdateSeedDateResult GetSeedDateChangeState(
122 const base::Time& server_seed_date, 93 const base::Time& server_seed_date,
123 const base::Time& stored_seed_date) { 94 const base::Time& stored_seed_date) {
124 if (server_seed_date < stored_seed_date) 95 if (server_seed_date < stored_seed_date)
125 return SEED_DATE_NEW_DATE_OLDER; 96 return UpdateSeedDateResult::NEW_DATE_IS_OLDER;
126 97
127 if (TruncateToUTCDay(server_seed_date) != 98 if (TruncateToUTCDay(server_seed_date) !=
128 TruncateToUTCDay(stored_seed_date)) { 99 TruncateToUTCDay(stored_seed_date)) {
129 // The server date is earlier than the stored date, and they are from 100 // The server date is later than the stored date, and they are from
130 // different UTC days, so |server_seed_date| is a valid new day. 101 // different UTC days, so |server_seed_date| is a valid new day.
131 return SEED_DATE_NEW_DAY; 102 return UpdateSeedDateResult::NEW_DAY;
132 } 103 }
133 return SEED_DATE_SAME_DAY; 104 return UpdateSeedDateResult::SAME_DAY;
134 } 105 }
135 106
136 #if defined(OS_ANDROID)
137 enum FirstRunResult {
138 FIRST_RUN_SEED_IMPORT_SUCCESS,
139 FIRST_RUN_SEED_IMPORT_FAIL_NO_CALLBACK,
140 FIRST_RUN_SEED_IMPORT_FAIL_NO_FIRST_RUN_SEED,
141 FIRST_RUN_SEED_IMPORT_FAIL_STORE_FAILED,
142 FIRST_RUN_SEED_IMPORT_FAIL_INVALID_RESPONSE_DATE,
143 FIRST_RUN_RESULT_ENUM_SIZE,
144 };
145
146 void RecordFirstRunResult(FirstRunResult result) {
147 UMA_HISTOGRAM_ENUMERATION("Variations.FirstRunResult", result,
148 FIRST_RUN_RESULT_ENUM_SIZE);
149 }
150 #endif // OS_ANDROID
151
152 } // namespace 107 } // namespace
153 108
154 VariationsSeedStore::VariationsSeedStore(PrefService* local_state) 109 VariationsSeedStore::VariationsSeedStore(PrefService* local_state)
155 : local_state_(local_state) {} 110 : local_state_(local_state) {}
156 111
157 VariationsSeedStore::~VariationsSeedStore() { 112 VariationsSeedStore::~VariationsSeedStore() {
158 } 113 }
159 114
160 bool VariationsSeedStore::LoadSeed(variations::VariationsSeed* seed) { 115 bool VariationsSeedStore::LoadSeed(variations::VariationsSeed* seed) {
161 invalid_base64_signature_.clear(); 116 invalid_base64_signature_.clear();
162 117
163 #if defined(OS_ANDROID) 118 #if defined(OS_ANDROID)
164 if (!local_state_->HasPrefPath(prefs::kVariationsSeedSignature)) 119 if (!local_state_->HasPrefPath(prefs::kVariationsSeedSignature))
165 ImportFirstRunJavaSeed(); 120 ImportFirstRunJavaSeed();
166 #endif // OS_ANDROID 121 #endif // OS_ANDROID
167 122
168 std::string seed_data; 123 std::string seed_data;
169 if (!ReadSeedData(&seed_data)) 124 LoadSeedResult read_result = ReadSeedData(&seed_data);
125 if (read_result != LoadSeedResult::SUCCESS) {
126 RecordLoadSeedResult(read_result);
170 return false; 127 return false;
128 }
171 129
172 const std::string base64_seed_signature = 130 if (SignatureVerificationEnabled()) {
173 local_state_->GetString(prefs::kVariationsSeedSignature); 131 const std::string base64_signature =
174 const VerifySignatureResult result = 132 local_state_->GetString(prefs::kVariationsSeedSignature);
175 VerifySeedSignature(seed_data, base64_seed_signature); 133
176 if (result != VARIATIONS_SEED_SIGNATURE_ENUM_SIZE) { 134 const VerifySignatureResult result =
135 VerifySeedSignature(seed_data, base64_signature);
177 UMA_HISTOGRAM_ENUMERATION("Variations.LoadSeedSignature", result, 136 UMA_HISTOGRAM_ENUMERATION("Variations.LoadSeedSignature", result,
178 VARIATIONS_SEED_SIGNATURE_ENUM_SIZE); 137 VerifySignatureResult::ENUM_SIZE);
179 if (result != VARIATIONS_SEED_SIGNATURE_VALID) { 138 if (result != VerifySignatureResult::VALID_SIGNATURE) {
139 // Record the invalid signature.
140 invalid_base64_signature_ = base64_signature;
180 ClearPrefs(); 141 ClearPrefs();
181 RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_INVALID_SIGNATURE); 142 RecordLoadSeedResult(LoadSeedResult::INVALID_SIGNATURE);
182 // Record the invalid signature.
183 invalid_base64_signature_ = base64_seed_signature;
184 return false; 143 return false;
185 } 144 }
186 } 145 }
187 146
188 if (!seed->ParseFromString(seed_data)) { 147 if (!seed->ParseFromString(seed_data)) {
189 ClearPrefs(); 148 ClearPrefs();
190 RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_CORRUPT_PROTOBUF); 149 RecordLoadSeedResult(LoadSeedResult::CORRUPT_PROTOBUF);
191 return false; 150 return false;
192 } 151 }
193 152
194 variations_serial_number_ = seed->serial_number(); 153 variations_serial_number_ = seed->serial_number();
195 RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_NOT_EMPTY); 154 RecordLoadSeedResult(LoadSeedResult::SUCCESS);
196 return true; 155 return true;
197 } 156 }
198 157
199 bool VariationsSeedStore::StoreSeedData( 158 bool VariationsSeedStore::StoreSeedData(
200 const std::string& data, 159 const std::string& data,
201 const std::string& base64_seed_signature, 160 const std::string& base64_seed_signature,
202 const std::string& country_code, 161 const std::string& country_code,
203 const base::Time& date_fetched, 162 const base::Time& date_fetched,
204 bool is_delta_compressed, 163 bool is_delta_compressed,
205 bool is_gzip_compressed, 164 bool is_gzip_compressed,
206 variations::VariationsSeed* parsed_seed) { 165 variations::VariationsSeed* parsed_seed) {
207 // If the data is gzip compressed, first uncompress it. 166 // If the data is gzip compressed, first uncompress it.
208 std::string ungzipped_data; 167 std::string ungzipped_data;
209 if (is_gzip_compressed) { 168 if (is_gzip_compressed) {
210 if (compression::GzipUncompress(data, &ungzipped_data)) { 169 if (compression::GzipUncompress(data, &ungzipped_data)) {
211 if (ungzipped_data.empty()) { 170 if (ungzipped_data.empty()) {
212 RecordSeedStoreHistogram( 171 RecordStoreSeedResult(StoreSeedResult::FAILED_EMPTY_GZIP_CONTENTS);
213 VARIATIONS_SEED_STORE_FAILED_EMPTY_GZIP_CONTENTS);
214 return false; 172 return false;
215 } 173 }
216 174
217 int size_reduction = ungzipped_data.length() - data.length(); 175 int size_reduction = ungzipped_data.length() - data.length();
218 UMA_HISTOGRAM_PERCENTAGE("Variations.StoreSeed.GzipSize.ReductionPercent", 176 UMA_HISTOGRAM_PERCENTAGE("Variations.StoreSeed.GzipSize.ReductionPercent",
219 100 * size_reduction / ungzipped_data.length()); 177 100 * size_reduction / ungzipped_data.length());
220 UMA_HISTOGRAM_COUNTS_1000("Variations.StoreSeed.GzipSize", 178 UMA_HISTOGRAM_COUNTS_1000("Variations.StoreSeed.GzipSize",
221 data.length() / 1024); 179 data.length() / 1024);
222 } else { 180 } else {
223 RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_UNGZIP); 181 RecordStoreSeedResult(StoreSeedResult::FAILED_UNGZIP);
224 return false; 182 return false;
225 } 183 }
226 } else { 184 } else {
227 ungzipped_data = data; 185 ungzipped_data = data;
228 } 186 }
229 187
230 if (!is_delta_compressed) { 188 if (!is_delta_compressed) {
231 const bool result = 189 const bool result =
232 StoreSeedDataNoDelta(ungzipped_data, base64_seed_signature, 190 StoreSeedDataNoDelta(ungzipped_data, base64_seed_signature,
233 country_code, date_fetched, parsed_seed); 191 country_code, date_fetched, parsed_seed);
234 if (result) { 192 if (result) {
235 UMA_HISTOGRAM_COUNTS_1000("Variations.StoreSeed.Size", 193 UMA_HISTOGRAM_COUNTS_1000("Variations.StoreSeed.Size",
236 ungzipped_data.length() / 1024); 194 ungzipped_data.length() / 1024);
237 } 195 }
238 return result; 196 return result;
239 } 197 }
240 198
241 // If the data is delta compressed, first decode it. 199 // If the data is delta compressed, first decode it.
242 DCHECK(invalid_base64_signature_.empty()); 200 DCHECK(invalid_base64_signature_.empty());
243 RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_DELTA_COUNT); 201 RecordStoreSeedResult(StoreSeedResult::DELTA_COUNT);
244 202
245 std::string existing_seed_data; 203 std::string existing_seed_data;
246 std::string updated_seed_data; 204 std::string updated_seed_data;
247 if (!ReadSeedData(&existing_seed_data)) { 205 LoadSeedResult read_result = ReadSeedData(&existing_seed_data);
248 RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_DELTA_READ_SEED); 206 if (read_result != LoadSeedResult::SUCCESS) {
207 RecordStoreSeedResult(StoreSeedResult::FAILED_DELTA_READ_SEED);
249 return false; 208 return false;
250 } 209 }
251 if (!ApplyDeltaPatch(existing_seed_data, ungzipped_data, 210 if (!ApplyDeltaPatch(existing_seed_data, ungzipped_data,
252 &updated_seed_data)) { 211 &updated_seed_data)) {
253 RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_DELTA_APPLY); 212 RecordStoreSeedResult(StoreSeedResult::FAILED_DELTA_APPLY);
254 return false; 213 return false;
255 } 214 }
256 215
257 const bool result = 216 const bool result =
258 StoreSeedDataNoDelta(updated_seed_data, base64_seed_signature, 217 StoreSeedDataNoDelta(updated_seed_data, base64_seed_signature,
259 country_code, date_fetched, parsed_seed); 218 country_code, date_fetched, parsed_seed);
260 if (result) { 219 if (result) {
261 // Note: |updated_seed_data.length()| is guaranteed to be non-zero, else 220 // Note: |updated_seed_data.length()| is guaranteed to be non-zero, else
262 // result would be false. 221 // result would be false.
263 int size_reduction = updated_seed_data.length() - ungzipped_data.length(); 222 int size_reduction = updated_seed_data.length() - ungzipped_data.length();
264 UMA_HISTOGRAM_PERCENTAGE("Variations.StoreSeed.DeltaSize.ReductionPercent", 223 UMA_HISTOGRAM_PERCENTAGE("Variations.StoreSeed.DeltaSize.ReductionPercent",
265 100 * size_reduction / updated_seed_data.length()); 224 100 * size_reduction / updated_seed_data.length());
266 UMA_HISTOGRAM_COUNTS_1000("Variations.StoreSeed.DeltaSize", 225 UMA_HISTOGRAM_COUNTS_1000("Variations.StoreSeed.DeltaSize",
267 ungzipped_data.length() / 1024); 226 ungzipped_data.length() / 1024);
268 } else { 227 } else {
269 RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_DELTA_STORE); 228 RecordStoreSeedResult(StoreSeedResult::FAILED_DELTA_STORE);
270 } 229 }
271 return result; 230 return result;
272 } 231 }
273 232
274 void VariationsSeedStore::UpdateSeedDateAndLogDayChange( 233 void VariationsSeedStore::UpdateSeedDateAndLogDayChange(
275 const base::Time& server_date_fetched) { 234 const base::Time& server_date_fetched) {
276 VariationsSeedDateChangeState date_change = SEED_DATE_NO_OLD_DATE; 235 UpdateSeedDateResult result = UpdateSeedDateResult::NO_OLD_DATE;
277 236
278 if (local_state_->HasPrefPath(prefs::kVariationsSeedDate)) { 237 if (local_state_->HasPrefPath(prefs::kVariationsSeedDate)) {
279 const int64_t stored_date_value = 238 const int64_t stored_date_value =
280 local_state_->GetInt64(prefs::kVariationsSeedDate); 239 local_state_->GetInt64(prefs::kVariationsSeedDate);
281 const base::Time stored_date = 240 const base::Time stored_date =
282 base::Time::FromInternalValue(stored_date_value); 241 base::Time::FromInternalValue(stored_date_value);
283 242
284 date_change = GetSeedDateChangeState(server_date_fetched, stored_date); 243 result = GetSeedDateChangeState(server_date_fetched, stored_date);
285 } 244 }
286 245
287 UMA_HISTOGRAM_ENUMERATION("Variations.SeedDateChange", date_change, 246 UMA_HISTOGRAM_ENUMERATION("Variations.SeedDateChange", result,
288 SEED_DATE_ENUM_SIZE); 247 UpdateSeedDateResult::ENUM_SIZE);
289 248
290 local_state_->SetInt64(prefs::kVariationsSeedDate, 249 local_state_->SetInt64(prefs::kVariationsSeedDate,
291 server_date_fetched.ToInternalValue()); 250 server_date_fetched.ToInternalValue());
292 } 251 }
293 252
294 std::string VariationsSeedStore::GetInvalidSignature() const { 253 std::string VariationsSeedStore::GetInvalidSignature() const {
295 return invalid_base64_signature_; 254 return invalid_base64_signature_;
296 } 255 }
297 256
298 // static 257 // static
299 void VariationsSeedStore::RegisterPrefs(PrefRegistrySimple* registry) { 258 void VariationsSeedStore::RegisterPrefs(PrefRegistrySimple* registry) {
300 registry->RegisterStringPref(prefs::kVariationsCompressedSeed, std::string()); 259 registry->RegisterStringPref(prefs::kVariationsCompressedSeed, std::string());
301 registry->RegisterStringPref(prefs::kVariationsCountry, std::string()); 260 registry->RegisterStringPref(prefs::kVariationsCountry, std::string());
302 registry->RegisterInt64Pref(prefs::kVariationsSeedDate, 261 registry->RegisterInt64Pref(prefs::kVariationsSeedDate,
303 base::Time().ToInternalValue()); 262 base::Time().ToInternalValue());
304 registry->RegisterStringPref(prefs::kVariationsSeedSignature, std::string()); 263 registry->RegisterStringPref(prefs::kVariationsSeedSignature, std::string());
305 } 264 }
306 265
307 VariationsSeedStore::VerifySignatureResult 266 bool VariationsSeedStore::SignatureVerificationEnabled() {
308 VariationsSeedStore::VerifySeedSignature( 267 #if defined(OS_IOS) || defined(OS_ANDROID)
309 const std::string& seed_bytes, 268 // Signature verification is disabled on mobile platforms for now, since it
310 const std::string& base64_seed_signature) { 269 // adds about ~15ms to the startup time on mobile (vs. a couple ms on
311 if (!SignatureVerificationEnabled()) 270 // desktop).
312 return VARIATIONS_SEED_SIGNATURE_ENUM_SIZE; 271 return false;
313 272 #else
314 if (base64_seed_signature.empty()) 273 return true;
315 return VARIATIONS_SEED_SIGNATURE_MISSING; 274 #endif
316
317 std::string signature;
318 if (!base::Base64Decode(base64_seed_signature, &signature))
319 return VARIATIONS_SEED_SIGNATURE_DECODE_FAILED;
320
321 crypto::SignatureVerifier verifier;
322 if (!verifier.VerifyInit(crypto::SignatureVerifier::ECDSA_SHA256,
323 reinterpret_cast<const uint8_t*>(signature.data()),
324 signature.size(), kPublicKey,
325 arraysize(kPublicKey))) {
326 return VARIATIONS_SEED_SIGNATURE_INVALID_SIGNATURE;
327 }
328
329 verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(seed_bytes.data()),
330 seed_bytes.size());
331 if (verifier.VerifyFinal())
332 return VARIATIONS_SEED_SIGNATURE_VALID;
333 return VARIATIONS_SEED_SIGNATURE_INVALID_SEED;
334 } 275 }
335 276
336 void VariationsSeedStore::ClearPrefs() { 277 void VariationsSeedStore::ClearPrefs() {
337 local_state_->ClearPref(prefs::kVariationsCompressedSeed); 278 local_state_->ClearPref(prefs::kVariationsCompressedSeed);
338 local_state_->ClearPref(prefs::kVariationsSeedDate); 279 local_state_->ClearPref(prefs::kVariationsSeedDate);
339 local_state_->ClearPref(prefs::kVariationsSeedSignature); 280 local_state_->ClearPref(prefs::kVariationsSeedSignature);
340 } 281 }
341 282
342 #if defined(OS_ANDROID) 283 #if defined(OS_ANDROID)
343 void VariationsSeedStore::ImportFirstRunJavaSeed() { 284 void VariationsSeedStore::ImportFirstRunJavaSeed() {
344 DVLOG(1) << "Importing first run seed from Java preferences."; 285 DVLOG(1) << "Importing first run seed from Java preferences.";
345 286
346 std::string seed_data; 287 std::string seed_data;
347 std::string seed_signature; 288 std::string seed_signature;
348 std::string seed_country; 289 std::string seed_country;
349 std::string response_date; 290 std::string response_date;
350 bool is_gzip_compressed; 291 bool is_gzip_compressed;
351 292
352 android::GetVariationsFirstRunSeed(&seed_data, &seed_signature, &seed_country, 293 android::GetVariationsFirstRunSeed(&seed_data, &seed_signature, &seed_country,
353 &response_date, &is_gzip_compressed); 294 &response_date, &is_gzip_compressed);
354 if (seed_data.empty()) { 295 if (seed_data.empty()) {
355 RecordFirstRunResult(FIRST_RUN_SEED_IMPORT_FAIL_NO_FIRST_RUN_SEED); 296 RecordFirstRunSeedImportResult(
297 FirstRunSeedImportResult::FAIL_NO_FIRST_RUN_SEED);
356 return; 298 return;
357 } 299 }
358 300
359 base::Time current_date; 301 base::Time current_date;
360 if (!base::Time::FromUTCString(response_date.c_str(), &current_date)) { 302 if (!base::Time::FromUTCString(response_date.c_str(), &current_date)) {
361 RecordFirstRunResult(FIRST_RUN_SEED_IMPORT_FAIL_INVALID_RESPONSE_DATE); 303 RecordFirstRunSeedImportResult(
304 FirstRunSeedImportResult::FAIL_INVALID_RESPONSE_DATE);
362 LOG(WARNING) << "Invalid response date: " << response_date; 305 LOG(WARNING) << "Invalid response date: " << response_date;
363 return; 306 return;
364 } 307 }
365 308
366 if (!StoreSeedData(seed_data, seed_signature, seed_country, current_date, 309 if (!StoreSeedData(seed_data, seed_signature, seed_country, current_date,
367 false, is_gzip_compressed, nullptr)) { 310 false, is_gzip_compressed, nullptr)) {
368 RecordFirstRunResult(FIRST_RUN_SEED_IMPORT_FAIL_STORE_FAILED); 311 RecordFirstRunSeedImportResult(FirstRunSeedImportResult::FAIL_STORE_FAILED);
369 LOG(WARNING) << "First run variations seed is invalid."; 312 LOG(WARNING) << "First run variations seed is invalid.";
370 return; 313 return;
371 } 314 }
372 RecordFirstRunResult(FIRST_RUN_SEED_IMPORT_SUCCESS); 315 RecordFirstRunSeedImportResult(FirstRunSeedImportResult::SUCCESS);
373 } 316 }
374 #endif // OS_ANDROID 317 #endif // OS_ANDROID
375 318
376 bool VariationsSeedStore::ReadSeedData(std::string* seed_data) { 319 LoadSeedResult VariationsSeedStore::ReadSeedData(std::string* seed_data) {
377 std::string base64_seed_data = 320 std::string base64_seed_data =
378 local_state_->GetString(prefs::kVariationsCompressedSeed); 321 local_state_->GetString(prefs::kVariationsCompressedSeed);
379 if (base64_seed_data.empty()) { 322 if (base64_seed_data.empty()) {
Alexei Svitkine (slow) 2017/06/13 15:26:37 Nit: No {}s
Ilya Sherman 2017/06/13 22:33:34 Done.
380 RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_EMPTY); 323 return LoadSeedResult::EMPTY;
381 return false;
382 } 324 }
383 325
384 // If the decode process fails, assume the pref value is corrupt and clear it. 326 // If the decode process fails, assume the pref value is corrupt and clear it.
385 std::string decoded_data; 327 std::string decoded_data;
386 if (!base::Base64Decode(base64_seed_data, &decoded_data)) { 328 if (!base::Base64Decode(base64_seed_data, &decoded_data)) {
387 ClearPrefs(); 329 ClearPrefs();
388 RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_CORRUPT_BASE64); 330 return LoadSeedResult::CORRUPT_BASE64;
389 return false;
390 } 331 }
391 332
392 if (!compression::GzipUncompress(decoded_data, seed_data)) { 333 if (!compression::GzipUncompress(decoded_data, seed_data)) {
393 ClearPrefs(); 334 ClearPrefs();
394 RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_CORRUPT_GZIP); 335 return LoadSeedResult::CORRUPT_GZIP;
395 return false;
396 } 336 }
397 337
398 return true; 338 return LoadSeedResult::SUCCESS;
399 } 339 }
400 340
401 bool VariationsSeedStore::StoreSeedDataNoDelta( 341 bool VariationsSeedStore::StoreSeedDataNoDelta(
402 const std::string& seed_data, 342 const std::string& seed_data,
403 const std::string& base64_seed_signature, 343 const std::string& base64_seed_signature,
404 const std::string& country_code, 344 const std::string& country_code,
405 const base::Time& date_fetched, 345 const base::Time& date_fetched,
406 variations::VariationsSeed* parsed_seed) { 346 variations::VariationsSeed* parsed_seed) {
407 if (seed_data.empty()) { 347 if (seed_data.empty()) {
408 RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_EMPTY_GZIP_CONTENTS); 348 RecordStoreSeedResult(StoreSeedResult::FAILED_EMPTY_GZIP_CONTENTS);
409 return false; 349 return false;
410 } 350 }
411 351
412 // Only store the seed data if it parses correctly. 352 // Only store the seed data if it parses correctly.
413 variations::VariationsSeed seed; 353 variations::VariationsSeed seed;
414 if (!seed.ParseFromString(seed_data)) { 354 if (!seed.ParseFromString(seed_data)) {
415 RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_PARSE); 355 RecordStoreSeedResult(StoreSeedResult::FAILED_PARSE);
416 return false; 356 return false;
417 } 357 }
418 358
419 const VerifySignatureResult result = 359 if (SignatureVerificationEnabled()) {
420 VerifySeedSignature(seed_data, base64_seed_signature); 360 const VerifySignatureResult result =
421 if (result != VARIATIONS_SEED_SIGNATURE_ENUM_SIZE) { 361 VerifySeedSignature(seed_data, base64_seed_signature);
422 UMA_HISTOGRAM_ENUMERATION("Variations.StoreSeedSignature", result, 362 UMA_HISTOGRAM_ENUMERATION("Variations.StoreSeedSignature", result,
423 VARIATIONS_SEED_SIGNATURE_ENUM_SIZE); 363 VerifySignatureResult::ENUM_SIZE);
424 if (result != VARIATIONS_SEED_SIGNATURE_VALID) { 364 if (result != VerifySignatureResult::VALID_SIGNATURE) {
425 RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_SIGNATURE); 365 RecordStoreSeedResult(StoreSeedResult::FAILED_SIGNATURE);
426 return false; 366 return false;
427 } 367 }
428 } 368 }
429 369
430 // Compress the seed before base64-encoding and storing. 370 // Compress the seed before base64-encoding and storing.
431 std::string compressed_seed_data; 371 std::string compressed_seed_data;
432 if (!compression::GzipCompress(seed_data, &compressed_seed_data)) { 372 if (!compression::GzipCompress(seed_data, &compressed_seed_data)) {
433 RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_GZIP); 373 RecordStoreSeedResult(StoreSeedResult::FAILED_GZIP);
434 return false; 374 return false;
435 } 375 }
436 376
437 std::string base64_seed_data; 377 std::string base64_seed_data;
438 base::Base64Encode(compressed_seed_data, &base64_seed_data); 378 base::Base64Encode(compressed_seed_data, &base64_seed_data);
439 379
440 #if defined(OS_ANDROID) 380 #if defined(OS_ANDROID)
441 // If currently we do not have any stored pref then we mark seed storing as 381 // If currently we do not have any stored pref then we mark seed storing as
442 // successful on the Java side of Chrome for Android to avoid repeated seed 382 // successful on the Java side of Chrome for Android to avoid repeated seed
443 // fetches and clear preferences on the Java side. 383 // fetches and clear preferences on the Java side.
444 if (local_state_->GetString(prefs::kVariationsCompressedSeed).empty()) { 384 if (local_state_->GetString(prefs::kVariationsCompressedSeed).empty()) {
445 android::MarkVariationsSeedAsStored(); 385 android::MarkVariationsSeedAsStored();
446 android::ClearJavaFirstRunPrefs(); 386 android::ClearJavaFirstRunPrefs();
447 } 387 }
448 #endif 388 #endif
449 389
450 // Update the saved country code only if one was returned from the server. 390 // Update the saved country code only if one was returned from the server.
451 if (!country_code.empty()) 391 if (!country_code.empty())
452 local_state_->SetString(prefs::kVariationsCountry, country_code); 392 local_state_->SetString(prefs::kVariationsCountry, country_code);
453 393
454 local_state_->SetString(prefs::kVariationsCompressedSeed, base64_seed_data); 394 local_state_->SetString(prefs::kVariationsCompressedSeed, base64_seed_data);
455 UpdateSeedDateAndLogDayChange(date_fetched); 395 UpdateSeedDateAndLogDayChange(date_fetched);
456 local_state_->SetString(prefs::kVariationsSeedSignature, 396 local_state_->SetString(prefs::kVariationsSeedSignature,
457 base64_seed_signature); 397 base64_seed_signature);
458 variations_serial_number_ = seed.serial_number(); 398 variations_serial_number_ = seed.serial_number();
459 if (parsed_seed) 399 if (parsed_seed)
460 seed.Swap(parsed_seed); 400 seed.Swap(parsed_seed);
461 401
462 RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_SUCCESS); 402 RecordStoreSeedResult(StoreSeedResult::SUCCESS);
463 return true; 403 return true;
464 } 404 }
465 405
466 // static 406 // static
467 bool VariationsSeedStore::ApplyDeltaPatch(const std::string& existing_data, 407 bool VariationsSeedStore::ApplyDeltaPatch(const std::string& existing_data,
468 const std::string& patch, 408 const std::string& patch,
469 std::string* output) { 409 std::string* output) {
470 output->clear(); 410 output->clear();
471 411
472 google::protobuf::io::CodedInputStream in( 412 google::protobuf::io::CodedInputStream in(
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 end_offset += length; 445 end_offset += length;
506 if (!end_offset.IsValid() || end_offset.ValueOrDie() > existing_data_size) 446 if (!end_offset.IsValid() || end_offset.ValueOrDie() > existing_data_size)
507 return false; 447 return false;
508 output->append(existing_data, offset, length); 448 output->append(existing_data, offset, length);
509 } 449 }
510 } 450 }
511 return true; 451 return true;
512 } 452 }
513 453
514 void VariationsSeedStore::ReportUnsupportedSeedFormatError() { 454 void VariationsSeedStore::ReportUnsupportedSeedFormatError() {
515 RecordSeedStoreHistogram( 455 RecordStoreSeedResult(StoreSeedResult::FAILED_UNSUPPORTED_SEED_FORMAT);
516 VARIATIONS_SEED_STORE_FAILED_UNSUPPORTED_SEED_FORMAT);
517 } 456 }
518 457
519 } // namespace variations 458 } // namespace variations
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698