1// Copyright 2014 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 "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h" 6 7#include <string> 8 9#include "base/bind.h" 10#include "base/bind_helpers.h" 11#include "base/callback.h" 12#include "base/command_line.h" 13#include "base/prefs/pref_service.h" 14#include "base/threading/thread_checker.h" 15#include "chrome/browser/chrome_notification_types.h" 16#include "chrome/browser/chromeos/profiles/profile_helper.h" 17#include "chrome/browser/chromeos/settings/cros_settings.h" 18#include "chrome/browser/chromeos/settings/session_manager_operation.h" 19#include "chrome/browser/profiles/profile.h" 20#include "chromeos/dbus/dbus_thread_manager.h" 21#include "chromeos/tpm_token_loader.h" 22#include "components/ownership/owner_key_util.h" 23#include "components/policy/core/common/cloud/cloud_policy_constants.h" 24#include "content/public/browser/browser_thread.h" 25#include "content/public/browser/notification_details.h" 26#include "content/public/browser/notification_service.h" 27#include "content/public/browser/notification_source.h" 28#include "content/public/common/content_switches.h" 29#include "crypto/nss_util.h" 30#include "crypto/nss_util_internal.h" 31#include "crypto/rsa_private_key.h" 32#include "crypto/scoped_nss_types.h" 33#include "crypto/signature_creator.h" 34 35namespace em = enterprise_management; 36 37using content::BrowserThread; 38using ownership::OwnerKeyUtil; 39using ownership::PrivateKey; 40using ownership::PublicKey; 41 42namespace chromeos { 43 44namespace { 45 46DeviceSettingsService* g_device_settings_service_for_testing = NULL; 47 48bool IsOwnerInTests(const std::string& user_id) { 49 if (user_id.empty() || 50 !CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestType) || 51 !CrosSettings::IsInitialized()) { 52 return false; 53 } 54 const base::Value* value = CrosSettings::Get()->GetPref(kDeviceOwner); 55 if (!value || value->GetType() != base::Value::TYPE_STRING) 56 return false; 57 return static_cast<const base::StringValue*>(value)->GetString() == user_id; 58} 59 60void LoadPrivateKeyByPublicKey( 61 const scoped_refptr<OwnerKeyUtil>& owner_key_util, 62 scoped_refptr<PublicKey> public_key, 63 const std::string& username_hash, 64 const base::Callback<void(const scoped_refptr<PublicKey>& public_key, 65 const scoped_refptr<PrivateKey>& private_key)>& 66 callback) { 67 crypto::EnsureNSSInit(); 68 crypto::ScopedPK11Slot slot = 69 crypto::GetPublicSlotForChromeOSUser(username_hash); 70 scoped_refptr<PrivateKey> private_key(new PrivateKey( 71 owner_key_util->FindPrivateKeyInSlot(public_key->data(), slot.get()))); 72 BrowserThread::PostTask(BrowserThread::UI, 73 FROM_HERE, 74 base::Bind(callback, public_key, private_key)); 75} 76 77void LoadPrivateKey( 78 const scoped_refptr<OwnerKeyUtil>& owner_key_util, 79 const std::string username_hash, 80 const base::Callback<void(const scoped_refptr<PublicKey>& public_key, 81 const scoped_refptr<PrivateKey>& private_key)>& 82 callback) { 83 std::vector<uint8> public_key_data; 84 scoped_refptr<PublicKey> public_key; 85 if (!owner_key_util->ImportPublicKey(&public_key_data)) { 86 scoped_refptr<PrivateKey> private_key; 87 BrowserThread::PostTask(BrowserThread::UI, 88 FROM_HERE, 89 base::Bind(callback, public_key, private_key)); 90 return; 91 } 92 public_key = new PublicKey(); 93 public_key->data().swap(public_key_data); 94 bool rv = BrowserThread::PostTask(BrowserThread::IO, 95 FROM_HERE, 96 base::Bind(&LoadPrivateKeyByPublicKey, 97 owner_key_util, 98 public_key, 99 username_hash, 100 callback)); 101 if (!rv) { 102 // IO thread doesn't exists in unit tests, but it's safe to use NSS from 103 // BlockingPool in unit tests. 104 LoadPrivateKeyByPublicKey( 105 owner_key_util, public_key, username_hash, callback); 106 } 107} 108 109bool DoesPrivateKeyExistAsyncHelper( 110 const scoped_refptr<OwnerKeyUtil>& owner_key_util) { 111 std::vector<uint8> public_key; 112 if (!owner_key_util->ImportPublicKey(&public_key)) 113 return false; 114 scoped_ptr<crypto::RSAPrivateKey> key( 115 crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key)); 116 bool is_owner = key.get() != NULL; 117 return is_owner; 118} 119 120// Checks whether NSS slots with private key are mounted or 121// not. Responds via |callback|. 122void DoesPrivateKeyExistAsync( 123 const scoped_refptr<OwnerKeyUtil>& owner_key_util, 124 const OwnerSettingsServiceChromeOS::IsOwnerCallback& callback) { 125 if (!owner_key_util.get()) { 126 callback.Run(false); 127 return; 128 } 129 scoped_refptr<base::TaskRunner> task_runner = 130 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( 131 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); 132 base::PostTaskAndReplyWithResult( 133 task_runner.get(), 134 FROM_HERE, 135 base::Bind(&DoesPrivateKeyExistAsyncHelper, owner_key_util), 136 callback); 137} 138 139DeviceSettingsService* GetDeviceSettingsService() { 140 if (g_device_settings_service_for_testing) 141 return g_device_settings_service_for_testing; 142 return DeviceSettingsService::IsInitialized() ? DeviceSettingsService::Get() 143 : NULL; 144} 145 146} // namespace 147 148OwnerSettingsServiceChromeOS::OwnerSettingsServiceChromeOS( 149 Profile* profile, 150 const scoped_refptr<OwnerKeyUtil>& owner_key_util) 151 : ownership::OwnerSettingsService(owner_key_util), 152 profile_(profile), 153 waiting_for_profile_creation_(true), 154 waiting_for_tpm_token_(true), 155 weak_factory_(this) { 156 if (TPMTokenLoader::IsInitialized()) { 157 TPMTokenLoader::TPMTokenStatus tpm_token_status = 158 TPMTokenLoader::Get()->IsTPMTokenEnabled( 159 base::Bind(&OwnerSettingsServiceChromeOS::OnTPMTokenReady, 160 weak_factory_.GetWeakPtr())); 161 waiting_for_tpm_token_ = 162 tpm_token_status == TPMTokenLoader::TPM_TOKEN_STATUS_UNDETERMINED; 163 } 164 165 if (DBusThreadManager::IsInitialized() && 166 DBusThreadManager::Get()->GetSessionManagerClient()) { 167 DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this); 168 } 169 170 registrar_.Add(this, 171 chrome::NOTIFICATION_PROFILE_CREATED, 172 content::Source<Profile>(profile_)); 173} 174 175OwnerSettingsServiceChromeOS::~OwnerSettingsServiceChromeOS() { 176 DCHECK(thread_checker_.CalledOnValidThread()); 177 if (DBusThreadManager::IsInitialized() && 178 DBusThreadManager::Get()->GetSessionManagerClient()) { 179 DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this); 180 } 181} 182 183void OwnerSettingsServiceChromeOS::OnTPMTokenReady( 184 bool /* tpm_token_enabled */) { 185 DCHECK(thread_checker_.CalledOnValidThread()); 186 waiting_for_tpm_token_ = false; 187 188 // TPMTokenLoader initializes the TPM and NSS database which is necessary to 189 // determine ownership. Force a reload once we know these are initialized. 190 ReloadKeypair(); 191} 192 193void OwnerSettingsServiceChromeOS::SignAndStorePolicyAsync( 194 scoped_ptr<em::PolicyData> policy, 195 const base::Closure& callback) { 196 DCHECK(thread_checker_.CalledOnValidThread()); 197 SignAndStoreSettingsOperation* operation = new SignAndStoreSettingsOperation( 198 base::Bind(&OwnerSettingsServiceChromeOS::HandleCompletedOperation, 199 weak_factory_.GetWeakPtr(), 200 callback), 201 policy.Pass()); 202 operation->set_owner_settings_service(weak_factory_.GetWeakPtr()); 203 pending_operations_.push_back(operation); 204 if (pending_operations_.front() == operation) 205 StartNextOperation(); 206} 207 208void OwnerSettingsServiceChromeOS::Observe( 209 int type, 210 const content::NotificationSource& source, 211 const content::NotificationDetails& details) { 212 DCHECK(thread_checker_.CalledOnValidThread()); 213 if (type != chrome::NOTIFICATION_PROFILE_CREATED) { 214 NOTREACHED(); 215 return; 216 } 217 218 Profile* profile = content::Source<Profile>(source).ptr(); 219 if (profile != profile_) { 220 NOTREACHED(); 221 return; 222 } 223 224 waiting_for_profile_creation_ = false; 225 ReloadKeypair(); 226} 227 228void OwnerSettingsServiceChromeOS::OwnerKeySet(bool success) { 229 DCHECK(thread_checker_.CalledOnValidThread()); 230 if (success) 231 ReloadKeypair(); 232} 233 234// static 235void OwnerSettingsServiceChromeOS::IsOwnerForSafeModeAsync( 236 const std::string& user_hash, 237 const scoped_refptr<OwnerKeyUtil>& owner_key_util, 238 const IsOwnerCallback& callback) { 239 CHECK(chromeos::LoginState::Get()->IsInSafeMode()); 240 241 // Make sure NSS is initialized and NSS DB is loaded for the user before 242 // searching for the owner key. 243 BrowserThread::PostTaskAndReply( 244 BrowserThread::IO, 245 FROM_HERE, 246 base::Bind(base::IgnoreResult(&crypto::InitializeNSSForChromeOSUser), 247 user_hash, 248 ProfileHelper::GetProfilePathByUserIdHash(user_hash)), 249 base::Bind(&DoesPrivateKeyExistAsync, owner_key_util, callback)); 250} 251 252// static 253void OwnerSettingsServiceChromeOS::SetDeviceSettingsServiceForTesting( 254 DeviceSettingsService* device_settings_service) { 255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 256 g_device_settings_service_for_testing = device_settings_service; 257} 258 259void OwnerSettingsServiceChromeOS::OnPostKeypairLoadedActions() { 260 DCHECK(thread_checker_.CalledOnValidThread()); 261 262 user_id_ = profile_->GetProfileName(); 263 const bool is_owner = IsOwner() || IsOwnerInTests(user_id_); 264 if (is_owner && GetDeviceSettingsService()) 265 GetDeviceSettingsService()->InitOwner(user_id_, weak_factory_.GetWeakPtr()); 266} 267 268void OwnerSettingsServiceChromeOS::ReloadKeypairImpl(const base::Callback< 269 void(const scoped_refptr<PublicKey>& public_key, 270 const scoped_refptr<PrivateKey>& private_key)>& callback) { 271 DCHECK(thread_checker_.CalledOnValidThread()); 272 273 if (waiting_for_profile_creation_ || waiting_for_tpm_token_) 274 return; 275 scoped_refptr<base::TaskRunner> task_runner = 276 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( 277 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); 278 task_runner->PostTask( 279 FROM_HERE, 280 base::Bind(&LoadPrivateKey, 281 owner_key_util_, 282 ProfileHelper::GetUserIdHashFromProfile(profile_), 283 callback)); 284} 285 286void OwnerSettingsServiceChromeOS::StartNextOperation() { 287 DeviceSettingsService* service = GetDeviceSettingsService(); 288 if (!pending_operations_.empty() && service && 289 service->session_manager_client()) { 290 pending_operations_.front()->Start( 291 service->session_manager_client(), owner_key_util_, public_key_); 292 } 293} 294 295void OwnerSettingsServiceChromeOS::HandleCompletedOperation( 296 const base::Closure& callback, 297 SessionManagerOperation* operation, 298 DeviceSettingsService::Status status) { 299 DCHECK_EQ(operation, pending_operations_.front()); 300 301 DeviceSettingsService* service = GetDeviceSettingsService(); 302 if (status == DeviceSettingsService::STORE_SUCCESS) { 303 service->set_policy_data(operation->policy_data().Pass()); 304 service->set_device_settings(operation->device_settings().Pass()); 305 } 306 307 if ((operation->public_key().get() && !public_key_.get()) || 308 (operation->public_key().get() && public_key_.get() && 309 operation->public_key()->data() != public_key_->data())) { 310 // Public part changed so we need to reload private part too. 311 ReloadKeypair(); 312 content::NotificationService::current()->Notify( 313 chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED, 314 content::Source<OwnerSettingsServiceChromeOS>(this), 315 content::NotificationService::NoDetails()); 316 } 317 service->OnSignAndStoreOperationCompleted(status); 318 if (!callback.is_null()) 319 callback.Run(); 320 321 pending_operations_.pop_front(); 322 delete operation; 323 StartNextOperation(); 324} 325 326} // namespace chromeos 327