Chromium Code Reviews| 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/variations/variations_seed_store.h" | 5 #include "components/variations/variations_seed_store.h" |
| 6 | 6 |
| 7 #include "base/base64.h" | 7 #include "base/base64.h" |
| 8 #include "base/macros.h" | 8 #include "base/macros.h" |
| 9 #include "base/test/histogram_tester.h" | |
| 9 #include "build/build_config.h" | 10 #include "build/build_config.h" |
| 10 #include "components/prefs/testing_pref_service.h" | 11 #include "components/prefs/testing_pref_service.h" |
| 11 #include "components/variations/pref_names.h" | 12 #include "components/variations/pref_names.h" |
| 12 #include "components/variations/proto/study.pb.h" | 13 #include "components/variations/proto/study.pb.h" |
| 13 #include "components/variations/proto/variations_seed.pb.h" | 14 #include "components/variations/proto/variations_seed.pb.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 15 #include "third_party/zlib/google/compression_utils.h" | 16 #include "third_party/zlib/google/compression_utils.h" |
| 16 | 17 |
| 17 #if defined(OS_ANDROID) | 18 #if defined(OS_ANDROID) |
| 18 #include "components/variations/android/variations_seed_bridge.h" | 19 #include "components/variations/android/variations_seed_bridge.h" |
| 19 #endif // OS_ANDROID | 20 #endif // OS_ANDROID |
| 20 | 21 |
| 21 namespace variations { | 22 namespace variations { |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| 25 class TestVariationsSeedStore : public VariationsSeedStore { | 26 class TestVariationsSeedStore : public VariationsSeedStore { |
| 26 public: | 27 public: |
| 27 explicit TestVariationsSeedStore(PrefService* local_state) | 28 explicit TestVariationsSeedStore(PrefService* local_state) |
| 28 : VariationsSeedStore(local_state) {} | 29 : VariationsSeedStore(local_state) {} |
| 29 ~TestVariationsSeedStore() override {} | 30 ~TestVariationsSeedStore() override {} |
| 30 | 31 |
| 31 bool StoreSeedForTesting(const std::string& seed_data) { | 32 bool StoreSeedForTesting(const std::string& seed_data) { |
| 32 return StoreSeedData(seed_data, std::string(), std::string(), | 33 return StoreSeedData(seed_data, std::string(), std::string(), |
| 33 base::Time::Now(), false, false, nullptr); | 34 base::Time::Now(), false, false, nullptr); |
| 34 } | 35 } |
| 35 | 36 |
| 36 VariationsSeedStore::VerifySignatureResult VerifySeedSignature( | 37 bool SignatureVerificationEnabled() override { return false; } |
| 37 const std::string& seed_bytes, | |
| 38 const std::string& base64_seed_signature) override { | |
| 39 return VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_ENUM_SIZE; | |
| 40 } | |
| 41 | 38 |
| 42 private: | 39 private: |
| 43 DISALLOW_COPY_AND_ASSIGN(TestVariationsSeedStore); | 40 DISALLOW_COPY_AND_ASSIGN(TestVariationsSeedStore); |
| 44 }; | 41 }; |
| 45 | 42 |
| 46 | 43 |
| 47 // Populates |seed| with simple test data. The resulting seed will contain one | 44 // Populates |seed| with simple test data. The resulting seed will contain one |
| 48 // study called "test", which contains one experiment called "abc" with | 45 // study called "test", which contains one experiment called "abc" with |
| 49 // probability weight 100. |seed|'s study field will be cleared before adding | 46 // probability weight 100. |seed|'s study field will be cleared before adding |
| 50 // the new study. | 47 // the new study. |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 152 base::Base64Encode(Compress(uncompressed_seed_data), | 149 base::Base64Encode(Compress(uncompressed_seed_data), |
| 153 &compressed_base64_seed_data); | 150 &compressed_base64_seed_data); |
| 154 | 151 |
| 155 // Set seed and valid signature in prefs. | 152 // Set seed and valid signature in prefs. |
| 156 prefs.SetString(prefs::kVariationsCompressedSeed, | 153 prefs.SetString(prefs::kVariationsCompressedSeed, |
| 157 compressed_base64_seed_data); | 154 compressed_base64_seed_data); |
| 158 prefs.SetString(prefs::kVariationsSeedSignature, base64_seed_signature); | 155 prefs.SetString(prefs::kVariationsSeedSignature, base64_seed_signature); |
| 159 | 156 |
| 160 VariationsSeedStore seed_store(&prefs); | 157 VariationsSeedStore seed_store(&prefs); |
| 161 variations::VariationsSeed loaded_seed; | 158 variations::VariationsSeed loaded_seed; |
| 162 seed_store.LoadSeed(&loaded_seed); | 159 EXPECT_TRUE(seed_store.LoadSeed(&loaded_seed)); |
| 163 std::string invalid_signature = seed_store.GetInvalidSignature(); | 160 std::string invalid_signature = seed_store.GetInvalidSignature(); |
| 164 // Valid signature so we get an empty string. | 161 // Valid signature so we get an empty string. |
| 165 EXPECT_EQ(std::string(), invalid_signature); | 162 EXPECT_EQ(std::string(), invalid_signature); |
| 166 | 163 |
| 167 prefs.SetString(prefs::kVariationsSeedSignature, | 164 prefs.SetString(prefs::kVariationsSeedSignature, |
| 168 base64_seed_signature_invalid); | 165 base64_seed_signature_invalid); |
| 169 seed_store.LoadSeed(&loaded_seed); | 166 #if defined(OS_IOS) || defined(OS_ANDROID) |
| 167 EXPECT_TRUE(seed_store.LoadSeed(&loaded_seed)); | |
| 168 #else | |
| 169 EXPECT_FALSE(seed_store.LoadSeed(&loaded_seed)); | |
| 170 #endif | |
| 170 // Invalid signature, so we should get the signature itself, except on mobile | 171 // Invalid signature, so we should get the signature itself, except on mobile |
| 171 // where we should get an empty string because verification is not enabled. | 172 // where we should get an empty string because verification is not enabled. |
| 172 invalid_signature = seed_store.GetInvalidSignature(); | 173 invalid_signature = seed_store.GetInvalidSignature(); |
| 173 #if defined(OS_IOS) || defined(OS_ANDROID) | 174 #if defined(OS_IOS) || defined(OS_ANDROID) |
| 174 EXPECT_EQ(std::string(), invalid_signature); | 175 EXPECT_EQ(std::string(), invalid_signature); |
| 175 #else | 176 #else |
| 176 EXPECT_EQ(base64_seed_signature_invalid, invalid_signature); | 177 EXPECT_EQ(base64_seed_signature_invalid, invalid_signature); |
| 177 #endif | 178 #endif |
| 178 | 179 |
| 179 prefs.SetString(prefs::kVariationsSeedSignature, std::string()); | 180 prefs.SetString(prefs::kVariationsSeedSignature, std::string()); |
| 180 seed_store.LoadSeed(&loaded_seed); | 181 #if defined(OS_IOS) || defined(OS_ANDROID) |
| 182 EXPECT_TRUE(seed_store.LoadSeed(&loaded_seed)); | |
| 183 #else | |
| 184 EXPECT_FALSE(seed_store.LoadSeed(&loaded_seed)); | |
| 185 #endif | |
| 181 invalid_signature = seed_store.GetInvalidSignature(); | 186 invalid_signature = seed_store.GetInvalidSignature(); |
| 182 // Empty signature, not considered invalid. | 187 // Empty signature, not considered invalid. |
| 183 EXPECT_EQ(std::string(), invalid_signature); | 188 EXPECT_EQ(std::string(), invalid_signature); |
| 184 } | 189 } |
| 185 | 190 |
| 186 TEST(VariationsSeedStoreTest, StoreSeedData) { | 191 TEST(VariationsSeedStoreTest, StoreSeedData) { |
| 187 const variations::VariationsSeed seed = CreateTestSeed(); | 192 const variations::VariationsSeed seed = CreateTestSeed(); |
| 188 const std::string serialized_seed = SerializeSeed(seed); | 193 const std::string serialized_seed = SerializeSeed(seed); |
| 189 | 194 |
| 190 TestingPrefServiceSimple prefs; | 195 TestingPrefServiceSimple prefs; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 270 VariationsSeedStore::RegisterPrefs(prefs.registry()); | 275 VariationsSeedStore::RegisterPrefs(prefs.registry()); |
| 271 TestVariationsSeedStore seed_store(&prefs); | 276 TestVariationsSeedStore seed_store(&prefs); |
| 272 | 277 |
| 273 variations::VariationsSeed parsed_seed; | 278 variations::VariationsSeed parsed_seed; |
| 274 EXPECT_FALSE(seed_store.StoreSeedData(compressed_seed, std::string(), | 279 EXPECT_FALSE(seed_store.StoreSeedData(compressed_seed, std::string(), |
| 275 std::string(), base::Time::Now(), false, | 280 std::string(), base::Time::Now(), false, |
| 276 true, &parsed_seed)); | 281 true, &parsed_seed)); |
| 277 } | 282 } |
| 278 | 283 |
| 279 TEST(VariationsSeedStoreTest, VerifySeedSignature) { | 284 TEST(VariationsSeedStoreTest, VerifySeedSignature) { |
| 285 TestingPrefServiceSimple prefs; | |
| 286 VariationsSeedStore::RegisterPrefs(prefs.registry()); | |
| 287 | |
| 288 #if defined(OS_IOS) || defined(OS_ANDROID) | |
| 289 // Signature verification is not enabled on mobile. | |
| 290 ASSERT_FALSE(VariationsSeedStore(&prefs).SignatureVerificationEnabled()); | |
|
Alexei Svitkine (slow)
2017/06/13 15:26:37
Could we just enable verification for the test?
Ilya Sherman
2017/06/13 22:33:34
Done.
| |
| 291 return; | |
| 292 #endif | |
| 293 | |
| 280 // The below seed and signature pair were generated using the server's | 294 // The below seed and signature pair were generated using the server's |
| 281 // private key. | 295 // private key. |
| 282 const std::string base64_seed_data = | 296 const std::string uncompressed_base64_seed_data = |
| 283 "CigxZDI5NDY0ZmIzZDc4ZmYxNTU2ZTViNTUxYzY0NDdjYmM3NGU1ZmQwEr0BCh9VTUEtVW5p" | 297 "CigxZDI5NDY0ZmIzZDc4ZmYxNTU2ZTViNTUxYzY0NDdjYmM3NGU1ZmQwEr0BCh9VTUEtVW5p" |
| 284 "Zm9ybWl0eS1UcmlhbC0xMC1QZXJjZW50GICckqUFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBAB" | 298 "Zm9ybWl0eS1UcmlhbC0xMC1QZXJjZW50GICckqUFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBAB" |
| 285 "SgwKCGdyb3VwXzAxEAFKDAoIZ3JvdXBfMDIQAUoMCghncm91cF8wMxABSgwKCGdyb3VwXzA0" | 299 "SgwKCGdyb3VwXzAxEAFKDAoIZ3JvdXBfMDIQAUoMCghncm91cF8wMxABSgwKCGdyb3VwXzA0" |
| 286 "EAFKDAoIZ3JvdXBfMDUQAUoMCghncm91cF8wNhABSgwKCGdyb3VwXzA3EAFKDAoIZ3JvdXBf" | 300 "EAFKDAoIZ3JvdXBfMDUQAUoMCghncm91cF8wNhABSgwKCGdyb3VwXzA3EAFKDAoIZ3JvdXBf" |
| 287 "MDgQAUoMCghncm91cF8wORAB"; | 301 "MDgQAUoMCghncm91cF8wORAB"; |
| 288 const std::string base64_seed_signature = | 302 const std::string base64_seed_signature = |
| 289 "MEQCIDD1IVxjzWYncun+9IGzqYjZvqxxujQEayJULTlbTGA/AiAr0oVmEgVUQZBYq5VLOSvy" | 303 "MEQCIDD1IVxjzWYncun+9IGzqYjZvqxxujQEayJULTlbTGA/AiAr0oVmEgVUQZBYq5VLOSvy" |
| 290 "96JkMYgzTkHPwbv7K/CmgA=="; | 304 "96JkMYgzTkHPwbv7K/CmgA=="; |
| 291 | 305 |
| 292 std::string seed_data; | 306 std::string seed_data; |
| 293 EXPECT_TRUE(base::Base64Decode(base64_seed_data, &seed_data)); | 307 ASSERT_TRUE(base::Base64Decode(uncompressed_base64_seed_data, &seed_data)); |
| 294 | 308 VariationsSeed seed; |
| 295 VariationsSeedStore seed_store(NULL); | 309 ASSERT_TRUE(seed.ParseFromString(seed_data)); |
| 296 | 310 std::string base64_seed_data = SerializeSeedBase64(seed); |
| 297 #if defined(OS_IOS) || defined(OS_ANDROID) | |
| 298 // Signature verification is not enabled on mobile. | |
| 299 if (seed_store.VerifySeedSignature(seed_data, base64_seed_signature) == | |
| 300 VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_ENUM_SIZE) { | |
| 301 return; | |
| 302 } | |
| 303 #endif | |
| 304 | 311 |
| 305 // The above inputs should be valid. | 312 // The above inputs should be valid. |
| 306 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_VALID, | 313 { |
| 307 seed_store.VerifySeedSignature(seed_data, base64_seed_signature)); | 314 prefs.SetString(prefs::kVariationsCompressedSeed, base64_seed_data); |
| 315 prefs.SetString(prefs::kVariationsSeedSignature, base64_seed_signature); | |
| 316 VariationsSeedStore seed_store(&prefs); | |
| 317 | |
| 318 base::HistogramTester histogram_tester; | |
| 319 VariationsSeed seed; | |
| 320 EXPECT_TRUE(seed_store.LoadSeed(&seed)); | |
| 321 histogram_tester.ExpectUniqueSample( | |
| 322 "Variations.LoadSeedSignature", | |
| 323 static_cast<base::HistogramBase::Sample>( | |
| 324 VerifySignatureResult::VALID_SIGNATURE), | |
| 325 1); | |
| 326 } | |
| 308 | 327 |
| 309 // If there's no signature, the corresponding result should be returned. | 328 // If there's no signature, the corresponding result should be returned. |
| 310 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_MISSING, | 329 { |
| 311 seed_store.VerifySeedSignature(seed_data, std::string())); | 330 prefs.SetString(prefs::kVariationsCompressedSeed, base64_seed_data); |
| 331 prefs.SetString(prefs::kVariationsSeedSignature, std::string()); | |
| 332 VariationsSeedStore seed_store(&prefs); | |
| 312 | 333 |
| 313 // Using non-base64 encoded value as signature (e.g. seed data) should fail. | 334 base::HistogramTester histogram_tester; |
| 314 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_DECODE_FAILED, | 335 VariationsSeed seed; |
| 315 seed_store.VerifySeedSignature(seed_data, seed_data)); | 336 EXPECT_FALSE(seed_store.LoadSeed(&seed)); |
| 337 histogram_tester.ExpectUniqueSample( | |
| 338 "Variations.LoadSeedSignature", | |
| 339 static_cast<base::HistogramBase::Sample>( | |
| 340 VerifySignatureResult::MISSING_SIGNATURE), | |
| 341 1); | |
| 342 } | |
| 343 | |
| 344 // Using non-base64 encoded value as signature should fail. | |
| 345 { | |
| 346 prefs.SetString(prefs::kVariationsCompressedSeed, base64_seed_data); | |
| 347 prefs.SetString(prefs::kVariationsSeedSignature, | |
| 348 "not a base64-encoded string"); | |
| 349 VariationsSeedStore seed_store(&prefs); | |
| 350 | |
| 351 base::HistogramTester histogram_tester; | |
| 352 VariationsSeed seed; | |
| 353 EXPECT_FALSE(seed_store.LoadSeed(&seed)); | |
| 354 histogram_tester.ExpectUniqueSample( | |
| 355 "Variations.LoadSeedSignature", | |
| 356 static_cast<base::HistogramBase::Sample>( | |
| 357 VerifySignatureResult::DECODE_FAILED), | |
| 358 1); | |
| 359 } | |
| 316 | 360 |
| 317 // Using a different signature (e.g. the base64 seed data) should fail. | 361 // Using a different signature (e.g. the base64 seed data) should fail. |
| 318 // OpenSSL doesn't distinguish signature decode failure from the | 362 // OpenSSL doesn't distinguish signature decode failure from the |
| 319 // signature not matching. | 363 // signature not matching. |
| 320 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SEED, | 364 { |
| 321 seed_store.VerifySeedSignature(seed_data, base64_seed_data)); | 365 prefs.SetString(prefs::kVariationsCompressedSeed, base64_seed_data); |
| 366 prefs.SetString(prefs::kVariationsSeedSignature, base64_seed_data); | |
| 367 VariationsSeedStore seed_store(&prefs); | |
| 368 | |
| 369 base::HistogramTester histogram_tester; | |
| 370 VariationsSeed seed; | |
| 371 EXPECT_FALSE(seed_store.LoadSeed(&seed)); | |
| 372 histogram_tester.ExpectUniqueSample( | |
| 373 "Variations.LoadSeedSignature", | |
| 374 static_cast<base::HistogramBase::Sample>( | |
| 375 VerifySignatureResult::INVALID_SEED), | |
| 376 1); | |
| 377 } | |
| 322 | 378 |
| 323 // Using a different seed should not match the signature. | 379 // Using a different seed should not match the signature. |
| 324 seed_data[0] = 'x'; | 380 { |
| 325 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SEED, | 381 VariationsSeed wrong_seed; |
| 326 seed_store.VerifySeedSignature(seed_data, base64_seed_signature)); | 382 ASSERT_TRUE(wrong_seed.ParseFromString(seed_data)); |
| 383 (*wrong_seed.mutable_study(0)->mutable_name())[0] = 'x'; | |
| 384 std::string base64_wrong_seed_data = SerializeSeedBase64(wrong_seed); | |
| 385 | |
| 386 prefs.SetString(prefs::kVariationsCompressedSeed, base64_wrong_seed_data); | |
| 387 prefs.SetString(prefs::kVariationsSeedSignature, base64_seed_signature); | |
| 388 VariationsSeedStore seed_store(&prefs); | |
| 389 | |
| 390 base::HistogramTester histogram_tester; | |
| 391 VariationsSeed seed; | |
| 392 EXPECT_FALSE(seed_store.LoadSeed(&seed)); | |
| 393 histogram_tester.ExpectUniqueSample( | |
| 394 "Variations.LoadSeedSignature", | |
| 395 static_cast<base::HistogramBase::Sample>( | |
| 396 VerifySignatureResult::INVALID_SEED), | |
| 397 1); | |
| 398 } | |
| 327 } | 399 } |
| 328 | 400 |
| 329 TEST(VariationsSeedStoreTest, ApplyDeltaPatch) { | 401 TEST(VariationsSeedStoreTest, ApplyDeltaPatch) { |
| 330 // Sample seeds and the server produced delta between them to verify that the | 402 // Sample seeds and the server produced delta between them to verify that the |
| 331 // client code is able to decode the deltas produced by the server. | 403 // client code is able to decode the deltas produced by the server. |
| 332 const std::string base64_before_seed_data = | 404 const std::string base64_before_seed_data = |
| 333 "CigxN2E4ZGJiOTI4ODI0ZGU3ZDU2MGUyODRlODY1ZDllYzg2NzU1MTE0ElgKDFVNQVN0YWJp" | 405 "CigxN2E4ZGJiOTI4ODI0ZGU3ZDU2MGUyODRlODY1ZDllYzg2NzU1MTE0ElgKDFVNQVN0YWJp" |
| 334 "bGl0eRjEyomgBTgBQgtTZXBhcmF0ZUxvZ0oLCgdEZWZhdWx0EABKDwoLU2VwYXJhdGVMb2cQ" | 406 "bGl0eRjEyomgBTgBQgtTZXBhcmF0ZUxvZ0oLCgdEZWZhdWx0EABKDwoLU2VwYXJhdGVMb2cQ" |
| 335 "ZFIVEgszNC4wLjE4MDEuMCAAIAEgAiADEkQKIFVNQS1Vbmlmb3JtaXR5LVRyaWFsLTEwMC1Q" | 407 "ZFIVEgszNC4wLjE4MDEuMCAAIAEgAiADEkQKIFVNQS1Vbmlmb3JtaXR5LVRyaWFsLTEwMC1Q" |
| 336 "ZXJjZW50GIDjhcAFOAFCCGdyb3VwXzAxSgwKCGdyb3VwXzAxEAFgARJPCh9VTUEtVW5pZm9y" | 408 "ZXJjZW50GIDjhcAFOAFCCGdyb3VwXzAxSgwKCGdyb3VwXzAxEAFgARJPCh9VTUEtVW5pZm9y" |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 394 &response_date, &is_gzip_compressed); | 466 &response_date, &is_gzip_compressed); |
| 395 EXPECT_EQ("", seed_data); | 467 EXPECT_EQ("", seed_data); |
| 396 EXPECT_EQ("", seed_signature); | 468 EXPECT_EQ("", seed_signature); |
| 397 EXPECT_EQ("", seed_country); | 469 EXPECT_EQ("", seed_country); |
| 398 EXPECT_EQ("", response_date); | 470 EXPECT_EQ("", response_date); |
| 399 EXPECT_FALSE(is_gzip_compressed); | 471 EXPECT_FALSE(is_gzip_compressed); |
| 400 } | 472 } |
| 401 #endif // OS_ANDROID | 473 #endif // OS_ANDROID |
| 402 | 474 |
| 403 } // namespace variations | 475 } // namespace variations |
| OLD | NEW |