Home | History | Annotate | Download | only in extensions
      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_prefs.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/common/content_switches.h"
     22 #include "extensions/common/manifest.h"
     23 #include "grit/generated_resources.h"
     24 #include "ui/base/l10n/l10n_util.h"
     25 
     26 namespace {
     27 
     28 enum VerifyStatus {
     29   NONE = 0,   // Do not request install signatures, and do not enforce them.
     30   BOOTSTRAP,  // Request install signatures, but do not enforce them.
     31   ENFORCE,    // Request install signatures, and enforce them.
     32 
     33   // This is used in histograms - do not remove or reorder entries above! Also
     34   // the "MAX" item below should always be the last element.
     35 
     36   VERIFY_STATUS_MAX
     37 };
     38 
     39 #if defined(GOOGLE_CHROME_BUILD)
     40 const char kExperimentName[] = "ExtensionInstallVerification";
     41 #endif  // defined(GOOGLE_CHROME_BUILD)
     42 
     43 VerifyStatus GetExperimentStatus() {
     44 #if defined(GOOGLE_CHROME_BUILD)
     45   const std::string group = base::FieldTrialList::FindFullName(
     46       kExperimentName);
     47 
     48   std::string forced_trials = CommandLine::ForCurrentProcess()->
     49       GetSwitchValueASCII(switches::kForceFieldTrials);
     50   if (forced_trials.find(kExperimentName) != std::string::npos) {
     51     // We don't want to allow turning off enforcement by forcing the field
     52     // trial group to something other than enforcement.
     53     return ENFORCE;
     54   }
     55 
     56   VerifyStatus default_status = NONE;
     57 
     58   if (group == "Enforce")
     59     return ENFORCE;
     60   else if (group == "Bootstrap")
     61     return BOOTSTRAP;
     62   else if (group == "None" || group == "Control")
     63     return NONE;
     64   else
     65     return default_status;
     66 #endif  // defined(GOOGLE_CHROME_BUILD)
     67 
     68   return NONE;
     69 }
     70 
     71 VerifyStatus GetCommandLineStatus() {
     72   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
     73   if (!extensions::InstallSigner::GetForcedNotFromWebstore().empty())
     74     return ENFORCE;
     75 
     76   if (cmdline->HasSwitch(switches::kExtensionsInstallVerification)) {
     77     std::string value = cmdline->GetSwitchValueASCII(
     78         switches::kExtensionsInstallVerification);
     79     if (value == "bootstrap")
     80       return BOOTSTRAP;
     81     else
     82       return ENFORCE;
     83   }
     84 
     85   return NONE;
     86 }
     87 
     88 VerifyStatus GetStatus() {
     89   return std::max(GetExperimentStatus(), GetCommandLineStatus());
     90 }
     91 
     92 bool ShouldFetchSignature() {
     93   VerifyStatus status = GetStatus();
     94   return (status == BOOTSTRAP || status == ENFORCE);
     95 }
     96 
     97 bool ShouldEnforce() {
     98   return GetStatus() == ENFORCE;
     99 }
    100 
    101 }  // namespace
    102 
    103 namespace extensions {
    104 
    105 InstallVerifier::InstallVerifier(ExtensionPrefs* prefs,
    106                                  net::URLRequestContextGetter* context_getter)
    107     : prefs_(prefs), context_getter_(context_getter) {
    108 }
    109 
    110 InstallVerifier::~InstallVerifier() {}
    111 
    112 namespace {
    113 
    114 enum 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 
    126 void LogInitResultHistogram(InitResult result) {
    127   UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.InitResult",
    128                             result, INIT_RESULT_MAX);
    129 }
    130 
    131 bool FromStore(const Extension& extension) {
    132   bool updates_from_store = ManifestURL::UpdatesFromGallery(&extension);
    133   return extension.from_webstore() || updates_from_store;
    134 }
    135 
    136 bool CanUseExtensionApis(const Extension& extension) {
    137   return extension.is_extension() || extension.is_legacy_packaged_app();
    138 }
    139 
    140 }  // namespace
    141 
    142 // static
    143 bool InstallVerifier::NeedsVerification(const Extension& extension) {
    144   return FromStore(extension) && CanUseExtensionApis(extension);
    145 }
    146 
    147 void InstallVerifier::Init() {
    148   UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ExperimentStatus",
    149                             GetExperimentStatus(), VERIFY_STATUS_MAX);
    150   UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ActualStatus",
    151                             GetStatus(), VERIFY_STATUS_MAX);
    152 
    153   const DictionaryValue* pref = prefs_->GetInstallSignature();
    154   if (pref) {
    155     scoped_ptr<InstallSignature> signature_from_prefs =
    156         InstallSignature::FromValue(*pref);
    157     if (!signature_from_prefs.get()) {
    158       LogInitResultHistogram(INIT_UNPARSEABLE_PREF);
    159     } else if (!InstallSigner::VerifySignature(*signature_from_prefs.get())) {
    160       LogInitResultHistogram(INIT_INVALID_SIGNATURE);
    161       DVLOG(1) << "Init - ignoring invalid signature";
    162     } else {
    163       signature_ = signature_from_prefs.Pass();
    164       LogInitResultHistogram(INIT_VALID_SIGNATURE);
    165       UMA_HISTOGRAM_COUNTS_100("ExtensionInstallVerifier.InitSignatureCount",
    166                                signature_->ids.size());
    167       GarbageCollect();
    168     }
    169   } else {
    170     LogInitResultHistogram(INIT_NO_PREF);
    171   }
    172 }
    173 
    174 bool InstallVerifier::NeedsBootstrap() {
    175   return signature_.get() == NULL && ShouldFetchSignature();
    176 }
    177 
    178 base::Time InstallVerifier::SignatureTimestamp() {
    179   if (signature_.get())
    180     return signature_->timestamp;
    181   else
    182     return base::Time();
    183 }
    184 
    185 void InstallVerifier::Add(const std::string& id,
    186                           const AddResultCallback& callback) {
    187   ExtensionIdSet ids;
    188   ids.insert(id);
    189   AddMany(ids, callback);
    190 }
    191 
    192 void InstallVerifier::AddMany(const ExtensionIdSet& ids,
    193                               const AddResultCallback& callback) {
    194   if (!ShouldFetchSignature()) {
    195     if (!callback.is_null())
    196       callback.Run(true);
    197     return;
    198   }
    199 
    200   if (signature_.get()) {
    201     ExtensionIdSet not_allowed_yet =
    202         base::STLSetDifference<ExtensionIdSet>(ids, signature_->ids);
    203     if (not_allowed_yet.empty()) {
    204       if (!callback.is_null())
    205         callback.Run(true);
    206       return;
    207     }
    208   }
    209 
    210   InstallVerifier::PendingOperation* operation =
    211     new InstallVerifier::PendingOperation();
    212   operation->type = InstallVerifier::ADD;
    213   operation->ids.insert(ids.begin(), ids.end());
    214   operation->callback = callback;
    215 
    216   operation_queue_.push(linked_ptr<PendingOperation>(operation));
    217 
    218   // If there are no ongoing pending requests, we need to kick one off.
    219   if (operation_queue_.size() == 1)
    220     BeginFetch();
    221 }
    222 
    223 void InstallVerifier::AddProvisional(const ExtensionIdSet& ids) {
    224   provisional_.insert(ids.begin(), ids.end());
    225   AddMany(ids, AddResultCallback());
    226 }
    227 
    228 void InstallVerifier::Remove(const std::string& id) {
    229   ExtensionIdSet ids;
    230   ids.insert(id);
    231   RemoveMany(ids);
    232 }
    233 
    234 void InstallVerifier::RemoveMany(const ExtensionIdSet& ids) {
    235   if (!signature_.get() || !ShouldFetchSignature())
    236     return;
    237 
    238   bool found_any = false;
    239   for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i) {
    240     if (ContainsKey(signature_->ids, *i)) {
    241       found_any = true;
    242       break;
    243     }
    244   }
    245   if (!found_any)
    246     return;
    247 
    248   InstallVerifier::PendingOperation* operation =
    249     new InstallVerifier::PendingOperation();
    250   operation->type = InstallVerifier::REMOVE;
    251   operation->ids = ids;
    252 
    253   operation_queue_.push(linked_ptr<PendingOperation>(operation));
    254   if (operation_queue_.size() == 1)
    255     BeginFetch();
    256 }
    257 
    258 std::string InstallVerifier::GetDebugPolicyProviderName() const {
    259   return std::string("InstallVerifier");
    260 }
    261 
    262 namespace {
    263 
    264 enum MustRemainDisabledOutcome {
    265   VERIFIED = 0,
    266   NOT_EXTENSION,
    267   UNPACKED,
    268   ENTERPRISE_POLICY_ALLOWED,
    269   FORCED_NOT_VERIFIED,
    270   NOT_FROM_STORE,
    271   NO_SIGNATURE,
    272   NOT_VERIFIED_BUT_NOT_ENFORCING,
    273   NOT_VERIFIED,
    274   NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE,
    275 
    276   // This is used in histograms - do not remove or reorder entries above! Also
    277   // the "MAX" item below should always be the last element.
    278   MUST_REMAIN_DISABLED_OUTCOME_MAX
    279 };
    280 
    281 void MustRemainDisabledHistogram(MustRemainDisabledOutcome outcome) {
    282   UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.MustRemainDisabled",
    283                             outcome, MUST_REMAIN_DISABLED_OUTCOME_MAX);
    284 }
    285 
    286 }  // namespace
    287 
    288 bool InstallVerifier::MustRemainDisabled(const Extension* extension,
    289                                          Extension::DisableReason* reason,
    290                                          base::string16* error) const {
    291   if (!CanUseExtensionApis(*extension)) {
    292     MustRemainDisabledHistogram(NOT_EXTENSION);
    293     return false;
    294   }
    295   if (Manifest::IsUnpackedLocation(extension->location())) {
    296     MustRemainDisabledHistogram(UNPACKED);
    297     return false;
    298   }
    299   if (AllowedByEnterprisePolicy(extension->id())) {
    300     MustRemainDisabledHistogram(ENTERPRISE_POLICY_ALLOWED);
    301     return false;
    302   }
    303 
    304   bool verified = true;
    305   MustRemainDisabledOutcome outcome = VERIFIED;
    306   if (ContainsKey(InstallSigner::GetForcedNotFromWebstore(), extension->id())) {
    307     verified = false;
    308     outcome = FORCED_NOT_VERIFIED;
    309   } else if (!FromStore(*extension)) {
    310     verified = false;
    311     outcome = NOT_FROM_STORE;
    312   } else if (signature_.get() == NULL) {
    313     // If we don't have a signature yet, we'll temporarily consider every
    314     // extension from the webstore verified to avoid false positives on existing
    315     // profiles hitting this code for the first time, and rely on consumers of
    316     // this class to check NeedsBootstrap() and schedule a first check so we can
    317     // get a signature.
    318     outcome = NO_SIGNATURE;
    319   } else if (!IsVerified(extension->id())) {
    320     if (WasInstalledAfterSignature(extension->id())) {
    321       outcome = NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE;
    322     } else {
    323       verified = false;
    324       outcome = NOT_VERIFIED;
    325     }
    326   }
    327   if (!verified && !ShouldEnforce()) {
    328     verified = true;
    329     outcome = NOT_VERIFIED_BUT_NOT_ENFORCING;
    330   }
    331   MustRemainDisabledHistogram(outcome);
    332 
    333   if (!verified) {
    334     if (reason)
    335       *reason = Extension::DISABLE_NOT_VERIFIED;
    336     if (error)
    337       *error = l10n_util::GetStringFUTF16(
    338           IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE,
    339           l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE));
    340   }
    341   return !verified;
    342 }
    343 
    344 InstallVerifier::PendingOperation::PendingOperation() {
    345   type = InstallVerifier::ADD;
    346 }
    347 
    348 InstallVerifier::PendingOperation::~PendingOperation() {
    349 }
    350 
    351 void InstallVerifier::GarbageCollect() {
    352   if (!ShouldFetchSignature()) {
    353     return;
    354   }
    355   CHECK(signature_.get());
    356   ExtensionIdSet leftovers = signature_->ids;
    357   ExtensionIdList all_ids;
    358   prefs_->GetExtensions(&all_ids);
    359   for (ExtensionIdList::const_iterator i = all_ids.begin();
    360        i != all_ids.end(); ++i) {
    361     ExtensionIdSet::iterator found = leftovers.find(*i);
    362     if (found != leftovers.end())
    363       leftovers.erase(found);
    364   }
    365   if (!leftovers.empty()) {
    366     RemoveMany(leftovers);
    367   }
    368 }
    369 
    370 bool InstallVerifier::AllowedByEnterprisePolicy(const std::string& id) const {
    371   PrefService* pref_service = prefs_->pref_service();
    372   if (pref_service->IsManagedPreference(prefs::kExtensionInstallAllowList)) {
    373     const base::ListValue* whitelist =
    374         pref_service->GetList(prefs::kExtensionInstallAllowList);
    375     base::StringValue id_value(id);
    376     if (whitelist && whitelist->Find(id_value) != whitelist->end())
    377       return true;
    378   }
    379   if (pref_service->IsManagedPreference(prefs::kExtensionInstallForceList)) {
    380     const base::DictionaryValue* forcelist =
    381         pref_service->GetDictionary(prefs::kExtensionInstallForceList);
    382     if (forcelist && forcelist->HasKey(id))
    383       return true;
    384   }
    385   return false;
    386 }
    387 
    388 bool InstallVerifier::IsVerified(const std::string& id) const {
    389   return ((signature_.get() && ContainsKey(signature_->ids, id)) ||
    390           ContainsKey(provisional_, id));
    391 }
    392 
    393 bool InstallVerifier::WasInstalledAfterSignature(const std::string& id) const {
    394   if (!signature_.get() || signature_->timestamp.is_null())
    395     return true;
    396 
    397   base::Time install_time = prefs_->GetInstallTime(id);
    398   // If the extension install time is in the future, just assume it isn't
    399   // newer than the signature. (Either the clock went backwards, or
    400   // an attacker changed the install time in the preferences).
    401   if (install_time >= base::Time::Now())
    402     return false;
    403   return install_time > signature_->timestamp;
    404 }
    405 
    406 void InstallVerifier::BeginFetch() {
    407   DCHECK(ShouldFetchSignature());
    408 
    409   // TODO(asargent) - It would be possible to coalesce all operations in the
    410   // queue into one fetch - we'd probably just need to change the queue to
    411   // hold (set of ids, list of callbacks) pairs.
    412   CHECK(!operation_queue_.empty());
    413   const PendingOperation& operation = *operation_queue_.front();
    414 
    415   ExtensionIdSet ids_to_sign;
    416   if (signature_.get()) {
    417     ids_to_sign.insert(signature_->ids.begin(), signature_->ids.end());
    418   }
    419   if (operation.type == InstallVerifier::ADD) {
    420     ids_to_sign.insert(operation.ids.begin(), operation.ids.end());
    421   } else {
    422     for (ExtensionIdSet::const_iterator i = operation.ids.begin();
    423          i != operation.ids.end(); ++i) {
    424       if (ContainsKey(ids_to_sign, *i))
    425         ids_to_sign.erase(*i);
    426     }
    427   }
    428 
    429   signer_.reset(new InstallSigner(context_getter_, ids_to_sign));
    430   signer_->GetSignature(base::Bind(&InstallVerifier::SignatureCallback,
    431                                    base::Unretained(this)));
    432 }
    433 
    434 void InstallVerifier::SaveToPrefs() {
    435   if (signature_.get())
    436     DCHECK(InstallSigner::VerifySignature(*signature_));
    437 
    438   if (!signature_.get() || signature_->ids.empty()) {
    439     DVLOG(1) << "SaveToPrefs - saving NULL";
    440     prefs_->SetInstallSignature(NULL);
    441   } else {
    442     DictionaryValue pref;
    443     signature_->ToValue(&pref);
    444     if (VLOG_IS_ON(1)) {
    445       DVLOG(1) << "SaveToPrefs - saving";
    446 
    447       DCHECK(InstallSigner::VerifySignature(*signature_.get()));
    448       scoped_ptr<InstallSignature> rehydrated =
    449           InstallSignature::FromValue(pref);
    450       DCHECK(InstallSigner::VerifySignature(*rehydrated.get()));
    451     }
    452     prefs_->SetInstallSignature(&pref);
    453   }
    454 }
    455 
    456 namespace {
    457 
    458 enum CallbackResult {
    459   CALLBACK_NO_SIGNATURE = 0,
    460   CALLBACK_INVALID_SIGNATURE,
    461   CALLBACK_VALID_SIGNATURE,
    462 
    463   // This is used in histograms - do not remove or reorder entries above! Also
    464   // the "MAX" item below should always be the last element.
    465 
    466   CALLBACK_RESULT_MAX
    467 };
    468 
    469 void GetSignatureResultHistogram(CallbackResult result) {
    470   UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.GetSignatureResult",
    471                             result, CALLBACK_RESULT_MAX);
    472 }
    473 
    474 }  // namespace
    475 
    476 void InstallVerifier::SignatureCallback(
    477     scoped_ptr<InstallSignature> signature) {
    478 
    479   linked_ptr<PendingOperation> operation = operation_queue_.front();
    480   operation_queue_.pop();
    481 
    482   bool success = false;
    483   if (!signature.get()) {
    484     GetSignatureResultHistogram(CALLBACK_NO_SIGNATURE);
    485   } else if (!InstallSigner::VerifySignature(*signature)) {
    486     GetSignatureResultHistogram(CALLBACK_INVALID_SIGNATURE);
    487   } else {
    488     GetSignatureResultHistogram(CALLBACK_VALID_SIGNATURE);
    489     success = true;
    490   }
    491 
    492   if (!success) {
    493     if (!operation->callback.is_null())
    494       operation->callback.Run(false);
    495 
    496     // TODO(asargent) - if this was something like a network error, we need to
    497     // do retries with exponential back off.
    498   } else {
    499     signature_ = signature.Pass();
    500     SaveToPrefs();
    501 
    502     if (!provisional_.empty()) {
    503       // Update |provisional_| to remove ids that were successfully signed.
    504       provisional_ = base::STLSetDifference<ExtensionIdSet>(
    505           provisional_, signature_->ids);
    506     }
    507 
    508     if (!operation->callback.is_null())
    509       operation->callback.Run(success);
    510   }
    511 
    512   if (!operation_queue_.empty())
    513     BeginFetch();
    514 }
    515 
    516 
    517 }  // namespace extensions
    518