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