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 3 // found in the LICENSE file. 4 5 #include "crypto/nss_util.h" 6 #include "crypto/nss_util_internal.h" 7 8 #include <nss.h> 9 #include <pk11pub.h> 10 #include <plarena.h> 11 #include <prerror.h> 12 #include <prinit.h> 13 #include <prtime.h> 14 #include <secmod.h> 15 16 #if defined(OS_OPENBSD) 17 #include <sys/mount.h> 18 #include <sys/param.h> 19 #endif 20 21 #include <map> 22 #include <vector> 23 24 #include "base/base_paths.h" 25 #include "base/bind.h" 26 #include "base/cpu.h" 27 #include "base/debug/alias.h" 28 #include "base/debug/stack_trace.h" 29 #include "base/environment.h" 30 #include "base/files/file_path.h" 31 #include "base/files/file_util.h" 32 #include "base/lazy_instance.h" 33 #include "base/logging.h" 34 #include "base/memory/scoped_ptr.h" 35 #include "base/message_loop/message_loop.h" 36 #include "base/metrics/histogram.h" 37 #include "base/native_library.h" 38 #include "base/path_service.h" 39 #include "base/stl_util.h" 40 #include "base/strings/stringprintf.h" 41 #include "base/threading/thread_checker.h" 42 #include "base/threading/thread_restrictions.h" 43 #include "base/threading/worker_pool.h" 44 #include "build/build_config.h" 45 46 // USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not 47 // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't 48 // use NSS for crypto or certificate verification, and we don't use the NSS 49 // certificate and key databases. 50 #if defined(USE_NSS) 51 #include "base/synchronization/lock.h" 52 #include "crypto/nss_crypto_module_delegate.h" 53 #endif // defined(USE_NSS) 54 55 namespace crypto { 56 57 namespace { 58 59 #if defined(OS_CHROMEOS) 60 const char kUserNSSDatabaseName[] = "UserNSSDB"; 61 62 // Constants for loading the Chrome OS TPM-backed PKCS #11 library. 63 const char kChapsModuleName[] = "Chaps"; 64 const char kChapsPath[] = "libchaps.so"; 65 66 // Fake certificate authority database used for testing. 67 static const base::FilePath::CharType kReadOnlyCertDB[] = 68 FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb"); 69 #endif // defined(OS_CHROMEOS) 70 71 std::string GetNSSErrorMessage() { 72 std::string result; 73 if (PR_GetErrorTextLength()) { 74 scoped_ptr<char[]> error_text(new char[PR_GetErrorTextLength() + 1]); 75 PRInt32 copied = PR_GetErrorText(error_text.get()); 76 result = std::string(error_text.get(), copied); 77 } else { 78 result = base::StringPrintf("NSS error code: %d", PR_GetError()); 79 } 80 return result; 81 } 82 83 #if defined(USE_NSS) 84 #if !defined(OS_CHROMEOS) 85 base::FilePath GetDefaultConfigDirectory() { 86 base::FilePath dir; 87 PathService::Get(base::DIR_HOME, &dir); 88 if (dir.empty()) { 89 LOG(ERROR) << "Failed to get home directory."; 90 return dir; 91 } 92 dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); 93 if (!base::CreateDirectory(dir)) { 94 LOG(ERROR) << "Failed to create " << dir.value() << " directory."; 95 dir.clear(); 96 } 97 DVLOG(2) << "DefaultConfigDirectory: " << dir.value(); 98 return dir; 99 } 100 #endif // !defined(IS_CHROMEOS) 101 102 // On non-Chrome OS platforms, return the default config directory. On Chrome OS 103 // test images, return a read-only directory with fake root CA certs (which are 104 // used by the local Google Accounts server mock we use when testing our login 105 // code). On Chrome OS non-test images (where the read-only directory doesn't 106 // exist), return an empty path. 107 base::FilePath GetInitialConfigDirectory() { 108 #if defined(OS_CHROMEOS) 109 base::FilePath database_dir = base::FilePath(kReadOnlyCertDB); 110 if (!base::PathExists(database_dir)) 111 database_dir.clear(); 112 return database_dir; 113 #else 114 return GetDefaultConfigDirectory(); 115 #endif // defined(OS_CHROMEOS) 116 } 117 118 // This callback for NSS forwards all requests to a caller-specified 119 // CryptoModuleBlockingPasswordDelegate object. 120 char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) { 121 crypto::CryptoModuleBlockingPasswordDelegate* delegate = 122 reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg); 123 if (delegate) { 124 bool cancelled = false; 125 std::string password = delegate->RequestPassword(PK11_GetTokenName(slot), 126 retry != PR_FALSE, 127 &cancelled); 128 if (cancelled) 129 return NULL; 130 char* result = PORT_Strdup(password.c_str()); 131 password.replace(0, password.size(), password.size(), 0); 132 return result; 133 } 134 DLOG(ERROR) << "PK11 password requested with NULL arg"; 135 return NULL; 136 } 137 138 // NSS creates a local cache of the sqlite database if it detects that the 139 // filesystem the database is on is much slower than the local disk. The 140 // detection doesn't work with the latest versions of sqlite, such as 3.6.22 141 // (NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=578561). So we set 142 // the NSS environment variable NSS_SDB_USE_CACHE to "yes" to override NSS's 143 // detection when database_dir is on NFS. See http://crbug.com/48585. 144 // 145 // TODO(wtc): port this function to other USE_NSS platforms. It is defined 146 // only for OS_LINUX and OS_OPENBSD simply because the statfs structure 147 // is OS-specific. 148 // 149 // Because this function sets an environment variable it must be run before we 150 // go multi-threaded. 151 void UseLocalCacheOfNSSDatabaseIfNFS(const base::FilePath& database_dir) { 152 bool db_on_nfs = false; 153 #if defined(OS_LINUX) 154 base::FileSystemType fs_type = base::FILE_SYSTEM_UNKNOWN; 155 if (base::GetFileSystemType(database_dir, &fs_type)) 156 db_on_nfs = (fs_type == base::FILE_SYSTEM_NFS); 157 #elif defined(OS_OPENBSD) 158 struct statfs buf; 159 if (statfs(database_dir.value().c_str(), &buf) == 0) 160 db_on_nfs = (strcmp(buf.f_fstypename, MOUNT_NFS) == 0); 161 #else 162 NOTIMPLEMENTED(); 163 #endif 164 165 if (db_on_nfs) { 166 scoped_ptr<base::Environment> env(base::Environment::Create()); 167 static const char kUseCacheEnvVar[] = "NSS_SDB_USE_CACHE"; 168 if (!env->HasVar(kUseCacheEnvVar)) 169 env->SetVar(kUseCacheEnvVar, "yes"); 170 } 171 } 172 173 #endif // defined(USE_NSS) 174 175 // A singleton to initialize/deinitialize NSPR. 176 // Separate from the NSS singleton because we initialize NSPR on the UI thread. 177 // Now that we're leaking the singleton, we could merge back with the NSS 178 // singleton. 179 class NSPRInitSingleton { 180 private: 181 friend struct base::DefaultLazyInstanceTraits<NSPRInitSingleton>; 182 183 NSPRInitSingleton() { 184 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); 185 } 186 187 // NOTE(willchan): We don't actually execute this code since we leak NSS to 188 // prevent non-joinable threads from using NSS after it's already been shut 189 // down. 190 ~NSPRInitSingleton() { 191 PL_ArenaFinish(); 192 PRStatus prstatus = PR_Cleanup(); 193 if (prstatus != PR_SUCCESS) 194 LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?"; 195 } 196 }; 197 198 base::LazyInstance<NSPRInitSingleton>::Leaky 199 g_nspr_singleton = LAZY_INSTANCE_INITIALIZER; 200 201 // Force a crash with error info on NSS_NoDB_Init failure. 202 void CrashOnNSSInitFailure() { 203 int nss_error = PR_GetError(); 204 int os_error = PR_GetOSError(); 205 base::debug::Alias(&nss_error); 206 base::debug::Alias(&os_error); 207 LOG(ERROR) << "Error initializing NSS without a persistent database: " 208 << GetNSSErrorMessage(); 209 LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error; 210 } 211 212 #if defined(OS_CHROMEOS) 213 class ChromeOSUserData { 214 public: 215 explicit ChromeOSUserData(ScopedPK11Slot public_slot) 216 : public_slot_(public_slot.Pass()), 217 private_slot_initialization_started_(false) {} 218 ~ChromeOSUserData() { 219 if (public_slot_) { 220 SECStatus status = SECMOD_CloseUserDB(public_slot_.get()); 221 if (status != SECSuccess) 222 PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); 223 } 224 } 225 226 ScopedPK11Slot GetPublicSlot() { 227 return ScopedPK11Slot( 228 public_slot_ ? PK11_ReferenceSlot(public_slot_.get()) : NULL); 229 } 230 231 ScopedPK11Slot GetPrivateSlot( 232 const base::Callback<void(ScopedPK11Slot)>& callback) { 233 if (private_slot_) 234 return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())); 235 if (!callback.is_null()) 236 tpm_ready_callback_list_.push_back(callback); 237 return ScopedPK11Slot(); 238 } 239 240 void SetPrivateSlot(ScopedPK11Slot private_slot) { 241 DCHECK(!private_slot_); 242 private_slot_ = private_slot.Pass(); 243 244 SlotReadyCallbackList callback_list; 245 callback_list.swap(tpm_ready_callback_list_); 246 for (SlotReadyCallbackList::iterator i = callback_list.begin(); 247 i != callback_list.end(); 248 ++i) { 249 (*i).Run(ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()))); 250 } 251 } 252 253 bool private_slot_initialization_started() const { 254 return private_slot_initialization_started_; 255 } 256 257 void set_private_slot_initialization_started() { 258 private_slot_initialization_started_ = true; 259 } 260 261 private: 262 ScopedPK11Slot public_slot_; 263 ScopedPK11Slot private_slot_; 264 265 bool private_slot_initialization_started_; 266 267 typedef std::vector<base::Callback<void(ScopedPK11Slot)> > 268 SlotReadyCallbackList; 269 SlotReadyCallbackList tpm_ready_callback_list_; 270 }; 271 #endif // defined(OS_CHROMEOS) 272 273 class NSSInitSingleton { 274 public: 275 #if defined(OS_CHROMEOS) 276 // Used with PostTaskAndReply to pass handles to worker thread and back. 277 struct TPMModuleAndSlot { 278 explicit TPMModuleAndSlot(SECMODModule* init_chaps_module) 279 : chaps_module(init_chaps_module) {} 280 SECMODModule* chaps_module; 281 crypto::ScopedPK11Slot tpm_slot; 282 }; 283 284 ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name, 285 const base::FilePath& path) { 286 DCHECK(thread_checker_.CalledOnValidThread()); 287 // NSS is allowed to do IO on the current thread since dispatching 288 // to a dedicated thread would still have the affect of blocking 289 // the current thread, due to NSS's internal locking requirements 290 base::ThreadRestrictions::ScopedAllowIO allow_io; 291 292 base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb"); 293 if (!base::CreateDirectory(nssdb_path)) { 294 LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory."; 295 return ScopedPK11Slot(); 296 } 297 return OpenSoftwareNSSDB(nssdb_path, db_name); 298 } 299 300 void EnableTPMTokenForNSS() { 301 DCHECK(thread_checker_.CalledOnValidThread()); 302 303 // If this gets set, then we'll use the TPM for certs with 304 // private keys, otherwise we'll fall back to the software 305 // implementation. 306 tpm_token_enabled_for_nss_ = true; 307 } 308 309 bool IsTPMTokenEnabledForNSS() { 310 DCHECK(thread_checker_.CalledOnValidThread()); 311 return tpm_token_enabled_for_nss_; 312 } 313 314 void InitializeTPMTokenAndSystemSlot( 315 int system_slot_id, 316 const base::Callback<void(bool)>& callback) { 317 DCHECK(thread_checker_.CalledOnValidThread()); 318 // Should not be called while there is already an initialization in 319 // progress. 320 DCHECK(!initializing_tpm_token_); 321 // If EnableTPMTokenForNSS hasn't been called, return false. 322 if (!tpm_token_enabled_for_nss_) { 323 base::MessageLoop::current()->PostTask(FROM_HERE, 324 base::Bind(callback, false)); 325 return; 326 } 327 328 // If everything is already initialized, then return true. 329 // Note that only |tpm_slot_| is checked, since |chaps_module_| could be 330 // NULL in tests while |tpm_slot_| has been set to the test DB. 331 if (tpm_slot_) { 332 base::MessageLoop::current()->PostTask(FROM_HERE, 333 base::Bind(callback, true)); 334 return; 335 } 336 337 // Note that a reference is not taken to chaps_module_. This is safe since 338 // NSSInitSingleton is Leaky, so the reference it holds is never released. 339 scoped_ptr<TPMModuleAndSlot> tpm_args(new TPMModuleAndSlot(chaps_module_)); 340 TPMModuleAndSlot* tpm_args_ptr = tpm_args.get(); 341 if (base::WorkerPool::PostTaskAndReply( 342 FROM_HERE, 343 base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread, 344 system_slot_id, 345 tpm_args_ptr), 346 base::Bind(&NSSInitSingleton::OnInitializedTPMTokenAndSystemSlot, 347 base::Unretained(this), // NSSInitSingleton is leaky 348 callback, 349 base::Passed(&tpm_args)), 350 true /* task_is_slow */ 351 )) { 352 initializing_tpm_token_ = true; 353 } else { 354 base::MessageLoop::current()->PostTask(FROM_HERE, 355 base::Bind(callback, false)); 356 } 357 } 358 359 static void InitializeTPMTokenOnWorkerThread(CK_SLOT_ID token_slot_id, 360 TPMModuleAndSlot* tpm_args) { 361 // This tries to load the Chaps module so NSS can talk to the hardware 362 // TPM. 363 if (!tpm_args->chaps_module) { 364 DVLOG(3) << "Loading chaps..."; 365 tpm_args->chaps_module = LoadModule( 366 kChapsModuleName, 367 kChapsPath, 368 // For more details on these parameters, see: 369 // https://developer.mozilla.org/en/PKCS11_Module_Specs 370 // slotFlags=[PublicCerts] -- Certificates and public keys can be 371 // read from this slot without requiring a call to C_Login. 372 // askpw=only -- Only authenticate to the token when necessary. 373 "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\""); 374 } 375 if (tpm_args->chaps_module) { 376 tpm_args->tpm_slot = 377 GetTPMSlotForIdOnWorkerThread(tpm_args->chaps_module, token_slot_id); 378 } 379 } 380 381 void OnInitializedTPMTokenAndSystemSlot( 382 const base::Callback<void(bool)>& callback, 383 scoped_ptr<TPMModuleAndSlot> tpm_args) { 384 DCHECK(thread_checker_.CalledOnValidThread()); 385 DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module 386 << ", got tpm slot: " << !!tpm_args->tpm_slot; 387 388 chaps_module_ = tpm_args->chaps_module; 389 tpm_slot_ = tpm_args->tpm_slot.Pass(); 390 if (!chaps_module_ && test_system_slot_) { 391 // chromeos_unittests try to test the TPM initialization process. If we 392 // have a test DB open, pretend that it is the TPM slot. 393 tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get())); 394 } 395 initializing_tpm_token_ = false; 396 397 if (tpm_slot_) 398 RunAndClearTPMReadyCallbackList(); 399 400 callback.Run(!!tpm_slot_); 401 } 402 403 void RunAndClearTPMReadyCallbackList() { 404 TPMReadyCallbackList callback_list; 405 callback_list.swap(tpm_ready_callback_list_); 406 for (TPMReadyCallbackList::iterator i = callback_list.begin(); 407 i != callback_list.end(); 408 ++i) { 409 i->Run(); 410 } 411 } 412 413 bool IsTPMTokenReady(const base::Closure& callback) { 414 if (!callback.is_null()) { 415 // Cannot DCHECK in the general case yet, but since the callback is 416 // a new addition to the API, DCHECK to make sure at least the new uses 417 // don't regress. 418 DCHECK(thread_checker_.CalledOnValidThread()); 419 } else if (!thread_checker_.CalledOnValidThread()) { 420 // TODO(mattm): Change to DCHECK when callers have been fixed. 421 DVLOG(1) << "Called on wrong thread.\n" 422 << base::debug::StackTrace().ToString(); 423 } 424 425 if (tpm_slot_) 426 return true; 427 428 if (!callback.is_null()) 429 tpm_ready_callback_list_.push_back(callback); 430 431 return false; 432 } 433 434 // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot 435 // id as an int. This should be safe since this is only used with chaps, which 436 // we also control. 437 static crypto::ScopedPK11Slot GetTPMSlotForIdOnWorkerThread( 438 SECMODModule* chaps_module, 439 CK_SLOT_ID slot_id) { 440 DCHECK(chaps_module); 441 442 DVLOG(3) << "Poking chaps module."; 443 SECStatus rv = SECMOD_UpdateSlotList(chaps_module); 444 if (rv != SECSuccess) 445 PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError(); 446 447 PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module->moduleID, slot_id); 448 if (!slot) 449 LOG(ERROR) << "TPM slot " << slot_id << " not found."; 450 return crypto::ScopedPK11Slot(slot); 451 } 452 453 bool InitializeNSSForChromeOSUser(const std::string& username_hash, 454 const base::FilePath& path) { 455 DCHECK(thread_checker_.CalledOnValidThread()); 456 if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) { 457 // This user already exists in our mapping. 458 DVLOG(2) << username_hash << " already initialized."; 459 return false; 460 } 461 462 DVLOG(2) << "Opening NSS DB " << path.value(); 463 std::string db_name = base::StringPrintf( 464 "%s %s", kUserNSSDatabaseName, username_hash.c_str()); 465 ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path)); 466 chromeos_user_map_[username_hash] = 467 new ChromeOSUserData(public_slot.Pass()); 468 return true; 469 } 470 471 bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) { 472 DCHECK(thread_checker_.CalledOnValidThread()); 473 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); 474 475 return !chromeos_user_map_[username_hash] 476 ->private_slot_initialization_started(); 477 } 478 479 void WillInitializeTPMForChromeOSUser(const std::string& username_hash) { 480 DCHECK(thread_checker_.CalledOnValidThread()); 481 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); 482 483 chromeos_user_map_[username_hash] 484 ->set_private_slot_initialization_started(); 485 } 486 487 void InitializeTPMForChromeOSUser(const std::string& username_hash, 488 CK_SLOT_ID slot_id) { 489 DCHECK(thread_checker_.CalledOnValidThread()); 490 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); 491 DCHECK(chromeos_user_map_[username_hash]-> 492 private_slot_initialization_started()); 493 494 if (!chaps_module_) 495 return; 496 497 // Note that a reference is not taken to chaps_module_. This is safe since 498 // NSSInitSingleton is Leaky, so the reference it holds is never released. 499 scoped_ptr<TPMModuleAndSlot> tpm_args(new TPMModuleAndSlot(chaps_module_)); 500 TPMModuleAndSlot* tpm_args_ptr = tpm_args.get(); 501 base::WorkerPool::PostTaskAndReply( 502 FROM_HERE, 503 base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread, 504 slot_id, 505 tpm_args_ptr), 506 base::Bind(&NSSInitSingleton::OnInitializedTPMForChromeOSUser, 507 base::Unretained(this), // NSSInitSingleton is leaky 508 username_hash, 509 base::Passed(&tpm_args)), 510 true /* task_is_slow */ 511 ); 512 } 513 514 void OnInitializedTPMForChromeOSUser(const std::string& username_hash, 515 scoped_ptr<TPMModuleAndSlot> tpm_args) { 516 DCHECK(thread_checker_.CalledOnValidThread()); 517 DVLOG(2) << "Got tpm slot for " << username_hash << " " 518 << !!tpm_args->tpm_slot; 519 chromeos_user_map_[username_hash]->SetPrivateSlot( 520 tpm_args->tpm_slot.Pass()); 521 } 522 523 void InitializePrivateSoftwareSlotForChromeOSUser( 524 const std::string& username_hash) { 525 DCHECK(thread_checker_.CalledOnValidThread()); 526 VLOG(1) << "using software private slot for " << username_hash; 527 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); 528 DCHECK(chromeos_user_map_[username_hash]-> 529 private_slot_initialization_started()); 530 531 chromeos_user_map_[username_hash]->SetPrivateSlot( 532 chromeos_user_map_[username_hash]->GetPublicSlot()); 533 } 534 535 ScopedPK11Slot GetPublicSlotForChromeOSUser( 536 const std::string& username_hash) { 537 DCHECK(thread_checker_.CalledOnValidThread()); 538 539 if (username_hash.empty()) { 540 DVLOG(2) << "empty username_hash"; 541 return ScopedPK11Slot(); 542 } 543 544 if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) { 545 LOG(ERROR) << username_hash << " not initialized."; 546 return ScopedPK11Slot(); 547 } 548 return chromeos_user_map_[username_hash]->GetPublicSlot(); 549 } 550 551 ScopedPK11Slot GetPrivateSlotForChromeOSUser( 552 const std::string& username_hash, 553 const base::Callback<void(ScopedPK11Slot)>& callback) { 554 DCHECK(thread_checker_.CalledOnValidThread()); 555 556 if (username_hash.empty()) { 557 DVLOG(2) << "empty username_hash"; 558 if (!callback.is_null()) { 559 base::MessageLoop::current()->PostTask( 560 FROM_HERE, base::Bind(callback, base::Passed(ScopedPK11Slot()))); 561 } 562 return ScopedPK11Slot(); 563 } 564 565 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); 566 567 return chromeos_user_map_[username_hash]->GetPrivateSlot(callback); 568 } 569 570 void CloseChromeOSUserForTesting(const std::string& username_hash) { 571 DCHECK(thread_checker_.CalledOnValidThread()); 572 ChromeOSUserMap::iterator i = chromeos_user_map_.find(username_hash); 573 DCHECK(i != chromeos_user_map_.end()); 574 delete i->second; 575 chromeos_user_map_.erase(i); 576 } 577 578 void SetSystemKeySlotForTesting(ScopedPK11Slot slot) { 579 // Ensure that a previous value of test_system_slot_ is not overwritten. 580 // Unsetting, i.e. setting a NULL, however is allowed. 581 DCHECK(!slot || !test_system_slot_); 582 test_system_slot_ = slot.Pass(); 583 if (test_system_slot_) { 584 tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get())); 585 RunAndClearTPMReadyCallbackList(); 586 } else { 587 tpm_slot_.reset(); 588 } 589 } 590 #endif // defined(OS_CHROMEOS) 591 592 #if !defined(OS_CHROMEOS) 593 PK11SlotInfo* GetPersistentNSSKeySlot() { 594 // TODO(mattm): Change to DCHECK when callers have been fixed. 595 if (!thread_checker_.CalledOnValidThread()) { 596 DVLOG(1) << "Called on wrong thread.\n" 597 << base::debug::StackTrace().ToString(); 598 } 599 600 return PK11_GetInternalKeySlot(); 601 } 602 #endif 603 604 #if defined(OS_CHROMEOS) 605 void GetSystemNSSKeySlotCallback( 606 const base::Callback<void(ScopedPK11Slot)>& callback) { 607 callback.Run(ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get()))); 608 } 609 610 ScopedPK11Slot GetSystemNSSKeySlot( 611 const base::Callback<void(ScopedPK11Slot)>& callback) { 612 DCHECK(thread_checker_.CalledOnValidThread()); 613 // TODO(mattm): chromeos::TPMTokenloader always calls 614 // InitializeTPMTokenAndSystemSlot with slot 0. If the system slot is 615 // disabled, tpm_slot_ will be the first user's slot instead. Can that be 616 // detected and return NULL instead? 617 618 base::Closure wrapped_callback; 619 if (!callback.is_null()) { 620 wrapped_callback = 621 base::Bind(&NSSInitSingleton::GetSystemNSSKeySlotCallback, 622 base::Unretained(this) /* singleton is leaky */, 623 callback); 624 } 625 if (IsTPMTokenReady(wrapped_callback)) 626 return ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get())); 627 return ScopedPK11Slot(); 628 } 629 #endif 630 631 #if defined(USE_NSS) 632 base::Lock* write_lock() { 633 return &write_lock_; 634 } 635 #endif // defined(USE_NSS) 636 637 // This method is used to force NSS to be initialized without a DB. 638 // Call this method before NSSInitSingleton() is constructed. 639 static void ForceNoDBInit() { 640 force_nodb_init_ = true; 641 } 642 643 private: 644 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>; 645 646 NSSInitSingleton() 647 : tpm_token_enabled_for_nss_(false), 648 initializing_tpm_token_(false), 649 chaps_module_(NULL), 650 root_(NULL) { 651 base::TimeTicks start_time = base::TimeTicks::Now(); 652 653 // It's safe to construct on any thread, since LazyInstance will prevent any 654 // other threads from accessing until the constructor is done. 655 thread_checker_.DetachFromThread(); 656 657 DisableAESNIIfNeeded(); 658 659 EnsureNSPRInit(); 660 661 // We *must* have NSS >= 3.14.3. 662 COMPILE_ASSERT( 663 (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) || 664 (NSS_VMAJOR == 3 && NSS_VMINOR > 14) || 665 (NSS_VMAJOR > 3), 666 nss_version_check_failed); 667 // Also check the run-time NSS version. 668 // NSS_VersionCheck is a >= check, not strict equality. 669 if (!NSS_VersionCheck("3.14.3")) { 670 LOG(FATAL) << "NSS_VersionCheck(\"3.14.3\") failed. NSS >= 3.14.3 is " 671 "required. Please upgrade to the latest NSS, and if you " 672 "still get this error, contact your distribution " 673 "maintainer."; 674 } 675 676 SECStatus status = SECFailure; 677 bool nodb_init = force_nodb_init_; 678 679 #if !defined(USE_NSS) 680 // Use the system certificate store, so initialize NSS without database. 681 nodb_init = true; 682 #endif 683 684 if (nodb_init) { 685 status = NSS_NoDB_Init(NULL); 686 if (status != SECSuccess) { 687 CrashOnNSSInitFailure(); 688 return; 689 } 690 #if defined(OS_IOS) 691 root_ = InitDefaultRootCerts(); 692 #endif // defined(OS_IOS) 693 } else { 694 #if defined(USE_NSS) 695 base::FilePath database_dir = GetInitialConfigDirectory(); 696 if (!database_dir.empty()) { 697 // This duplicates the work which should have been done in 698 // EarlySetupForNSSInit. However, this function is idempotent so 699 // there's no harm done. 700 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); 701 702 // Initialize with a persistent database (likely, ~/.pki/nssdb). 703 // Use "sql:" which can be shared by multiple processes safely. 704 std::string nss_config_dir = 705 base::StringPrintf("sql:%s", database_dir.value().c_str()); 706 #if defined(OS_CHROMEOS) 707 status = NSS_Init(nss_config_dir.c_str()); 708 #else 709 status = NSS_InitReadWrite(nss_config_dir.c_str()); 710 #endif 711 if (status != SECSuccess) { 712 LOG(ERROR) << "Error initializing NSS with a persistent " 713 "database (" << nss_config_dir 714 << "): " << GetNSSErrorMessage(); 715 } 716 } 717 if (status != SECSuccess) { 718 VLOG(1) << "Initializing NSS without a persistent database."; 719 status = NSS_NoDB_Init(NULL); 720 if (status != SECSuccess) { 721 CrashOnNSSInitFailure(); 722 return; 723 } 724 } 725 726 PK11_SetPasswordFunc(PKCS11PasswordFunc); 727 728 // If we haven't initialized the password for the NSS databases, 729 // initialize an empty-string password so that we don't need to 730 // log in. 731 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); 732 if (slot) { 733 // PK11_InitPin may write to the keyDB, but no other thread can use NSS 734 // yet, so we don't need to lock. 735 if (PK11_NeedUserInit(slot)) 736 PK11_InitPin(slot, NULL, NULL); 737 PK11_FreeSlot(slot); 738 } 739 740 root_ = InitDefaultRootCerts(); 741 #endif // defined(USE_NSS) 742 } 743 744 // Disable MD5 certificate signatures. (They are disabled by default in 745 // NSS 3.14.) 746 NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE); 747 NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, 748 0, NSS_USE_ALG_IN_CERT_SIGNATURE); 749 750 // The UMA bit is conditionally set for this histogram in 751 // components/startup_metric_utils.cc . 752 LOCAL_HISTOGRAM_CUSTOM_TIMES("Startup.SlowStartupNSSInit", 753 base::TimeTicks::Now() - start_time, 754 base::TimeDelta::FromMilliseconds(10), 755 base::TimeDelta::FromHours(1), 756 50); 757 } 758 759 // NOTE(willchan): We don't actually execute this code since we leak NSS to 760 // prevent non-joinable threads from using NSS after it's already been shut 761 // down. 762 ~NSSInitSingleton() { 763 #if defined(OS_CHROMEOS) 764 STLDeleteValues(&chromeos_user_map_); 765 #endif 766 tpm_slot_.reset(); 767 if (root_) { 768 SECMOD_UnloadUserModule(root_); 769 SECMOD_DestroyModule(root_); 770 root_ = NULL; 771 } 772 if (chaps_module_) { 773 SECMOD_UnloadUserModule(chaps_module_); 774 SECMOD_DestroyModule(chaps_module_); 775 chaps_module_ = NULL; 776 } 777 778 SECStatus status = NSS_Shutdown(); 779 if (status != SECSuccess) { 780 // We VLOG(1) because this failure is relatively harmless (leaking, but 781 // we're shutting down anyway). 782 VLOG(1) << "NSS_Shutdown failed; see http://crbug.com/4609"; 783 } 784 } 785 786 #if defined(USE_NSS) || defined(OS_IOS) 787 // Load nss's built-in root certs. 788 SECMODModule* InitDefaultRootCerts() { 789 SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", NULL); 790 if (root) 791 return root; 792 793 // Aw, snap. Can't find/load root cert shared library. 794 // This will make it hard to talk to anybody via https. 795 // TODO(mattm): Re-add the NOTREACHED here when crbug.com/310972 is fixed. 796 return NULL; 797 } 798 799 // Load the given module for this NSS session. 800 static SECMODModule* LoadModule(const char* name, 801 const char* library_path, 802 const char* params) { 803 std::string modparams = base::StringPrintf( 804 "name=\"%s\" library=\"%s\" %s", 805 name, library_path, params ? params : ""); 806 807 // Shouldn't need to const_cast here, but SECMOD doesn't properly 808 // declare input string arguments as const. Bug 809 // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed 810 // on NSS codebase to address this. 811 SECMODModule* module = SECMOD_LoadUserModule( 812 const_cast<char*>(modparams.c_str()), NULL, PR_FALSE); 813 if (!module) { 814 LOG(ERROR) << "Error loading " << name << " module into NSS: " 815 << GetNSSErrorMessage(); 816 return NULL; 817 } 818 if (!module->loaded) { 819 LOG(ERROR) << "After loading " << name << ", loaded==false: " 820 << GetNSSErrorMessage(); 821 SECMOD_DestroyModule(module); 822 return NULL; 823 } 824 return module; 825 } 826 #endif 827 828 static void DisableAESNIIfNeeded() { 829 if (NSS_VersionCheck("3.15") && !NSS_VersionCheck("3.15.4")) { 830 // Some versions of NSS have a bug that causes AVX instructions to be 831 // used without testing whether XSAVE is enabled by the operating system. 832 // In order to work around this, we disable AES-NI in NSS when we find 833 // that |has_avx()| is false (which includes the XSAVE test). See 834 // https://bugzilla.mozilla.org/show_bug.cgi?id=940794 835 base::CPU cpu; 836 837 if (cpu.has_avx_hardware() && !cpu.has_avx()) { 838 base::Environment::Create()->SetVar("NSS_DISABLE_HW_AES", "1"); 839 } 840 } 841 } 842 843 // If this is set to true NSS is forced to be initialized without a DB. 844 static bool force_nodb_init_; 845 846 bool tpm_token_enabled_for_nss_; 847 bool initializing_tpm_token_; 848 typedef std::vector<base::Closure> TPMReadyCallbackList; 849 TPMReadyCallbackList tpm_ready_callback_list_; 850 SECMODModule* chaps_module_; 851 crypto::ScopedPK11Slot tpm_slot_; 852 SECMODModule* root_; 853 #if defined(OS_CHROMEOS) 854 typedef std::map<std::string, ChromeOSUserData*> ChromeOSUserMap; 855 ChromeOSUserMap chromeos_user_map_; 856 ScopedPK11Slot test_system_slot_; 857 #endif 858 #if defined(USE_NSS) 859 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 860 // is fixed, we will no longer need the lock. 861 base::Lock write_lock_; 862 #endif // defined(USE_NSS) 863 864 base::ThreadChecker thread_checker_; 865 }; 866 867 // static 868 bool NSSInitSingleton::force_nodb_init_ = false; 869 870 base::LazyInstance<NSSInitSingleton>::Leaky 871 g_nss_singleton = LAZY_INSTANCE_INITIALIZER; 872 } // namespace 873 874 #if defined(USE_NSS) 875 ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path, 876 const std::string& description) { 877 const std::string modspec = 878 base::StringPrintf("configDir='sql:%s' tokenDescription='%s'", 879 path.value().c_str(), 880 description.c_str()); 881 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str()); 882 if (db_slot) { 883 if (PK11_NeedUserInit(db_slot)) 884 PK11_InitPin(db_slot, NULL, NULL); 885 } else { 886 LOG(ERROR) << "Error opening persistent database (" << modspec 887 << "): " << GetNSSErrorMessage(); 888 } 889 return ScopedPK11Slot(db_slot); 890 } 891 892 void EarlySetupForNSSInit() { 893 base::FilePath database_dir = GetInitialConfigDirectory(); 894 if (!database_dir.empty()) 895 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); 896 } 897 #endif 898 899 void EnsureNSPRInit() { 900 g_nspr_singleton.Get(); 901 } 902 903 void InitNSSSafely() { 904 // We might fork, but we haven't loaded any security modules. 905 DisableNSSForkCheck(); 906 // If we're sandboxed, we shouldn't be able to open user security modules, 907 // but it's more correct to tell NSS to not even try. 908 // Loading user security modules would have security implications. 909 ForceNSSNoDBInit(); 910 // Initialize NSS. 911 EnsureNSSInit(); 912 } 913 914 void EnsureNSSInit() { 915 // Initializing SSL causes us to do blocking IO. 916 // Temporarily allow it until we fix 917 // http://code.google.com/p/chromium/issues/detail?id=59847 918 base::ThreadRestrictions::ScopedAllowIO allow_io; 919 g_nss_singleton.Get(); 920 } 921 922 void ForceNSSNoDBInit() { 923 NSSInitSingleton::ForceNoDBInit(); 924 } 925 926 void DisableNSSForkCheck() { 927 scoped_ptr<base::Environment> env(base::Environment::Create()); 928 env->SetVar("NSS_STRICT_NOFORK", "DISABLED"); 929 } 930 931 void LoadNSSLibraries() { 932 // Some NSS libraries are linked dynamically so load them here. 933 #if defined(USE_NSS) 934 // Try to search for multiple directories to load the libraries. 935 std::vector<base::FilePath> paths; 936 937 // Use relative path to Search PATH for the library files. 938 paths.push_back(base::FilePath()); 939 940 // For Debian derivatives NSS libraries are located here. 941 paths.push_back(base::FilePath("/usr/lib/nss")); 942 943 // Ubuntu 11.10 (Oneiric) and Debian Wheezy place the libraries here. 944 #if defined(ARCH_CPU_X86_64) 945 paths.push_back(base::FilePath("/usr/lib/x86_64-linux-gnu/nss")); 946 #elif defined(ARCH_CPU_X86) 947 paths.push_back(base::FilePath("/usr/lib/i386-linux-gnu/nss")); 948 #elif defined(ARCH_CPU_ARMEL) 949 #if defined(__ARM_PCS_VFP) 950 paths.push_back(base::FilePath("/usr/lib/arm-linux-gnueabihf/nss")); 951 #else 952 paths.push_back(base::FilePath("/usr/lib/arm-linux-gnueabi/nss")); 953 #endif // defined(__ARM_PCS_VFP) 954 #elif defined(ARCH_CPU_MIPSEL) 955 paths.push_back(base::FilePath("/usr/lib/mipsel-linux-gnu/nss")); 956 #endif // defined(ARCH_CPU_X86_64) 957 958 // A list of library files to load. 959 std::vector<std::string> libs; 960 libs.push_back("libsoftokn3.so"); 961 libs.push_back("libfreebl3.so"); 962 963 // For each combination of library file and path, check for existence and 964 // then load. 965 size_t loaded = 0; 966 for (size_t i = 0; i < libs.size(); ++i) { 967 for (size_t j = 0; j < paths.size(); ++j) { 968 base::FilePath path = paths[j].Append(libs[i]); 969 base::NativeLibrary lib = base::LoadNativeLibrary(path, NULL); 970 if (lib) { 971 ++loaded; 972 break; 973 } 974 } 975 } 976 977 if (loaded == libs.size()) { 978 VLOG(3) << "NSS libraries loaded."; 979 } else { 980 LOG(ERROR) << "Failed to load NSS libraries."; 981 } 982 #endif // defined(USE_NSS) 983 } 984 985 bool CheckNSSVersion(const char* version) { 986 return !!NSS_VersionCheck(version); 987 } 988 989 #if defined(USE_NSS) 990 base::Lock* GetNSSWriteLock() { 991 return g_nss_singleton.Get().write_lock(); 992 } 993 994 AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) { 995 // May be NULL if the lock is not needed in our version of NSS. 996 if (lock_) 997 lock_->Acquire(); 998 } 999 1000 AutoNSSWriteLock::~AutoNSSWriteLock() { 1001 if (lock_) { 1002 lock_->AssertAcquired(); 1003 lock_->Release(); 1004 } 1005 } 1006 1007 AutoSECMODListReadLock::AutoSECMODListReadLock() 1008 : lock_(SECMOD_GetDefaultModuleListLock()) { 1009 SECMOD_GetReadLock(lock_); 1010 } 1011 1012 AutoSECMODListReadLock::~AutoSECMODListReadLock() { 1013 SECMOD_ReleaseReadLock(lock_); 1014 } 1015 #endif // defined(USE_NSS) 1016 1017 #if defined(OS_CHROMEOS) 1018 ScopedPK11Slot GetSystemNSSKeySlot( 1019 const base::Callback<void(ScopedPK11Slot)>& callback) { 1020 return g_nss_singleton.Get().GetSystemNSSKeySlot(callback); 1021 } 1022 1023 void SetSystemKeySlotForTesting(ScopedPK11Slot slot) { 1024 g_nss_singleton.Get().SetSystemKeySlotForTesting(slot.Pass()); 1025 } 1026 1027 void EnableTPMTokenForNSS() { 1028 g_nss_singleton.Get().EnableTPMTokenForNSS(); 1029 } 1030 1031 bool IsTPMTokenEnabledForNSS() { 1032 return g_nss_singleton.Get().IsTPMTokenEnabledForNSS(); 1033 } 1034 1035 bool IsTPMTokenReady(const base::Closure& callback) { 1036 return g_nss_singleton.Get().IsTPMTokenReady(callback); 1037 } 1038 1039 void InitializeTPMTokenAndSystemSlot( 1040 int token_slot_id, 1041 const base::Callback<void(bool)>& callback) { 1042 g_nss_singleton.Get().InitializeTPMTokenAndSystemSlot(token_slot_id, 1043 callback); 1044 } 1045 1046 bool InitializeNSSForChromeOSUser(const std::string& username_hash, 1047 const base::FilePath& path) { 1048 return g_nss_singleton.Get().InitializeNSSForChromeOSUser(username_hash, 1049 path); 1050 } 1051 1052 bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) { 1053 return g_nss_singleton.Get().ShouldInitializeTPMForChromeOSUser( 1054 username_hash); 1055 } 1056 1057 void WillInitializeTPMForChromeOSUser(const std::string& username_hash) { 1058 g_nss_singleton.Get().WillInitializeTPMForChromeOSUser(username_hash); 1059 } 1060 1061 void InitializeTPMForChromeOSUser( 1062 const std::string& username_hash, 1063 CK_SLOT_ID slot_id) { 1064 g_nss_singleton.Get().InitializeTPMForChromeOSUser(username_hash, slot_id); 1065 } 1066 1067 void InitializePrivateSoftwareSlotForChromeOSUser( 1068 const std::string& username_hash) { 1069 g_nss_singleton.Get().InitializePrivateSoftwareSlotForChromeOSUser( 1070 username_hash); 1071 } 1072 1073 ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) { 1074 return g_nss_singleton.Get().GetPublicSlotForChromeOSUser(username_hash); 1075 } 1076 1077 ScopedPK11Slot GetPrivateSlotForChromeOSUser( 1078 const std::string& username_hash, 1079 const base::Callback<void(ScopedPK11Slot)>& callback) { 1080 return g_nss_singleton.Get().GetPrivateSlotForChromeOSUser(username_hash, 1081 callback); 1082 } 1083 1084 void CloseChromeOSUserForTesting(const std::string& username_hash) { 1085 g_nss_singleton.Get().CloseChromeOSUserForTesting(username_hash); 1086 } 1087 #endif // defined(OS_CHROMEOS) 1088 1089 base::Time PRTimeToBaseTime(PRTime prtime) { 1090 return base::Time::FromInternalValue( 1091 prtime + base::Time::UnixEpoch().ToInternalValue()); 1092 } 1093 1094 PRTime BaseTimeToPRTime(base::Time time) { 1095 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); 1096 } 1097 1098 #if !defined(OS_CHROMEOS) 1099 PK11SlotInfo* GetPersistentNSSKeySlot() { 1100 return g_nss_singleton.Get().GetPersistentNSSKeySlot(); 1101 } 1102 #endif 1103 1104 } // namespace crypto 1105