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

Side by Side Diff: chromeos/network/cert_loader.cc

Issue 15649018: Call crypto::InitializeTPMToken on the IO thread (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 7 years, 6 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
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/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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698