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 |