diff options
author | ygorshenin@chromium.org <ygorshenin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-21 01:50:25 +0000 |
---|---|---|
committer | ygorshenin@chromium.org <ygorshenin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-21 01:50:25 +0000 |
commit | 196e53e84cfd2533fe8a195fafb7a46e41440c00 (patch) | |
tree | 98a343569dc922e682a720c5f0f5b2aa8e8c2d7f | |
parent | f571bc032bdfab736cb212b56e83dcb95ec5d7c6 (diff) | |
download | chromium_src-196e53e84cfd2533fe8a195fafb7a46e41440c00.zip chromium_src-196e53e84cfd2533fe8a195fafb7a46e41440c00.tar.gz chromium_src-196e53e84cfd2533fe8a195fafb7a46e41440c00.tar.bz2 |
Implemented profile-aware owner key loading.
BUG=230018
TEST=manual
Review URL: https://codereview.chromium.org/270663002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271802 0039d316-1c4b-4281-b951-d872f2087c98
22 files changed, 462 insertions, 57 deletions
diff --git a/chrome/browser/chromeos/login/auth/parallel_authenticator.cc b/chrome/browser/chromeos/login/auth/parallel_authenticator.cc index 04457ff..099c9e0 100644 --- a/chrome/browser/chromeos/login/auth/parallel_authenticator.cc +++ b/chrome/browser/chromeos/login/auth/parallel_authenticator.cc @@ -17,6 +17,7 @@ #include "chrome/browser/chromeos/login/auth/user_context.h" #include "chrome/browser/chromeos/login/users/user.h" #include "chrome/browser/chromeos/login/users/user_manager.h" +#include "chrome/browser/chromeos/ownership/owner_settings_service_factory.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/common/chrome_switches.h" #include "chromeos/cryptohome/async_method_caller.h" @@ -488,9 +489,10 @@ bool ParallelAuthenticator::VerifyOwner() { owner_is_verified_ = true; return true; } - // Now we can continue reading the private key. - DeviceSettingsService::Get()->SetUsername( + + OwnerSettingsServiceFactory::GetInstance()->SetUsername( current_state_->user_context.GetUserID()); + // This should trigger certificate loading, which is needed in order to // correctly determine if the current user is the owner. if (LoginState::IsInitialized()) { diff --git a/chrome/browser/chromeos/login/users/user_manager_impl.cc b/chrome/browser/chromeos/login/users/user_manager_impl.cc index d5ba933..86bf5da 100644 --- a/chrome/browser/chromeos/login/users/user_manager_impl.cc +++ b/chrome/browser/chromeos/login/users/user_manager_impl.cc @@ -43,6 +43,7 @@ #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/net/network_portal_detector.h" #include "chrome/browser/chromeos/net/network_portal_detector_strategy.h" +#include "chrome/browser/chromeos/ownership/owner_settings_service_factory.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/device_local_account.h" #include "chrome/browser/chromeos/profiles/multiprofiles_session_aborted_dialog.h" @@ -1566,10 +1567,8 @@ void UserManagerImpl::NotifyOnLogin() { // Owner must be first user in session. DeviceSettingsService can't deal with // multiple user and will mix up ownership, crbug.com/230018. if (GetLoggedInUsers().size() == 1) { - // Indicate to DeviceSettingsService that the owner key may have become - // available. - DeviceSettingsService::Get()->SetUsername(active_user_->email()); - + OwnerSettingsServiceFactory::GetInstance()->SetUsername( + active_user_->email()); if (NetworkPortalDetector::IsInitialized()) { NetworkPortalDetector::Get()->SetStrategy( PortalDetectorStrategy::STRATEGY_ID_SESSION); diff --git a/chrome/browser/chromeos/ownership/owner_settings_service.cc b/chrome/browser/chromeos/ownership/owner_settings_service.cc new file mode 100644 index 0000000..fa7a21a --- /dev/null +++ b/chrome/browser/chromeos/ownership/owner_settings_service.cc @@ -0,0 +1,72 @@ +// Copyright 2014 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/ownership/owner_settings_service.h" + +#include <string> + +#include "base/bind.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/chromeos/login/users/user.h" +#include "chrome/browser/chromeos/login/users/user_manager.h" +#include "chrome/browser/chromeos/ownership/owner_settings_service_factory.h" +#include "chrome/browser/chromeos/settings/device_settings_service.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_source.h" +#include "crypto/nss_util_internal.h" +#include "crypto/scoped_nss_types.h" + +using content::BrowserThread; + +namespace chromeos { + +OwnerSettingsService::OwnerSettingsService(Profile* profile) + : profile_(profile), weak_factory_(this) { + registrar_.Add(this, + chrome::NOTIFICATION_PROFILE_CREATED, + content::Source<Profile>(profile_)); +} + +OwnerSettingsService::~OwnerSettingsService() { +} + +void OwnerSettingsService::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type != chrome::NOTIFICATION_PROFILE_CREATED) { + NOTREACHED(); + return; + } + + Profile* profile = content::Source<Profile>(source).ptr(); + if (profile != profile_) { + NOTREACHED(); + return; + } + + ReloadOwnerKey(); +} + +void OwnerSettingsService::ReloadOwnerKey() { + if (!UserManager::IsInitialized()) + return; + const User* user = UserManager::Get()->GetUserByProfile(profile_); + if (!user || !user->is_profile_created()) + return; + std::string user_id = user->email(); + if (user_id != OwnerSettingsServiceFactory::GetInstance()->GetUsername()) + return; + BrowserThread::PostTaskAndReplyWithResult( + BrowserThread::IO, + FROM_HERE, + base::Bind(&crypto::GetPublicSlotForChromeOSUser, user->username_hash()), + base::Bind(&DeviceSettingsService::InitOwner, + base::Unretained(DeviceSettingsService::Get()), + user_id)); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/ownership/owner_settings_service.h b/chrome/browser/chromeos/ownership/owner_settings_service.h new file mode 100644 index 0000000..8324373 --- /dev/null +++ b/chrome/browser/chromeos/ownership/owner_settings_service.h @@ -0,0 +1,51 @@ +// Copyright 2014 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. + +#ifndef CHROME_BROWSER_CHROMEOS_OWNERSHIP_OWNER_SETTINGS_SERVICE_H_ +#define CHROME_BROWSER_CHROMEOS_OWNERSHIP_OWNER_SETTINGS_SERVICE_H_ + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/keyed_service/core/keyed_service.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" + +class Profile; + +namespace chromeos { + +// This class reloads owner key from profile NSS slots. +// +// TODO (ygorshenin@): move write path for device settings here +// (crbug.com/230018). +class OwnerSettingsService : public KeyedService, + public content::NotificationObserver { + public: + virtual ~OwnerSettingsService(); + + // NotificationObserver implementation: + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + private: + friend class OwnerSettingsServiceFactory; + + explicit OwnerSettingsService(Profile* profile); + + void ReloadOwnerKey(); + + Profile* profile_; + + content::NotificationRegistrar registrar_; + + base::WeakPtrFactory<OwnerSettingsService> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(OwnerSettingsService); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_OWNERSHIP_OWNER_SETTINGS_SERVICE_H_ diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_factory.cc b/chrome/browser/chromeos/ownership/owner_settings_service_factory.cc new file mode 100644 index 0000000..606e0e3 --- /dev/null +++ b/chrome/browser/chromeos/ownership/owner_settings_service_factory.cc @@ -0,0 +1,77 @@ +// Copyright 2014 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/ownership/owner_settings_service_factory.h" + +#include "chrome/browser/chromeos/login/users/user.h" +#include "chrome/browser/chromeos/login/users/user_manager.h" +#include "chrome/browser/chromeos/ownership/owner_settings_service.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/profiles/profile.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +namespace chromeos { + +OwnerSettingsServiceFactory::OwnerSettingsServiceFactory() + : BrowserContextKeyedServiceFactory( + "OwnerSettingsService", + BrowserContextDependencyManager::GetInstance()) { +} + +OwnerSettingsServiceFactory::~OwnerSettingsServiceFactory() { +} + +// static +OwnerSettingsService* OwnerSettingsServiceFactory::GetForProfile( + Profile* profile) { + return static_cast<OwnerSettingsService*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +// static +OwnerSettingsServiceFactory* OwnerSettingsServiceFactory::GetInstance() { + return Singleton<OwnerSettingsServiceFactory>::get(); +} + +void OwnerSettingsServiceFactory::SetUsername(const std::string& username) { + username_ = username; + if (!UserManager::IsInitialized()) + return; + const User* user = UserManager::Get()->FindUser(username_); + if (!user || !user->is_profile_created()) + return; + Profile* profile = UserManager::Get()->GetProfileByUser(user); + if (!profile) + return; + OwnerSettingsService* service = GetForProfile(profile); + + // It's safe to call ReloadOwnerKey() here, as profile is fully created + // at this time. + if (service) + service->ReloadOwnerKey(); +} + +std::string OwnerSettingsServiceFactory::GetUsername() const { + return username_; +} + +// static +KeyedService* OwnerSettingsServiceFactory::BuildInstanceFor( + content::BrowserContext* browser_context) { + Profile* profile = static_cast<Profile*>(browser_context); + if (profile->IsGuestSession() || ProfileHelper::IsSigninProfile(profile)) + return NULL; + return new OwnerSettingsService(profile); +} + +bool OwnerSettingsServiceFactory::ServiceIsCreatedWithBrowserContext() const { + return true; +} + +KeyedService* OwnerSettingsServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return BuildInstanceFor(context); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_factory.h b/chrome/browser/chromeos/ownership/owner_settings_service_factory.h new file mode 100644 index 0000000..055fb3e --- /dev/null +++ b/chrome/browser/chromeos/ownership/owner_settings_service_factory.h @@ -0,0 +1,60 @@ +// Copyright 2014 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. + +#ifndef CHROME_BROWSER_CHROMEOS_OWNERSHIP_OWNER_SETTINGS_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_CHROMEOS_OWNERSHIP_OWNER_SETTINGS_SERVICE_FACTORY_H_ + +#include <string> + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class KeyedService; +class Profile; + +namespace chromeos { + +class OwnerSettingsService; + +class OwnerSettingsServiceFactory : public BrowserContextKeyedServiceFactory { + public: + static OwnerSettingsService* GetForProfile(Profile* profile); + + static OwnerSettingsServiceFactory* GetInstance(); + + // Sets name of the user supposed to be an owner. If profile + // for |username| is ready, request to reload owner key will be + // sent. Otherwise, owner key will be reloaded as soon as profile will + // be ready. + void SetUsername(const std::string& username); + + // Returns the name of the user supposed to be an owner. + std::string GetUsername() const; + + private: + friend struct DefaultSingletonTraits<OwnerSettingsServiceFactory>; + + OwnerSettingsServiceFactory(); + virtual ~OwnerSettingsServiceFactory(); + + static KeyedService* BuildInstanceFor(content::BrowserContext* context); + + // BrowserContextKeyedBaseFactory overrides: + virtual bool ServiceIsCreatedWithBrowserContext() const OVERRIDE; + + // BrowserContextKeyedServiceFactory implementation: + virtual KeyedService* BuildServiceInstanceFor( + content::BrowserContext* browser_context) const OVERRIDE; + + // Name of the user supposed to be an owner. + std::string username_; + + DISALLOW_COPY_AND_ASSIGN(OwnerSettingsServiceFactory); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_OWNERSHIP_OWNER_SETTINGS_SERVICE_FACTORY_H_ diff --git a/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc b/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc index d37f7af..6405b4b 100644 --- a/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc +++ b/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc @@ -222,7 +222,8 @@ void LoginScreenDefaultPolicyInSessionBrowsertest::SetUpOnMainThread() { LoginScreenDefaultPolicyBrowsertestBase::SetUpOnMainThread(); // Tell the DeviceSettingsService that there is no local owner. - chromeos::DeviceSettingsService::Get()->SetUsername(std::string()); + crypto::ScopedPK11Slot slot; + chromeos::DeviceSettingsService::Get()->InitOwner(std::string(), slot.Pass()); } void LoginScreenDefaultPolicyInSessionBrowsertest::VerifyPrefFollowsDefault( diff --git a/chrome/browser/chromeos/policy/power_policy_browsertest.cc b/chrome/browser/chromeos/policy/power_policy_browsertest.cc index 08b16f6..da8f416 100644 --- a/chrome/browser/chromeos/policy/power_policy_browsertest.cc +++ b/chrome/browser/chromeos/policy/power_policy_browsertest.cc @@ -307,7 +307,8 @@ void PowerPolicyInSessionBrowserTest::SetUpOnMainThread() { PowerPolicyBrowserTestBase::SetUpOnMainThread(); // Tell the DeviceSettingsService that there is no local owner. - chromeos::DeviceSettingsService::Get()->SetUsername(std::string()); + crypto::ScopedPK11Slot slot; + chromeos::DeviceSettingsService::Get()->InitOwner(std::string(), slot.Pass()); } // Verifies that device policy is applied on the login screen. diff --git a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc index 1da5a9b..b84ce88 100644 --- a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc +++ b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc @@ -139,7 +139,9 @@ TEST_F(DeviceSettingsProviderTest, SetPrefFailed) { TEST_F(DeviceSettingsProviderTest, SetPrefSucceed) { owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); - device_settings_service_.SetUsername(device_policy_.policy_data().username()); + crypto::ScopedPK11Slot slot; + device_settings_service_.InitOwner(device_policy_.policy_data().username(), + slot.Pass()); FlushDeviceSettings(); base::FundamentalValue value(true); @@ -167,7 +169,9 @@ TEST_F(DeviceSettingsProviderTest, SetPrefSucceed) { TEST_F(DeviceSettingsProviderTest, SetPrefTwice) { owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); - device_settings_service_.SetUsername(device_policy_.policy_data().username()); + crypto::ScopedPK11Slot slot; + device_settings_service_.InitOwner(device_policy_.policy_data().username(), + slot.Pass()); FlushDeviceSettings(); EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); diff --git a/chrome/browser/chromeos/settings/device_settings_service.cc b/chrome/browser/chromeos/settings/device_settings_service.cc index 0895080..0c54895 100644 --- a/chrome/browser/chromeos/settings/device_settings_service.cc +++ b/chrome/browser/chromeos/settings/device_settings_service.cc @@ -232,8 +232,13 @@ void DeviceSettingsService::IsCurrentUserOwnerAsync( } } -void DeviceSettingsService::SetUsername(const std::string& username) { +void DeviceSettingsService::InitOwner(const std::string& username, + crypto::ScopedPK11Slot slot) { + if (!username_.empty()) + return; + username_ = username; + slot_ = slot.Pass(); // The private key may have become available, so force a key reload. owner_key_ = NULL; @@ -292,14 +297,19 @@ void DeviceSettingsService::EnqueueLoad(bool force_key_load) { weak_factory_.GetWeakPtr(), base::Closure())); operation->set_force_key_load(force_key_load); + operation->set_username(username_); + operation->set_slot(slot_.get()); Enqueue(operation); } void DeviceSettingsService::EnsureReload(bool force_key_load) { - if (!pending_operations_.empty()) + if (!pending_operations_.empty()) { + pending_operations_.front()->set_username(username_); + pending_operations_.front()->set_slot(slot_.get()); pending_operations_.front()->RestartLoad(force_key_load); - else + } else { EnqueueLoad(force_key_load); + } } void DeviceSettingsService::StartNextOperation() { diff --git a/chrome/browser/chromeos/settings/device_settings_service.h b/chrome/browser/chromeos/settings/device_settings_service.h index 5b05513..f22f4a9 100644 --- a/chrome/browser/chromeos/settings/device_settings_service.h +++ b/chrome/browser/chromeos/settings/device_settings_service.h @@ -19,6 +19,7 @@ #include "chromeos/dbus/session_manager_client.h" #include "chromeos/tpm_token_loader.h" #include "components/policy/core/common/cloud/cloud_policy_validator.h" +#include "crypto/scoped_nss_types.h" #include "policy/proto/device_management_backend.pb.h" namespace crypto { @@ -199,7 +200,7 @@ class DeviceSettingsService : public SessionManagerClient::Observer, // Sets the identity of the user that's interacting with the service. This is // relevant only for writing settings through SignAndStore(). - void SetUsername(const std::string& username); + void InitOwner(const std::string& username, crypto::ScopedPK11Slot slot); const std::string& GetUsername() const; // Adds an observer. @@ -261,6 +262,7 @@ class DeviceSettingsService : public SessionManagerClient::Observer, pending_is_current_user_owner_callbacks_; std::string username_; + crypto::ScopedPK11Slot slot_; scoped_refptr<OwnerKey> owner_key_; // Whether TPM token still needs to be initialized. bool waiting_for_tpm_token_; diff --git a/chrome/browser/chromeos/settings/device_settings_service_unittest.cc b/chrome/browser/chromeos/settings/device_settings_service_unittest.cc index 727a34f..88c0114 100644 --- a/chrome/browser/chromeos/settings/device_settings_service_unittest.cc +++ b/chrome/browser/chromeos/settings/device_settings_service_unittest.cc @@ -164,7 +164,9 @@ TEST_F(DeviceSettingsServiceTest, SignAndStoreFailure) { device_settings_service_.status()); owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); - device_settings_service_.SetUsername(device_policy_.policy_data().username()); + crypto::ScopedPK11Slot slot; + device_settings_service_.InitOwner(device_policy_.policy_data().username(), + slot.Pass()); FlushDeviceSettings(); scoped_ptr<em::ChromeDeviceSettingsProto> new_device_settings( @@ -190,7 +192,9 @@ TEST_F(DeviceSettingsServiceTest, SignAndStoreSuccess) { device_settings_service_.status()); owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); - device_settings_service_.SetUsername(device_policy_.policy_data().username()); + crypto::ScopedPK11Slot slot; + device_settings_service_.InitOwner(device_policy_.policy_data().username(), + slot.Pass()); FlushDeviceSettings(); device_policy_.payload().mutable_device_policy_refresh_rate()-> @@ -229,7 +233,9 @@ TEST_F(DeviceSettingsServiceTest, SetManagementSettingsModeTransition) { device_settings_service_.status()); owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); - device_settings_service_.SetUsername(device_policy_.policy_data().username()); + crypto::ScopedPK11Slot slot; + device_settings_service_.InitOwner(device_policy_.policy_data().username(), + slot.Pass()); FlushDeviceSettings(); // The initial management mode should be NOT_MANAGED. @@ -343,7 +349,9 @@ TEST_F(DeviceSettingsServiceTest, SetManagementSettingsSuccess) { device_settings_service_.status()); owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); - device_settings_service_.SetUsername(device_policy_.policy_data().username()); + crypto::ScopedPK11Slot slot; + device_settings_service_.InitOwner(device_policy_.policy_data().username(), + slot.Pass()); FlushDeviceSettings(); device_settings_service_.SetManagementSettings( @@ -470,7 +478,9 @@ TEST_F(DeviceSettingsServiceTest, OwnershipStatus) { EXPECT_EQ(DeviceSettingsService::OWNERSHIP_TAKEN, ownership_status_); owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); - device_settings_service_.SetUsername(device_policy_.policy_data().username()); + crypto::ScopedPK11Slot slot; + device_settings_service_.InitOwner(device_policy_.policy_data().username(), + slot.Pass()); device_settings_service_.GetOwnershipStatusAsync( base::Bind(&DeviceSettingsServiceTest::SetOwnershipStatus, base::Unretained(this))); @@ -554,7 +564,9 @@ TEST_F(DeviceSettingsServiceTest, OnTPMTokenReadyForOwner) { EXPECT_FALSE(is_owner_set_); owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); - device_settings_service_.SetUsername(device_policy_.policy_data().username()); + crypto::ScopedPK11Slot slot; + device_settings_service_.InitOwner(device_policy_.policy_data().username(), + slot.Pass()); device_settings_service_.OnTPMTokenReady(); FlushDeviceSettings(); @@ -580,7 +592,9 @@ TEST_F(DeviceSettingsServiceTest, IsCurrentUserOwnerAsyncWithLoadedCerts) { owner_key_util_->SetPublicKeyFromPrivateKey(*device_policy_.GetSigningKey()); owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); - device_settings_service_.SetUsername(device_policy_.policy_data().username()); + crypto::ScopedPK11Slot slot; + device_settings_service_.InitOwner(device_policy_.policy_data().username(), + slot.Pass()); ReloadDeviceSettings(); device_settings_service_.OnTPMTokenReady(); diff --git a/chrome/browser/chromeos/settings/mock_owner_key_util.cc b/chrome/browser/chromeos/settings/mock_owner_key_util.cc index 1f77545..bd62af5 100644 --- a/chrome/browser/chromeos/settings/mock_owner_key_util.cc +++ b/chrome/browser/chromeos/settings/mock_owner_key_util.cc @@ -22,6 +22,12 @@ crypto::RSAPrivateKey* MockOwnerKeyUtil::FindPrivateKey( return private_key_.get() ? private_key_->Copy() : NULL; } +crypto::RSAPrivateKey* MockOwnerKeyUtil::FindPrivateKeyInSlot( + const std::vector<uint8>& key, + PK11SlotInfo* slot) { + return private_key_.get() ? private_key_->Copy() : NULL; +} + bool MockOwnerKeyUtil::IsPublicKeyPresent() { return !public_key_.empty(); } diff --git a/chrome/browser/chromeos/settings/mock_owner_key_util.h b/chrome/browser/chromeos/settings/mock_owner_key_util.h index c3f52bd..9c598e0 100644 --- a/chrome/browser/chromeos/settings/mock_owner_key_util.h +++ b/chrome/browser/chromeos/settings/mock_owner_key_util.h @@ -23,6 +23,9 @@ class MockOwnerKeyUtil : public OwnerKeyUtil { virtual bool ImportPublicKey(std::vector<uint8>* output) OVERRIDE; virtual crypto::RSAPrivateKey* FindPrivateKey( const std::vector<uint8>& key) OVERRIDE; + virtual crypto::RSAPrivateKey* FindPrivateKeyInSlot( + const std::vector<uint8>& key, + PK11SlotInfo* slot) OVERRIDE; virtual bool IsPublicKeyPresent() OVERRIDE; // Clears the public and private keys. diff --git a/chrome/browser/chromeos/settings/owner_key_util.cc b/chrome/browser/chromeos/settings/owner_key_util.cc index d98fe07..752c372 100644 --- a/chrome/browser/chromeos/settings/owner_key_util.cc +++ b/chrome/browser/chromeos/settings/owner_key_util.cc @@ -70,6 +70,12 @@ crypto::RSAPrivateKey* OwnerKeyUtilImpl::FindPrivateKey( return crypto::RSAPrivateKey::FindFromPublicKeyInfo(key); } +crypto::RSAPrivateKey* OwnerKeyUtilImpl::FindPrivateKeyInSlot( + const std::vector<uint8>& key, + PK11SlotInfo* slot) { + return crypto::RSAPrivateKey::FindFromPublicKeyInfoInSlot(key, slot); +} + bool OwnerKeyUtilImpl::IsPublicKeyPresent() { return base::PathExists(key_file_); } diff --git a/chrome/browser/chromeos/settings/owner_key_util.h b/chrome/browser/chromeos/settings/owner_key_util.h index 8e42a50..8522db7 100644 --- a/chrome/browser/chromeos/settings/owner_key_util.h +++ b/chrome/browser/chromeos/settings/owner_key_util.h @@ -13,6 +13,7 @@ #include "base/files/file_path.h" #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" +#include "net/cert/x509_util_nss.h" namespace base { class FilePath; @@ -38,9 +39,19 @@ class OwnerKeyUtil : public base::RefCountedThreadSafe<OwnerKeyUtil> { // Looks for the private key associated with |key| in the default slot, // and returns it if it can be found. Returns NULL otherwise. // Caller takes ownership. + // + // TODO (ygorshenin@): this function is deprecated and should be + // removed, see crbug.com/372316. virtual crypto::RSAPrivateKey* FindPrivateKey( const std::vector<uint8>& key) = 0; + // Looks for the private key associated with |key| in the |slot| + // and returns it if it can be found. Returns NULL otherwise. + // Caller takes ownership. + virtual crypto::RSAPrivateKey* FindPrivateKeyInSlot( + const std::vector<uint8>& key, + PK11SlotInfo* slot) = 0; + // Checks whether the public key is present in the file system. virtual bool IsPublicKeyPresent() = 0; @@ -63,6 +74,9 @@ class OwnerKeyUtilImpl : public OwnerKeyUtil { virtual bool ImportPublicKey(std::vector<uint8>* output) OVERRIDE; virtual crypto::RSAPrivateKey* FindPrivateKey( const std::vector<uint8>& key) OVERRIDE; + virtual crypto::RSAPrivateKey* FindPrivateKeyInSlot( + const std::vector<uint8>& key, + PK11SlotInfo* slot) OVERRIDE; virtual bool IsPublicKeyPresent() OVERRIDE; protected: diff --git a/chrome/browser/chromeos/settings/session_manager_operation.cc b/chrome/browser/chromeos/settings/session_manager_operation.cc index b95d283..f8ec443 100644 --- a/chrome/browser/chromeos/settings/session_manager_operation.cc +++ b/chrome/browser/chromeos/settings/session_manager_operation.cc @@ -11,8 +11,11 @@ #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" @@ -72,16 +75,19 @@ void SessionManagerOperation::ReportResult( void SessionManagerOperation::EnsureOwnerKey(const base::Closure& callback) { if (force_key_load_ || !owner_key_.get() || !owner_key_->public_key()) { scoped_refptr<base::TaskRunner> task_runner = - content::BrowserThread::GetBlockingPool()-> - GetTaskRunnerWithShutdownBehavior( - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); + 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_), + owner_key_util_, + owner_key_, + slot_), base::Bind(&SessionManagerOperation::StoreOwnerKey, - weak_factory_.GetWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), + callback)); } else { callback.Run(); } @@ -90,7 +96,8 @@ void SessionManagerOperation::EnsureOwnerKey(const base::Closure& callback) { // static scoped_refptr<OwnerKey> SessionManagerOperation::LoadOwnerKey( scoped_refptr<OwnerKeyUtil> util, - scoped_refptr<OwnerKey> current_key) { + scoped_refptr<OwnerKey> current_key, + PK11SlotInfo* slot) { scoped_ptr<std::vector<uint8> > public_key; scoped_ptr<crypto::RSAPrivateKey> private_key; @@ -109,7 +116,7 @@ scoped_refptr<OwnerKey> SessionManagerOperation::LoadOwnerKey( } if (public_key.get() && !private_key.get()) { - private_key.reset(util->FindPrivateKey(*public_key)); + private_key.reset(util->FindPrivateKeyInSlot(*public_key, slot)); if (!private_key.get()) VLOG(1) << "Failed to load private owner key."; } diff --git a/chrome/browser/chromeos/settings/session_manager_operation.h b/chrome/browser/chromeos/settings/session_manager_operation.h index f15e0eb..6d7d566 100644 --- a/chrome/browser/chromeos/settings/session_manager_operation.h +++ b/chrome/browser/chromeos/settings/session_manager_operation.h @@ -11,6 +11,7 @@ #include "base/memory/scoped_ptr.h" #include "chrome/browser/chromeos/policy/device_cloud_policy_validator.h" #include "chrome/browser/chromeos/settings/device_settings_service.h" +#include "net/cert/x509_util_nss.h" namespace enterprise_management { class ChromeDeviceSettingsProto; @@ -66,6 +67,9 @@ class SessionManagerOperation { force_key_load_ = force_key_load; } + void set_username(const std::string& username) { username_ = username; } + void set_slot(PK11SlotInfo* slot) { slot_ = slot; } + protected: // Runs the operation. The result is reported through |callback_|. virtual void Run() = 0; @@ -88,7 +92,8 @@ class SessionManagerOperation { // Loads the owner key from disk. Must be run on a thread that can do I/O. static scoped_refptr<OwnerKey> LoadOwnerKey( scoped_refptr<OwnerKeyUtil> util, - scoped_refptr<OwnerKey> current_key); + scoped_refptr<OwnerKey> current_key, + PK11SlotInfo* slot); // Stores the owner key loaded by LoadOwnerKey and calls |callback|. void StoreOwnerKey(const base::Closure& callback, @@ -112,6 +117,8 @@ class SessionManagerOperation { scoped_refptr<OwnerKey> owner_key_; bool force_key_load_; + std::string username_; + PK11SlotInfo* slot_; bool is_loading_; scoped_ptr<enterprise_management::PolicyData> policy_data_; diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index 6bca265..90cfa30 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc @@ -65,6 +65,7 @@ #include "chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.h" #include "chrome/browser/policy/schema_registry_service_factory.h" #if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/ownership/owner_settings_service_factory.h" #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h" #include "chrome/browser/chromeos/policy/recommendation_restorer_factory.h" #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h" @@ -214,6 +215,7 @@ EnsureBrowserContextKeyedServiceFactoriesBuilt() { policy::ProfilePolicyConnectorFactory::GetInstance(); #if defined(ENABLE_CONFIGURATION_POLICY) #if defined(OS_CHROMEOS) + chromeos::OwnerSettingsServiceFactory::GetInstance(); policy::PolicyCertServiceFactory::GetInstance(); policy::RecommendationRestorerFactory::GetInstance(); policy::UserCloudPolicyManagerFactoryChromeOS::GetInstance(); diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index 7da1c7f..6e41a27 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi @@ -746,6 +746,10 @@ 'browser/chromeos/options/wifi_config_view.h', 'browser/chromeos/options/wimax_config_view.cc', 'browser/chromeos/options/wimax_config_view.h', + 'browser/chromeos/ownership/owner_settings_service.cc', + 'browser/chromeos/ownership/owner_settings_service.h', + 'browser/chromeos/ownership/owner_settings_service_factory.cc', + 'browser/chromeos/ownership/owner_settings_service_factory.h', 'browser/chromeos/policy/app_pack_updater.cc', 'browser/chromeos/policy/app_pack_updater.h', 'browser/chromeos/policy/auto_enrollment_client.cc', diff --git a/crypto/rsa_private_key.h b/crypto/rsa_private_key.h index 4453845..cb19067 100644 --- a/crypto/rsa_private_key.h +++ b/crypto/rsa_private_key.h @@ -206,6 +206,16 @@ class CRYPTO_EXPORT RSAPrivateKey { // created in the key database. static RSAPrivateKey* FindFromPublicKeyInfo( const std::vector<uint8>& input); + + // Import an existing public key, and then search for the private + // half in the slot specified by |slot|. The format of the public + // key blob is is an X509 SubjectPublicKeyInfo block. This can return + // NULL if initialization fails or the private key cannot be found. + // The caller takes ownership of the returned object, but nothing new + // is created in the slot. + static RSAPrivateKey* FindFromPublicKeyInfoInSlot( + const std::vector<uint8>& input, + PK11SlotInfo* slot); #endif #if defined(USE_OPENSSL) @@ -254,6 +264,14 @@ class CRYPTO_EXPORT RSAPrivateKey { bool sensitive); #endif +#if defined(USE_NSS) + // Import an existing public key. The format of the public key blob + // is an X509 SubjectPublicKeyInfo block. This can return NULL if + // initialization fails. The caller takes ownership of the returned + // object. Note that this method doesn't initialize the |key_| member. + static RSAPrivateKey* InitPublicPart(const std::vector<uint8>& input); +#endif + #if defined(USE_OPENSSL) EVP_PKEY* key_; #else diff --git a/crypto/rsa_private_key_nss.cc b/crypto/rsa_private_key_nss.cc index bd54c2e..078544d 100644 --- a/crypto/rsa_private_key_nss.cc +++ b/crypto/rsa_private_key_nss.cc @@ -38,6 +38,37 @@ static bool ReadAttribute(SECKEYPrivateKey* key, return true; } +#if defined(USE_NSS) +struct PublicKeyInfoDeleter { + inline void operator()(CERTSubjectPublicKeyInfo* spki) { + SECKEY_DestroySubjectPublicKeyInfo(spki); + } +}; + +typedef scoped_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter> + ScopedPublicKeyInfo; + +// The function decodes RSA public key from the |input|. +crypto::ScopedSECKEYPublicKey GetRSAPublicKey(const std::vector<uint8>& input) { + // First, decode and save the public key. + SECItem key_der; + key_der.type = siBuffer; + key_der.data = const_cast<unsigned char*>(&input[0]); + key_der.len = input.size(); + + ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der)); + if (!spki) + return crypto::ScopedSECKEYPublicKey(); + + crypto::ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get())); + + // Make sure the key is an RSA key.. If not, that's an error. + if (!result || result->keyType != rsaKey) + return crypto::ScopedSECKEYPublicKey(); + return result.Pass(); +} +#endif // defined(USE_NSS) + } // namespace namespace crypto { @@ -112,35 +143,9 @@ RSAPrivateKey* RSAPrivateKey::CreateFromKey(SECKEYPrivateKey* key) { // static RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( const std::vector<uint8>& input) { - EnsureNSSInit(); - - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - - // First, decode and save the public key. - SECItem key_der; - key_der.type = siBuffer; - key_der.data = const_cast<unsigned char*>(&input[0]); - key_der.len = input.size(); - - CERTSubjectPublicKeyInfo* spki = - SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der); - if (!spki) { - NOTREACHED(); - return NULL; - } - - result->public_key_ = SECKEY_ExtractPublicKey(spki); - SECKEY_DestroySubjectPublicKeyInfo(spki); - if (!result->public_key_) { - NOTREACHED(); - return NULL; - } - - // Make sure the key is an RSA key. If not, that's an error - if (result->public_key_->keyType != rsaKey) { - NOTREACHED(); + scoped_ptr<RSAPrivateKey> result(InitPublicPart(input)); + if (!result) return NULL; - } ScopedSECItem ck_id( PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus))); @@ -166,6 +171,30 @@ RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( // We didn't find the key. return NULL; } + +// static +RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfoInSlot( + const std::vector<uint8>& input, + PK11SlotInfo* slot) { + if (!slot) + return NULL; + + scoped_ptr<RSAPrivateKey> result(InitPublicPart(input)); + if (!result) + return NULL; + + ScopedSECItem ck_id( + PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus))); + if (!ck_id.get()) { + NOTREACHED(); + return NULL; + } + + result->key_ = PK11_FindKeyByKeyID(slot, ck_id.get(), NULL); + if (!result->key_) + return NULL; + return result.release(); +} #endif RSAPrivateKey* RSAPrivateKey::Copy() const { @@ -273,4 +302,20 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams( return result.release(); } +#if defined(USE_NSS) +// static +RSAPrivateKey* RSAPrivateKey::InitPublicPart(const std::vector<uint8>& input) { + EnsureNSSInit(); + + scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey()); + result->public_key_ = GetRSAPublicKey(input).release(); + if (!result->public_key_) { + NOTREACHED(); + return NULL; + } + + return result.release(); +} +#endif // defined(USE_NSS) + } // namespace crypto |