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 |