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