diff options
author | pneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-02 07:37:24 +0000 |
---|---|---|
committer | pneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-02 07:37:24 +0000 |
commit | 442233d48747e65512b01ee892ba0c3a4eb8935a (patch) | |
tree | d48d3a5868e45e14be94cf101dab4c6bdbc4f83c | |
parent | a093e53ac4c5df37c17ee95c1ba456133bd4f013 (diff) | |
download | chromium_src-442233d48747e65512b01ee892ba0c3a4eb8935a.zip chromium_src-442233d48747e65512b01ee892ba0c3a4eb8935a.tar.gz chromium_src-442233d48747e65512b01ee892ba0c3a4eb8935a.tar.bz2 |
Enable system NSS key slot.
This only affects users of domains that the device is registered to for policy.
All other users are unaffected (EnableNSSSystemKeySlotForResourceContext is only called for USER_AFFILIATION_MANAGED)
For the affected users, this enables and uses the slot for
- client authentication for TSL (see ClientCertStoreChromeOS)
- client authentication for 802.1x networks
- listing/removing certificates on the settings page (see CertificateManager)
In a follow up, also the enterprise.platformKeys API will be updated.
Depends on:
https://codereview.chromium.org/426983002/
https://codereview.chromium.org/428933002/
BUG=210525
R=mattm@chromium.org, rsleevi@chromium.org, willchan@chromium.org, xiyuan@chromium.org
Review URL: https://codereview.chromium.org/424523002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287175 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/chromeos/net/cert_verify_proc_chromeos.cc | 5 | ||||
-rw-r--r-- | chrome/browser/net/nss_context.h | 8 | ||||
-rw-r--r-- | chrome/browser/net/nss_context_chromeos.cc | 65 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_io_data.cc | 22 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_io_data.h | 4 | ||||
-rw-r--r-- | crypto/nss_util.cc | 29 | ||||
-rw-r--r-- | crypto/nss_util_internal.h | 9 | ||||
-rw-r--r-- | crypto/scoped_test_nss_db.h | 4 | ||||
-rw-r--r-- | crypto/scoped_test_system_nss_key_slot.cc | 4 | ||||
-rw-r--r-- | crypto/scoped_test_system_nss_key_slot.h | 14 | ||||
-rw-r--r-- | net/cert/nss_cert_database.cc | 6 | ||||
-rw-r--r-- | net/cert/nss_cert_database.h | 10 | ||||
-rw-r--r-- | net/cert/nss_cert_database_chromeos.cc | 18 | ||||
-rw-r--r-- | net/cert/nss_cert_database_chromeos.h | 6 | ||||
-rw-r--r-- | net/cert/nss_profile_filter_chromeos.cc | 26 | ||||
-rw-r--r-- | net/cert/nss_profile_filter_chromeos.h | 4 | ||||
-rw-r--r-- | net/cert/nss_profile_filter_chromeos_unittest.cc | 33 | ||||
-rw-r--r-- | net/ssl/client_cert_store_chromeos.cc | 70 | ||||
-rw-r--r-- | net/ssl/client_cert_store_chromeos.h | 16 | ||||
-rw-r--r-- | net/ssl/client_cert_store_chromeos_unittest.cc | 149 |
20 files changed, 415 insertions, 87 deletions
diff --git a/chrome/browser/chromeos/net/cert_verify_proc_chromeos.cc b/chrome/browser/chromeos/net/cert_verify_proc_chromeos.cc index b99d98c..be4621e 100644 --- a/chrome/browser/chromeos/net/cert_verify_proc_chromeos.cc +++ b/chrome/browser/chromeos/net/cert_verify_proc_chromeos.cc @@ -29,7 +29,10 @@ CertVerifyProcChromeOS::CertVerifyProcChromeOS() {} CertVerifyProcChromeOS::CertVerifyProcChromeOS( crypto::ScopedPK11Slot public_slot) { - profile_filter_.Init(public_slot.Pass(), crypto::ScopedPK11Slot()); + // Only the software slot is passed, since that is the only one where user + // trust settings are stored. + profile_filter_.Init( + public_slot.Pass(), crypto::ScopedPK11Slot(), crypto::ScopedPK11Slot()); } CertVerifyProcChromeOS::~CertVerifyProcChromeOS() {} diff --git a/chrome/browser/net/nss_context.h b/chrome/browser/net/nss_context.h index 33023c0..8212ee1 100644 --- a/chrome/browser/net/nss_context.h +++ b/chrome/browser/net/nss_context.h @@ -46,6 +46,14 @@ net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext( const base::Callback<void(net::NSSCertDatabase*)>& callback) WARN_UNUSED_RESULT; +#if defined(OS_CHROMEOS) +// Enables the system key slot in the NSSCertDatabase for the user associated +// with |context|. +// Must be called only on the IO thread. +void EnableNSSSystemKeySlotForResourceContext( + content::ResourceContext* context); +#endif + // Gets a pointer to the NSSCertDatabase for the user associated with |context|. // It's a wrapper around |GetNSSCertDatabaseForResourceContext| which makes // sure it's called on IO thread (with |profile|'s resource context). The diff --git a/chrome/browser/net/nss_context_chromeos.cc b/chrome/browser/net/nss_context_chromeos.cc index fdd96cf..abac67c 100644 --- a/chrome/browser/net/nss_context_chromeos.cc +++ b/chrome/browser/net/nss_context_chromeos.cc @@ -17,6 +17,8 @@ void* kDatabaseManagerKey = &kDatabaseManagerKey; class NSSCertDatabaseChromeOSManager : public base::SupportsUserData::Data { public: + typedef base::Callback<void(net::NSSCertDatabaseChromeOS*)> + GetNSSCertDatabaseCallback; explicit NSSCertDatabaseChromeOSManager(const std::string& username_hash) : username_hash_(username_hash), weak_ptr_factory_(this) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); @@ -32,8 +34,8 @@ class NSSCertDatabaseChromeOSManager : public base::SupportsUserData::Data { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); } - net::NSSCertDatabase* GetNSSCertDatabase( - const base::Callback<void(net::NSSCertDatabase*)>& callback) { + net::NSSCertDatabaseChromeOS* GetNSSCertDatabase( + const GetNSSCertDatabaseCallback& callback) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); if (nss_cert_database_) @@ -44,8 +46,7 @@ class NSSCertDatabaseChromeOSManager : public base::SupportsUserData::Data { } private: - typedef std::vector<base::Callback<void(net::NSSCertDatabase*)> > - ReadyCallbackList; + typedef std::vector<GetNSSCertDatabaseCallback> ReadyCallbackList; void DidGetPrivateSlot(crypto::ScopedPK11Slot private_slot) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); @@ -74,6 +75,43 @@ std::string GetUsername(content::ResourceContext* context) { return ProfileIOData::FromResourceContext(context)->username_hash(); } +net::NSSCertDatabaseChromeOS* GetNSSCertDatabaseChromeOS( + content::ResourceContext* context, + const NSSCertDatabaseChromeOSManager::GetNSSCertDatabaseCallback& + callback) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + NSSCertDatabaseChromeOSManager* manager = + static_cast<NSSCertDatabaseChromeOSManager*>( + context->GetUserData(kDatabaseManagerKey)); + if (!manager) { + manager = new NSSCertDatabaseChromeOSManager(GetUsername(context)); + context->SetUserData(kDatabaseManagerKey, manager); + } + return manager->GetNSSCertDatabase(callback); +} + +void CallWithNSSCertDatabase( + const base::Callback<void(net::NSSCertDatabase*)>& callback, + net::NSSCertDatabaseChromeOS* db) { + callback.Run(db); +} + +void SetSystemSlot(crypto::ScopedPK11Slot system_slot, + net::NSSCertDatabaseChromeOS* db) { + db->SetSystemSlot(system_slot.Pass()); +} + +void SetSystemSlotOfDBForResourceContext(content::ResourceContext* context, + crypto::ScopedPK11Slot system_slot) { + base::Callback<void(net::NSSCertDatabaseChromeOS*)> callback = + base::Bind(&SetSystemSlot, base::Passed(&system_slot)); + + net::NSSCertDatabaseChromeOS* db = + GetNSSCertDatabaseChromeOS(context, callback); + if (db) + callback.Run(db); +} + } // namespace crypto::ScopedPK11Slot GetPublicNSSKeySlotForResourceContext( @@ -92,13 +130,16 @@ crypto::ScopedPK11Slot GetPrivateNSSKeySlotForResourceContext( net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext( content::ResourceContext* context, const base::Callback<void(net::NSSCertDatabase*)>& callback) { + return GetNSSCertDatabaseChromeOS( + context, base::Bind(&CallWithNSSCertDatabase, callback)); +} + +void EnableNSSSystemKeySlotForResourceContext( + content::ResourceContext* context) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - NSSCertDatabaseChromeOSManager* manager = - static_cast<NSSCertDatabaseChromeOSManager*>( - context->GetUserData(kDatabaseManagerKey)); - if (!manager) { - manager = new NSSCertDatabaseChromeOSManager(GetUsername(context)); - context->SetUserData(kDatabaseManagerKey, manager); - } - return manager->GetNSSCertDatabase(callback); + base::Callback<void(crypto::ScopedPK11Slot)> callback = + base::Bind(&SetSystemSlotOfDBForResourceContext, context); + crypto::ScopedPK11Slot system_slot = crypto::GetSystemNSSKeySlot(callback); + if (system_slot) + callback.Run(system_slot.Pass()); } diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc index 004c35e..b5ced2d 100644 --- a/chrome/browser/profiles/profile_io_data.cc +++ b/chrome/browser/profiles/profile_io_data.cc @@ -110,11 +110,13 @@ #include "chrome/browser/chromeos/login/startup_utils.h" #include "chrome/browser/chromeos/login/users/user_manager.h" #include "chrome/browser/chromeos/net/cert_verify_proc_chromeos.h" +#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/policy_cert_service.h" #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h" #include "chrome/browser/chromeos/policy/policy_cert_verifier.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/net/nss_context.h" #include "chromeos/dbus/cryptohome_client.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/settings/cros_settings_names.h" @@ -382,6 +384,15 @@ void ProfileIOData::InitializeOnUIThread(Profile* profile) { user->email(), user->username_hash(), profile->GetPath())); + + // Use the device-wide system key slot only if the user is of the same + // domain as the device is registered to. + policy::BrowserPolicyConnectorChromeOS* connector = + g_browser_process->platform_part() + ->browser_policy_connector_chromeos(); + params->use_system_key_slot = + connector->GetUserAffiliation(user->email()) == + policy::USER_AFFILIATION_MANAGED; } } #endif @@ -577,6 +588,9 @@ ProfileIOData::AppRequestContext::~AppRequestContext() { ProfileIOData::ProfileParams::ProfileParams() : io_thread(NULL), +#if defined(OS_CHROMEOS) + use_system_key_slot(false), +#endif profile(NULL) { } @@ -584,6 +598,9 @@ ProfileIOData::ProfileParams::~ProfileParams() {} ProfileIOData::ProfileIOData(Profile::ProfileType profile_type) : initialized_(false), +#if defined(OS_CHROMEOS) + use_system_key_slot_(false), +#endif resource_context_(new ResourceContext(this)), initialized_on_UI_thread_(false), profile_type_(profile_type) { @@ -904,6 +921,7 @@ ProfileIOData::ResourceContext::CreateClientCertStore() { return io_data_->client_cert_store_factory_.Run(); #if defined(OS_CHROMEOS) return scoped_ptr<net::ClientCertStore>(new net::ClientCertStoreChromeOS( + io_data_->use_system_key_slot(), io_data_->username_hash(), base::Bind(&CreateCryptoModuleBlockingPasswordDelegate, chrome::kCryptoModulePasswordClientAuth))); @@ -1091,6 +1109,10 @@ void ProfileIOData::Init( #if defined(OS_CHROMEOS) username_hash_ = profile_params_->username_hash; + use_system_key_slot_ = profile_params_->use_system_key_slot; + if (use_system_key_slot_) + EnableNSSSystemKeySlotForResourceContext(resource_context_.get()); + scoped_refptr<net::CertVerifyProc> verify_proc; crypto::ScopedPK11Slot public_slot = crypto::GetPublicSlotForChromeOSUser(username_hash_); diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h index bc17731..f0d6149 100644 --- a/chrome/browser/profiles/profile_io_data.h +++ b/chrome/browser/profiles/profile_io_data.h @@ -213,6 +213,8 @@ class ProfileIOData { std::string username_hash() const { return username_hash_; } + + bool use_system_key_slot() const { return use_system_key_slot_; } #endif Profile::ProfileType profile_type() const { @@ -326,6 +328,7 @@ class ProfileIOData { #if defined(OS_CHROMEOS) std::string username_hash; + bool use_system_key_slot; #endif // The profile this struct was populated from. It's passed as a void* to @@ -589,6 +592,7 @@ class ProfileIOData { #if defined(OS_CHROMEOS) mutable scoped_ptr<policy::PolicyCertVerifier> cert_verifier_; mutable std::string username_hash_; + mutable bool use_system_key_slot_; #endif mutable scoped_ptr<net::TransportSecurityPersister> diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc index 29a0b66..062bcb5 100644 --- a/crypto/nss_util.cc +++ b/crypto/nss_util.cc @@ -394,19 +394,22 @@ class NSSInitSingleton { } initializing_tpm_token_ = false; - if (tpm_slot_) { - TPMReadyCallbackList callback_list; - callback_list.swap(tpm_ready_callback_list_); - for (TPMReadyCallbackList::iterator i = callback_list.begin(); - i != callback_list.end(); - ++i) { - (*i).Run(); - } - } + if (tpm_slot_) + RunAndClearTPMReadyCallbackList(); callback.Run(!!tpm_slot_); } + void RunAndClearTPMReadyCallbackList() { + TPMReadyCallbackList callback_list; + callback_list.swap(tpm_ready_callback_list_); + for (TPMReadyCallbackList::iterator i = callback_list.begin(); + i != callback_list.end(); + ++i) { + i->Run(); + } + } + bool IsTPMTokenReady(const base::Closure& callback) { if (!callback.is_null()) { // Cannot DCHECK in the general case yet, but since the callback is @@ -579,6 +582,12 @@ class NSSInitSingleton { // Unsetting, i.e. setting a NULL, however is allowed. DCHECK(!slot || !test_system_slot_); test_system_slot_ = slot.Pass(); + if (test_system_slot_) { + tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get())); + RunAndClearTPMReadyCallbackList(); + } else { + tpm_slot_.reset(); + } } #endif // defined(OS_CHROMEOS) @@ -1014,7 +1023,7 @@ ScopedPK11Slot GetSystemNSSKeySlot( } void SetSystemKeySlotForTesting(ScopedPK11Slot slot) { - g_nss_singleton.Get().SetSystemKeySlotForTesting(ScopedPK11Slot()); + g_nss_singleton.Get().SetSystemKeySlotForTesting(slot.Pass()); } void EnableTPMTokenForNSS() { diff --git a/crypto/nss_util_internal.h b/crypto/nss_util_internal.h index cb1b9bd..839d7ba7 100644 --- a/crypto/nss_util_internal.h +++ b/crypto/nss_util_internal.h @@ -53,11 +53,10 @@ class CRYPTO_EXPORT AutoSECMODListReadLock { CRYPTO_EXPORT ScopedPK11Slot GetSystemNSSKeySlot( const base::Callback<void(ScopedPK11Slot)>& callback) WARN_UNUSED_RESULT; -// Sets the test system slot. If this was called before -// InitializeTPMTokenAndSystemSlot and no system token is provided by the Chaps -// module, then this test slot will be used and the initialization continues as -// if Chaps had provided this test slot. In particular, |slot| will be exposed -// by |GetSystemNSSKeySlot| and |IsTPMTokenReady| will return true. +// Sets the test system slot to |slot|, which means that |slot| will be exposed +// through |GetSystemNSSKeySlot| and |IsTPMTokenReady| will return true. +// |InitializeTPMTokenAndSystemSlot|, which triggers the TPM initialization, +// does not have to be called if the test system slot is set. // This must must not be called consecutively with a |slot| != NULL. If |slot| // is NULL, the test system slot is unset. CRYPTO_EXPORT_PRIVATE void SetSystemKeySlotForTesting(ScopedPK11Slot slot); diff --git a/crypto/scoped_test_nss_db.h b/crypto/scoped_test_nss_db.h index cc6996d..88c2d55 100644 --- a/crypto/scoped_test_nss_db.h +++ b/crypto/scoped_test_nss_db.h @@ -20,8 +20,8 @@ class CRYPTO_EXPORT_PRIVATE ScopedTestNSSDB { ScopedTestNSSDB(); ~ScopedTestNSSDB(); - bool is_open() { return slot_; } - PK11SlotInfo* slot() { return slot_.get(); } + bool is_open() const { return slot_; } + PK11SlotInfo* slot() const { return slot_.get(); } private: base::ScopedTempDir temp_dir_; diff --git a/crypto/scoped_test_system_nss_key_slot.cc b/crypto/scoped_test_system_nss_key_slot.cc index ee5e1df..53fbbff 100644 --- a/crypto/scoped_test_system_nss_key_slot.cc +++ b/crypto/scoped_test_system_nss_key_slot.cc @@ -25,4 +25,8 @@ bool ScopedTestSystemNSSKeySlot::ConstructedSuccessfully() const { return test_db_->is_open(); } +PK11SlotInfo* ScopedTestSystemNSSKeySlot::slot() const { + return test_db_->slot(); +} + } // namespace crypto diff --git a/crypto/scoped_test_system_nss_key_slot.h b/crypto/scoped_test_system_nss_key_slot.h index 1565047..ac3b72c 100644 --- a/crypto/scoped_test_system_nss_key_slot.h +++ b/crypto/scoped_test_system_nss_key_slot.h @@ -9,17 +9,20 @@ #include "base/memory/scoped_ptr.h" #include "crypto/crypto_export.h" +// Forward declaration, from <pk11pub.h> +typedef struct PK11SlotInfoStr PK11SlotInfo; + namespace crypto { class ScopedTestNSSDB; // Opens a persistent NSS software database in a temporary directory and sets // the test system slot to the opened database. This helper should be created in -// tests where no system token is provided by the Chaps module and before -// InitializeTPMTokenAndSystemSlot is called. Then the opened test database will -// be used and the initialization continues as if Chaps had provided this test -// database. In particular, the DB will be exposed by |GetSystemNSSKeySlot| and -// |IsTPMTokenReady| will return true. +// tests to fake the system token that is usually provided by the Chaps module. +// |slot| is exposed through |GetSystemNSSKeySlot| and |IsTPMTokenReady| will +// return true. +// |InitializeTPMTokenAndSystemSlot|, which triggers the TPM initialization, +// does not have to be called if this helper is used. // At most one instance of this helper must be used at a time. class CRYPTO_EXPORT_PRIVATE ScopedTestSystemNSSKeySlot { public: @@ -27,6 +30,7 @@ class CRYPTO_EXPORT_PRIVATE ScopedTestSystemNSSKeySlot { ~ScopedTestSystemNSSKeySlot(); bool ConstructedSuccessfully() const; + PK11SlotInfo* slot() const; private: scoped_ptr<ScopedTestNSSDB> test_db_; diff --git a/net/cert/nss_cert_database.cc b/net/cert/nss_cert_database.cc index 8b69ca5..7e6755f 100644 --- a/net/cert/nss_cert_database.cc +++ b/net/cert/nss_cert_database.cc @@ -130,6 +130,12 @@ void NSSCertDatabase::ListCertsInSlot(const ListCertsCallback& callback, base::Bind(callback, base::Passed(&certs))); } +#if defined(OS_CHROMEOS) +crypto::ScopedPK11Slot NSSCertDatabase::GetSystemSlot() const { + return crypto::ScopedPK11Slot(); +} +#endif + crypto::ScopedPK11Slot NSSCertDatabase::GetPublicSlot() const { return crypto::ScopedPK11Slot(PK11_ReferenceSlot(public_slot_.get())); } diff --git a/net/cert/nss_cert_database.h b/net/cert/nss_cert_database.h index 4c47429..f161169 100644 --- a/net/cert/nss_cert_database.h +++ b/net/cert/nss_cert_database.h @@ -130,6 +130,16 @@ class NET_EXPORT NSSCertDatabase { virtual void ListCertsInSlot(const ListCertsCallback& callback, PK11SlotInfo* slot); +#if defined(OS_CHROMEOS) + // Get the slot for system-wide key data. May be NULL if the system token was + // not explicitly set. + // Note: The System slot is set after the NSSCertDatabase is constructed and + // this call returns synchronously. Thus, it is possible to call this function + // before SetSystemSlot is called and get a NULL result. + // See https://crbug.com/399554 . + virtual crypto::ScopedPK11Slot GetSystemSlot() const; +#endif + // Get the default slot for public key data. crypto::ScopedPK11Slot GetPublicSlot() const; diff --git a/net/cert/nss_cert_database_chromeos.cc b/net/cert/nss_cert_database_chromeos.cc index 60f7f2e..63d969c 100644 --- a/net/cert/nss_cert_database_chromeos.cc +++ b/net/cert/nss_cert_database_chromeos.cc @@ -22,11 +22,21 @@ NSSCertDatabaseChromeOS::NSSCertDatabaseChromeOS( crypto::ScopedPK11Slot public_slot, crypto::ScopedPK11Slot private_slot) : NSSCertDatabase(public_slot.Pass(), private_slot.Pass()) { - profile_filter_.Init(GetPublicSlot(), GetPrivateSlot()); + // By default, don't use a system slot. Only if explicitly set by + // SetSystemSlot, the system slot will be used. + profile_filter_.Init(GetPublicSlot(), + GetPrivateSlot(), + crypto::ScopedPK11Slot() /* no system slot */); } NSSCertDatabaseChromeOS::~NSSCertDatabaseChromeOS() {} +void NSSCertDatabaseChromeOS::SetSystemSlot( + crypto::ScopedPK11Slot system_slot) { + system_slot_ = system_slot.Pass(); + profile_filter_.Init(GetPublicSlot(), GetPrivateSlot(), GetSystemSlot()); +} + void NSSCertDatabaseChromeOS::ListCertsSync(CertificateList* certs) { ListCertsImpl(profile_filter_, certs); } @@ -45,6 +55,12 @@ void NSSCertDatabaseChromeOS::ListCerts( base::Bind(callback, base::Passed(&certs))); } +crypto::ScopedPK11Slot NSSCertDatabaseChromeOS::GetSystemSlot() const { + if (system_slot_) + return crypto::ScopedPK11Slot(PK11_ReferenceSlot(system_slot_.get())); + return crypto::ScopedPK11Slot(); +} + void NSSCertDatabaseChromeOS::ListModules(CryptoModuleList* modules, bool need_rw) const { NSSCertDatabase::ListModules(modules, need_rw); diff --git a/net/cert/nss_cert_database_chromeos.h b/net/cert/nss_cert_database_chromeos.h index b68f742..dfcefec 100644 --- a/net/cert/nss_cert_database_chromeos.h +++ b/net/cert/nss_cert_database_chromeos.h @@ -20,12 +20,17 @@ class NET_EXPORT NSSCertDatabaseChromeOS : public NSSCertDatabase { crypto::ScopedPK11Slot private_slot); virtual ~NSSCertDatabaseChromeOS(); + // |system_slot| is the system TPM slot, which is only enabled for certain + // users. + void SetSystemSlot(crypto::ScopedPK11Slot system_slot); + // NSSCertDatabase implementation. virtual void ListCertsSync(CertificateList* certs) OVERRIDE; virtual void ListCerts(const NSSCertDatabase::ListCertsCallback& callback) OVERRIDE; virtual void ListModules(CryptoModuleList* modules, bool need_rw) const OVERRIDE; + virtual crypto::ScopedPK11Slot GetSystemSlot() const OVERRIDE; // TODO(mattm): handle trust setting, deletion, etc correctly when certs exist // in multiple slots. @@ -40,6 +45,7 @@ class NET_EXPORT NSSCertDatabaseChromeOS : public NSSCertDatabase { CertificateList* certs); NSSProfileFilterChromeOS profile_filter_; + crypto::ScopedPK11Slot system_slot_; DISALLOW_COPY_AND_ASSIGN(NSSCertDatabaseChromeOS); }; diff --git a/net/cert/nss_profile_filter_chromeos.cc b/net/cert/nss_profile_filter_chromeos.cc index e555750..8e4167a 100644 --- a/net/cert/nss_profile_filter_chromeos.cc +++ b/net/cert/nss_profile_filter_chromeos.cc @@ -43,6 +43,8 @@ NSSProfileFilterChromeOS::NSSProfileFilterChromeOS( private_slot_.reset(other.private_slot_ ? PK11_ReferenceSlot(other.private_slot_.get()) : NULL); + system_slot_.reset( + other.system_slot_ ? PK11_ReferenceSlot(other.system_slot_.get()) : NULL); } NSSProfileFilterChromeOS::~NSSProfileFilterChromeOS() {} @@ -55,11 +57,14 @@ NSSProfileFilterChromeOS& NSSProfileFilterChromeOS::operator=( private_slot_.reset(other.private_slot_ ? PK11_ReferenceSlot(other.private_slot_.get()) : NULL); + system_slot_.reset( + other.system_slot_ ? PK11_ReferenceSlot(other.system_slot_.get()) : NULL); return *this; } void NSSProfileFilterChromeOS::Init(crypto::ScopedPK11Slot public_slot, - crypto::ScopedPK11Slot private_slot) { + crypto::ScopedPK11Slot private_slot, + crypto::ScopedPK11Slot system_slot) { // crypto::ScopedPK11Slot actually holds a reference counted object. // Because scoped_ptr<T> assignment is a no-op if it already points to // the same pointer, a reference would be leaked because .Pass() does @@ -69,12 +74,17 @@ void NSSProfileFilterChromeOS::Init(crypto::ScopedPK11Slot public_slot, public_slot_ = public_slot.Pass(); if (private_slot_.get() != private_slot.get()) private_slot_ = private_slot.Pass(); + if (system_slot_.get() != system_slot.get()) + system_slot_ = system_slot.Pass(); } bool NSSProfileFilterChromeOS::IsModuleAllowed(PK11SlotInfo* slot) const { - // If this is one of the public/private slots for this profile, allow it. - if (slot == public_slot_.get() || slot == private_slot_.get()) + // If this is one of the public/private slots for this profile or the system + // slot, allow it. + if (slot == public_slot_.get() || slot == private_slot_.get() || + slot == system_slot_.get()) { return true; + } // Allow the root certs module. if (PK11_HasRootCerts(slot)) return true; @@ -86,11 +96,17 @@ bool NSSProfileFilterChromeOS::IsModuleAllowed(PK11SlotInfo* slot) const { if (!public_slot_.get() || !private_slot_.get()) return false; // If this is not the internal (file-system) module or the TPM module, allow - // it. + // it. This would allow smartcards/etc, although ChromeOS doesn't currently + // support that. (This assumes that private_slot_ and system_slot_ are on the + // same module.) + DCHECK(!system_slot_.get() || + PK11_GetModule(private_slot_.get()) == + PK11_GetModule(system_slot_.get())); SECMODModule* module_for_slot = PK11_GetModule(slot); if (module_for_slot != PK11_GetModule(public_slot_.get()) && - module_for_slot != PK11_GetModule(private_slot_.get())) + module_for_slot != PK11_GetModule(private_slot_.get())) { return true; + } return false; } diff --git a/net/cert/nss_profile_filter_chromeos.h b/net/cert/nss_profile_filter_chromeos.h index 4698619..36c42d0 100644 --- a/net/cert/nss_profile_filter_chromeos.h +++ b/net/cert/nss_profile_filter_chromeos.h @@ -36,7 +36,8 @@ class NET_EXPORT NSSProfileFilterChromeOS { // Initialize the filter with the slot handles to allow. This method is not // thread-safe. void Init(crypto::ScopedPK11Slot public_slot, - crypto::ScopedPK11Slot private_slot); + crypto::ScopedPK11Slot private_slot, + crypto::ScopedPK11Slot system_slot); bool IsModuleAllowed(PK11SlotInfo* slot) const; bool IsCertAllowed(CERTCertificate* cert) const; @@ -64,6 +65,7 @@ class NET_EXPORT NSSProfileFilterChromeOS { private: crypto::ScopedPK11Slot public_slot_; crypto::ScopedPK11Slot private_slot_; + crypto::ScopedPK11Slot system_slot_; }; } // namespace net diff --git a/net/cert/nss_profile_filter_chromeos_unittest.cc b/net/cert/nss_profile_filter_chromeos_unittest.cc index b133c33..b48a527 100644 --- a/net/cert/nss_profile_filter_chromeos_unittest.cc +++ b/net/cert/nss_profile_filter_chromeos_unittest.cc @@ -11,6 +11,7 @@ #include "crypto/nss_util_internal.h" #include "crypto/scoped_nss_types.h" #include "crypto/scoped_test_nss_chromeos_user.h" +#include "crypto/scoped_test_nss_db.h" #include "net/base/test_data_directory.h" #include "net/test/cert_test_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -58,7 +59,7 @@ class NSSProfileFilterChromeOSTest : public testing::Test { NSSProfileFilterChromeOSTest() : user_1_("user1"), user_2_("user2") {} virtual void SetUp() OVERRIDE { - // Initialize nss_util slots. + ASSERT_TRUE(system_slot_user_.is_open()); ASSERT_TRUE(user_1_.constructed_successfully()); ASSERT_TRUE(user_2_.constructed_successfully()); user_1_.FinishInit(); @@ -74,7 +75,8 @@ class NSSProfileFilterChromeOSTest : public testing::Test { ASSERT_TRUE(private_slot_1.get()); profile_filter_1_.Init( crypto::GetPublicSlotForChromeOSUser(user_1_.username_hash()), - private_slot_1.Pass()); + private_slot_1.Pass(), + get_system_slot()); profile_filter_1_copy_ = profile_filter_1_; @@ -84,7 +86,8 @@ class NSSProfileFilterChromeOSTest : public testing::Test { ASSERT_TRUE(private_slot_2.get()); profile_filter_2_.Init( crypto::GetPublicSlotForChromeOSUser(user_2_.username_hash()), - private_slot_2.Pass()); + private_slot_2.Pass(), + crypto::ScopedPK11Slot() /* no system slot */); certs_ = CreateCertificateListFromFile(GetTestCertsDirectory(), "root_ca_cert.pem", @@ -92,8 +95,13 @@ class NSSProfileFilterChromeOSTest : public testing::Test { ASSERT_EQ(1U, certs_.size()); } + crypto::ScopedPK11Slot get_system_slot() { + return crypto::ScopedPK11Slot(PK11_ReferenceSlot(system_slot_user_.slot())); + } + protected: CertificateList certs_; + crypto::ScopedTestNSSDB system_slot_user_; crypto::ScopedTestNSSChromeOSUser user_1_; crypto::ScopedTestNSSChromeOSUser user_2_; NSSProfileFilterChromeOS no_slots_profile_filter_; @@ -148,6 +156,7 @@ TEST_F(NSSProfileFilterChromeOSTest, RootCertsAllowed) { } TEST_F(NSSProfileFilterChromeOSTest, SoftwareSlots) { + crypto::ScopedPK11Slot system_slot(get_system_slot()); crypto::ScopedPK11Slot slot_1( crypto::GetPublicSlotForChromeOSUser(user_1_.username_hash())); ASSERT_TRUE(slot_1); @@ -160,6 +169,12 @@ TEST_F(NSSProfileFilterChromeOSTest, SoftwareSlots) { GetTestCertsDirectory(), "ok_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs_2.size()); scoped_refptr<X509Certificate> cert_2 = certs_2[0]; + CertificateList system_certs = + CreateCertificateListFromFile(GetTestCertsDirectory(), + "mit.davidben.der", + X509Certificate::FORMAT_AUTO); + ASSERT_EQ(1U, system_certs.size()); + scoped_refptr<X509Certificate> system_cert = system_certs[0]; ASSERT_EQ(SECSuccess, PK11_ImportCert(slot_1.get(), @@ -174,19 +189,31 @@ TEST_F(NSSProfileFilterChromeOSTest, SoftwareSlots) { CK_INVALID_HANDLE, "cert2", PR_FALSE /* includeTrust (unused) */)); + ASSERT_EQ(SECSuccess, + PK11_ImportCert(system_slot.get(), + system_cert->os_cert_handle(), + CK_INVALID_HANDLE, + "systemcert", + PR_FALSE /* includeTrust (unused) */)); EXPECT_FALSE( no_slots_profile_filter_.IsCertAllowed(cert_1->os_cert_handle())); EXPECT_FALSE( no_slots_profile_filter_.IsCertAllowed(cert_2->os_cert_handle())); + EXPECT_FALSE( + no_slots_profile_filter_.IsCertAllowed(system_cert->os_cert_handle())); EXPECT_TRUE(profile_filter_1_.IsCertAllowed(cert_1->os_cert_handle())); EXPECT_TRUE(profile_filter_1_copy_.IsCertAllowed(cert_1->os_cert_handle())); EXPECT_FALSE(profile_filter_1_.IsCertAllowed(cert_2->os_cert_handle())); EXPECT_FALSE(profile_filter_1_copy_.IsCertAllowed(cert_2->os_cert_handle())); + EXPECT_TRUE(profile_filter_1_.IsCertAllowed(system_cert->os_cert_handle())); + EXPECT_TRUE( + profile_filter_1_copy_.IsCertAllowed(system_cert->os_cert_handle())); EXPECT_FALSE(profile_filter_2_.IsCertAllowed(cert_1->os_cert_handle())); EXPECT_TRUE(profile_filter_2_.IsCertAllowed(cert_2->os_cert_handle())); + EXPECT_FALSE(profile_filter_2_.IsCertAllowed(system_cert->os_cert_handle())); } } // namespace net diff --git a/net/ssl/client_cert_store_chromeos.cc b/net/ssl/client_cert_store_chromeos.cc index bd4a5c4..6dacd45 100644 --- a/net/ssl/client_cert_store_chromeos.cc +++ b/net/ssl/client_cert_store_chromeos.cc @@ -12,11 +12,46 @@ namespace net { +namespace { + +typedef base::Callback<void(crypto::ScopedPK11Slot system_slot, + crypto::ScopedPK11Slot private_slot)> + GetSystemAndPrivateSlotCallback; + +// Gets the private slot for the user with the username hash |username_hash| and +// calls |callback| with both |system_slot| and the obtained private slot. +void GetPrivateSlotAndCallBack(const std::string& username_hash, + const GetSystemAndPrivateSlotCallback& callback, + crypto::ScopedPK11Slot system_slot) { + base::Callback<void(crypto::ScopedPK11Slot)> wrapped_callback = + base::Bind(callback, base::Passed(&system_slot)); + + crypto::ScopedPK11Slot slot( + crypto::GetPrivateSlotForChromeOSUser(username_hash, wrapped_callback)); + if (slot) + wrapped_callback.Run(slot.Pass()); +} + +// Gets the system slot, then the private slot for the user with the username +// hash |username_hash|, and finally calls |callback| with both slots. +void GetSystemAndPrivateSlot(const std::string& username_hash, + const GetSystemAndPrivateSlotCallback& callback) { + crypto::ScopedPK11Slot system_slot(crypto::GetSystemNSSKeySlot( + base::Bind(&GetPrivateSlotAndCallBack, username_hash, callback))); + if (system_slot) + GetPrivateSlotAndCallBack(username_hash, callback, system_slot.Pass()); +} + +} // namespace + ClientCertStoreChromeOS::ClientCertStoreChromeOS( + bool use_system_slot, const std::string& username_hash, const PasswordDelegateFactory& password_delegate_factory) : ClientCertStoreNSS(password_delegate_factory), - username_hash_(username_hash) {} + use_system_slot_(use_system_slot), + username_hash_(username_hash) { +} ClientCertStoreChromeOS::~ClientCertStoreChromeOS() {} @@ -24,24 +59,29 @@ void ClientCertStoreChromeOS::GetClientCerts( const SSLCertRequestInfo& cert_request_info, CertificateList* selected_certs, const base::Closure& callback) { - crypto::ScopedPK11Slot private_slot(crypto::GetPrivateSlotForChromeOSUser( - username_hash_, - base::Bind(&ClientCertStoreChromeOS::DidGetPrivateSlot, + GetSystemAndPrivateSlotCallback bound_callback = + base::Bind(&ClientCertStoreChromeOS::DidGetSystemAndPrivateSlot, // Caller is responsible for keeping the ClientCertStore alive // until the callback is run. base::Unretained(this), &cert_request_info, selected_certs, - callback))); - if (private_slot) - DidGetPrivateSlot( - &cert_request_info, selected_certs, callback, private_slot.Pass()); + callback); + + if (use_system_slot_) { + GetSystemAndPrivateSlot(username_hash_, bound_callback); + } else { + // Skip getting the system slot. + GetPrivateSlotAndCallBack( + username_hash_, bound_callback, crypto::ScopedPK11Slot()); + } } -void ClientCertStoreChromeOS::GetClientCertsImpl(CERTCertList* cert_list, - const SSLCertRequestInfo& request, - bool query_nssdb, - CertificateList* selected_certs) { +void ClientCertStoreChromeOS::GetClientCertsImpl( + CERTCertList* cert_list, + const SSLCertRequestInfo& request, + bool query_nssdb, + CertificateList* selected_certs) { ClientCertStoreNSS::GetClientCertsImpl( cert_list, request, query_nssdb, selected_certs); @@ -57,13 +97,15 @@ void ClientCertStoreChromeOS::GetClientCertsImpl(CERTCertList* cert_list, << pre_size << " certs"; } -void ClientCertStoreChromeOS::DidGetPrivateSlot( +void ClientCertStoreChromeOS::DidGetSystemAndPrivateSlot( const SSLCertRequestInfo* request, CertificateList* selected_certs, const base::Closure& callback, + crypto::ScopedPK11Slot system_slot, crypto::ScopedPK11Slot private_slot) { profile_filter_.Init(crypto::GetPublicSlotForChromeOSUser(username_hash_), - private_slot.Pass()); + private_slot.Pass(), + system_slot.Pass()); ClientCertStoreNSS::GetClientCerts(*request, selected_certs, callback); } diff --git a/net/ssl/client_cert_store_chromeos.h b/net/ssl/client_cert_store_chromeos.h index 087190c..940888d 100644 --- a/net/ssl/client_cert_store_chromeos.h +++ b/net/ssl/client_cert_store_chromeos.h @@ -15,7 +15,11 @@ namespace net { class NET_EXPORT ClientCertStoreChromeOS : public ClientCertStoreNSS { public: + // Constructs a ClientCertStore that will return client certs available on + // the user's private and public slots. If |use_system_slot| is true, certs on + // the system slot will also be returned. ClientCertStoreChromeOS( + bool use_system_slot, const std::string& username_hash, const PasswordDelegateFactory& password_delegate_factory); virtual ~ClientCertStoreChromeOS(); @@ -33,13 +37,13 @@ class NET_EXPORT ClientCertStoreChromeOS : public ClientCertStoreNSS { CertificateList* selected_certs) OVERRIDE; private: - friend class ClientCertStoreChromeOSTestDelegate; - - void DidGetPrivateSlot(const SSLCertRequestInfo* request, - CertificateList* selected_certs, - const base::Closure& callback, - crypto::ScopedPK11Slot private_slot); + void DidGetSystemAndPrivateSlot(const SSLCertRequestInfo* request, + CertificateList* selected_certs, + const base::Closure& callback, + crypto::ScopedPK11Slot system_slot, + crypto::ScopedPK11Slot private_slot); + bool use_system_slot_; std::string username_hash_; NSSProfileFilterChromeOS profile_filter_; diff --git a/net/ssl/client_cert_store_chromeos_unittest.cc b/net/ssl/client_cert_store_chromeos_unittest.cc index 3bd6d60..12a1b43 100644 --- a/net/ssl/client_cert_store_chromeos_unittest.cc +++ b/net/ssl/client_cert_store_chromeos_unittest.cc @@ -14,6 +14,7 @@ #include "crypto/nss_util_internal.h" #include "crypto/rsa_private_key.h" #include "crypto/scoped_test_nss_chromeos_user.h" +#include "crypto/scoped_test_system_nss_key_slot.h" #include "net/base/test_data_directory.h" #include "net/cert/cert_type.h" #include "net/cert/x509_certificate.h" @@ -42,15 +43,28 @@ bool ImportClientCertToSlot(const scoped_refptr<X509Certificate>& cert, return true; } +enum ReadFromSlot { + READ_FROM_SLOT_USER, + READ_FROM_SLOT_SYSTEM +}; + +enum SystemSlotAvailability { + SYSTEM_SLOT_AVAILABILITY_ENABLED, + SYSTEM_SLOT_AVAILABILITY_DISABLED +}; + } // namespace // Define a delegate to be used for instantiating the parameterized test set // ClientCertStoreTest. +template <ReadFromSlot read_from, + SystemSlotAvailability system_slot_availability> class ClientCertStoreChromeOSTestDelegate { public: ClientCertStoreChromeOSTestDelegate() : user_("scopeduser"), - store_(user_.username_hash(), + store_(system_slot_availability == SYSTEM_SLOT_AVAILABILITY_ENABLED, + user_.username_hash(), ClientCertStoreChromeOS::PasswordDelegateFactory()) { // Defer futher initialization and checks to SelectClientCerts, because the // constructor doesn't allow us to return an initialization result. Could be @@ -72,10 +86,19 @@ class ClientCertStoreChromeOSTestDelegate { } user_.FinishInit(); - crypto::ScopedPK11Slot slot( - crypto::GetPublicSlotForChromeOSUser(user_.username_hash())); + crypto::ScopedPK11Slot slot; + switch (read_from) { + case READ_FROM_SLOT_USER: + slot = crypto::GetPublicSlotForChromeOSUser(user_.username_hash()); + break; + case READ_FROM_SLOT_SYSTEM: + slot.reset(PK11_ReferenceSlot(system_db_.slot())); + break; + default: + CHECK(false); + } if (!slot) { - LOG(ERROR) << "Could not get the user's public slot"; + LOG(ERROR) << "Could not get the NSS key slot"; return false; } @@ -104,6 +127,7 @@ class ClientCertStoreChromeOSTestDelegate { private: crypto::ScopedTestNSSChromeOSUser user_; + crypto::ScopedTestSystemNSSKeySlot system_db_; ClientCertStoreChromeOS store_; }; @@ -112,26 +136,43 @@ class ClientCertStoreChromeOSTestDelegate { // To verify that this delegation is functional, run the same filtering tests as // for the other implementations. These tests are defined in // client_cert_store_unittest-inl.h and are instantiated for each platform. -INSTANTIATE_TYPED_TEST_CASE_P(ChromeOS, + +// In this case, all requested certs are read from the user's slot and the +// system slot is not enabled in the store. +typedef ClientCertStoreChromeOSTestDelegate<READ_FROM_SLOT_USER, + SYSTEM_SLOT_AVAILABILITY_DISABLED> + DelegateReadUserDisableSystem; +INSTANTIATE_TYPED_TEST_CASE_P(ChromeOS_ReadUserDisableSystem, + ClientCertStoreTest, + DelegateReadUserDisableSystem); + +// In this case, all requested certs are read from the user's slot and the +// system slot is enabled in the store. +typedef ClientCertStoreChromeOSTestDelegate<READ_FROM_SLOT_USER, + SYSTEM_SLOT_AVAILABILITY_ENABLED> + DelegateReadUserEnableSystem; +INSTANTIATE_TYPED_TEST_CASE_P(ChromeOS_ReadUserEnableSystem, + ClientCertStoreTest, + DelegateReadUserEnableSystem); + +// In this case, all requested certs are read from the system slot, therefore +// the system slot is enabled in the store. +typedef ClientCertStoreChromeOSTestDelegate<READ_FROM_SLOT_SYSTEM, + SYSTEM_SLOT_AVAILABILITY_ENABLED> + DelegateReadSystem; +INSTANTIATE_TYPED_TEST_CASE_P(ChromeOS_ReadSystem, ClientCertStoreTest, - ClientCertStoreChromeOSTestDelegate); + DelegateReadSystem); class ClientCertStoreChromeOSTest : public ::testing::Test { public: - scoped_refptr<X509Certificate> ImportCertForUser( - const std::string& username_hash, + scoped_refptr<X509Certificate> ImportCertToSlot( const std::string& cert_filename, - const std::string& key_filename) { - crypto::ScopedPK11Slot slot( - crypto::GetPublicSlotForChromeOSUser(username_hash)); - if (!slot) { - LOG(ERROR) << "No slot for user " << username_hash; - return NULL; - } - + const std::string& key_filename, + PK11SlotInfo* slot) { if (!ImportSensitiveKeyFromFile( - GetTestCertsDirectory(), key_filename, slot.get())) { - LOG(ERROR) << "Could not import private key for user " << username_hash; + GetTestCertsDirectory(), key_filename, slot)) { + LOG(ERROR) << "Could not import private key from file " << key_filename; return NULL; } @@ -143,7 +184,7 @@ class ClientCertStoreChromeOSTest : public ::testing::Test { return NULL; } - if (!ImportClientCertToSlot(cert, slot.get())) + if (!ImportClientCertToSlot(cert, slot)) return NULL; // |cert| continues to point to the original X509Certificate before the @@ -151,6 +192,21 @@ class ClientCertStoreChromeOSTest : public ::testing::Test { // test. return cert; } + + scoped_refptr<X509Certificate> ImportCertForUser( + const std::string& username_hash, + const std::string& cert_filename, + const std::string& key_filename) { + crypto::ScopedPK11Slot slot( + crypto::GetPublicSlotForChromeOSUser(username_hash)); + if (!slot) { + LOG(ERROR) << "No slot for user " << username_hash; + return NULL; + } + + return ImportCertToSlot(cert_filename, key_filename, slot.get()); + } + }; // Ensure that cert requests, that are started before the user's NSS DB is @@ -158,8 +214,13 @@ class ClientCertStoreChromeOSTest : public ::testing::Test { TEST_F(ClientCertStoreChromeOSTest, RequestWaitsForNSSInitAndSucceeds) { crypto::ScopedTestNSSChromeOSUser user("scopeduser"); ASSERT_TRUE(user.constructed_successfully()); + + crypto::ScopedTestSystemNSSKeySlot system_slot; + ClientCertStoreChromeOS store( - user.username_hash(), ClientCertStoreChromeOS::PasswordDelegateFactory()); + true /* use system slot */, + user.username_hash(), + ClientCertStoreChromeOS::PasswordDelegateFactory()); scoped_refptr<X509Certificate> cert_1( ImportCertForUser(user.username_hash(), "client_1.pem", "client_1.pk8")); ASSERT_TRUE(cert_1); @@ -194,8 +255,12 @@ TEST_F(ClientCertStoreChromeOSTest, RequestsAfterNSSInitSucceed) { ASSERT_TRUE(user.constructed_successfully()); user.FinishInit(); + crypto::ScopedTestSystemNSSKeySlot system_slot; + ClientCertStoreChromeOS store( - user.username_hash(), ClientCertStoreChromeOS::PasswordDelegateFactory()); + true /* use system slot */, + user.username_hash(), + ClientCertStoreChromeOS::PasswordDelegateFactory()); scoped_refptr<X509Certificate> cert_1( ImportCertForUser(user.username_hash(), "client_1.pem", "client_1.pk8")); ASSERT_TRUE(cert_1); @@ -213,7 +278,7 @@ TEST_F(ClientCertStoreChromeOSTest, RequestsAfterNSSInitSucceed) { // This verifies that a request in the context of User1 doesn't see certificates // of User2, and the other way round. We check both directions, to ensure that // the behavior doesn't depend on initialization order of the DBs, for example. -TEST_F(ClientCertStoreChromeOSTest, RequestDoesCrossReadSecondDB) { +TEST_F(ClientCertStoreChromeOSTest, RequestDoesCrossReadOtherUserDB) { crypto::ScopedTestNSSChromeOSUser user1("scopeduser1"); ASSERT_TRUE(user1.constructed_successfully()); crypto::ScopedTestNSSChromeOSUser user2("scopeduser2"); @@ -222,10 +287,14 @@ TEST_F(ClientCertStoreChromeOSTest, RequestDoesCrossReadSecondDB) { user1.FinishInit(); user2.FinishInit(); + crypto::ScopedTestSystemNSSKeySlot system_slot; + ClientCertStoreChromeOS store1( + true /* use system slot */, user1.username_hash(), ClientCertStoreChromeOS::PasswordDelegateFactory()); ClientCertStoreChromeOS store2( + true /* use system slot */, user2.username_hash(), ClientCertStoreChromeOS::PasswordDelegateFactory()); @@ -259,4 +328,40 @@ TEST_F(ClientCertStoreChromeOSTest, RequestDoesCrossReadSecondDB) { EXPECT_TRUE(cert_2->Equals(selected_certs2[0])); } +// This verifies that a request in the context of User1 doesn't see certificates +// of the system store if the system store is disabled. +TEST_F(ClientCertStoreChromeOSTest, RequestDoesCrossReadSystemDB) { + crypto::ScopedTestNSSChromeOSUser user1("scopeduser1"); + ASSERT_TRUE(user1.constructed_successfully()); + + user1.FinishInit(); + + crypto::ScopedTestSystemNSSKeySlot system_slot; + + ClientCertStoreChromeOS store( + false /* do not use system slot */, + user1.username_hash(), + ClientCertStoreChromeOS::PasswordDelegateFactory()); + + scoped_refptr<X509Certificate> cert_1( + ImportCertForUser(user1.username_hash(), "client_1.pem", "client_1.pk8")); + ASSERT_TRUE(cert_1); + scoped_refptr<X509Certificate> cert_2( + ImportCertToSlot("client_2.pem", "client_2.pk8", system_slot.slot())); + ASSERT_TRUE(cert_2); + + scoped_refptr<SSLCertRequestInfo> request_all(new SSLCertRequestInfo()); + + base::RunLoop run_loop; + + CertificateList selected_certs; + store.GetClientCerts(*request_all, &selected_certs, run_loop.QuitClosure()); + + run_loop.Run(); + + // store should only return certs of the user, namely cert_1. + ASSERT_EQ(1u, selected_certs.size()); + EXPECT_TRUE(cert_1->Equals(selected_certs[0])); +} + } // namespace net |