OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "crypto/nss_util.h" | 5 #include "crypto/nss_util.h" |
6 #include "crypto/nss_util_internal.h" | 6 #include "crypto/nss_util_internal.h" |
7 | 7 |
8 #include <nss.h> | 8 #include <nss.h> |
9 #include <pk11pub.h> | 9 #include <pk11pub.h> |
10 #include <plarena.h> | 10 #include <plarena.h> |
11 #include <prerror.h> | 11 #include <prerror.h> |
12 #include <prinit.h> | 12 #include <prinit.h> |
13 #include <prtime.h> | 13 #include <prtime.h> |
14 #include <secmod.h> | 14 #include <secmod.h> |
15 | 15 |
16 #if defined(OS_LINUX) | 16 #if defined(OS_LINUX) |
17 #include <linux/nfs_fs.h> | 17 #include <linux/nfs_fs.h> |
18 #include <sys/vfs.h> | 18 #include <sys/vfs.h> |
19 #elif defined(OS_OPENBSD) | 19 #elif defined(OS_OPENBSD) |
20 #include <sys/mount.h> | 20 #include <sys/mount.h> |
21 #include <sys/param.h> | 21 #include <sys/param.h> |
22 #endif | 22 #endif |
23 | 23 |
24 #include <vector> | 24 #include <vector> |
25 | 25 |
26 #include "base/debug/alias.h" | 26 #include "base/debug/alias.h" |
27 #include "base/debug/stack_trace.h" | |
27 #include "base/environment.h" | 28 #include "base/environment.h" |
28 #include "base/file_util.h" | 29 #include "base/file_util.h" |
29 #include "base/files/file_path.h" | 30 #include "base/files/file_path.h" |
30 #include "base/files/scoped_temp_dir.h" | 31 #include "base/files/scoped_temp_dir.h" |
31 #include "base/lazy_instance.h" | 32 #include "base/lazy_instance.h" |
32 #include "base/logging.h" | 33 #include "base/logging.h" |
33 #include "base/memory/scoped_ptr.h" | 34 #include "base/memory/scoped_ptr.h" |
34 #include "base/metrics/histogram.h" | 35 #include "base/metrics/histogram.h" |
35 #include "base/native_library.h" | 36 #include "base/native_library.h" |
36 #include "base/strings/stringprintf.h" | 37 #include "base/strings/stringprintf.h" |
38 #include "base/threading/non_thread_safe.h" | |
37 #include "base/threading/thread_restrictions.h" | 39 #include "base/threading/thread_restrictions.h" |
38 #include "build/build_config.h" | 40 #include "build/build_config.h" |
39 | 41 |
40 // USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not | 42 // USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not |
41 // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't | 43 // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't |
42 // use NSS for crypto or certificate verification, and we don't use the NSS | 44 // use NSS for crypto or certificate verification, and we don't use the NSS |
43 // certificate and key databases. | 45 // certificate and key databases. |
44 #if defined(USE_NSS) | 46 #if defined(USE_NSS) |
45 #include "base/synchronization/lock.h" | 47 #include "base/synchronization/lock.h" |
46 #include "crypto/crypto_module_blocking_password_delegate.h" | 48 #include "crypto/crypto_module_blocking_password_delegate.h" |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
206 void CrashOnNSSInitFailure() { | 208 void CrashOnNSSInitFailure() { |
207 int nss_error = PR_GetError(); | 209 int nss_error = PR_GetError(); |
208 int os_error = PR_GetOSError(); | 210 int os_error = PR_GetOSError(); |
209 base::debug::Alias(&nss_error); | 211 base::debug::Alias(&nss_error); |
210 base::debug::Alias(&os_error); | 212 base::debug::Alias(&os_error); |
211 LOG(ERROR) << "Error initializing NSS without a persistent database: " | 213 LOG(ERROR) << "Error initializing NSS without a persistent database: " |
212 << GetNSSErrorMessage(); | 214 << GetNSSErrorMessage(); |
213 LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error; | 215 LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error; |
214 } | 216 } |
215 | 217 |
216 class NSSInitSingleton { | 218 class NSSInitSingleton : public base::NonThreadSafe { |
217 public: | 219 public: |
218 #if defined(OS_CHROMEOS) | 220 #if defined(OS_CHROMEOS) |
219 void OpenPersistentNSSDB() { | 221 void OpenPersistentNSSDB() { |
222 DCHECK(CalledOnValidThread()); | |
223 | |
220 if (!chromeos_user_logged_in_) { | 224 if (!chromeos_user_logged_in_) { |
221 // GetDefaultConfigDirectory causes us to do blocking IO on UI thread. | 225 // GetDefaultConfigDirectory causes us to do blocking IO on UI thread. |
222 // Temporarily allow it until we fix http://crbug.com/70119 | 226 // Temporarily allow it until we fix http://crbug.com/70119 |
223 base::ThreadRestrictions::ScopedAllowIO allow_io; | 227 base::ThreadRestrictions::ScopedAllowIO allow_io; |
224 chromeos_user_logged_in_ = true; | 228 chromeos_user_logged_in_ = true; |
225 | 229 |
226 // This creates another DB slot in NSS that is read/write, unlike | 230 // This creates another DB slot in NSS that is read/write, unlike |
227 // the fake root CA cert DB and the "default" crypto key | 231 // the fake root CA cert DB and the "default" crypto key |
228 // provider, which are still read-only (because we initialized | 232 // provider, which are still read-only (because we initialized |
229 // NSS before we had a cryptohome mounted). | 233 // NSS before we had a cryptohome mounted). |
230 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), | 234 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), |
231 kNSSDatabaseName); | 235 kNSSDatabaseName); |
232 } | 236 } |
233 } | 237 } |
234 | 238 |
235 void EnableTPMTokenForNSS() { | 239 void EnableTPMTokenForNSS() { |
240 DCHECK(CalledOnValidThread()); | |
241 | |
236 // If this gets set, then we'll use the TPM for certs with | 242 // If this gets set, then we'll use the TPM for certs with |
237 // private keys, otherwise we'll fall back to the software | 243 // private keys, otherwise we'll fall back to the software |
238 // implementation. | 244 // implementation. |
239 tpm_token_enabled_for_nss_ = true; | 245 tpm_token_enabled_for_nss_ = true; |
240 } | 246 } |
241 | 247 |
242 bool InitializeTPMToken(const std::string& token_name, | 248 bool InitializeTPMToken(const std::string& token_name, |
243 int token_slot_id, | 249 int token_slot_id, |
244 const std::string& user_pin) { | 250 const std::string& user_pin) { |
251 DCHECK(CalledOnValidThread()); | |
252 | |
245 // If EnableTPMTokenForNSS hasn't been called, return false. | 253 // If EnableTPMTokenForNSS hasn't been called, return false. |
246 if (!tpm_token_enabled_for_nss_) | 254 if (!tpm_token_enabled_for_nss_) |
247 return false; | 255 return false; |
248 | 256 |
249 // If everything is already initialized, then return true. | 257 // If everything is already initialized, then return true. |
250 if (chaps_module_ && tpm_slot_) | 258 if (chaps_module_ && tpm_slot_) |
251 return true; | 259 return true; |
252 | 260 |
253 tpm_token_name_ = token_name; | 261 tpm_token_name_ = token_name; |
254 tpm_user_pin_ = user_pin; | 262 tpm_user_pin_ = user_pin; |
(...skipping 19 matching lines...) Expand all Loading... | |
274 } | 282 } |
275 if (chaps_module_){ | 283 if (chaps_module_){ |
276 tpm_slot_ = GetTPMSlotForId(token_slot_id); | 284 tpm_slot_ = GetTPMSlotForId(token_slot_id); |
277 | 285 |
278 return tpm_slot_ != NULL; | 286 return tpm_slot_ != NULL; |
279 } | 287 } |
280 return false; | 288 return false; |
281 } | 289 } |
282 | 290 |
283 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { | 291 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { |
292 // TODO(mattm): Change to DCHECK when callers have been fixed. | |
293 if (!CalledOnValidThread()) { | |
294 DVLOG(1) << "Called on wrong thread.\n" | |
295 << base::debug::StackTrace().ToString(); | |
296 } | |
297 | |
284 if (!tpm_token_enabled_for_nss_) { | 298 if (!tpm_token_enabled_for_nss_) { |
285 LOG(ERROR) << "GetTPMTokenInfo called before TPM Token is ready."; | 299 LOG(ERROR) << "GetTPMTokenInfo called before TPM Token is ready."; |
286 return; | 300 return; |
287 } | 301 } |
288 if (token_name) | 302 if (token_name) |
289 *token_name = tpm_token_name_; | 303 *token_name = tpm_token_name_; |
290 if (user_pin) | 304 if (user_pin) |
291 *user_pin = tpm_user_pin_; | 305 *user_pin = tpm_user_pin_; |
292 } | 306 } |
293 | 307 |
294 bool IsTPMTokenReady() { | 308 bool IsTPMTokenReady() { |
309 // TODO(mattm): Change to DCHECK when callers have been fixed. | |
310 if (!CalledOnValidThread()) { | |
311 DVLOG(1) << "Called on wrong thread.\n" | |
312 << base::debug::StackTrace().ToString(); | |
313 } | |
314 | |
295 return tpm_slot_ != NULL; | 315 return tpm_slot_ != NULL; |
296 } | 316 } |
297 | 317 |
298 // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot | 318 // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot |
299 // id as an int. This should be safe since this is only used with chaps, which | 319 // id as an int. This should be safe since this is only used with chaps, which |
300 // we also control. | 320 // we also control. |
301 PK11SlotInfo* GetTPMSlotForId(CK_SLOT_ID slot_id) { | 321 PK11SlotInfo* GetTPMSlotForId(CK_SLOT_ID slot_id) { |
322 DCHECK(CalledOnValidThread()); | |
323 | |
302 if (!chaps_module_) | 324 if (!chaps_module_) |
303 return NULL; | 325 return NULL; |
304 | 326 |
305 VLOG(1) << "Poking chaps module."; | 327 VLOG(1) << "Poking chaps module."; |
306 SECStatus rv = SECMOD_UpdateSlotList(chaps_module_); | 328 SECStatus rv = SECMOD_UpdateSlotList(chaps_module_); |
307 if (rv != SECSuccess) | 329 if (rv != SECSuccess) |
308 PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError(); | 330 PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError(); |
309 | 331 |
310 PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module_->moduleID, slot_id); | 332 PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module_->moduleID, slot_id); |
311 if (!slot) | 333 if (!slot) |
312 LOG(ERROR) << "TPM slot " << slot_id << " not found."; | 334 LOG(ERROR) << "TPM slot " << slot_id << " not found."; |
313 return slot; | 335 return slot; |
314 } | 336 } |
315 #endif // defined(OS_CHROMEOS) | 337 #endif // defined(OS_CHROMEOS) |
316 | 338 |
317 | 339 |
318 bool OpenTestNSSDB() { | 340 bool OpenTestNSSDB() { |
341 DCHECK(CalledOnValidThread()); | |
342 | |
319 if (test_slot_) | 343 if (test_slot_) |
320 return true; | 344 return true; |
321 if (!g_test_nss_db_dir.Get().CreateUniqueTempDir()) | 345 if (!g_test_nss_db_dir.Get().CreateUniqueTempDir()) |
322 return false; | 346 return false; |
323 test_slot_ = OpenUserDB(g_test_nss_db_dir.Get().path(), kTestTPMTokenName); | 347 test_slot_ = OpenUserDB(g_test_nss_db_dir.Get().path(), kTestTPMTokenName); |
324 return !!test_slot_; | 348 return !!test_slot_; |
325 } | 349 } |
326 | 350 |
327 void CloseTestNSSDB() { | 351 void CloseTestNSSDB() { |
352 DCHECK(CalledOnValidThread()); | |
353 | |
328 if (!test_slot_) | 354 if (!test_slot_) |
329 return; | 355 return; |
330 SECStatus status = SECMOD_CloseUserDB(test_slot_); | 356 SECStatus status = SECMOD_CloseUserDB(test_slot_); |
331 if (status != SECSuccess) | 357 if (status != SECSuccess) |
332 PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); | 358 PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); |
333 PK11_FreeSlot(test_slot_); | 359 PK11_FreeSlot(test_slot_); |
334 test_slot_ = NULL; | 360 test_slot_ = NULL; |
335 ignore_result(g_test_nss_db_dir.Get().Delete()); | 361 ignore_result(g_test_nss_db_dir.Get().Delete()); |
336 } | 362 } |
337 | 363 |
338 PK11SlotInfo* GetPublicNSSKeySlot() { | 364 PK11SlotInfo* GetPublicNSSKeySlot() { |
365 // TODO(mattm): Change to DCHECK when callers have been fixed. | |
366 if (!CalledOnValidThread()) { | |
367 DVLOG(1) << "Called on wrong thread.\n" | |
368 << base::debug::StackTrace().ToString(); | |
369 } | |
370 | |
339 if (test_slot_) | 371 if (test_slot_) |
340 return PK11_ReferenceSlot(test_slot_); | 372 return PK11_ReferenceSlot(test_slot_); |
341 if (software_slot_) | 373 if (software_slot_) |
342 return PK11_ReferenceSlot(software_slot_); | 374 return PK11_ReferenceSlot(software_slot_); |
343 return PK11_GetInternalKeySlot(); | 375 return PK11_GetInternalKeySlot(); |
344 } | 376 } |
345 | 377 |
346 PK11SlotInfo* GetPrivateNSSKeySlot() { | 378 PK11SlotInfo* GetPrivateNSSKeySlot() { |
379 // TODO(mattm): Change to DCHECK when callers have been fixed. | |
380 if (!CalledOnValidThread()) { | |
381 DVLOG(1) << "Called on wrong thread.\n" | |
382 << base::debug::StackTrace().ToString(); | |
383 } | |
384 | |
347 if (test_slot_) | 385 if (test_slot_) |
348 return PK11_ReferenceSlot(test_slot_); | 386 return PK11_ReferenceSlot(test_slot_); |
349 | 387 |
350 #if defined(OS_CHROMEOS) | 388 #if defined(OS_CHROMEOS) |
351 if (tpm_token_enabled_for_nss_) { | 389 if (tpm_token_enabled_for_nss_) { |
352 if (IsTPMTokenReady()) { | 390 if (IsTPMTokenReady()) { |
353 return PK11_ReferenceSlot(tpm_slot_); | 391 return PK11_ReferenceSlot(tpm_slot_); |
354 } else { | 392 } else { |
355 // If we were supposed to get the hardware token, but were | 393 // If we were supposed to get the hardware token, but were |
356 // unable to, return NULL rather than fall back to sofware. | 394 // unable to, return NULL rather than fall back to sofware. |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
480 NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, | 518 NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, |
481 0, NSS_USE_ALG_IN_CERT_SIGNATURE); | 519 0, NSS_USE_ALG_IN_CERT_SIGNATURE); |
482 | 520 |
483 // The UMA bit is conditionally set for this histogram in | 521 // The UMA bit is conditionally set for this histogram in |
484 // chrome/common/startup_metric_utils.cc . | 522 // chrome/common/startup_metric_utils.cc . |
485 HISTOGRAM_CUSTOM_TIMES("Startup.SlowStartupNSSInit", | 523 HISTOGRAM_CUSTOM_TIMES("Startup.SlowStartupNSSInit", |
486 base::TimeTicks::Now() - start_time, | 524 base::TimeTicks::Now() - start_time, |
487 base::TimeDelta::FromMilliseconds(10), | 525 base::TimeDelta::FromMilliseconds(10), |
488 base::TimeDelta::FromHours(1), | 526 base::TimeDelta::FromHours(1), |
489 50); | 527 50); |
528 | |
529 // It's safe to construct on any thread, since LazyInstance will prevent any | |
530 // other threads from accessing until the constructor is done. | |
531 DetachFromThread(); | |
wtc
2013/11/11 22:10:15
If this can be called at the beginning of this fun
mattm
2013/11/12 00:41:34
Done.
| |
490 } | 532 } |
491 | 533 |
492 // NOTE(willchan): We don't actually execute this code since we leak NSS to | 534 // NOTE(willchan): We don't actually execute this code since we leak NSS to |
493 // prevent non-joinable threads from using NSS after it's already been shut | 535 // prevent non-joinable threads from using NSS after it's already been shut |
494 // down. | 536 // down. |
495 ~NSSInitSingleton() { | 537 ~NSSInitSingleton() { |
496 if (tpm_slot_) { | 538 if (tpm_slot_) { |
497 PK11_FreeSlot(tpm_slot_); | 539 PK11_FreeSlot(tpm_slot_); |
498 tpm_slot_ = NULL; | 540 tpm_slot_ = NULL; |
499 } | 541 } |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
781 | 823 |
782 PK11SlotInfo* GetPublicNSSKeySlot() { | 824 PK11SlotInfo* GetPublicNSSKeySlot() { |
783 return g_nss_singleton.Get().GetPublicNSSKeySlot(); | 825 return g_nss_singleton.Get().GetPublicNSSKeySlot(); |
784 } | 826 } |
785 | 827 |
786 PK11SlotInfo* GetPrivateNSSKeySlot() { | 828 PK11SlotInfo* GetPrivateNSSKeySlot() { |
787 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); | 829 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); |
788 } | 830 } |
789 | 831 |
790 } // namespace crypto | 832 } // namespace crypto |
OLD | NEW |