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