variations_seed_store.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/metrics/variations/variations_seed_store.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/base64.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_registry_simple.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_service.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/sha1.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/pref_names.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/variations/proto/variations_seed.pb.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "crypto/signature_verifier.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace chrome_variations {
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Computes a hash of the serialized variations seed data.
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// TODO(asvitkine): Remove this once the seed signature is ubiquitous.
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string HashSeed(const std::string& seed_data) {
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string sha1 = base::SHA1HashString(seed_data);
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::HexEncode(sha1.data(), sha1.size());
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Signature verification is disabled on mobile platforms for now, since it
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// adds about ~15ms to the startup time on mobile (vs. a couple ms on desktop).
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool SignatureVerificationEnabled() {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_IOS) || defined(OS_ANDROID)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This is the algorithm ID for ECDSA with SHA-256. Parameters are ABSENT.
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// RFC 5758:
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//   ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//        us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//   ...
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//   When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//   ecdsa-with-SHA512 algorithm identifier appears in the algorithm field
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//   as an AlgorithmIdentifier, the encoding MUST omit the parameters
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//   field.  That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//   component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//   SHA384, or ecdsa-with-SHA512.
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// See also RFC 5480, Appendix A.
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const uint8 kECDSAWithSHA256AlgorithmID[] = {
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x30, 0x0a,
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    0x06, 0x08,
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The ECDSA public key of the variations server for verifying variations seed
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// signatures.
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const uint8_t kPublicKey[] = {
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x04, 0x51, 0x7c, 0x31, 0x4b, 0x50, 0x42, 0xdd, 0x59, 0xda, 0x0b, 0xfa, 0x43,
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x44, 0x33, 0x7c, 0x5f, 0xa1, 0x0b, 0xd5, 0x82, 0xf6, 0xac, 0x04, 0x19, 0x72,
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x6c, 0x40, 0xd4, 0x3e, 0x56, 0xe2, 0xa0, 0x80, 0xa0, 0x41, 0xb3, 0x23, 0x7b,
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x71, 0xc9, 0x80, 0x87, 0xde, 0x35, 0x0d, 0x25, 0x71, 0x09, 0x7f, 0xb4, 0x15,
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x2b, 0xff, 0x82, 0x4d, 0xd3, 0xfe, 0xc5, 0xef, 0x20, 0xc6, 0xa3, 0x10, 0xbf,
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Note: UMA histogram enum - don't re-order or remove entries.
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum VariationSeedSignatureState {
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VARIATIONS_SEED_SIGNATURE_MISSING,
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VARIATIONS_SEED_SIGNATURE_DECODE_FAILED,
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VARIATIONS_SEED_SIGNATURE_INVALID_SIGNATURE,
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VARIATIONS_SEED_SIGNATURE_INVALID_SEED,
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VARIATIONS_SEED_SIGNATURE_VALID,
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VARIATIONS_SEED_SIGNATURE_ENUM_SIZE,
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Verifies a variations seed (the serialized proto bytes) with the specified
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// base-64 encoded signate that was received from the server and returns the
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// result. The signature is assumed to be an "ECDSA with SHA-256" signature
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// (see kECDSAWithSHA256AlgorithmID above).
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VariationSeedSignatureState VerifySeedSignature(
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& seed_bytes,
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& base64_seed_signature) {
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (base64_seed_signature.empty())
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return VARIATIONS_SEED_SIGNATURE_MISSING;
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string signature;
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::Base64Decode(base64_seed_signature, &signature))
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return VARIATIONS_SEED_SIGNATURE_DECODE_FAILED;
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  crypto::SignatureVerifier verifier;
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!verifier.VerifyInit(
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kECDSAWithSHA256AlgorithmID, sizeof(kECDSAWithSHA256AlgorithmID),
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          reinterpret_cast<const uint8*>(signature.data()), signature.size(),
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kPublicKey, arraysize(kPublicKey))) {
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return VARIATIONS_SEED_SIGNATURE_INVALID_SIGNATURE;
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  verifier.VerifyUpdate(reinterpret_cast<const uint8*>(seed_bytes.data()),
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        seed_bytes.size());
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (verifier.VerifyFinal())
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return VARIATIONS_SEED_SIGNATURE_VALID;
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return VARIATIONS_SEED_SIGNATURE_INVALID_SEED;
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Note: UMA histogram enum - don't re-order or remove entries.
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum VariationSeedEmptyState {
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VARIATIONS_SEED_NOT_EMPTY,
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VARIATIONS_SEED_EMPTY,
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VARIATIONS_SEED_CORRUPT,
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VARIATIONS_SEED_EMPTY_ENUM_SIZE,
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RecordVariationSeedEmptyHistogram(VariationSeedEmptyState state) {
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Variations.SeedEmpty", state,
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            VARIATIONS_SEED_EMPTY_ENUM_SIZE);
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VariationsSeedStore::VariationsSeedStore(PrefService* local_state)
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : local_state_(local_state) {
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VariationsSeedStore::~VariationsSeedStore() {
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool VariationsSeedStore::LoadSeed(VariationsSeed* seed) {
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string base64_seed_data =
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      local_state_->GetString(prefs::kVariationsSeed);
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (base64_seed_data.empty()) {
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_EMPTY);
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string hash_from_pref =
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      local_state_->GetString(prefs::kVariationsSeedHash);
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If the decode process fails, assume the pref value is corrupt and clear it.
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string seed_data;
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::Base64Decode(base64_seed_data, &seed_data) ||
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (!hash_from_pref.empty() && HashSeed(seed_data) != hash_from_pref) ||
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !seed->ParseFromString(seed_data)) {
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "Variations seed data in local pref is corrupt, clearing the "
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            << "pref.";
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ClearPrefs();
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_CORRUPT);
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (SignatureVerificationEnabled()) {
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string base64_seed_signature =
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        local_state_->GetString(prefs::kVariationsSeedSignature);
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const VariationSeedSignatureState signature_state =
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        VerifySeedSignature(seed_data, base64_seed_signature);
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Variations.LoadSeedSignature", signature_state,
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              VARIATIONS_SEED_SIGNATURE_ENUM_SIZE);
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  variations_serial_number_ = seed->serial_number();
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_NOT_EMPTY);
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool VariationsSeedStore::StoreSeedData(
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& seed_data,
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& base64_seed_signature,
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Time& date_fetched) {
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (seed_data.empty()) {
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "Variations seed data is empty, rejecting the seed.";
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Only store the seed data if it parses correctly.
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VariationsSeed seed;
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!seed.ParseFromString(seed_data)) {
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "Variations seed data is not in valid proto format, "
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            << "rejecting the seed.";
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (SignatureVerificationEnabled()) {
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const VariationSeedSignatureState signature_state =
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        VerifySeedSignature(seed_data, base64_seed_signature);
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Variations.StoreSeedSignature", signature_state,
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              VARIATIONS_SEED_SIGNATURE_ENUM_SIZE);
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string base64_seed_data;
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::Base64Encode(seed_data, &base64_seed_data);
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_state_->SetString(prefs::kVariationsSeed, base64_seed_data);
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_state_->SetString(prefs::kVariationsSeedHash, HashSeed(seed_data));
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_state_->SetInt64(prefs::kVariationsSeedDate,
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         date_fetched.ToInternalValue());
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_state_->SetString(prefs::kVariationsSeedSignature,
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          base64_seed_signature);
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  variations_serial_number_ = seed.serial_number();
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void VariationsSeedStore::RegisterPrefs(PrefRegistrySimple* registry) {
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry->RegisterStringPref(prefs::kVariationsSeed, std::string());
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry->RegisterStringPref(prefs::kVariationsSeedHash, std::string());
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry->RegisterInt64Pref(prefs::kVariationsSeedDate,
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              base::Time().ToInternalValue());
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry->RegisterStringPref(prefs::kVariationsSeedSignature, std::string());
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void VariationsSeedStore::ClearPrefs() {
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_state_->ClearPref(prefs::kVariationsSeed);
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_state_->ClearPref(prefs::kVariationsSeedDate);
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_state_->ClearPref(prefs::kVariationsSeedHash);
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_state_->ClearPref(prefs::kVariationsSeedSignature);
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace chrome_variations
220