Commit dc3eb775 authored by atwilson@chromium.org's avatar atwilson@chromium.org

No longer accept unsigned cloud policy blobs.

UMA stats show that >99% of users have migrated to signed cloud policy blobs,
so it's time to stop supporting unsigned blobs - anyone who still has an
unsigned blob on their machine will go through a policy refresh on their
next restart.

BUG=404664

Review URL: https://codereview.chromium.org/491513002

Cr-Commit-Position: refs/heads/master@{#290801}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@290801 0039d316-1c4b-4281-b951-d872f2087c98
parent bb338dd1
......@@ -339,9 +339,6 @@ void UserCloudPolicyStore::Validate(
const std::string& verification_key,
bool validate_in_background,
const UserCloudPolicyValidator::CompletionCallback& callback) {
const bool signed_policy = policy->has_policy_data_signature();
// Configure the validator.
scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(
policy.Pass(),
......@@ -368,8 +365,8 @@ void UserCloudPolicyStore::Validate(
// There are 4 cases:
//
// 1) Validation after loading from cache with no cached key.
// Action: Don't validate signature (migration from previously cached
// unsigned blob).
// Action: Just validate signature with an empty key - this will result in
// a failed validation and the cached policy will be rejected.
//
// 2) Validation after loading from cache with a cached key
// Action: Validate signature on policy blob but don't allow key rotation.
......@@ -381,27 +378,25 @@ void UserCloudPolicyStore::Validate(
// 4) Validation after loading new policy from the server with a cached key
// Action: Validate as normal, and allow key rotation.
if (cached_key) {
// Case #1/#2 - loading from cache. Validate the cached key (if no key,
// then the validation will fail), then do normal policy data signature
// validation using the cached key.
// Loading from cache should not change the cached keys.
DCHECK(policy_key_.empty() || policy_key_ == cached_key->signing_key());
if (!signed_policy || !cached_key->has_signing_key()) {
// Case #1 - loading from cache with no signing key.
// TODO(atwilson): Reject policy with no cached key once
// kMetricPolicyHasVerifiedCachedKey rises to a high enough level.
DLOG(WARNING) << "Allowing unsigned cached blob for migration";
} else {
// Case #2 - loading from cache with a cached key - validate the cached
// key, then do normal policy data signature validation using the cached
// key. We're loading from cache so don't allow key rotation.
validator->ValidateCachedKey(cached_key->signing_key(),
cached_key->signing_key_signature(),
verification_key,
owning_domain);
const bool no_rotation = false;
validator->ValidateSignature(cached_key->signing_key(),
verification_key,
owning_domain,
no_rotation);
}
DLOG_IF(WARNING, !cached_key->has_signing_key()) <<
"Unsigned policy blob detected";
validator->ValidateCachedKey(cached_key->signing_key(),
cached_key->signing_key_signature(),
verification_key,
owning_domain);
// Loading from cache, so don't allow key rotation.
const bool no_rotation = false;
validator->ValidateSignature(cached_key->signing_key(),
verification_key,
owning_domain,
no_rotation);
} else {
// No passed cached_key - this is not validating the initial policy load
// from cache, but rather an update from the server.
......
......@@ -207,8 +207,8 @@ TEST_F(UserCloudPolicyStoreTest, LoadImmediatelyWithInvalidFile) {
EXPECT_TRUE(store_->policy_map().empty());
}
// Load file from cache with no key data, then migrate to have a key.
TEST_F(UserCloudPolicyStoreTest, Migration) {
// Load file from cache with no key data - should give us a validation error.
TEST_F(UserCloudPolicyStoreTest, ShouldFailToLoadUnsignedPolicy) {
UserPolicyBuilder unsigned_builder;
unsigned_builder.UnsetSigningKey();
InitPolicyPayload(&unsigned_builder.payload());
......@@ -223,22 +223,11 @@ TEST_F(UserCloudPolicyStoreTest, Migration) {
int size = data.size();
ASSERT_EQ(size, base::WriteFile(policy_file(), data.c_str(), size));
// Now make sure the data can get loaded.
Sequence s;
EXPECT_CALL(*external_data_manager_, OnPolicyStoreLoaded()).InSequence(s);
EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).InSequence(s);
// Now make sure the data generates a validation error.
ExpectError(store_.get(), CloudPolicyStore::STATUS_VALIDATION_ERROR);
store_->LoadImmediately(); // Should load without running the message loop.
Mock::VerifyAndClearExpectations(external_data_manager_.get());
Mock::VerifyAndClearExpectations(&observer_);
ASSERT_TRUE(store_->policy());
EXPECT_EQ(unsigned_builder.policy_data().SerializeAsString(),
store_->policy()->SerializeAsString());
VerifyPolicyMap(store_.get());
EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
EXPECT_TRUE(store_->policy_key().empty());
EXPECT_FALSE(base::PathExists(key_file()));
// Now mimic a new policy coming down - this should result in a new key
// being installed.
StorePolicyAndEnsureLoaded(policy_.policy());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment