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