Chromium Code Reviews| 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" |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 161 #endif | 162 #endif |
| 162 scoped_ptr<base::Environment> env(base::Environment::Create()); | 163 scoped_ptr<base::Environment> env(base::Environment::Create()); |
| 163 const char* use_cache_env_var = "NSS_SDB_USE_CACHE"; | 164 const char* use_cache_env_var = "NSS_SDB_USE_CACHE"; |
| 164 if (!env->HasVar(use_cache_env_var)) | 165 if (!env->HasVar(use_cache_env_var)) |
| 165 env->SetVar(use_cache_env_var, "yes"); | 166 env->SetVar(use_cache_env_var, "yes"); |
| 166 } | 167 } |
| 167 } | 168 } |
| 168 #endif // defined(OS_LINUX) || defined(OS_OPENBSD) | 169 #endif // defined(OS_LINUX) || defined(OS_OPENBSD) |
| 169 } | 170 } |
| 170 | 171 |
| 171 PK11SlotInfo* FindSlotWithTokenName(const std::string& token_name) { | |
| 172 AutoSECMODListReadLock auto_lock; | |
| 173 SECMODModuleList* head = SECMOD_GetDefaultModuleList(); | |
| 174 for (SECMODModuleList* item = head; item != NULL; item = item->next) { | |
| 175 int slot_count = item->module->loaded ? item->module->slotCount : 0; | |
| 176 for (int i = 0; i < slot_count; i++) { | |
| 177 PK11SlotInfo* slot = item->module->slots[i]; | |
| 178 if (PK11_GetTokenName(slot) == token_name) | |
| 179 return PK11_ReferenceSlot(slot); | |
| 180 } | |
| 181 } | |
| 182 return NULL; | |
| 183 } | |
| 184 | |
| 185 #endif // defined(USE_NSS) | 172 #endif // defined(USE_NSS) |
| 186 | 173 |
| 187 // A singleton to initialize/deinitialize NSPR. | 174 // A singleton to initialize/deinitialize NSPR. |
| 188 // Separate from the NSS singleton because we initialize NSPR on the UI thread. | 175 // Separate from the NSS singleton because we initialize NSPR on the UI thread. |
| 189 // Now that we're leaking the singleton, we could merge back with the NSS | 176 // Now that we're leaking the singleton, we could merge back with the NSS |
| 190 // singleton. | 177 // singleton. |
| 191 class NSPRInitSingleton { | 178 class NSPRInitSingleton { |
| 192 private: | 179 private: |
| 193 friend struct base::DefaultLazyInstanceTraits<NSPRInitSingleton>; | 180 friend struct base::DefaultLazyInstanceTraits<NSPRInitSingleton>; |
| 194 | 181 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 240 // This creates another DB slot in NSS that is read/write, unlike | 227 // This creates another DB slot in NSS that is read/write, unlike |
| 241 // the fake root CA cert DB and the "default" crypto key | 228 // the fake root CA cert DB and the "default" crypto key |
| 242 // provider, which are still read-only (because we initialized | 229 // provider, which are still read-only (because we initialized |
| 243 // NSS before we had a cryptohome mounted). | 230 // NSS before we had a cryptohome mounted). |
| 244 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), | 231 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), |
| 245 kNSSDatabaseName); | 232 kNSSDatabaseName); |
| 246 } | 233 } |
| 247 } | 234 } |
| 248 | 235 |
| 249 void EnableTPMTokenForNSS() { | 236 void EnableTPMTokenForNSS() { |
| 237 // If this gets set, then we'll use the TPM for certs with | |
| 238 // private keys, otherwise we'll fall back to the software | |
| 239 // implementation. | |
| 250 tpm_token_enabled_for_nss_ = true; | 240 tpm_token_enabled_for_nss_ = true; |
| 251 } | 241 } |
| 252 | 242 |
| 253 bool InitializeTPMToken(const std::string& token_name, | 243 bool InitializeTPMToken(const std::string& token_name, |
| 254 const std::string& user_pin) { | 244 const std::string& user_pin, |
| 245 int token_slot_id) { | |
| 255 // If EnableTPMTokenForNSS hasn't been called, return false. | 246 // If EnableTPMTokenForNSS hasn't been called, return false. |
| 256 if (!tpm_token_enabled_for_nss_) | 247 if (!tpm_token_enabled_for_nss_) |
| 257 return false; | 248 return false; |
| 258 | 249 |
| 259 // If everything is already initialized, then return true. | 250 // If everything is already initialized, then return true. |
| 260 if (chaps_module_ && tpm_slot_) | 251 if (chaps_module_ && tpm_slot_) |
| 261 return true; | 252 return true; |
| 262 | 253 |
| 263 tpm_token_name_ = token_name; | 254 tpm_token_name_ = token_name; |
| 264 tpm_user_pin_ = user_pin; | 255 tpm_user_pin_ = user_pin; |
| 265 | 256 |
| 266 // This tries to load the Chaps module so NSS can talk to the hardware | 257 // This tries to load the Chaps module so NSS can talk to the hardware |
| 267 // TPM. | 258 // TPM. |
| 268 if (!chaps_module_) { | 259 if (!chaps_module_) { |
| 269 chaps_module_ = LoadModule( | 260 chaps_module_ = LoadModule( |
| 270 kChapsModuleName, | 261 kChapsModuleName, |
| 271 kChapsPath, | 262 kChapsPath, |
| 272 // For more details on these parameters, see: | 263 // For more details on these parameters, see: |
| 273 // https://developer.mozilla.org/en/PKCS11_Module_Specs | 264 // https://developer.mozilla.org/en/PKCS11_Module_Specs |
| 274 // slotFlags=[PublicCerts] -- Certificates and public keys can be | 265 // slotFlags=[PublicCerts] -- Certificates and public keys can be |
| 275 // read from this slot without requiring a call to C_Login. | 266 // read from this slot without requiring a call to C_Login. |
| 276 // askpw=only -- Only authenticate to the token when necessary. | 267 // askpw=only -- Only authenticate to the token when necessary. |
| 277 "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\""); | 268 "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\""); |
| 269 if (!chaps_module_ && test_slot_) { | |
| 270 // chromeos_unittests try to test the TPM initialization process. If we | |
| 271 // have a test DB open, pretend that it is the TPM slot. | |
| 272 tpm_slot_ = PK11_ReferenceSlot(test_slot_); | |
| 273 return true; | |
| 274 } | |
| 278 } | 275 } |
| 279 if (chaps_module_){ | 276 if (chaps_module_){ |
| 280 // If this gets set, then we'll use the TPM for certs with | 277 tpm_slot_ = GetTPMSlotForId(token_slot_id); |
|
Ryan Sleevi
2013/10/24 01:26:21
CASTING DANGER: CK_SLOT_ID is a CK_ULONG - which i
mattm
2013/10/24 01:59:07
Done.
| |
| 281 // private keys, otherwise we'll fall back to the software | |
| 282 // implementation. | |
| 283 tpm_slot_ = GetTPMSlot(); | |
| 284 | 278 |
| 285 return tpm_slot_ != NULL; | 279 return tpm_slot_ != NULL; |
| 286 } | 280 } |
| 287 return false; | 281 return false; |
| 288 } | 282 } |
| 289 | 283 |
| 290 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { | 284 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { |
| 291 if (!tpm_token_enabled_for_nss_) { | 285 if (!tpm_token_enabled_for_nss_) { |
| 292 LOG(ERROR) << "GetTPMTokenInfo called before TPM Token is ready."; | 286 LOG(ERROR) << "GetTPMTokenInfo called before TPM Token is ready."; |
| 293 return; | 287 return; |
| 294 } | 288 } |
| 295 if (token_name) | 289 if (token_name) |
| 296 *token_name = tpm_token_name_; | 290 *token_name = tpm_token_name_; |
| 297 if (user_pin) | 291 if (user_pin) |
| 298 *user_pin = tpm_user_pin_; | 292 *user_pin = tpm_user_pin_; |
| 299 } | 293 } |
| 300 | 294 |
| 301 bool IsTPMTokenReady() { | 295 bool IsTPMTokenReady() { |
| 302 return tpm_slot_ != NULL; | 296 return tpm_slot_ != NULL; |
| 303 } | 297 } |
| 304 | 298 |
| 305 PK11SlotInfo* GetTPMSlot() { | 299 PK11SlotInfo* GetTPMSlotForId(CK_SLOT_ID slot_id) { |
| 306 std::string token_name; | 300 if (!chaps_module_) |
| 307 GetTPMTokenInfo(&token_name, NULL); | 301 return NULL; |
| 308 return FindSlotWithTokenName(token_name); | 302 |
| 303 VLOG(1) << "Poking chaps module."; | |
| 304 SECStatus rv = SECMOD_UpdateSlotList(chaps_module_); | |
| 305 if (rv != SECSuccess) | |
| 306 PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError(); | |
| 307 | |
| 308 PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module_->moduleID, slot_id); | |
| 309 if (!slot) | |
| 310 LOG(ERROR) << "TPM slot " << slot_id << " not found."; | |
| 311 return slot; | |
| 309 } | 312 } |
| 310 #endif // defined(OS_CHROMEOS) | 313 #endif // defined(OS_CHROMEOS) |
| 311 | 314 |
| 312 | 315 |
| 313 bool OpenTestNSSDB() { | 316 bool OpenTestNSSDB() { |
| 314 if (test_slot_) | 317 if (test_slot_) |
| 315 return true; | 318 return true; |
| 316 if (!g_test_nss_db_dir.Get().CreateUniqueTempDir()) | 319 if (!g_test_nss_db_dir.Get().CreateUniqueTempDir()) |
| 317 return false; | 320 return false; |
| 318 test_slot_ = OpenUserDB(g_test_nss_db_dir.Get().path(), kTestTPMTokenName); | 321 test_slot_ = OpenUserDB(g_test_nss_db_dir.Get().path(), kTestTPMTokenName); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 376 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>; | 379 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>; |
| 377 | 380 |
| 378 NSSInitSingleton() | 381 NSSInitSingleton() |
| 379 : tpm_token_enabled_for_nss_(false), | 382 : tpm_token_enabled_for_nss_(false), |
| 380 chaps_module_(NULL), | 383 chaps_module_(NULL), |
| 381 software_slot_(NULL), | 384 software_slot_(NULL), |
| 382 test_slot_(NULL), | 385 test_slot_(NULL), |
| 383 tpm_slot_(NULL), | 386 tpm_slot_(NULL), |
| 384 root_(NULL), | 387 root_(NULL), |
| 385 chromeos_user_logged_in_(false) { | 388 chromeos_user_logged_in_(false) { |
| 389 LOG(ERROR) << __func__; | |
| 390 base::debug::StackTrace().Print(); | |
| 386 base::TimeTicks start_time = base::TimeTicks::Now(); | 391 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 387 EnsureNSPRInit(); | 392 EnsureNSPRInit(); |
| 388 | 393 |
| 389 // We *must* have NSS >= 3.14.3. | 394 // We *must* have NSS >= 3.14.3. |
| 390 COMPILE_ASSERT( | 395 COMPILE_ASSERT( |
| 391 (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) || | 396 (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) || |
| 392 (NSS_VMAJOR == 3 && NSS_VMINOR > 14) || | 397 (NSS_VMAJOR == 3 && NSS_VMINOR > 14) || |
| 393 (NSS_VMAJOR > 3), | 398 (NSS_VMAJOR > 3), |
| 394 nss_version_check_failed); | 399 nss_version_check_failed); |
| 395 // Also check the run-time NSS version. | 400 // Also check the run-time NSS version. |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 542 // declare input string arguments as const. Bug | 547 // declare input string arguments as const. Bug |
| 543 // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed | 548 // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed |
| 544 // on NSS codebase to address this. | 549 // on NSS codebase to address this. |
| 545 SECMODModule* module = SECMOD_LoadUserModule( | 550 SECMODModule* module = SECMOD_LoadUserModule( |
| 546 const_cast<char*>(modparams.c_str()), NULL, PR_FALSE); | 551 const_cast<char*>(modparams.c_str()), NULL, PR_FALSE); |
| 547 if (!module) { | 552 if (!module) { |
| 548 LOG(ERROR) << "Error loading " << name << " module into NSS: " | 553 LOG(ERROR) << "Error loading " << name << " module into NSS: " |
| 549 << GetNSSErrorMessage(); | 554 << GetNSSErrorMessage(); |
| 550 return NULL; | 555 return NULL; |
| 551 } | 556 } |
| 557 if (!module->loaded) { | |
| 558 LOG(ERROR) << "After loading " << name << ", loaded==false: " | |
| 559 << GetNSSErrorMessage(); | |
| 560 SECMOD_DestroyModule(module); | |
| 561 return NULL; | |
| 562 } | |
| 552 return module; | 563 return module; |
| 553 } | 564 } |
| 554 #endif | 565 #endif |
| 555 | 566 |
| 556 static PK11SlotInfo* OpenUserDB(const base::FilePath& path, | 567 static PK11SlotInfo* OpenUserDB(const base::FilePath& path, |
| 557 const char* description) { | 568 const char* description) { |
| 558 const std::string modspec = | 569 const std::string modspec = |
| 559 base::StringPrintf("configDir='sql:%s' tokenDescription='%s'", | 570 base::StringPrintf("configDir='sql:%s' tokenDescription='%s'", |
| 560 path.value().c_str(), description); | 571 path.value().c_str(), description); |
| 561 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str()); | 572 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str()); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 623 | 634 |
| 624 void EnsureNSSInit() { | 635 void EnsureNSSInit() { |
| 625 // Initializing SSL causes us to do blocking IO. | 636 // Initializing SSL causes us to do blocking IO. |
| 626 // Temporarily allow it until we fix | 637 // Temporarily allow it until we fix |
| 627 // http://code.google.com/p/chromium/issues/detail?id=59847 | 638 // http://code.google.com/p/chromium/issues/detail?id=59847 |
| 628 base::ThreadRestrictions::ScopedAllowIO allow_io; | 639 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 629 g_nss_singleton.Get(); | 640 g_nss_singleton.Get(); |
| 630 } | 641 } |
| 631 | 642 |
| 632 void ForceNSSNoDBInit() { | 643 void ForceNSSNoDBInit() { |
| 644 LOG(ERROR) << "OKAAAAAAAAAAAAAAAAY"; | |
| 633 NSSInitSingleton::ForceNoDBInit(); | 645 NSSInitSingleton::ForceNoDBInit(); |
| 634 } | 646 } |
| 635 | 647 |
| 636 void DisableNSSForkCheck() { | 648 void DisableNSSForkCheck() { |
| 637 scoped_ptr<base::Environment> env(base::Environment::Create()); | 649 scoped_ptr<base::Environment> env(base::Environment::Create()); |
| 638 env->SetVar("NSS_STRICT_NOFORK", "DISABLED"); | 650 env->SetVar("NSS_STRICT_NOFORK", "DISABLED"); |
| 639 } | 651 } |
| 640 | 652 |
| 641 void LoadNSSLibraries() { | 653 void LoadNSSLibraries() { |
| 642 // Some NSS libraries are linked dynamically so load them here. | 654 // Some NSS libraries are linked dynamically so load them here. |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 745 | 757 |
| 746 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { | 758 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { |
| 747 g_nss_singleton.Get().GetTPMTokenInfo(token_name, user_pin); | 759 g_nss_singleton.Get().GetTPMTokenInfo(token_name, user_pin); |
| 748 } | 760 } |
| 749 | 761 |
| 750 bool IsTPMTokenReady() { | 762 bool IsTPMTokenReady() { |
| 751 return g_nss_singleton.Get().IsTPMTokenReady(); | 763 return g_nss_singleton.Get().IsTPMTokenReady(); |
| 752 } | 764 } |
| 753 | 765 |
| 754 bool InitializeTPMToken(const std::string& token_name, | 766 bool InitializeTPMToken(const std::string& token_name, |
| 755 const std::string& user_pin) { | 767 const std::string& user_pin, |
| 756 return g_nss_singleton.Get().InitializeTPMToken(token_name, user_pin); | 768 int token_slot_id) { |
| 769 return g_nss_singleton.Get().InitializeTPMToken( | |
| 770 token_name, user_pin, token_slot_id); | |
| 771 } | |
| 772 | |
| 773 PK11SlotInfo* GetTPMSlotForId(CK_SLOT_ID slot_id) { | |
| 774 return g_nss_singleton.Get().GetTPMSlotForId(slot_id); | |
| 757 } | 775 } |
| 758 #endif // defined(OS_CHROMEOS) | 776 #endif // defined(OS_CHROMEOS) |
| 759 | 777 |
| 760 base::Time PRTimeToBaseTime(PRTime prtime) { | 778 base::Time PRTimeToBaseTime(PRTime prtime) { |
| 761 return base::Time::FromInternalValue( | 779 return base::Time::FromInternalValue( |
| 762 prtime + base::Time::UnixEpoch().ToInternalValue()); | 780 prtime + base::Time::UnixEpoch().ToInternalValue()); |
| 763 } | 781 } |
| 764 | 782 |
| 765 PRTime BaseTimeToPRTime(base::Time time) { | 783 PRTime BaseTimeToPRTime(base::Time time) { |
| 766 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); | 784 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); |
| 767 } | 785 } |
| 768 | 786 |
| 769 PK11SlotInfo* GetPublicNSSKeySlot() { | 787 PK11SlotInfo* GetPublicNSSKeySlot() { |
| 770 return g_nss_singleton.Get().GetPublicNSSKeySlot(); | 788 return g_nss_singleton.Get().GetPublicNSSKeySlot(); |
| 771 } | 789 } |
| 772 | 790 |
| 773 PK11SlotInfo* GetPrivateNSSKeySlot() { | 791 PK11SlotInfo* GetPrivateNSSKeySlot() { |
| 774 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); | 792 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); |
| 775 } | 793 } |
| 776 | 794 |
| 777 } // namespace crypto | 795 } // namespace crypto |
| OLD | NEW |