| 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/callback.h" |
| 26 #include "base/debug/alias.h" | 27 #include "base/debug/alias.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" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 base::FilePath dir = file_util::GetHomeDir(); | 80 base::FilePath dir = file_util::GetHomeDir(); |
| 80 if (dir.empty()) { | 81 if (dir.empty()) { |
| 81 LOG(ERROR) << "Failed to get home directory."; | 82 LOG(ERROR) << "Failed to get home directory."; |
| 82 return dir; | 83 return dir; |
| 83 } | 84 } |
| 84 dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); | 85 dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); |
| 85 if (!file_util::CreateDirectory(dir)) { | 86 if (!file_util::CreateDirectory(dir)) { |
| 86 LOG(ERROR) << "Failed to create " << dir.value() << " directory."; | 87 LOG(ERROR) << "Failed to create " << dir.value() << " directory."; |
| 87 dir.clear(); | 88 dir.clear(); |
| 88 } | 89 } |
| 90 LOG(WARNING) << "GetDefaultConfigDirectory: " << dir.value(); |
| 89 return dir; | 91 return dir; |
| 90 } | 92 } |
| 91 | 93 |
| 92 // On non-Chrome OS platforms, return the default config directory. On Chrome OS | 94 // On non-Chrome OS platforms, return the default config directory. On Chrome OS |
| 93 // test images, return a read-only directory with fake root CA certs (which are | 95 // test images, return a read-only directory with fake root CA certs (which are |
| 94 // used by the local Google Accounts server mock we use when testing our login | 96 // used by the local Google Accounts server mock we use when testing our login |
| 95 // code). On Chrome OS non-test images (where the read-only directory doesn't | 97 // code). On Chrome OS non-test images (where the read-only directory doesn't |
| 96 // exist), return an empty path. | 98 // exist), return an empty path. |
| 97 base::FilePath GetInitialConfigDirectory() { | 99 base::FilePath GetInitialConfigDirectory() { |
| 98 #if defined(OS_CHROMEOS) | 100 #if defined(OS_CHROMEOS) |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 | 241 |
| 240 // This creates another DB slot in NSS that is read/write, unlike | 242 // This creates another DB slot in NSS that is read/write, unlike |
| 241 // the fake root CA cert DB and the "default" crypto key | 243 // the fake root CA cert DB and the "default" crypto key |
| 242 // provider, which are still read-only (because we initialized | 244 // provider, which are still read-only (because we initialized |
| 243 // NSS before we had a cryptohome mounted). | 245 // NSS before we had a cryptohome mounted). |
| 244 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), | 246 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), |
| 245 kNSSDatabaseName); | 247 kNSSDatabaseName); |
| 246 } | 248 } |
| 247 } | 249 } |
| 248 | 250 |
| 251 PK11SlotInfo* OpenPersistentNSSDBForPath(const base::FilePath& path) { |
| 252 LOG(WARNING) << __func__ << " " << path.AsUTF8Unsafe(); |
| 253 // We do NSS file io on the IO thread. |
| 254 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 255 |
| 256 if (force_nodb_init_) { |
| 257 // XXX probably unneccessary |
| 258 LOG(WARNING) << "force_nodb_init_, returning NULL"; |
| 259 return NULL; |
| 260 } |
| 261 base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb"); |
| 262 // XXX shoud we be doing this? |
| 263 if (!file_util::CreateDirectory(nssdb_path)) { |
| 264 LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory."; |
| 265 return NULL; |
| 266 } |
| 267 return OpenUserDB(nssdb_path, kNSSDatabaseName); |
| 268 } |
| 269 |
| 249 void EnableTPMTokenForNSS() { | 270 void EnableTPMTokenForNSS() { |
| 271 // If this gets set, then we'll use the TPM for certs with |
| 272 // private keys, otherwise we'll fall back to the software |
| 273 // implementation. |
| 250 tpm_token_enabled_for_nss_ = true; | 274 tpm_token_enabled_for_nss_ = true; |
| 251 } | 275 } |
| 252 | 276 |
| 277 bool IsTPMTokenEnabledForNSS() { |
| 278 return tpm_token_enabled_for_nss_; |
| 279 } |
| 280 |
| 253 bool InitializeTPMToken(const std::string& token_name, | 281 bool InitializeTPMToken(const std::string& token_name, |
| 254 const std::string& user_pin) { | 282 const std::string& user_pin, |
| 283 int token_slot_id) { |
| 255 // If EnableTPMTokenForNSS hasn't been called, return false. | 284 // If EnableTPMTokenForNSS hasn't been called, return false. |
| 256 if (!tpm_token_enabled_for_nss_) | 285 if (!tpm_token_enabled_for_nss_) |
| 257 return false; | 286 return false; |
| 258 | 287 |
| 259 // If everything is already initialized, then return true. | 288 // If everything is already initialized, then return true. |
| 260 if (chaps_module_ && tpm_slot_) | 289 if (chaps_module_ && tpm_slot_) |
| 261 return true; | 290 return true; |
| 262 | 291 |
| 263 tpm_token_name_ = token_name; | 292 tpm_token_name_ = token_name; |
| 264 tpm_user_pin_ = user_pin; | 293 tpm_user_pin_ = user_pin; |
| 265 | 294 |
| 266 // This tries to load the Chaps module so NSS can talk to the hardware | 295 // This tries to load the Chaps module so NSS can talk to the hardware |
| 267 // TPM. | 296 // TPM. |
| 268 if (!chaps_module_) { | 297 if (!chaps_module_) { |
| 269 chaps_module_ = LoadModule( | 298 chaps_module_ = LoadModule( |
| 270 kChapsModuleName, | 299 kChapsModuleName, |
| 271 kChapsPath, | 300 kChapsPath, |
| 272 // For more details on these parameters, see: | 301 // For more details on these parameters, see: |
| 273 // https://developer.mozilla.org/en/PKCS11_Module_Specs | 302 // https://developer.mozilla.org/en/PKCS11_Module_Specs |
| 274 // slotFlags=[PublicCerts] -- Certificates and public keys can be | 303 // slotFlags=[PublicCerts] -- Certificates and public keys can be |
| 275 // read from this slot without requiring a call to C_Login. | 304 // read from this slot without requiring a call to C_Login. |
| 276 // askpw=only -- Only authenticate to the token when necessary. | 305 // askpw=only -- Only authenticate to the token when necessary. |
| 277 "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\""); | 306 "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\""); |
| 278 } | 307 } |
| 279 if (chaps_module_){ | 308 if (chaps_module_){ |
| 280 // If this gets set, then we'll use the TPM for certs with | 309 tpm_slot_ = GetTPMSlotForId(token_slot_id); |
| 281 // private keys, otherwise we'll fall back to the software | 310 |
| 282 // implementation. | 311 if (tpm_slot_) { |
| 283 tpm_slot_ = GetTPMSlot(); | 312 for (std::vector<base::Closure>::iterator i = |
| 313 tpm_ready_callback_list_.begin(); |
| 314 i != tpm_ready_callback_list_.end(); |
| 315 ++i) { |
| 316 (*i).Run(); |
| 317 } |
| 318 tpm_ready_callback_list_.clear(); |
| 319 } |
| 284 | 320 |
| 285 return tpm_slot_ != NULL; | 321 return tpm_slot_ != NULL; |
| 286 } | 322 } |
| 287 return false; | 323 return false; |
| 288 } | 324 } |
| 289 | 325 |
| 290 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { | 326 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { |
| 291 if (!tpm_token_enabled_for_nss_) { | 327 if (!tpm_token_enabled_for_nss_) { |
| 292 LOG(ERROR) << "GetTPMTokenInfo called before TPM Token is ready."; | 328 LOG(ERROR) << "GetTPMTokenInfo called before TPM Token is ready."; |
| 293 return; | 329 return; |
| 294 } | 330 } |
| 295 if (token_name) | 331 if (token_name) |
| 296 *token_name = tpm_token_name_; | 332 *token_name = tpm_token_name_; |
| 297 if (user_pin) | 333 if (user_pin) |
| 298 *user_pin = tpm_user_pin_; | 334 *user_pin = tpm_user_pin_; |
| 299 } | 335 } |
| 300 | 336 |
| 301 bool IsTPMTokenReady() { | 337 bool IsTPMTokenReady() { |
| 302 return tpm_slot_ != NULL; | 338 return tpm_slot_ != NULL; |
| 303 } | 339 } |
| 304 | 340 |
| 305 PK11SlotInfo* GetTPMSlot() { | 341 void OnTPMReady(const base::Closure& callback) { |
| 306 std::string token_name; | 342 if (IsTPMTokenReady()) |
| 307 GetTPMTokenInfo(&token_name, NULL); | 343 callback.Run(); |
| 308 return FindSlotWithTokenName(token_name); | 344 else |
| 345 tpm_ready_callback_list_.push_back(callback); |
| 346 } |
| 347 |
| 348 PK11SlotInfo* GetTPMSlotForId(CK_SLOT_ID slot_id) { |
| 349 if (!chaps_module_) |
| 350 return NULL; |
| 351 |
| 352 VLOG(1) << "Poking chaps module."; |
| 353 SECStatus rv = SECMOD_UpdateSlotList(chaps_module_); |
| 354 if (rv != SECSuccess) |
| 355 PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError(); |
| 356 |
| 357 PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module_->moduleID, slot_id); |
| 358 if (!slot) |
| 359 LOG(ERROR) << "TPM slot " << slot_id << " not found."; |
| 360 return slot; |
| 309 } | 361 } |
| 310 #endif // defined(OS_CHROMEOS) | 362 #endif // defined(OS_CHROMEOS) |
| 311 | 363 |
| 312 | 364 |
| 313 bool OpenTestNSSDB() { | 365 bool OpenTestNSSDB() { |
| 314 if (test_slot_) | 366 if (test_slot_) |
| 315 return true; | 367 return true; |
| 316 if (!g_test_nss_db_dir.Get().CreateUniqueTempDir()) | 368 if (!g_test_nss_db_dir.Get().CreateUniqueTempDir()) |
| 317 return false; | 369 return false; |
| 318 test_slot_ = OpenUserDB(g_test_nss_db_dir.Get().path(), kTestTPMTokenName); | 370 test_slot_ = OpenUserDB(g_test_nss_db_dir.Get().path(), kTestTPMTokenName); |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 569 } | 621 } |
| 570 return db_slot; | 622 return db_slot; |
| 571 } | 623 } |
| 572 | 624 |
| 573 // If this is set to true NSS is forced to be initialized without a DB. | 625 // If this is set to true NSS is forced to be initialized without a DB. |
| 574 static bool force_nodb_init_; | 626 static bool force_nodb_init_; |
| 575 | 627 |
| 576 bool tpm_token_enabled_for_nss_; | 628 bool tpm_token_enabled_for_nss_; |
| 577 std::string tpm_token_name_; | 629 std::string tpm_token_name_; |
| 578 std::string tpm_user_pin_; | 630 std::string tpm_user_pin_; |
| 631 std::vector<base::Closure> tpm_ready_callback_list_; |
| 579 SECMODModule* chaps_module_; | 632 SECMODModule* chaps_module_; |
| 580 PK11SlotInfo* software_slot_; | 633 PK11SlotInfo* software_slot_; |
| 581 PK11SlotInfo* test_slot_; | 634 PK11SlotInfo* test_slot_; |
| 582 PK11SlotInfo* tpm_slot_; | 635 PK11SlotInfo* tpm_slot_; |
| 583 SECMODModule* root_; | 636 SECMODModule* root_; |
| 584 bool chromeos_user_logged_in_; | 637 bool chromeos_user_logged_in_; |
| 585 #if defined(USE_NSS) | 638 #if defined(USE_NSS) |
| 586 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 | 639 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 |
| 587 // is fixed, we will no longer need the lock. | 640 // is fixed, we will no longer need the lock. |
| 588 base::Lock write_lock_; | 641 base::Lock write_lock_; |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 736 | 789 |
| 737 #if defined(OS_CHROMEOS) | 790 #if defined(OS_CHROMEOS) |
| 738 void OpenPersistentNSSDB() { | 791 void OpenPersistentNSSDB() { |
| 739 g_nss_singleton.Get().OpenPersistentNSSDB(); | 792 g_nss_singleton.Get().OpenPersistentNSSDB(); |
| 740 } | 793 } |
| 741 | 794 |
| 742 void EnableTPMTokenForNSS() { | 795 void EnableTPMTokenForNSS() { |
| 743 g_nss_singleton.Get().EnableTPMTokenForNSS(); | 796 g_nss_singleton.Get().EnableTPMTokenForNSS(); |
| 744 } | 797 } |
| 745 | 798 |
| 799 bool IsTPMTokenEnabledForNSS() { |
| 800 return g_nss_singleton.Get().IsTPMTokenEnabledForNSS(); |
| 801 } |
| 802 |
| 746 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { | 803 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { |
| 747 g_nss_singleton.Get().GetTPMTokenInfo(token_name, user_pin); | 804 g_nss_singleton.Get().GetTPMTokenInfo(token_name, user_pin); |
| 748 } | 805 } |
| 749 | 806 |
| 750 bool IsTPMTokenReady() { | 807 bool IsTPMTokenReady() { |
| 751 return g_nss_singleton.Get().IsTPMTokenReady(); | 808 return g_nss_singleton.Get().IsTPMTokenReady(); |
| 752 } | 809 } |
| 753 | 810 |
| 811 void OnTPMReady(const base::Closure& callback) { |
| 812 g_nss_singleton.Get().OnTPMReady(callback); |
| 813 } |
| 814 |
| 754 bool InitializeTPMToken(const std::string& token_name, | 815 bool InitializeTPMToken(const std::string& token_name, |
| 755 const std::string& user_pin) { | 816 const std::string& user_pin, |
| 756 return g_nss_singleton.Get().InitializeTPMToken(token_name, user_pin); | 817 int token_slot_id) { |
| 818 return g_nss_singleton.Get().InitializeTPMToken( |
| 819 token_name, user_pin, token_slot_id); |
| 820 } |
| 821 |
| 822 PK11SlotInfo* OpenPersistentNSSDBForPath(const base::FilePath& path) { |
| 823 return g_nss_singleton.Get().OpenPersistentNSSDBForPath(path); |
| 824 } |
| 825 |
| 826 PK11SlotInfo* GetTPMSlotForId(CK_SLOT_ID slot_id) { |
| 827 return g_nss_singleton.Get().GetTPMSlotForId(slot_id); |
| 757 } | 828 } |
| 758 #endif // defined(OS_CHROMEOS) | 829 #endif // defined(OS_CHROMEOS) |
| 759 | 830 |
| 760 base::Time PRTimeToBaseTime(PRTime prtime) { | 831 base::Time PRTimeToBaseTime(PRTime prtime) { |
| 761 return base::Time::FromInternalValue( | 832 return base::Time::FromInternalValue( |
| 762 prtime + base::Time::UnixEpoch().ToInternalValue()); | 833 prtime + base::Time::UnixEpoch().ToInternalValue()); |
| 763 } | 834 } |
| 764 | 835 |
| 765 PRTime BaseTimeToPRTime(base::Time time) { | 836 PRTime BaseTimeToPRTime(base::Time time) { |
| 766 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); | 837 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); |
| 767 } | 838 } |
| 768 | 839 |
| 769 PK11SlotInfo* GetPublicNSSKeySlot() { | 840 PK11SlotInfo* GetPublicNSSKeySlot() { |
| 770 return g_nss_singleton.Get().GetPublicNSSKeySlot(); | 841 return g_nss_singleton.Get().GetPublicNSSKeySlot(); |
| 771 } | 842 } |
| 772 | 843 |
| 773 PK11SlotInfo* GetPrivateNSSKeySlot() { | 844 PK11SlotInfo* GetPrivateNSSKeySlot() { |
| 774 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); | 845 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); |
| 775 } | 846 } |
| 776 | 847 |
| 848 void DumpNSSSlotInfos() { |
| 849 AutoSECMODListReadLock auto_lock; |
| 850 SECMODModuleList* head = SECMOD_GetDefaultModuleList(); |
| 851 LOG(WARNING) << "DumpNSSSlotInfos:"; |
| 852 for (SECMODModuleList* item = head; item != NULL; item = item->next) { |
| 853 int slot_count = item->module->loaded ? item->module->slotCount : 0; |
| 854 LOG(WARNING) << item->module->moduleID |
| 855 << " module " << item->module->commonName |
| 856 << " loaded:" << item->module->loaded; |
| 857 for (int i = 0; i < slot_count; i++) { |
| 858 PK11SlotInfo* slot = item->module->slots[i]; |
| 859 LOG(WARNING) << " " << PK11_GetSlotID(slot) |
| 860 << " tok:" << PK11_GetTokenName(slot) |
| 861 << " slot:" << PK11_GetSlotName(slot) |
| 862 << (PK11_IsInternal(slot) ? " internal" : "") |
| 863 << (PK11_IsInternalKeySlot(slot) ? " internalkeyslot" : "") |
| 864 << (PK11_IsReadOnly(slot) ? " readonly" : ""); |
| 865 } |
| 866 } |
| 867 LOG(WARNING) << ""; |
| 868 } |
| 869 |
| 777 } // namespace crypto | 870 } // namespace crypto |
| OLD | NEW |