1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/install_verifier.h"
6
7#include <algorithm>
8#include <string>
9
10#include "base/bind.h"
11#include "base/command_line.h"
12#include "base/metrics/field_trial.h"
13#include "base/metrics/histogram.h"
14#include "base/prefs/pref_service.h"
15#include "base/stl_util.h"
16#include "chrome/browser/extensions/extension_management.h"
17#include "chrome/browser/extensions/extension_service.h"
18#include "chrome/browser/extensions/install_signer.h"
19#include "chrome/common/chrome_switches.h"
20#include "chrome/common/extensions/manifest_url_handler.h"
21#include "chrome/common/pref_names.h"
22#include "chrome/grit/generated_resources.h"
23#include "content/public/browser/browser_context.h"
24#include "content/public/common/content_switches.h"
25#include "extensions/browser/extension_prefs.h"
26#include "extensions/browser/extension_registry.h"
27#include "extensions/browser/extension_system.h"
28#include "extensions/browser/pref_names.h"
29#include "extensions/common/extension_set.h"
30#include "extensions/common/manifest.h"
31#include "extensions/common/one_shot_event.h"
32#include "ui/base/l10n/l10n_util.h"
33
34namespace extensions {
35
36namespace {
37
38enum VerifyStatus {
39  NONE = 0,   // Do not request install signatures, and do not enforce them.
40  BOOTSTRAP,  // Request install signatures, but do not enforce them.
41  ENFORCE,    // Request install signatures, and enforce them.
42  ENFORCE_STRICT,  // Same as ENFORCE, but hard fail if we can't fetch
43                   // signatures.
44
45  // This is used in histograms - do not remove or reorder entries above! Also
46  // the "MAX" item below should always be the last element.
47  VERIFY_STATUS_MAX
48};
49
50#if defined(GOOGLE_CHROME_BUILD)
51const char kExperimentName[] = "ExtensionInstallVerification";
52#endif  // defined(GOOGLE_CHROME_BUILD)
53
54VerifyStatus GetExperimentStatus() {
55#if defined(GOOGLE_CHROME_BUILD)
56  const std::string group = base::FieldTrialList::FindFullName(
57      kExperimentName);
58
59  std::string forced_trials = CommandLine::ForCurrentProcess()->
60      GetSwitchValueASCII(switches::kForceFieldTrials);
61  if (forced_trials.find(kExperimentName) != std::string::npos) {
62    // We don't want to allow turning off enforcement by forcing the field
63    // trial group to something other than enforcement.
64    return ENFORCE_STRICT;
65  }
66
67  VerifyStatus default_status = NONE;
68
69  if (group == "EnforceStrict")
70    return ENFORCE_STRICT;
71  else if (group == "Enforce")
72    return ENFORCE;
73  else if (group == "Bootstrap")
74    return BOOTSTRAP;
75  else if (group == "None" || group == "Control")
76    return NONE;
77  else
78    return default_status;
79#endif  // defined(GOOGLE_CHROME_BUILD)
80
81  return NONE;
82}
83
84VerifyStatus GetCommandLineStatus() {
85  const CommandLine* cmdline = CommandLine::ForCurrentProcess();
86  if (!InstallSigner::GetForcedNotFromWebstore().empty())
87    return ENFORCE;
88
89  if (cmdline->HasSwitch(switches::kExtensionsInstallVerification)) {
90    std::string value = cmdline->GetSwitchValueASCII(
91        switches::kExtensionsInstallVerification);
92    if (value == "bootstrap")
93      return BOOTSTRAP;
94    else if (value == "enforce_strict")
95      return ENFORCE_STRICT;
96    else
97      return ENFORCE;
98  }
99
100  return NONE;
101}
102
103VerifyStatus GetStatus() {
104  return std::max(GetExperimentStatus(), GetCommandLineStatus());
105}
106
107bool ShouldFetchSignature() {
108  return GetStatus() >= BOOTSTRAP;
109}
110
111bool ShouldEnforce() {
112  return GetStatus() >= ENFORCE;
113}
114
115enum InitResult {
116  INIT_NO_PREF = 0,
117  INIT_UNPARSEABLE_PREF,
118  INIT_INVALID_SIGNATURE,
119  INIT_VALID_SIGNATURE,
120
121  // This is used in histograms - do not remove or reorder entries above! Also
122  // the "MAX" item below should always be the last element.
123
124  INIT_RESULT_MAX
125};
126
127void LogInitResultHistogram(InitResult result) {
128  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.InitResult",
129                            result, INIT_RESULT_MAX);
130}
131
132bool CanUseExtensionApis(const Extension& extension) {
133  return extension.is_extension() || extension.is_legacy_packaged_app();
134}
135
136enum VerifyAllSuccess {
137  VERIFY_ALL_BOOTSTRAP_SUCCESS = 0,
138  VERIFY_ALL_BOOTSTRAP_FAILURE,
139  VERIFY_ALL_NON_BOOTSTRAP_SUCCESS,
140  VERIFY_ALL_NON_BOOTSTRAP_FAILURE,
141
142  // Used in histograms. Do not remove/reorder any entries above, and the below
143  // MAX entry should always come last.
144  VERIFY_ALL_SUCCESS_MAX
145};
146
147// Record the success or failure of verifying all extensions, and whether or
148// not it was a bootstrapping.
149void LogVerifyAllSuccessHistogram(bool bootstrap, bool success) {
150  VerifyAllSuccess result;
151  if (bootstrap && success)
152    result = VERIFY_ALL_BOOTSTRAP_SUCCESS;
153  else if (bootstrap && !success)
154    result = VERIFY_ALL_BOOTSTRAP_FAILURE;
155  else if (!bootstrap && success)
156    result = VERIFY_ALL_NON_BOOTSTRAP_SUCCESS;
157  else
158    result = VERIFY_ALL_NON_BOOTSTRAP_FAILURE;
159
160  // This used to be part of ExtensionService, but moved here. In order to keep
161  // our histograms accurate, the name is unchanged.
162  UMA_HISTOGRAM_ENUMERATION(
163      "ExtensionService.VerifyAllSuccess", result, VERIFY_ALL_SUCCESS_MAX);
164}
165
166// Record the success or failure of a single verification.
167void LogAddVerifiedSuccess(bool success) {
168  // This used to be part of ExtensionService, but moved here. In order to keep
169  // our histograms accurate, the name is unchanged.
170  UMA_HISTOGRAM_BOOLEAN("ExtensionService.AddVerified", success);
171}
172
173}  // namespace
174
175InstallVerifier::InstallVerifier(ExtensionPrefs* prefs,
176                                 content::BrowserContext* context)
177    : prefs_(prefs),
178      context_(context),
179      bootstrap_check_complete_(false),
180      weak_factory_(this) {
181}
182
183InstallVerifier::~InstallVerifier() {}
184
185// static
186bool InstallVerifier::NeedsVerification(const Extension& extension) {
187  return IsFromStore(extension) && CanUseExtensionApis(extension);
188}
189
190
191
192// static
193bool InstallVerifier::IsFromStore(const Extension& extension) {
194  if (extension.from_webstore() || ManifestURL::UpdatesFromGallery(&extension))
195    return true;
196
197  // If an extension has no update url, our autoupdate code will ask the
198  // webstore about it (to aid in migrating to the webstore from self-hosting
199  // or sideloading based installs). So we want to do verification checks on
200  // such extensions too so that we don't accidentally disable old installs of
201  // extensions that did migrate to the webstore.
202  return (ManifestURL::GetUpdateURL(&extension).is_empty() &&
203          Manifest::IsAutoUpdateableLocation(extension.location()));
204}
205
206void InstallVerifier::Init() {
207  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ExperimentStatus",
208                            GetExperimentStatus(), VERIFY_STATUS_MAX);
209  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ActualStatus",
210                            GetStatus(), VERIFY_STATUS_MAX);
211
212  const base::DictionaryValue* pref = prefs_->GetInstallSignature();
213  if (pref) {
214    scoped_ptr<InstallSignature> signature_from_prefs =
215        InstallSignature::FromValue(*pref);
216    if (!signature_from_prefs.get()) {
217      LogInitResultHistogram(INIT_UNPARSEABLE_PREF);
218    } else if (!InstallSigner::VerifySignature(*signature_from_prefs.get())) {
219      LogInitResultHistogram(INIT_INVALID_SIGNATURE);
220      DVLOG(1) << "Init - ignoring invalid signature";
221    } else {
222      signature_ = signature_from_prefs.Pass();
223      LogInitResultHistogram(INIT_VALID_SIGNATURE);
224      UMA_HISTOGRAM_COUNTS_100("ExtensionInstallVerifier.InitSignatureCount",
225                               signature_->ids.size());
226      GarbageCollect();
227    }
228  } else {
229    LogInitResultHistogram(INIT_NO_PREF);
230  }
231
232  ExtensionSystem::Get(context_)->ready().Post(
233      FROM_HERE,
234      base::Bind(&InstallVerifier::MaybeBootstrapSelf,
235                 weak_factory_.GetWeakPtr()));
236}
237
238void InstallVerifier::VerifyAllExtensions() {
239  AddMany(GetExtensionsToVerify(), ADD_ALL);
240}
241
242base::Time InstallVerifier::SignatureTimestamp() {
243  if (signature_.get())
244    return signature_->timestamp;
245  else
246    return base::Time();
247}
248
249bool InstallVerifier::IsKnownId(const std::string& id) const {
250  return signature_.get() && (ContainsKey(signature_->ids, id) ||
251                              ContainsKey(signature_->invalid_ids, id));
252}
253
254bool InstallVerifier::IsInvalid(const std::string& id) const {
255  return ((signature_.get() && ContainsKey(signature_->invalid_ids, id)));
256}
257
258void InstallVerifier::VerifyExtension(const std::string& extension_id) {
259  ExtensionIdSet ids;
260  ids.insert(extension_id);
261  AddMany(ids, ADD_SINGLE);
262}
263
264void InstallVerifier::AddMany(const ExtensionIdSet& ids, OperationType type) {
265  if (!ShouldFetchSignature()) {
266    OnVerificationComplete(true, type);  // considered successful.
267    return;
268  }
269
270  if (signature_.get()) {
271    ExtensionIdSet not_allowed_yet =
272        base::STLSetDifference<ExtensionIdSet>(ids, signature_->ids);
273    if (not_allowed_yet.empty()) {
274      OnVerificationComplete(true, type);  // considered successful.
275      return;
276    }
277  }
278
279  InstallVerifier::PendingOperation* operation =
280      new InstallVerifier::PendingOperation(type);
281  operation->ids.insert(ids.begin(), ids.end());
282
283  operation_queue_.push(linked_ptr<PendingOperation>(operation));
284
285  // If there are no ongoing pending requests, we need to kick one off.
286  if (operation_queue_.size() == 1)
287    BeginFetch();
288}
289
290void InstallVerifier::AddProvisional(const ExtensionIdSet& ids) {
291  provisional_.insert(ids.begin(), ids.end());
292  AddMany(ids, ADD_PROVISIONAL);
293}
294
295void InstallVerifier::Remove(const std::string& id) {
296  ExtensionIdSet ids;
297  ids.insert(id);
298  RemoveMany(ids);
299}
300
301void InstallVerifier::RemoveMany(const ExtensionIdSet& ids) {
302  if (!signature_.get() || !ShouldFetchSignature())
303    return;
304
305  bool found_any = false;
306  for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i) {
307    if (ContainsKey(signature_->ids, *i) ||
308        ContainsKey(signature_->invalid_ids, *i)) {
309      found_any = true;
310      break;
311    }
312  }
313  if (!found_any)
314    return;
315
316  InstallVerifier::PendingOperation* operation =
317      new InstallVerifier::PendingOperation(InstallVerifier::REMOVE);
318  operation->ids = ids;
319
320  operation_queue_.push(linked_ptr<PendingOperation>(operation));
321  if (operation_queue_.size() == 1)
322    BeginFetch();
323}
324
325bool InstallVerifier::AllowedByEnterprisePolicy(const std::string& id) const {
326  return ExtensionManagementFactory::GetForBrowserContext(context_)
327      ->IsInstallationExplicitlyAllowed(id);
328}
329
330std::string InstallVerifier::GetDebugPolicyProviderName() const {
331  return std::string("InstallVerifier");
332}
333
334namespace {
335
336enum MustRemainDisabledOutcome {
337  VERIFIED = 0,
338  NOT_EXTENSION,
339  UNPACKED,
340  ENTERPRISE_POLICY_ALLOWED,
341  FORCED_NOT_VERIFIED,
342  NOT_FROM_STORE,
343  NO_SIGNATURE,
344  NOT_VERIFIED_BUT_NOT_ENFORCING,
345  NOT_VERIFIED,
346  NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE,
347  NOT_VERIFIED_BUT_UNKNOWN_ID,
348  COMPONENT,
349
350  // This is used in histograms - do not remove or reorder entries above! Also
351  // the "MAX" item below should always be the last element.
352  MUST_REMAIN_DISABLED_OUTCOME_MAX
353};
354
355void MustRemainDisabledHistogram(MustRemainDisabledOutcome outcome) {
356  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.MustRemainDisabled",
357                            outcome, MUST_REMAIN_DISABLED_OUTCOME_MAX);
358}
359
360}  // namespace
361
362bool InstallVerifier::MustRemainDisabled(const Extension* extension,
363                                         Extension::DisableReason* reason,
364                                         base::string16* error) const {
365  CHECK(extension);
366  if (!CanUseExtensionApis(*extension)) {
367    MustRemainDisabledHistogram(NOT_EXTENSION);
368    return false;
369  }
370  if (Manifest::IsUnpackedLocation(extension->location())) {
371    MustRemainDisabledHistogram(UNPACKED);
372    return false;
373  }
374  if (extension->location() == Manifest::COMPONENT) {
375    MustRemainDisabledHistogram(COMPONENT);
376    return false;
377  }
378  if (AllowedByEnterprisePolicy(extension->id())) {
379    MustRemainDisabledHistogram(ENTERPRISE_POLICY_ALLOWED);
380    return false;
381  }
382
383  bool verified = true;
384  MustRemainDisabledOutcome outcome = VERIFIED;
385  if (ContainsKey(InstallSigner::GetForcedNotFromWebstore(), extension->id())) {
386    verified = false;
387    outcome = FORCED_NOT_VERIFIED;
388  } else if (!IsFromStore(*extension)) {
389    verified = false;
390    outcome = NOT_FROM_STORE;
391  } else if (signature_.get() == NULL &&
392             (!bootstrap_check_complete_ || GetStatus() < ENFORCE_STRICT)) {
393    // If we don't have a signature yet, we'll temporarily consider every
394    // extension from the webstore verified to avoid false positives on existing
395    // profiles hitting this code for the first time. The InstallVerifier
396    // will bootstrap itself once the ExtensionsSystem is ready.
397    outcome = NO_SIGNATURE;
398  } else if (!IsVerified(extension->id())) {
399    if (signature_.get() &&
400        !ContainsKey(signature_->invalid_ids, extension->id())) {
401      outcome = NOT_VERIFIED_BUT_UNKNOWN_ID;
402    } else {
403      verified = false;
404      outcome = NOT_VERIFIED;
405    }
406  }
407  if (!verified && !ShouldEnforce()) {
408    verified = true;
409    outcome = NOT_VERIFIED_BUT_NOT_ENFORCING;
410  }
411  MustRemainDisabledHistogram(outcome);
412
413  if (!verified) {
414    if (reason)
415      *reason = Extension::DISABLE_NOT_VERIFIED;
416    if (error)
417      *error = l10n_util::GetStringFUTF16(
418          IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE,
419          l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE));
420  }
421  return !verified;
422}
423
424InstallVerifier::PendingOperation::PendingOperation(OperationType type)
425    : type(type) {}
426
427InstallVerifier::PendingOperation::~PendingOperation() {
428}
429
430ExtensionIdSet InstallVerifier::GetExtensionsToVerify() const {
431  ExtensionIdSet result;
432  scoped_ptr<ExtensionSet> extensions =
433      ExtensionRegistry::Get(context_)->GenerateInstalledExtensionsSet();
434  for (ExtensionSet::const_iterator iter = extensions->begin();
435       iter != extensions->end();
436       ++iter) {
437    if (NeedsVerification(*iter->get()))
438      result.insert((*iter)->id());
439  }
440  return result;
441}
442
443void InstallVerifier::MaybeBootstrapSelf() {
444  bool needs_bootstrap = false;
445
446  ExtensionIdSet extension_ids = GetExtensionsToVerify();
447  if (signature_.get() == NULL && ShouldFetchSignature()) {
448    needs_bootstrap = true;
449  } else {
450    for (ExtensionIdSet::const_iterator iter = extension_ids.begin();
451         iter != extension_ids.end();
452         ++iter) {
453      if (!IsKnownId(*iter)) {
454        needs_bootstrap = true;
455        break;
456      }
457    }
458  }
459
460  if (needs_bootstrap)
461    AddMany(extension_ids, ADD_ALL_BOOTSTRAP);
462  else
463    bootstrap_check_complete_ = true;
464}
465
466void InstallVerifier::OnVerificationComplete(bool success, OperationType type) {
467  switch (type) {
468    case ADD_SINGLE:
469      LogAddVerifiedSuccess(success);
470      break;
471    case ADD_ALL:
472    case ADD_ALL_BOOTSTRAP:
473      LogVerifyAllSuccessHistogram(type == ADD_ALL_BOOTSTRAP, success);
474      bootstrap_check_complete_ = true;
475      if (success) {
476        // Iterate through the extensions and, if any are newly-verified and
477        // should have the DISABLE_NOT_VERIFIED reason lifted, do so.
478        const ExtensionSet& disabled_extensions =
479            ExtensionRegistry::Get(context_)->disabled_extensions();
480        for (ExtensionSet::const_iterator iter = disabled_extensions.begin();
481             iter != disabled_extensions.end();
482             ++iter) {
483          int disable_reasons = prefs_->GetDisableReasons((*iter)->id());
484          if (disable_reasons & Extension::DISABLE_NOT_VERIFIED &&
485              !MustRemainDisabled(iter->get(), NULL, NULL)) {
486            prefs_->RemoveDisableReason((*iter)->id(),
487                                        Extension::DISABLE_NOT_VERIFIED);
488          }
489        }
490      }
491      if (success || GetStatus() == ENFORCE_STRICT) {
492        ExtensionSystem::Get(context_)
493            ->extension_service()
494            ->CheckManagementPolicy();
495      }
496      break;
497    // We don't need to check disable reasons or report UMA stats for
498    // provisional adds or removals.
499    case ADD_PROVISIONAL:
500    case REMOVE:
501      break;
502  }
503}
504
505void InstallVerifier::GarbageCollect() {
506  if (!ShouldFetchSignature()) {
507    return;
508  }
509  CHECK(signature_.get());
510  ExtensionIdSet leftovers = signature_->ids;
511  leftovers.insert(signature_->invalid_ids.begin(),
512                   signature_->invalid_ids.end());
513  ExtensionIdList all_ids;
514  prefs_->GetExtensions(&all_ids);
515  for (ExtensionIdList::const_iterator i = all_ids.begin();
516       i != all_ids.end(); ++i) {
517    ExtensionIdSet::iterator found = leftovers.find(*i);
518    if (found != leftovers.end())
519      leftovers.erase(found);
520  }
521  if (!leftovers.empty()) {
522    RemoveMany(leftovers);
523  }
524}
525
526bool InstallVerifier::IsVerified(const std::string& id) const {
527  return ((signature_.get() && ContainsKey(signature_->ids, id)) ||
528          ContainsKey(provisional_, id));
529}
530
531void InstallVerifier::BeginFetch() {
532  DCHECK(ShouldFetchSignature());
533
534  // TODO(asargent) - It would be possible to coalesce all operations in the
535  // queue into one fetch - we'd probably just need to change the queue to
536  // hold (set of ids, list of operation type) pairs.
537  CHECK(!operation_queue_.empty());
538  const PendingOperation& operation = *operation_queue_.front();
539
540  ExtensionIdSet ids_to_sign;
541  if (signature_.get()) {
542    ids_to_sign.insert(signature_->ids.begin(), signature_->ids.end());
543  }
544  if (operation.type == InstallVerifier::REMOVE) {
545    for (ExtensionIdSet::const_iterator i = operation.ids.begin();
546         i != operation.ids.end(); ++i) {
547      if (ContainsKey(ids_to_sign, *i))
548        ids_to_sign.erase(*i);
549    }
550  } else {  // All other operation types are some form of "ADD".
551    ids_to_sign.insert(operation.ids.begin(), operation.ids.end());
552  }
553
554  signer_.reset(new InstallSigner(context_->GetRequestContext(), ids_to_sign));
555  signer_->GetSignature(base::Bind(&InstallVerifier::SignatureCallback,
556                                   weak_factory_.GetWeakPtr()));
557}
558
559void InstallVerifier::SaveToPrefs() {
560  if (signature_.get())
561    DCHECK(InstallSigner::VerifySignature(*signature_));
562
563  if (!signature_.get() || signature_->ids.empty()) {
564    DVLOG(1) << "SaveToPrefs - saving NULL";
565    prefs_->SetInstallSignature(NULL);
566  } else {
567    base::DictionaryValue pref;
568    signature_->ToValue(&pref);
569    if (VLOG_IS_ON(1)) {
570      DVLOG(1) << "SaveToPrefs - saving";
571
572      DCHECK(InstallSigner::VerifySignature(*signature_.get()));
573      scoped_ptr<InstallSignature> rehydrated =
574          InstallSignature::FromValue(pref);
575      DCHECK(InstallSigner::VerifySignature(*rehydrated.get()));
576    }
577    prefs_->SetInstallSignature(&pref);
578  }
579}
580
581namespace {
582
583enum CallbackResult {
584  CALLBACK_NO_SIGNATURE = 0,
585  CALLBACK_INVALID_SIGNATURE,
586  CALLBACK_VALID_SIGNATURE,
587
588  // This is used in histograms - do not remove or reorder entries above! Also
589  // the "MAX" item below should always be the last element.
590
591  CALLBACK_RESULT_MAX
592};
593
594void GetSignatureResultHistogram(CallbackResult result) {
595  UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.GetSignatureResult",
596                            result, CALLBACK_RESULT_MAX);
597}
598
599}  // namespace
600
601void InstallVerifier::SignatureCallback(
602    scoped_ptr<InstallSignature> signature) {
603
604  linked_ptr<PendingOperation> operation = operation_queue_.front();
605  operation_queue_.pop();
606
607  bool success = false;
608  if (!signature.get()) {
609    GetSignatureResultHistogram(CALLBACK_NO_SIGNATURE);
610  } else if (!InstallSigner::VerifySignature(*signature)) {
611    GetSignatureResultHistogram(CALLBACK_INVALID_SIGNATURE);
612  } else {
613    GetSignatureResultHistogram(CALLBACK_VALID_SIGNATURE);
614    success = true;
615  }
616
617  if (!success) {
618    OnVerificationComplete(false, operation->type);
619
620    // TODO(asargent) - if this was something like a network error, we need to
621    // do retries with exponential back off.
622  } else {
623    signature_ = signature.Pass();
624    SaveToPrefs();
625
626    if (!provisional_.empty()) {
627      // Update |provisional_| to remove ids that were successfully signed.
628      provisional_ = base::STLSetDifference<ExtensionIdSet>(
629          provisional_, signature_->ids);
630    }
631
632    OnVerificationComplete(success, operation->type);
633  }
634
635  if (!operation_queue_.empty())
636    BeginFetch();
637}
638
639}  // namespace extensions
640