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/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 enum 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.
     35 struct PolicyLoadResult {
     36   PolicyLoadStatus status;
     37   em::PolicyFetchResponse policy;
     38   em::PolicySigningKey key;
     39 };
     40 
     41 namespace {
     42 
     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");
     48 
     49 // File in the above directory for storing policy signing key data.
     50 const base::FilePath::CharType kKeyCacheFile[] =
     51     FILE_PATH_LITERAL("Signing Key");
     52 
     53 const char kMetricPolicyHasVerifiedCachedKey[] =
     54     "Enterprise.PolicyHasVerifiedCachedKey";
     55 
     56 // Maximum policy and key size that will be loaded, in bytes.
     57 const size_t kPolicySizeLimit = 1024 * 1024;
     58 const size_t kKeySizeLimit = 16 * 1024;
     59 
     60 // Loads policy from the backing file. Returns a PolicyLoadResult with the
     61 // results of the fetch.
     62 policy::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 
    103 bool 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).
    120 void 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 
    154 UserCloudPolicyStore::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 
    165 UserCloudPolicyStore::~UserCloudPolicyStore() {}
    166 
    167 // static
    168 scoped_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 
    180 void UserCloudPolicyStore::SetSigninUsername(const std::string& username) {
    181   signin_username_ = username;
    182 }
    183 
    184 void 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 
    194 void 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 
    207 void 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 
    222 void 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 
    273 void 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 
    304 void 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 
    318 void 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 
    417 void 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