// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/settings/session_manager_operation.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/files/file_path.h" #include "base/message_loop/message_loop.h" #include "base/stl_util.h" #include "base/task_runner_util.h" #include "base/threading/sequenced_worker_pool.h" #include "chrome/browser/chromeos/login/users/user.h" #include "chrome/browser/chromeos/login/users/user_manager.h" #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/chromeos/settings/owner_key_util.h" #include "chrome/browser/net/nss_context.h" #include "components/policy/core/common/cloud/cloud_policy_constants.h" #include "content/public/browser/browser_thread.h" #include "crypto/rsa_private_key.h" #include "crypto/signature_creator.h" #include "policy/proto/device_management_backend.pb.h" namespace em = enterprise_management; namespace chromeos { SessionManagerOperation::SessionManagerOperation(const Callback& callback) : session_manager_client_(NULL), weak_factory_(this), callback_(callback), force_key_load_(false), slot_(NULL), is_loading_(false) {} SessionManagerOperation::~SessionManagerOperation() {} void SessionManagerOperation::Start( SessionManagerClient* session_manager_client, scoped_refptr owner_key_util, scoped_refptr owner_key) { session_manager_client_ = session_manager_client; owner_key_util_ = owner_key_util; owner_key_ = owner_key; Run(); } void SessionManagerOperation::RestartLoad(bool key_changed) { if (key_changed) owner_key_ = NULL; if (!is_loading_) return; // Abort previous load operations. weak_factory_.InvalidateWeakPtrs(); // Mark as not loading to start loading again. is_loading_ = false; StartLoading(); } void SessionManagerOperation::StartLoading() { if (is_loading_) return; is_loading_ = true; EnsureOwnerKey(base::Bind(&SessionManagerOperation::RetrieveDeviceSettings, weak_factory_.GetWeakPtr())); } void SessionManagerOperation::ReportResult( DeviceSettingsService::Status status) { callback_.Run(this, status); } void SessionManagerOperation::EnsureOwnerKey(const base::Closure& callback) { if (force_key_load_ || !owner_key_.get() || !owner_key_->public_key()) { scoped_refptr task_runner = content::BrowserThread::GetBlockingPool() ->GetTaskRunnerWithShutdownBehavior( base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); base::PostTaskAndReplyWithResult( task_runner.get(), FROM_HERE, base::Bind(&SessionManagerOperation::LoadOwnerKey, owner_key_util_, owner_key_, slot_), base::Bind(&SessionManagerOperation::StoreOwnerKey, weak_factory_.GetWeakPtr(), callback)); } else { callback.Run(); } } // static scoped_refptr SessionManagerOperation::LoadOwnerKey( scoped_refptr util, scoped_refptr current_key, PK11SlotInfo* slot) { scoped_ptr > public_key; scoped_ptr private_key; // Keep any already-existing keys. if (current_key.get()) { if (current_key->public_key()) public_key.reset(new std::vector(*current_key->public_key())); if (current_key->private_key()) private_key.reset(current_key->private_key()->Copy()); } if (!public_key.get() && util->IsPublicKeyPresent()) { public_key.reset(new std::vector()); if (!util->ImportPublicKey(public_key.get())) LOG(ERROR) << "Failed to load public owner key."; } if (public_key.get() && !private_key.get()) { private_key.reset(util->FindPrivateKeyInSlot(*public_key, slot)); if (!private_key.get()) VLOG(1) << "Failed to load private owner key."; } return new OwnerKey(public_key.Pass(), private_key.Pass()); } void SessionManagerOperation::StoreOwnerKey(const base::Closure& callback, scoped_refptr new_key) { force_key_load_ = false; owner_key_ = new_key; if (!owner_key_.get() || !owner_key_->public_key()) { ReportResult(DeviceSettingsService::STORE_KEY_UNAVAILABLE); return; } callback.Run(); } void SessionManagerOperation::RetrieveDeviceSettings() { session_manager_client()->RetrieveDevicePolicy( base::Bind(&SessionManagerOperation::ValidateDeviceSettings, weak_factory_.GetWeakPtr())); } void SessionManagerOperation::ValidateDeviceSettings( const std::string& policy_blob) { scoped_ptr policy(new em::PolicyFetchResponse()); if (policy_blob.empty()) { ReportResult(DeviceSettingsService::STORE_NO_POLICY); return; } if (!policy->ParseFromString(policy_blob) || !policy->IsInitialized()) { ReportResult(DeviceSettingsService::STORE_INVALID_POLICY); return; } base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool(); scoped_refptr background_task_runner = pool->GetSequencedTaskRunnerWithShutdownBehavior( pool->GetSequenceToken(), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); policy::DeviceCloudPolicyValidator* validator = policy::DeviceCloudPolicyValidator::Create(policy.Pass(), background_task_runner); // Policy auto-generated by session manager doesn't include a timestamp, so // the timestamp shouldn't be verified in that case. // // Additionally, offline devices can get their clock set backwards in time // under some hardware conditions; checking the timestamp now could likely // find a value in the future, and prevent the user from signing-in or // starting guest mode. Tlsdate will eventually fix the clock when the device // is back online, but the network configuration may come from device ONC. // // To prevent all of these issues the timestamp is just not verified when // loading the device policy from the cache. Note that the timestamp is still // verified during enrollment and when a new policy is fetched from the // server. validator->ValidateAgainstCurrentPolicy( policy_data_.get(), policy::CloudPolicyValidatorBase::TIMESTAMP_NOT_REQUIRED, policy::CloudPolicyValidatorBase::DM_TOKEN_NOT_REQUIRED); validator->ValidatePolicyType(policy::dm_protocol::kChromeDevicePolicyType); validator->ValidatePayload(); // We don't check the DMServer verification key below, because the signing // key is validated when it is installed. validator->ValidateSignature(owner_key_->public_key_as_string(), std::string(), // No key validation check. std::string(), false); validator->StartValidation( base::Bind(&SessionManagerOperation::ReportValidatorStatus, weak_factory_.GetWeakPtr())); } void SessionManagerOperation::ReportValidatorStatus( policy::DeviceCloudPolicyValidator* validator) { DeviceSettingsService::Status status = DeviceSettingsService::STORE_VALIDATION_ERROR; if (validator->success()) { status = DeviceSettingsService::STORE_SUCCESS; policy_data_ = validator->policy_data().Pass(); device_settings_ = validator->payload().Pass(); } else { LOG(ERROR) << "Policy validation failed: " << validator->status(); // Those are mostly caused by RTC loss and are recoverable. if (validator->status() == policy::DeviceCloudPolicyValidator::VALIDATION_BAD_TIMESTAMP) { status = DeviceSettingsService::STORE_TEMP_VALIDATION_ERROR; } } ReportResult(status); } LoadSettingsOperation::LoadSettingsOperation(const Callback& callback) : SessionManagerOperation(callback) {} LoadSettingsOperation::~LoadSettingsOperation() {} void LoadSettingsOperation::Run() { StartLoading(); } StoreSettingsOperation::StoreSettingsOperation( const Callback& callback, scoped_ptr policy) : SessionManagerOperation(callback), policy_(policy.Pass()), weak_factory_(this) {} StoreSettingsOperation::~StoreSettingsOperation() {} void StoreSettingsOperation::Run() { session_manager_client()->StoreDevicePolicy( policy_->SerializeAsString(), base::Bind(&StoreSettingsOperation::HandleStoreResult, weak_factory_.GetWeakPtr())); } void StoreSettingsOperation::HandleStoreResult(bool success) { if (!success) ReportResult(DeviceSettingsService::STORE_OPERATION_FAILED); else StartLoading(); } SignAndStoreSettingsOperation::SignAndStoreSettingsOperation( const Callback& callback, scoped_ptr new_policy) : SessionManagerOperation(callback), new_policy_(new_policy.Pass()), weak_factory_(this) { DCHECK(new_policy_); } SignAndStoreSettingsOperation::~SignAndStoreSettingsOperation() {} void SignAndStoreSettingsOperation::Run() { EnsureOwnerKey(base::Bind(&SignAndStoreSettingsOperation::StartSigning, weak_factory_.GetWeakPtr())); } void SignAndStoreSettingsOperation::StartSigning() { if (!owner_key().get() || !owner_key()->private_key() || new_policy_->username().empty()) { ReportResult(DeviceSettingsService::STORE_KEY_UNAVAILABLE); return; } base::PostTaskAndReplyWithResult( content::BrowserThread::GetBlockingPool(), FROM_HERE, base::Bind(&SignAndStoreSettingsOperation::AssembleAndSignPolicy, base::Passed(&new_policy_), owner_key()), base::Bind(&SignAndStoreSettingsOperation::StoreDeviceSettingsBlob, weak_factory_.GetWeakPtr())); } // static std::string SignAndStoreSettingsOperation::AssembleAndSignPolicy( scoped_ptr policy, scoped_refptr owner_key) { // Assemble the policy. em::PolicyFetchResponse policy_response; if (!policy->SerializeToString(policy_response.mutable_policy_data())) { LOG(ERROR) << "Failed to encode policy payload."; return std::string(); } // Generate the signature. scoped_ptr signature_creator( crypto::SignatureCreator::Create(owner_key->private_key())); signature_creator->Update( reinterpret_cast(policy_response.policy_data().c_str()), policy_response.policy_data().size()); std::vector signature_bytes; std::string policy_blob; if (!signature_creator->Final(&signature_bytes)) { LOG(ERROR) << "Failed to create policy signature."; return std::string(); } policy_response.mutable_policy_data_signature()->assign( reinterpret_cast(vector_as_array(&signature_bytes)), signature_bytes.size()); return policy_response.SerializeAsString(); } void SignAndStoreSettingsOperation::StoreDeviceSettingsBlob( std::string device_settings_blob) { if (device_settings_blob.empty()) { ReportResult(DeviceSettingsService::STORE_POLICY_ERROR); return; } session_manager_client()->StoreDevicePolicy( device_settings_blob, base::Bind(&SignAndStoreSettingsOperation::HandleStoreResult, weak_factory_.GetWeakPtr())); } void SignAndStoreSettingsOperation::HandleStoreResult(bool success) { if (!success) ReportResult(DeviceSettingsService::STORE_OPERATION_FAILED); else StartLoading(); } } // namespace chromeos