Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Unified Diff: chrome/browser/policy/user_cloud_policy_store_chromeos.cc

Issue 12183017: Verify the signature on user cloud policy downloads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/policy/user_cloud_policy_store_chromeos.cc
diff --git a/chrome/browser/policy/user_cloud_policy_store_chromeos.cc b/chrome/browser/policy/user_cloud_policy_store_chromeos.cc
index 419a3f2d497dab9aaf5f9687b85a4c59767a5a49..803ea9a48197b4f8037a200262ddc5bc32c5ae2a 100644
--- a/chrome/browser/policy/user_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/policy/user_cloud_policy_store_chromeos.cc
@@ -11,10 +11,13 @@
#include "base/callback.h"
#include "base/file_util.h"
#include "base/memory/ref_counted.h"
+#include "base/stringprintf.h"
#include "chrome/browser/policy/proto/cloud_policy.pb.h"
#include "chrome/browser/policy/proto/device_management_local.pb.h"
#include "chrome/browser/policy/user_policy_disk_cache.h"
+#include "chrome/browser/policy/user_policy_key.h"
#include "chrome/browser/policy/user_policy_token_loader.h"
+#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/session_manager_client.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/gaia/gaia_auth_util.h"
@@ -30,6 +33,10 @@ const FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Device Management");
const FilePath::CharType kTokenCacheFile[] = FILE_PATH_LITERAL("Token");
// File in the above directory for storing user policy data.
const FilePath::CharType kPolicyCacheFile[] = FILE_PATH_LITERAL("Policy");
+// Path that contains the user policy key after the user's vault is mounted.
+// "%s" must be substituted with the sanitized username.
+const FilePath::CharType kPolicyKeyFile[] =
+ FILE_PATH_LITERAL("/var/run/user_policy/%s.pub");
Mattias Nissler (ping if slow) 2013/02/04 16:44:57 can we make user_policy/%s a directory? That'd all
Joao da Silva 2013/02/06 00:34:37 In progress at https://gerrit.chromium.org/gerrit/
} // namespace
@@ -146,11 +153,13 @@ CloudPolicyStore::Status LegacyPolicyCacheLoader::TranslateLoadResult(
}
UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS(
+ chromeos::CryptohomeClient* cryptohome_client,
chromeos::SessionManagerClient* session_manager_client,
const std::string& username,
const FilePath& legacy_token_cache_file,
const FilePath& legacy_policy_cache_file)
- : session_manager_client_(session_manager_client),
+ : cryptohome_client_(cryptohome_client),
+ session_manager_client_(session_manager_client),
username_(username),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
legacy_cache_dir_(legacy_token_cache_file.DirName()),
@@ -164,10 +173,12 @@ void UserCloudPolicyStoreChromeOS::Store(
const em::PolicyFetchResponse& policy) {
// Cancel all pending requests.
weak_factory_.InvalidateWeakPtrs();
- Validate(
- scoped_ptr<em::PolicyFetchResponse>(new em::PolicyFetchResponse(policy)),
- base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
- weak_factory_.GetWeakPtr()));
+ scoped_ptr<em::PolicyFetchResponse> response(
+ new em::PolicyFetchResponse(policy));
+ EnsurePolicyKeyLoaded(
+ base::Bind(&UserCloudPolicyStoreChromeOS::ValidatePolicyForStore,
+ weak_factory_.GetWeakPtr(),
+ base::Passed(&response)));
}
void UserCloudPolicyStoreChromeOS::Load() {
@@ -178,6 +189,64 @@ void UserCloudPolicyStoreChromeOS::Load() {
weak_factory_.GetWeakPtr()));
}
+void UserCloudPolicyStoreChromeOS::ValidatePolicyForStore(
+ scoped_ptr<em::PolicyFetchResponse> policy) {
+ // Create and configure a validator.
+ scoped_ptr<UserCloudPolicyValidator> validator =
+ CreateValidator(policy.Pass());
+ validator->ValidateUsername(username_);
+ if (policy_key_->key().empty()) {
+ validator->ValidateInitialKey();
+ } else {
+ const bool allow_rotation = true;
+ validator->ValidateSignature(policy_key_->key(), allow_rotation);
+ }
+
+ // Start validation. The Validator will free itself once validation is
+ // complete.
+ validator.release()->StartValidation(
+ base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
+ weak_factory_.GetWeakPtr()));
+}
+
+void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
+ UserCloudPolicyValidator* validator) {
+ validation_status_ = validator->status();
+ if (!validator->success()) {
+ status_ = STATUS_VALIDATION_ERROR;
+ NotifyStoreError();
+ return;
+ }
+
+ std::string policy_blob;
+ if (!validator->policy()->SerializeToString(&policy_blob)) {
+ status_ = STATUS_SERIALIZE_ERROR;
+ NotifyStoreError();
+ return;
+ }
+
+ session_manager_client_->StoreUserPolicy(
+ policy_blob,
+ base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored,
+ weak_factory_.GetWeakPtr()));
+}
+
+void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) {
+ if (!success) {
+ status_ = STATUS_STORE_ERROR;
+ NotifyStoreError();
+ } else {
+ // Load the policy right after storing it, to make sure it was accepted by
+ // the session manager. An additional validation is performed after the
+ // load; reload the key for that validation too, in case it was rotated.
+ // This method is the callback for a store operation, which is posted after
+ // validating the policy, and the validation is performed after ensuring the
+ // key is loaded, so |policy_key_| is valid here.
+ policy_key_->Load(base::Bind(&UserCloudPolicyStoreChromeOS::Load,
+ weak_factory_.GetWeakPtr()));
+ }
+}
+
void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved(
const std::string& policy_blob) {
if (policy_blob.empty()) {
@@ -206,9 +275,26 @@ void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved(
return;
}
- Validate(policy.Pass(),
- base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated,
- weak_factory_.GetWeakPtr()));
+ // Load |policy_key_| to verify the loaded policy.
+ EnsurePolicyKeyLoaded(
+ base::Bind(&UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy,
+ weak_factory_.GetWeakPtr(),
+ base::Passed(&policy)));
+}
+
+void UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy(
+ scoped_ptr<em::PolicyFetchResponse> policy) {
+ // Create and configure a validator for the loaded policy.
+ scoped_ptr<UserCloudPolicyValidator> validator =
+ CreateValidator(policy.Pass());
+ validator->ValidateUsername(username_);
+ const bool allow_rotation = false;
+ validator->ValidateSignature(policy_key_->key(), allow_rotation);
+ // Start validation. The Validator will free itself once validation is
+ // complete.
+ validator.release()->StartValidation(
+ base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated,
+ weak_factory_.GetWeakPtr()));
}
void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
@@ -235,56 +321,6 @@ void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
NotifyStoreLoaded();
}
-void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
- UserCloudPolicyValidator* validator) {
- validation_status_ = validator->status();
- if (!validator->success()) {
- status_ = STATUS_VALIDATION_ERROR;
- NotifyStoreError();
- return;
- }
-
- std::string policy_blob;
- if (!validator->policy()->SerializeToString(&policy_blob)) {
- status_ = STATUS_SERIALIZE_ERROR;
- NotifyStoreError();
- return;
- }
-
- session_manager_client_->StoreUserPolicy(
- policy_blob,
- base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored,
- weak_factory_.GetWeakPtr()));
-}
-
-void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) {
- if (!success) {
- status_ = STATUS_STORE_ERROR;
- NotifyStoreError();
- } else {
- // TODO(mnissler): Once we do signature verifications, we'll have to reload
- // the key at this point to account for key rotations.
- Load();
- }
-}
-
-void UserCloudPolicyStoreChromeOS::Validate(
- scoped_ptr<em::PolicyFetchResponse> policy,
- const UserCloudPolicyValidator::CompletionCallback& callback) {
- // Configure the validator.
- scoped_ptr<UserCloudPolicyValidator> validator =
- CreateValidator(policy.Pass());
- validator->ValidateUsername(username_);
-
- // TODO(mnissler): Do a signature check here as well. The key is stored by
- // session_manager in the root-owned cryptohome area, which is currently
- // inaccessible to Chrome though.
-
- // Start validation. The Validator will free itself once validation is
- // complete.
- validator.release()->StartValidation(callback);
-}
-
void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished(
const std::string& dm_token,
const std::string& device_id,
@@ -292,10 +328,16 @@ void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished(
scoped_ptr<em::PolicyFetchResponse> policy) {
status_ = status;
if (policy.get()) {
- Validate(policy.Pass(),
- base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated,
- weak_factory_.GetWeakPtr(),
- dm_token, device_id));
+ // Create and configure a validator for the loaded legacy policy. Note that
+ // the signature on this policy is not verified.
+ scoped_ptr<UserCloudPolicyValidator> validator =
+ CreateValidator(policy.Pass());
+ validator->ValidateUsername(username_);
+ validator.release()->StartValidation(
+ base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated,
+ weak_factory_.GetWeakPtr(),
+ dm_token,
+ device_id));
} else {
InstallLegacyTokens(dm_token, device_id);
}
@@ -308,8 +350,7 @@ void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated(
validation_status_ = validator->status();
if (validator->success()) {
status_ = STATUS_OK;
- InstallPolicy(validator->policy_data().Pass(),
- validator->payload().Pass());
+ InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
// Clear the public key version. The public key version field would
// otherwise indicate that we have key installed in the store when in fact
@@ -346,4 +387,37 @@ void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(const FilePath& dir) {
LOG(ERROR) << "Failed to remove cache dir " << dir.value();
}
+void UserCloudPolicyStoreChromeOS::EnsurePolicyKeyLoaded(
+ const base::Closure& callback) {
+ if (policy_key_) {
+ callback.Run();
+ } else {
+ // Get the hashed username that's part of the key's path, to create a new
+ // |policy_key_| later.
+ cryptohome_client_->GetSanitizedUsername(username_,
+ base::Bind(&UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername,
+ weak_factory_.GetWeakPtr(),
+ callback));
+ }
+}
+
+void UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername(
+ const base::Closure& callback,
+ chromeos::DBusMethodCallStatus call_status,
+ const std::string& sanitized_username) {
+ // EnsurePolicyKeyLoaded() may have been called twice before getting a reply
+ // from dbus; the second request will just reload the key.
+ if (!policy_key_) {
+ // The default empty path will always yield an empty key.
+ FilePath path;
+ if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS &&
+ !sanitized_username.empty()) {
+ path = FilePath(
+ base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
+ }
+ policy_key_.reset(new UserPolicyKey(path));
+ }
+ policy_key_->Load(callback);
+}
+
} // namespace policy

Powered by Google App Engine
This is Rietveld 408576698