Skip to content

Commit

Permalink
Enable system NSS key slot.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
pneubeck@chromium.org committed Aug 2, 2014
1 parent a093e53 commit 442233d
Show file tree
Hide file tree
Showing 20 changed files with 415 additions and 87 deletions.
5 changes: 4 additions & 1 deletion chrome/browser/chromeos/net/cert_verify_proc_chromeos.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
Expand Down
8 changes: 8 additions & 0 deletions chrome/browser/net/nss_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
65 changes: 53 additions & 12 deletions chrome/browser/net/nss_context_chromeos.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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_)
Expand All @@ -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));
Expand Down Expand Up @@ -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(
Expand All @@ -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());
}
22 changes: 22 additions & 0 deletions chrome/browser/profiles/profile_io_data.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -577,13 +588,19 @@ ProfileIOData::AppRequestContext::~AppRequestContext() {

ProfileIOData::ProfileParams::ProfileParams()
: io_thread(NULL),
#if defined(OS_CHROMEOS)
use_system_key_slot(false),
#endif
profile(NULL) {
}

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) {
Expand Down Expand Up @@ -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)));
Expand Down Expand Up @@ -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_);
Expand Down
4 changes: 4 additions & 0 deletions chrome/browser/profiles/profile_io_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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>
Expand Down
29 changes: 19 additions & 10 deletions crypto/nss_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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() {
Expand Down
9 changes: 4 additions & 5 deletions crypto/nss_util_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions crypto/scoped_test_nss_db.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down
4 changes: 4 additions & 0 deletions crypto/scoped_test_system_nss_key_slot.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ bool ScopedTestSystemNSSKeySlot::ConstructedSuccessfully() const {
return test_db_->is_open();
}

PK11SlotInfo* ScopedTestSystemNSSKeySlot::slot() const {
return test_db_->slot();
}

} // namespace crypto
14 changes: 9 additions & 5 deletions crypto/scoped_test_system_nss_key_slot.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,28 @@
#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:
explicit ScopedTestSystemNSSKeySlot();
~ScopedTestSystemNSSKeySlot();

bool ConstructedSuccessfully() const;
PK11SlotInfo* slot() const;

private:
scoped_ptr<ScopedTestNSSDB> test_db_;
Expand Down
6 changes: 6 additions & 0 deletions net/cert/nss_cert_database.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}
Expand Down
10 changes: 10 additions & 0 deletions net/cert/nss_cert_database.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Loading

0 comments on commit 442233d

Please sign in to comment.