diff options
author | tbarzic@chromium.org <tbarzic@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-21 23:14:53 +0000 |
---|---|---|
committer | tbarzic@chromium.org <tbarzic@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-21 23:14:53 +0000 |
commit | b2390837986574afa95926297767fad126bc9b74 (patch) | |
tree | 8744896918af941c5850db968d7f71bf428dfea4 /chromeos/cert_loader.cc | |
parent | b2d1f2dcf6d9181cd8b60804e6cbf0c13fbf9a93 (diff) | |
download | chromium_src-b2390837986574afa95926297767fad126bc9b74.zip chromium_src-b2390837986574afa95926297767fad126bc9b74.tar.gz chromium_src-b2390837986574afa95926297767fad126bc9b74.tar.bz2 |
Split chromeos::CertLoader
CertLoader does both TPM token initialization and certificate loading
from the cert database. This extracts token initializetion in a separate
class.
BUG=315343
Review URL: https://codereview.chromium.org/132313004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@246154 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos/cert_loader.cc')
-rw-r--r-- | chromeos/cert_loader.cc | 254 |
1 files changed, 31 insertions, 223 deletions
diff --git a/chromeos/cert_loader.cc b/chromeos/cert_loader.cc index 8b10a9e..70e4981 100644 --- a/chromeos/cert_loader.cc +++ b/chromeos/cert_loader.cc @@ -6,55 +6,23 @@ #include <algorithm> -#include "base/message_loop/message_loop_proxy.h" -#include "base/observer_list.h" -#include "base/sequenced_task_runner.h" +#include "base/bind.h" +#include "base/location.h" #include "base/strings/string_number_conversions.h" -#include "base/sys_info.h" #include "base/task_runner_util.h" #include "base/threading/worker_pool.h" -#include "chromeos/dbus/cryptohome_client.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "crypto/encryptor.h" #include "crypto/nss_util.h" -#include "crypto/sha2.h" -#include "crypto/symmetric_key.h" #include "net/cert/nss_cert_database.h" +#include "net/cert/x509_certificate.h" namespace chromeos { namespace { -const int64 kInitialRequestDelayMs = 100; -const int64 kMaxRequestDelayMs = 300000; // 5 minutes - -// Calculates the delay before running next attempt to initiatialize the TPM -// token, if |last_delay| was the last or initial delay. -base::TimeDelta GetNextRequestDelayMs(base::TimeDelta last_delay) { - // This implements an exponential backoff, as we don't know in which order of - // magnitude the TPM token changes it's state. - base::TimeDelta next_delay = last_delay * 2; - - // Cap the delay to prevent an overflow. This threshold is arbitrarily chosen. - const base::TimeDelta max_delay = - base::TimeDelta::FromMilliseconds(kMaxRequestDelayMs); - if (next_delay > max_delay) - next_delay = max_delay; - return next_delay; -} - -void LoadNSSCertificates(net::CertificateList* cert_list) { - net::NSSCertDatabase::GetInstance()->ListCerts(cert_list); -} - -void CallOpenPersistentNSSDB() { - // Called from crypto_task_runner_. - VLOG(1) << "CallOpenPersistentNSSDB"; - - // Ensure we've opened the user's key/certificate database. - if (base::SysInfo::IsRunningOnChromeOS()) - crypto::OpenPersistentNSSDB(); - crypto::EnableTPMTokenForNSS(); +// Loads certificates from |cert_database| into |cert_list|. +void LoadNSSCertificates(net::NSSCertDatabase* cert_database, + net::CertificateList* cert_list) { + cert_database->ListCerts(cert_list); } } // namespace @@ -86,29 +54,14 @@ bool CertLoader::IsInitialized() { } CertLoader::CertLoader() - : initialize_tpm_for_test_(false), - certificates_requested_(false), + : certificates_requested_(false), certificates_loaded_(false), certificates_update_required_(false), certificates_update_running_(false), - tpm_token_state_(TPM_STATE_UNKNOWN), - tpm_request_delay_( - base::TimeDelta::FromMilliseconds(kInitialRequestDelayMs)), tpm_token_slot_id_(-1), - initialize_token_factory_(this), - update_certificates_factory_(this) { - if (LoginState::IsInitialized()) - LoginState::Get()->AddObserver(this); -} - -void CertLoader::InitializeTPMForTest() { - initialize_tpm_for_test_ = true; -} - -void CertLoader::SetCryptoTaskRunner( - const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner) { - crypto_task_runner_ = crypto_task_runner; - MaybeRequestCertificates(); + weak_factory_(this) { + if (TPMTokenLoader::IsInitialized()) + TPMTokenLoader::Get()->AddObserver(this); } void CertLoader::SetSlowTaskRunnerForTest( @@ -118,8 +71,8 @@ void CertLoader::SetSlowTaskRunnerForTest( CertLoader::~CertLoader() { net::CertDatabase::GetInstance()->RemoveObserver(this); - if (LoginState::IsInitialized()) - LoginState::Get()->RemoveObserver(this); + if (TPMTokenLoader::IsInitialized()) + TPMTokenLoader::Get()->RemoveObserver(this); } void CertLoader::AddObserver(CertLoader::Observer* observer) { @@ -130,115 +83,12 @@ void CertLoader::RemoveObserver(CertLoader::Observer* observer) { observers_.RemoveObserver(observer); } -bool CertLoader::CertificatesLoading() const { - return certificates_requested_ && !certificates_loaded_; -} - bool CertLoader::IsHardwareBacked() const { return !tpm_token_name_.empty(); } -void CertLoader::MaybeRequestCertificates() { - CHECK(thread_checker_.CalledOnValidThread()); - - // This is the entry point to the TPM token initialization process, - // which we should do at most once. - if (certificates_requested_ || !crypto_task_runner_.get()) - return; - - if (!LoginState::IsInitialized()) - return; - - bool request_certificates = LoginState::Get()->IsUserLoggedIn() || - LoginState::Get()->IsInSafeMode(); - - VLOG(1) << "RequestCertificates: " << request_certificates; - if (!request_certificates) - return; - - certificates_requested_ = true; - - // Ensure we only initialize the TPM token once. - DCHECK_EQ(tpm_token_state_, TPM_STATE_UNKNOWN); - if (!initialize_tpm_for_test_ && !base::SysInfo::IsRunningOnChromeOS()) - tpm_token_state_ = TPM_DISABLED; - - // Treat TPM as disabled for guest users since they do not store certs. - if (LoginState::Get()->IsGuestUser()) - tpm_token_state_ = TPM_DISABLED; - - InitializeTokenAndLoadCertificates(); -} - -void CertLoader::InitializeTokenAndLoadCertificates() { - CHECK(thread_checker_.CalledOnValidThread()); - VLOG(1) << "InitializeTokenAndLoadCertificates: " << tpm_token_state_; - - switch (tpm_token_state_) { - case TPM_STATE_UNKNOWN: { - crypto_task_runner_->PostTaskAndReply( - FROM_HERE, - base::Bind(&CallOpenPersistentNSSDB), - base::Bind(&CertLoader::OnPersistentNSSDBOpened, - initialize_token_factory_.GetWeakPtr())); - return; - } - case TPM_DB_OPENED: { - DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( - base::Bind(&CertLoader::OnTpmIsEnabled, - initialize_token_factory_.GetWeakPtr())); - return; - } - case TPM_DISABLED: { - // TPM is disabled, so proceed with empty tpm token name. - StartLoadCertificates(); - return; - } - case TPM_ENABLED: { - DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11IsTpmTokenReady( - base::Bind(&CertLoader::OnPkcs11IsTpmTokenReady, - initialize_token_factory_.GetWeakPtr())); - return; - } - case TPM_TOKEN_READY: { - // Retrieve token_name_ and user_pin_ here since they will never change - // and CryptohomeClient calls are not thread safe. - DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11GetTpmTokenInfo( - base::Bind(&CertLoader::OnPkcs11GetTpmTokenInfo, - initialize_token_factory_.GetWeakPtr())); - return; - } - case TPM_TOKEN_INFO_RECEIVED: { - base::PostTaskAndReplyWithResult( - crypto_task_runner_.get(), - FROM_HERE, - base::Bind(&crypto::InitializeTPMToken, tpm_token_slot_id_), - base::Bind(&CertLoader::OnTPMTokenInitialized, - initialize_token_factory_.GetWeakPtr())); - return; - } - case TPM_TOKEN_INITIALIZED: { - StartLoadCertificates(); - return; - } - } -} - -void CertLoader::RetryTokenInitializationLater() { - CHECK(thread_checker_.CalledOnValidThread()); - LOG(WARNING) << "Retry token initialization later."; - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&CertLoader::InitializeTokenAndLoadCertificates, - initialize_token_factory_.GetWeakPtr()), - tpm_request_delay_); - tpm_request_delay_ = GetNextRequestDelayMs(tpm_request_delay_); -} - -void CertLoader::OnPersistentNSSDBOpened() { - VLOG(1) << "PersistentNSSDBOpened"; - tpm_token_state_ = TPM_DB_OPENED; - InitializeTokenAndLoadCertificates(); +bool CertLoader::CertificatesLoading() const { + return certificates_requested_ && !certificates_loaded_; } // This is copied from chrome/common/net/x509_certificate_model_nss.cc. @@ -270,61 +120,11 @@ std::string CertLoader::GetPkcs11IdForCert(const net::X509Certificate& cert) { return pkcs11_id; } -void CertLoader::OnTpmIsEnabled(DBusMethodCallStatus call_status, - bool tpm_is_enabled) { - VLOG(1) << "OnTpmIsEnabled: " << tpm_is_enabled; - - if (call_status == DBUS_METHOD_CALL_SUCCESS && tpm_is_enabled) - tpm_token_state_ = TPM_ENABLED; - else - tpm_token_state_ = TPM_DISABLED; - - InitializeTokenAndLoadCertificates(); -} - -void CertLoader::OnPkcs11IsTpmTokenReady(DBusMethodCallStatus call_status, - bool is_tpm_token_ready) { - VLOG(1) << "OnPkcs11IsTpmTokenReady: " << is_tpm_token_ready; - - if (call_status == DBUS_METHOD_CALL_FAILURE || !is_tpm_token_ready) { - RetryTokenInitializationLater(); +void CertLoader::RequestCertificates() { + if (certificates_requested_) return; - } - - tpm_token_state_ = TPM_TOKEN_READY; - InitializeTokenAndLoadCertificates(); -} - -void CertLoader::OnPkcs11GetTpmTokenInfo(DBusMethodCallStatus call_status, - const std::string& token_name, - const std::string& user_pin, - int token_slot_id) { - VLOG(1) << "OnPkcs11GetTpmTokenInfo: " << token_name; - - if (call_status == DBUS_METHOD_CALL_FAILURE) { - RetryTokenInitializationLater(); - return; - } - - tpm_token_name_ = token_name; - tpm_token_slot_id_ = token_slot_id; - tpm_user_pin_ = user_pin; - tpm_token_state_ = TPM_TOKEN_INFO_RECEIVED; - - InitializeTokenAndLoadCertificates(); -} - -void CertLoader::OnTPMTokenInitialized(bool success) { - VLOG(1) << "OnTPMTokenInitialized: " << success; - if (!success) { - RetryTokenInitializationLater(); - return; - } - tpm_token_state_ = TPM_TOKEN_INITIALIZED; - InitializeTokenAndLoadCertificates(); -} + certificates_requested_ = true; -void CertLoader::StartLoadCertificates() { DCHECK(!certificates_loaded_ && !certificates_update_running_); net::CertDatabase::GetInstance()->AddObserver(this); LoadCertificates(); @@ -348,9 +148,11 @@ void CertLoader::LoadCertificates() { task_runner = base::WorkerPool::GetTaskRunner(true /* task is slow */); task_runner->PostTaskAndReply( FROM_HERE, - base::Bind(LoadNSSCertificates, cert_list), + base::Bind(LoadNSSCertificates, + net::NSSCertDatabase::GetInstance(), + cert_list), base::Bind(&CertLoader::UpdateCertificates, - update_certificates_factory_.GetWeakPtr(), + weak_factory_.GetWeakPtr(), base::Owned(cert_list))); } @@ -393,9 +195,15 @@ void CertLoader::OnCertRemoved(const net::X509Certificate* cert) { LoadCertificates(); } -void CertLoader::LoggedInStateChanged() { - VLOG(1) << "LoggedInStateChanged"; - MaybeRequestCertificates(); +void CertLoader::OnTPMTokenReady(const std::string& tpm_user_pin, + const std::string& tpm_token_name, + int tpm_token_slot_id) { + tpm_user_pin_ = tpm_user_pin; + tpm_token_name_ = tpm_token_name; + tpm_token_slot_id_ = tpm_token_slot_id; + + VLOG(1) << "TPM token ready."; + RequestCertificates(); } } // namespace chromeos |