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 "chrome/browser/metrics/variations/variations_seed_store.h" | 5 #include "chrome/browser/metrics/variations/variations_seed_store.h" |
6 | 6 |
7 #include "base/base64.h" | 7 #include "base/base64.h" |
8 #include "base/prefs/testing_pref_service.h" | 8 #include "base/prefs/testing_pref_service.h" |
9 #include "base/sha1.h" | 9 #include "base/sha1.h" |
10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
12 #include "chrome/common/pref_names.h" | 12 #include "chrome/common/pref_names.h" |
13 #include "components/variations/proto/study.pb.h" | 13 #include "components/variations/proto/study.pb.h" |
14 #include "components/variations/proto/variations_seed.pb.h" | 14 #include "components/variations/proto/variations_seed.pb.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
16 | 16 |
17 namespace chrome_variations { | 17 namespace chrome_variations { |
18 | 18 |
19 namespace { | 19 namespace { |
20 | 20 |
| 21 class TestVariationsSeedStore : public VariationsSeedStore { |
| 22 public: |
| 23 explicit TestVariationsSeedStore(PrefService* local_state) |
| 24 : VariationsSeedStore(local_state) {} |
| 25 virtual ~TestVariationsSeedStore() {} |
| 26 |
| 27 virtual VariationsSeedStore::VerifySignatureResult VerifySeedSignature( |
| 28 const std::string& seed_bytes, |
| 29 const std::string& base64_seed_signature) OVERRIDE { |
| 30 return VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_ENUM_SIZE; |
| 31 } |
| 32 |
| 33 private: |
| 34 DISALLOW_COPY_AND_ASSIGN(TestVariationsSeedStore); |
| 35 }; |
| 36 |
| 37 |
21 // Populates |seed| with simple test data. The resulting seed will contain one | 38 // Populates |seed| with simple test data. The resulting seed will contain one |
22 // study called "test", which contains one experiment called "abc" with | 39 // study called "test", which contains one experiment called "abc" with |
23 // probability weight 100. |seed|'s study field will be cleared before adding | 40 // probability weight 100. |seed|'s study field will be cleared before adding |
24 // the new study. | 41 // the new study. |
25 VariationsSeed CreateTestSeed() { | 42 VariationsSeed CreateTestSeed() { |
26 VariationsSeed seed; | 43 VariationsSeed seed; |
27 Study* study = seed.add_study(); | 44 Study* study = seed.add_study(); |
28 study->set_name("test"); | 45 study->set_name("test"); |
29 study->set_default_experiment_name("abc"); | 46 study->set_default_experiment_name("abc"); |
30 Study_Experiment* experiment = study->add_experiment(); | 47 Study_Experiment* experiment = study->add_experiment(); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 TEST(VariationsSeedStoreTest, LoadSeed) { | 82 TEST(VariationsSeedStoreTest, LoadSeed) { |
66 // Store good seed data to test if loading from prefs works. | 83 // Store good seed data to test if loading from prefs works. |
67 const VariationsSeed seed = CreateTestSeed(); | 84 const VariationsSeed seed = CreateTestSeed(); |
68 std::string seed_hash; | 85 std::string seed_hash; |
69 const std::string base64_seed = SerializeSeedBase64(seed, &seed_hash); | 86 const std::string base64_seed = SerializeSeedBase64(seed, &seed_hash); |
70 | 87 |
71 TestingPrefServiceSimple prefs; | 88 TestingPrefServiceSimple prefs; |
72 VariationsSeedStore::RegisterPrefs(prefs.registry()); | 89 VariationsSeedStore::RegisterPrefs(prefs.registry()); |
73 prefs.SetString(prefs::kVariationsSeed, base64_seed); | 90 prefs.SetString(prefs::kVariationsSeed, base64_seed); |
74 | 91 |
75 VariationsSeedStore seed_store(&prefs); | 92 TestVariationsSeedStore seed_store(&prefs); |
76 | 93 |
77 VariationsSeed loaded_seed; | 94 VariationsSeed loaded_seed; |
78 // Check that loading a seed without a hash pref set works correctly. | 95 // Check that loading a seed without a hash pref set works correctly. |
79 EXPECT_TRUE(seed_store.LoadSeed(&loaded_seed)); | 96 EXPECT_TRUE(seed_store.LoadSeed(&loaded_seed)); |
80 | 97 |
81 // Check that the loaded data is the same as the original. | 98 // Check that the loaded data is the same as the original. |
82 EXPECT_EQ(SerializeSeed(seed), SerializeSeed(loaded_seed)); | 99 EXPECT_EQ(SerializeSeed(seed), SerializeSeed(loaded_seed)); |
83 // Make sure the pref hasn't been changed. | 100 // Make sure the pref hasn't been changed. |
84 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); | 101 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); |
85 EXPECT_EQ(base64_seed, prefs.GetString(prefs::kVariationsSeed)); | 102 EXPECT_EQ(base64_seed, prefs.GetString(prefs::kVariationsSeed)); |
86 | 103 |
87 // Check that loading a seed with the correct hash works. | 104 // Check that loading a seed with the correct hash works. |
88 prefs.SetString(prefs::kVariationsSeedHash, seed_hash); | 105 prefs.SetString(prefs::kVariationsSeedHash, seed_hash); |
89 loaded_seed.Clear(); | 106 loaded_seed.Clear(); |
90 EXPECT_TRUE(seed_store.LoadSeed(&loaded_seed)); | 107 EXPECT_TRUE(seed_store.LoadSeed(&loaded_seed)); |
91 EXPECT_EQ(SerializeSeed(seed), SerializeSeed(loaded_seed)); | 108 EXPECT_EQ(SerializeSeed(seed), SerializeSeed(loaded_seed)); |
92 | 109 |
93 // Check that false is returned and the pref is cleared when hash differs. | |
94 VariationsSeed different_seed = seed; | |
95 different_seed.mutable_study(0)->set_name("octopus"); | |
96 std::string different_hash; | |
97 prefs.SetString(prefs::kVariationsSeed, | |
98 SerializeSeedBase64(different_seed, &different_hash)); | |
99 ASSERT_NE(different_hash, prefs.GetString(prefs::kVariationsSeedHash)); | |
100 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); | |
101 EXPECT_FALSE(seed_store.LoadSeed(&loaded_seed)); | |
102 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); | |
103 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedDate)); | |
104 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedHash)); | |
105 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedSignature)); | |
106 | |
107 // Check that loading a bad seed returns false and clears the pref. | 110 // Check that loading a bad seed returns false and clears the pref. |
108 prefs.ClearPref(prefs::kVariationsSeed); | 111 prefs.ClearPref(prefs::kVariationsSeed); |
109 prefs.SetString(prefs::kVariationsSeed, "this should fail"); | 112 prefs.SetString(prefs::kVariationsSeed, "this should fail"); |
110 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); | 113 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); |
111 EXPECT_FALSE(seed_store.LoadSeed(&loaded_seed)); | 114 EXPECT_FALSE(seed_store.LoadSeed(&loaded_seed)); |
112 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); | 115 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); |
113 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedDate)); | 116 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedDate)); |
114 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedHash)); | |
115 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedSignature)); | 117 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedSignature)); |
116 | 118 |
117 // Check that having no seed in prefs results in a return value of false. | 119 // Check that having no seed in prefs results in a return value of false. |
118 prefs.ClearPref(prefs::kVariationsSeed); | 120 prefs.ClearPref(prefs::kVariationsSeed); |
119 EXPECT_FALSE(seed_store.LoadSeed(&loaded_seed)); | 121 EXPECT_FALSE(seed_store.LoadSeed(&loaded_seed)); |
120 } | 122 } |
121 | 123 |
122 TEST(VariationsSeedStoreTest, StoreSeedData) { | 124 TEST(VariationsSeedStoreTest, StoreSeedData) { |
123 const base::Time now = base::Time::Now(); | 125 const base::Time now = base::Time::Now(); |
124 const VariationsSeed seed = CreateTestSeed(); | 126 const VariationsSeed seed = CreateTestSeed(); |
125 const std::string serialized_seed = SerializeSeed(seed); | 127 const std::string serialized_seed = SerializeSeed(seed); |
126 | 128 |
127 TestingPrefServiceSimple prefs; | 129 TestingPrefServiceSimple prefs; |
128 VariationsSeedStore::RegisterPrefs(prefs.registry()); | 130 VariationsSeedStore::RegisterPrefs(prefs.registry()); |
129 | 131 |
130 VariationsSeedStore seed_store(&prefs); | 132 TestVariationsSeedStore seed_store(&prefs); |
131 | 133 |
132 EXPECT_TRUE(seed_store.StoreSeedData(serialized_seed, std::string(), now)); | 134 EXPECT_TRUE(seed_store.StoreSeedData(serialized_seed, std::string(), now)); |
133 // Make sure the pref was actually set. | 135 // Make sure the pref was actually set. |
134 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); | 136 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); |
135 | 137 |
136 std::string loaded_serialized_seed = prefs.GetString(prefs::kVariationsSeed); | 138 std::string loaded_serialized_seed = prefs.GetString(prefs::kVariationsSeed); |
137 std::string decoded_serialized_seed; | 139 std::string decoded_serialized_seed; |
138 ASSERT_TRUE(base::Base64Decode(loaded_serialized_seed, | 140 ASSERT_TRUE(base::Base64Decode(loaded_serialized_seed, |
139 &decoded_serialized_seed)); | 141 &decoded_serialized_seed)); |
140 // Make sure the stored seed from pref is the same as the seed we created. | 142 // Make sure the stored seed from pref is the same as the seed we created. |
141 EXPECT_EQ(serialized_seed, decoded_serialized_seed); | 143 EXPECT_EQ(serialized_seed, decoded_serialized_seed); |
142 | 144 |
143 // Check if trying to store a bad seed leaves the pref unchanged. | 145 // Check if trying to store a bad seed leaves the pref unchanged. |
144 prefs.ClearPref(prefs::kVariationsSeed); | 146 prefs.ClearPref(prefs::kVariationsSeed); |
145 EXPECT_FALSE(seed_store.StoreSeedData("should fail", std::string(), now)); | 147 EXPECT_FALSE(seed_store.StoreSeedData("should fail", std::string(), now)); |
146 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); | 148 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeed)); |
147 } | 149 } |
148 | 150 |
| 151 TEST(VariationsSeedStoreTest, VerifySeedSignature) { |
| 152 // The below seed and signature pair were generated using the server's |
| 153 // private key. |
| 154 const std::string base64_seed_data = |
| 155 "CigxZDI5NDY0ZmIzZDc4ZmYxNTU2ZTViNTUxYzY0NDdjYmM3NGU1ZmQwEr0BCh9VTUEtVW5p" |
| 156 "Zm9ybWl0eS1UcmlhbC0xMC1QZXJjZW50GICckqUFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBAB" |
| 157 "SgwKCGdyb3VwXzAxEAFKDAoIZ3JvdXBfMDIQAUoMCghncm91cF8wMxABSgwKCGdyb3VwXzA0" |
| 158 "EAFKDAoIZ3JvdXBfMDUQAUoMCghncm91cF8wNhABSgwKCGdyb3VwXzA3EAFKDAoIZ3JvdXBf" |
| 159 "MDgQAUoMCghncm91cF8wORAB"; |
| 160 const std::string base64_seed_signature = |
| 161 "MEQCIDD1IVxjzWYncun+9IGzqYjZvqxxujQEayJULTlbTGA/AiAr0oVmEgVUQZBYq5VLOSvy" |
| 162 "96JkMYgzTkHPwbv7K/CmgA=="; |
| 163 |
| 164 std::string seed_data; |
| 165 EXPECT_TRUE(base::Base64Decode(base64_seed_data, &seed_data)); |
| 166 |
| 167 VariationsSeedStore seed_store(NULL); |
| 168 |
| 169 #if defined(OS_IOS) || defined(OS_ANDROID) |
| 170 // Signature verification is not enabled on mobile. |
| 171 if (seed_store.VerifySeedSignature(seed_data, base64_seed_signature) == |
| 172 VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_ENUM_SIZE) { |
| 173 return; |
| 174 } |
| 175 #endif |
| 176 |
| 177 // The above inputs should be valid. |
| 178 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_VALID, |
| 179 seed_store.VerifySeedSignature(seed_data, base64_seed_signature)); |
| 180 |
| 181 // If there's no signature, the corresponding result should be returned. |
| 182 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_MISSING, |
| 183 seed_store.VerifySeedSignature(seed_data, std::string())); |
| 184 |
| 185 // Using non-base64 encoded value as signature (e.g. seed data) should fail. |
| 186 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_DECODE_FAILED, |
| 187 seed_store.VerifySeedSignature(seed_data, seed_data)); |
| 188 |
| 189 // Using a different signature (e.g. the base64 seed data) should fail. |
| 190 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SIGNATURE, |
| 191 seed_store.VerifySeedSignature(seed_data, base64_seed_data)); |
| 192 |
| 193 // Using a different seed should not match the signature. |
| 194 seed_data[0] = 'x'; |
| 195 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SEED, |
| 196 seed_store.VerifySeedSignature(seed_data, base64_seed_signature)); |
| 197 } |
| 198 |
149 } // namespace chrome_variations | 199 } // namespace chrome_variations |
OLD | NEW |