Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(336)

Side by Side Diff: chromeos/cert_loader.cc

Issue 20130002: Call crypto::InitializeTPMToken on the IO thread (Take 2) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chromeos/cert_loader.h ('k') | chromeos/chromeos.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « chromeos/cert_loader.h ('k') | chromeos/chromeos.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698