1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file.
4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/extensions/install_verifier.h"
6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <algorithm>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/bind.h"
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/command_line.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/field_trial.h"
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/metrics/histogram.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/prefs/pref_service.h"
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/stl_util.h"
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/extensions/extension_management.h"
17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/extension_service.h"
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/extensions/install_signer.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/common/extensions/manifest_url_handler.h"
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/common/pref_names.h"
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/grit/generated_resources.h"
23effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/browser_context.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/common/content_switches.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
26effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/browser/extension_registry.h"
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/browser/extension_system.h"
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/pref_names.h"
29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/common/extension_set.h"
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/manifest.h"
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/common/one_shot_event.h"
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace extensions {
35effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace {
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)enum VerifyStatus {
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NONE = 0,   // Do not request install signatures, and do not enforce them.
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BOOTSTRAP,  // Request install signatures, but do not enforce them.
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ENFORCE,    // Request install signatures, and enforce them.
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ENFORCE_STRICT,  // Same as ENFORCE, but hard fail if we can't fetch
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   // signatures.
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This is used in histograms - do not remove or reorder entries above! Also
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the "MAX" item below should always be the last element.
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VERIFY_STATUS_MAX
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)};
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(GOOGLE_CHROME_BUILD)
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kExperimentName[] = "ExtensionInstallVerification";
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif  // defined(GOOGLE_CHROME_BUILD)
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VerifyStatus GetExperimentStatus() {
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(GOOGLE_CHROME_BUILD)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string group = base::FieldTrialList::FindFullName(
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      kExperimentName);
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string forced_trials = CommandLine::ForCurrentProcess()->
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetSwitchValueASCII(switches::kForceFieldTrials);
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (forced_trials.find(kExperimentName) != std::string::npos) {
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // We don't want to allow turning off enforcement by forcing the field
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // trial group to something other than enforcement.
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return ENFORCE_STRICT;
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VerifyStatus default_status = NONE;
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (group == "EnforceStrict")
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return ENFORCE_STRICT;
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  else if (group == "Enforce")
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return ENFORCE;
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else if (group == "Bootstrap")
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return BOOTSTRAP;
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else if (group == "None" || group == "Control")
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NONE;
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return default_status;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif  // defined(GOOGLE_CHROME_BUILD)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return NONE;
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VerifyStatus GetCommandLineStatus() {
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const CommandLine* cmdline = CommandLine::ForCurrentProcess();
86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!InstallSigner::GetForcedNotFromWebstore().empty())
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return ENFORCE;
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (cmdline->HasSwitch(switches::kExtensionsInstallVerification)) {
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string value = cmdline->GetSwitchValueASCII(
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        switches::kExtensionsInstallVerification);
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (value == "bootstrap")
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return BOOTSTRAP;
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    else if (value == "enforce_strict")
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ENFORCE_STRICT;
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    else
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return ENFORCE;
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return NONE;
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VerifyStatus GetStatus() {
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return std::max(GetExperimentStatus(), GetCommandLineStatus());
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ShouldFetchSignature() {
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return GetStatus() >= BOOTSTRAP;
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ShouldEnforce() {
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return GetStatus() >= ENFORCE;
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum InitResult {
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  INIT_NO_PREF = 0,
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  INIT_UNPARSEABLE_PREF,
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  INIT_INVALID_SIGNATURE,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  INIT_VALID_SIGNATURE,
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This is used in histograms - do not remove or reorder entries above! Also
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the "MAX" item below should always be the last element.
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  INIT_RESULT_MAX
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void LogInitResultHistogram(InitResult result) {
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.InitResult",
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            result, INIT_RESULT_MAX);
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool CanUseExtensionApis(const Extension& extension) {
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return extension.is_extension() || extension.is_legacy_packaged_app();
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochenum VerifyAllSuccess {
137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VERIFY_ALL_BOOTSTRAP_SUCCESS = 0,
138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VERIFY_ALL_BOOTSTRAP_FAILURE,
139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VERIFY_ALL_NON_BOOTSTRAP_SUCCESS,
140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VERIFY_ALL_NON_BOOTSTRAP_FAILURE,
141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Used in histograms. Do not remove/reorder any entries above, and the below
143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // MAX entry should always come last.
144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VERIFY_ALL_SUCCESS_MAX
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch};
146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Record the success or failure of verifying all extensions, and whether or
148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// not it was a bootstrapping.
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid LogVerifyAllSuccessHistogram(bool bootstrap, bool success) {
150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VerifyAllSuccess result;
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (bootstrap && success)
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    result = VERIFY_ALL_BOOTSTRAP_SUCCESS;
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  else if (bootstrap && !success)
154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    result = VERIFY_ALL_BOOTSTRAP_FAILURE;
155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  else if (!bootstrap && success)
156effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    result = VERIFY_ALL_NON_BOOTSTRAP_SUCCESS;
157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  else
158effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    result = VERIFY_ALL_NON_BOOTSTRAP_FAILURE;
159effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
160effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // This used to be part of ExtensionService, but moved here. In order to keep
161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // our histograms accurate, the name is unchanged.
162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  UMA_HISTOGRAM_ENUMERATION(
163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      "ExtensionService.VerifyAllSuccess", result, VERIFY_ALL_SUCCESS_MAX);
164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
166effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Record the success or failure of a single verification.
167effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid LogAddVerifiedSuccess(bool success) {
168effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // This used to be part of ExtensionService, but moved here. In order to keep
169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // our histograms accurate, the name is unchanged.
170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  UMA_HISTOGRAM_BOOLEAN("ExtensionService.AddVerified", success);
171effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
175effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochInstallVerifier::InstallVerifier(ExtensionPrefs* prefs,
176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                 content::BrowserContext* context)
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : prefs_(prefs),
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      context_(context),
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      bootstrap_check_complete_(false),
180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      weak_factory_(this) {
181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
183effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochInstallVerifier::~InstallVerifier() {}
184effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InstallVerifier::NeedsVerification(const Extension& extension) {
1876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return IsFromStore(extension) && CanUseExtensionApis(extension);
1886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// static
1936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool InstallVerifier::IsFromStore(const Extension& extension) {
1946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (extension.from_webstore() || ManifestURL::UpdatesFromGallery(&extension))
1956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return true;
1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If an extension has no update url, our autoupdate code will ask the
1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // webstore about it (to aid in migrating to the webstore from self-hosting
1996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // or sideloading based installs). So we want to do verification checks on
2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // such extensions too so that we don't accidentally disable old installs of
2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // extensions that did migrate to the webstore.
2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return (ManifestURL::GetUpdateURL(&extension).is_empty() &&
2036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          Manifest::IsAutoUpdateableLocation(extension.location()));
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::Init() {
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ExperimentStatus",
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            GetExperimentStatus(), VERIFY_STATUS_MAX);
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ActualStatus",
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            GetStatus(), VERIFY_STATUS_MAX);
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::DictionaryValue* pref = prefs_->GetInstallSignature();
213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (pref) {
214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_ptr<InstallSignature> signature_from_prefs =
215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        InstallSignature::FromValue(*pref);
216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!signature_from_prefs.get()) {
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LogInitResultHistogram(INIT_UNPARSEABLE_PREF);
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else if (!InstallSigner::VerifySignature(*signature_from_prefs.get())) {
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LogInitResultHistogram(INIT_INVALID_SIGNATURE);
220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DVLOG(1) << "Init - ignoring invalid signature";
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else {
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      signature_ = signature_from_prefs.Pass();
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LogInitResultHistogram(INIT_VALID_SIGNATURE);
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      UMA_HISTOGRAM_COUNTS_100("ExtensionInstallVerifier.InitSignatureCount",
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               signature_->ids.size());
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      GarbageCollect();
227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LogInitResultHistogram(INIT_NO_PREF);
230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
231effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
232effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ExtensionSystem::Get(context_)->ready().Post(
233effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
234effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&InstallVerifier::MaybeBootstrapSelf,
235effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 weak_factory_.GetWeakPtr()));
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
238effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InstallVerifier::VerifyAllExtensions() {
239effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  AddMany(GetExtensionsToVerify(), ADD_ALL);
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::Time InstallVerifier::SignatureTimestamp() {
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (signature_.get())
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return signature_->timestamp;
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return base::Time();
247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool InstallVerifier::IsKnownId(const std::string& id) const {
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return signature_.get() && (ContainsKey(signature_->ids, id) ||
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                              ContainsKey(signature_->invalid_ids, id));
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool InstallVerifier::IsInvalid(const std::string& id) const {
2556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return ((signature_.get() && ContainsKey(signature_->invalid_ids, id)));
2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
258effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InstallVerifier::VerifyExtension(const std::string& extension_id) {
259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionIdSet ids;
260effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ids.insert(extension_id);
261effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  AddMany(ids, ADD_SINGLE);
262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
264effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InstallVerifier::AddMany(const ExtensionIdSet& ids, OperationType type) {
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ShouldFetchSignature()) {
266effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    OnVerificationComplete(true, type);  // considered successful.
267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
269f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (signature_.get()) {
271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ExtensionIdSet not_allowed_yet =
272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        base::STLSetDifference<ExtensionIdSet>(ids, signature_->ids);
273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (not_allowed_yet.empty()) {
274effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      OnVerificationComplete(true, type);  // considered successful.
275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return;
276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  InstallVerifier::PendingOperation* operation =
280effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new InstallVerifier::PendingOperation(type);
281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  operation->ids.insert(ids.begin(), ids.end());
282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  operation_queue_.push(linked_ptr<PendingOperation>(operation));
284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // If there are no ongoing pending requests, we need to kick one off.
286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (operation_queue_.size() == 1)
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    BeginFetch();
288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::AddProvisional(const ExtensionIdSet& ids) {
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  provisional_.insert(ids.begin(), ids.end());
292effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  AddMany(ids, ADD_PROVISIONAL);
293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::Remove(const std::string& id) {
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionIdSet ids;
297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ids.insert(id);
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RemoveMany(ids);
299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::RemoveMany(const ExtensionIdSet& ids) {
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!signature_.get() || !ShouldFetchSignature())
303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool found_any = false;
306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i) {
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (ContainsKey(signature_->ids, *i) ||
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        ContainsKey(signature_->invalid_ids, *i)) {
309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      found_any = true;
310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      break;
311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!found_any)
314f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  InstallVerifier::PendingOperation* operation =
317effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new InstallVerifier::PendingOperation(InstallVerifier::REMOVE);
318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  operation->ids = ids;
319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  operation_queue_.push(linked_ptr<PendingOperation>(operation));
321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (operation_queue_.size() == 1)
322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    BeginFetch();
323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool InstallVerifier::AllowedByEnterprisePolicy(const std::string& id) const {
3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return ExtensionManagementFactory::GetForBrowserContext(context_)
3271675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch      ->IsInstallationExplicitlyAllowed(id);
3286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
3296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)std::string InstallVerifier::GetDebugPolicyProviderName() const {
331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return std::string("InstallVerifier");
332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum MustRemainDisabledOutcome {
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VERIFIED = 0,
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOT_EXTENSION,
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UNPACKED,
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ENTERPRISE_POLICY_ALLOWED,
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FORCED_NOT_VERIFIED,
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOT_FROM_STORE,
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NO_SIGNATURE,
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOT_VERIFIED_BUT_NOT_ENFORCING,
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOT_VERIFIED,
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE,
347a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NOT_VERIFIED_BUT_UNKNOWN_ID,
348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  COMPONENT,
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This is used in histograms - do not remove or reorder entries above! Also
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the "MAX" item below should always be the last element.
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MUST_REMAIN_DISABLED_OUTCOME_MAX
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MustRemainDisabledHistogram(MustRemainDisabledOutcome outcome) {
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.MustRemainDisabled",
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            outcome, MUST_REMAIN_DISABLED_OUTCOME_MAX);
358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool InstallVerifier::MustRemainDisabled(const Extension* extension,
363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                         Extension::DisableReason* reason,
364a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                         base::string16* error) const {
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK(extension);
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!CanUseExtensionApis(*extension)) {
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MustRemainDisabledHistogram(NOT_EXTENSION);
368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (Manifest::IsUnpackedLocation(extension->location())) {
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MustRemainDisabledHistogram(UNPACKED);
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (extension->location() == Manifest::COMPONENT) {
375a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    MustRemainDisabledHistogram(COMPONENT);
376a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (AllowedByEnterprisePolicy(extension->id())) {
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MustRemainDisabledHistogram(ENTERPRISE_POLICY_ALLOWED);
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool verified = true;
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MustRemainDisabledOutcome outcome = VERIFIED;
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ContainsKey(InstallSigner::GetForcedNotFromWebstore(), extension->id())) {
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    verified = false;
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    outcome = FORCED_NOT_VERIFIED;
3886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else if (!IsFromStore(*extension)) {
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    verified = false;
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    outcome = NOT_FROM_STORE;
391f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else if (signature_.get() == NULL &&
392f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             (!bootstrap_check_complete_ || GetStatus() < ENFORCE_STRICT)) {
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If we don't have a signature yet, we'll temporarily consider every
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // extension from the webstore verified to avoid false positives on existing
395effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // profiles hitting this code for the first time. The InstallVerifier
396effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // will bootstrap itself once the ExtensionsSystem is ready.
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    outcome = NO_SIGNATURE;
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (!IsVerified(extension->id())) {
399f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (signature_.get() &&
400f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        !ContainsKey(signature_->invalid_ids, extension->id())) {
401a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      outcome = NOT_VERIFIED_BUT_UNKNOWN_ID;
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      verified = false;
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      outcome = NOT_VERIFIED;
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!verified && !ShouldEnforce()) {
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    verified = true;
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    outcome = NOT_VERIFIED_BUT_NOT_ENFORCING;
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MustRemainDisabledHistogram(outcome);
412f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
413f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!verified) {
414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (reason)
415f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      *reason = Extension::DISABLE_NOT_VERIFIED;
416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (error)
417f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      *error = l10n_util::GetStringFUTF16(
418f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE,
419f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE));
420f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
421f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !verified;
422f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
423f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
424effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochInstallVerifier::PendingOperation::PendingOperation(OperationType type)
425effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    : type(type) {}
426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)InstallVerifier::PendingOperation::~PendingOperation() {
428f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
429f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
430effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochExtensionIdSet InstallVerifier::GetExtensionsToVerify() const {
431effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ExtensionIdSet result;
432effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<ExtensionSet> extensions =
433effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      ExtensionRegistry::Get(context_)->GenerateInstalledExtensionsSet();
434effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (ExtensionSet::const_iterator iter = extensions->begin();
435effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       iter != extensions->end();
436effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++iter) {
4371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (NeedsVerification(*iter->get()))
438effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      result.insert((*iter)->id());
439effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
440effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return result;
441effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
442effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
443effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InstallVerifier::MaybeBootstrapSelf() {
444effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  bool needs_bootstrap = false;
445effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
446effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ExtensionIdSet extension_ids = GetExtensionsToVerify();
447effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (signature_.get() == NULL && ShouldFetchSignature()) {
448effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    needs_bootstrap = true;
449effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  } else {
450effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    for (ExtensionIdSet::const_iterator iter = extension_ids.begin();
451effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         iter != extension_ids.end();
452effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         ++iter) {
453effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (!IsKnownId(*iter)) {
454effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        needs_bootstrap = true;
455effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        break;
456effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
457effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
458effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
459effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
460effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (needs_bootstrap)
461effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    AddMany(extension_ids, ADD_ALL_BOOTSTRAP);
462f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  else
463f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    bootstrap_check_complete_ = true;
464effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
465effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
466f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void InstallVerifier::OnVerificationComplete(bool success, OperationType type) {
467effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  switch (type) {
468effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case ADD_SINGLE:
469effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LogAddVerifiedSuccess(success);
470effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      break;
471effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case ADD_ALL:
472effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case ADD_ALL_BOOTSTRAP:
473effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LogVerifyAllSuccessHistogram(type == ADD_ALL_BOOTSTRAP, success);
474f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      bootstrap_check_complete_ = true;
475effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (success) {
476effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // Iterate through the extensions and, if any are newly-verified and
477effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // should have the DISABLE_NOT_VERIFIED reason lifted, do so.
478effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        const ExtensionSet& disabled_extensions =
479effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            ExtensionRegistry::Get(context_)->disabled_extensions();
480effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        for (ExtensionSet::const_iterator iter = disabled_extensions.begin();
481effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch             iter != disabled_extensions.end();
482effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch             ++iter) {
483effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          int disable_reasons = prefs_->GetDisableReasons((*iter)->id());
484effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          if (disable_reasons & Extension::DISABLE_NOT_VERIFIED &&
4851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              !MustRemainDisabled(iter->get(), NULL, NULL)) {
486effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            prefs_->RemoveDisableReason((*iter)->id(),
487effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                        Extension::DISABLE_NOT_VERIFIED);
488effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          }
489effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        }
490f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
491f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (success || GetStatus() == ENFORCE_STRICT) {
492effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        ExtensionSystem::Get(context_)
493effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            ->extension_service()
494effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            ->CheckManagementPolicy();
495effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
496effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      break;
497effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // We don't need to check disable reasons or report UMA stats for
498effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // provisional adds or removals.
499effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case ADD_PROVISIONAL:
500effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case REMOVE:
501effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      break;
502effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
503effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
504effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
505f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::GarbageCollect() {
506f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!ShouldFetchSignature()) {
507f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
508f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
509f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CHECK(signature_.get());
510f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionIdSet leftovers = signature_->ids;
511a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  leftovers.insert(signature_->invalid_ids.begin(),
512a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   signature_->invalid_ids.end());
513f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionIdList all_ids;
514f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  prefs_->GetExtensions(&all_ids);
515f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (ExtensionIdList::const_iterator i = all_ids.begin();
516f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       i != all_ids.end(); ++i) {
517f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ExtensionIdSet::iterator found = leftovers.find(*i);
518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (found != leftovers.end())
519f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      leftovers.erase(found);
520f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
521f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!leftovers.empty()) {
522f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RemoveMany(leftovers);
523f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
524f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
525f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
526f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool InstallVerifier::IsVerified(const std::string& id) const {
527f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return ((signature_.get() && ContainsKey(signature_->ids, id)) ||
528f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          ContainsKey(provisional_, id));
529f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
530f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
531f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::BeginFetch() {
532f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(ShouldFetchSignature());
533f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
534f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // TODO(asargent) - It would be possible to coalesce all operations in the
535f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // queue into one fetch - we'd probably just need to change the queue to
536effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // hold (set of ids, list of operation type) pairs.
537f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CHECK(!operation_queue_.empty());
538f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const PendingOperation& operation = *operation_queue_.front();
539f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
540f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionIdSet ids_to_sign;
541f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (signature_.get()) {
542f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ids_to_sign.insert(signature_->ids.begin(), signature_->ids.end());
543f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
544effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (operation.type == InstallVerifier::REMOVE) {
545f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for (ExtensionIdSet::const_iterator i = operation.ids.begin();
546f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         i != operation.ids.end(); ++i) {
547f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (ContainsKey(ids_to_sign, *i))
548f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        ids_to_sign.erase(*i);
549f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
550effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  } else {  // All other operation types are some form of "ADD".
551effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ids_to_sign.insert(operation.ids.begin(), operation.ids.end());
552f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
553f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
554effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  signer_.reset(new InstallSigner(context_->GetRequestContext(), ids_to_sign));
555f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  signer_->GetSignature(base::Bind(&InstallVerifier::SignatureCallback,
556effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                   weak_factory_.GetWeakPtr()));
557f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
558f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
559f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::SaveToPrefs() {
560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (signature_.get())
561f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK(InstallSigner::VerifySignature(*signature_));
562f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!signature_.get() || signature_->ids.empty()) {
564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "SaveToPrefs - saving NULL";
565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    prefs_->SetInstallSignature(NULL);
566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue pref;
568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    signature_->ToValue(&pref);
569f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (VLOG_IS_ON(1)) {
570f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DVLOG(1) << "SaveToPrefs - saving";
571f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
572f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DCHECK(InstallSigner::VerifySignature(*signature_.get()));
573f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      scoped_ptr<InstallSignature> rehydrated =
574f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          InstallSignature::FromValue(pref);
575f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DCHECK(InstallSigner::VerifySignature(*rehydrated.get()));
576f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
577f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    prefs_->SetInstallSignature(&pref);
578f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
579f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
5825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum CallbackResult {
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CALLBACK_NO_SIGNATURE = 0,
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CALLBACK_INVALID_SIGNATURE,
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CALLBACK_VALID_SIGNATURE,
5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This is used in histograms - do not remove or reorder entries above! Also
5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the "MAX" item below should always be the last element.
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CALLBACK_RESULT_MAX
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GetSignatureResultHistogram(CallbackResult result) {
5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.GetSignatureResult",
5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            result, CALLBACK_RESULT_MAX);
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
601f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::SignatureCallback(
602f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_ptr<InstallSignature> signature) {
603f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
604f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  linked_ptr<PendingOperation> operation = operation_queue_.front();
605f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  operation_queue_.pop();
606f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
607f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool success = false;
608f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!signature.get()) {
6095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GetSignatureResultHistogram(CALLBACK_NO_SIGNATURE);
610f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else if (!InstallSigner::VerifySignature(*signature)) {
6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GetSignatureResultHistogram(CALLBACK_INVALID_SIGNATURE);
612f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GetSignatureResultHistogram(CALLBACK_VALID_SIGNATURE);
614f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    success = true;
615f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
616f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
617f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!success) {
618effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    OnVerificationComplete(false, operation->type);
619f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
620f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // TODO(asargent) - if this was something like a network error, we need to
621f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // do retries with exponential back off.
622f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
623f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    signature_ = signature.Pass();
624f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    SaveToPrefs();
625f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
626f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!provisional_.empty()) {
627f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Update |provisional_| to remove ids that were successfully signed.
628f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      provisional_ = base::STLSetDifference<ExtensionIdSet>(
629f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          provisional_, signature_->ids);
630f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
631f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
632effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    OnVerificationComplete(success, operation->type);
633f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
634f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
635f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!operation_queue_.empty())
636f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    BeginFetch();
637f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
638f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
639f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace extensions
640