| 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" |
| 38 #include "base/threading/thread_checker.h" |
| 37 #include "base/threading/thread_restrictions.h" | 39 #include "base/threading/thread_restrictions.h" |
| 38 #include "build/build_config.h" | 40 #include "build/build_config.h" |
| 39 | 41 |
| 40 // 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 |
| 41 // 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 |
| 42 // 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 |
| 43 // certificate and key databases. | 45 // certificate and key databases. |
| 44 #if defined(USE_NSS) | 46 #if defined(USE_NSS) |
| 45 #include "base/synchronization/lock.h" | 47 #include "base/synchronization/lock.h" |
| 46 #include "crypto/crypto_module_blocking_password_delegate.h" | 48 #include "crypto/crypto_module_blocking_password_delegate.h" |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 base::debug::Alias(&os_error); | 212 base::debug::Alias(&os_error); |
| 211 LOG(ERROR) << "Error initializing NSS without a persistent database: " | 213 LOG(ERROR) << "Error initializing NSS without a persistent database: " |
| 212 << GetNSSErrorMessage(); | 214 << GetNSSErrorMessage(); |
| 213 LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error; | 215 LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error; |
| 214 } | 216 } |
| 215 | 217 |
| 216 class NSSInitSingleton { | 218 class NSSInitSingleton { |
| 217 public: | 219 public: |
| 218 #if defined(OS_CHROMEOS) | 220 #if defined(OS_CHROMEOS) |
| 219 void OpenPersistentNSSDB() { | 221 void OpenPersistentNSSDB() { |
| 222 DCHECK(thread_checker_.CalledOnValidThread()); |
| 223 |
| 220 if (!chromeos_user_logged_in_) { | 224 if (!chromeos_user_logged_in_) { |
| 221 // GetDefaultConfigDirectory causes us to do blocking IO on UI thread. | 225 // GetDefaultConfigDirectory causes us to do blocking IO on UI thread. |
| 222 // Temporarily allow it until we fix http://crbug.com/70119 | 226 // Temporarily allow it until we fix http://crbug.com/70119 |
| 223 base::ThreadRestrictions::ScopedAllowIO allow_io; | 227 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 224 chromeos_user_logged_in_ = true; | 228 chromeos_user_logged_in_ = true; |
| 225 | 229 |
| 226 // This creates another DB slot in NSS that is read/write, unlike | 230 // This creates another DB slot in NSS that is read/write, unlike |
| 227 // the fake root CA cert DB and the "default" crypto key | 231 // the fake root CA cert DB and the "default" crypto key |
| 228 // provider, which are still read-only (because we initialized | 232 // provider, which are still read-only (because we initialized |
| 229 // NSS before we had a cryptohome mounted). | 233 // NSS before we had a cryptohome mounted). |
| 230 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), | 234 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), |
| 231 kNSSDatabaseName); | 235 kNSSDatabaseName); |
| 232 } | 236 } |
| 233 } | 237 } |
| 234 | 238 |
| 235 void EnableTPMTokenForNSS() { | 239 void EnableTPMTokenForNSS() { |
| 240 DCHECK(thread_checker_.CalledOnValidThread()); |
| 241 |
| 236 // If this gets set, then we'll use the TPM for certs with | 242 // If this gets set, then we'll use the TPM for certs with |
| 237 // private keys, otherwise we'll fall back to the software | 243 // private keys, otherwise we'll fall back to the software |
| 238 // implementation. | 244 // implementation. |
| 239 tpm_token_enabled_for_nss_ = true; | 245 tpm_token_enabled_for_nss_ = true; |
| 240 } | 246 } |
| 241 | 247 |
| 242 bool InitializeTPMToken(const std::string& token_name, | 248 bool InitializeTPMToken(const std::string& token_name, |
| 243 int token_slot_id, | 249 int token_slot_id, |
| 244 const std::string& user_pin) { | 250 const std::string& user_pin) { |
| 251 DCHECK(thread_checker_.CalledOnValidThread()); |
| 252 |
| 245 // If EnableTPMTokenForNSS hasn't been called, return false. | 253 // If EnableTPMTokenForNSS hasn't been called, return false. |
| 246 if (!tpm_token_enabled_for_nss_) | 254 if (!tpm_token_enabled_for_nss_) |
| 247 return false; | 255 return false; |
| 248 | 256 |
| 249 // If everything is already initialized, then return true. | 257 // If everything is already initialized, then return true. |
| 250 if (chaps_module_ && tpm_slot_) | 258 if (chaps_module_ && tpm_slot_) |
| 251 return true; | 259 return true; |
| 252 | 260 |
| 253 tpm_token_name_ = token_name; | 261 tpm_token_name_ = token_name; |
| 254 tpm_user_pin_ = user_pin; | 262 tpm_user_pin_ = user_pin; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 274 } | 282 } |
| 275 if (chaps_module_){ | 283 if (chaps_module_){ |
| 276 tpm_slot_ = GetTPMSlotForId(token_slot_id); | 284 tpm_slot_ = GetTPMSlotForId(token_slot_id); |
| 277 | 285 |
| 278 return tpm_slot_ != NULL; | 286 return tpm_slot_ != NULL; |
| 279 } | 287 } |
| 280 return false; | 288 return false; |
| 281 } | 289 } |
| 282 | 290 |
| 283 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { | 291 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { |
| 292 // TODO(mattm): Change to DCHECK when callers have been fixed. |
| 293 if (!thread_checker_.CalledOnValidThread()) { |
| 294 DVLOG(1) << "Called on wrong thread.\n" |
| 295 << base::debug::StackTrace().ToString(); |
| 296 } |
| 297 |
| 284 if (!tpm_token_enabled_for_nss_) { | 298 if (!tpm_token_enabled_for_nss_) { |
| 285 LOG(ERROR) << "GetTPMTokenInfo called before TPM Token is ready."; | 299 LOG(ERROR) << "GetTPMTokenInfo called before TPM Token is ready."; |
| 286 return; | 300 return; |
| 287 } | 301 } |
| 288 if (token_name) | 302 if (token_name) |
| 289 *token_name = tpm_token_name_; | 303 *token_name = tpm_token_name_; |
| 290 if (user_pin) | 304 if (user_pin) |
| 291 *user_pin = tpm_user_pin_; | 305 *user_pin = tpm_user_pin_; |
| 292 } | 306 } |
| 293 | 307 |
| 294 bool IsTPMTokenReady() { | 308 bool IsTPMTokenReady() { |
| 309 // TODO(mattm): Change to DCHECK when callers have been fixed. |
| 310 if (!thread_checker_.CalledOnValidThread()) { |
| 311 DVLOG(1) << "Called on wrong thread.\n" |
| 312 << base::debug::StackTrace().ToString(); |
| 313 } |
| 314 |
| 295 return tpm_slot_ != NULL; | 315 return tpm_slot_ != NULL; |
| 296 } | 316 } |
| 297 | 317 |
| 298 // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot | 318 // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot |
| 299 // id as an int. This should be safe since this is only used with chaps, which | 319 // id as an int. This should be safe since this is only used with chaps, which |
| 300 // we also control. | 320 // we also control. |
| 301 PK11SlotInfo* GetTPMSlotForId(CK_SLOT_ID slot_id) { | 321 PK11SlotInfo* GetTPMSlotForId(CK_SLOT_ID slot_id) { |
| 322 DCHECK(thread_checker_.CalledOnValidThread()); |
| 323 |
| 302 if (!chaps_module_) | 324 if (!chaps_module_) |
| 303 return NULL; | 325 return NULL; |
| 304 | 326 |
| 305 VLOG(1) << "Poking chaps module."; | 327 VLOG(1) << "Poking chaps module."; |
| 306 SECStatus rv = SECMOD_UpdateSlotList(chaps_module_); | 328 SECStatus rv = SECMOD_UpdateSlotList(chaps_module_); |
| 307 if (rv != SECSuccess) | 329 if (rv != SECSuccess) |
| 308 PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError(); | 330 PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError(); |
| 309 | 331 |
| 310 PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module_->moduleID, slot_id); | 332 PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module_->moduleID, slot_id); |
| 311 if (!slot) | 333 if (!slot) |
| 312 LOG(ERROR) << "TPM slot " << slot_id << " not found."; | 334 LOG(ERROR) << "TPM slot " << slot_id << " not found."; |
| 313 return slot; | 335 return slot; |
| 314 } | 336 } |
| 315 #endif // defined(OS_CHROMEOS) | 337 #endif // defined(OS_CHROMEOS) |
| 316 | 338 |
| 317 | 339 |
| 318 bool OpenTestNSSDB() { | 340 bool OpenTestNSSDB() { |
| 341 DCHECK(thread_checker_.CalledOnValidThread()); |
| 342 |
| 319 if (test_slot_) | 343 if (test_slot_) |
| 320 return true; | 344 return true; |
| 321 if (!g_test_nss_db_dir.Get().CreateUniqueTempDir()) | 345 if (!g_test_nss_db_dir.Get().CreateUniqueTempDir()) |
| 322 return false; | 346 return false; |
| 323 test_slot_ = OpenUserDB(g_test_nss_db_dir.Get().path(), kTestTPMTokenName); | 347 test_slot_ = OpenUserDB(g_test_nss_db_dir.Get().path(), kTestTPMTokenName); |
| 324 return !!test_slot_; | 348 return !!test_slot_; |
| 325 } | 349 } |
| 326 | 350 |
| 327 void CloseTestNSSDB() { | 351 void CloseTestNSSDB() { |
| 352 DCHECK(thread_checker_.CalledOnValidThread()); |
| 353 |
| 328 if (!test_slot_) | 354 if (!test_slot_) |
| 329 return; | 355 return; |
| 330 SECStatus status = SECMOD_CloseUserDB(test_slot_); | 356 SECStatus status = SECMOD_CloseUserDB(test_slot_); |
| 331 if (status != SECSuccess) | 357 if (status != SECSuccess) |
| 332 PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); | 358 PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); |
| 333 PK11_FreeSlot(test_slot_); | 359 PK11_FreeSlot(test_slot_); |
| 334 test_slot_ = NULL; | 360 test_slot_ = NULL; |
| 335 ignore_result(g_test_nss_db_dir.Get().Delete()); | 361 ignore_result(g_test_nss_db_dir.Get().Delete()); |
| 336 } | 362 } |
| 337 | 363 |
| 338 PK11SlotInfo* GetPublicNSSKeySlot() { | 364 PK11SlotInfo* GetPublicNSSKeySlot() { |
| 365 // TODO(mattm): Change to DCHECK when callers have been fixed. |
| 366 if (!thread_checker_.CalledOnValidThread()) { |
| 367 DVLOG(1) << "Called on wrong thread.\n" |
| 368 << base::debug::StackTrace().ToString(); |
| 369 } |
| 370 |
| 339 if (test_slot_) | 371 if (test_slot_) |
| 340 return PK11_ReferenceSlot(test_slot_); | 372 return PK11_ReferenceSlot(test_slot_); |
| 341 if (software_slot_) | 373 if (software_slot_) |
| 342 return PK11_ReferenceSlot(software_slot_); | 374 return PK11_ReferenceSlot(software_slot_); |
| 343 return PK11_GetInternalKeySlot(); | 375 return PK11_GetInternalKeySlot(); |
| 344 } | 376 } |
| 345 | 377 |
| 346 PK11SlotInfo* GetPrivateNSSKeySlot() { | 378 PK11SlotInfo* GetPrivateNSSKeySlot() { |
| 379 // TODO(mattm): Change to DCHECK when callers have been fixed. |
| 380 if (!thread_checker_.CalledOnValidThread()) { |
| 381 DVLOG(1) << "Called on wrong thread.\n" |
| 382 << base::debug::StackTrace().ToString(); |
| 383 } |
| 384 |
| 347 if (test_slot_) | 385 if (test_slot_) |
| 348 return PK11_ReferenceSlot(test_slot_); | 386 return PK11_ReferenceSlot(test_slot_); |
| 349 | 387 |
| 350 #if defined(OS_CHROMEOS) | 388 #if defined(OS_CHROMEOS) |
| 351 if (tpm_token_enabled_for_nss_) { | 389 if (tpm_token_enabled_for_nss_) { |
| 352 if (IsTPMTokenReady()) { | 390 if (IsTPMTokenReady()) { |
| 353 return PK11_ReferenceSlot(tpm_slot_); | 391 return PK11_ReferenceSlot(tpm_slot_); |
| 354 } else { | 392 } else { |
| 355 // If we were supposed to get the hardware token, but were | 393 // If we were supposed to get the hardware token, but were |
| 356 // unable to, return NULL rather than fall back to sofware. | 394 // unable to, return NULL rather than fall back to sofware. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 382 | 420 |
| 383 NSSInitSingleton() | 421 NSSInitSingleton() |
| 384 : tpm_token_enabled_for_nss_(false), | 422 : tpm_token_enabled_for_nss_(false), |
| 385 chaps_module_(NULL), | 423 chaps_module_(NULL), |
| 386 software_slot_(NULL), | 424 software_slot_(NULL), |
| 387 test_slot_(NULL), | 425 test_slot_(NULL), |
| 388 tpm_slot_(NULL), | 426 tpm_slot_(NULL), |
| 389 root_(NULL), | 427 root_(NULL), |
| 390 chromeos_user_logged_in_(false) { | 428 chromeos_user_logged_in_(false) { |
| 391 base::TimeTicks start_time = base::TimeTicks::Now(); | 429 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 430 |
| 431 // It's safe to construct on any thread, since LazyInstance will prevent any |
| 432 // other threads from accessing until the constructor is done. |
| 433 thread_checker_.DetachFromThread(); |
| 434 |
| 392 EnsureNSPRInit(); | 435 EnsureNSPRInit(); |
| 393 | 436 |
| 394 // We *must* have NSS >= 3.14.3. | 437 // We *must* have NSS >= 3.14.3. |
| 395 COMPILE_ASSERT( | 438 COMPILE_ASSERT( |
| 396 (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) || | 439 (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) || |
| 397 (NSS_VMAJOR == 3 && NSS_VMINOR > 14) || | 440 (NSS_VMAJOR == 3 && NSS_VMINOR > 14) || |
| 398 (NSS_VMAJOR > 3), | 441 (NSS_VMAJOR > 3), |
| 399 nss_version_check_failed); | 442 nss_version_check_failed); |
| 400 // Also check the run-time NSS version. | 443 // Also check the run-time NSS version. |
| 401 // NSS_VersionCheck is a >= check, not strict equality. | 444 // NSS_VersionCheck is a >= check, not strict equality. |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 PK11SlotInfo* software_slot_; | 634 PK11SlotInfo* software_slot_; |
| 592 PK11SlotInfo* test_slot_; | 635 PK11SlotInfo* test_slot_; |
| 593 PK11SlotInfo* tpm_slot_; | 636 PK11SlotInfo* tpm_slot_; |
| 594 SECMODModule* root_; | 637 SECMODModule* root_; |
| 595 bool chromeos_user_logged_in_; | 638 bool chromeos_user_logged_in_; |
| 596 #if defined(USE_NSS) | 639 #if defined(USE_NSS) |
| 597 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 | 640 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 |
| 598 // is fixed, we will no longer need the lock. | 641 // is fixed, we will no longer need the lock. |
| 599 base::Lock write_lock_; | 642 base::Lock write_lock_; |
| 600 #endif // defined(USE_NSS) | 643 #endif // defined(USE_NSS) |
| 644 |
| 645 base::ThreadChecker thread_checker_; |
| 601 }; | 646 }; |
| 602 | 647 |
| 603 // static | 648 // static |
| 604 bool NSSInitSingleton::force_nodb_init_ = false; | 649 bool NSSInitSingleton::force_nodb_init_ = false; |
| 605 | 650 |
| 606 base::LazyInstance<NSSInitSingleton>::Leaky | 651 base::LazyInstance<NSSInitSingleton>::Leaky |
| 607 g_nss_singleton = LAZY_INSTANCE_INITIALIZER; | 652 g_nss_singleton = LAZY_INSTANCE_INITIALIZER; |
| 608 } // namespace | 653 } // namespace |
| 609 | 654 |
| 610 const char kTestTPMTokenName[] = "Test DB"; | 655 const char kTestTPMTokenName[] = "Test DB"; |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 781 | 826 |
| 782 PK11SlotInfo* GetPublicNSSKeySlot() { | 827 PK11SlotInfo* GetPublicNSSKeySlot() { |
| 783 return g_nss_singleton.Get().GetPublicNSSKeySlot(); | 828 return g_nss_singleton.Get().GetPublicNSSKeySlot(); |
| 784 } | 829 } |
| 785 | 830 |
| 786 PK11SlotInfo* GetPrivateNSSKeySlot() { | 831 PK11SlotInfo* GetPrivateNSSKeySlot() { |
| 787 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); | 832 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); |
| 788 } | 833 } |
| 789 | 834 |
| 790 } // namespace crypto | 835 } // namespace crypto |
| OLD | NEW |