chaps_support.cc 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // Copyright 2020 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. #include "crypto/chaps_support.h"
  5. #include <dlfcn.h>
  6. #include <secmod.h>
  7. #include <secmodt.h>
  8. #include "base/logging.h"
  9. #include "base/threading/scoped_blocking_call.h"
  10. #include "crypto/scoped_nss_types.h"
  11. #include "nss_util_internal.h"
  12. namespace crypto {
  13. namespace {
  14. // Constants for loading the Chrome OS TPM-backed PKCS #11 library.
  15. const char kChapsModuleName[] = "Chaps";
  16. const char kChapsPath[] = "libchaps.so";
  17. class ScopedChapsLoadFixup {
  18. public:
  19. ScopedChapsLoadFixup();
  20. ~ScopedChapsLoadFixup();
  21. private:
  22. #if defined(COMPONENT_BUILD)
  23. void* chaps_handle_;
  24. #endif
  25. };
  26. #if defined(COMPONENT_BUILD)
  27. ScopedChapsLoadFixup::ScopedChapsLoadFixup() {
  28. // HACK: libchaps links the system protobuf and there are symbol conflicts
  29. // with the bundled copy. Load chaps with RTLD_DEEPBIND to workaround.
  30. chaps_handle_ = dlopen(kChapsPath, RTLD_LOCAL | RTLD_NOW | RTLD_DEEPBIND);
  31. }
  32. ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {
  33. // LoadNSSModule() will have taken a 2nd reference.
  34. if (chaps_handle_)
  35. dlclose(chaps_handle_);
  36. }
  37. #else
  38. ScopedChapsLoadFixup::ScopedChapsLoadFixup() = default;
  39. ScopedChapsLoadFixup::~ScopedChapsLoadFixup() = default;
  40. #endif // defined(COMPONENT_BUILD)
  41. } // namespace
  42. SECMODModule* LoadChaps() {
  43. // NSS functions may reenter //net via extension hooks. If the reentered
  44. // code needs to synchronously wait for a task to run but the thread pool in
  45. // which that task must run doesn't have enough threads to schedule it, a
  46. // deadlock occurs. To prevent that, the base::ScopedBlockingCall below
  47. // increments the thread pool capacity for the duration of the TPM
  48. // initialization.
  49. base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
  50. base::BlockingType::WILL_BLOCK);
  51. ScopedChapsLoadFixup chaps_loader;
  52. DVLOG(3) << "Loading chaps...";
  53. return LoadNSSModule(
  54. kChapsModuleName, kChapsPath,
  55. // For more details on these parameters, see:
  56. // https://developer.mozilla.org/en/PKCS11_Module_Specs
  57. // slotFlags=[PublicCerts] -- Certificates and public keys can be
  58. // read from this slot without requiring a call to C_Login.
  59. // askpw=only -- Only authenticate to the token when necessary.
  60. "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\"");
  61. }
  62. ScopedPK11Slot GetChapsSlot(SECMODModule* chaps_module, CK_SLOT_ID slot_id) {
  63. DCHECK(chaps_module);
  64. // NSS functions may reenter //net via extension hooks. If the reentered
  65. // code needs to synchronously wait for a task to run but the thread pool in
  66. // which that task must run doesn't have enough threads to schedule it, a
  67. // deadlock occurs. To prevent that, the base::ScopedBlockingCall below
  68. // increments the thread pool capacity for the duration of the TPM
  69. // initialization.
  70. base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
  71. base::BlockingType::WILL_BLOCK);
  72. DVLOG(3) << "Poking chaps module.";
  73. SECStatus rv = SECMOD_UpdateSlotList(chaps_module);
  74. if (rv != SECSuccess)
  75. LOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError();
  76. ScopedPK11Slot slot =
  77. ScopedPK11Slot(SECMOD_LookupSlot(chaps_module->moduleID, slot_id));
  78. if (!slot)
  79. LOG(ERROR) << "TPM slot " << slot_id << " not found.";
  80. return slot;
  81. }
  82. bool IsSlotProvidedByChaps(PK11SlotInfo* slot) {
  83. if (!slot)
  84. return false;
  85. SECMODModule* pk11_module = PK11_GetModule(slot);
  86. return pk11_module && base::StringPiece(pk11_module->commonName) ==
  87. base::StringPiece(kChapsModuleName);
  88. }
  89. } // namespace crypto