install_verifier.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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"
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/extension_service.h"
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/extensions/install_signer.h"
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/common/extensions/manifest_url_handler.h"
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/common/pref_names.h"
21effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/browser_context.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/common/content_switches.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
24effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/browser/extension_registry.h"
25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/browser/extension_system.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/pref_names.h"
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/common/extension_set.h"
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/manifest.h"
29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/common/one_shot_event.h"
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "grit/generated_resources.h"
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
33effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace extensions {
34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace {
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)enum VerifyStatus {
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NONE = 0,   // Do not request install signatures, and do not enforce them.
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BOOTSTRAP,  // Request install signatures, but do not enforce them.
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ENFORCE,    // Request install signatures, and enforce them.
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ENFORCE_STRICT,  // Same as ENFORCE, but hard fail if we can't fetch
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   // signatures.
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This is used in histograms - do not remove or reorder entries above! Also
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the "MAX" item below should always be the last element.
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VERIFY_STATUS_MAX
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)};
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(GOOGLE_CHROME_BUILD)
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kExperimentName[] = "ExtensionInstallVerification";
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif  // defined(GOOGLE_CHROME_BUILD)
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VerifyStatus GetExperimentStatus() {
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(GOOGLE_CHROME_BUILD)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string group = base::FieldTrialList::FindFullName(
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      kExperimentName);
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string forced_trials = CommandLine::ForCurrentProcess()->
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetSwitchValueASCII(switches::kForceFieldTrials);
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (forced_trials.find(kExperimentName) != std::string::npos) {
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // We don't want to allow turning off enforcement by forcing the field
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // trial group to something other than enforcement.
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return ENFORCE_STRICT;
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VerifyStatus default_status = NONE;
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (group == "EnforceStrict")
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return ENFORCE_STRICT;
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  else if (group == "Enforce")
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return ENFORCE;
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else if (group == "Bootstrap")
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return BOOTSTRAP;
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else if (group == "None" || group == "Control")
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NONE;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return default_status;
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif  // defined(GOOGLE_CHROME_BUILD)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return NONE;
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VerifyStatus GetCommandLineStatus() {
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const CommandLine* cmdline = CommandLine::ForCurrentProcess();
85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!InstallSigner::GetForcedNotFromWebstore().empty())
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return ENFORCE;
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (cmdline->HasSwitch(switches::kExtensionsInstallVerification)) {
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string value = cmdline->GetSwitchValueASCII(
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        switches::kExtensionsInstallVerification);
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (value == "bootstrap")
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return BOOTSTRAP;
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    else if (value == "enforce_strict")
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ENFORCE_STRICT;
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    else
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return ENFORCE;
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return NONE;
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VerifyStatus GetStatus() {
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return std::max(GetExperimentStatus(), GetCommandLineStatus());
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ShouldFetchSignature() {
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return GetStatus() >= BOOTSTRAP;
108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ShouldEnforce() {
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return GetStatus() >= ENFORCE;
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum InitResult {
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  INIT_NO_PREF = 0,
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  INIT_UNPARSEABLE_PREF,
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  INIT_INVALID_SIGNATURE,
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  INIT_VALID_SIGNATURE,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This is used in histograms - do not remove or reorder entries above! Also
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the "MAX" item below should always be the last element.
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  INIT_RESULT_MAX
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void LogInitResultHistogram(InitResult result) {
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.InitResult",
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            result, INIT_RESULT_MAX);
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool FromStore(const Extension& extension) {
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (extension.from_webstore() || ManifestURL::UpdatesFromGallery(&extension))
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return true;
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If an extension has no update url, our autoupdate code will ask the
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // webstore about it (to aid in migrating to the webstore from self-hosting
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // or sideloading based installs). So we want to do verification checks on
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // such extensions too so that we don't accidentally disable old installs of
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // extensions that did migrate to the webstore.
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return (ManifestURL::GetUpdateURL(&extension).is_empty() &&
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          Manifest::IsAutoUpdateableLocation(extension.location()));
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool CanUseExtensionApis(const Extension& extension) {
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return extension.is_extension() || extension.is_legacy_packaged_app();
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochenum VerifyAllSuccess {
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VERIFY_ALL_BOOTSTRAP_SUCCESS = 0,
150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VERIFY_ALL_BOOTSTRAP_FAILURE,
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VERIFY_ALL_NON_BOOTSTRAP_SUCCESS,
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VERIFY_ALL_NON_BOOTSTRAP_FAILURE,
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Used in histograms. Do not remove/reorder any entries above, and the below
155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // MAX entry should always come last.
156effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VERIFY_ALL_SUCCESS_MAX
157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch};
158effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
159effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Record the success or failure of verifying all extensions, and whether or
160effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// not it was a bootstrapping.
161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid LogVerifyAllSuccessHistogram(bool bootstrap, bool success) {
162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  VerifyAllSuccess result;
163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (bootstrap && success)
164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    result = VERIFY_ALL_BOOTSTRAP_SUCCESS;
165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  else if (bootstrap && !success)
166effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    result = VERIFY_ALL_BOOTSTRAP_FAILURE;
167effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  else if (!bootstrap && success)
168effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    result = VERIFY_ALL_NON_BOOTSTRAP_SUCCESS;
169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  else
170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    result = VERIFY_ALL_NON_BOOTSTRAP_FAILURE;
171effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // This used to be part of ExtensionService, but moved here. In order to keep
173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // our histograms accurate, the name is unchanged.
174effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  UMA_HISTOGRAM_ENUMERATION(
175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      "ExtensionService.VerifyAllSuccess", result, VERIFY_ALL_SUCCESS_MAX);
176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Record the success or failure of a single verification.
179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid LogAddVerifiedSuccess(bool success) {
180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // This used to be part of ExtensionService, but moved here. In order to keep
181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // our histograms accurate, the name is unchanged.
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  UMA_HISTOGRAM_BOOLEAN("ExtensionService.AddVerified", success);
183effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
184effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
187effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochInstallVerifier::InstallVerifier(ExtensionPrefs* prefs,
188effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                 content::BrowserContext* context)
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : prefs_(prefs),
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      context_(context),
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      bootstrap_check_complete_(false),
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      weak_factory_(this) {
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
194effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
195effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochInstallVerifier::~InstallVerifier() {}
196effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InstallVerifier::NeedsVerification(const Extension& extension) {
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return FromStore(extension) && CanUseExtensionApis(extension);
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::Init() {
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ExperimentStatus",
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            GetExperimentStatus(), VERIFY_STATUS_MAX);
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ActualStatus",
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            GetStatus(), VERIFY_STATUS_MAX);
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::DictionaryValue* pref = prefs_->GetInstallSignature();
209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (pref) {
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_ptr<InstallSignature> signature_from_prefs =
211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        InstallSignature::FromValue(*pref);
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!signature_from_prefs.get()) {
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LogInitResultHistogram(INIT_UNPARSEABLE_PREF);
214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else if (!InstallSigner::VerifySignature(*signature_from_prefs.get())) {
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LogInitResultHistogram(INIT_INVALID_SIGNATURE);
216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DVLOG(1) << "Init - ignoring invalid signature";
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else {
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      signature_ = signature_from_prefs.Pass();
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LogInitResultHistogram(INIT_VALID_SIGNATURE);
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      UMA_HISTOGRAM_COUNTS_100("ExtensionInstallVerifier.InitSignatureCount",
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               signature_->ids.size());
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      GarbageCollect();
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LogInitResultHistogram(INIT_NO_PREF);
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
227effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
228effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ExtensionSystem::Get(context_)->ready().Post(
229effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
230effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&InstallVerifier::MaybeBootstrapSelf,
231effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 weak_factory_.GetWeakPtr()));
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
234effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InstallVerifier::VerifyAllExtensions() {
235effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  AddMany(GetExtensionsToVerify(), ADD_ALL);
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::Time InstallVerifier::SignatureTimestamp() {
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (signature_.get())
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return signature_->timestamp;
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return base::Time();
243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool InstallVerifier::IsKnownId(const std::string& id) {
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return signature_.get() && (ContainsKey(signature_->ids, id) ||
247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                              ContainsKey(signature_->invalid_ids, id));
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
250effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InstallVerifier::VerifyExtension(const std::string& extension_id) {
251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionIdSet ids;
252effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ids.insert(extension_id);
253effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  AddMany(ids, ADD_SINGLE);
254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
256effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InstallVerifier::AddMany(const ExtensionIdSet& ids, OperationType type) {
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ShouldFetchSignature()) {
258effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    OnVerificationComplete(true, type);  // considered successful.
259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (signature_.get()) {
263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ExtensionIdSet not_allowed_yet =
264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        base::STLSetDifference<ExtensionIdSet>(ids, signature_->ids);
265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (not_allowed_yet.empty()) {
266effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      OnVerificationComplete(true, type);  // considered successful.
267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return;
268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
269f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  InstallVerifier::PendingOperation* operation =
272effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new InstallVerifier::PendingOperation(type);
273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  operation->ids.insert(ids.begin(), ids.end());
274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  operation_queue_.push(linked_ptr<PendingOperation>(operation));
276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // If there are no ongoing pending requests, we need to kick one off.
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (operation_queue_.size() == 1)
279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    BeginFetch();
280f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::AddProvisional(const ExtensionIdSet& ids) {
283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  provisional_.insert(ids.begin(), ids.end());
284effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  AddMany(ids, ADD_PROVISIONAL);
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::Remove(const std::string& id) {
288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionIdSet ids;
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ids.insert(id);
290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RemoveMany(ids);
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::RemoveMany(const ExtensionIdSet& ids) {
294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!signature_.get() || !ShouldFetchSignature())
295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool found_any = false;
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i) {
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (ContainsKey(signature_->ids, *i) ||
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        ContainsKey(signature_->invalid_ids, *i)) {
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      found_any = true;
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      break;
303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!found_any)
306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  InstallVerifier::PendingOperation* operation =
309effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new InstallVerifier::PendingOperation(InstallVerifier::REMOVE);
310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  operation->ids = ids;
311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  operation_queue_.push(linked_ptr<PendingOperation>(operation));
313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (operation_queue_.size() == 1)
314f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    BeginFetch();
315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)std::string InstallVerifier::GetDebugPolicyProviderName() const {
318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return std::string("InstallVerifier");
319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum MustRemainDisabledOutcome {
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VERIFIED = 0,
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOT_EXTENSION,
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UNPACKED,
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ENTERPRISE_POLICY_ALLOWED,
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FORCED_NOT_VERIFIED,
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOT_FROM_STORE,
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NO_SIGNATURE,
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOT_VERIFIED_BUT_NOT_ENFORCING,
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOT_VERIFIED,
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE,
334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NOT_VERIFIED_BUT_UNKNOWN_ID,
335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  COMPONENT,
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This is used in histograms - do not remove or reorder entries above! Also
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the "MAX" item below should always be the last element.
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MUST_REMAIN_DISABLED_OUTCOME_MAX
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MustRemainDisabledHistogram(MustRemainDisabledOutcome outcome) {
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.MustRemainDisabled",
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            outcome, MUST_REMAIN_DISABLED_OUTCOME_MAX);
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool InstallVerifier::MustRemainDisabled(const Extension* extension,
350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                         Extension::DisableReason* reason,
351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                         base::string16* error) const {
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK(extension);
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!CanUseExtensionApis(*extension)) {
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MustRemainDisabledHistogram(NOT_EXTENSION);
355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (Manifest::IsUnpackedLocation(extension->location())) {
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MustRemainDisabledHistogram(UNPACKED);
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (extension->location() == Manifest::COMPONENT) {
362a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    MustRemainDisabledHistogram(COMPONENT);
363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (AllowedByEnterprisePolicy(extension->id())) {
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MustRemainDisabledHistogram(ENTERPRISE_POLICY_ALLOWED);
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool verified = true;
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MustRemainDisabledOutcome outcome = VERIFIED;
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ContainsKey(InstallSigner::GetForcedNotFromWebstore(), extension->id())) {
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    verified = false;
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    outcome = FORCED_NOT_VERIFIED;
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (!FromStore(*extension)) {
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    verified = false;
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    outcome = NOT_FROM_STORE;
378f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else if (signature_.get() == NULL &&
379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             (!bootstrap_check_complete_ || GetStatus() < ENFORCE_STRICT)) {
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If we don't have a signature yet, we'll temporarily consider every
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // extension from the webstore verified to avoid false positives on existing
382effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // profiles hitting this code for the first time. The InstallVerifier
383effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // will bootstrap itself once the ExtensionsSystem is ready.
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    outcome = NO_SIGNATURE;
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (!IsVerified(extension->id())) {
386f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (signature_.get() &&
387f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        !ContainsKey(signature_->invalid_ids, extension->id())) {
388a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      outcome = NOT_VERIFIED_BUT_UNKNOWN_ID;
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      verified = false;
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      outcome = NOT_VERIFIED;
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!verified && !ShouldEnforce()) {
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    verified = true;
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    outcome = NOT_VERIFIED_BUT_NOT_ENFORCING;
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MustRemainDisabledHistogram(outcome);
399f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
400f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!verified) {
401f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (reason)
402f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      *reason = Extension::DISABLE_NOT_VERIFIED;
403f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (error)
404f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      *error = l10n_util::GetStringFUTF16(
405f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE,
406f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE));
407f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
408f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !verified;
409f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
410f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
411effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochInstallVerifier::PendingOperation::PendingOperation(OperationType type)
412effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    : type(type) {}
413f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)InstallVerifier::PendingOperation::~PendingOperation() {
415f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
417effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochExtensionIdSet InstallVerifier::GetExtensionsToVerify() const {
418effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ExtensionIdSet result;
419effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<ExtensionSet> extensions =
420effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      ExtensionRegistry::Get(context_)->GenerateInstalledExtensionsSet();
421effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (ExtensionSet::const_iterator iter = extensions->begin();
422effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       iter != extensions->end();
423effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++iter) {
424effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (NeedsVerification(**iter))
425effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      result.insert((*iter)->id());
426effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
427effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return result;
428effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
429effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
430effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InstallVerifier::MaybeBootstrapSelf() {
431effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  bool needs_bootstrap = false;
432effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
433effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ExtensionIdSet extension_ids = GetExtensionsToVerify();
434effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (signature_.get() == NULL && ShouldFetchSignature()) {
435effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    needs_bootstrap = true;
436effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  } else {
437effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    for (ExtensionIdSet::const_iterator iter = extension_ids.begin();
438effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         iter != extension_ids.end();
439effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         ++iter) {
440effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (!IsKnownId(*iter)) {
441effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        needs_bootstrap = true;
442effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        break;
443effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
444effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
445effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
446effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
447effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (needs_bootstrap)
448effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    AddMany(extension_ids, ADD_ALL_BOOTSTRAP);
449f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  else
450f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    bootstrap_check_complete_ = true;
451effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
452effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
453f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void InstallVerifier::OnVerificationComplete(bool success, OperationType type) {
454effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  switch (type) {
455effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case ADD_SINGLE:
456effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LogAddVerifiedSuccess(success);
457effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      break;
458effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case ADD_ALL:
459effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case ADD_ALL_BOOTSTRAP:
460effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LogVerifyAllSuccessHistogram(type == ADD_ALL_BOOTSTRAP, success);
461f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      bootstrap_check_complete_ = true;
462effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (success) {
463effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // Iterate through the extensions and, if any are newly-verified and
464effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // should have the DISABLE_NOT_VERIFIED reason lifted, do so.
465effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        const ExtensionSet& disabled_extensions =
466effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            ExtensionRegistry::Get(context_)->disabled_extensions();
467effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        for (ExtensionSet::const_iterator iter = disabled_extensions.begin();
468effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch             iter != disabled_extensions.end();
469effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch             ++iter) {
470effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          int disable_reasons = prefs_->GetDisableReasons((*iter)->id());
471effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          if (disable_reasons & Extension::DISABLE_NOT_VERIFIED &&
472effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch              !MustRemainDisabled(*iter, NULL, NULL)) {
473effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            prefs_->RemoveDisableReason((*iter)->id(),
474effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                        Extension::DISABLE_NOT_VERIFIED);
475effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          }
476effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        }
477f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
478f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (success || GetStatus() == ENFORCE_STRICT) {
479effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        ExtensionSystem::Get(context_)
480effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            ->extension_service()
481effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            ->CheckManagementPolicy();
482effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
483effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      break;
484effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // We don't need to check disable reasons or report UMA stats for
485effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // provisional adds or removals.
486effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case ADD_PROVISIONAL:
487effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case REMOVE:
488effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      break;
489effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
490effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
491effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::GarbageCollect() {
493f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!ShouldFetchSignature()) {
494f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
495f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
496f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CHECK(signature_.get());
497f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionIdSet leftovers = signature_->ids;
498a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  leftovers.insert(signature_->invalid_ids.begin(),
499a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   signature_->invalid_ids.end());
500f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionIdList all_ids;
501f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  prefs_->GetExtensions(&all_ids);
502f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (ExtensionIdList::const_iterator i = all_ids.begin();
503f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       i != all_ids.end(); ++i) {
504f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ExtensionIdSet::iterator found = leftovers.find(*i);
505f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (found != leftovers.end())
506f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      leftovers.erase(found);
507f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
508f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!leftovers.empty()) {
509f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RemoveMany(leftovers);
510f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
511f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
512f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
513f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool InstallVerifier::AllowedByEnterprisePolicy(const std::string& id) const {
514f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  PrefService* pref_service = prefs_->pref_service();
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (pref_service->IsManagedPreference(pref_names::kInstallAllowList)) {
516f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::ListValue* whitelist =
5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        pref_service->GetList(pref_names::kInstallAllowList);
518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    base::StringValue id_value(id);
519f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (whitelist && whitelist->Find(id_value) != whitelist->end())
520f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return true;
521f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (pref_service->IsManagedPreference(pref_names::kInstallForceList)) {
523f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::DictionaryValue* forcelist =
5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        pref_service->GetDictionary(pref_names::kInstallForceList);
525f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (forcelist && forcelist->HasKey(id))
526f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return true;
527f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
528f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return false;
529f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
530f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
531f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool InstallVerifier::IsVerified(const std::string& id) const {
532f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return ((signature_.get() && ContainsKey(signature_->ids, id)) ||
533f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          ContainsKey(provisional_, id));
534f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
535f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
536f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::BeginFetch() {
537f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(ShouldFetchSignature());
538f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
539f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // TODO(asargent) - It would be possible to coalesce all operations in the
540f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // queue into one fetch - we'd probably just need to change the queue to
541effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // hold (set of ids, list of operation type) pairs.
542f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CHECK(!operation_queue_.empty());
543f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const PendingOperation& operation = *operation_queue_.front();
544f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
545f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionIdSet ids_to_sign;
546f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (signature_.get()) {
547f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ids_to_sign.insert(signature_->ids.begin(), signature_->ids.end());
548f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
549effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (operation.type == InstallVerifier::REMOVE) {
550f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for (ExtensionIdSet::const_iterator i = operation.ids.begin();
551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         i != operation.ids.end(); ++i) {
552f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (ContainsKey(ids_to_sign, *i))
553f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        ids_to_sign.erase(*i);
554f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
555effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  } else {  // All other operation types are some form of "ADD".
556effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ids_to_sign.insert(operation.ids.begin(), operation.ids.end());
557f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
558f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
559effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  signer_.reset(new InstallSigner(context_->GetRequestContext(), ids_to_sign));
560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  signer_->GetSignature(base::Bind(&InstallVerifier::SignatureCallback,
561effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                   weak_factory_.GetWeakPtr()));
562f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::SaveToPrefs() {
565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (signature_.get())
566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK(InstallSigner::VerifySignature(*signature_));
567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!signature_.get() || signature_->ids.empty()) {
569f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "SaveToPrefs - saving NULL";
570f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    prefs_->SetInstallSignature(NULL);
571f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue pref;
573f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    signature_->ToValue(&pref);
574f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (VLOG_IS_ON(1)) {
575f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DVLOG(1) << "SaveToPrefs - saving";
576f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
577f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DCHECK(InstallSigner::VerifySignature(*signature_.get()));
578f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      scoped_ptr<InstallSignature> rehydrated =
579f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          InstallSignature::FromValue(pref);
580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DCHECK(InstallSigner::VerifySignature(*rehydrated.get()));
581f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
582f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    prefs_->SetInstallSignature(&pref);
583f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
584f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
585f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum CallbackResult {
5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CALLBACK_NO_SIGNATURE = 0,
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CALLBACK_INVALID_SIGNATURE,
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CALLBACK_VALID_SIGNATURE,
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This is used in histograms - do not remove or reorder entries above! Also
5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the "MAX" item below should always be the last element.
5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CALLBACK_RESULT_MAX
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GetSignatureResultHistogram(CallbackResult result) {
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.GetSignatureResult",
6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            result, CALLBACK_RESULT_MAX);
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
606f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InstallVerifier::SignatureCallback(
607f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_ptr<InstallSignature> signature) {
608f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
609f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  linked_ptr<PendingOperation> operation = operation_queue_.front();
610f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  operation_queue_.pop();
611f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
612f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool success = false;
613f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!signature.get()) {
6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GetSignatureResultHistogram(CALLBACK_NO_SIGNATURE);
615f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else if (!InstallSigner::VerifySignature(*signature)) {
6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GetSignatureResultHistogram(CALLBACK_INVALID_SIGNATURE);
617f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GetSignatureResultHistogram(CALLBACK_VALID_SIGNATURE);
619f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    success = true;
620f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
621f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
622f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!success) {
623effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    OnVerificationComplete(false, operation->type);
624f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
625f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // TODO(asargent) - if this was something like a network error, we need to
626f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // do retries with exponential back off.
627f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
628f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    signature_ = signature.Pass();
629f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    SaveToPrefs();
630f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
631f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!provisional_.empty()) {
632f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Update |provisional_| to remove ids that were successfully signed.
633f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      provisional_ = base::STLSetDifference<ExtensionIdSet>(
634f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          provisional_, signature_->ids);
635f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
636f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
637effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    OnVerificationComplete(success, operation->type);
638f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
639f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
640f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!operation_queue_.empty())
641f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    BeginFetch();
642f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
643f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
644f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace extensions
645