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/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 |
| 63 static CertLoader* g_cert_loader = NULL; |
| 64 // static |
| 65 void CertLoader::Initialize() { |
| 66 CHECK(!g_cert_loader); |
| 67 g_cert_loader = new CertLoader(); |
| 68 g_cert_loader->Init(); |
| 69 } |
| 70 |
| 71 // static |
| 72 void CertLoader::Shutdown() { |
| 73 CHECK(g_cert_loader); |
| 74 delete g_cert_loader; |
| 75 g_cert_loader = NULL; |
| 76 } |
| 77 |
| 78 // static |
| 79 CertLoader* CertLoader::Get() { |
| 80 CHECK(g_cert_loader) |
| 81 << "CertLoader::Get() called before Initialize()"; |
| 82 return g_cert_loader; |
| 83 } |
| 84 |
| 85 // static |
| 86 bool CertLoader::IsInitialized() { |
| 87 return g_cert_loader; |
| 88 } |
| 89 |
51 CertLoader::CertLoader() | 90 CertLoader::CertLoader() |
52 : certificates_requested_(false), | 91 : certificates_requested_(false), |
53 certificates_loaded_(false), | 92 certificates_loaded_(false), |
54 certificates_update_required_(false), | 93 certificates_update_required_(false), |
55 certificates_update_running_(false), | 94 certificates_update_running_(false), |
56 tpm_token_state_(TPM_STATE_UNKNOWN), | 95 tpm_token_state_(TPM_STATE_UNKNOWN), |
57 tpm_request_delay_( | 96 tpm_request_delay_( |
58 base::TimeDelta::FromMilliseconds(kInitialRequestDelayMs)), | 97 base::TimeDelta::FromMilliseconds(kInitialRequestDelayMs)), |
59 initialize_token_factory_(this), | 98 initialize_token_factory_(this), |
60 update_certificates_factory_(this) { | 99 update_certificates_factory_(this) { |
| 100 } |
| 101 |
| 102 void CertLoader::Init() { |
61 net::CertDatabase::GetInstance()->AddObserver(this); | 103 net::CertDatabase::GetInstance()->AddObserver(this); |
62 if (LoginState::IsInitialized()) | 104 if (LoginState::IsInitialized()) |
63 LoginState::Get()->AddObserver(this); | 105 LoginState::Get()->AddObserver(this); |
64 RequestCertificates(); | 106 } |
| 107 |
| 108 void CertLoader::SetCryptoTaskRunner( |
| 109 const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner) { |
| 110 crypto_task_runner_ = crypto_task_runner; |
| 111 MaybeRequestCertificates(); |
65 } | 112 } |
66 | 113 |
67 CertLoader::~CertLoader() { | 114 CertLoader::~CertLoader() { |
68 net::CertDatabase::GetInstance()->RemoveObserver(this); | 115 net::CertDatabase::GetInstance()->RemoveObserver(this); |
69 if (LoginState::IsInitialized()) | 116 if (LoginState::IsInitialized()) |
70 LoginState::Get()->RemoveObserver(this); | 117 LoginState::Get()->RemoveObserver(this); |
71 } | 118 } |
72 | 119 |
73 void CertLoader::AddObserver(CertLoader::Observer* observer) { | 120 void CertLoader::AddObserver(CertLoader::Observer* observer) { |
74 observers_.AddObserver(observer); | 121 observers_.AddObserver(observer); |
75 } | 122 } |
76 | 123 |
77 void CertLoader::RemoveObserver(CertLoader::Observer* observer) { | 124 void CertLoader::RemoveObserver(CertLoader::Observer* observer) { |
78 observers_.RemoveObserver(observer); | 125 observers_.RemoveObserver(observer); |
79 } | 126 } |
80 | 127 |
81 bool CertLoader::CertificatesLoading() const { | 128 bool CertLoader::CertificatesLoading() const { |
82 return certificates_requested_ && !certificates_loaded_; | 129 return certificates_requested_ && !certificates_loaded_; |
83 } | 130 } |
84 | 131 |
85 bool CertLoader::IsHardwareBacked() const { | 132 bool CertLoader::IsHardwareBacked() const { |
86 return !tpm_token_name_.empty(); | 133 return !tpm_token_name_.empty(); |
87 } | 134 } |
88 | 135 |
89 void CertLoader::RequestCertificates() { | 136 void CertLoader::MaybeRequestCertificates() { |
90 CHECK(thread_checker_.CalledOnValidThread()); | 137 CHECK(thread_checker_.CalledOnValidThread()); |
| 138 |
| 139 // This is the entry point to the TPM token initialization process, |
| 140 // which we should do at most once. |
| 141 if (certificates_requested_ || !crypto_task_runner_.get()) |
| 142 return; |
| 143 |
91 const bool logged_in = LoginState::IsInitialized() ? | 144 const bool logged_in = LoginState::IsInitialized() ? |
92 LoginState::Get()->IsUserLoggedIn() : false; | 145 LoginState::Get()->IsUserLoggedIn() : false; |
93 VLOG(1) << "RequestCertificates: " << logged_in; | 146 VLOG(1) << "RequestCertificates: " << logged_in; |
94 if (certificates_requested_ || !logged_in) | 147 if (!logged_in) |
95 return; | 148 return; |
96 | 149 |
97 certificates_requested_ = true; | 150 certificates_requested_ = true; |
98 | 151 |
99 // Ensure we've opened the user's key/certificate database. | 152 // Ensure we only initialize the TPM token once. |
100 crypto::OpenPersistentNSSDB(); | 153 DCHECK_EQ(tpm_token_state_, TPM_STATE_UNKNOWN); |
101 if (base::chromeos::IsRunningOnChromeOS()) | |
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(); | 154 InitializeTokenAndLoadCertificates(); |
108 } | 155 } |
109 | 156 |
110 void CertLoader::InitializeTokenAndLoadCertificates() { | 157 void CertLoader::InitializeTokenAndLoadCertificates() { |
111 CHECK(thread_checker_.CalledOnValidThread()); | 158 CHECK(thread_checker_.CalledOnValidThread()); |
112 VLOG(1) << "InitializeTokenAndLoadCertificates"; | 159 VLOG(1) << "InitializeTokenAndLoadCertificates: " << tpm_token_state_; |
113 | 160 |
114 switch (tpm_token_state_) { | 161 switch (tpm_token_state_) { |
115 case TPM_STATE_UNKNOWN: { | 162 case TPM_STATE_UNKNOWN: { |
| 163 crypto_task_runner_->PostTaskAndReply( |
| 164 FROM_HERE, |
| 165 base::Bind(&CallOpenPersistentNSSDB), |
| 166 base::Bind(&CertLoader::OnPersistentNSSDBOpened, |
| 167 initialize_token_factory_.GetWeakPtr())); |
| 168 return; |
| 169 } |
| 170 case TPM_DB_OPENED: { |
116 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( | 171 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( |
117 base::Bind(&CertLoader::OnTpmIsEnabled, | 172 base::Bind(&CertLoader::OnTpmIsEnabled, |
118 initialize_token_factory_.GetWeakPtr())); | 173 initialize_token_factory_.GetWeakPtr())); |
119 return; | 174 return; |
120 } | 175 } |
121 case TPM_DISABLED: { | 176 case TPM_DISABLED: { |
122 // TPM is disabled, so proceed with empty tpm token name. | 177 // TPM is disabled, so proceed with empty tpm token name. |
123 StartLoadCertificates(); | 178 StartLoadCertificates(); |
124 return; | 179 return; |
125 } | 180 } |
126 case TPM_ENABLED: { | 181 case TPM_ENABLED: { |
127 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11IsTpmTokenReady( | 182 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11IsTpmTokenReady( |
128 base::Bind(&CertLoader::OnPkcs11IsTpmTokenReady, | 183 base::Bind(&CertLoader::OnPkcs11IsTpmTokenReady, |
129 initialize_token_factory_.GetWeakPtr())); | 184 initialize_token_factory_.GetWeakPtr())); |
130 return; | 185 return; |
131 } | 186 } |
132 case TPM_TOKEN_READY: { | 187 case TPM_TOKEN_READY: { |
133 // Retrieve token_name_ and user_pin_ here since they will never change | 188 // Retrieve token_name_ and user_pin_ here since they will never change |
134 // and CryptohomeClient calls are not thread safe. | 189 // and CryptohomeClient calls are not thread safe. |
135 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11GetTpmTokenInfo( | 190 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11GetTpmTokenInfo( |
136 base::Bind(&CertLoader::OnPkcs11GetTpmTokenInfo, | 191 base::Bind(&CertLoader::OnPkcs11GetTpmTokenInfo, |
137 initialize_token_factory_.GetWeakPtr())); | 192 initialize_token_factory_.GetWeakPtr())); |
138 return; | 193 return; |
139 } | 194 } |
140 case TPM_TOKEN_INFO_RECEIVED: { | 195 case TPM_TOKEN_INFO_RECEIVED: { |
141 InitializeNSSForTPMToken(); | 196 if (base::chromeos::IsRunningOnChromeOS()) { |
142 return; | 197 base::PostTaskAndReplyWithResult( |
| 198 crypto_task_runner_.get(), |
| 199 FROM_HERE, |
| 200 base::Bind(&crypto::InitializeTPMToken, |
| 201 tpm_token_name_, tpm_user_pin_), |
| 202 base::Bind(&CertLoader::OnTPMTokenInitialized, |
| 203 initialize_token_factory_.GetWeakPtr())); |
| 204 return; |
| 205 } |
| 206 tpm_token_state_ = TPM_TOKEN_INITIALIZED; |
| 207 // FALL_THROUGH_INTENDED |
143 } | 208 } |
144 case TPM_TOKEN_NSS_INITIALIZED: { | 209 case TPM_TOKEN_INITIALIZED: { |
145 StartLoadCertificates(); | 210 StartLoadCertificates(); |
146 return; | 211 return; |
147 } | 212 } |
148 } | 213 } |
149 } | 214 } |
150 | 215 |
151 void CertLoader::RetryTokenInitializationLater() { | 216 void CertLoader::RetryTokenInitializationLater() { |
| 217 CHECK(thread_checker_.CalledOnValidThread()); |
152 LOG(WARNING) << "Re-Requesting Certificates later."; | 218 LOG(WARNING) << "Re-Requesting Certificates later."; |
153 base::MessageLoop::current()->PostDelayedTask( | 219 base::MessageLoop::current()->PostDelayedTask( |
154 FROM_HERE, | 220 FROM_HERE, |
155 base::Bind(&CertLoader::InitializeTokenAndLoadCertificates, | 221 base::Bind(&CertLoader::InitializeTokenAndLoadCertificates, |
156 initialize_token_factory_.GetWeakPtr()), | 222 initialize_token_factory_.GetWeakPtr()), |
157 tpm_request_delay_); | 223 tpm_request_delay_); |
158 tpm_request_delay_ = GetNextRequestDelayMs(tpm_request_delay_); | 224 tpm_request_delay_ = GetNextRequestDelayMs(tpm_request_delay_); |
159 } | 225 } |
160 | 226 |
| 227 void CertLoader::OnPersistentNSSDBOpened() { |
| 228 VLOG(1) << "PersistentNSSDBOpened"; |
| 229 tpm_token_state_ = TPM_DB_OPENED; |
| 230 InitializeTokenAndLoadCertificates(); |
| 231 } |
| 232 |
161 // For background see this discussion on dev-tech-crypto.lists.mozilla.org: | 233 // For background see this discussion on dev-tech-crypto.lists.mozilla.org: |
162 // http://web.archiveorange.com/archive/v/6JJW7E40sypfZGtbkzxX | 234 // http://web.archiveorange.com/archive/v/6JJW7E40sypfZGtbkzxX |
163 // | 235 // |
164 // NOTE: This function relies on the convention that the same PKCS#11 ID | 236 // 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 | 237 // is shared between a certificate and its associated private and public |
166 // keys. I tried to implement this with PK11_GetLowLevelKeyIDForCert(), | 238 // keys. I tried to implement this with PK11_GetLowLevelKeyIDForCert(), |
167 // but that always returns NULL on Chrome OS for me. | 239 // but that always returns NULL on Chrome OS for me. |
168 std::string CertLoader::GetPkcs11IdForCert( | 240 std::string CertLoader::GetPkcs11IdForCert( |
169 const net::X509Certificate& cert) const { | 241 const net::X509Certificate& cert) const { |
170 if (!IsHardwareBacked()) | 242 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 | 299 // 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. | 300 // crbug.com/201101. For now, use a hard coded, well known slot instead. |
229 const char kHardcodedTpmSlot[] = "0"; | 301 const char kHardcodedTpmSlot[] = "0"; |
230 tpm_token_slot_ = kHardcodedTpmSlot; | 302 tpm_token_slot_ = kHardcodedTpmSlot; |
231 tpm_user_pin_ = user_pin; | 303 tpm_user_pin_ = user_pin; |
232 tpm_token_state_ = TPM_TOKEN_INFO_RECEIVED; | 304 tpm_token_state_ = TPM_TOKEN_INFO_RECEIVED; |
233 | 305 |
234 InitializeTokenAndLoadCertificates(); | 306 InitializeTokenAndLoadCertificates(); |
235 } | 307 } |
236 | 308 |
237 void CertLoader::InitializeNSSForTPMToken() { | 309 void CertLoader::OnTPMTokenInitialized(bool success) { |
238 VLOG(1) << "InitializeNSSForTPMToken"; | 310 VLOG(1) << "OnTPMTokenInitialized: " << success; |
239 | 311 if (!success) { |
240 if (base::chromeos::IsRunningOnChromeOS() && | |
241 !crypto::InitializeTPMToken(tpm_token_name_, tpm_user_pin_)) { | |
242 RetryTokenInitializationLater(); | 312 RetryTokenInitializationLater(); |
243 return; | 313 return; |
244 } | 314 } |
245 | 315 tpm_token_state_ = TPM_TOKEN_INITIALIZED; |
246 tpm_token_state_ = TPM_TOKEN_NSS_INITIALIZED; | |
247 InitializeTokenAndLoadCertificates(); | 316 InitializeTokenAndLoadCertificates(); |
248 } | 317 } |
249 | 318 |
250 void CertLoader::StartLoadCertificates() { | 319 void CertLoader::StartLoadCertificates() { |
251 VLOG(1) << "StartLoadCertificates"; | 320 CHECK(thread_checker_.CalledOnValidThread()); |
| 321 VLOG(1) << "StartLoadCertificates: " << certificates_update_running_; |
252 | 322 |
253 if (certificates_update_running_) { | 323 if (certificates_update_running_) { |
254 certificates_update_required_ = true; | 324 certificates_update_required_ = true; |
255 return; | 325 return; |
256 } | 326 } |
257 | 327 |
258 net::CertificateList* cert_list = new net::CertificateList; | 328 net::CertificateList* cert_list = new net::CertificateList; |
259 certificates_update_running_ = true; | 329 certificates_update_running_ = true; |
260 certificates_update_required_ = false; | 330 certificates_update_required_ = false; |
261 base::WorkerPool::GetTaskRunner(true /* task_is_slow */)-> | 331 base::WorkerPool::GetTaskRunner(true /* task_is_slow */)-> |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 StartLoadCertificates(); | 366 StartLoadCertificates(); |
297 } | 367 } |
298 | 368 |
299 void CertLoader::OnCertRemoved(const net::X509Certificate* cert) { | 369 void CertLoader::OnCertRemoved(const net::X509Certificate* cert) { |
300 VLOG(1) << "OnCertRemoved"; | 370 VLOG(1) << "OnCertRemoved"; |
301 StartLoadCertificates(); | 371 StartLoadCertificates(); |
302 } | 372 } |
303 | 373 |
304 void CertLoader::LoggedInStateChanged(LoginState::LoggedInState state) { | 374 void CertLoader::LoggedInStateChanged(LoginState::LoggedInState state) { |
305 VLOG(1) << "LoggedInStateChanged: " << state; | 375 VLOG(1) << "LoggedInStateChanged: " << state; |
306 RequestCertificates(); | 376 MaybeRequestCertificates(); |
307 } | 377 } |
308 | 378 |
309 } // namespace chromeos | 379 } // namespace chromeos |
OLD | NEW |