Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chromeos/network/cert_loader.h" | 5 #include "chromeos/network/cert_loader.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/chromeos/chromeos_version.h" | 9 #include "base/chromeos/chromeos_version.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" | |
| 10 #include "base/observer_list.h" | 11 #include "base/observer_list.h" |
| 12 #include "base/sequenced_task_runner.h" | |
| 11 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 12 #include "base/task_runner_util.h" | 14 #include "base/task_runner_util.h" |
| 13 #include "base/threading/worker_pool.h" | 15 #include "base/threading/worker_pool.h" |
| 14 #include "chromeos/dbus/cryptohome_client.h" | 16 #include "chromeos/dbus/cryptohome_client.h" |
| 15 #include "chromeos/dbus/dbus_thread_manager.h" | 17 #include "chromeos/dbus/dbus_thread_manager.h" |
| 16 #include "crypto/encryptor.h" | 18 #include "crypto/encryptor.h" |
| 17 #include "crypto/nss_util.h" | 19 #include "crypto/nss_util.h" |
| 18 #include "crypto/sha2.h" | 20 #include "crypto/sha2.h" |
| 19 #include "crypto/symmetric_key.h" | 21 #include "crypto/symmetric_key.h" |
| 20 #include "net/cert/nss_cert_database.h" | 22 #include "net/cert/nss_cert_database.h" |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 39 if (next_delay > max_delay) | 41 if (next_delay > max_delay) |
| 40 next_delay = max_delay; | 42 next_delay = max_delay; |
| 41 return next_delay; | 43 return next_delay; |
| 42 } | 44 } |
| 43 | 45 |
| 44 void LoadNSSCertificates(net::CertificateList* cert_list) { | 46 void LoadNSSCertificates(net::CertificateList* cert_list) { |
| 45 if (base::chromeos::IsRunningOnChromeOS()) | 47 if (base::chromeos::IsRunningOnChromeOS()) |
| 46 net::NSSCertDatabase::GetInstance()->ListCerts(cert_list); | 48 net::NSSCertDatabase::GetInstance()->ListCerts(cert_list); |
| 47 } | 49 } |
| 48 | 50 |
| 51 void CallOpenPersistentNSSDB() { | |
| 52 // Called from crypto_task_runner_. | |
| 53 VLOG(1) << "CallOpenPersistentNSSDB"; | |
| 54 | |
| 55 // Ensure we've opened the user's key/certificate database. | |
| 56 crypto::OpenPersistentNSSDB(); | |
| 57 if (base::chromeos::IsRunningOnChromeOS()) | |
| 58 crypto::EnableTPMTokenForNSS(); | |
| 59 } | |
| 60 | |
| 49 } // namespace | 61 } // namespace |
| 50 | 62 |
| 51 CertLoader::CertLoader() | 63 CertLoader::CertLoader() |
| 52 : certificates_requested_(false), | 64 : certificates_requested_(false), |
| 53 certificates_loaded_(false), | 65 certificates_loaded_(false), |
| 54 certificates_update_required_(false), | 66 certificates_update_required_(false), |
| 55 certificates_update_running_(false), | 67 certificates_update_running_(false), |
| 56 tpm_token_state_(TPM_STATE_UNKNOWN), | 68 tpm_token_state_(TPM_STATE_UNKNOWN), |
| 57 tpm_request_delay_( | 69 tpm_request_delay_( |
| 58 base::TimeDelta::FromMilliseconds(kInitialRequestDelayMs)), | 70 base::TimeDelta::FromMilliseconds(kInitialRequestDelayMs)), |
| 59 initialize_token_factory_(this), | 71 initialize_token_factory_(this), |
| 60 update_certificates_factory_(this) { | 72 update_certificates_factory_(this) { |
| 73 } | |
| 74 | |
| 75 void CertLoader::Init() { | |
| 61 net::CertDatabase::GetInstance()->AddObserver(this); | 76 net::CertDatabase::GetInstance()->AddObserver(this); |
| 62 if (LoginState::IsInitialized()) | 77 if (LoginState::IsInitialized()) |
| 63 LoginState::Get()->AddObserver(this); | 78 LoginState::Get()->AddObserver(this); |
| 64 RequestCertificates(); | 79 } |
| 80 | |
| 81 void CertLoader::SetCryptoTaskRunner( | |
| 82 const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner) { | |
| 83 crypto_task_runner_ = crypto_task_runner; | |
| 84 MaybeRequestCertificates(); | |
| 65 } | 85 } |
| 66 | 86 |
| 67 CertLoader::~CertLoader() { | 87 CertLoader::~CertLoader() { |
| 68 net::CertDatabase::GetInstance()->RemoveObserver(this); | 88 net::CertDatabase::GetInstance()->RemoveObserver(this); |
| 69 if (LoginState::IsInitialized()) | 89 if (LoginState::IsInitialized()) |
| 70 LoginState::Get()->RemoveObserver(this); | 90 LoginState::Get()->RemoveObserver(this); |
| 71 } | 91 } |
| 72 | 92 |
| 73 void CertLoader::AddObserver(CertLoader::Observer* observer) { | 93 void CertLoader::AddObserver(CertLoader::Observer* observer) { |
| 74 observers_.AddObserver(observer); | 94 observers_.AddObserver(observer); |
| 75 } | 95 } |
| 76 | 96 |
| 77 void CertLoader::RemoveObserver(CertLoader::Observer* observer) { | 97 void CertLoader::RemoveObserver(CertLoader::Observer* observer) { |
| 78 observers_.RemoveObserver(observer); | 98 observers_.RemoveObserver(observer); |
| 79 } | 99 } |
| 80 | 100 |
| 81 bool CertLoader::CertificatesLoading() const { | 101 bool CertLoader::CertificatesLoading() const { |
| 82 return certificates_requested_ && !certificates_loaded_; | 102 return certificates_requested_ && !certificates_loaded_; |
| 83 } | 103 } |
| 84 | 104 |
| 85 bool CertLoader::IsHardwareBacked() const { | 105 bool CertLoader::IsHardwareBacked() const { |
| 86 return !tpm_token_name_.empty(); | 106 return !tpm_token_name_.empty(); |
| 87 } | 107 } |
| 88 | 108 |
| 89 void CertLoader::RequestCertificates() { | 109 void CertLoader::MaybeRequestCertificates() { |
| 90 CHECK(thread_checker_.CalledOnValidThread()); | 110 CHECK(thread_checker_.CalledOnValidThread()); |
| 111 if (certificates_requested_ || | |
| 112 !LoginState::Get()->IsUserLoggedIn() || | |
|
Ryan Sleevi
2013/06/12 20:58:50
Is this check safe, considering the check on line
stevenjb
2013/06/12 21:08:31
Good catch, thanks. (This is a merge bug, the code
| |
| 113 !crypto_task_runner_.get()) | |
| 114 return; | |
| 115 | |
| 91 const bool logged_in = LoginState::IsInitialized() ? | 116 const bool logged_in = LoginState::IsInitialized() ? |
| 92 LoginState::Get()->IsUserLoggedIn() : false; | 117 LoginState::Get()->IsUserLoggedIn() : false; |
| 93 VLOG(1) << "RequestCertificates: " << logged_in; | 118 VLOG(1) << "RequestCertificates: " << logged_in; |
| 94 if (certificates_requested_ || !logged_in) | 119 if (!logged_in) |
| 95 return; | 120 return; |
| 96 | 121 |
| 97 certificates_requested_ = true; | 122 certificates_requested_ = true; |
| 98 | 123 |
| 99 // Ensure we've opened the user's key/certificate database. | 124 // This is the entry point to the TPM token initialization process, |
| 100 crypto::OpenPersistentNSSDB(); | 125 // which we should do at most once. |
| 101 if (base::chromeos::IsRunningOnChromeOS()) | 126 DCHECK_EQ(tpm_token_state_, TPM_STATE_UNKNOWN); |
| 102 crypto::EnableTPMTokenForNSS(); | |
| 103 | |
| 104 // This is the entry point to the TPM token initialization process, which we | |
| 105 // should do at most once. | |
| 106 DCHECK(!initialize_token_factory_.HasWeakPtrs()); | |
| 107 InitializeTokenAndLoadCertificates(); | 127 InitializeTokenAndLoadCertificates(); |
| 108 } | 128 } |
| 109 | 129 |
| 110 void CertLoader::InitializeTokenAndLoadCertificates() { | 130 void CertLoader::InitializeTokenAndLoadCertificates() { |
| 111 CHECK(thread_checker_.CalledOnValidThread()); | 131 CHECK(thread_checker_.CalledOnValidThread()); |
| 112 VLOG(1) << "InitializeTokenAndLoadCertificates"; | 132 VLOG(1) << "InitializeTokenAndLoadCertificates: " << tpm_token_state_; |
| 113 | 133 |
| 114 switch (tpm_token_state_) { | 134 switch (tpm_token_state_) { |
| 115 case TPM_STATE_UNKNOWN: { | 135 case TPM_STATE_UNKNOWN: { |
| 136 crypto_task_runner_->PostTaskAndReply( | |
| 137 FROM_HERE, | |
| 138 base::Bind(&CallOpenPersistentNSSDB), | |
| 139 base::Bind(&CertLoader::OnPersistentNSSDBOpened, | |
| 140 initialize_token_factory_.GetWeakPtr())); | |
| 141 return; | |
| 142 } | |
| 143 case TPM_DB_OPENED: { | |
| 116 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( | 144 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( |
| 117 base::Bind(&CertLoader::OnTpmIsEnabled, | 145 base::Bind(&CertLoader::OnTpmIsEnabled, |
| 118 initialize_token_factory_.GetWeakPtr())); | 146 initialize_token_factory_.GetWeakPtr())); |
| 119 return; | 147 return; |
| 120 } | 148 } |
| 121 case TPM_DISABLED: { | 149 case TPM_DISABLED: { |
| 122 // TPM is disabled, so proceed with empty tpm token name. | 150 // TPM is disabled, so proceed with empty tpm token name. |
| 123 StartLoadCertificates(); | 151 StartLoadCertificates(); |
| 124 return; | 152 return; |
| 125 } | 153 } |
| 126 case TPM_ENABLED: { | 154 case TPM_ENABLED: { |
| 127 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11IsTpmTokenReady( | 155 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11IsTpmTokenReady( |
| 128 base::Bind(&CertLoader::OnPkcs11IsTpmTokenReady, | 156 base::Bind(&CertLoader::OnPkcs11IsTpmTokenReady, |
| 129 initialize_token_factory_.GetWeakPtr())); | 157 initialize_token_factory_.GetWeakPtr())); |
| 130 return; | 158 return; |
| 131 } | 159 } |
| 132 case TPM_TOKEN_READY: { | 160 case TPM_TOKEN_READY: { |
| 133 // Retrieve token_name_ and user_pin_ here since they will never change | 161 // Retrieve token_name_ and user_pin_ here since they will never change |
| 134 // and CryptohomeClient calls are not thread safe. | 162 // and CryptohomeClient calls are not thread safe. |
| 135 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11GetTpmTokenInfo( | 163 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11GetTpmTokenInfo( |
| 136 base::Bind(&CertLoader::OnPkcs11GetTpmTokenInfo, | 164 base::Bind(&CertLoader::OnPkcs11GetTpmTokenInfo, |
| 137 initialize_token_factory_.GetWeakPtr())); | 165 initialize_token_factory_.GetWeakPtr())); |
| 138 return; | 166 return; |
| 139 } | 167 } |
| 140 case TPM_TOKEN_INFO_RECEIVED: { | 168 case TPM_TOKEN_INFO_RECEIVED: { |
| 141 InitializeNSSForTPMToken(); | 169 if (base::chromeos::IsRunningOnChromeOS()) { |
| 142 return; | 170 base::PostTaskAndReplyWithResult( |
| 171 crypto_task_runner_.get(), | |
| 172 FROM_HERE, | |
| 173 base::Bind(&crypto::InitializeTPMToken, | |
| 174 tpm_token_name_, tpm_user_pin_), | |
| 175 base::Bind(&CertLoader::OnTPMTokenInitialized, | |
| 176 initialize_token_factory_.GetWeakPtr())); | |
| 177 return; | |
| 178 } | |
| 179 tpm_token_state_ = TPM_TOKEN_INITIALIZED; | |
| 180 // FALL_THROUGH_INTENDED | |
| 143 } | 181 } |
| 144 case TPM_TOKEN_NSS_INITIALIZED: { | 182 case TPM_TOKEN_INITIALIZED: { |
| 145 StartLoadCertificates(); | 183 StartLoadCertificates(); |
| 146 return; | 184 return; |
| 147 } | 185 } |
| 148 } | 186 } |
| 149 } | 187 } |
| 150 | 188 |
| 151 void CertLoader::RetryTokenInitializationLater() { | 189 void CertLoader::RetryTokenInitializationLater() { |
| 190 CHECK(thread_checker_.CalledOnValidThread()); | |
| 152 LOG(WARNING) << "Re-Requesting Certificates later."; | 191 LOG(WARNING) << "Re-Requesting Certificates later."; |
| 153 base::MessageLoop::current()->PostDelayedTask( | 192 base::MessageLoop::current()->PostDelayedTask( |
| 154 FROM_HERE, | 193 FROM_HERE, |
| 155 base::Bind(&CertLoader::InitializeTokenAndLoadCertificates, | 194 base::Bind(&CertLoader::InitializeTokenAndLoadCertificates, |
| 156 initialize_token_factory_.GetWeakPtr()), | 195 initialize_token_factory_.GetWeakPtr()), |
| 157 tpm_request_delay_); | 196 tpm_request_delay_); |
| 158 tpm_request_delay_ = GetNextRequestDelayMs(tpm_request_delay_); | 197 tpm_request_delay_ = GetNextRequestDelayMs(tpm_request_delay_); |
| 159 } | 198 } |
| 160 | 199 |
| 200 void CertLoader::OnPersistentNSSDBOpened() { | |
| 201 VLOG(1) << "PersistentNSSDBOpened"; | |
| 202 tpm_token_state_ = TPM_DB_OPENED; | |
| 203 InitializeTokenAndLoadCertificates(); | |
| 204 } | |
| 205 | |
| 161 // For background see this discussion on dev-tech-crypto.lists.mozilla.org: | 206 // For background see this discussion on dev-tech-crypto.lists.mozilla.org: |
| 162 // http://web.archiveorange.com/archive/v/6JJW7E40sypfZGtbkzxX | 207 // http://web.archiveorange.com/archive/v/6JJW7E40sypfZGtbkzxX |
| 163 // | 208 // |
| 164 // NOTE: This function relies on the convention that the same PKCS#11 ID | 209 // NOTE: This function relies on the convention that the same PKCS#11 ID |
| 165 // is shared between a certificate and its associated private and public | 210 // is shared between a certificate and its associated private and public |
| 166 // keys. I tried to implement this with PK11_GetLowLevelKeyIDForCert(), | 211 // keys. I tried to implement this with PK11_GetLowLevelKeyIDForCert(), |
| 167 // but that always returns NULL on Chrome OS for me. | 212 // but that always returns NULL on Chrome OS for me. |
| 168 std::string CertLoader::GetPkcs11IdForCert( | 213 std::string CertLoader::GetPkcs11IdForCert( |
| 169 const net::X509Certificate& cert) const { | 214 const net::X509Certificate& cert) const { |
| 170 if (!IsHardwareBacked()) | 215 if (!IsHardwareBacked()) |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 227 // TODO(stevenjb): The network code expects a slot ID, not a label. See | 272 // TODO(stevenjb): The network code expects a slot ID, not a label. See |
| 228 // crbug.com/201101. For now, use a hard coded, well known slot instead. | 273 // crbug.com/201101. For now, use a hard coded, well known slot instead. |
| 229 const char kHardcodedTpmSlot[] = "0"; | 274 const char kHardcodedTpmSlot[] = "0"; |
| 230 tpm_token_slot_ = kHardcodedTpmSlot; | 275 tpm_token_slot_ = kHardcodedTpmSlot; |
| 231 tpm_user_pin_ = user_pin; | 276 tpm_user_pin_ = user_pin; |
| 232 tpm_token_state_ = TPM_TOKEN_INFO_RECEIVED; | 277 tpm_token_state_ = TPM_TOKEN_INFO_RECEIVED; |
| 233 | 278 |
| 234 InitializeTokenAndLoadCertificates(); | 279 InitializeTokenAndLoadCertificates(); |
| 235 } | 280 } |
| 236 | 281 |
| 237 void CertLoader::InitializeNSSForTPMToken() { | 282 void CertLoader::OnTPMTokenInitialized(bool success) { |
| 238 VLOG(1) << "InitializeNSSForTPMToken"; | 283 VLOG(1) << "OnTPMTokenInitialized: " << success; |
| 239 | 284 if (!success) { |
| 240 if (base::chromeos::IsRunningOnChromeOS() && | |
| 241 !crypto::InitializeTPMToken(tpm_token_name_, tpm_user_pin_)) { | |
| 242 RetryTokenInitializationLater(); | 285 RetryTokenInitializationLater(); |
| 243 return; | 286 return; |
| 244 } | 287 } |
| 245 | 288 tpm_token_state_ = TPM_TOKEN_INITIALIZED; |
| 246 tpm_token_state_ = TPM_TOKEN_NSS_INITIALIZED; | |
| 247 InitializeTokenAndLoadCertificates(); | 289 InitializeTokenAndLoadCertificates(); |
| 248 } | 290 } |
| 249 | 291 |
| 250 void CertLoader::StartLoadCertificates() { | 292 void CertLoader::StartLoadCertificates() { |
| 251 VLOG(1) << "StartLoadCertificates"; | 293 CHECK(thread_checker_.CalledOnValidThread()); |
| 294 VLOG(1) << "StartLoadCertificates: " << certificates_update_running_; | |
| 252 | 295 |
| 253 if (certificates_update_running_) { | 296 if (certificates_update_running_) { |
| 254 certificates_update_required_ = true; | 297 certificates_update_required_ = true; |
| 255 return; | 298 return; |
| 256 } | 299 } |
| 257 | 300 |
| 258 net::CertificateList* cert_list = new net::CertificateList; | 301 net::CertificateList* cert_list = new net::CertificateList; |
| 259 certificates_update_running_ = true; | 302 certificates_update_running_ = true; |
| 260 certificates_update_required_ = false; | 303 certificates_update_required_ = false; |
| 261 base::WorkerPool::GetTaskRunner(true /* task_is_slow */)-> | 304 base::WorkerPool::GetTaskRunner(true /* task_is_slow */)-> |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 296 StartLoadCertificates(); | 339 StartLoadCertificates(); |
| 297 } | 340 } |
| 298 | 341 |
| 299 void CertLoader::OnCertRemoved(const net::X509Certificate* cert) { | 342 void CertLoader::OnCertRemoved(const net::X509Certificate* cert) { |
| 300 VLOG(1) << "OnCertRemoved"; | 343 VLOG(1) << "OnCertRemoved"; |
| 301 StartLoadCertificates(); | 344 StartLoadCertificates(); |
| 302 } | 345 } |
| 303 | 346 |
| 304 void CertLoader::LoggedInStateChanged(LoginState::LoggedInState state) { | 347 void CertLoader::LoggedInStateChanged(LoginState::LoggedInState state) { |
| 305 VLOG(1) << "LoggedInStateChanged: " << state; | 348 VLOG(1) << "LoggedInStateChanged: " << state; |
| 306 RequestCertificates(); | 349 MaybeRequestCertificates(); |
| 307 } | 350 } |
| 308 | 351 |
| 309 } // namespace chromeos | 352 } // namespace chromeos |
| OLD | NEW |