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