| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/policy/core/common/cloud/user_cloud_policy_store.h" | 5 #include "components/policy/core/common/cloud/user_cloud_policy_store.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
| 9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/metrics/histogram.h" |
| 10 #include "base/task_runner_util.h" | 11 #include "base/task_runner_util.h" |
| 11 #include "policy/proto/cloud_policy.pb.h" | 12 #include "policy/proto/cloud_policy.pb.h" |
| 12 #include "policy/proto/device_management_backend.pb.h" | 13 #include "policy/proto/device_management_backend.pb.h" |
| 14 #include "policy/proto/policy_signing_key.pb.h" |
| 13 | 15 |
| 14 namespace em = enterprise_management; | 16 namespace em = enterprise_management; |
| 15 | 17 |
| 16 namespace policy { | 18 namespace policy { |
| 17 | 19 |
| 18 enum PolicyLoadStatus { | 20 enum PolicyLoadStatus { |
| 19 // Policy blob was successfully loaded and parsed. | 21 // Policy blob was successfully loaded and parsed. |
| 20 LOAD_RESULT_SUCCESS, | 22 LOAD_RESULT_SUCCESS, |
| 21 | 23 |
| 22 // No previously stored policy was found. | 24 // No previously stored policy was found. |
| 23 LOAD_RESULT_NO_POLICY_FILE, | 25 LOAD_RESULT_NO_POLICY_FILE, |
| 24 | 26 |
| 25 // Could not load the previously stored policy due to either a parse or | 27 // Could not load the previously stored policy due to either a parse or |
| 26 // file read error. | 28 // file read error. |
| 27 LOAD_RESULT_LOAD_ERROR, | 29 LOAD_RESULT_LOAD_ERROR, |
| 28 }; | 30 }; |
| 29 | 31 |
| 30 // Struct containing the result of a policy load - if |status| == | 32 // Struct containing the result of a policy load - if |status| == |
| 31 // LOAD_RESULT_SUCCESS, |policy| is initialized from the policy file on disk. | 33 // LOAD_RESULT_SUCCESS, |policy| is initialized from the policy file on disk. |
| 32 struct PolicyLoadResult { | 34 struct PolicyLoadResult { |
| 33 PolicyLoadStatus status; | 35 PolicyLoadStatus status; |
| 34 em::PolicyFetchResponse policy; | 36 em::PolicyFetchResponse policy; |
| 37 em::PolicySigningKey key; |
| 35 }; | 38 }; |
| 36 | 39 |
| 37 namespace { | 40 namespace { |
| 38 | 41 |
| 39 // Subdirectory in the user's profile for storing user policies. | 42 // Subdirectory in the user's profile for storing user policies. |
| 40 const base::FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Policy"); | 43 const base::FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Policy"); |
| 41 // File in the above directory for storing user policy data. | 44 // File in the above directory for storing user policy data. |
| 42 const base::FilePath::CharType kPolicyCacheFile[] = | 45 const base::FilePath::CharType kPolicyCacheFile[] = |
| 43 FILE_PATH_LITERAL("User Policy"); | 46 FILE_PATH_LITERAL("User Policy"); |
| 44 | 47 |
| 48 // File in the above directory for storing policy signing key data. |
| 49 const base::FilePath::CharType kKeyCacheFile[] = |
| 50 FILE_PATH_LITERAL("Signing Key"); |
| 51 |
| 52 const char kMetricPolicyHasVerifiedCachedKey[] = |
| 53 "Enterprise.PolicyHasVerifiedCachedKey"; |
| 54 |
| 45 // Loads policy from the backing file. Returns a PolicyLoadResult with the | 55 // Loads policy from the backing file. Returns a PolicyLoadResult with the |
| 46 // results of the fetch. | 56 // results of the fetch. |
| 47 policy::PolicyLoadResult LoadPolicyFromDisk(const base::FilePath& path) { | 57 policy::PolicyLoadResult LoadPolicyFromDisk( |
| 58 const base::FilePath& policy_path, |
| 59 const base::FilePath& key_path) { |
| 48 policy::PolicyLoadResult result; | 60 policy::PolicyLoadResult result; |
| 49 // If the backing file does not exist, just return. | 61 // If the backing file does not exist, just return. We don't verify the key |
| 50 if (!base::PathExists(path)) { | 62 // path here, because the key is optional (the validation code will fail if |
| 63 // the key does not exist but the loaded policy is unsigned). |
| 64 if (!base::PathExists(policy_path)) { |
| 51 result.status = policy::LOAD_RESULT_NO_POLICY_FILE; | 65 result.status = policy::LOAD_RESULT_NO_POLICY_FILE; |
| 52 return result; | 66 return result; |
| 53 } | 67 } |
| 54 std::string data; | 68 std::string data; |
| 55 if (!base::ReadFileToString(path, &data) || | 69 // TODO(atwilson): Enforce a policy/key maxsize when ReadFileToString() can |
| 56 !result.policy.ParseFromArray(data.c_str(), data.size())) { | 70 // accept a max_size (http://crbug.com/339417). |
| 57 LOG(WARNING) << "Failed to read or parse policy data from " << path.value(); | 71 if (!base::ReadFileToString(policy_path, &data) || |
| 72 !result.policy.ParseFromString(data)) { |
| 73 LOG(WARNING) << "Failed to read or parse policy data from " |
| 74 << policy_path.value(); |
| 58 result.status = policy::LOAD_RESULT_LOAD_ERROR; | 75 result.status = policy::LOAD_RESULT_LOAD_ERROR; |
| 59 return result; | 76 return result; |
| 60 } | 77 } |
| 61 | 78 |
| 79 if (!base::ReadFileToString(key_path, &data) || |
| 80 !result.key.ParseFromString(data)) { |
| 81 // Log an error on missing key data, but do not trigger a load failure |
| 82 // for now since there are still old unsigned cached policy blobs in the |
| 83 // wild with no associated key (see kMetricPolicyHasVerifiedCachedKey UMA |
| 84 // stat below). |
| 85 LOG(ERROR) << "Failed to read or parse key data from " << key_path.value(); |
| 86 result.key.clear_signing_key(); |
| 87 } |
| 88 |
| 89 // Track the occurrence of valid cached keys - when this ratio gets high |
| 90 // enough, we can update the code to reject unsigned policy or unverified |
| 91 // keys. |
| 92 UMA_HISTOGRAM_BOOLEAN(kMetricPolicyHasVerifiedCachedKey, |
| 93 result.key.has_signing_key()); |
| 94 |
| 62 result.status = policy::LOAD_RESULT_SUCCESS; | 95 result.status = policy::LOAD_RESULT_SUCCESS; |
| 63 return result; | 96 return result; |
| 64 } | 97 } |
| 65 | 98 |
| 99 bool WriteStringToFile(const base::FilePath path, const std::string& data) { |
| 100 if (!base::CreateDirectory(path.DirName())) { |
| 101 DLOG(WARNING) << "Failed to create directory " << path.DirName().value(); |
| 102 return false; |
| 103 } |
| 104 |
| 105 int size = data.size(); |
| 106 if (file_util::WriteFile(path, data.c_str(), size) != size) { |
| 107 DLOG(WARNING) << "Failed to write " << path.value(); |
| 108 return false; |
| 109 } |
| 110 |
| 111 return true; |
| 112 } |
| 113 |
| 66 // Stores policy to the backing file (must be called via a task on | 114 // Stores policy to the backing file (must be called via a task on |
| 67 // the background thread). | 115 // the background thread). |
| 68 void StorePolicyToDiskOnBackgroundThread( | 116 void StorePolicyToDiskOnBackgroundThread( |
| 69 const base::FilePath& path, | 117 const base::FilePath& policy_path, |
| 118 const base::FilePath& key_path, |
| 70 const em::PolicyFetchResponse& policy) { | 119 const em::PolicyFetchResponse& policy) { |
| 71 DVLOG(1) << "Storing policy to " << path.value(); | 120 DVLOG(1) << "Storing policy to " << policy_path.value(); |
| 72 std::string data; | 121 std::string data; |
| 73 if (!policy.SerializeToString(&data)) { | 122 if (!policy.SerializeToString(&data)) { |
| 74 DLOG(WARNING) << "Failed to serialize policy data"; | 123 DLOG(WARNING) << "Failed to serialize policy data"; |
| 75 return; | 124 return; |
| 76 } | 125 } |
| 77 | 126 |
| 78 if (!base::CreateDirectory(path.DirName())) { | 127 if (!WriteStringToFile(policy_path, data)) |
| 79 DLOG(WARNING) << "Failed to create directory " << path.DirName().value(); | |
| 80 return; | 128 return; |
| 81 } | |
| 82 | 129 |
| 83 int size = data.size(); | 130 if (policy.has_new_public_key()) { |
| 84 if (file_util::WriteFile(path, data.c_str(), size) != size) { | 131 // Write the new public key and its verification signature to a file. |
| 85 DLOG(WARNING) << "Failed to write " << path.value(); | 132 em::PolicySigningKey key_info; |
| 133 key_info.set_signing_key(policy.new_public_key()); |
| 134 key_info.set_signing_key_signature( |
| 135 policy.new_public_key_verification_signature()); |
| 136 std::string key_data; |
| 137 if (!key_info.SerializeToString(&key_data)) { |
| 138 DLOG(WARNING) << "Failed to serialize policy signing key"; |
| 139 return; |
| 140 } |
| 141 |
| 142 WriteStringToFile(key_path, key_data); |
| 86 } | 143 } |
| 87 } | 144 } |
| 88 | 145 |
| 89 } // namespace | 146 } // namespace |
| 90 | 147 |
| 91 UserCloudPolicyStore::UserCloudPolicyStore( | 148 UserCloudPolicyStore::UserCloudPolicyStore( |
| 92 const base::FilePath& path, | 149 const base::FilePath& policy_path, |
| 150 const base::FilePath& key_path, |
| 151 const std::string& verification_key, |
| 93 scoped_refptr<base::SequencedTaskRunner> background_task_runner) | 152 scoped_refptr<base::SequencedTaskRunner> background_task_runner) |
| 94 : UserCloudPolicyStoreBase(background_task_runner), | 153 : UserCloudPolicyStoreBase(background_task_runner), |
| 95 weak_factory_(this), | 154 weak_factory_(this), |
| 96 backing_file_path_(path) {} | 155 policy_path_(policy_path), |
| 156 key_path_(key_path), |
| 157 verification_key_(verification_key) {} |
| 97 | 158 |
| 98 UserCloudPolicyStore::~UserCloudPolicyStore() {} | 159 UserCloudPolicyStore::~UserCloudPolicyStore() {} |
| 99 | 160 |
| 100 // static | 161 // static |
| 101 scoped_ptr<UserCloudPolicyStore> UserCloudPolicyStore::Create( | 162 scoped_ptr<UserCloudPolicyStore> UserCloudPolicyStore::Create( |
| 102 const base::FilePath& profile_path, | 163 const base::FilePath& profile_path, |
| 164 const std::string& verification_key, |
| 103 scoped_refptr<base::SequencedTaskRunner> background_task_runner) { | 165 scoped_refptr<base::SequencedTaskRunner> background_task_runner) { |
| 104 base::FilePath path = | 166 base::FilePath policy_path = |
| 105 profile_path.Append(kPolicyDir).Append(kPolicyCacheFile); | 167 profile_path.Append(kPolicyDir).Append(kPolicyCacheFile); |
| 106 return make_scoped_ptr( | 168 base::FilePath key_path = |
| 107 new UserCloudPolicyStore(path, background_task_runner)); | 169 profile_path.Append(kPolicyDir).Append(kKeyCacheFile); |
| 170 return make_scoped_ptr(new UserCloudPolicyStore( |
| 171 policy_path, key_path, verification_key, background_task_runner)); |
| 108 } | 172 } |
| 109 | 173 |
| 110 void UserCloudPolicyStore::SetSigninUsername(const std::string& username) { | 174 void UserCloudPolicyStore::SetSigninUsername(const std::string& username) { |
| 111 signin_username_ = username; | 175 signin_username_ = username; |
| 112 } | 176 } |
| 113 | 177 |
| 114 void UserCloudPolicyStore::LoadImmediately() { | 178 void UserCloudPolicyStore::LoadImmediately() { |
| 115 DVLOG(1) << "Initiating immediate policy load from disk"; | 179 DVLOG(1) << "Initiating immediate policy load from disk"; |
| 116 // Cancel any pending Load/Store/Validate operations. | 180 // Cancel any pending Load/Store/Validate operations. |
| 117 weak_factory_.InvalidateWeakPtrs(); | 181 weak_factory_.InvalidateWeakPtrs(); |
| 118 // Load the policy from disk... | 182 // Load the policy from disk... |
| 119 PolicyLoadResult result = LoadPolicyFromDisk(backing_file_path_); | 183 PolicyLoadResult result = LoadPolicyFromDisk(policy_path_, key_path_); |
| 120 // ...and install it, reporting success/failure to any observers. | 184 // ...and install it, reporting success/failure to any observers. |
| 121 PolicyLoaded(false, result); | 185 PolicyLoaded(false, result); |
| 122 } | 186 } |
| 123 | 187 |
| 124 void UserCloudPolicyStore::Clear() { | 188 void UserCloudPolicyStore::Clear() { |
| 125 background_task_runner()->PostTask( | 189 background_task_runner()->PostTask( |
| 126 FROM_HERE, | 190 FROM_HERE, |
| 127 base::Bind( | 191 base::Bind(base::IgnoreResult(&base::DeleteFile), policy_path_, false)); |
| 128 base::IgnoreResult(&base::DeleteFile), backing_file_path_, false)); | 192 background_task_runner()->PostTask( |
| 193 FROM_HERE, |
| 194 base::Bind(base::IgnoreResult(&base::DeleteFile), key_path_, false)); |
| 129 policy_.reset(); | 195 policy_.reset(); |
| 130 policy_map_.Clear(); | 196 policy_map_.Clear(); |
| 197 policy_key_.clear(); |
| 131 NotifyStoreLoaded(); | 198 NotifyStoreLoaded(); |
| 132 } | 199 } |
| 133 | 200 |
| 134 void UserCloudPolicyStore::Load() { | 201 void UserCloudPolicyStore::Load() { |
| 135 DVLOG(1) << "Initiating policy load from disk"; | 202 DVLOG(1) << "Initiating policy load from disk"; |
| 136 // Cancel any pending Load/Store/Validate operations. | 203 // Cancel any pending Load/Store/Validate operations. |
| 137 weak_factory_.InvalidateWeakPtrs(); | 204 weak_factory_.InvalidateWeakPtrs(); |
| 138 | 205 |
| 139 // Start a new Load operation and have us get called back when it is | 206 // Start a new Load operation and have us get called back when it is |
| 140 // complete. | 207 // complete. |
| 141 base::PostTaskAndReplyWithResult( | 208 base::PostTaskAndReplyWithResult( |
| 142 background_task_runner(), | 209 background_task_runner(), |
| 143 FROM_HERE, | 210 FROM_HERE, |
| 144 base::Bind(&LoadPolicyFromDisk, backing_file_path_), | 211 base::Bind(&LoadPolicyFromDisk, policy_path_, key_path_), |
| 145 base::Bind(&UserCloudPolicyStore::PolicyLoaded, | 212 base::Bind(&UserCloudPolicyStore::PolicyLoaded, |
| 146 weak_factory_.GetWeakPtr(), true)); | 213 weak_factory_.GetWeakPtr(), true)); |
| 147 } | 214 } |
| 148 | 215 |
| 149 void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background, | 216 void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background, |
| 150 PolicyLoadResult result) { | 217 PolicyLoadResult result) { |
| 151 switch (result.status) { | 218 switch (result.status) { |
| 152 case LOAD_RESULT_LOAD_ERROR: | 219 case LOAD_RESULT_LOAD_ERROR: |
| 153 status_ = STATUS_LOAD_ERROR; | 220 status_ = STATUS_LOAD_ERROR; |
| 154 NotifyStoreError(); | 221 NotifyStoreError(); |
| 155 break; | 222 break; |
| 156 | 223 |
| 157 case LOAD_RESULT_NO_POLICY_FILE: | 224 case LOAD_RESULT_NO_POLICY_FILE: |
| 158 DVLOG(1) << "No policy found on disk"; | 225 DVLOG(1) << "No policy found on disk"; |
| 159 NotifyStoreLoaded(); | 226 NotifyStoreLoaded(); |
| 160 break; | 227 break; |
| 161 | 228 |
| 162 case LOAD_RESULT_SUCCESS: { | 229 case LOAD_RESULT_SUCCESS: { |
| 163 // Found policy on disk - need to validate it before it can be used. | 230 // Found policy on disk - need to validate it before it can be used. |
| 164 scoped_ptr<em::PolicyFetchResponse> cloud_policy( | 231 scoped_ptr<em::PolicyFetchResponse> cloud_policy( |
| 165 new em::PolicyFetchResponse(result.policy)); | 232 new em::PolicyFetchResponse(result.policy)); |
| 233 scoped_ptr<em::PolicySigningKey> key( |
| 234 new em::PolicySigningKey(result.key)); |
| 166 Validate(cloud_policy.Pass(), | 235 Validate(cloud_policy.Pass(), |
| 236 key.Pass(), |
| 167 validate_in_background, | 237 validate_in_background, |
| 168 base::Bind( | 238 base::Bind( |
| 169 &UserCloudPolicyStore::InstallLoadedPolicyAfterValidation, | 239 &UserCloudPolicyStore::InstallLoadedPolicyAfterValidation, |
| 170 weak_factory_.GetWeakPtr())); | 240 weak_factory_.GetWeakPtr(), |
| 241 result.key.has_signing_key() ? |
| 242 result.key.signing_key() : std::string())); |
| 171 break; | 243 break; |
| 172 } | 244 } |
| 173 default: | 245 default: |
| 174 NOTREACHED(); | 246 NOTREACHED(); |
| 175 } | 247 } |
| 176 } | 248 } |
| 177 | 249 |
| 178 void UserCloudPolicyStore::InstallLoadedPolicyAfterValidation( | 250 void UserCloudPolicyStore::InstallLoadedPolicyAfterValidation( |
| 251 const std::string& signing_key, |
| 179 UserCloudPolicyValidator* validator) { | 252 UserCloudPolicyValidator* validator) { |
| 180 validation_status_ = validator->status(); | 253 validation_status_ = validator->status(); |
| 181 if (!validator->success()) { | 254 if (!validator->success()) { |
| 182 DVLOG(1) << "Validation failed: status=" << validation_status_; | 255 DVLOG(1) << "Validation failed: status=" << validation_status_; |
| 183 status_ = STATUS_VALIDATION_ERROR; | 256 status_ = STATUS_VALIDATION_ERROR; |
| 184 NotifyStoreError(); | 257 NotifyStoreError(); |
| 185 return; | 258 return; |
| 186 } | 259 } |
| 187 | 260 |
| 188 DVLOG(1) << "Validation succeeded - installing policy with dm_token: " << | 261 DVLOG(1) << "Validation succeeded - installing policy with dm_token: " << |
| 189 validator->policy_data()->request_token(); | 262 validator->policy_data()->request_token(); |
| 190 DVLOG(1) << "Device ID: " << validator->policy_data()->device_id(); | 263 DVLOG(1) << "Device ID: " << validator->policy_data()->device_id(); |
| 191 | 264 |
| 192 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); | 265 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); |
| 266 // Policy validation succeeded, so we know the signing key is good. |
| 267 policy_key_ = signing_key; |
| 193 status_ = STATUS_OK; | 268 status_ = STATUS_OK; |
| 194 NotifyStoreLoaded(); | 269 NotifyStoreLoaded(); |
| 195 } | 270 } |
| 196 | 271 |
| 197 void UserCloudPolicyStore::Store(const em::PolicyFetchResponse& policy) { | 272 void UserCloudPolicyStore::Store(const em::PolicyFetchResponse& policy) { |
| 198 // Stop any pending requests to store policy, then validate the new policy | 273 // Stop any pending requests to store policy, then validate the new policy |
| 199 // before storing it. | 274 // before storing it. |
| 200 weak_factory_.InvalidateWeakPtrs(); | 275 weak_factory_.InvalidateWeakPtrs(); |
| 201 scoped_ptr<em::PolicyFetchResponse> policy_copy( | 276 scoped_ptr<em::PolicyFetchResponse> policy_copy( |
| 202 new em::PolicyFetchResponse(policy)); | 277 new em::PolicyFetchResponse(policy)); |
| 203 Validate(policy_copy.Pass(), | 278 Validate(policy_copy.Pass(), |
| 279 scoped_ptr<em::PolicySigningKey>(), |
| 204 true, | 280 true, |
| 205 base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation, | 281 base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation, |
| 206 weak_factory_.GetWeakPtr())); | 282 weak_factory_.GetWeakPtr())); |
| 207 } | 283 } |
| 208 | 284 |
| 209 void UserCloudPolicyStore::Validate( | 285 void UserCloudPolicyStore::Validate( |
| 210 scoped_ptr<em::PolicyFetchResponse> policy, | 286 scoped_ptr<em::PolicyFetchResponse> policy, |
| 287 scoped_ptr<em::PolicySigningKey> cached_key, |
| 211 bool validate_in_background, | 288 bool validate_in_background, |
| 212 const UserCloudPolicyValidator::CompletionCallback& callback) { | 289 const UserCloudPolicyValidator::CompletionCallback& callback) { |
| 290 |
| 291 const bool signed_policy = policy->has_policy_data_signature(); |
| 292 |
| 213 // Configure the validator. | 293 // Configure the validator. |
| 214 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator( | 294 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator( |
| 215 policy.Pass(), | 295 policy.Pass(), |
| 216 CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE); | 296 CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE); |
| 217 | 297 |
| 218 // Validate the username if the user is signed in. | 298 // Validate the username if the user is signed in. |
| 219 if (!signin_username_.empty()) | 299 if (!signin_username_.empty()) { |
| 300 DVLOG(1) << "Validating username: " << signin_username_; |
| 220 validator->ValidateUsername(signin_username_); | 301 validator->ValidateUsername(signin_username_); |
| 302 } |
| 303 |
| 304 // There are 4 cases: |
| 305 // |
| 306 // 1) Validation after loading from cache with no cached key. |
| 307 // Action: Don't validate signature (migration from previously cached |
| 308 // unsigned blob). |
| 309 // |
| 310 // 2) Validation after loading from cache with a cached key |
| 311 // Action: Validate signature on policy blob but don't allow key rotation. |
| 312 // |
| 313 // 3) Validation after loading new policy from the server with no cached key |
| 314 // Action: Validate as initial key provisioning (case where we are migrating |
| 315 // from unsigned policy) |
| 316 // |
| 317 // 4) Validation after loading new policy from the server with a cached key |
| 318 // Action: Validate as normal, and allow key rotation. |
| 319 if (cached_key) { |
| 320 // Loading from cache should not change the cached keys. |
| 321 DCHECK(policy_key_.empty() || policy_key_ == cached_key->signing_key()); |
| 322 if (!signed_policy || !cached_key->has_signing_key()) { |
| 323 // Case #1 - loading from cache with no signing key. |
| 324 // TODO(atwilson): Reject policy with no cached key once |
| 325 // kMetricPolicyHasVerifiedCachedKey rises to a high enough level. |
| 326 DLOG(WARNING) << "Allowing unsigned cached blob for migration"; |
| 327 } else { |
| 328 // Case #2 - loading from cache with a cached key - just do normal |
| 329 // signature validation using this key. We're loading from cache so don't |
| 330 // allow key rotation. |
| 331 const bool no_rotation = false; |
| 332 validator->ValidateSignature(cached_key->signing_key(), |
| 333 verification_key_, |
| 334 cached_key->signing_key_signature(), |
| 335 no_rotation); |
| 336 } |
| 337 } else { |
| 338 // No passed cached_key - this is not validating the initial policy load |
| 339 // from cache, but rather an update from the server. |
| 340 if (policy_key_.empty()) { |
| 341 // Case #3 - no valid existing policy key, so this new policy fetch should |
| 342 // include an initial key provision. |
| 343 validator->ValidateInitialKey(verification_key_); |
| 344 } else { |
| 345 // Case #4 - verify new policy with existing key. We always allow key |
| 346 // rotation - the verification key will prevent invalid policy from being |
| 347 // injected. |policy_key_| is already known to be valid, so no |
| 348 // verification signature is passed in. |
| 349 const bool allow_rotation = true; |
| 350 validator->ValidateSignature( |
| 351 policy_key_, verification_key_, std::string(), allow_rotation); |
| 352 } |
| 353 } |
| 221 | 354 |
| 222 if (validate_in_background) { | 355 if (validate_in_background) { |
| 223 // Start validation in the background. The Validator will free itself once | 356 // Start validation in the background. The Validator will free itself once |
| 224 // validation is complete. | 357 // validation is complete. |
| 225 validator.release()->StartValidation(callback); | 358 validator.release()->StartValidation(callback); |
| 226 } else { | 359 } else { |
| 227 // Run validation immediately and invoke the callback with the results. | 360 // Run validation immediately and invoke the callback with the results. |
| 228 validator->RunValidation(); | 361 validator->RunValidation(); |
| 229 callback.Run(validator.get()); | 362 callback.Run(validator.get()); |
| 230 } | 363 } |
| 231 } | 364 } |
| 232 | 365 |
| 233 void UserCloudPolicyStore::StorePolicyAfterValidation( | 366 void UserCloudPolicyStore::StorePolicyAfterValidation( |
| 234 UserCloudPolicyValidator* validator) { | 367 UserCloudPolicyValidator* validator) { |
| 235 validation_status_ = validator->status(); | 368 validation_status_ = validator->status(); |
| 236 DVLOG(1) << "Policy validation complete: status = " << validation_status_; | 369 DVLOG(1) << "Policy validation complete: status = " << validation_status_; |
| 237 if (!validator->success()) { | 370 if (!validator->success()) { |
| 238 status_ = STATUS_VALIDATION_ERROR; | 371 status_ = STATUS_VALIDATION_ERROR; |
| 239 NotifyStoreError(); | 372 NotifyStoreError(); |
| 240 return; | 373 return; |
| 241 } | 374 } |
| 242 | 375 |
| 243 // Persist the validated policy (just fire a task - don't bother getting a | 376 // Persist the validated policy (just fire a task - don't bother getting a |
| 244 // reply because we can't do anything if it fails). | 377 // reply because we can't do anything if it fails). |
| 245 background_task_runner()->PostTask( | 378 background_task_runner()->PostTask( |
| 246 FROM_HERE, | 379 FROM_HERE, |
| 247 base::Bind(&StorePolicyToDiskOnBackgroundThread, | 380 base::Bind(&StorePolicyToDiskOnBackgroundThread, |
| 248 backing_file_path_, *validator->policy())); | 381 policy_path_, key_path_, *validator->policy())); |
| 249 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); | 382 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); |
| 383 |
| 384 // If the key was rotated, update our local cache of the key. |
| 385 if (validator->policy()->has_new_public_key()) |
| 386 policy_key_ = validator->policy()->new_public_key(); |
| 250 status_ = STATUS_OK; | 387 status_ = STATUS_OK; |
| 251 NotifyStoreLoaded(); | 388 NotifyStoreLoaded(); |
| 252 } | 389 } |
| 253 | 390 |
| 254 } // namespace policy | 391 } // namespace policy |
| OLD | NEW |