Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: chrome/browser/policy/user_cloud_policy_store_chromeos.cc

Issue 12183017: Verify the signature on user cloud policy downloads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/policy/user_cloud_policy_store_chromeos.h" 5 #include "chrome/browser/policy/user_cloud_policy_store_chromeos.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
11 #include "base/callback.h" 11 #include "base/callback.h"
12 #include "base/file_util.h" 12 #include "base/file_util.h"
13 #include "base/memory/ref_counted.h" 13 #include "base/memory/ref_counted.h"
14 #include "base/stringprintf.h"
14 #include "chrome/browser/policy/proto/cloud_policy.pb.h" 15 #include "chrome/browser/policy/proto/cloud_policy.pb.h"
15 #include "chrome/browser/policy/proto/device_management_local.pb.h" 16 #include "chrome/browser/policy/proto/device_management_local.pb.h"
16 #include "chrome/browser/policy/user_policy_disk_cache.h" 17 #include "chrome/browser/policy/user_policy_disk_cache.h"
18 #include "chrome/browser/policy/user_policy_key.h"
17 #include "chrome/browser/policy/user_policy_token_loader.h" 19 #include "chrome/browser/policy/user_policy_token_loader.h"
20 #include "chromeos/dbus/cryptohome_client.h"
18 #include "chromeos/dbus/session_manager_client.h" 21 #include "chromeos/dbus/session_manager_client.h"
19 #include "content/public/browser/browser_thread.h" 22 #include "content/public/browser/browser_thread.h"
20 #include "google_apis/gaia/gaia_auth_util.h" 23 #include "google_apis/gaia/gaia_auth_util.h"
21 24
22 namespace em = enterprise_management; 25 namespace em = enterprise_management;
23 26
24 namespace policy { 27 namespace policy {
25 28
26 namespace { 29 namespace {
27 // Subdirectory in the user's profile for storing user policies. 30 // Subdirectory in the user's profile for storing user policies.
28 const FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Device Management"); 31 const FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Device Management");
29 // File in the above directory for stroing user policy dmtokens. 32 // File in the above directory for stroing user policy dmtokens.
30 const FilePath::CharType kTokenCacheFile[] = FILE_PATH_LITERAL("Token"); 33 const FilePath::CharType kTokenCacheFile[] = FILE_PATH_LITERAL("Token");
31 // File in the above directory for storing user policy data. 34 // File in the above directory for storing user policy data.
32 const FilePath::CharType kPolicyCacheFile[] = FILE_PATH_LITERAL("Policy"); 35 const FilePath::CharType kPolicyCacheFile[] = FILE_PATH_LITERAL("Policy");
36 // Path that contains the user policy key after the user's vault is mounted.
37 // "%s" must be substituted with the sanitized username.
38 const FilePath::CharType kPolicyKeyFile[] =
39 FILE_PATH_LITERAL("/var/run/user_policy/%s.pub");
Mattias Nissler (ping if slow) 2013/02/04 16:44:57 can we make user_policy/%s a directory? That'd all
Joao da Silva 2013/02/06 00:34:37 In progress at https://gerrit.chromium.org/gerrit/
33 } // namespace 40 } // namespace
34 41
35 42
36 // Helper class for loading legacy policy caches. 43 // Helper class for loading legacy policy caches.
37 class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate, 44 class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate,
38 public UserPolicyDiskCache::Delegate { 45 public UserPolicyDiskCache::Delegate {
39 public: 46 public:
40 typedef base::Callback<void(const std::string&, 47 typedef base::Callback<void(const std::string&,
41 const std::string&, 48 const std::string&,
42 CloudPolicyStore::Status, 49 CloudPolicyStore::Status,
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 return CloudPolicyStore::STATUS_OK; 146 return CloudPolicyStore::STATUS_OK;
140 case UserPolicyDiskCache::LOAD_RESULT_PARSE_ERROR: 147 case UserPolicyDiskCache::LOAD_RESULT_PARSE_ERROR:
141 case UserPolicyDiskCache::LOAD_RESULT_READ_ERROR: 148 case UserPolicyDiskCache::LOAD_RESULT_READ_ERROR:
142 return CloudPolicyStore::STATUS_LOAD_ERROR; 149 return CloudPolicyStore::STATUS_LOAD_ERROR;
143 } 150 }
144 NOTREACHED(); 151 NOTREACHED();
145 return CloudPolicyStore::STATUS_OK; 152 return CloudPolicyStore::STATUS_OK;
146 } 153 }
147 154
148 UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS( 155 UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS(
156 chromeos::CryptohomeClient* cryptohome_client,
149 chromeos::SessionManagerClient* session_manager_client, 157 chromeos::SessionManagerClient* session_manager_client,
150 const std::string& username, 158 const std::string& username,
151 const FilePath& legacy_token_cache_file, 159 const FilePath& legacy_token_cache_file,
152 const FilePath& legacy_policy_cache_file) 160 const FilePath& legacy_policy_cache_file)
153 : session_manager_client_(session_manager_client), 161 : cryptohome_client_(cryptohome_client),
162 session_manager_client_(session_manager_client),
154 username_(username), 163 username_(username),
155 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), 164 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
156 legacy_cache_dir_(legacy_token_cache_file.DirName()), 165 legacy_cache_dir_(legacy_token_cache_file.DirName()),
157 legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file, 166 legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file,
158 legacy_policy_cache_file)), 167 legacy_policy_cache_file)),
159 legacy_caches_loaded_(false) {} 168 legacy_caches_loaded_(false) {}
160 169
161 UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {} 170 UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {}
162 171
163 void UserCloudPolicyStoreChromeOS::Store( 172 void UserCloudPolicyStoreChromeOS::Store(
164 const em::PolicyFetchResponse& policy) { 173 const em::PolicyFetchResponse& policy) {
165 // Cancel all pending requests. 174 // Cancel all pending requests.
166 weak_factory_.InvalidateWeakPtrs(); 175 weak_factory_.InvalidateWeakPtrs();
167 Validate( 176 scoped_ptr<em::PolicyFetchResponse> response(
168 scoped_ptr<em::PolicyFetchResponse>(new em::PolicyFetchResponse(policy)), 177 new em::PolicyFetchResponse(policy));
169 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated, 178 EnsurePolicyKeyLoaded(
170 weak_factory_.GetWeakPtr())); 179 base::Bind(&UserCloudPolicyStoreChromeOS::ValidatePolicyForStore,
180 weak_factory_.GetWeakPtr(),
181 base::Passed(&response)));
171 } 182 }
172 183
173 void UserCloudPolicyStoreChromeOS::Load() { 184 void UserCloudPolicyStoreChromeOS::Load() {
174 // Cancel all pending requests. 185 // Cancel all pending requests.
175 weak_factory_.InvalidateWeakPtrs(); 186 weak_factory_.InvalidateWeakPtrs();
176 session_manager_client_->RetrieveUserPolicy( 187 session_manager_client_->RetrieveUserPolicy(
177 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyRetrieved, 188 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyRetrieved,
178 weak_factory_.GetWeakPtr())); 189 weak_factory_.GetWeakPtr()));
179 } 190 }
180 191
192 void UserCloudPolicyStoreChromeOS::ValidatePolicyForStore(
193 scoped_ptr<em::PolicyFetchResponse> policy) {
194 // Create and configure a validator.
195 scoped_ptr<UserCloudPolicyValidator> validator =
196 CreateValidator(policy.Pass());
197 validator->ValidateUsername(username_);
198 if (policy_key_->key().empty()) {
199 validator->ValidateInitialKey();
200 } else {
201 const bool allow_rotation = true;
202 validator->ValidateSignature(policy_key_->key(), allow_rotation);
203 }
204
205 // Start validation. The Validator will free itself once validation is
206 // complete.
207 validator.release()->StartValidation(
208 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
209 weak_factory_.GetWeakPtr()));
210 }
211
212 void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
213 UserCloudPolicyValidator* validator) {
214 validation_status_ = validator->status();
215 if (!validator->success()) {
216 status_ = STATUS_VALIDATION_ERROR;
217 NotifyStoreError();
218 return;
219 }
220
221 std::string policy_blob;
222 if (!validator->policy()->SerializeToString(&policy_blob)) {
223 status_ = STATUS_SERIALIZE_ERROR;
224 NotifyStoreError();
225 return;
226 }
227
228 session_manager_client_->StoreUserPolicy(
229 policy_blob,
230 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored,
231 weak_factory_.GetWeakPtr()));
232 }
233
234 void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) {
235 if (!success) {
236 status_ = STATUS_STORE_ERROR;
237 NotifyStoreError();
238 } else {
239 // Load the policy right after storing it, to make sure it was accepted by
240 // the session manager. An additional validation is performed after the
241 // load; reload the key for that validation too, in case it was rotated.
242 // This method is the callback for a store operation, which is posted after
243 // validating the policy, and the validation is performed after ensuring the
244 // key is loaded, so |policy_key_| is valid here.
245 policy_key_->Load(base::Bind(&UserCloudPolicyStoreChromeOS::Load,
246 weak_factory_.GetWeakPtr()));
247 }
248 }
249
181 void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved( 250 void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved(
182 const std::string& policy_blob) { 251 const std::string& policy_blob) {
183 if (policy_blob.empty()) { 252 if (policy_blob.empty()) {
184 // Policy fetch failed. Try legacy caches if we haven't done that already. 253 // Policy fetch failed. Try legacy caches if we haven't done that already.
185 if (!legacy_caches_loaded_ && legacy_loader_.get()) { 254 if (!legacy_caches_loaded_ && legacy_loader_.get()) {
186 legacy_caches_loaded_ = true; 255 legacy_caches_loaded_ = true;
187 legacy_loader_->Load( 256 legacy_loader_->Load(
188 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished, 257 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished,
189 weak_factory_.GetWeakPtr())); 258 weak_factory_.GetWeakPtr()));
190 } else { 259 } else {
191 // session_manager doesn't have policy. Adjust internal state and notify 260 // session_manager doesn't have policy. Adjust internal state and notify
192 // the world about the policy update. 261 // the world about the policy update.
193 policy_.reset(); 262 policy_.reset();
194 NotifyStoreLoaded(); 263 NotifyStoreLoaded();
195 } 264 }
196 return; 265 return;
197 } 266 }
198 267
199 // Policy is supplied by session_manager. Disregard legacy data from now on. 268 // Policy is supplied by session_manager. Disregard legacy data from now on.
200 legacy_loader_.reset(); 269 legacy_loader_.reset();
201 270
202 scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse()); 271 scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
203 if (!policy->ParseFromString(policy_blob)) { 272 if (!policy->ParseFromString(policy_blob)) {
204 status_ = STATUS_PARSE_ERROR; 273 status_ = STATUS_PARSE_ERROR;
205 NotifyStoreError(); 274 NotifyStoreError();
206 return; 275 return;
207 } 276 }
208 277
209 Validate(policy.Pass(), 278 // Load |policy_key_| to verify the loaded policy.
210 base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated, 279 EnsurePolicyKeyLoaded(
211 weak_factory_.GetWeakPtr())); 280 base::Bind(&UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy,
281 weak_factory_.GetWeakPtr(),
282 base::Passed(&policy)));
283 }
284
285 void UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy(
286 scoped_ptr<em::PolicyFetchResponse> policy) {
287 // Create and configure a validator for the loaded policy.
288 scoped_ptr<UserCloudPolicyValidator> validator =
289 CreateValidator(policy.Pass());
290 validator->ValidateUsername(username_);
291 const bool allow_rotation = false;
292 validator->ValidateSignature(policy_key_->key(), allow_rotation);
293 // Start validation. The Validator will free itself once validation is
294 // complete.
295 validator.release()->StartValidation(
296 base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated,
297 weak_factory_.GetWeakPtr()));
212 } 298 }
213 299
214 void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated( 300 void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
215 UserCloudPolicyValidator* validator) { 301 UserCloudPolicyValidator* validator) {
216 validation_status_ = validator->status(); 302 validation_status_ = validator->status();
217 if (!validator->success()) { 303 if (!validator->success()) {
218 status_ = STATUS_VALIDATION_ERROR; 304 status_ = STATUS_VALIDATION_ERROR;
219 NotifyStoreError(); 305 NotifyStoreError();
220 return; 306 return;
221 } 307 }
222 308
223 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); 309 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
224 status_ = STATUS_OK; 310 status_ = STATUS_OK;
225 311
226 // Policy has been loaded successfully. This indicates that new-style policy 312 // Policy has been loaded successfully. This indicates that new-style policy
227 // is working, so the legacy cache directory can be removed. 313 // is working, so the legacy cache directory can be removed.
228 if (!legacy_cache_dir_.empty()) { 314 if (!legacy_cache_dir_.empty()) {
229 content::BrowserThread::PostBlockingPoolTask( 315 content::BrowserThread::PostBlockingPoolTask(
230 FROM_HERE, 316 FROM_HERE,
231 base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir, 317 base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir,
232 legacy_cache_dir_)); 318 legacy_cache_dir_));
233 legacy_cache_dir_.clear(); 319 legacy_cache_dir_.clear();
234 } 320 }
235 NotifyStoreLoaded(); 321 NotifyStoreLoaded();
236 } 322 }
237 323
238 void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
239 UserCloudPolicyValidator* validator) {
240 validation_status_ = validator->status();
241 if (!validator->success()) {
242 status_ = STATUS_VALIDATION_ERROR;
243 NotifyStoreError();
244 return;
245 }
246
247 std::string policy_blob;
248 if (!validator->policy()->SerializeToString(&policy_blob)) {
249 status_ = STATUS_SERIALIZE_ERROR;
250 NotifyStoreError();
251 return;
252 }
253
254 session_manager_client_->StoreUserPolicy(
255 policy_blob,
256 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored,
257 weak_factory_.GetWeakPtr()));
258 }
259
260 void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) {
261 if (!success) {
262 status_ = STATUS_STORE_ERROR;
263 NotifyStoreError();
264 } else {
265 // TODO(mnissler): Once we do signature verifications, we'll have to reload
266 // the key at this point to account for key rotations.
267 Load();
268 }
269 }
270
271 void UserCloudPolicyStoreChromeOS::Validate(
272 scoped_ptr<em::PolicyFetchResponse> policy,
273 const UserCloudPolicyValidator::CompletionCallback& callback) {
274 // Configure the validator.
275 scoped_ptr<UserCloudPolicyValidator> validator =
276 CreateValidator(policy.Pass());
277 validator->ValidateUsername(username_);
278
279 // TODO(mnissler): Do a signature check here as well. The key is stored by
280 // session_manager in the root-owned cryptohome area, which is currently
281 // inaccessible to Chrome though.
282
283 // Start validation. The Validator will free itself once validation is
284 // complete.
285 validator.release()->StartValidation(callback);
286 }
287
288 void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished( 324 void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished(
289 const std::string& dm_token, 325 const std::string& dm_token,
290 const std::string& device_id, 326 const std::string& device_id,
291 Status status, 327 Status status,
292 scoped_ptr<em::PolicyFetchResponse> policy) { 328 scoped_ptr<em::PolicyFetchResponse> policy) {
293 status_ = status; 329 status_ = status;
294 if (policy.get()) { 330 if (policy.get()) {
295 Validate(policy.Pass(), 331 // Create and configure a validator for the loaded legacy policy. Note that
296 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated, 332 // the signature on this policy is not verified.
297 weak_factory_.GetWeakPtr(), 333 scoped_ptr<UserCloudPolicyValidator> validator =
298 dm_token, device_id)); 334 CreateValidator(policy.Pass());
335 validator->ValidateUsername(username_);
336 validator.release()->StartValidation(
337 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated,
338 weak_factory_.GetWeakPtr(),
339 dm_token,
340 device_id));
299 } else { 341 } else {
300 InstallLegacyTokens(dm_token, device_id); 342 InstallLegacyTokens(dm_token, device_id);
301 } 343 }
302 } 344 }
303 345
304 void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated( 346 void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated(
305 const std::string& dm_token, 347 const std::string& dm_token,
306 const std::string& device_id, 348 const std::string& device_id,
307 UserCloudPolicyValidator* validator) { 349 UserCloudPolicyValidator* validator) {
308 validation_status_ = validator->status(); 350 validation_status_ = validator->status();
309 if (validator->success()) { 351 if (validator->success()) {
310 status_ = STATUS_OK; 352 status_ = STATUS_OK;
311 InstallPolicy(validator->policy_data().Pass(), 353 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
312 validator->payload().Pass());
313 354
314 // Clear the public key version. The public key version field would 355 // Clear the public key version. The public key version field would
315 // otherwise indicate that we have key installed in the store when in fact 356 // otherwise indicate that we have key installed in the store when in fact
316 // we haven't. This may result in policy updates failing signature 357 // we haven't. This may result in policy updates failing signature
317 // verification. 358 // verification.
318 policy_->clear_public_key_version(); 359 policy_->clear_public_key_version();
319 } else { 360 } else {
320 status_ = STATUS_VALIDATION_ERROR; 361 status_ = STATUS_VALIDATION_ERROR;
321 } 362 }
322 363
(...skipping 16 matching lines...) Expand all
339 // Tell the rest of the world that the policy load completed. 380 // Tell the rest of the world that the policy load completed.
340 NotifyStoreLoaded(); 381 NotifyStoreLoaded();
341 } 382 }
342 383
343 // static 384 // static
344 void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(const FilePath& dir) { 385 void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(const FilePath& dir) {
345 if (file_util::PathExists(dir) && !file_util::Delete(dir, true)) 386 if (file_util::PathExists(dir) && !file_util::Delete(dir, true))
346 LOG(ERROR) << "Failed to remove cache dir " << dir.value(); 387 LOG(ERROR) << "Failed to remove cache dir " << dir.value();
347 } 388 }
348 389
390 void UserCloudPolicyStoreChromeOS::EnsurePolicyKeyLoaded(
391 const base::Closure& callback) {
392 if (policy_key_) {
393 callback.Run();
394 } else {
395 // Get the hashed username that's part of the key's path, to create a new
396 // |policy_key_| later.
397 cryptohome_client_->GetSanitizedUsername(username_,
398 base::Bind(&UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername,
399 weak_factory_.GetWeakPtr(),
400 callback));
401 }
402 }
403
404 void UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername(
405 const base::Closure& callback,
406 chromeos::DBusMethodCallStatus call_status,
407 const std::string& sanitized_username) {
408 // EnsurePolicyKeyLoaded() may have been called twice before getting a reply
409 // from dbus; the second request will just reload the key.
410 if (!policy_key_) {
411 // The default empty path will always yield an empty key.
412 FilePath path;
413 if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS &&
414 !sanitized_username.empty()) {
415 path = FilePath(
416 base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
417 }
418 policy_key_.reset(new UserPolicyKey(path));
419 }
420 policy_key_->Load(callback);
421 }
422
349 } // namespace policy 423 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698