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

Unified Diff: chrome/browser/metrics/variations/variations_seed_store.cc

Issue 183003008: Enforce variations signature verification. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 6 years, 10 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 side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698