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 <plarena.h> | 9 #include <plarena.h> |
10 #include <prerror.h> | 10 #include <prerror.h> |
11 #include <prinit.h> | 11 #include <prinit.h> |
12 #include <prtime.h> | 12 #include <prtime.h> |
13 #include <pk11pub.h> | 13 #include <pk11pub.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/bind.h" | |
27 #include "base/environment.h" | 26 #include "base/environment.h" |
28 #include "base/file_path.h" | 27 #include "base/file_path.h" |
29 #include "base/file_util.h" | 28 #include "base/file_util.h" |
30 #include "base/lazy_instance.h" | 29 #include "base/lazy_instance.h" |
31 #include "base/logging.h" | 30 #include "base/logging.h" |
32 #include "base/memory/scoped_ptr.h" | 31 #include "base/memory/scoped_ptr.h" |
33 #include "base/message_loop.h" | |
34 #include "base/native_library.h" | 32 #include "base/native_library.h" |
35 #include "base/scoped_temp_dir.h" | 33 #include "base/scoped_temp_dir.h" |
36 #include "base/stringprintf.h" | 34 #include "base/stringprintf.h" |
37 #include "base/threading/thread_restrictions.h" | 35 #include "base/threading/thread_restrictions.h" |
38 #include "build/build_config.h" | 36 #include "build/build_config.h" |
39 #include "crypto/scoped_nss_types.h" | |
40 | 37 |
41 #if defined(OS_CHROMEOS) | 38 #if defined(OS_CHROMEOS) |
42 #include "crypto/symmetric_key.h" | 39 #include "crypto/symmetric_key.h" |
43 #endif | 40 #endif |
44 | 41 |
45 // 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 |
46 // 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 |
47 // 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 |
48 // certificate and key databases. | 45 // certificate and key databases. |
49 #if defined(USE_NSS) | 46 #if defined(USE_NSS) |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
240 | 237 |
241 // This creates another DB slot in NSS that is read/write, unlike | 238 // This creates another DB slot in NSS that is read/write, unlike |
242 // the fake root CA cert DB and the "default" crypto key | 239 // the fake root CA cert DB and the "default" crypto key |
243 // provider, which are still read-only (because we initialized | 240 // provider, which are still read-only (because we initialized |
244 // NSS before we had a cryptohome mounted). | 241 // NSS before we had a cryptohome mounted). |
245 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), | 242 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), |
246 kNSSDatabaseName); | 243 kNSSDatabaseName); |
247 } | 244 } |
248 } | 245 } |
249 | 246 |
250 void EnableTPMTokenForNSS(TPMTokenInfoDelegate* info_delegate) { | 247 void EnableTPMTokenForNSS() { |
251 CHECK(info_delegate); | 248 tpm_token_enabled_for_nss_ = true; |
252 tpm_token_info_delegate_.reset(info_delegate); | |
253 } | 249 } |
254 | 250 |
255 void InitializeTPMToken(InitializeTPMTokenCallback callback) { | 251 bool InitializeTPMToken(const std::string& token_name, |
256 // If EnableTPMTokenForNSS hasn't been called, run |callback| with false. | 252 const std::string& user_pin) { |
257 if (tpm_token_info_delegate_.get() == NULL) { | 253 // If EnableTPMTokenForNSS hasn't been called, return false. |
258 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, false)); | 254 if (!tpm_token_enabled_for_nss_) { |
259 return; | 255 return false; |
260 } | 256 } |
Ryan Sleevi
2012/05/16 17:02:16
nit: Remove the { } for the one-line conditionals
hashimoto
2012/05/17 07:35:07
Done.
| |
261 | 257 |
262 // If everything is already initialized, then run |callback| with true. | 258 // If everything is already initialized, then return true. |
263 if (chaps_module_ && tpm_slot_) { | 259 if (chaps_module_ && tpm_slot_) { |
264 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true)); | 260 return true; |
265 return; | |
266 } | 261 } |
267 tpm_token_info_delegate_->RequestIsTokenReady( | 262 |
268 base::Bind(&NSSInitSingleton::InitializeTPMTokenInternal, | 263 tpm_token_name_ = token_name; |
269 weak_ptr_factory_.GetWeakPtr(), | 264 tpm_user_pin_ = user_pin; |
270 callback)); | 265 |
266 // This tries to load the Chaps module so NSS can talk to the hardware | |
267 // TPM. | |
268 if (!chaps_module_) { | |
269 chaps_module_ = LoadModule( | |
270 kChapsModuleName, | |
271 kChapsPath, | |
272 // For more details on these parameters, see: | |
273 // https://developer.mozilla.org/en/PKCS11_Module_Specs | |
274 // slotFlags=[PublicCerts] -- Certificates and public keys can be | |
275 // read from this slot without requiring a call to C_Login. | |
276 // askpw=only -- Only authenticate to the token when necessary. | |
277 "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\""); | |
278 } | |
279 if (chaps_module_){ | |
280 // If this gets set, then we'll use the TPM for certs with | |
281 // private keys, otherwise we'll fall back to the software | |
282 // implementation. | |
283 tpm_slot_ = GetTPMSlot(); | |
284 | |
285 return tpm_slot_ != NULL; | |
286 } | |
287 return false; | |
271 } | 288 } |
272 | 289 |
273 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { | 290 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { |
274 if (tpm_token_info_delegate_.get() == NULL) { | 291 if (!tpm_token_enabled_for_nss_) { |
275 LOG(ERROR) << "GetTPMTokenInfo called before TPM Token is ready."; | 292 LOG(ERROR) << "GetTPMTokenInfo called before TPM Token is ready."; |
276 return; | 293 return; |
277 } | 294 } |
278 tpm_token_info_delegate_->GetTokenInfo(token_name, user_pin); | 295 if (token_name) |
296 *token_name = tpm_token_name_; | |
297 if (user_pin) | |
298 *user_pin = tpm_user_pin_; | |
279 } | 299 } |
280 | 300 |
281 bool IsTPMTokenReady() { | 301 bool IsTPMTokenReady() { |
282 return tpm_slot_ != NULL; | 302 return tpm_slot_ != NULL; |
283 } | 303 } |
284 | 304 |
285 PK11SlotInfo* GetTPMSlot() { | 305 PK11SlotInfo* GetTPMSlot() { |
286 std::string token_name; | 306 std::string token_name; |
287 GetTPMTokenInfo(&token_name, NULL); | 307 GetTPMTokenInfo(&token_name, NULL); |
288 return FindSlotWithTokenName(token_name); | 308 return FindSlotWithTokenName(token_name); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
351 if (software_slot_) | 371 if (software_slot_) |
352 return PK11_ReferenceSlot(software_slot_); | 372 return PK11_ReferenceSlot(software_slot_); |
353 return PK11_GetInternalKeySlot(); | 373 return PK11_GetInternalKeySlot(); |
354 } | 374 } |
355 | 375 |
356 PK11SlotInfo* GetPrivateNSSKeySlot() { | 376 PK11SlotInfo* GetPrivateNSSKeySlot() { |
357 if (test_slot_) | 377 if (test_slot_) |
358 return PK11_ReferenceSlot(test_slot_); | 378 return PK11_ReferenceSlot(test_slot_); |
359 | 379 |
360 #if defined(OS_CHROMEOS) | 380 #if defined(OS_CHROMEOS) |
361 if (tpm_token_info_delegate_.get() != NULL) { | 381 if (!tpm_token_enabled_for_nss_) { |
Ryan Sleevi
2012/05/16 17:02:16
Note: This is still thread-racey.
EnableTPMTokenF
hashimoto
2012/05/17 07:35:07
Now EnableTPMTokenForNSS is called only on UI thre
Ryan Sleevi
2012/05/17 17:09:45
I would prefer it only be called on the I/O thread
| |
362 if (IsTPMTokenReady()) { | 382 if (IsTPMTokenReady()) { |
363 return PK11_ReferenceSlot(tpm_slot_); | 383 return PK11_ReferenceSlot(tpm_slot_); |
364 } else { | 384 } else { |
365 // If we were supposed to get the hardware token, but were | 385 // If we were supposed to get the hardware token, but were |
366 // unable to, return NULL rather than fall back to sofware. | 386 // unable to, return NULL rather than fall back to sofware. |
367 return NULL; | 387 return NULL; |
368 } | 388 } |
369 } | 389 } |
370 #endif | 390 #endif |
371 // If we weren't supposed to enable the TPM for NSS, then return | 391 // If we weren't supposed to enable the TPM for NSS, then return |
(...skipping 12 matching lines...) Expand all Loading... | |
384 // This method is used to force NSS to be initialized without a DB. | 404 // This method is used to force NSS to be initialized without a DB. |
385 // Call this method before NSSInitSingleton() is constructed. | 405 // Call this method before NSSInitSingleton() is constructed. |
386 static void ForceNoDBInit() { | 406 static void ForceNoDBInit() { |
387 force_nodb_init_ = true; | 407 force_nodb_init_ = true; |
388 } | 408 } |
389 | 409 |
390 private: | 410 private: |
391 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>; | 411 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>; |
392 | 412 |
393 NSSInitSingleton() | 413 NSSInitSingleton() |
394 : chaps_module_(NULL), | 414 : tpm_token_enabled_for_nss_(false), |
415 chaps_module_(NULL), | |
395 software_slot_(NULL), | 416 software_slot_(NULL), |
396 test_slot_(NULL), | 417 test_slot_(NULL), |
397 tpm_slot_(NULL), | 418 tpm_slot_(NULL), |
398 root_(NULL), | 419 root_(NULL), |
399 chromeos_user_logged_in_(false), | 420 chromeos_user_logged_in_(false) { |
400 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | |
401 EnsureNSPRInit(); | 421 EnsureNSPRInit(); |
402 | 422 |
403 // We *must* have NSS >= 3.12.3. See bug 26448. | 423 // We *must* have NSS >= 3.12.3. See bug 26448. |
404 COMPILE_ASSERT( | 424 COMPILE_ASSERT( |
405 (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 3) || | 425 (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 3) || |
406 (NSS_VMAJOR == 3 && NSS_VMINOR > 12) || | 426 (NSS_VMAJOR == 3 && NSS_VMINOR > 12) || |
407 (NSS_VMAJOR > 3), | 427 (NSS_VMAJOR > 3), |
408 nss_version_check_failed); | 428 nss_version_check_failed); |
409 // Also check the run-time NSS version. | 429 // Also check the run-time NSS version. |
410 // NSS_VersionCheck is a >= check, not strict equality. | 430 // NSS_VersionCheck is a >= check, not strict equality. |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
514 } | 534 } |
515 | 535 |
516 SECStatus status = NSS_Shutdown(); | 536 SECStatus status = NSS_Shutdown(); |
517 if (status != SECSuccess) { | 537 if (status != SECSuccess) { |
518 // We VLOG(1) because this failure is relatively harmless (leaking, but | 538 // We VLOG(1) because this failure is relatively harmless (leaking, but |
519 // we're shutting down anyway). | 539 // we're shutting down anyway). |
520 VLOG(1) << "NSS_Shutdown failed; see http://crbug.com/4609"; | 540 VLOG(1) << "NSS_Shutdown failed; see http://crbug.com/4609"; |
521 } | 541 } |
522 } | 542 } |
523 | 543 |
524 #if defined(OS_CHROMEOS) | |
525 // This method is used to implement InitializeTPMToken. | |
526 void InitializeTPMTokenInternal(InitializeTPMTokenCallback callback, | |
527 bool is_token_ready) { | |
528 if (is_token_ready) { | |
529 // This tries to load the Chaps module so NSS can talk to the hardware | |
530 // TPM. | |
531 if (!chaps_module_) { | |
532 chaps_module_ = LoadModule( | |
533 kChapsModuleName, | |
534 kChapsPath, | |
535 // For more details on these parameters, see: | |
536 // https://developer.mozilla.org/en/PKCS11_Module_Specs | |
537 // slotFlags=[PublicCerts] -- Certificates and public keys can be | |
538 // read from this slot without requiring a call to C_Login. | |
539 // askpw=only -- Only authenticate to the token when necessary. | |
540 "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\""); | |
541 } | |
542 if (chaps_module_) { | |
543 // If this gets set, then we'll use the TPM for certs with | |
544 // private keys, otherwise we'll fall back to the software | |
545 // implementation. | |
546 tpm_slot_ = GetTPMSlot(); | |
547 | |
548 callback.Run(tpm_slot_ != NULL); | |
549 return; | |
550 } | |
551 } | |
552 callback.Run(false); | |
553 } | |
554 #endif // defined(OS_CHROMEOS) | |
555 | |
556 #if defined(USE_NSS) | 544 #if defined(USE_NSS) |
557 // Load nss's built-in root certs. | 545 // Load nss's built-in root certs. |
558 SECMODModule* InitDefaultRootCerts() { | 546 SECMODModule* InitDefaultRootCerts() { |
559 SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", NULL); | 547 SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", NULL); |
560 if (root) | 548 if (root) |
561 return root; | 549 return root; |
562 | 550 |
563 // Aw, snap. Can't find/load root cert shared library. | 551 // Aw, snap. Can't find/load root cert shared library. |
564 // This will make it hard to talk to anybody via https. | 552 // This will make it hard to talk to anybody via https. |
565 NOTREACHED(); | 553 NOTREACHED(); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
602 else { | 590 else { |
603 LOG(ERROR) << "Error opening persistent database (" << modspec | 591 LOG(ERROR) << "Error opening persistent database (" << modspec |
604 << "): " << GetNSSErrorMessage(); | 592 << "): " << GetNSSErrorMessage(); |
605 } | 593 } |
606 return db_slot; | 594 return db_slot; |
607 } | 595 } |
608 | 596 |
609 // If this is set to true NSS is forced to be initialized without a DB. | 597 // If this is set to true NSS is forced to be initialized without a DB. |
610 static bool force_nodb_init_; | 598 static bool force_nodb_init_; |
611 | 599 |
612 #if defined(OS_CHROMEOS) | 600 bool tpm_token_enabled_for_nss_; |
613 scoped_ptr<TPMTokenInfoDelegate> tpm_token_info_delegate_; | 601 std::string tpm_token_name_; |
614 #endif | 602 std::string tpm_user_pin_; |
615 | |
616 SECMODModule* chaps_module_; | 603 SECMODModule* chaps_module_; |
617 PK11SlotInfo* software_slot_; | 604 PK11SlotInfo* software_slot_; |
618 PK11SlotInfo* test_slot_; | 605 PK11SlotInfo* test_slot_; |
619 PK11SlotInfo* tpm_slot_; | 606 PK11SlotInfo* tpm_slot_; |
620 SECMODModule* root_; | 607 SECMODModule* root_; |
621 bool chromeos_user_logged_in_; | 608 bool chromeos_user_logged_in_; |
622 base::WeakPtrFactory<NSSInitSingleton> weak_ptr_factory_; | |
623 #if defined(USE_NSS) | 609 #if defined(USE_NSS) |
624 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 | 610 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 |
625 // is fixed, we will no longer need the lock. | 611 // is fixed, we will no longer need the lock. |
626 base::Lock write_lock_; | 612 base::Lock write_lock_; |
627 #endif // defined(USE_NSS) | 613 #endif // defined(USE_NSS) |
628 }; | 614 }; |
629 | 615 |
630 // static | 616 // static |
631 bool NSSInitSingleton::force_nodb_init_ = false; | 617 bool NSSInitSingleton::force_nodb_init_ = false; |
632 | 618 |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
746 SECMOD_ReleaseReadLock(lock_); | 732 SECMOD_ReleaseReadLock(lock_); |
747 } | 733 } |
748 | 734 |
749 #endif // defined(USE_NSS) | 735 #endif // defined(USE_NSS) |
750 | 736 |
751 #if defined(OS_CHROMEOS) | 737 #if defined(OS_CHROMEOS) |
752 void OpenPersistentNSSDB() { | 738 void OpenPersistentNSSDB() { |
753 g_nss_singleton.Get().OpenPersistentNSSDB(); | 739 g_nss_singleton.Get().OpenPersistentNSSDB(); |
754 } | 740 } |
755 | 741 |
756 TPMTokenInfoDelegate::TPMTokenInfoDelegate() {} | 742 void EnableTPMTokenForNSS() { |
757 TPMTokenInfoDelegate::~TPMTokenInfoDelegate() {} | 743 g_nss_singleton.Get().EnableTPMTokenForNSS(); |
758 | |
759 void EnableTPMTokenForNSS(TPMTokenInfoDelegate* info_delegate) { | |
760 g_nss_singleton.Get().EnableTPMTokenForNSS(info_delegate); | |
761 } | 744 } |
762 | 745 |
763 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { | 746 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { |
764 g_nss_singleton.Get().GetTPMTokenInfo(token_name, user_pin); | 747 g_nss_singleton.Get().GetTPMTokenInfo(token_name, user_pin); |
765 } | 748 } |
766 | 749 |
767 bool IsTPMTokenReady() { | 750 bool IsTPMTokenReady() { |
768 return g_nss_singleton.Get().IsTPMTokenReady(); | 751 return g_nss_singleton.Get().IsTPMTokenReady(); |
769 } | 752 } |
770 | 753 |
771 void InitializeTPMToken(InitializeTPMTokenCallback callback) { | 754 bool InitializeTPMToken(const std::string& token_name, |
772 g_nss_singleton.Get().InitializeTPMToken(callback); | 755 const std::string& user_pin) { |
756 return g_nss_singleton.Get().InitializeTPMToken(token_name, user_pin); | |
773 } | 757 } |
774 | 758 |
775 SymmetricKey* GetSupplementalUserKey() { | 759 SymmetricKey* GetSupplementalUserKey() { |
776 return g_nss_singleton.Get().GetSupplementalUserKey(); | 760 return g_nss_singleton.Get().GetSupplementalUserKey(); |
777 } | 761 } |
778 #endif // defined(OS_CHROMEOS) | 762 #endif // defined(OS_CHROMEOS) |
779 | 763 |
780 base::Time PRTimeToBaseTime(PRTime prtime) { | 764 base::Time PRTimeToBaseTime(PRTime prtime) { |
781 return base::Time::FromInternalValue( | 765 return base::Time::FromInternalValue( |
782 prtime + base::Time::UnixEpoch().ToInternalValue()); | 766 prtime + base::Time::UnixEpoch().ToInternalValue()); |
783 } | 767 } |
784 | 768 |
785 PRTime BaseTimeToPRTime(base::Time time) { | 769 PRTime BaseTimeToPRTime(base::Time time) { |
786 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); | 770 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); |
787 } | 771 } |
788 | 772 |
789 PK11SlotInfo* GetPublicNSSKeySlot() { | 773 PK11SlotInfo* GetPublicNSSKeySlot() { |
790 return g_nss_singleton.Get().GetPublicNSSKeySlot(); | 774 return g_nss_singleton.Get().GetPublicNSSKeySlot(); |
791 } | 775 } |
792 | 776 |
793 PK11SlotInfo* GetPrivateNSSKeySlot() { | 777 PK11SlotInfo* GetPrivateNSSKeySlot() { |
794 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); | 778 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); |
795 } | 779 } |
796 | 780 |
797 } // namespace crypto | 781 } // namespace crypto |
OLD | NEW |