user_cloud_policy_store.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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// Maximum policy and key size that will be loaded, in bytes.
57const size_t kPolicySizeLimit = 1024 * 1024;
58const size_t kKeySizeLimit = 16 * 1024;
59
60// Loads policy from the backing file. Returns a PolicyLoadResult with the
61// results of the fetch.
62policy::PolicyLoadResult LoadPolicyFromDisk(
63    const base::FilePath& policy_path,
64    const base::FilePath& key_path) {
65  policy::PolicyLoadResult result;
66  // If the backing file does not exist, just return. We don't verify the key
67  // path here, because the key is optional (the validation code will fail if
68  // the key does not exist but the loaded policy is unsigned).
69  if (!base::PathExists(policy_path)) {
70    result.status = policy::LOAD_RESULT_NO_POLICY_FILE;
71    return result;
72  }
73  std::string data;
74
75  if (!base::ReadFileToString(policy_path, &data, kPolicySizeLimit) ||
76      !result.policy.ParseFromString(data)) {
77    LOG(WARNING) << "Failed to read or parse policy data from "
78                 << policy_path.value();
79    result.status = policy::LOAD_RESULT_LOAD_ERROR;
80    return result;
81  }
82
83  if (!base::ReadFileToString(key_path, &data, kKeySizeLimit) ||
84      !result.key.ParseFromString(data)) {
85    // Log an error on missing key data, but do not trigger a load failure
86    // for now since there are still old unsigned cached policy blobs in the
87    // wild with no associated key (see kMetricPolicyHasVerifiedCachedKey UMA
88    // stat below).
89    LOG(ERROR) << "Failed to read or parse key data from " << key_path.value();
90    result.key.clear_signing_key();
91  }
92
93  // Track the occurrence of valid cached keys - when this ratio gets high
94  // enough, we can update the code to reject unsigned policy or unverified
95  // keys.
96  UMA_HISTOGRAM_BOOLEAN(kMetricPolicyHasVerifiedCachedKey,
97                        result.key.has_signing_key());
98
99  result.status = policy::LOAD_RESULT_SUCCESS;
100  return result;
101}
102
103bool WriteStringToFile(const base::FilePath path, const std::string& data) {
104 if (!base::CreateDirectory(path.DirName())) {
105    DLOG(WARNING) << "Failed to create directory " << path.DirName().value();
106    return false;
107  }
108
109  int size = data.size();
110  if (base::WriteFile(path, data.c_str(), size) != size) {
111    DLOG(WARNING) << "Failed to write " << path.value();
112    return false;
113  }
114
115  return true;
116}
117
118// Stores policy to the backing file (must be called via a task on
119// the background thread).
120void StorePolicyToDiskOnBackgroundThread(
121    const base::FilePath& policy_path,
122    const base::FilePath& key_path,
123    const std::string& verification_key,
124    const em::PolicyFetchResponse& policy) {
125  DVLOG(1) << "Storing policy to " << policy_path.value();
126  std::string data;
127  if (!policy.SerializeToString(&data)) {
128    DLOG(WARNING) << "Failed to serialize policy data";
129    return;
130  }
131
132  if (!WriteStringToFile(policy_path, data))
133    return;
134
135  if (policy.has_new_public_key()) {
136    // Write the new public key and its verification signature/key to a file.
137    em::PolicySigningKey key_info;
138    key_info.set_signing_key(policy.new_public_key());
139    key_info.set_signing_key_signature(
140        policy.new_public_key_verification_signature());
141    key_info.set_verification_key(verification_key);
142    std::string key_data;
143    if (!key_info.SerializeToString(&key_data)) {
144      DLOG(WARNING) << "Failed to serialize policy signing key";
145      return;
146    }
147
148    WriteStringToFile(key_path, key_data);
149  }
150}
151
152}  // namespace
153
154UserCloudPolicyStore::UserCloudPolicyStore(
155    const base::FilePath& policy_path,
156    const base::FilePath& key_path,
157    const std::string& verification_key,
158    scoped_refptr<base::SequencedTaskRunner> background_task_runner)
159    : UserCloudPolicyStoreBase(background_task_runner),
160      weak_factory_(this),
161      policy_path_(policy_path),
162      key_path_(key_path),
163      verification_key_(verification_key) {}
164
165UserCloudPolicyStore::~UserCloudPolicyStore() {}
166
167// static
168scoped_ptr<UserCloudPolicyStore> UserCloudPolicyStore::Create(
169    const base::FilePath& profile_path,
170    const std::string& verification_key,
171    scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
172  base::FilePath policy_path =
173      profile_path.Append(kPolicyDir).Append(kPolicyCacheFile);
174  base::FilePath key_path =
175      profile_path.Append(kPolicyDir).Append(kKeyCacheFile);
176  return make_scoped_ptr(new UserCloudPolicyStore(
177      policy_path, key_path, verification_key, background_task_runner));
178}
179
180void UserCloudPolicyStore::SetSigninUsername(const std::string& username) {
181  signin_username_ = username;
182}
183
184void UserCloudPolicyStore::LoadImmediately() {
185  DVLOG(1) << "Initiating immediate policy load from disk";
186  // Cancel any pending Load/Store/Validate operations.
187  weak_factory_.InvalidateWeakPtrs();
188  // Load the policy from disk...
189  PolicyLoadResult result = LoadPolicyFromDisk(policy_path_, key_path_);
190  // ...and install it, reporting success/failure to any observers.
191  PolicyLoaded(false, result);
192}
193
194void UserCloudPolicyStore::Clear() {
195  background_task_runner()->PostTask(
196      FROM_HERE,
197      base::Bind(base::IgnoreResult(&base::DeleteFile), policy_path_, false));
198  background_task_runner()->PostTask(
199      FROM_HERE,
200      base::Bind(base::IgnoreResult(&base::DeleteFile), key_path_, false));
201  policy_.reset();
202  policy_map_.Clear();
203  policy_key_.clear();
204  NotifyStoreLoaded();
205}
206
207void UserCloudPolicyStore::Load() {
208  DVLOG(1) << "Initiating policy load from disk";
209  // Cancel any pending Load/Store/Validate operations.
210  weak_factory_.InvalidateWeakPtrs();
211
212  // Start a new Load operation and have us get called back when it is
213  // complete.
214  base::PostTaskAndReplyWithResult(
215      background_task_runner(),
216      FROM_HERE,
217      base::Bind(&LoadPolicyFromDisk, policy_path_, key_path_),
218      base::Bind(&UserCloudPolicyStore::PolicyLoaded,
219                 weak_factory_.GetWeakPtr(), true));
220}
221
222void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background,
223                                        PolicyLoadResult result) {
224  switch (result.status) {
225    case LOAD_RESULT_LOAD_ERROR:
226      status_ = STATUS_LOAD_ERROR;
227      NotifyStoreError();
228      break;
229
230    case LOAD_RESULT_NO_POLICY_FILE:
231      DVLOG(1) << "No policy found on disk";
232      NotifyStoreLoaded();
233      break;
234
235    case LOAD_RESULT_SUCCESS: {
236      // Found policy on disk - need to validate it before it can be used.
237      scoped_ptr<em::PolicyFetchResponse> cloud_policy(
238          new em::PolicyFetchResponse(result.policy));
239      scoped_ptr<em::PolicySigningKey> key(
240          new em::PolicySigningKey(result.key));
241
242      bool doing_key_rotation = false;
243      const std::string& verification_key = verification_key_;
244      if (!key->has_verification_key() ||
245          key->verification_key() != verification_key_) {
246        // The cached key didn't match our current key, so we're doing a key
247        // rotation - make sure we request a new key from the server on our
248        // next fetch.
249        doing_key_rotation = true;
250        DLOG(WARNING) << "Verification key rotation detected";
251        // TODO(atwilson): Add code to update |verification_key| to point to
252        // the correct key to validate the existing blob (can't do this until
253        // we've done our first key rotation).
254      }
255
256      Validate(cloud_policy.Pass(),
257               key.Pass(),
258               verification_key,
259               validate_in_background,
260               base::Bind(
261                   &UserCloudPolicyStore::InstallLoadedPolicyAfterValidation,
262                   weak_factory_.GetWeakPtr(),
263                   doing_key_rotation,
264                   result.key.has_signing_key() ?
265                       result.key.signing_key() : std::string()));
266      break;
267    }
268    default:
269      NOTREACHED();
270  }
271}
272
273void UserCloudPolicyStore::InstallLoadedPolicyAfterValidation(
274    bool doing_key_rotation,
275    const std::string& signing_key,
276    UserCloudPolicyValidator* validator) {
277  validation_status_ = validator->status();
278  if (!validator->success()) {
279    DVLOG(1) << "Validation failed: status=" << validation_status_;
280    status_ = STATUS_VALIDATION_ERROR;
281    NotifyStoreError();
282    return;
283  }
284
285  DVLOG(1) << "Validation succeeded - installing policy with dm_token: " <<
286      validator->policy_data()->request_token();
287  DVLOG(1) << "Device ID: " << validator->policy_data()->device_id();
288
289  // If we're doing a key rotation, clear the public key version so a future
290  // policy fetch will force regeneration of the keys.
291  if (doing_key_rotation) {
292    validator->policy_data()->clear_public_key_version();
293    policy_key_.clear();
294  } else {
295    // Policy validation succeeded, so we know the signing key is good.
296    policy_key_ = signing_key;
297  }
298
299  InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
300  status_ = STATUS_OK;
301  NotifyStoreLoaded();
302}
303
304void UserCloudPolicyStore::Store(const em::PolicyFetchResponse& policy) {
305  // Stop any pending requests to store policy, then validate the new policy
306  // before storing it.
307  weak_factory_.InvalidateWeakPtrs();
308  scoped_ptr<em::PolicyFetchResponse> policy_copy(
309      new em::PolicyFetchResponse(policy));
310  Validate(policy_copy.Pass(),
311           scoped_ptr<em::PolicySigningKey>(),
312           verification_key_,
313           true,
314           base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation,
315                      weak_factory_.GetWeakPtr()));
316}
317
318void UserCloudPolicyStore::Validate(
319    scoped_ptr<em::PolicyFetchResponse> policy,
320    scoped_ptr<em::PolicySigningKey> cached_key,
321    const std::string& verification_key,
322    bool validate_in_background,
323    const UserCloudPolicyValidator::CompletionCallback& callback) {
324
325  const bool signed_policy = policy->has_policy_data_signature();
326
327  // Configure the validator.
328  scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(
329      policy.Pass(),
330      CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE);
331
332  // Extract the owning domain from the signed-in user (if any is set yet).
333  // If there's no owning domain, then the code just ensures that the policy
334  // is self-consistent (that the keys are signed with the same domain that the
335  // username field in the policy contains). UserPolicySigninServerBase will
336  // verify that the username matches the signed in user once profile
337  // initialization is complete (http://crbug.com/342327).
338  std::string owning_domain;
339
340  // Validate the username if the user is signed in. The signin_username_ can
341  // be empty during initial policy load because this happens before the
342  // Prefs subsystem is initialized.
343  if (!signin_username_.empty()) {
344    DVLOG(1) << "Validating username: " << signin_username_;
345    validator->ValidateUsername(signin_username_, true);
346    owning_domain = gaia::ExtractDomainName(
347        gaia::CanonicalizeEmail(gaia::SanitizeEmail(signin_username_)));
348  }
349
350  // There are 4 cases:
351  //
352  // 1) Validation after loading from cache with no cached key.
353  // Action: Don't validate signature (migration from previously cached
354  // unsigned blob).
355  //
356  // 2) Validation after loading from cache with a cached key
357  // Action: Validate signature on policy blob but don't allow key rotation.
358  //
359  // 3) Validation after loading new policy from the server with no cached key
360  // Action: Validate as initial key provisioning (case where we are migrating
361  // from unsigned policy)
362  //
363  // 4) Validation after loading new policy from the server with a cached key
364  // Action: Validate as normal, and allow key rotation.
365  if (cached_key) {
366    // Loading from cache should not change the cached keys.
367    DCHECK(policy_key_.empty() || policy_key_ == cached_key->signing_key());
368    if (!signed_policy || !cached_key->has_signing_key()) {
369      // Case #1 - loading from cache with no signing key.
370      // TODO(atwilson): Reject policy with no cached key once
371      // kMetricPolicyHasVerifiedCachedKey rises to a high enough level.
372      DLOG(WARNING) << "Allowing unsigned cached blob for migration";
373    } else {
374      // Case #2 - loading from cache with a cached key - validate the cached
375      // key, then do normal policy data signature validation using the cached
376      // key. We're loading from cache so don't allow key rotation.
377      validator->ValidateCachedKey(cached_key->signing_key(),
378                                   cached_key->signing_key_signature(),
379                                   verification_key,
380                                   owning_domain);
381      const bool no_rotation = false;
382      validator->ValidateSignature(cached_key->signing_key(),
383                                   verification_key,
384                                   owning_domain,
385                                   no_rotation);
386    }
387  } else {
388    // No passed cached_key - this is not validating the initial policy load
389    // from cache, but rather an update from the server.
390    if (policy_key_.empty()) {
391      // Case #3 - no valid existing policy key (either this is the initial
392      // policy fetch, or we're doing a key rotation), so this new policy fetch
393      // should include an initial key provision.
394      validator->ValidateInitialKey(verification_key, owning_domain);
395    } else {
396      // Case #4 - verify new policy with existing key. We always allow key
397      // rotation - the verification key will prevent invalid policy from being
398      // injected. |policy_key_| is already known to be valid, so no need to
399      // verify via ValidateCachedKey().
400      const bool allow_rotation = true;
401      validator->ValidateSignature(
402          policy_key_, verification_key, owning_domain, allow_rotation);
403    }
404  }
405
406  if (validate_in_background) {
407    // Start validation in the background. The Validator will free itself once
408    // validation is complete.
409    validator.release()->StartValidation(callback);
410  } else {
411    // Run validation immediately and invoke the callback with the results.
412    validator->RunValidation();
413    callback.Run(validator.get());
414  }
415}
416
417void UserCloudPolicyStore::StorePolicyAfterValidation(
418    UserCloudPolicyValidator* validator) {
419  validation_status_ = validator->status();
420  DVLOG(1) << "Policy validation complete: status = " << validation_status_;
421  if (!validator->success()) {
422    status_ = STATUS_VALIDATION_ERROR;
423    NotifyStoreError();
424    return;
425  }
426
427  // Persist the validated policy (just fire a task - don't bother getting a
428  // reply because we can't do anything if it fails).
429  background_task_runner()->PostTask(
430      FROM_HERE,
431      base::Bind(&StorePolicyToDiskOnBackgroundThread,
432                 policy_path_, key_path_, verification_key_,
433                 *validator->policy()));
434  InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
435
436  // If the key was rotated, update our local cache of the key.
437  if (validator->policy()->has_new_public_key())
438    policy_key_ = validator->policy()->new_public_key();
439  status_ = STATUS_OK;
440  NotifyStoreLoaded();
441}
442
443}  // namespace policy
444