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.
5 #include "components/policy/core/common/cloud/user_cloud_policy_store.h"
8 #include "base/file_util.h"
9 #include "base/location.h"
10 #include "base/metrics/histogram.h"
11 #include "base/task_runner_util.h"
12 #include "google_apis/gaia/gaia_auth_util.h"
13 #include "policy/proto/cloud_policy.pb.h"
14 #include "policy/proto/device_management_backend.pb.h"
15 #include "policy/proto/policy_signing_key.pb.h"
17 namespace em = enterprise_management;
21 enum PolicyLoadStatus {
22 // Policy blob was successfully loaded and parsed.
25 // No previously stored policy was found.
26 LOAD_RESULT_NO_POLICY_FILE,
28 // Could not load the previously stored policy due to either a parse or
30 LOAD_RESULT_LOAD_ERROR,
33 // Struct containing the result of a policy load - if |status| ==
34 // LOAD_RESULT_SUCCESS, |policy| is initialized from the policy file on disk.
35 struct PolicyLoadResult {
36 PolicyLoadStatus status;
37 em::PolicyFetchResponse policy;
38 em::PolicySigningKey key;
43 // Subdirectory in the user's profile for storing user policies.
44 const base::FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Policy");
45 // File in the above directory for storing user policy data.
46 const base::FilePath::CharType kPolicyCacheFile[] =
47 FILE_PATH_LITERAL("User Policy");
49 // File in the above directory for storing policy signing key data.
50 const base::FilePath::CharType kKeyCacheFile[] =
51 FILE_PATH_LITERAL("Signing Key");
53 const char kMetricPolicyHasVerifiedCachedKey[] =
54 "Enterprise.PolicyHasVerifiedCachedKey";
56 // Loads policy from the backing file. Returns a PolicyLoadResult with the
57 // results of the fetch.
58 policy::PolicyLoadResult LoadPolicyFromDisk(
59 const base::FilePath& policy_path,
60 const base::FilePath& key_path) {
61 policy::PolicyLoadResult result;
62 // If the backing file does not exist, just return. We don't verify the key
63 // path here, because the key is optional (the validation code will fail if
64 // the key does not exist but the loaded policy is unsigned).
65 if (!base::PathExists(policy_path)) {
66 result.status = policy::LOAD_RESULT_NO_POLICY_FILE;
70 // TODO(atwilson): Enforce a policy/key maxsize when ReadFileToString() can
71 // accept a max_size (http://crbug.com/339417).
72 if (!base::ReadFileToString(policy_path, &data) ||
73 !result.policy.ParseFromString(data)) {
74 LOG(WARNING) << "Failed to read or parse policy data from "
75 << policy_path.value();
76 result.status = policy::LOAD_RESULT_LOAD_ERROR;
80 if (!base::ReadFileToString(key_path, &data) ||
81 !result.key.ParseFromString(data)) {
82 // Log an error on missing key data, but do not trigger a load failure
83 // for now since there are still old unsigned cached policy blobs in the
84 // wild with no associated key (see kMetricPolicyHasVerifiedCachedKey UMA
86 LOG(ERROR) << "Failed to read or parse key data from " << key_path.value();
87 result.key.clear_signing_key();
90 // Track the occurrence of valid cached keys - when this ratio gets high
91 // enough, we can update the code to reject unsigned policy or unverified
93 UMA_HISTOGRAM_BOOLEAN(kMetricPolicyHasVerifiedCachedKey,
94 result.key.has_signing_key());
96 result.status = policy::LOAD_RESULT_SUCCESS;
100 bool WriteStringToFile(const base::FilePath path, const std::string& data) {
101 if (!base::CreateDirectory(path.DirName())) {
102 DLOG(WARNING) << "Failed to create directory " << path.DirName().value();
106 int size = data.size();
107 if (file_util::WriteFile(path, data.c_str(), size) != size) {
108 DLOG(WARNING) << "Failed to write " << path.value();
115 // Stores policy to the backing file (must be called via a task on
116 // the background thread).
117 void StorePolicyToDiskOnBackgroundThread(
118 const base::FilePath& policy_path,
119 const base::FilePath& key_path,
120 const std::string& verification_key,
121 const em::PolicyFetchResponse& policy) {
122 DVLOG(1) << "Storing policy to " << policy_path.value();
124 if (!policy.SerializeToString(&data)) {
125 DLOG(WARNING) << "Failed to serialize policy data";
129 if (!WriteStringToFile(policy_path, data))
132 if (policy.has_new_public_key()) {
133 // Write the new public key and its verification signature/key to a file.
134 em::PolicySigningKey key_info;
135 key_info.set_signing_key(policy.new_public_key());
136 key_info.set_signing_key_signature(
137 policy.new_public_key_verification_signature());
138 key_info.set_verification_key(verification_key);
139 std::string key_data;
140 if (!key_info.SerializeToString(&key_data)) {
141 DLOG(WARNING) << "Failed to serialize policy signing key";
145 WriteStringToFile(key_path, key_data);
151 UserCloudPolicyStore::UserCloudPolicyStore(
152 const base::FilePath& policy_path,
153 const base::FilePath& key_path,
154 const std::string& verification_key,
155 scoped_refptr<base::SequencedTaskRunner> background_task_runner)
156 : UserCloudPolicyStoreBase(background_task_runner),
158 policy_path_(policy_path),
160 verification_key_(verification_key) {}
162 UserCloudPolicyStore::~UserCloudPolicyStore() {}
165 scoped_ptr<UserCloudPolicyStore> UserCloudPolicyStore::Create(
166 const base::FilePath& profile_path,
167 const std::string& verification_key,
168 scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
169 base::FilePath policy_path =
170 profile_path.Append(kPolicyDir).Append(kPolicyCacheFile);
171 base::FilePath key_path =
172 profile_path.Append(kPolicyDir).Append(kKeyCacheFile);
173 return make_scoped_ptr(new UserCloudPolicyStore(
174 policy_path, key_path, verification_key, background_task_runner));
177 void UserCloudPolicyStore::SetSigninUsername(const std::string& username) {
178 signin_username_ = username;
181 void UserCloudPolicyStore::LoadImmediately() {
182 DVLOG(1) << "Initiating immediate policy load from disk";
183 // Cancel any pending Load/Store/Validate operations.
184 weak_factory_.InvalidateWeakPtrs();
185 // Load the policy from disk...
186 PolicyLoadResult result = LoadPolicyFromDisk(policy_path_, key_path_);
187 // ...and install it, reporting success/failure to any observers.
188 PolicyLoaded(false, result);
191 void UserCloudPolicyStore::Clear() {
192 background_task_runner()->PostTask(
194 base::Bind(base::IgnoreResult(&base::DeleteFile), policy_path_, false));
195 background_task_runner()->PostTask(
197 base::Bind(base::IgnoreResult(&base::DeleteFile), key_path_, false));
204 void UserCloudPolicyStore::Load() {
205 DVLOG(1) << "Initiating policy load from disk";
206 // Cancel any pending Load/Store/Validate operations.
207 weak_factory_.InvalidateWeakPtrs();
209 // Start a new Load operation and have us get called back when it is
211 base::PostTaskAndReplyWithResult(
212 background_task_runner(),
214 base::Bind(&LoadPolicyFromDisk, policy_path_, key_path_),
215 base::Bind(&UserCloudPolicyStore::PolicyLoaded,
216 weak_factory_.GetWeakPtr(), true));
219 void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background,
220 PolicyLoadResult result) {
221 switch (result.status) {
222 case LOAD_RESULT_LOAD_ERROR:
223 status_ = STATUS_LOAD_ERROR;
227 case LOAD_RESULT_NO_POLICY_FILE:
228 DVLOG(1) << "No policy found on disk";
232 case LOAD_RESULT_SUCCESS: {
233 // Found policy on disk - need to validate it before it can be used.
234 scoped_ptr<em::PolicyFetchResponse> cloud_policy(
235 new em::PolicyFetchResponse(result.policy));
236 scoped_ptr<em::PolicySigningKey> key(
237 new em::PolicySigningKey(result.key));
239 bool doing_key_rotation = false;
240 const std::string& verification_key = verification_key_;
241 if (!key->has_verification_key() ||
242 key->verification_key() != verification_key_) {
243 // The cached key didn't match our current key, so we're doing a key
244 // rotation - make sure we request a new key from the server on our
246 doing_key_rotation = true;
247 DLOG(WARNING) << "Verification key rotation detected";
248 // TODO(atwilson): Add code to update |verification_key| to point to
249 // the correct key to validate the existing blob (can't do this until
250 // we've done our first key rotation).
253 Validate(cloud_policy.Pass(),
256 validate_in_background,
258 &UserCloudPolicyStore::InstallLoadedPolicyAfterValidation,
259 weak_factory_.GetWeakPtr(),
261 result.key.has_signing_key() ?
262 result.key.signing_key() : std::string()));
270 void UserCloudPolicyStore::InstallLoadedPolicyAfterValidation(
271 bool doing_key_rotation,
272 const std::string& signing_key,
273 UserCloudPolicyValidator* validator) {
274 validation_status_ = validator->status();
275 if (!validator->success()) {
276 DVLOG(1) << "Validation failed: status=" << validation_status_;
277 status_ = STATUS_VALIDATION_ERROR;
282 DVLOG(1) << "Validation succeeded - installing policy with dm_token: " <<
283 validator->policy_data()->request_token();
284 DVLOG(1) << "Device ID: " << validator->policy_data()->device_id();
286 // If we're doing a key rotation, clear the public key version so a future
287 // policy fetch will force regeneration of the keys.
288 if (doing_key_rotation) {
289 validator->policy_data()->clear_public_key_version();
292 // Policy validation succeeded, so we know the signing key is good.
293 policy_key_ = signing_key;
296 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
301 void UserCloudPolicyStore::Store(const em::PolicyFetchResponse& policy) {
302 // Stop any pending requests to store policy, then validate the new policy
303 // before storing it.
304 weak_factory_.InvalidateWeakPtrs();
305 scoped_ptr<em::PolicyFetchResponse> policy_copy(
306 new em::PolicyFetchResponse(policy));
307 Validate(policy_copy.Pass(),
308 scoped_ptr<em::PolicySigningKey>(),
311 base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation,
312 weak_factory_.GetWeakPtr()));
315 void UserCloudPolicyStore::Validate(
316 scoped_ptr<em::PolicyFetchResponse> policy,
317 scoped_ptr<em::PolicySigningKey> cached_key,
318 const std::string& verification_key,
319 bool validate_in_background,
320 const UserCloudPolicyValidator::CompletionCallback& callback) {
322 const bool signed_policy = policy->has_policy_data_signature();
324 // Configure the validator.
325 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(
327 CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE);
329 // Extract the owning domain from the signed-in user (if any is set yet).
330 // If there's no owning domain, then the code just ensures that the policy
331 // is self-consistent (that the keys are signed with the same domain that the
332 // username field in the policy contains). UserPolicySigninServerBase will
333 // verify that the username matches the signed in user once profile
334 // initialization is complete (http://crbug.com/342327).
335 std::string owning_domain;
337 // Validate the username if the user is signed in. The signin_username_ can
338 // be empty during initial policy load because this happens before the
339 // Prefs subsystem is initialized.
340 if (!signin_username_.empty()) {
341 DVLOG(1) << "Validating username: " << signin_username_;
342 validator->ValidateUsername(signin_username_);
343 owning_domain = gaia::ExtractDomainName(
344 gaia::CanonicalizeEmail(gaia::SanitizeEmail(signin_username_)));
347 // There are 4 cases:
349 // 1) Validation after loading from cache with no cached key.
350 // Action: Don't validate signature (migration from previously cached
353 // 2) Validation after loading from cache with a cached key
354 // Action: Validate signature on policy blob but don't allow key rotation.
356 // 3) Validation after loading new policy from the server with no cached key
357 // Action: Validate as initial key provisioning (case where we are migrating
358 // from unsigned policy)
360 // 4) Validation after loading new policy from the server with a cached key
361 // Action: Validate as normal, and allow key rotation.
363 // Loading from cache should not change the cached keys.
364 DCHECK(policy_key_.empty() || policy_key_ == cached_key->signing_key());
365 if (!signed_policy || !cached_key->has_signing_key()) {
366 // Case #1 - loading from cache with no signing key.
367 // TODO(atwilson): Reject policy with no cached key once
368 // kMetricPolicyHasVerifiedCachedKey rises to a high enough level.
369 DLOG(WARNING) << "Allowing unsigned cached blob for migration";
371 // Case #2 - loading from cache with a cached key - validate the cached
372 // key, then do normal policy data signature validation using the cached
373 // key. We're loading from cache so don't allow key rotation.
374 validator->ValidateCachedKey(cached_key->signing_key(),
375 cached_key->signing_key_signature(),
378 const bool no_rotation = false;
379 validator->ValidateSignature(cached_key->signing_key(),
385 // No passed cached_key - this is not validating the initial policy load
386 // from cache, but rather an update from the server.
387 if (policy_key_.empty()) {
388 // Case #3 - no valid existing policy key (either this is the initial
389 // policy fetch, or we're doing a key rotation), so this new policy fetch
390 // should include an initial key provision.
391 validator->ValidateInitialKey(verification_key, owning_domain);
393 // Case #4 - verify new policy with existing key. We always allow key
394 // rotation - the verification key will prevent invalid policy from being
395 // injected. |policy_key_| is already known to be valid, so no need to
396 // verify via ValidateCachedKey().
397 const bool allow_rotation = true;
398 validator->ValidateSignature(
399 policy_key_, verification_key, owning_domain, allow_rotation);
403 if (validate_in_background) {
404 // Start validation in the background. The Validator will free itself once
405 // validation is complete.
406 validator.release()->StartValidation(callback);
408 // Run validation immediately and invoke the callback with the results.
409 validator->RunValidation();
410 callback.Run(validator.get());
414 void UserCloudPolicyStore::StorePolicyAfterValidation(
415 UserCloudPolicyValidator* validator) {
416 validation_status_ = validator->status();
417 DVLOG(1) << "Policy validation complete: status = " << validation_status_;
418 if (!validator->success()) {
419 status_ = STATUS_VALIDATION_ERROR;
424 // Persist the validated policy (just fire a task - don't bother getting a
425 // reply because we can't do anything if it fails).
426 background_task_runner()->PostTask(
428 base::Bind(&StorePolicyToDiskOnBackgroundThread,
429 policy_path_, key_path_, verification_key_,
430 *validator->policy()));
431 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
433 // If the key was rotated, update our local cache of the key.
434 if (validator->policy()->has_new_public_key())
435 policy_key_ = validator->policy()->new_public_key();
440 } // namespace policy