Home | History | Annotate | Download | only in ownership
      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 
     35 namespace em = enterprise_management;
     36 
     37 using content::BrowserThread;
     38 using ownership::OwnerKeyUtil;
     39 using ownership::PrivateKey;
     40 using ownership::PublicKey;
     41 
     42 namespace chromeos {
     43 
     44 namespace {
     45 
     46 DeviceSettingsService* g_device_settings_service_for_testing = NULL;
     47 
     48 bool 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 
     60 void 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 
     77 void 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 
    109 bool 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|.
    122 void 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 
    139 DeviceSettingsService* 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 
    148 OwnerSettingsServiceChromeOS::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 
    175 OwnerSettingsServiceChromeOS::~OwnerSettingsServiceChromeOS() {
    176   DCHECK(thread_checker_.CalledOnValidThread());
    177   if (DBusThreadManager::IsInitialized() &&
    178       DBusThreadManager::Get()->GetSessionManagerClient()) {
    179     DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
    180   }
    181 }
    182 
    183 void 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 
    193 void 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 
    208 void 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 
    228 void OwnerSettingsServiceChromeOS::OwnerKeySet(bool success) {
    229   DCHECK(thread_checker_.CalledOnValidThread());
    230   if (success)
    231     ReloadKeypair();
    232 }
    233 
    234 // static
    235 void 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
    253 void 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 
    259 void 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 
    268 void 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 
    286 void 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 
    295 void 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