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

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: rebased 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 07c247a351a6fb42c2bf016fb57053cfd6edb52a..77eb0fe9e489af429f81d30f8391b601c5a7f98b 100644
--- a/chrome/browser/policy/user_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/policy/user_cloud_policy_store_chromeos.cc
@@ -4,17 +4,19 @@
#include "chrome/browser/policy/user_cloud_policy_store_chromeos.h"
-#include <string>
-
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/file_util.h"
+#include "base/logging.h"
#include "base/memory/ref_counted.h"
+#include "base/stl_util.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_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"
@@ -24,15 +26,16 @@ namespace em = enterprise_management;
namespace policy {
namespace {
-// Subdirectory in the user's profile for storing user policies.
-const base::FilePath::CharType kPolicyDir[] =
- FILE_PATH_LITERAL("Device Management");
-// File in the above directory for stroing user policy dmtokens.
-const base::FilePath::CharType kTokenCacheFile[] = FILE_PATH_LITERAL("Token");
-// File in the above directory for storing user policy data.
-const base::FilePath::CharType kPolicyCacheFile[] = FILE_PATH_LITERAL("Policy");
-} // namespace
+// Path within |user_policy_key_dir_| that contains the policy key.
+// "%s" must be substituted with the sanitized username.
+const base::FilePath::CharType kPolicyKeyFile[] =
+ FILE_PATH_LITERAL("%s/policy.pub");
+
+// Maximum key size that will be loaded, in bytes.
+const int kKeySizeLimit = 16 * 1024;
+
+} // namespace
// Helper class for loading legacy policy caches.
class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate,
@@ -147,17 +150,22 @@ CloudPolicyStore::Status LegacyPolicyCacheLoader::TranslateLoadResult(
}
UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS(
+ chromeos::CryptohomeClient* cryptohome_client,
chromeos::SessionManagerClient* session_manager_client,
const std::string& username,
+ const base::FilePath& user_policy_key_dir,
const base::FilePath& legacy_token_cache_file,
const base::FilePath& legacy_policy_cache_file)
- : session_manager_client_(session_manager_client),
+ : cryptohome_client_(cryptohome_client),
+ session_manager_client_(session_manager_client),
username_(username),
+ user_policy_key_dir_(user_policy_key_dir),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
legacy_cache_dir_(legacy_token_cache_file.DirName()),
legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file,
legacy_policy_cache_file)),
- legacy_caches_loaded_(false) {}
+ legacy_caches_loaded_(false),
+ policy_key_loaded_(false) {}
UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {}
@@ -165,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() {
@@ -179,6 +189,61 @@ 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_.empty()) {
+ validator->ValidateInitialKey();
+ } else {
+ const bool allow_rotation = true;
+ validator->ValidateSignature(policy_key_, allow_rotation);
+ }
+
+ // Start validation. The Validator will delete 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.
+ ReloadPolicyKey(base::Bind(&UserCloudPolicyStoreChromeOS::Load,
+ weak_factory_.GetWeakPtr()));
+ }
+}
+
void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved(
const std::string& policy_blob) {
if (policy_blob.empty()) {
@@ -207,9 +272,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_, allow_rotation);
+ // Start validation. The Validator will delete itself once validation is
+ // complete.
+ validator.release()->StartValidation(
+ base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated,
+ weak_factory_.GetWeakPtr()));
}
void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
@@ -236,56 +318,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,
@@ -293,10 +325,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);
}
@@ -309,8 +347,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
@@ -348,4 +385,77 @@ void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(
LOG(ERROR) << "Failed to remove cache dir " << dir.value();
}
+void UserCloudPolicyStoreChromeOS::ReloadPolicyKey(
+ const base::Closure& callback) {
+ std::vector<uint8>* key = new std::vector<uint8>();
+ content::BrowserThread::PostBlockingPoolTaskAndReply(
+ FROM_HERE,
+ base::Bind(&UserCloudPolicyStoreChromeOS::LoadPolicyKey,
+ policy_key_path_,
+ key),
+ base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded,
+ weak_factory_.GetWeakPtr(),
+ base::Owned(key),
+ callback));
+}
+
+// static
+void UserCloudPolicyStoreChromeOS::LoadPolicyKey(const base::FilePath& path,
+ std::vector<uint8>* key) {
+ if (!file_util::PathExists(path)) {
+ VLOG(1) << "No key at " << path.value();
+ return;
+ }
+
+ int64 size;
+ if (!file_util::GetFileSize(path, &size)) {
+ LOG(ERROR) << "Could not get size of " << path.value();
+ } else if (size == 0 || size > kKeySizeLimit) {
+ LOG(ERROR) << "Key at " << path.value() << " has bad size " << size;
+ } else {
+ key->resize(size);
+ int read_size = file_util::ReadFile(
+ path, reinterpret_cast<char*>(vector_as_array(key)), size);
+ if (read_size != size) {
+ LOG(ERROR) << "Failed to read key at " << path.value();
+ key->clear();
+ }
+ }
+}
+
+void UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded(
+ std::vector<uint8>* key,
+ const base::Closure& callback) {
+ policy_key_.swap(*key);
+ policy_key_loaded_ = true;
+ callback.Run();
+}
+
+void UserCloudPolicyStoreChromeOS::EnsurePolicyKeyLoaded(
+ const base::Closure& callback) {
+ if (policy_key_loaded_) {
+ callback.Run();
+ } else {
+ // Get the hashed username that's part of the key's path, to determine
+ // |policy_key_path_|.
+ 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) {
+ // The default empty path will always yield an empty key.
+ if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS &&
+ !sanitized_username.empty()) {
+ policy_key_path_ = user_policy_key_dir_.Append(
+ base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
+ }
+ ReloadPolicyKey(callback);
+}
+
} // namespace policy

Powered by Google App Engine
This is Rietveld 408576698