Index: chrome/browser/metrics/variations/variations_seed_store.cc |
=================================================================== |
--- chrome/browser/metrics/variations/variations_seed_store.cc (revision 254843) |
+++ chrome/browser/metrics/variations/variations_seed_store.cc (working copy) |
@@ -18,13 +18,6 @@ |
namespace { |
-// Computes a hash of the serialized variations seed data. |
-// TODO(asvitkine): Remove this once the seed signature is ubiquitous. |
-std::string HashSeed(const std::string& seed_data) { |
- const std::string sha1 = base::SHA1HashString(seed_data); |
- return base::HexEncode(sha1.data(), sha1.size()); |
-} |
- |
// Signature verification is disabled on mobile platforms for now, since it |
// adds about ~15ms to the startup time on mobile (vs. a couple ms on desktop). |
bool SignatureVerificationEnabled() { |
@@ -66,49 +59,11 @@ |
}; |
// Note: UMA histogram enum - don't re-order or remove entries. |
-enum VariationSeedSignatureState { |
- VARIATIONS_SEED_SIGNATURE_MISSING, |
- VARIATIONS_SEED_SIGNATURE_DECODE_FAILED, |
- VARIATIONS_SEED_SIGNATURE_INVALID_SIGNATURE, |
- VARIATIONS_SEED_SIGNATURE_INVALID_SEED, |
- VARIATIONS_SEED_SIGNATURE_VALID, |
- VARIATIONS_SEED_SIGNATURE_ENUM_SIZE, |
-}; |
- |
-// Verifies a variations seed (the serialized proto bytes) with the specified |
-// base-64 encoded signate that was received from the server and returns the |
-// result. The signature is assumed to be an "ECDSA with SHA-256" signature |
-// (see kECDSAWithSHA256AlgorithmID above). |
-VariationSeedSignatureState VerifySeedSignature( |
- const std::string& seed_bytes, |
- const std::string& base64_seed_signature) { |
- if (base64_seed_signature.empty()) |
- return VARIATIONS_SEED_SIGNATURE_MISSING; |
- |
- std::string signature; |
- if (!base::Base64Decode(base64_seed_signature, &signature)) |
- return VARIATIONS_SEED_SIGNATURE_DECODE_FAILED; |
- |
- crypto::SignatureVerifier verifier; |
- if (!verifier.VerifyInit( |
- kECDSAWithSHA256AlgorithmID, sizeof(kECDSAWithSHA256AlgorithmID), |
- reinterpret_cast<const uint8*>(signature.data()), signature.size(), |
- kPublicKey, arraysize(kPublicKey))) { |
- return VARIATIONS_SEED_SIGNATURE_INVALID_SIGNATURE; |
- } |
- |
- verifier.VerifyUpdate(reinterpret_cast<const uint8*>(seed_bytes.data()), |
- seed_bytes.size()); |
- if (verifier.VerifyFinal()) |
- return VARIATIONS_SEED_SIGNATURE_VALID; |
- return VARIATIONS_SEED_SIGNATURE_INVALID_SEED; |
-} |
- |
-// Note: UMA histogram enum - don't re-order or remove entries. |
enum VariationSeedEmptyState { |
VARIATIONS_SEED_NOT_EMPTY, |
VARIATIONS_SEED_EMPTY, |
VARIATIONS_SEED_CORRUPT, |
+ VARIATIONS_SEED_INVALID_SIGNATURE, |
VARIATIONS_SEED_EMPTY_ENUM_SIZE, |
}; |
@@ -134,12 +89,9 @@ |
return false; |
} |
- const std::string hash_from_pref = |
- local_state_->GetString(prefs::kVariationsSeedHash); |
// If the decode process fails, assume the pref value is corrupt and clear it. |
std::string seed_data; |
if (!base::Base64Decode(base64_seed_data, &seed_data) || |
- (!hash_from_pref.empty() && HashSeed(seed_data) != hash_from_pref) || |
!seed->ParseFromString(seed_data)) { |
VLOG(1) << "Variations seed data in local pref is corrupt, clearing the " |
<< "pref."; |
@@ -148,13 +100,20 @@ |
return false; |
} |
- if (SignatureVerificationEnabled()) { |
- const std::string base64_seed_signature = |
- local_state_->GetString(prefs::kVariationsSeedSignature); |
- const VariationSeedSignatureState signature_state = |
- VerifySeedSignature(seed_data, base64_seed_signature); |
- UMA_HISTOGRAM_ENUMERATION("Variations.LoadSeedSignature", signature_state, |
+ const std::string base64_seed_signature = |
+ local_state_->GetString(prefs::kVariationsSeedSignature); |
+ const VerifySignatureResult result = |
+ VerifySeedSignature(seed_data, base64_seed_signature); |
+ if (result != VARIATIONS_SEED_SIGNATURE_ENUM_SIZE) { |
+ UMA_HISTOGRAM_ENUMERATION("Variations.LoadSeedSignature", result, |
VARIATIONS_SEED_SIGNATURE_ENUM_SIZE); |
+ if (result != VARIATIONS_SEED_SIGNATURE_VALID) { |
+ VLOG(1) << "Variations seed signature in local pref missing or invalid " |
jwd
2014/03/05 17:56:27
Do these need to be VLOGs?
Alexei Svitkine (slow)
2014/03/05 18:21:43
I've followed the convention that's used in this f
jwd
2014/03/05 18:36:00
Ah, didn't notice the convention. I was thinking D
|
+ << "with result: " << result << ". Clearing the pref."; |
+ ClearPrefs(); |
+ RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_INVALID_SIGNATURE); |
+ return false; |
+ } |
} |
variations_serial_number_ = seed->serial_number(); |
@@ -179,18 +138,26 @@ |
return false; |
} |
- if (SignatureVerificationEnabled()) { |
- const VariationSeedSignatureState signature_state = |
- VerifySeedSignature(seed_data, base64_seed_signature); |
- UMA_HISTOGRAM_ENUMERATION("Variations.StoreSeedSignature", signature_state, |
+ const VerifySignatureResult result = |
+ VerifySeedSignature(seed_data, base64_seed_signature); |
+ if (result != VARIATIONS_SEED_SIGNATURE_ENUM_SIZE) { |
+ UMA_HISTOGRAM_ENUMERATION("Variations.StoreSeedSignature", result, |
VARIATIONS_SEED_SIGNATURE_ENUM_SIZE); |
+ if (result != VARIATIONS_SEED_SIGNATURE_VALID) { |
+ VLOG(1) << "Variations seed signature missing or invalid with result: " |
+ << result << ". Rejecting the seed."; |
+ return false; |
+ } |
} |
std::string base64_seed_data; |
base::Base64Encode(seed_data, &base64_seed_data); |
+ // TODO(asvitkine): This pref is no longer being used. Remove it completely |
+ // in a couple of releases. |
+ local_state_->ClearPref(prefs::kVariationsSeedHash); |
+ |
local_state_->SetString(prefs::kVariationsSeed, base64_seed_data); |
- local_state_->SetString(prefs::kVariationsSeedHash, HashSeed(seed_data)); |
local_state_->SetInt64(prefs::kVariationsSeedDate, |
date_fetched.ToInternalValue()); |
local_state_->SetString(prefs::kVariationsSeedSignature, |
@@ -216,4 +183,33 @@ |
local_state_->ClearPref(prefs::kVariationsSeedSignature); |
} |
+VariationsSeedStore::VerifySignatureResult |
+VariationsSeedStore::VerifySeedSignature( |
jwd
2014/03/05 17:56:27
Can this be tested? What about having a testing ke
Alexei Svitkine (slow)
2014/03/05 18:21:43
A testing key pair would require passing the publi
jwd
2014/03/05 18:36:00
Base-64 blob seems fine then.
Alexei Svitkine (slow)
2014/03/06 18:16:07
Done. Added checking for all the possible return v
|
+ const std::string& seed_bytes, |
+ const std::string& base64_seed_signature) { |
+ if (!SignatureVerificationEnabled()) |
+ return VARIATIONS_SEED_SIGNATURE_ENUM_SIZE; |
+ |
+ if (base64_seed_signature.empty()) |
+ return VARIATIONS_SEED_SIGNATURE_MISSING; |
+ |
+ std::string signature; |
+ if (!base::Base64Decode(base64_seed_signature, &signature)) |
+ return VARIATIONS_SEED_SIGNATURE_DECODE_FAILED; |
+ |
+ crypto::SignatureVerifier verifier; |
+ if (!verifier.VerifyInit( |
+ kECDSAWithSHA256AlgorithmID, sizeof(kECDSAWithSHA256AlgorithmID), |
+ reinterpret_cast<const uint8*>(signature.data()), signature.size(), |
+ kPublicKey, arraysize(kPublicKey))) { |
+ return VARIATIONS_SEED_SIGNATURE_INVALID_SIGNATURE; |
+ } |
+ |
+ verifier.VerifyUpdate(reinterpret_cast<const uint8*>(seed_bytes.data()), |
+ seed_bytes.size()); |
+ if (verifier.VerifyFinal()) |
+ return VARIATIONS_SEED_SIGNATURE_VALID; |
+ return VARIATIONS_SEED_SIGNATURE_INVALID_SEED; |
+} |
+ |
} // namespace chrome_variations |