user_cloud_policy_store.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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.
4
5#include "components/policy/core/common/cloud/user_cloud_policy_store.h"
6
7#include "base/bind.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"
16
17namespace em = enterprise_management;
18
19namespace policy {
20
21enum PolicyLoadStatus {
22  // Policy blob was successfully loaded and parsed.
23  LOAD_RESULT_SUCCESS,
24
25  // No previously stored policy was found.
26  LOAD_RESULT_NO_POLICY_FILE,
27
28  // Could not load the previously stored policy due to either a parse or
29  // file read error.
30  LOAD_RESULT_LOAD_ERROR,
31};
32
33// Struct containing the result of a policy load - if |status| ==
34// LOAD_RESULT_SUCCESS, |policy| is initialized from the policy file on disk.
35struct PolicyLoadResult {
36  PolicyLoadStatus status;
37  em::PolicyFetchResponse policy;
38  em::PolicySigningKey key;
39};
40
41namespace {
42
43// Subdirectory in the user's profile for storing user policies.
44const base::FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Policy");
45// File in the above directory for storing user policy data.
46const base::FilePath::CharType kPolicyCacheFile[] =
47    FILE_PATH_LITERAL("User Policy");
48
49// File in the above directory for storing policy signing key data.
50const base::FilePath::CharType kKeyCacheFile[] =
51    FILE_PATH_LITERAL("Signing Key");
52
53const char kMetricPolicyHasVerifiedCachedKey[] =
54    "Enterprise.PolicyHasVerifiedCachedKey";
55
56// Loads policy from the backing file. Returns a PolicyLoadResult with the
57// results of the fetch.
58policy::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;
67    return result;
68  }
69  std::string data;
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;
77    return result;
78  }
79
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
85    // stat below).
86    LOG(ERROR) << "Failed to read or parse key data from " << key_path.value();
87    result.key.clear_signing_key();
88  }
89
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
92  // keys.
93  UMA_HISTOGRAM_BOOLEAN(kMetricPolicyHasVerifiedCachedKey,
94                        result.key.has_signing_key());
95
96  result.status = policy::LOAD_RESULT_SUCCESS;
97  return result;
98}
99
100bool 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();
103    return false;
104  }
105
106  int size = data.size();
107  if (file_util::WriteFile(path, data.c_str(), size) != size) {
108    DLOG(WARNING) << "Failed to write " << path.value();
109    return false;
110  }
111
112  return true;
113}
114
115// Stores policy to the backing file (must be called via a task on
116// the background thread).
117void 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();
123  std::string data;
124  if (!policy.SerializeToString(&data)) {
125    DLOG(WARNING) << "Failed to serialize policy data";
126    return;
127  }
128
129  if (!WriteStringToFile(policy_path, data))
130    return;
131
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";
142      return;
143    }
144
145    WriteStringToFile(key_path, key_data);
146  }
147}
148
149}  // namespace
150
151UserCloudPolicyStore::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),
157      weak_factory_(this),
158      policy_path_(policy_path),
159      key_path_(key_path),
160      verification_key_(verification_key) {}
161
162UserCloudPolicyStore::~UserCloudPolicyStore() {}
163
164// static
165scoped_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));
175}
176
177void UserCloudPolicyStore::SetSigninUsername(const std::string& username) {
178  signin_username_ = username;
179}
180
181void 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);
189}
190
191void UserCloudPolicyStore::Clear() {
192  background_task_runner()->PostTask(
193      FROM_HERE,
194      base::Bind(base::IgnoreResult(&base::DeleteFile), policy_path_, false));
195  background_task_runner()->PostTask(
196      FROM_HERE,
197      base::Bind(base::IgnoreResult(&base::DeleteFile), key_path_, false));
198  policy_.reset();
199  policy_map_.Clear();
200  policy_key_.clear();
201  NotifyStoreLoaded();
202}
203
204void UserCloudPolicyStore::Load() {
205  DVLOG(1) << "Initiating policy load from disk";
206  // Cancel any pending Load/Store/Validate operations.
207  weak_factory_.InvalidateWeakPtrs();
208
209  // Start a new Load operation and have us get called back when it is
210  // complete.
211  base::PostTaskAndReplyWithResult(
212      background_task_runner(),
213      FROM_HERE,
214      base::Bind(&LoadPolicyFromDisk, policy_path_, key_path_),
215      base::Bind(&UserCloudPolicyStore::PolicyLoaded,
216                 weak_factory_.GetWeakPtr(), true));
217}
218
219void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background,
220                                        PolicyLoadResult result) {
221  switch (result.status) {
222    case LOAD_RESULT_LOAD_ERROR:
223      status_ = STATUS_LOAD_ERROR;
224      NotifyStoreError();
225      break;
226
227    case LOAD_RESULT_NO_POLICY_FILE:
228      DVLOG(1) << "No policy found on disk";
229      NotifyStoreLoaded();
230      break;
231
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));
238
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
245        // next fetch.
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).
251      }
252
253      Validate(cloud_policy.Pass(),
254               key.Pass(),
255               verification_key,
256               validate_in_background,
257               base::Bind(
258                   &UserCloudPolicyStore::InstallLoadedPolicyAfterValidation,
259                   weak_factory_.GetWeakPtr(),
260                   doing_key_rotation,
261                   result.key.has_signing_key() ?
262                       result.key.signing_key() : std::string()));
263      break;
264    }
265    default:
266      NOTREACHED();
267  }
268}
269
270void 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;
278    NotifyStoreError();
279    return;
280  }
281
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();
285
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();
290    policy_key_.clear();
291  } else {
292    // Policy validation succeeded, so we know the signing key is good.
293    policy_key_ = signing_key;
294  }
295
296  InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
297  status_ = STATUS_OK;
298  NotifyStoreLoaded();
299}
300
301void 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>(),
309           verification_key_,
310           true,
311           base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation,
312                      weak_factory_.GetWeakPtr()));
313}
314
315void 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) {
321
322  const bool signed_policy = policy->has_policy_data_signature();
323
324  // Configure the validator.
325  scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(
326      policy.Pass(),
327      CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE);
328
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;
336
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_)));
345  }
346
347  // There are 4 cases:
348  //
349  // 1) Validation after loading from cache with no cached key.
350  // Action: Don't validate signature (migration from previously cached
351  // unsigned blob).
352  //
353  // 2) Validation after loading from cache with a cached key
354  // Action: Validate signature on policy blob but don't allow key rotation.
355  //
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)
359  //
360  // 4) Validation after loading new policy from the server with a cached key
361  // Action: Validate as normal, and allow key rotation.
362  if (cached_key) {
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";
370    } else {
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(),
376                                   verification_key,
377                                   owning_domain);
378      const bool no_rotation = false;
379      validator->ValidateSignature(cached_key->signing_key(),
380                                   verification_key,
381                                   owning_domain,
382                                   no_rotation);
383    }
384  } else {
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);
392    } else {
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);
400    }
401  }
402
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);
407  } else {
408    // Run validation immediately and invoke the callback with the results.
409    validator->RunValidation();
410    callback.Run(validator.get());
411  }
412}
413
414void 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;
420    NotifyStoreError();
421    return;
422  }
423
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(
427      FROM_HERE,
428      base::Bind(&StorePolicyToDiskOnBackgroundThread,
429                 policy_path_, key_path_, verification_key_,
430                 *validator->policy()));
431  InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
432
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();
436  status_ = STATUS_OK;
437  NotifyStoreLoaded();
438}
439
440}  // namespace policy
441