xref: /aosp_15_r20/external/cronet/crypto/nss_util_chromeos.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "crypto/nss_util.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <nss.h>
8*6777b538SAndroid Build Coastguard Worker #include <pk11pub.h>
9*6777b538SAndroid Build Coastguard Worker #include <plarena.h>
10*6777b538SAndroid Build Coastguard Worker #include <prerror.h>
11*6777b538SAndroid Build Coastguard Worker #include <prinit.h>
12*6777b538SAndroid Build Coastguard Worker #include <prtime.h>
13*6777b538SAndroid Build Coastguard Worker #include <secmod.h>
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker #include <map>
16*6777b538SAndroid Build Coastguard Worker #include <memory>
17*6777b538SAndroid Build Coastguard Worker #include <utility>
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker #include "base/callback_list.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/containers/contains.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/debug/stack_trace.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/files/file_enumerator.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/files/file_path.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/lazy_instance.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
30*6777b538SAndroid Build Coastguard Worker #include "base/no_destructor.h"
31*6777b538SAndroid Build Coastguard Worker #include "base/path_service.h"
32*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
33*6777b538SAndroid Build Coastguard Worker #include "base/task/sequenced_task_runner.h"
34*6777b538SAndroid Build Coastguard Worker #include "base/task/single_thread_task_runner.h"
35*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool.h"
36*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
37*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_checker.h"
38*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
39*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
40*6777b538SAndroid Build Coastguard Worker #include "crypto/chaps_support.h"
41*6777b538SAndroid Build Coastguard Worker #include "crypto/nss_util_internal.h"
42*6777b538SAndroid Build Coastguard Worker 
43*6777b538SAndroid Build Coastguard Worker namespace crypto {
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker namespace {
46*6777b538SAndroid Build Coastguard Worker 
47*6777b538SAndroid Build Coastguard Worker const char kUserNSSDatabaseName[] = "UserNSSDB";
48*6777b538SAndroid Build Coastguard Worker 
49*6777b538SAndroid Build Coastguard Worker class ChromeOSUserData {
50*6777b538SAndroid Build Coastguard Worker  public:
51*6777b538SAndroid Build Coastguard Worker   using SlotReadyCallback = base::OnceCallback<void(ScopedPK11Slot)>;
52*6777b538SAndroid Build Coastguard Worker 
ChromeOSUserData(ScopedPK11Slot public_slot)53*6777b538SAndroid Build Coastguard Worker   explicit ChromeOSUserData(ScopedPK11Slot public_slot)
54*6777b538SAndroid Build Coastguard Worker       : public_slot_(std::move(public_slot)) {}
55*6777b538SAndroid Build Coastguard Worker 
~ChromeOSUserData()56*6777b538SAndroid Build Coastguard Worker   ~ChromeOSUserData() {
57*6777b538SAndroid Build Coastguard Worker     if (public_slot_) {
58*6777b538SAndroid Build Coastguard Worker       SECStatus status = CloseSoftwareNSSDB(public_slot_.get());
59*6777b538SAndroid Build Coastguard Worker       if (status != SECSuccess)
60*6777b538SAndroid Build Coastguard Worker         PLOG(ERROR) << "CloseSoftwareNSSDB failed: " << PORT_GetError();
61*6777b538SAndroid Build Coastguard Worker     }
62*6777b538SAndroid Build Coastguard Worker   }
63*6777b538SAndroid Build Coastguard Worker 
GetPublicSlot()64*6777b538SAndroid Build Coastguard Worker   ScopedPK11Slot GetPublicSlot() {
65*6777b538SAndroid Build Coastguard Worker     return ScopedPK11Slot(public_slot_ ? PK11_ReferenceSlot(public_slot_.get())
66*6777b538SAndroid Build Coastguard Worker                                        : nullptr);
67*6777b538SAndroid Build Coastguard Worker   }
68*6777b538SAndroid Build Coastguard Worker 
GetPrivateSlot(SlotReadyCallback callback)69*6777b538SAndroid Build Coastguard Worker   ScopedPK11Slot GetPrivateSlot(SlotReadyCallback callback) {
70*6777b538SAndroid Build Coastguard Worker     if (private_slot_)
71*6777b538SAndroid Build Coastguard Worker       return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()));
72*6777b538SAndroid Build Coastguard Worker     if (!callback.is_null()) {
73*6777b538SAndroid Build Coastguard Worker       // Callback lists cannot hold callbacks that take move-only args, since
74*6777b538SAndroid Build Coastguard Worker       // Notify()ing such a list would move the arg into the first callback,
75*6777b538SAndroid Build Coastguard Worker       // leaving it null or unspecified for remaining callbacks.  Instead, adapt
76*6777b538SAndroid Build Coastguard Worker       // the provided callbacks to accept a raw pointer, which can be copied,
77*6777b538SAndroid Build Coastguard Worker       // and then wrap in a separate scoping object for each callback.
78*6777b538SAndroid Build Coastguard Worker       tpm_ready_callback_list_.AddUnsafe(base::BindOnce(
79*6777b538SAndroid Build Coastguard Worker           [](SlotReadyCallback callback, PK11SlotInfo* info) {
80*6777b538SAndroid Build Coastguard Worker             std::move(callback).Run(ScopedPK11Slot(PK11_ReferenceSlot(info)));
81*6777b538SAndroid Build Coastguard Worker           },
82*6777b538SAndroid Build Coastguard Worker           std::move(callback)));
83*6777b538SAndroid Build Coastguard Worker     }
84*6777b538SAndroid Build Coastguard Worker     return ScopedPK11Slot();
85*6777b538SAndroid Build Coastguard Worker   }
86*6777b538SAndroid Build Coastguard Worker 
SetPrivateSlot(ScopedPK11Slot private_slot)87*6777b538SAndroid Build Coastguard Worker   void SetPrivateSlot(ScopedPK11Slot private_slot) {
88*6777b538SAndroid Build Coastguard Worker     DCHECK(!private_slot_);
89*6777b538SAndroid Build Coastguard Worker     private_slot_ = std::move(private_slot);
90*6777b538SAndroid Build Coastguard Worker     tpm_ready_callback_list_.Notify(private_slot_.get());
91*6777b538SAndroid Build Coastguard Worker   }
92*6777b538SAndroid Build Coastguard Worker 
private_slot_initialization_started() const93*6777b538SAndroid Build Coastguard Worker   bool private_slot_initialization_started() const {
94*6777b538SAndroid Build Coastguard Worker     return private_slot_initialization_started_;
95*6777b538SAndroid Build Coastguard Worker   }
96*6777b538SAndroid Build Coastguard Worker 
set_private_slot_initialization_started()97*6777b538SAndroid Build Coastguard Worker   void set_private_slot_initialization_started() {
98*6777b538SAndroid Build Coastguard Worker     private_slot_initialization_started_ = true;
99*6777b538SAndroid Build Coastguard Worker   }
100*6777b538SAndroid Build Coastguard Worker 
101*6777b538SAndroid Build Coastguard Worker  private:
102*6777b538SAndroid Build Coastguard Worker   using SlotReadyCallbackList = base::OnceCallbackList<void(PK11SlotInfo*)>;
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker   ScopedPK11Slot public_slot_;
105*6777b538SAndroid Build Coastguard Worker   ScopedPK11Slot private_slot_;
106*6777b538SAndroid Build Coastguard Worker 
107*6777b538SAndroid Build Coastguard Worker   bool private_slot_initialization_started_ = false;
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker   SlotReadyCallbackList tpm_ready_callback_list_;
110*6777b538SAndroid Build Coastguard Worker };
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker // Contains state used for the ChromeOSTokenManager. Unlike the
113*6777b538SAndroid Build Coastguard Worker // ChromeOSTokenManager, which is thread-checked, this object may live
114*6777b538SAndroid Build Coastguard Worker // and be accessed on multiple threads. While this is normally dangerous,
115*6777b538SAndroid Build Coastguard Worker // this is done to support callers initializing early in process startup,
116*6777b538SAndroid Build Coastguard Worker // where the threads using the objects may not be created yet, and the
117*6777b538SAndroid Build Coastguard Worker // thread startup may depend on these objects.
118*6777b538SAndroid Build Coastguard Worker // Put differently: They may be written to from any thread, if, and only
119*6777b538SAndroid Build Coastguard Worker // if, the thread they will be read from has not yet been created;
120*6777b538SAndroid Build Coastguard Worker // otherwise, this should be treated as thread-affine/thread-hostile.
121*6777b538SAndroid Build Coastguard Worker struct ChromeOSTokenManagerDataForTesting {
GetInstancecrypto::__anon58d160150111::ChromeOSTokenManagerDataForTesting122*6777b538SAndroid Build Coastguard Worker   static ChromeOSTokenManagerDataForTesting& GetInstance() {
123*6777b538SAndroid Build Coastguard Worker     static base::NoDestructor<ChromeOSTokenManagerDataForTesting> instance;
124*6777b538SAndroid Build Coastguard Worker     return *instance;
125*6777b538SAndroid Build Coastguard Worker   }
126*6777b538SAndroid Build Coastguard Worker 
127*6777b538SAndroid Build Coastguard Worker   // System slot that will be used for the system slot initialization.
128*6777b538SAndroid Build Coastguard Worker   ScopedPK11Slot test_system_slot;
129*6777b538SAndroid Build Coastguard Worker };
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker class ChromeOSTokenManager {
132*6777b538SAndroid Build Coastguard Worker  public:
133*6777b538SAndroid Build Coastguard Worker   enum class State {
134*6777b538SAndroid Build Coastguard Worker     // Initial state.
135*6777b538SAndroid Build Coastguard Worker     kInitializationNotStarted,
136*6777b538SAndroid Build Coastguard Worker     // Initialization of the TPM token was started.
137*6777b538SAndroid Build Coastguard Worker     kInitializationStarted,
138*6777b538SAndroid Build Coastguard Worker     // TPM token was successfully initialized, but not available to the class'
139*6777b538SAndroid Build Coastguard Worker     // users yet.
140*6777b538SAndroid Build Coastguard Worker     kTpmTokenInitialized,
141*6777b538SAndroid Build Coastguard Worker     // TPM token was successfully enabled. It is a final state.
142*6777b538SAndroid Build Coastguard Worker     kTpmTokenEnabled,
143*6777b538SAndroid Build Coastguard Worker     // TPM token will never be enabled. It is a final state.
144*6777b538SAndroid Build Coastguard Worker     kTpmTokenDisabled,
145*6777b538SAndroid Build Coastguard Worker   };
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker   // Used with PostTaskAndReply to pass handles to worker thread and back.
148*6777b538SAndroid Build Coastguard Worker   struct TPMModuleAndSlot {
TPMModuleAndSlotcrypto::__anon58d160150111::ChromeOSTokenManager::TPMModuleAndSlot149*6777b538SAndroid Build Coastguard Worker     explicit TPMModuleAndSlot(SECMODModule* init_chaps_module)
150*6777b538SAndroid Build Coastguard Worker         : chaps_module(init_chaps_module) {}
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker     raw_ptr<SECMODModule> chaps_module;
153*6777b538SAndroid Build Coastguard Worker     ScopedPK11Slot tpm_slot;
154*6777b538SAndroid Build Coastguard Worker   };
155*6777b538SAndroid Build Coastguard Worker 
OpenPersistentNSSDBForPath(const std::string & db_name,const base::FilePath & path)156*6777b538SAndroid Build Coastguard Worker   ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name,
157*6777b538SAndroid Build Coastguard Worker                                             const base::FilePath& path) {
158*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
159*6777b538SAndroid Build Coastguard Worker     // NSS is allowed to do IO on the current thread since dispatching
160*6777b538SAndroid Build Coastguard Worker     // to a dedicated thread would still have the affect of blocking
161*6777b538SAndroid Build Coastguard Worker     // the current thread, due to NSS's internal locking requirements
162*6777b538SAndroid Build Coastguard Worker     ScopedAllowBlockingForNSS allow_blocking;
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker     base::FilePath nssdb_path = GetSoftwareNSSDBPath(path);
165*6777b538SAndroid Build Coastguard Worker     if (!base::CreateDirectory(nssdb_path)) {
166*6777b538SAndroid Build Coastguard Worker       LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory.";
167*6777b538SAndroid Build Coastguard Worker       return ScopedPK11Slot();
168*6777b538SAndroid Build Coastguard Worker     }
169*6777b538SAndroid Build Coastguard Worker     return OpenSoftwareNSSDB(nssdb_path, db_name);
170*6777b538SAndroid Build Coastguard Worker   }
171*6777b538SAndroid Build Coastguard Worker 
InitializeTPMTokenAndSystemSlot(int system_slot_id,base::OnceCallback<void (bool)> callback)172*6777b538SAndroid Build Coastguard Worker   void InitializeTPMTokenAndSystemSlot(
173*6777b538SAndroid Build Coastguard Worker       int system_slot_id,
174*6777b538SAndroid Build Coastguard Worker       base::OnceCallback<void(bool)> callback) {
175*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
176*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(state_, State::kInitializationNotStarted);
177*6777b538SAndroid Build Coastguard Worker     state_ = State::kInitializationStarted;
178*6777b538SAndroid Build Coastguard Worker 
179*6777b538SAndroid Build Coastguard Worker     // Note that a reference is not taken to chaps_module_. This is safe since
180*6777b538SAndroid Build Coastguard Worker     // ChromeOSTokenManager is Leaky, so the reference it holds is never
181*6777b538SAndroid Build Coastguard Worker     // released.
182*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<TPMModuleAndSlot> tpm_args(
183*6777b538SAndroid Build Coastguard Worker         new TPMModuleAndSlot(chaps_module_));
184*6777b538SAndroid Build Coastguard Worker     TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
185*6777b538SAndroid Build Coastguard Worker     base::ThreadPool::PostTaskAndReply(
186*6777b538SAndroid Build Coastguard Worker         FROM_HERE,
187*6777b538SAndroid Build Coastguard Worker         {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
188*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&ChromeOSTokenManager::InitializeTPMTokenInThreadPool,
189*6777b538SAndroid Build Coastguard Worker                        system_slot_id, tpm_args_ptr),
190*6777b538SAndroid Build Coastguard Worker         base::BindOnce(
191*6777b538SAndroid Build Coastguard Worker             &ChromeOSTokenManager::OnInitializedTPMTokenAndSystemSlot,
192*6777b538SAndroid Build Coastguard Worker             base::Unretained(this),  // ChromeOSTokenManager is leaky
193*6777b538SAndroid Build Coastguard Worker             std::move(callback), std::move(tpm_args)));
194*6777b538SAndroid Build Coastguard Worker   }
195*6777b538SAndroid Build Coastguard Worker 
FinishInitializingTPMTokenAndSystemSlot()196*6777b538SAndroid Build Coastguard Worker   void FinishInitializingTPMTokenAndSystemSlot() {
197*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
198*6777b538SAndroid Build Coastguard Worker     DCHECK(!IsInitializationFinished());
199*6777b538SAndroid Build Coastguard Worker 
200*6777b538SAndroid Build Coastguard Worker     // If `OnInitializedTPMTokenAndSystemSlot` was not called, but a test system
201*6777b538SAndroid Build Coastguard Worker     // slot is prepared, start using it now. Can happen in tests that don't fake
202*6777b538SAndroid Build Coastguard Worker     // enable TPM.
203*6777b538SAndroid Build Coastguard Worker     if (!system_slot_ &&
204*6777b538SAndroid Build Coastguard Worker         ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot) {
205*6777b538SAndroid Build Coastguard Worker       system_slot_ = ScopedPK11Slot(
206*6777b538SAndroid Build Coastguard Worker           PK11_ReferenceSlot(ChromeOSTokenManagerDataForTesting::GetInstance()
207*6777b538SAndroid Build Coastguard Worker                                  .test_system_slot.get()));
208*6777b538SAndroid Build Coastguard Worker     }
209*6777b538SAndroid Build Coastguard Worker 
210*6777b538SAndroid Build Coastguard Worker     state_ = (state_ == State::kTpmTokenInitialized) ? State::kTpmTokenEnabled
211*6777b538SAndroid Build Coastguard Worker                                                      : State::kTpmTokenDisabled;
212*6777b538SAndroid Build Coastguard Worker 
213*6777b538SAndroid Build Coastguard Worker     tpm_ready_callback_list_->Notify();
214*6777b538SAndroid Build Coastguard Worker   }
215*6777b538SAndroid Build Coastguard Worker 
InitializeTPMTokenInThreadPool(CK_SLOT_ID token_slot_id,TPMModuleAndSlot * tpm_args)216*6777b538SAndroid Build Coastguard Worker   static void InitializeTPMTokenInThreadPool(CK_SLOT_ID token_slot_id,
217*6777b538SAndroid Build Coastguard Worker                                              TPMModuleAndSlot* tpm_args) {
218*6777b538SAndroid Build Coastguard Worker     // NSS functions may reenter //net via extension hooks. If the reentered
219*6777b538SAndroid Build Coastguard Worker     // code needs to synchronously wait for a task to run but the thread pool in
220*6777b538SAndroid Build Coastguard Worker     // which that task must run doesn't have enough threads to schedule it, a
221*6777b538SAndroid Build Coastguard Worker     // deadlock occurs. To prevent that, the base::ScopedBlockingCall below
222*6777b538SAndroid Build Coastguard Worker     // increments the thread pool capacity for the duration of the TPM
223*6777b538SAndroid Build Coastguard Worker     // initialization.
224*6777b538SAndroid Build Coastguard Worker     base::ScopedBlockingCall scoped_blocking_call(
225*6777b538SAndroid Build Coastguard Worker         FROM_HERE, base::BlockingType::WILL_BLOCK);
226*6777b538SAndroid Build Coastguard Worker 
227*6777b538SAndroid Build Coastguard Worker     if (!tpm_args->chaps_module) {
228*6777b538SAndroid Build Coastguard Worker       tpm_args->chaps_module = LoadChaps();
229*6777b538SAndroid Build Coastguard Worker     }
230*6777b538SAndroid Build Coastguard Worker     if (tpm_args->chaps_module) {
231*6777b538SAndroid Build Coastguard Worker       tpm_args->tpm_slot = GetChapsSlot(tpm_args->chaps_module, token_slot_id);
232*6777b538SAndroid Build Coastguard Worker     }
233*6777b538SAndroid Build Coastguard Worker   }
234*6777b538SAndroid Build Coastguard Worker 
OnInitializedTPMTokenAndSystemSlot(base::OnceCallback<void (bool)> callback,std::unique_ptr<TPMModuleAndSlot> tpm_args)235*6777b538SAndroid Build Coastguard Worker   void OnInitializedTPMTokenAndSystemSlot(
236*6777b538SAndroid Build Coastguard Worker       base::OnceCallback<void(bool)> callback,
237*6777b538SAndroid Build Coastguard Worker       std::unique_ptr<TPMModuleAndSlot> tpm_args) {
238*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
239*6777b538SAndroid Build Coastguard Worker     DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module
240*6777b538SAndroid Build Coastguard Worker              << ", got tpm slot: " << !!tpm_args->tpm_slot;
241*6777b538SAndroid Build Coastguard Worker 
242*6777b538SAndroid Build Coastguard Worker     chaps_module_ = tpm_args->chaps_module;
243*6777b538SAndroid Build Coastguard Worker 
244*6777b538SAndroid Build Coastguard Worker     if (ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot) {
245*6777b538SAndroid Build Coastguard Worker       // chromeos_unittests try to test the TPM initialization process. If we
246*6777b538SAndroid Build Coastguard Worker       // have a test DB open, pretend that it is the system slot.
247*6777b538SAndroid Build Coastguard Worker       system_slot_ = ScopedPK11Slot(
248*6777b538SAndroid Build Coastguard Worker           PK11_ReferenceSlot(ChromeOSTokenManagerDataForTesting::GetInstance()
249*6777b538SAndroid Build Coastguard Worker                                  .test_system_slot.get()));
250*6777b538SAndroid Build Coastguard Worker     } else {
251*6777b538SAndroid Build Coastguard Worker       system_slot_ = std::move(tpm_args->tpm_slot);
252*6777b538SAndroid Build Coastguard Worker     }
253*6777b538SAndroid Build Coastguard Worker 
254*6777b538SAndroid Build Coastguard Worker     if (system_slot_) {
255*6777b538SAndroid Build Coastguard Worker       state_ = State::kTpmTokenInitialized;
256*6777b538SAndroid Build Coastguard Worker     }
257*6777b538SAndroid Build Coastguard Worker 
258*6777b538SAndroid Build Coastguard Worker     std::move(callback).Run(!!system_slot_);
259*6777b538SAndroid Build Coastguard Worker   }
260*6777b538SAndroid Build Coastguard Worker 
IsTPMTokenEnabled(base::OnceCallback<void (bool)> callback)261*6777b538SAndroid Build Coastguard Worker   void IsTPMTokenEnabled(base::OnceCallback<void(bool)> callback) {
262*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
263*6777b538SAndroid Build Coastguard Worker     DCHECK(!callback.is_null());
264*6777b538SAndroid Build Coastguard Worker 
265*6777b538SAndroid Build Coastguard Worker     if (!IsInitializationFinished()) {
266*6777b538SAndroid Build Coastguard Worker       // Call back to this method when initialization is finished.
267*6777b538SAndroid Build Coastguard Worker       tpm_ready_callback_list_->AddUnsafe(
268*6777b538SAndroid Build Coastguard Worker           base::BindOnce(&ChromeOSTokenManager::IsTPMTokenEnabled,
269*6777b538SAndroid Build Coastguard Worker                          base::Unretained(this) /* singleton is leaky */,
270*6777b538SAndroid Build Coastguard Worker                          std::move(callback)));
271*6777b538SAndroid Build Coastguard Worker       return;
272*6777b538SAndroid Build Coastguard Worker     }
273*6777b538SAndroid Build Coastguard Worker 
274*6777b538SAndroid Build Coastguard Worker     DCHECK(base::SequencedTaskRunner::HasCurrentDefault());
275*6777b538SAndroid Build Coastguard Worker     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
276*6777b538SAndroid Build Coastguard Worker         FROM_HERE,
277*6777b538SAndroid Build Coastguard Worker         base::BindOnce(std::move(callback),
278*6777b538SAndroid Build Coastguard Worker                        /*is_tpm_enabled=*/(state_ == State::kTpmTokenEnabled)));
279*6777b538SAndroid Build Coastguard Worker   }
280*6777b538SAndroid Build Coastguard Worker 
InitializeNSSForChromeOSUser(const std::string & username_hash,const base::FilePath & path)281*6777b538SAndroid Build Coastguard Worker   bool InitializeNSSForChromeOSUser(const std::string& username_hash,
282*6777b538SAndroid Build Coastguard Worker                                     const base::FilePath& path) {
283*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
284*6777b538SAndroid Build Coastguard Worker     if (base::Contains(chromeos_user_map_, username_hash)) {
285*6777b538SAndroid Build Coastguard Worker       // This user already exists in our mapping.
286*6777b538SAndroid Build Coastguard Worker       DVLOG(2) << username_hash << " already initialized.";
287*6777b538SAndroid Build Coastguard Worker       return false;
288*6777b538SAndroid Build Coastguard Worker     }
289*6777b538SAndroid Build Coastguard Worker 
290*6777b538SAndroid Build Coastguard Worker     DVLOG(2) << "Opening NSS DB " << path.value();
291*6777b538SAndroid Build Coastguard Worker     std::string db_name = base::StringPrintf("%s %s", kUserNSSDatabaseName,
292*6777b538SAndroid Build Coastguard Worker                                              username_hash.c_str());
293*6777b538SAndroid Build Coastguard Worker     ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path));
294*6777b538SAndroid Build Coastguard Worker 
295*6777b538SAndroid Build Coastguard Worker     return InitializeNSSForChromeOSUserWithSlot(username_hash,
296*6777b538SAndroid Build Coastguard Worker                                                 std::move(public_slot));
297*6777b538SAndroid Build Coastguard Worker   }
298*6777b538SAndroid Build Coastguard Worker 
InitializeNSSForChromeOSUserWithSlot(const std::string & username_hash,ScopedPK11Slot public_slot)299*6777b538SAndroid Build Coastguard Worker   bool InitializeNSSForChromeOSUserWithSlot(const std::string& username_hash,
300*6777b538SAndroid Build Coastguard Worker                                             ScopedPK11Slot public_slot) {
301*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
302*6777b538SAndroid Build Coastguard Worker     if (base::Contains(chromeos_user_map_, username_hash)) {
303*6777b538SAndroid Build Coastguard Worker       // This user already exists in our mapping.
304*6777b538SAndroid Build Coastguard Worker       DVLOG(2) << username_hash << " already initialized.";
305*6777b538SAndroid Build Coastguard Worker       return false;
306*6777b538SAndroid Build Coastguard Worker     }
307*6777b538SAndroid Build Coastguard Worker 
308*6777b538SAndroid Build Coastguard Worker     chromeos_user_map_[username_hash] =
309*6777b538SAndroid Build Coastguard Worker         std::make_unique<ChromeOSUserData>(std::move(public_slot));
310*6777b538SAndroid Build Coastguard Worker     return true;
311*6777b538SAndroid Build Coastguard Worker   }
312*6777b538SAndroid Build Coastguard Worker 
ShouldInitializeTPMForChromeOSUser(const std::string & username_hash)313*6777b538SAndroid Build Coastguard Worker   bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
314*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
315*6777b538SAndroid Build Coastguard Worker     DCHECK(base::Contains(chromeos_user_map_, username_hash));
316*6777b538SAndroid Build Coastguard Worker 
317*6777b538SAndroid Build Coastguard Worker     return !chromeos_user_map_[username_hash]
318*6777b538SAndroid Build Coastguard Worker                 ->private_slot_initialization_started();
319*6777b538SAndroid Build Coastguard Worker   }
320*6777b538SAndroid Build Coastguard Worker 
WillInitializeTPMForChromeOSUser(const std::string & username_hash)321*6777b538SAndroid Build Coastguard Worker   void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
322*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
323*6777b538SAndroid Build Coastguard Worker     DCHECK(base::Contains(chromeos_user_map_, username_hash));
324*6777b538SAndroid Build Coastguard Worker 
325*6777b538SAndroid Build Coastguard Worker     chromeos_user_map_[username_hash]
326*6777b538SAndroid Build Coastguard Worker         ->set_private_slot_initialization_started();
327*6777b538SAndroid Build Coastguard Worker   }
328*6777b538SAndroid Build Coastguard Worker 
InitializeTPMForChromeOSUser(const std::string & username_hash,CK_SLOT_ID slot_id)329*6777b538SAndroid Build Coastguard Worker   void InitializeTPMForChromeOSUser(const std::string& username_hash,
330*6777b538SAndroid Build Coastguard Worker                                     CK_SLOT_ID slot_id) {
331*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
332*6777b538SAndroid Build Coastguard Worker     DCHECK(base::Contains(chromeos_user_map_, username_hash));
333*6777b538SAndroid Build Coastguard Worker     DCHECK(chromeos_user_map_[username_hash]
334*6777b538SAndroid Build Coastguard Worker                ->private_slot_initialization_started());
335*6777b538SAndroid Build Coastguard Worker 
336*6777b538SAndroid Build Coastguard Worker     if (!chaps_module_)
337*6777b538SAndroid Build Coastguard Worker       return;
338*6777b538SAndroid Build Coastguard Worker 
339*6777b538SAndroid Build Coastguard Worker     // Note that a reference is not taken to chaps_module_. This is safe since
340*6777b538SAndroid Build Coastguard Worker     // ChromeOSTokenManager is Leaky, so the reference it holds is never
341*6777b538SAndroid Build Coastguard Worker     // released.
342*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<TPMModuleAndSlot> tpm_args(
343*6777b538SAndroid Build Coastguard Worker         new TPMModuleAndSlot(chaps_module_));
344*6777b538SAndroid Build Coastguard Worker     TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
345*6777b538SAndroid Build Coastguard Worker     base::ThreadPool::PostTaskAndReply(
346*6777b538SAndroid Build Coastguard Worker         FROM_HERE,
347*6777b538SAndroid Build Coastguard Worker         {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
348*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&ChromeOSTokenManager::InitializeTPMTokenInThreadPool,
349*6777b538SAndroid Build Coastguard Worker                        slot_id, tpm_args_ptr),
350*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&ChromeOSTokenManager::OnInitializedTPMForChromeOSUser,
351*6777b538SAndroid Build Coastguard Worker                        base::Unretained(this),  // ChromeOSTokenManager is leaky
352*6777b538SAndroid Build Coastguard Worker                        username_hash, std::move(tpm_args)));
353*6777b538SAndroid Build Coastguard Worker   }
354*6777b538SAndroid Build Coastguard Worker 
OnInitializedTPMForChromeOSUser(const std::string & username_hash,std::unique_ptr<TPMModuleAndSlot> tpm_args)355*6777b538SAndroid Build Coastguard Worker   void OnInitializedTPMForChromeOSUser(
356*6777b538SAndroid Build Coastguard Worker       const std::string& username_hash,
357*6777b538SAndroid Build Coastguard Worker       std::unique_ptr<TPMModuleAndSlot> tpm_args) {
358*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
359*6777b538SAndroid Build Coastguard Worker     DVLOG(2) << "Got tpm slot for " << username_hash << " "
360*6777b538SAndroid Build Coastguard Worker              << !!tpm_args->tpm_slot;
361*6777b538SAndroid Build Coastguard Worker     chromeos_user_map_[username_hash]->SetPrivateSlot(
362*6777b538SAndroid Build Coastguard Worker         std::move(tpm_args->tpm_slot));
363*6777b538SAndroid Build Coastguard Worker   }
364*6777b538SAndroid Build Coastguard Worker 
InitializePrivateSoftwareSlotForChromeOSUser(const std::string & username_hash)365*6777b538SAndroid Build Coastguard Worker   void InitializePrivateSoftwareSlotForChromeOSUser(
366*6777b538SAndroid Build Coastguard Worker       const std::string& username_hash) {
367*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
368*6777b538SAndroid Build Coastguard Worker     VLOG(1) << "using software private slot for " << username_hash;
369*6777b538SAndroid Build Coastguard Worker     DCHECK(base::Contains(chromeos_user_map_, username_hash));
370*6777b538SAndroid Build Coastguard Worker     DCHECK(chromeos_user_map_[username_hash]
371*6777b538SAndroid Build Coastguard Worker                ->private_slot_initialization_started());
372*6777b538SAndroid Build Coastguard Worker 
373*6777b538SAndroid Build Coastguard Worker     if (prepared_test_private_slot_) {
374*6777b538SAndroid Build Coastguard Worker       chromeos_user_map_[username_hash]->SetPrivateSlot(
375*6777b538SAndroid Build Coastguard Worker           std::move(prepared_test_private_slot_));
376*6777b538SAndroid Build Coastguard Worker       return;
377*6777b538SAndroid Build Coastguard Worker     }
378*6777b538SAndroid Build Coastguard Worker 
379*6777b538SAndroid Build Coastguard Worker     chromeos_user_map_[username_hash]->SetPrivateSlot(
380*6777b538SAndroid Build Coastguard Worker         chromeos_user_map_[username_hash]->GetPublicSlot());
381*6777b538SAndroid Build Coastguard Worker   }
382*6777b538SAndroid Build Coastguard Worker 
GetPublicSlotForChromeOSUser(const std::string & username_hash)383*6777b538SAndroid Build Coastguard Worker   ScopedPK11Slot GetPublicSlotForChromeOSUser(
384*6777b538SAndroid Build Coastguard Worker       const std::string& username_hash) {
385*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
386*6777b538SAndroid Build Coastguard Worker 
387*6777b538SAndroid Build Coastguard Worker     if (username_hash.empty()) {
388*6777b538SAndroid Build Coastguard Worker       DVLOG(2) << "empty username_hash";
389*6777b538SAndroid Build Coastguard Worker       return ScopedPK11Slot();
390*6777b538SAndroid Build Coastguard Worker     }
391*6777b538SAndroid Build Coastguard Worker 
392*6777b538SAndroid Build Coastguard Worker     if (!base::Contains(chromeos_user_map_, username_hash)) {
393*6777b538SAndroid Build Coastguard Worker       LOG(ERROR) << username_hash << " not initialized.";
394*6777b538SAndroid Build Coastguard Worker       return ScopedPK11Slot();
395*6777b538SAndroid Build Coastguard Worker     }
396*6777b538SAndroid Build Coastguard Worker     return chromeos_user_map_[username_hash]->GetPublicSlot();
397*6777b538SAndroid Build Coastguard Worker   }
398*6777b538SAndroid Build Coastguard Worker 
GetPrivateSlotForChromeOSUser(const std::string & username_hash,base::OnceCallback<void (ScopedPK11Slot)> callback)399*6777b538SAndroid Build Coastguard Worker   ScopedPK11Slot GetPrivateSlotForChromeOSUser(
400*6777b538SAndroid Build Coastguard Worker       const std::string& username_hash,
401*6777b538SAndroid Build Coastguard Worker       base::OnceCallback<void(ScopedPK11Slot)> callback) {
402*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
403*6777b538SAndroid Build Coastguard Worker 
404*6777b538SAndroid Build Coastguard Worker     if (username_hash.empty()) {
405*6777b538SAndroid Build Coastguard Worker       DVLOG(2) << "empty username_hash";
406*6777b538SAndroid Build Coastguard Worker       if (!callback.is_null()) {
407*6777b538SAndroid Build Coastguard Worker         base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
408*6777b538SAndroid Build Coastguard Worker             FROM_HERE, base::BindOnce(std::move(callback), ScopedPK11Slot()));
409*6777b538SAndroid Build Coastguard Worker       }
410*6777b538SAndroid Build Coastguard Worker       return ScopedPK11Slot();
411*6777b538SAndroid Build Coastguard Worker     }
412*6777b538SAndroid Build Coastguard Worker 
413*6777b538SAndroid Build Coastguard Worker     DCHECK(base::Contains(chromeos_user_map_, username_hash));
414*6777b538SAndroid Build Coastguard Worker 
415*6777b538SAndroid Build Coastguard Worker     return chromeos_user_map_[username_hash]->GetPrivateSlot(
416*6777b538SAndroid Build Coastguard Worker         std::move(callback));
417*6777b538SAndroid Build Coastguard Worker   }
418*6777b538SAndroid Build Coastguard Worker 
CloseChromeOSUserForTesting(const std::string & username_hash)419*6777b538SAndroid Build Coastguard Worker   void CloseChromeOSUserForTesting(const std::string& username_hash) {
420*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
421*6777b538SAndroid Build Coastguard Worker     auto i = chromeos_user_map_.find(username_hash);
422*6777b538SAndroid Build Coastguard Worker     DCHECK(i != chromeos_user_map_.end());
423*6777b538SAndroid Build Coastguard Worker     chromeos_user_map_.erase(i);
424*6777b538SAndroid Build Coastguard Worker   }
425*6777b538SAndroid Build Coastguard Worker 
GetSystemNSSKeySlot(base::OnceCallback<void (ScopedPK11Slot)> callback)426*6777b538SAndroid Build Coastguard Worker   void GetSystemNSSKeySlot(base::OnceCallback<void(ScopedPK11Slot)> callback) {
427*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
428*6777b538SAndroid Build Coastguard Worker 
429*6777b538SAndroid Build Coastguard Worker     if (!IsInitializationFinished()) {
430*6777b538SAndroid Build Coastguard Worker       // Call back to this method when initialization is finished.
431*6777b538SAndroid Build Coastguard Worker       tpm_ready_callback_list_->AddUnsafe(
432*6777b538SAndroid Build Coastguard Worker           base::BindOnce(&ChromeOSTokenManager::GetSystemNSSKeySlot,
433*6777b538SAndroid Build Coastguard Worker                          base::Unretained(this) /* singleton is leaky */,
434*6777b538SAndroid Build Coastguard Worker                          std::move(callback)));
435*6777b538SAndroid Build Coastguard Worker       return;
436*6777b538SAndroid Build Coastguard Worker     }
437*6777b538SAndroid Build Coastguard Worker 
438*6777b538SAndroid Build Coastguard Worker     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
439*6777b538SAndroid Build Coastguard Worker         FROM_HERE,
440*6777b538SAndroid Build Coastguard Worker         base::BindOnce(std::move(callback),
441*6777b538SAndroid Build Coastguard Worker                        /*system_slot=*/ScopedPK11Slot(
442*6777b538SAndroid Build Coastguard Worker                            system_slot_ ? PK11_ReferenceSlot(system_slot_.get())
443*6777b538SAndroid Build Coastguard Worker                                         : nullptr)));
444*6777b538SAndroid Build Coastguard Worker   }
445*6777b538SAndroid Build Coastguard Worker 
ResetSystemSlotForTesting()446*6777b538SAndroid Build Coastguard Worker   void ResetSystemSlotForTesting() { system_slot_.reset(); }
447*6777b538SAndroid Build Coastguard Worker 
ResetTokenManagerForTesting()448*6777b538SAndroid Build Coastguard Worker   void ResetTokenManagerForTesting() {
449*6777b538SAndroid Build Coastguard Worker     // Prevent test failures when two tests in the same process use the same
450*6777b538SAndroid Build Coastguard Worker     // ChromeOSTokenManager from different threads.
451*6777b538SAndroid Build Coastguard Worker     DETACH_FROM_THREAD(thread_checker_);
452*6777b538SAndroid Build Coastguard Worker     state_ = State::kInitializationNotStarted;
453*6777b538SAndroid Build Coastguard Worker 
454*6777b538SAndroid Build Coastguard Worker     // Configuring chaps_module_ here is not supported yet.
455*6777b538SAndroid Build Coastguard Worker     CHECK(!chaps_module_);
456*6777b538SAndroid Build Coastguard Worker 
457*6777b538SAndroid Build Coastguard Worker     // Make sure there are no outstanding callbacks between tests.
458*6777b538SAndroid Build Coastguard Worker     // OnceClosureList doesn't provide a way to clear the callback list.
459*6777b538SAndroid Build Coastguard Worker     tpm_ready_callback_list_ = std::make_unique<base::OnceClosureList>();
460*6777b538SAndroid Build Coastguard Worker 
461*6777b538SAndroid Build Coastguard Worker     chromeos_user_map_.clear();
462*6777b538SAndroid Build Coastguard Worker     ResetSystemSlotForTesting();  // IN-TEST
463*6777b538SAndroid Build Coastguard Worker     prepared_test_private_slot_.reset();
464*6777b538SAndroid Build Coastguard Worker   }
465*6777b538SAndroid Build Coastguard Worker 
SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot)466*6777b538SAndroid Build Coastguard Worker   void SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot) {
467*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
468*6777b538SAndroid Build Coastguard Worker 
469*6777b538SAndroid Build Coastguard Worker     // Ensure that a previous value of prepared_test_private_slot_ is not
470*6777b538SAndroid Build Coastguard Worker     // overwritten. Unsetting, i.e. setting a nullptr, however is allowed.
471*6777b538SAndroid Build Coastguard Worker     DCHECK(!slot || !prepared_test_private_slot_);
472*6777b538SAndroid Build Coastguard Worker     prepared_test_private_slot_ = std::move(slot);
473*6777b538SAndroid Build Coastguard Worker   }
474*6777b538SAndroid Build Coastguard Worker 
IsInitializationStarted()475*6777b538SAndroid Build Coastguard Worker   bool IsInitializationStarted() {
476*6777b538SAndroid Build Coastguard Worker     return (state_ != State::kInitializationNotStarted);
477*6777b538SAndroid Build Coastguard Worker   }
478*6777b538SAndroid Build Coastguard Worker 
479*6777b538SAndroid Build Coastguard Worker  private:
480*6777b538SAndroid Build Coastguard Worker   friend struct base::LazyInstanceTraitsBase<ChromeOSTokenManager>;
481*6777b538SAndroid Build Coastguard Worker 
ChromeOSTokenManager()482*6777b538SAndroid Build Coastguard Worker   ChromeOSTokenManager() { EnsureNSSInit(); }
483*6777b538SAndroid Build Coastguard Worker 
484*6777b538SAndroid Build Coastguard Worker   // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS
485*6777b538SAndroid Build Coastguard Worker   // to prevent non-joinable threads from using NSS after it's already been
486*6777b538SAndroid Build Coastguard Worker   // shut down.
487*6777b538SAndroid Build Coastguard Worker   ~ChromeOSTokenManager() = delete;
488*6777b538SAndroid Build Coastguard Worker 
IsInitializationFinished()489*6777b538SAndroid Build Coastguard Worker   bool IsInitializationFinished() {
490*6777b538SAndroid Build Coastguard Worker     switch (state_) {
491*6777b538SAndroid Build Coastguard Worker       case State::kTpmTokenEnabled:
492*6777b538SAndroid Build Coastguard Worker       case State::kTpmTokenDisabled:
493*6777b538SAndroid Build Coastguard Worker         return true;
494*6777b538SAndroid Build Coastguard Worker       case State::kInitializationNotStarted:
495*6777b538SAndroid Build Coastguard Worker       case State::kInitializationStarted:
496*6777b538SAndroid Build Coastguard Worker       case State::kTpmTokenInitialized:
497*6777b538SAndroid Build Coastguard Worker         return false;
498*6777b538SAndroid Build Coastguard Worker     }
499*6777b538SAndroid Build Coastguard Worker   }
500*6777b538SAndroid Build Coastguard Worker 
501*6777b538SAndroid Build Coastguard Worker   State state_ = State::kInitializationNotStarted;
502*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<base::OnceClosureList> tpm_ready_callback_list_ =
503*6777b538SAndroid Build Coastguard Worker       std::make_unique<base::OnceClosureList>();
504*6777b538SAndroid Build Coastguard Worker 
505*6777b538SAndroid Build Coastguard Worker   raw_ptr<SECMODModule> chaps_module_ = nullptr;
506*6777b538SAndroid Build Coastguard Worker   ScopedPK11Slot system_slot_;
507*6777b538SAndroid Build Coastguard Worker   std::map<std::string, std::unique_ptr<ChromeOSUserData>> chromeos_user_map_;
508*6777b538SAndroid Build Coastguard Worker   ScopedPK11Slot prepared_test_private_slot_;
509*6777b538SAndroid Build Coastguard Worker 
510*6777b538SAndroid Build Coastguard Worker   THREAD_CHECKER(thread_checker_);
511*6777b538SAndroid Build Coastguard Worker };
512*6777b538SAndroid Build Coastguard Worker 
513*6777b538SAndroid Build Coastguard Worker base::LazyInstance<ChromeOSTokenManager>::Leaky g_token_manager =
514*6777b538SAndroid Build Coastguard Worker     LAZY_INSTANCE_INITIALIZER;
515*6777b538SAndroid Build Coastguard Worker }  // namespace
516*6777b538SAndroid Build Coastguard Worker 
GetSoftwareNSSDBPath(const base::FilePath & profile_directory_path)517*6777b538SAndroid Build Coastguard Worker base::FilePath GetSoftwareNSSDBPath(
518*6777b538SAndroid Build Coastguard Worker     const base::FilePath& profile_directory_path) {
519*6777b538SAndroid Build Coastguard Worker   return profile_directory_path.AppendASCII(".pki").AppendASCII("nssdb");
520*6777b538SAndroid Build Coastguard Worker }
521*6777b538SAndroid Build Coastguard Worker 
GetSystemNSSKeySlot(base::OnceCallback<void (ScopedPK11Slot)> callback)522*6777b538SAndroid Build Coastguard Worker void GetSystemNSSKeySlot(base::OnceCallback<void(ScopedPK11Slot)> callback) {
523*6777b538SAndroid Build Coastguard Worker   g_token_manager.Get().GetSystemNSSKeySlot(std::move(callback));
524*6777b538SAndroid Build Coastguard Worker }
525*6777b538SAndroid Build Coastguard Worker 
PrepareSystemSlotForTesting(ScopedPK11Slot slot)526*6777b538SAndroid Build Coastguard Worker void PrepareSystemSlotForTesting(ScopedPK11Slot slot) {
527*6777b538SAndroid Build Coastguard Worker   DCHECK(!ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot);
528*6777b538SAndroid Build Coastguard Worker   DCHECK(!g_token_manager.IsCreated() ||
529*6777b538SAndroid Build Coastguard Worker          !g_token_manager.Get().IsInitializationStarted())
530*6777b538SAndroid Build Coastguard Worker       << "PrepareSystemSlotForTesting is called after initialization started";
531*6777b538SAndroid Build Coastguard Worker 
532*6777b538SAndroid Build Coastguard Worker   ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot =
533*6777b538SAndroid Build Coastguard Worker       std::move(slot);
534*6777b538SAndroid Build Coastguard Worker }
535*6777b538SAndroid Build Coastguard Worker 
ResetSystemSlotForTesting()536*6777b538SAndroid Build Coastguard Worker void ResetSystemSlotForTesting() {
537*6777b538SAndroid Build Coastguard Worker   if (g_token_manager.IsCreated()) {
538*6777b538SAndroid Build Coastguard Worker     g_token_manager.Get().ResetSystemSlotForTesting();  // IN-TEST
539*6777b538SAndroid Build Coastguard Worker   }
540*6777b538SAndroid Build Coastguard Worker   ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot.reset();
541*6777b538SAndroid Build Coastguard Worker }
542*6777b538SAndroid Build Coastguard Worker 
ResetTokenManagerForTesting()543*6777b538SAndroid Build Coastguard Worker void ResetTokenManagerForTesting() {
544*6777b538SAndroid Build Coastguard Worker   if (g_token_manager.IsCreated()) {
545*6777b538SAndroid Build Coastguard Worker     g_token_manager.Get().ResetTokenManagerForTesting();  // IN-TEST
546*6777b538SAndroid Build Coastguard Worker   }
547*6777b538SAndroid Build Coastguard Worker   ResetSystemSlotForTesting();  // IN-TEST
548*6777b538SAndroid Build Coastguard Worker }
549*6777b538SAndroid Build Coastguard Worker 
IsTPMTokenEnabled(base::OnceCallback<void (bool)> callback)550*6777b538SAndroid Build Coastguard Worker void IsTPMTokenEnabled(base::OnceCallback<void(bool)> callback) {
551*6777b538SAndroid Build Coastguard Worker   g_token_manager.Get().IsTPMTokenEnabled(std::move(callback));
552*6777b538SAndroid Build Coastguard Worker }
553*6777b538SAndroid Build Coastguard Worker 
InitializeTPMTokenAndSystemSlot(int token_slot_id,base::OnceCallback<void (bool)> callback)554*6777b538SAndroid Build Coastguard Worker void InitializeTPMTokenAndSystemSlot(int token_slot_id,
555*6777b538SAndroid Build Coastguard Worker                                      base::OnceCallback<void(bool)> callback) {
556*6777b538SAndroid Build Coastguard Worker   g_token_manager.Get().InitializeTPMTokenAndSystemSlot(token_slot_id,
557*6777b538SAndroid Build Coastguard Worker                                                         std::move(callback));
558*6777b538SAndroid Build Coastguard Worker }
559*6777b538SAndroid Build Coastguard Worker 
FinishInitializingTPMTokenAndSystemSlot()560*6777b538SAndroid Build Coastguard Worker void FinishInitializingTPMTokenAndSystemSlot() {
561*6777b538SAndroid Build Coastguard Worker   g_token_manager.Get().FinishInitializingTPMTokenAndSystemSlot();
562*6777b538SAndroid Build Coastguard Worker }
563*6777b538SAndroid Build Coastguard Worker 
InitializeNSSForChromeOSUser(const std::string & username_hash,const base::FilePath & path)564*6777b538SAndroid Build Coastguard Worker bool InitializeNSSForChromeOSUser(const std::string& username_hash,
565*6777b538SAndroid Build Coastguard Worker                                   const base::FilePath& path) {
566*6777b538SAndroid Build Coastguard Worker   return g_token_manager.Get().InitializeNSSForChromeOSUser(username_hash,
567*6777b538SAndroid Build Coastguard Worker                                                             path);
568*6777b538SAndroid Build Coastguard Worker }
569*6777b538SAndroid Build Coastguard Worker 
InitializeNSSForChromeOSUserWithSlot(const std::string & username_hash,ScopedPK11Slot public_slot)570*6777b538SAndroid Build Coastguard Worker bool InitializeNSSForChromeOSUserWithSlot(const std::string& username_hash,
571*6777b538SAndroid Build Coastguard Worker                                           ScopedPK11Slot public_slot) {
572*6777b538SAndroid Build Coastguard Worker   return g_token_manager.Get().InitializeNSSForChromeOSUserWithSlot(
573*6777b538SAndroid Build Coastguard Worker       username_hash, std::move(public_slot));
574*6777b538SAndroid Build Coastguard Worker }
575*6777b538SAndroid Build Coastguard Worker 
ShouldInitializeTPMForChromeOSUser(const std::string & username_hash)576*6777b538SAndroid Build Coastguard Worker bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
577*6777b538SAndroid Build Coastguard Worker   return g_token_manager.Get().ShouldInitializeTPMForChromeOSUser(
578*6777b538SAndroid Build Coastguard Worker       username_hash);
579*6777b538SAndroid Build Coastguard Worker }
580*6777b538SAndroid Build Coastguard Worker 
WillInitializeTPMForChromeOSUser(const std::string & username_hash)581*6777b538SAndroid Build Coastguard Worker void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
582*6777b538SAndroid Build Coastguard Worker   g_token_manager.Get().WillInitializeTPMForChromeOSUser(username_hash);
583*6777b538SAndroid Build Coastguard Worker }
584*6777b538SAndroid Build Coastguard Worker 
InitializeTPMForChromeOSUser(const std::string & username_hash,CK_SLOT_ID slot_id)585*6777b538SAndroid Build Coastguard Worker void InitializeTPMForChromeOSUser(const std::string& username_hash,
586*6777b538SAndroid Build Coastguard Worker                                   CK_SLOT_ID slot_id) {
587*6777b538SAndroid Build Coastguard Worker   g_token_manager.Get().InitializeTPMForChromeOSUser(username_hash, slot_id);
588*6777b538SAndroid Build Coastguard Worker }
589*6777b538SAndroid Build Coastguard Worker 
InitializePrivateSoftwareSlotForChromeOSUser(const std::string & username_hash)590*6777b538SAndroid Build Coastguard Worker void InitializePrivateSoftwareSlotForChromeOSUser(
591*6777b538SAndroid Build Coastguard Worker     const std::string& username_hash) {
592*6777b538SAndroid Build Coastguard Worker   g_token_manager.Get().InitializePrivateSoftwareSlotForChromeOSUser(
593*6777b538SAndroid Build Coastguard Worker       username_hash);
594*6777b538SAndroid Build Coastguard Worker }
595*6777b538SAndroid Build Coastguard Worker 
GetPublicSlotForChromeOSUser(const std::string & username_hash)596*6777b538SAndroid Build Coastguard Worker ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) {
597*6777b538SAndroid Build Coastguard Worker   return g_token_manager.Get().GetPublicSlotForChromeOSUser(username_hash);
598*6777b538SAndroid Build Coastguard Worker }
599*6777b538SAndroid Build Coastguard Worker 
GetPrivateSlotForChromeOSUser(const std::string & username_hash,base::OnceCallback<void (ScopedPK11Slot)> callback)600*6777b538SAndroid Build Coastguard Worker ScopedPK11Slot GetPrivateSlotForChromeOSUser(
601*6777b538SAndroid Build Coastguard Worker     const std::string& username_hash,
602*6777b538SAndroid Build Coastguard Worker     base::OnceCallback<void(ScopedPK11Slot)> callback) {
603*6777b538SAndroid Build Coastguard Worker   return g_token_manager.Get().GetPrivateSlotForChromeOSUser(
604*6777b538SAndroid Build Coastguard Worker       username_hash, std::move(callback));
605*6777b538SAndroid Build Coastguard Worker }
606*6777b538SAndroid Build Coastguard Worker 
CloseChromeOSUserForTesting(const std::string & username_hash)607*6777b538SAndroid Build Coastguard Worker void CloseChromeOSUserForTesting(const std::string& username_hash) {
608*6777b538SAndroid Build Coastguard Worker   g_token_manager.Get().CloseChromeOSUserForTesting(username_hash);
609*6777b538SAndroid Build Coastguard Worker }
610*6777b538SAndroid Build Coastguard Worker 
SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot)611*6777b538SAndroid Build Coastguard Worker void SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot) {
612*6777b538SAndroid Build Coastguard Worker   g_token_manager.Get().SetPrivateSoftwareSlotForChromeOSUserForTesting(
613*6777b538SAndroid Build Coastguard Worker       std::move(slot));
614*6777b538SAndroid Build Coastguard Worker }
615*6777b538SAndroid Build Coastguard Worker 
616*6777b538SAndroid Build Coastguard Worker namespace {
PrintDirectoryInfo(const base::FilePath & path)617*6777b538SAndroid Build Coastguard Worker void PrintDirectoryInfo(const base::FilePath& path) {
618*6777b538SAndroid Build Coastguard Worker   base::stat_wrapper_t file_stat;
619*6777b538SAndroid Build Coastguard Worker 
620*6777b538SAndroid Build Coastguard Worker   if (base::File::Stat(path.value().c_str(), &file_stat) == -1) {
621*6777b538SAndroid Build Coastguard Worker     base::File::Error error_code = base::File::OSErrorToFileError(errno);
622*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to collect directory info, error: " << error_code;
623*6777b538SAndroid Build Coastguard Worker   }
624*6777b538SAndroid Build Coastguard Worker 
625*6777b538SAndroid Build Coastguard Worker   LOG(ERROR) << path << ", " << std::oct << file_stat.st_mode << std::dec
626*6777b538SAndroid Build Coastguard Worker              << ", "
627*6777b538SAndroid Build Coastguard Worker              << "uid " << file_stat.st_uid << ", "
628*6777b538SAndroid Build Coastguard Worker              << "gid " << file_stat.st_gid << std::endl;
629*6777b538SAndroid Build Coastguard Worker }
630*6777b538SAndroid Build Coastguard Worker }  // namespace
631*6777b538SAndroid Build Coastguard Worker 
632*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1163303): Remove when the bug is fixed.
DiagnosePublicSlotAndCrash(const base::FilePath & nss_path)633*6777b538SAndroid Build Coastguard Worker void DiagnosePublicSlotAndCrash(const base::FilePath& nss_path) {
634*6777b538SAndroid Build Coastguard Worker   LOG(ERROR) << "Public slot is invalid. Start collecting stats.";
635*6777b538SAndroid Build Coastguard Worker   // Should be something like /home/chronos/u-<hash>/.pki/nssdb .
636*6777b538SAndroid Build Coastguard Worker   LOG(ERROR) << "NSS path: " << nss_path;
637*6777b538SAndroid Build Coastguard Worker 
638*6777b538SAndroid Build Coastguard Worker   {
639*6777b538SAndroid Build Coastguard Worker     // NSS files like pkcs11.txt, cert9.db, key4.db .
640*6777b538SAndroid Build Coastguard Worker     base::FileEnumerator files(
641*6777b538SAndroid Build Coastguard Worker         nss_path, /*recursive=*/false,
642*6777b538SAndroid Build Coastguard Worker         /*file_type=*/base::FileEnumerator::FILES,
643*6777b538SAndroid Build Coastguard Worker         /*pattern=*/base::FilePath::StringType(),
644*6777b538SAndroid Build Coastguard Worker         base::FileEnumerator::FolderSearchPolicy::MATCH_ONLY,
645*6777b538SAndroid Build Coastguard Worker         base::FileEnumerator::ErrorPolicy::STOP_ENUMERATION);
646*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "Public slot database files:";
647*6777b538SAndroid Build Coastguard Worker     for (base::FilePath path = files.Next(); !path.empty();
648*6777b538SAndroid Build Coastguard Worker          path = files.Next()) {
649*6777b538SAndroid Build Coastguard Worker       base::FileEnumerator::FileInfo file_info = files.GetInfo();
650*6777b538SAndroid Build Coastguard Worker 
651*6777b538SAndroid Build Coastguard Worker       char buf[16];
652*6777b538SAndroid Build Coastguard Worker       int read_result = base::ReadFile(path, buf, sizeof(buf) - 1);
653*6777b538SAndroid Build Coastguard Worker 
654*6777b538SAndroid Build Coastguard Worker       LOG(ERROR) << file_info.GetName() << ", " << std::oct
655*6777b538SAndroid Build Coastguard Worker                  << file_info.stat().st_mode << std::dec << ", "
656*6777b538SAndroid Build Coastguard Worker                  << "uid " << file_info.stat().st_uid << ", "
657*6777b538SAndroid Build Coastguard Worker                  << "gid " << file_info.stat().st_gid << ", "
658*6777b538SAndroid Build Coastguard Worker                  << file_info.stat().st_size << " bytes, "
659*6777b538SAndroid Build Coastguard Worker                  << ((read_result > 0) ? "readable" : "not readable");
660*6777b538SAndroid Build Coastguard Worker     }
661*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "Enumerate error code: " << files.GetError();
662*6777b538SAndroid Build Coastguard Worker   }
663*6777b538SAndroid Build Coastguard Worker 
664*6777b538SAndroid Build Coastguard Worker   // NSS directory might not be created yet, also check parent directories.
665*6777b538SAndroid Build Coastguard Worker   // Use u-hash directory as a comparison point for user and group ids and
666*6777b538SAndroid Build Coastguard Worker   // access permissions.
667*6777b538SAndroid Build Coastguard Worker 
668*6777b538SAndroid Build Coastguard Worker   base::FilePath nssdb_path = nss_path.Append(base::FilePath::kParentDirectory);
669*6777b538SAndroid Build Coastguard Worker   PrintDirectoryInfo(nssdb_path);
670*6777b538SAndroid Build Coastguard Worker 
671*6777b538SAndroid Build Coastguard Worker   base::FilePath pki_path = nssdb_path.Append(base::FilePath::kParentDirectory);
672*6777b538SAndroid Build Coastguard Worker   PrintDirectoryInfo(pki_path);
673*6777b538SAndroid Build Coastguard Worker 
674*6777b538SAndroid Build Coastguard Worker   base::FilePath u_hash_path =
675*6777b538SAndroid Build Coastguard Worker       pki_path.Append(base::FilePath::kParentDirectory);
676*6777b538SAndroid Build Coastguard Worker   PrintDirectoryInfo(u_hash_path);
677*6777b538SAndroid Build Coastguard Worker 
678*6777b538SAndroid Build Coastguard Worker   {
679*6777b538SAndroid Build Coastguard Worker     // Check whether the NSS path exists, and if not, check whether it's
680*6777b538SAndroid Build Coastguard Worker     // possible to create it.
681*6777b538SAndroid Build Coastguard Worker     if (base::DirectoryExists(nss_path)) {
682*6777b538SAndroid Build Coastguard Worker       LOG(ERROR) << "NSS path exists (as expected).";
683*6777b538SAndroid Build Coastguard Worker     } else {
684*6777b538SAndroid Build Coastguard Worker       base::File::Error error = base::File::Error::FILE_OK;
685*6777b538SAndroid Build Coastguard Worker       if (base::CreateDirectoryAndGetError(nss_path, &error)) {
686*6777b538SAndroid Build Coastguard Worker         LOG(ERROR) << "NSS path didn't exist. Created successfully.";
687*6777b538SAndroid Build Coastguard Worker       } else {
688*6777b538SAndroid Build Coastguard Worker         LOG(ERROR) << "NSS path didn't exist. Failed to create, error: "
689*6777b538SAndroid Build Coastguard Worker                    << error;
690*6777b538SAndroid Build Coastguard Worker       }
691*6777b538SAndroid Build Coastguard Worker     }
692*6777b538SAndroid Build Coastguard Worker   }
693*6777b538SAndroid Build Coastguard Worker 
694*6777b538SAndroid Build Coastguard Worker   CHECK(false) << "Public slot is invalid.";
695*6777b538SAndroid Build Coastguard Worker }
696*6777b538SAndroid Build Coastguard Worker 
697*6777b538SAndroid Build Coastguard Worker }  // namespace crypto
698