| Index: components/cert_database/cert_database_service_io_part_chromeos.cc
|
| diff --git a/components/cert_database/cert_database_service_io_part_chromeos.cc b/components/cert_database/cert_database_service_io_part_chromeos.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3b1ab488dc67c426e76da1f8979d5d0c27f17349
|
| --- /dev/null
|
| +++ b/components/cert_database/cert_database_service_io_part_chromeos.cc
|
| @@ -0,0 +1,345 @@
|
| +// 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 "components/cert_database/cert_database_service_io_part_chromeos.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/callback.h"
|
| +#include "base/location.h"
|
| +#include "base/single_thread_task_runner.h"
|
| +#include "base/thread_task_runner_handle.h"
|
| +#include "chromeos/dbus/cryptohome_client.h"
|
| +#include "crypto/nss_util.h"
|
| +#include "crypto/nss_util_internal.h"
|
| +#include "net/cert/nss_cert_database_chromeos.h"
|
| +
|
| +namespace cert_database {
|
| +
|
| +namespace {
|
| +
|
| +void DidGetTPMInfoOnUICallBackToIO(
|
| + const chromeos::CryptohomeClient::Pkcs11GetTpmTokenInfoCallback& callback,
|
| + scoped_refptr<base::SingleThreadTaskRunner> origin_thread,
|
| + chromeos::DBusMethodCallStatus call_status,
|
| + const std::string& label,
|
| + const std::string& user_pin,
|
| + int slot_id) {
|
| + DVLOG(1) << "Got TPM info for slot " << slot_id;
|
| + origin_thread->PostTask(
|
| + FROM_HERE, base::Bind(callback, call_status, label, user_pin, slot_id));
|
| +}
|
| +
|
| +void GetTPMInfoForUserOnUIThread(
|
| + const std::string& user_email,
|
| + const chromeos::CryptohomeClient::Pkcs11GetTpmTokenInfoCallback& callback,
|
| + scoped_refptr<base::SingleThreadTaskRunner> origin_thread,
|
| + chromeos::CryptohomeClient* cryptohome_client) {
|
| + DVLOG(1) << "Getting TPM info from cryptohome for "
|
| + << " " << user_email;
|
| + cryptohome_client->Pkcs11GetTpmTokenInfoForUser(
|
| + user_email,
|
| + base::Bind(&DidGetTPMInfoOnUICallBackToIO, callback, origin_thread));
|
| +}
|
| +
|
| +void GetTPMInfoForUserOnIOThread(
|
| + const std::string& user_email,
|
| + const chromeos::CryptohomeClient::Pkcs11GetTpmTokenInfoCallback& callback,
|
| + scoped_refptr<base::SequencedTaskRunner> dbus_task_runner,
|
| + chromeos::CryptohomeClient* cryptohome_client) {
|
| + dbus_task_runner->PostTask(FROM_HERE,
|
| + base::Bind(&GetTPMInfoForUserOnUIThread,
|
| + user_email,
|
| + callback,
|
| + base::ThreadTaskRunnerHandle::Get(),
|
| + cryptohome_client));
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class CertDatabaseServiceIOPartChromeOS::Internal {
|
| + public:
|
| + Internal(const std::string& user_email,
|
| + const std::string& username_hash,
|
| + bool use_system_key_slot,
|
| + const base::FilePath& path,
|
| + const scoped_refptr<base::SequencedTaskRunner>& dbus_task_runner,
|
| + chromeos::CryptohomeClient* cryptohome_client,
|
| + CertDatabaseServiceIOPartChromeOS* io_part)
|
| + : user_email_(user_email),
|
| + username_hash_(username_hash),
|
| + use_system_key_slot_(use_system_key_slot),
|
| + path_(path),
|
| + dbus_task_runner_(dbus_task_runner),
|
| + state_(NOT_STARTED),
|
| + system_tpm_token_status_(SYSTEM_TPM_TOKEN_STATUS_UNDETERMINED),
|
| + cryptohome_client_(cryptohome_client),
|
| + io_part_(io_part),
|
| + weak_ptr_factory_(this) {
|
| + CHECK(dbus_task_runner_.get());
|
| + CHECK(cryptohome_client_);
|
| + CHECK(io_part_);
|
| + }
|
| +
|
| + void Run() {
|
| + thread_checker_.DetachFromThread();
|
| + thread_checker_.CalledOnValidThread();
|
| + DCHECK_EQ(NOT_STARTED, state_);
|
| +
|
| + VLOG(1) << "Initialize NSS for chromeos user " << username_hash_;
|
| + crypto::InitializeNSSForChromeOSUser(username_hash_, path_);
|
| + RunNextStep(TPM_TOKEN_STATE_UNKNOWN);
|
| + }
|
| +
|
| + typedef base::Callback<void(bool system_tpm_token_enabled)>
|
| + SystemTPMTokenReadyCallback;
|
| + SystemTPMTokenReadyCallback GetSystemTPMTokenReadyCallback() {
|
| + return base::Bind(&Internal::OnSystemTPMTokenReady,
|
| + weak_ptr_factory_.GetWeakPtr());
|
| + }
|
| +
|
| + private:
|
| + enum SystemTPMTokenStatus {
|
| + SYSTEM_TPM_TOKEN_STATUS_UNDETERMINED,
|
| + SYSTEM_TPM_TOKEN_STATUS_ENABLED,
|
| + SYSTEM_TPM_TOKEN_STATUS_DISABLED
|
| + };
|
| +
|
| + enum State {
|
| + NOT_STARTED,
|
| + TPM_TOKEN_STATE_UNKNOWN,
|
| + TPM_TOKEN_ENABLED_AND_READY,
|
| + INITIALIZED_NSS_FOR_USER,
|
| + GOT_PRIVATE_SLOT_FOR_USER,
|
| + WAITING_FOR_SYSTEM_TPM_TOKEN,
|
| + SYSTEM_TPM_TOKEN_READY,
|
| + GOT_SYSTEM_SLOT,
|
| + CREATED_NSS_CERTDB
|
| + };
|
| +
|
| + void RunNextStep(const State& next_state) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + VLOG(1) << "State transition " << state_ << " -> " << next_state;
|
| + state_ = next_state;
|
| + switch (state_) {
|
| + case NOT_STARTED:
|
| + NOTREACHED();
|
| + break;
|
| + case TPM_TOKEN_STATE_UNKNOWN:
|
| + CheckTPMTokenState();
|
| + break;
|
| + case TPM_TOKEN_ENABLED_AND_READY:
|
| + GetTPMTokenInfo();
|
| + break;
|
| + case INITIALIZED_NSS_FOR_USER:
|
| + GetPrivateSlot();
|
| + break;
|
| + case GOT_PRIVATE_SLOT_FOR_USER:
|
| + if (!use_system_key_slot_) {
|
| + RunNextStep(GOT_SYSTEM_SLOT);
|
| + } else if (system_tpm_token_status_ ==
|
| + SYSTEM_TPM_TOKEN_STATUS_UNDETERMINED) {
|
| + state_ = WAITING_FOR_SYSTEM_TPM_TOKEN;
|
| + } else {
|
| + RunNextStep(SYSTEM_TPM_TOKEN_READY);
|
| + }
|
| + break;
|
| + case WAITING_FOR_SYSTEM_TPM_TOKEN:
|
| + // This step is waiting for OnSystemTPMTokenReady to be called.
|
| + NOTREACHED();
|
| + break;
|
| + case SYSTEM_TPM_TOKEN_READY:
|
| + GetSystemSlot();
|
| + break;
|
| + case GOT_SYSTEM_SLOT:
|
| + CreateCertDatabase();
|
| + break;
|
| + case CREATED_NSS_CERTDB:
|
| + NOTREACHED();
|
| + }
|
| + }
|
| +
|
| + void FinishWithState(const State& state) {
|
| + VLOG(1) << "FinishWithState " << state;
|
| + state_ = state;
|
| + }
|
| +
|
| + void CheckTPMTokenState() {
|
| + // Check if it's OK to initialize TPM for the user before continuing. This
|
| + // may not be the case if the TPM slot initialization was previously
|
| + // requested for the same user.
|
| + if (!crypto::ShouldInitializeTPMForChromeOSUser(username_hash_)) {
|
| + RunNextStep(INITIALIZED_NSS_FOR_USER);
|
| + return;
|
| + }
|
| +
|
| + crypto::WillInitializeTPMForChromeOSUser(username_hash_);
|
| +
|
| + if (crypto::IsTPMTokenEnabledForNSS()) {
|
| + base::Closure tpm_token_ready_callback =
|
| + base::Bind(&Internal::RunNextStep,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + TPM_TOKEN_ENABLED_AND_READY);
|
| + if (crypto::IsTPMTokenReady(tpm_token_ready_callback))
|
| + tpm_token_ready_callback.Run();
|
| + else
|
| + DVLOG(1) << "Waiting for tpm ready ...";
|
| + } else {
|
| + crypto::InitializePrivateSoftwareSlotForChromeOSUser(username_hash_);
|
| + RunNextStep(INITIALIZED_NSS_FOR_USER);
|
| + }
|
| + }
|
| +
|
| + void GetTPMTokenInfo() {
|
| + GetTPMInfoForUserOnIOThread(
|
| + user_email_,
|
| + base::Bind(&Internal::GotTPMTokenInfo, weak_ptr_factory_.GetWeakPtr()),
|
| + dbus_task_runner_,
|
| + cryptohome_client_);
|
| + }
|
| +
|
| + void GotTPMTokenInfo(chromeos::DBusMethodCallStatus call_status,
|
| + const std::string& label,
|
| + const std::string& user_pin,
|
| + int slot_id) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + if (call_status == chromeos::DBUS_METHOD_CALL_FAILURE) {
|
| + // TODO(pneubeck, tbarzic): Retry instead of just failing.
|
| + // https://crbug.com/426349
|
| + LOG(ERROR) << "DBus error while getting TPM info for " << username_hash_;
|
| + crypto::InitializePrivateSoftwareSlotForChromeOSUser(username_hash_);
|
| + } else {
|
| + crypto::InitializeTPMForChromeOSUser(username_hash_, slot_id);
|
| + }
|
| + RunNextStep(INITIALIZED_NSS_FOR_USER);
|
| + }
|
| +
|
| + void GetPrivateSlot() {
|
| + base::Callback<void(crypto::ScopedPK11Slot)> callback =
|
| + base::Bind(&Internal::GotPrivateSlot, weak_ptr_factory_.GetWeakPtr());
|
| +
|
| + crypto::ScopedPK11Slot private_slot(
|
| + crypto::GetPrivateSlotForChromeOSUser(username_hash_, callback));
|
| + if (private_slot)
|
| + callback.Run(private_slot.Pass());
|
| + }
|
| +
|
| + void GotPrivateSlot(crypto::ScopedPK11Slot private_slot) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(private_slot);
|
| +
|
| + private_slot_ = private_slot.Pass();
|
| + RunNextStep(GOT_PRIVATE_SLOT_FOR_USER);
|
| + }
|
| +
|
| + // This is called from external once the TPM token is ready. Must be called at
|
| + // most once and after Run().
|
| + void OnSystemTPMTokenReady(bool system_tpm_token_enabled) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK_NE(NOT_STARTED, state_);
|
| + DCHECK_EQ(SYSTEM_TPM_TOKEN_STATUS_UNDETERMINED, system_tpm_token_status_);
|
| +
|
| + if (!use_system_key_slot_)
|
| + return;
|
| + if (system_tpm_token_enabled)
|
| + system_tpm_token_status_ = SYSTEM_TPM_TOKEN_STATUS_ENABLED;
|
| + else
|
| + system_tpm_token_status_ = SYSTEM_TPM_TOKEN_STATUS_DISABLED;
|
| + if (state_ == WAITING_FOR_SYSTEM_TPM_TOKEN)
|
| + RunNextStep(SYSTEM_TPM_TOKEN_READY);
|
| + }
|
| +
|
| + void GetSystemSlot() {
|
| + if (!use_system_key_slot_ ||
|
| + system_tpm_token_status_ == SYSTEM_TPM_TOKEN_STATUS_DISABLED) {
|
| + VLOG(2) << "Skip system key slot initialization";
|
| + RunNextStep(GOT_SYSTEM_SLOT);
|
| + return;
|
| + }
|
| +
|
| + base::Callback<void(crypto::ScopedPK11Slot)> callback =
|
| + base::Bind(&Internal::GotSystemSlot, weak_ptr_factory_.GetWeakPtr());
|
| +
|
| + crypto::ScopedPK11Slot system_slot = crypto::GetSystemNSSKeySlot(callback);
|
| + if (system_slot)
|
| + callback.Run(system_slot.Pass());
|
| + }
|
| +
|
| + void GotSystemSlot(crypto::ScopedPK11Slot system_slot) {
|
| + if (!system_slot)
|
| + LOG(ERROR) << "Could not get the system key slot.";
|
| + system_slot_ = system_slot.Pass();
|
| + RunNextStep(GOT_SYSTEM_SLOT);
|
| + }
|
| +
|
| + void CreateCertDatabase() {
|
| + crypto::ScopedPK11Slot public_slot =
|
| + crypto::GetPublicSlotForChromeOSUser(username_hash_);
|
| +
|
| + scoped_ptr<net::NSSCertDatabaseChromeOS> db(
|
| + new net::NSSCertDatabaseChromeOS(public_slot.Pass(),
|
| + private_slot_.Pass()));
|
| + if (system_slot_)
|
| + db->SetSystemSlot(system_slot_.Pass());
|
| +
|
| + FinishWithState(CREATED_NSS_CERTDB);
|
| + io_part_->DidCreateNSSCertDatabase(db.Pass()); // Will delete this.
|
| + }
|
| +
|
| + const std::string user_email_;
|
| + const std::string username_hash_;
|
| + bool use_system_key_slot_;
|
| + const base::FilePath path_;
|
| + scoped_refptr<base::SequencedTaskRunner> dbus_task_runner_;
|
| + State state_;
|
| + crypto::ScopedPK11Slot private_slot_;
|
| + SystemTPMTokenStatus system_tpm_token_status_;
|
| + crypto::ScopedPK11Slot system_slot_;
|
| + chromeos::CryptohomeClient* cryptohome_client_;
|
| + CertDatabaseServiceIOPartChromeOS* io_part_;
|
| + base::ThreadChecker thread_checker_;
|
| + base::WeakPtrFactory<Internal> weak_ptr_factory_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Internal);
|
| +};
|
| +
|
| +CertDatabaseServiceIOPartChromeOS::CertDatabaseServiceIOPartChromeOS(
|
| + const std::string& user_email,
|
| + const std::string& username_hash,
|
| + bool use_system_key_slot,
|
| + const base::FilePath& path,
|
| + const scoped_refptr<base::SequencedTaskRunner>& dbus_task_runner,
|
| + chromeos::CryptohomeClient* cryptohome_client)
|
| + : internal_(new Internal(user_email,
|
| + username_hash,
|
| + use_system_key_slot,
|
| + path,
|
| + dbus_task_runner,
|
| + cryptohome_client,
|
| + this)) {
|
| +}
|
| +
|
| +CertDatabaseServiceIOPartChromeOS::~CertDatabaseServiceIOPartChromeOS() {
|
| +}
|
| +
|
| +void CertDatabaseServiceIOPartChromeOS::Init() {
|
| + CertDatabaseServiceIOPart::Init();
|
| + internal_->Run();
|
| +}
|
| +
|
| +void CertDatabaseServiceIOPartChromeOS::DidCreateNSSCertDatabase(
|
| + scoped_ptr<net::NSSCertDatabase> db) {
|
| + internal_.reset();
|
| + SetNSSCertDatabase(db.Pass());
|
| +}
|
| +
|
| +CertDatabaseServiceIOPartChromeOS::SystemTPMTokenReadyCallback
|
| +CertDatabaseServiceIOPartChromeOS::GetSystemTPMTokenReadyCallback() {
|
| + CHECK(!IsInitialized());
|
| + return internal_->GetSystemTPMTokenReadyCallback();
|
| +}
|
| +
|
| +} // namespace cert_database
|
|
|