summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorasargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-13 00:00:38 +0000
committerasargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-13 00:00:38 +0000
commit33dc0c6e1118ce4a738ca96278d11261b2eee64c (patch)
tree490c08f31962366fd91571114dae32592b6ec4ba
parent82792996a329f3f364c36c1fa331b100bca49568 (diff)
downloadchromium_src-33dc0c6e1118ce4a738ca96278d11261b2eee64c.zip
chromium_src-33dc0c6e1118ce4a738ca96278d11261b2eee64c.tar.gz
chromium_src-33dc0c6e1118ce4a738ca96278d11261b2eee64c.tar.bz2
Don't disable extensions immediately if verification is out of date
If the install verification signature we have stored in our prefs is older than the install time of an extension, we don't want to immediately disable it. Instead, we want to do another server request to update our signature, and then disable if appropriate. BUG=342165 R=finnur@chromium.org Review URL: https://codereview.chromium.org/160313002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@250855 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/extension_service.cc34
-rw-r--r--chrome/browser/extensions/extension_service.h3
-rw-r--r--chrome/browser/extensions/install_signer.cc18
-rw-r--r--chrome/browser/extensions/install_signer.h6
-rw-r--r--chrome/browser/extensions/install_verifier.cc30
-rw-r--r--chrome/browser/extensions/install_verifier.h7
6 files changed, 91 insertions, 7 deletions
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index db32e5a..137071b 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -574,10 +574,7 @@ void ExtensionService::Init() {
// rather than running immediately at startup.
CheckForExternalUpdates();
- InstallVerifier* verifier =
- extensions::ExtensionSystem::Get(profile_)->install_verifier();
- if (verifier->NeedsBootstrap())
- VerifyAllExtensions(true); // bootstrap=true.
+ MaybeBootstrapVerifier();
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&ExtensionService::GarbageCollectExtensions, AsWeakPtr()),
@@ -611,6 +608,35 @@ void ExtensionService::LoadGreylistFromPrefs() {
}
}
+void ExtensionService::MaybeBootstrapVerifier() {
+ InstallVerifier* verifier =
+ extensions::ExtensionSystem::Get(profile_)->install_verifier();
+ bool do_bootstrap = false;
+
+ if (verifier->NeedsBootstrap()) {
+ do_bootstrap = true;
+ } else {
+ // If any of the installed extensions have an install time newer than the
+ // signature's timestamp, we need to bootstrap because our signature may
+ // be missing valid extensions.
+ base::Time timestamp = verifier->SignatureTimestamp();
+ for (extensions::ExtensionSet::const_iterator i = extensions()->begin();
+ i != extensions()->end();
+ ++i) {
+ const Extension& extension = **i;
+ base::Time install_time =
+ extension_prefs_->GetInstallTime(extension.id());
+ if (verifier->NeedsVerification(extension) &&
+ install_time < base::Time::Now() && install_time >= timestamp) {
+ do_bootstrap = true;
+ break;
+ }
+ }
+ }
+ if (do_bootstrap)
+ VerifyAllExtensions(true); // bootstrap=true.
+}
+
void ExtensionService::VerifyAllExtensions(bool bootstrap) {
ExtensionIdSet to_add;
scoped_ptr<ExtensionSet> all_extensions = GenerateInstalledExtensionsSet();
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index eaf9af2..0d801a4 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -196,6 +196,9 @@ class ExtensionService
// Initialize and start all installed extensions.
void Init();
+ // See if we need to bootstrap the install verifier.
+ void MaybeBootstrapVerifier();
+
// Attempts to verify all extensions using the InstallVerifier. The
// |bootstrap| parameter indicates whether we're doing this because the
// InstallVerifier needed to be bootstrapped (otherwise it's for another
diff --git a/chrome/browser/extensions/install_signer.cc b/chrome/browser/extensions/install_signer.cc
index 8e6da408..d7f74c0 100644
--- a/chrome/browser/extensions/install_signer.cc
+++ b/chrome/browser/extensions/install_signer.cc
@@ -48,6 +48,7 @@ const char kInvalidIdsKey[] = "invalid_ids";
const char kProtocolVersionKey[] = "protocol_version";
const char kSaltKey[] = "salt";
const char kSignatureKey[] = "signature";
+const char kTimestampKey[] = "timestamp";
const size_t kSaltBytes = 32;
@@ -133,6 +134,8 @@ void InstallSignature::ToValue(base::DictionaryValue* value) const {
base::Base64Encode(signature, &signature_base64);
value->SetString(kSaltKey, salt_base64);
value->SetString(kSignatureKey, signature_base64);
+ value->SetString(kTimestampKey,
+ base::Int64ToString(timestamp.ToInternalValue()));
}
// static
@@ -152,6 +155,19 @@ scoped_ptr<InstallSignature> InstallSignature::FromValue(
return result.Pass();
}
+ // Note: earlier versions of the code did not write out a timestamp value
+ // so older entries will not necessarily have this.
+ if (value.HasKey(kTimestampKey)) {
+ std::string timestamp;
+ int64 timestamp_value = 0;
+ if (!value.GetString(kTimestampKey, &timestamp) ||
+ !base::StringToInt64(timestamp, &timestamp_value)) {
+ result.reset();
+ return result.Pass();
+ }
+ result->timestamp = base::Time::FromInternalValue(timestamp_value);
+ }
+
const base::ListValue* ids = NULL;
if (!value.GetList(kIdsKey, &ids)) {
result.reset();
@@ -343,6 +359,7 @@ void InstallSigner::GetSignature(const SignatureCallback& callback) {
}
url_fetcher_->SetUploadData("application/json", json);
LogRequestStartHistograms();
+ request_start_time_ = base::Time::Now();
url_fetcher_->Start();
}
@@ -437,6 +454,7 @@ void InstallSigner::HandleSignatureResult(const std::string& signature,
result->salt = salt_;
result->signature = signature;
result->expire_date = expire_date;
+ result->timestamp = request_start_time_;
bool verified = VerifySignature(*result);
UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.ResultWasValid", verified);
UMA_HISTOGRAM_COUNTS_100("ExtensionInstallSigner.InvalidCount",
diff --git a/chrome/browser/extensions/install_signer.h b/chrome/browser/extensions/install_signer.h
index 988f6e6..a6177c4 100644
--- a/chrome/browser/extensions/install_signer.h
+++ b/chrome/browser/extensions/install_signer.h
@@ -38,6 +38,9 @@ struct InstallSignature {
// The date that the signature should expire, in YYYY-MM-DD format.
std::string expire_date;
+ // The time this signature was obtained from the server.
+ base::Time timestamp;
+
InstallSignature();
~InstallSignature();
@@ -109,6 +112,9 @@ class InstallSigner {
scoped_ptr<net::URLFetcher> url_fetcher_;
scoped_ptr<FetcherDelegate> delegate_;
+ // The time the request to the server was started.
+ base::Time request_start_time_;
+
DISALLOW_COPY_AND_ASSIGN(InstallSigner);
};
diff --git a/chrome/browser/extensions/install_verifier.cc b/chrome/browser/extensions/install_verifier.cc
index 642457d..1f6e824 100644
--- a/chrome/browser/extensions/install_verifier.cc
+++ b/chrome/browser/extensions/install_verifier.cc
@@ -176,6 +176,13 @@ bool InstallVerifier::NeedsBootstrap() {
return signature_.get() == NULL && ShouldFetchSignature();
}
+base::Time InstallVerifier::SignatureTimestamp() {
+ if (signature_.get())
+ return signature_->timestamp;
+ else
+ return base::Time();
+}
+
void InstallVerifier::Add(const std::string& id,
const AddResultCallback& callback) {
ExtensionIdSet ids;
@@ -265,10 +272,10 @@ enum MustRemainDisabledOutcome {
NO_SIGNATURE,
NOT_VERIFIED_BUT_NOT_ENFORCING,
NOT_VERIFIED,
+ NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE,
// This is used in histograms - do not remove or reorder entries above! Also
// the "MAX" item below should always be the last element.
-
MUST_REMAIN_DISABLED_OUTCOME_MAX
};
@@ -312,8 +319,12 @@ bool InstallVerifier::MustRemainDisabled(const Extension* extension,
// get a signature.
outcome = NO_SIGNATURE;
} else if (!IsVerified(extension->id())) {
- verified = false;
- outcome = NOT_VERIFIED;
+ if (WasInstalledAfterSignature(extension->id())) {
+ outcome = NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE;
+ } else {
+ verified = false;
+ outcome = NOT_VERIFIED;
+ }
}
if (!verified && !ShouldEnforce()) {
verified = true;
@@ -381,6 +392,19 @@ bool InstallVerifier::IsVerified(const std::string& id) const {
ContainsKey(provisional_, id));
}
+bool InstallVerifier::WasInstalledAfterSignature(const std::string& id) const {
+ if (!signature_.get() || signature_->timestamp.is_null())
+ return true;
+
+ base::Time install_time = prefs_->GetInstallTime(id);
+ // If the extension install time is in the future, just assume it isn't
+ // newer than the signature. (Either the clock went backwards, or
+ // an attacker changed the install time in the preferences).
+ if (install_time >= base::Time::Now())
+ return false;
+ return install_time > signature_->timestamp;
+}
+
void InstallVerifier::BeginFetch() {
DCHECK(ShouldFetchSignature());
diff --git a/chrome/browser/extensions/install_verifier.h b/chrome/browser/extensions/install_verifier.h
index 522c508..7c7c3ee 100644
--- a/chrome/browser/extensions/install_verifier.h
+++ b/chrome/browser/extensions/install_verifier.h
@@ -53,6 +53,9 @@ class InstallVerifier : public ManagementPolicy::Provider {
// an initial one so that MustRemainDisabled can actually check against it.
bool NeedsBootstrap();
+ // Returns the timestamp of our InstallSignature, if we have one.
+ base::Time SignatureTimestamp();
+
// A callback for indicating success/failure of adding new ids.
typedef base::Callback<void(bool)> AddResultCallback;
@@ -107,6 +110,10 @@ class InstallVerifier : public ManagementPolicy::Provider {
// Returns whether the given |id| is included in our verified signature.
bool IsVerified(const std::string& id) const;
+ // Returns true if the extension with |id| was installed later than the
+ // timestamp of our signature.
+ bool WasInstalledAfterSignature(const std::string& id) const;
+
// Begins the process of fetching a new signature, based on applying the
// operation at the head of the queue to the current set of ids in
// |signature_| (if any) and then sending a request to sign that.