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/observer_list.h" | 10 #include "base/observer_list.h" |
| 11 #include "base/strings/string_number_conversions.h" | |
| 11 #include "base/task_runner_util.h" | 12 #include "base/task_runner_util.h" |
| 12 #include "base/threading/worker_pool.h" | 13 #include "base/threading/worker_pool.h" |
| 13 #include "chromeos/dbus/cryptohome_client.h" | 14 #include "chromeos/dbus/cryptohome_client.h" |
| 14 #include "chromeos/dbus/dbus_thread_manager.h" | 15 #include "chromeos/dbus/dbus_thread_manager.h" |
| 15 #include "crypto/encryptor.h" | 16 #include "crypto/encryptor.h" |
| 16 #include "crypto/nss_util.h" | 17 #include "crypto/nss_util.h" |
| 17 #include "crypto/sha2.h" | 18 #include "crypto/sha2.h" |
| 18 #include "crypto/symmetric_key.h" | 19 #include "crypto/symmetric_key.h" |
| 19 #include "net/cert/nss_cert_database.h" | 20 #include "net/cert/nss_cert_database.h" |
| 20 | 21 |
| 21 namespace chromeos { | 22 namespace chromeos { |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| 25 // Delay between certificate requests while waiting for TPM/PKCS#11 init. | 26 // Delay between certificate requests while waiting for TPM/PKCS#11 init. |
| 26 const int kRequestDelayMs = 500; | 27 const int kRequestDelayMs = 500; |
| 27 | 28 |
| 28 net::CertificateList* LoadNSSCertificates() { | 29 net::CertificateList* LoadNSSCertificates() { |
| 29 net::CertificateList* cert_list(new net::CertificateList()); | 30 net::CertificateList* cert_list(new net::CertificateList()); |
| 30 net::NSSCertDatabase::GetInstance()->ListCerts(cert_list); | 31 if (base::chromeos::IsRunningOnChromeOS()) |
| 32 net::NSSCertDatabase::GetInstance()->ListCerts(cert_list); | |
| 31 return cert_list; | 33 return cert_list; |
| 32 } | 34 } |
| 33 | 35 |
| 34 } // namespace | 36 } // namespace |
| 35 | 37 |
| 36 static CertLoader* g_cert_loader = NULL; | 38 static CertLoader* g_cert_loader = NULL; |
| 37 | 39 |
| 38 // static | 40 // static |
| 39 void CertLoader::Initialize() { | 41 void CertLoader::Initialize() { |
| 40 CHECK(!g_cert_loader); | 42 CHECK(!g_cert_loader); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 112 certificates_requested_ = true; | 114 certificates_requested_ = true; |
| 113 | 115 |
| 114 VLOG(1) << "Requesting Certificates."; | 116 VLOG(1) << "Requesting Certificates."; |
| 115 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( | 117 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( |
| 116 base::Bind(&CertLoader::OnTpmIsEnabled, | 118 base::Bind(&CertLoader::OnTpmIsEnabled, |
| 117 weak_ptr_factory_.GetWeakPtr())); | 119 weak_ptr_factory_.GetWeakPtr())); |
| 118 | 120 |
| 119 return; | 121 return; |
| 120 } | 122 } |
| 121 | 123 |
| 124 // For background see this discussion on dev-tech-crypto.lists.mozilla.org: | |
| 125 // http://web.archiveorange.com/archive/v/6JJW7E40sypfZGtbkzxX | |
| 126 // | |
| 127 // NOTE: This function relies on the convention that the same PKCS#11 ID | |
| 128 // is shared between a certificate and its associated private and public | |
| 129 // keys. I tried to implement this with PK11_GetLowLevelKeyIDForCert(), | |
| 130 // but that always returns NULL on Chrome OS for me. | |
| 131 std::string CertLoader::GetPkcs11IdForCert( | |
| 132 const net::X509Certificate& cert) const { | |
| 133 if (!IsHardwareBacked()) | |
| 134 return std::string(); | |
| 135 | |
| 136 CERTCertificateStr* cert_handle = cert.os_cert_handle(); | |
| 137 SECKEYPrivateKey *priv_key = | |
| 138 PK11_FindKeyByAnyCert(cert_handle, NULL /* wincx */); | |
| 139 if (!priv_key) | |
| 140 return std::string(); | |
| 141 | |
| 142 // Get the CKA_ID attribute for a key. | |
| 143 SECItem* sec_item = PK11_GetLowLevelKeyIDForPrivateKey(priv_key); | |
| 144 std::string pkcs11_id; | |
| 145 if (sec_item) { | |
| 146 pkcs11_id = base::HexEncode(sec_item->data, sec_item->len); | |
| 147 SECITEM_FreeItem(sec_item, PR_TRUE); | |
| 148 } | |
| 149 SECKEY_DestroyPrivateKey(priv_key); | |
| 150 | |
| 151 return pkcs11_id; | |
| 152 } | |
| 153 | |
| 122 void CertLoader::OnTpmIsEnabled(DBusMethodCallStatus call_status, | 154 void CertLoader::OnTpmIsEnabled(DBusMethodCallStatus call_status, |
| 123 bool tpm_is_enabled) { | 155 bool tpm_is_enabled) { |
| 124 VLOG(1) << "OnTpmIsEnabled: " << tpm_is_enabled; | 156 VLOG(1) << "OnTpmIsEnabled: " << tpm_is_enabled; |
| 125 if (call_status != DBUS_METHOD_CALL_SUCCESS || !tpm_is_enabled) { | 157 if (call_status != DBUS_METHOD_CALL_SUCCESS || !tpm_is_enabled) { |
| 126 // TPM is not enabled, so proceed with empty tpm token name. | 158 // TPM is not enabled, so proceed with empty tpm token name. |
| 127 VLOG(1) << "TPM not available."; | 159 VLOG(1) << "TPM not available."; |
| 128 StartLoadCertificates(); | 160 StartLoadCertificates(); |
| 129 } else if (tpm_token_ready_) { | 161 } else if (tpm_token_ready_) { |
| 130 // Once the TPM token is ready, initialize it. | 162 // Once the TPM token is ready, initialize it. |
| 131 InitializeTPMToken(); | 163 InitializeTPMToken(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 const char kHardcodedTpmSlot[] = "0"; | 197 const char kHardcodedTpmSlot[] = "0"; |
| 166 tpm_token_slot_ = kHardcodedTpmSlot; | 198 tpm_token_slot_ = kHardcodedTpmSlot; |
| 167 tpm_user_pin_ = user_pin; | 199 tpm_user_pin_ = user_pin; |
| 168 tpm_token_ready_ = true; | 200 tpm_token_ready_ = true; |
| 169 | 201 |
| 170 InitializeTPMToken(); | 202 InitializeTPMToken(); |
| 171 } | 203 } |
| 172 | 204 |
| 173 void CertLoader::InitializeTPMToken() { | 205 void CertLoader::InitializeTPMToken() { |
| 174 VLOG(1) << "InitializeTPMToken"; | 206 VLOG(1) << "InitializeTPMToken"; |
| 175 if (!crypto::InitializeTPMToken(tpm_token_name_, tpm_user_pin_)) { | 207 if (base::chromeos::IsRunningOnChromeOS() && |
| 208 !crypto::InitializeTPMToken(tpm_token_name_, tpm_user_pin_)) { | |
| 176 MaybeRetryRequestCertificates(); | 209 MaybeRetryRequestCertificates(); |
| 177 return; | 210 return; |
| 178 } | 211 } |
| 179 StartLoadCertificates(); | 212 StartLoadCertificates(); |
| 180 } | 213 } |
| 181 | 214 |
| 182 void CertLoader::StartLoadCertificates() { | 215 void CertLoader::StartLoadCertificates() { |
| 183 VLOG(1) << "Start Load Certificates"; | 216 VLOG(1) << "Start Load Certificates"; |
| 184 base::PostTaskAndReplyWithResult( | 217 base::PostTaskAndReplyWithResult( |
| 185 base::WorkerPool::GetTaskRunner(true /* task_is_slow */), | 218 base::WorkerPool::GetTaskRunner(true /* task_is_slow */), |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 206 NotifyCertificatesLoaded(true); | 239 NotifyCertificatesLoaded(true); |
| 207 } else { | 240 } else { |
| 208 NotifyCertificatesLoaded(false); | 241 NotifyCertificatesLoaded(false); |
| 209 } | 242 } |
| 210 } | 243 } |
| 211 | 244 |
| 212 void CertLoader::MaybeRetryRequestCertificates() { | 245 void CertLoader::MaybeRetryRequestCertificates() { |
| 213 if (!request_task_.is_null()) | 246 if (!request_task_.is_null()) |
| 214 return; | 247 return; |
| 215 | 248 |
| 249 LOG(WARNING) << "Re-Requesting Certificates."; | |
|
Greg Spencer (Chromium)
2013/05/13 20:28:53
Nit: Does this really need to be a warning? Could
| |
| 250 | |
| 216 // Cryptohome does not notify us when the token is ready, so call | 251 // Cryptohome does not notify us when the token is ready, so call |
| 217 // this again after a delay. | 252 // this again after a delay. |
| 218 request_task_ = base::Bind(&CertLoader::RequestCertificatesTask, | 253 request_task_ = base::Bind(&CertLoader::RequestCertificatesTask, |
| 219 weak_ptr_factory_.GetWeakPtr()); | 254 weak_ptr_factory_.GetWeakPtr()); |
| 220 MessageLoop::current()->PostDelayedTask( | 255 MessageLoop::current()->PostDelayedTask( |
| 221 FROM_HERE, | 256 FROM_HERE, |
| 222 request_task_, | 257 request_task_, |
| 223 base::TimeDelta::FromMilliseconds(kRequestDelayMs)); | 258 base::TimeDelta::FromMilliseconds(kRequestDelayMs)); |
| 224 } | 259 } |
| 225 | 260 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 251 StartLoadCertificates(); | 286 StartLoadCertificates(); |
| 252 } | 287 } |
| 253 | 288 |
| 254 void CertLoader::LoggedInStateChanged(LoginState::LoggedInState state) { | 289 void CertLoader::LoggedInStateChanged(LoginState::LoggedInState state) { |
| 255 VLOG(1) << "LoggedInStateChanged: " << state; | 290 VLOG(1) << "LoggedInStateChanged: " << state; |
| 256 if (LoginState::Get()->IsUserLoggedIn() && !certificates_requested_) | 291 if (LoginState::Get()->IsUserLoggedIn() && !certificates_requested_) |
| 257 RequestCertificates(); | 292 RequestCertificates(); |
| 258 } | 293 } |
| 259 | 294 |
| 260 } // namespace chromeos | 295 } // namespace chromeos |
| OLD | NEW |