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

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: Comment 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 // Path within |user_policy_key_dir_| that contains the policy key.
28 const FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Device Management"); 31 // "%s" must be substituted with the sanitized username.
29 // File in the above directory for stroing user policy dmtokens. 32 const FilePath::CharType kPolicyKeyFile[] = FILE_PATH_LITERAL("%s/policy.pub");
30 const FilePath::CharType kTokenCacheFile[] = FILE_PATH_LITERAL("Token");
31 // File in the above directory for storing user policy data.
32 const FilePath::CharType kPolicyCacheFile[] = FILE_PATH_LITERAL("Policy");
33 } // namespace 33 } // namespace
34 34
35 35
36 // Helper class for loading legacy policy caches. 36 // Helper class for loading legacy policy caches.
37 class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate, 37 class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate,
38 public UserPolicyDiskCache::Delegate { 38 public UserPolicyDiskCache::Delegate {
39 public: 39 public:
40 typedef base::Callback<void(const std::string&, 40 typedef base::Callback<void(const std::string&,
41 const std::string&, 41 const std::string&,
42 CloudPolicyStore::Status, 42 CloudPolicyStore::Status,
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 return CloudPolicyStore::STATUS_OK; 139 return CloudPolicyStore::STATUS_OK;
140 case UserPolicyDiskCache::LOAD_RESULT_PARSE_ERROR: 140 case UserPolicyDiskCache::LOAD_RESULT_PARSE_ERROR:
141 case UserPolicyDiskCache::LOAD_RESULT_READ_ERROR: 141 case UserPolicyDiskCache::LOAD_RESULT_READ_ERROR:
142 return CloudPolicyStore::STATUS_LOAD_ERROR; 142 return CloudPolicyStore::STATUS_LOAD_ERROR;
143 } 143 }
144 NOTREACHED(); 144 NOTREACHED();
145 return CloudPolicyStore::STATUS_OK; 145 return CloudPolicyStore::STATUS_OK;
146 } 146 }
147 147
148 UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS( 148 UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS(
149 chromeos::CryptohomeClient* cryptohome_client,
149 chromeos::SessionManagerClient* session_manager_client, 150 chromeos::SessionManagerClient* session_manager_client,
150 const std::string& username, 151 const std::string& username,
152 const FilePath& user_policy_key_dir,
151 const FilePath& legacy_token_cache_file, 153 const FilePath& legacy_token_cache_file,
152 const FilePath& legacy_policy_cache_file) 154 const FilePath& legacy_policy_cache_file)
153 : session_manager_client_(session_manager_client), 155 : cryptohome_client_(cryptohome_client),
156 session_manager_client_(session_manager_client),
154 username_(username), 157 username_(username),
158 user_policy_key_dir_(user_policy_key_dir),
155 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), 159 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
156 legacy_cache_dir_(legacy_token_cache_file.DirName()), 160 legacy_cache_dir_(legacy_token_cache_file.DirName()),
157 legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file, 161 legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file,
158 legacy_policy_cache_file)), 162 legacy_policy_cache_file)),
159 legacy_caches_loaded_(false) {} 163 legacy_caches_loaded_(false) {}
160 164
161 UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {} 165 UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {}
162 166
163 void UserCloudPolicyStoreChromeOS::Store( 167 void UserCloudPolicyStoreChromeOS::Store(
164 const em::PolicyFetchResponse& policy) { 168 const em::PolicyFetchResponse& policy) {
165 // Cancel all pending requests. 169 // Cancel all pending requests.
166 weak_factory_.InvalidateWeakPtrs(); 170 weak_factory_.InvalidateWeakPtrs();
167 Validate( 171 scoped_ptr<em::PolicyFetchResponse> response(
168 scoped_ptr<em::PolicyFetchResponse>(new em::PolicyFetchResponse(policy)), 172 new em::PolicyFetchResponse(policy));
169 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated, 173 EnsurePolicyKeyLoaded(
170 weak_factory_.GetWeakPtr())); 174 base::Bind(&UserCloudPolicyStoreChromeOS::ValidatePolicyForStore,
175 weak_factory_.GetWeakPtr(),
176 base::Passed(&response)));
171 } 177 }
172 178
173 void UserCloudPolicyStoreChromeOS::Load() { 179 void UserCloudPolicyStoreChromeOS::Load() {
174 // Cancel all pending requests. 180 // Cancel all pending requests.
175 weak_factory_.InvalidateWeakPtrs(); 181 weak_factory_.InvalidateWeakPtrs();
176 session_manager_client_->RetrieveUserPolicy( 182 session_manager_client_->RetrieveUserPolicy(
177 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyRetrieved, 183 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyRetrieved,
178 weak_factory_.GetWeakPtr())); 184 weak_factory_.GetWeakPtr()));
179 } 185 }
180 186
187 void UserCloudPolicyStoreChromeOS::ValidatePolicyForStore(
188 scoped_ptr<em::PolicyFetchResponse> policy) {
189 // Create and configure a validator.
190 scoped_ptr<UserCloudPolicyValidator> validator =
191 CreateValidator(policy.Pass());
192 validator->ValidateUsername(username_);
193 if (policy_key_->key().empty()) {
194 validator->ValidateInitialKey();
195 } else {
196 const bool allow_rotation = true;
197 validator->ValidateSignature(policy_key_->key(), allow_rotation);
198 }
199
200 // Start validation. The Validator will free itself once validation is
Mattias Nissler (ping if slow) 2013/02/07 14:12:07 nit: s/free/delete/
Joao da Silva 2013/02/07 16:32:00 Done.
201 // complete.
202 validator.release()->StartValidation(
203 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
204 weak_factory_.GetWeakPtr()));
205 }
206
207 void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
208 UserCloudPolicyValidator* validator) {
209 validation_status_ = validator->status();
210 if (!validator->success()) {
211 status_ = STATUS_VALIDATION_ERROR;
212 NotifyStoreError();
213 return;
214 }
215
216 std::string policy_blob;
217 if (!validator->policy()->SerializeToString(&policy_blob)) {
218 status_ = STATUS_SERIALIZE_ERROR;
219 NotifyStoreError();
220 return;
221 }
222
223 session_manager_client_->StoreUserPolicy(
224 policy_blob,
225 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored,
226 weak_factory_.GetWeakPtr()));
227 }
228
229 void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) {
230 if (!success) {
231 status_ = STATUS_STORE_ERROR;
232 NotifyStoreError();
233 } else {
234 // Load the policy right after storing it, to make sure it was accepted by
235 // the session manager. An additional validation is performed after the
236 // load; reload the key for that validation too, in case it was rotated.
237 // This method is the callback for a store operation, which is posted after
238 // validating the policy, and the validation is performed after ensuring the
239 // key is loaded, so |policy_key_| is valid here.
240 policy_key_->Load(base::Bind(&UserCloudPolicyStoreChromeOS::Load,
241 weak_factory_.GetWeakPtr()));
242 }
243 }
244
181 void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved( 245 void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved(
182 const std::string& policy_blob) { 246 const std::string& policy_blob) {
183 if (policy_blob.empty()) { 247 if (policy_blob.empty()) {
184 // Policy fetch failed. Try legacy caches if we haven't done that already. 248 // Policy fetch failed. Try legacy caches if we haven't done that already.
185 if (!legacy_caches_loaded_ && legacy_loader_.get()) { 249 if (!legacy_caches_loaded_ && legacy_loader_.get()) {
186 legacy_caches_loaded_ = true; 250 legacy_caches_loaded_ = true;
187 legacy_loader_->Load( 251 legacy_loader_->Load(
188 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished, 252 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished,
189 weak_factory_.GetWeakPtr())); 253 weak_factory_.GetWeakPtr()));
190 } else { 254 } else {
191 // session_manager doesn't have policy. Adjust internal state and notify 255 // session_manager doesn't have policy. Adjust internal state and notify
192 // the world about the policy update. 256 // the world about the policy update.
193 policy_.reset(); 257 policy_.reset();
194 NotifyStoreLoaded(); 258 NotifyStoreLoaded();
195 } 259 }
196 return; 260 return;
197 } 261 }
198 262
199 // Policy is supplied by session_manager. Disregard legacy data from now on. 263 // Policy is supplied by session_manager. Disregard legacy data from now on.
200 legacy_loader_.reset(); 264 legacy_loader_.reset();
201 265
202 scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse()); 266 scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
203 if (!policy->ParseFromString(policy_blob)) { 267 if (!policy->ParseFromString(policy_blob)) {
204 status_ = STATUS_PARSE_ERROR; 268 status_ = STATUS_PARSE_ERROR;
205 NotifyStoreError(); 269 NotifyStoreError();
206 return; 270 return;
207 } 271 }
208 272
209 Validate(policy.Pass(), 273 // Load |policy_key_| to verify the loaded policy.
210 base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated, 274 EnsurePolicyKeyLoaded(
211 weak_factory_.GetWeakPtr())); 275 base::Bind(&UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy,
276 weak_factory_.GetWeakPtr(),
277 base::Passed(&policy)));
278 }
279
280 void UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy(
281 scoped_ptr<em::PolicyFetchResponse> policy) {
282 // Create and configure a validator for the loaded policy.
283 scoped_ptr<UserCloudPolicyValidator> validator =
284 CreateValidator(policy.Pass());
285 validator->ValidateUsername(username_);
286 const bool allow_rotation = false;
287 validator->ValidateSignature(policy_key_->key(), allow_rotation);
288 // Start validation. The Validator will free itself once validation is
Joao da Silva 2013/02/07 16:32:00 Changed here too for consistency.
289 // complete.
290 validator.release()->StartValidation(
291 base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated,
292 weak_factory_.GetWeakPtr()));
212 } 293 }
213 294
214 void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated( 295 void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
215 UserCloudPolicyValidator* validator) { 296 UserCloudPolicyValidator* validator) {
216 validation_status_ = validator->status(); 297 validation_status_ = validator->status();
217 if (!validator->success()) { 298 if (!validator->success()) {
218 status_ = STATUS_VALIDATION_ERROR; 299 status_ = STATUS_VALIDATION_ERROR;
219 NotifyStoreError(); 300 NotifyStoreError();
220 return; 301 return;
221 } 302 }
222 303
223 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); 304 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
224 status_ = STATUS_OK; 305 status_ = STATUS_OK;
225 306
226 // Policy has been loaded successfully. This indicates that new-style policy 307 // Policy has been loaded successfully. This indicates that new-style policy
227 // is working, so the legacy cache directory can be removed. 308 // is working, so the legacy cache directory can be removed.
228 if (!legacy_cache_dir_.empty()) { 309 if (!legacy_cache_dir_.empty()) {
229 content::BrowserThread::PostBlockingPoolTask( 310 content::BrowserThread::PostBlockingPoolTask(
230 FROM_HERE, 311 FROM_HERE,
231 base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir, 312 base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir,
232 legacy_cache_dir_)); 313 legacy_cache_dir_));
233 legacy_cache_dir_.clear(); 314 legacy_cache_dir_.clear();
234 } 315 }
235 NotifyStoreLoaded(); 316 NotifyStoreLoaded();
236 } 317 }
237 318
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
Joao da Silva 2013/02/07 16:32:00 I think the comment was originally from here.
284 // complete.
285 validator.release()->StartValidation(callback);
286 }
287
288 void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished( 319 void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished(
289 const std::string& dm_token, 320 const std::string& dm_token,
290 const std::string& device_id, 321 const std::string& device_id,
291 Status status, 322 Status status,
292 scoped_ptr<em::PolicyFetchResponse> policy) { 323 scoped_ptr<em::PolicyFetchResponse> policy) {
293 status_ = status; 324 status_ = status;
294 if (policy.get()) { 325 if (policy.get()) {
295 Validate(policy.Pass(), 326 // Create and configure a validator for the loaded legacy policy. Note that
296 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated, 327 // the signature on this policy is not verified.
297 weak_factory_.GetWeakPtr(), 328 scoped_ptr<UserCloudPolicyValidator> validator =
298 dm_token, device_id)); 329 CreateValidator(policy.Pass());
330 validator->ValidateUsername(username_);
331 validator.release()->StartValidation(
332 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated,
333 weak_factory_.GetWeakPtr(),
334 dm_token,
335 device_id));
299 } else { 336 } else {
300 InstallLegacyTokens(dm_token, device_id); 337 InstallLegacyTokens(dm_token, device_id);
301 } 338 }
302 } 339 }
303 340
304 void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated( 341 void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated(
305 const std::string& dm_token, 342 const std::string& dm_token,
306 const std::string& device_id, 343 const std::string& device_id,
307 UserCloudPolicyValidator* validator) { 344 UserCloudPolicyValidator* validator) {
308 validation_status_ = validator->status(); 345 validation_status_ = validator->status();
309 if (validator->success()) { 346 if (validator->success()) {
310 status_ = STATUS_OK; 347 status_ = STATUS_OK;
311 InstallPolicy(validator->policy_data().Pass(), 348 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
312 validator->payload().Pass());
313 349
314 // Clear the public key version. The public key version field would 350 // 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 351 // 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 352 // we haven't. This may result in policy updates failing signature
317 // verification. 353 // verification.
318 policy_->clear_public_key_version(); 354 policy_->clear_public_key_version();
319 } else { 355 } else {
320 status_ = STATUS_VALIDATION_ERROR; 356 status_ = STATUS_VALIDATION_ERROR;
321 } 357 }
322 358
(...skipping 16 matching lines...) Expand all
339 // Tell the rest of the world that the policy load completed. 375 // Tell the rest of the world that the policy load completed.
340 NotifyStoreLoaded(); 376 NotifyStoreLoaded();
341 } 377 }
342 378
343 // static 379 // static
344 void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(const FilePath& dir) { 380 void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(const FilePath& dir) {
345 if (file_util::PathExists(dir) && !file_util::Delete(dir, true)) 381 if (file_util::PathExists(dir) && !file_util::Delete(dir, true))
346 LOG(ERROR) << "Failed to remove cache dir " << dir.value(); 382 LOG(ERROR) << "Failed to remove cache dir " << dir.value();
347 } 383 }
348 384
385 void UserCloudPolicyStoreChromeOS::EnsurePolicyKeyLoaded(
386 const base::Closure& callback) {
387 if (policy_key_) {
388 callback.Run();
389 } else {
390 // Get the hashed username that's part of the key's path, to create a new
391 // |policy_key_| later.
392 cryptohome_client_->GetSanitizedUsername(username_,
393 base::Bind(&UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername,
394 weak_factory_.GetWeakPtr(),
395 callback));
396 }
397 }
398
399 void UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername(
400 const base::Closure& callback,
401 chromeos::DBusMethodCallStatus call_status,
402 const std::string& sanitized_username) {
403 // EnsurePolicyKeyLoaded() may have been called twice before getting a reply
404 // from dbus; the second request will just reload the key.
405 if (!policy_key_) {
406 // The default empty path will always yield an empty key.
407 FilePath path;
408 if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS &&
409 !sanitized_username.empty()) {
410 path = user_policy_key_dir_.Append(
411 base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
412 }
413 policy_key_.reset(new UserPolicyKey(path));
414 }
415 policy_key_->Load(callback);
416 }
417
349 } // namespace policy 418 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698