xref: /aosp_15_r20/external/libchrome/crypto/nss_util.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "crypto/nss_util.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <nss.h>
8*635a8641SAndroid Build Coastguard Worker #include <pk11pub.h>
9*635a8641SAndroid Build Coastguard Worker #include <plarena.h>
10*635a8641SAndroid Build Coastguard Worker #include <prerror.h>
11*635a8641SAndroid Build Coastguard Worker #include <prinit.h>
12*635a8641SAndroid Build Coastguard Worker #include <prtime.h>
13*635a8641SAndroid Build Coastguard Worker #include <secmod.h>
14*635a8641SAndroid Build Coastguard Worker 
15*635a8641SAndroid Build Coastguard Worker #include <map>
16*635a8641SAndroid Build Coastguard Worker #include <memory>
17*635a8641SAndroid Build Coastguard Worker #include <utility>
18*635a8641SAndroid Build Coastguard Worker #include <vector>
19*635a8641SAndroid Build Coastguard Worker 
20*635a8641SAndroid Build Coastguard Worker #include "base/base_paths.h"
21*635a8641SAndroid Build Coastguard Worker #include "base/bind.h"
22*635a8641SAndroid Build Coastguard Worker #include "base/debug/alias.h"
23*635a8641SAndroid Build Coastguard Worker #include "base/debug/stack_trace.h"
24*635a8641SAndroid Build Coastguard Worker #include "base/files/file_path.h"
25*635a8641SAndroid Build Coastguard Worker #include "base/files/file_util.h"
26*635a8641SAndroid Build Coastguard Worker #include "base/lazy_instance.h"
27*635a8641SAndroid Build Coastguard Worker #include "base/location.h"
28*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
29*635a8641SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
30*635a8641SAndroid Build Coastguard Worker #include "base/path_service.h"
31*635a8641SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
32*635a8641SAndroid Build Coastguard Worker #include "base/task_scheduler/post_task.h"
33*635a8641SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
34*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_checker.h"
35*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
36*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_task_runner_handle.h"
37*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
38*635a8641SAndroid Build Coastguard Worker #include "crypto/nss_crypto_module_delegate.h"
39*635a8641SAndroid Build Coastguard Worker #include "crypto/nss_util_internal.h"
40*635a8641SAndroid Build Coastguard Worker 
41*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
42*635a8641SAndroid Build Coastguard Worker #include <dlfcn.h>
43*635a8641SAndroid Build Coastguard Worker #endif
44*635a8641SAndroid Build Coastguard Worker 
45*635a8641SAndroid Build Coastguard Worker namespace crypto {
46*635a8641SAndroid Build Coastguard Worker 
47*635a8641SAndroid Build Coastguard Worker namespace {
48*635a8641SAndroid Build Coastguard Worker 
49*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
50*635a8641SAndroid Build Coastguard Worker const char kUserNSSDatabaseName[] = "UserNSSDB";
51*635a8641SAndroid Build Coastguard Worker 
52*635a8641SAndroid Build Coastguard Worker // Constants for loading the Chrome OS TPM-backed PKCS #11 library.
53*635a8641SAndroid Build Coastguard Worker const char kChapsModuleName[] = "Chaps";
54*635a8641SAndroid Build Coastguard Worker const char kChapsPath[] = "libchaps.so";
55*635a8641SAndroid Build Coastguard Worker 
56*635a8641SAndroid Build Coastguard Worker // Fake certificate authority database used for testing.
57*635a8641SAndroid Build Coastguard Worker static const base::FilePath::CharType kReadOnlyCertDB[] =
58*635a8641SAndroid Build Coastguard Worker     FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb");
59*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
60*635a8641SAndroid Build Coastguard Worker 
GetNSSErrorMessage()61*635a8641SAndroid Build Coastguard Worker std::string GetNSSErrorMessage() {
62*635a8641SAndroid Build Coastguard Worker   std::string result;
63*635a8641SAndroid Build Coastguard Worker   if (PR_GetErrorTextLength()) {
64*635a8641SAndroid Build Coastguard Worker     std::unique_ptr<char[]> error_text(new char[PR_GetErrorTextLength() + 1]);
65*635a8641SAndroid Build Coastguard Worker     PRInt32 copied = PR_GetErrorText(error_text.get());
66*635a8641SAndroid Build Coastguard Worker     result = std::string(error_text.get(), copied);
67*635a8641SAndroid Build Coastguard Worker   } else {
68*635a8641SAndroid Build Coastguard Worker     result = base::StringPrintf("NSS error code: %d", PR_GetError());
69*635a8641SAndroid Build Coastguard Worker   }
70*635a8641SAndroid Build Coastguard Worker   return result;
71*635a8641SAndroid Build Coastguard Worker }
72*635a8641SAndroid Build Coastguard Worker 
73*635a8641SAndroid Build Coastguard Worker #if !defined(OS_CHROMEOS)
GetDefaultConfigDirectory()74*635a8641SAndroid Build Coastguard Worker base::FilePath GetDefaultConfigDirectory() {
75*635a8641SAndroid Build Coastguard Worker   base::FilePath dir;
76*635a8641SAndroid Build Coastguard Worker   base::PathService::Get(base::DIR_HOME, &dir);
77*635a8641SAndroid Build Coastguard Worker   if (dir.empty()) {
78*635a8641SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to get home directory.";
79*635a8641SAndroid Build Coastguard Worker     return dir;
80*635a8641SAndroid Build Coastguard Worker   }
81*635a8641SAndroid Build Coastguard Worker   dir = dir.AppendASCII(".pki").AppendASCII("nssdb");
82*635a8641SAndroid Build Coastguard Worker   if (!base::CreateDirectory(dir)) {
83*635a8641SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to create " << dir.value() << " directory.";
84*635a8641SAndroid Build Coastguard Worker     dir.clear();
85*635a8641SAndroid Build Coastguard Worker   }
86*635a8641SAndroid Build Coastguard Worker   DVLOG(2) << "DefaultConfigDirectory: " << dir.value();
87*635a8641SAndroid Build Coastguard Worker   return dir;
88*635a8641SAndroid Build Coastguard Worker }
89*635a8641SAndroid Build Coastguard Worker #endif  // !defined(OS_CHROMEOS)
90*635a8641SAndroid Build Coastguard Worker 
91*635a8641SAndroid Build Coastguard Worker // On non-Chrome OS platforms, return the default config directory. On Chrome OS
92*635a8641SAndroid Build Coastguard Worker // test images, return a read-only directory with fake root CA certs (which are
93*635a8641SAndroid Build Coastguard Worker // used by the local Google Accounts server mock we use when testing our login
94*635a8641SAndroid Build Coastguard Worker // code). On Chrome OS non-test images (where the read-only directory doesn't
95*635a8641SAndroid Build Coastguard Worker // exist), return an empty path.
GetInitialConfigDirectory()96*635a8641SAndroid Build Coastguard Worker base::FilePath GetInitialConfigDirectory() {
97*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
98*635a8641SAndroid Build Coastguard Worker   base::FilePath database_dir = base::FilePath(kReadOnlyCertDB);
99*635a8641SAndroid Build Coastguard Worker   if (!base::PathExists(database_dir))
100*635a8641SAndroid Build Coastguard Worker     database_dir.clear();
101*635a8641SAndroid Build Coastguard Worker   return database_dir;
102*635a8641SAndroid Build Coastguard Worker #else
103*635a8641SAndroid Build Coastguard Worker   return GetDefaultConfigDirectory();
104*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
105*635a8641SAndroid Build Coastguard Worker }
106*635a8641SAndroid Build Coastguard Worker 
107*635a8641SAndroid Build Coastguard Worker // This callback for NSS forwards all requests to a caller-specified
108*635a8641SAndroid Build Coastguard Worker // CryptoModuleBlockingPasswordDelegate object.
PKCS11PasswordFunc(PK11SlotInfo * slot,PRBool retry,void * arg)109*635a8641SAndroid Build Coastguard Worker char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) {
110*635a8641SAndroid Build Coastguard Worker   crypto::CryptoModuleBlockingPasswordDelegate* delegate =
111*635a8641SAndroid Build Coastguard Worker       reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg);
112*635a8641SAndroid Build Coastguard Worker   if (delegate) {
113*635a8641SAndroid Build Coastguard Worker     bool cancelled = false;
114*635a8641SAndroid Build Coastguard Worker     std::string password = delegate->RequestPassword(PK11_GetTokenName(slot),
115*635a8641SAndroid Build Coastguard Worker                                                      retry != PR_FALSE,
116*635a8641SAndroid Build Coastguard Worker                                                      &cancelled);
117*635a8641SAndroid Build Coastguard Worker     if (cancelled)
118*635a8641SAndroid Build Coastguard Worker       return nullptr;
119*635a8641SAndroid Build Coastguard Worker     char* result = PORT_Strdup(password.c_str());
120*635a8641SAndroid Build Coastguard Worker     password.replace(0, password.size(), password.size(), 0);
121*635a8641SAndroid Build Coastguard Worker     return result;
122*635a8641SAndroid Build Coastguard Worker   }
123*635a8641SAndroid Build Coastguard Worker   DLOG(ERROR) << "PK11 password requested with nullptr arg";
124*635a8641SAndroid Build Coastguard Worker   return nullptr;
125*635a8641SAndroid Build Coastguard Worker }
126*635a8641SAndroid Build Coastguard Worker 
127*635a8641SAndroid Build Coastguard Worker // A singleton to initialize/deinitialize NSPR.
128*635a8641SAndroid Build Coastguard Worker // Separate from the NSS singleton because we initialize NSPR on the UI thread.
129*635a8641SAndroid Build Coastguard Worker // Now that we're leaking the singleton, we could merge back with the NSS
130*635a8641SAndroid Build Coastguard Worker // singleton.
131*635a8641SAndroid Build Coastguard Worker class NSPRInitSingleton {
132*635a8641SAndroid Build Coastguard Worker  private:
133*635a8641SAndroid Build Coastguard Worker   friend struct base::LazyInstanceTraitsBase<NSPRInitSingleton>;
134*635a8641SAndroid Build Coastguard Worker 
NSPRInitSingleton()135*635a8641SAndroid Build Coastguard Worker   NSPRInitSingleton() {
136*635a8641SAndroid Build Coastguard Worker     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
137*635a8641SAndroid Build Coastguard Worker   }
138*635a8641SAndroid Build Coastguard Worker 
139*635a8641SAndroid Build Coastguard Worker   // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS
140*635a8641SAndroid Build Coastguard Worker   // to prevent non-joinable threads from using NSS after it's already been
141*635a8641SAndroid Build Coastguard Worker   // shut down.
142*635a8641SAndroid Build Coastguard Worker   ~NSPRInitSingleton() = delete;
143*635a8641SAndroid Build Coastguard Worker };
144*635a8641SAndroid Build Coastguard Worker 
145*635a8641SAndroid Build Coastguard Worker base::LazyInstance<NSPRInitSingleton>::Leaky
146*635a8641SAndroid Build Coastguard Worker     g_nspr_singleton = LAZY_INSTANCE_INITIALIZER;
147*635a8641SAndroid Build Coastguard Worker 
148*635a8641SAndroid Build Coastguard Worker // Force a crash with error info on NSS_NoDB_Init failure.
CrashOnNSSInitFailure()149*635a8641SAndroid Build Coastguard Worker void CrashOnNSSInitFailure() {
150*635a8641SAndroid Build Coastguard Worker   int nss_error = PR_GetError();
151*635a8641SAndroid Build Coastguard Worker   int os_error = PR_GetOSError();
152*635a8641SAndroid Build Coastguard Worker   base::debug::Alias(&nss_error);
153*635a8641SAndroid Build Coastguard Worker   base::debug::Alias(&os_error);
154*635a8641SAndroid Build Coastguard Worker   LOG(ERROR) << "Error initializing NSS without a persistent database: "
155*635a8641SAndroid Build Coastguard Worker              << GetNSSErrorMessage();
156*635a8641SAndroid Build Coastguard Worker   LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error;
157*635a8641SAndroid Build Coastguard Worker }
158*635a8641SAndroid Build Coastguard Worker 
159*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
160*635a8641SAndroid Build Coastguard Worker class ChromeOSUserData {
161*635a8641SAndroid Build Coastguard Worker  public:
ChromeOSUserData(ScopedPK11Slot public_slot)162*635a8641SAndroid Build Coastguard Worker   explicit ChromeOSUserData(ScopedPK11Slot public_slot)
163*635a8641SAndroid Build Coastguard Worker       : public_slot_(std::move(public_slot)),
164*635a8641SAndroid Build Coastguard Worker         private_slot_initialization_started_(false) {}
~ChromeOSUserData()165*635a8641SAndroid Build Coastguard Worker   ~ChromeOSUserData() {
166*635a8641SAndroid Build Coastguard Worker     if (public_slot_) {
167*635a8641SAndroid Build Coastguard Worker       SECStatus status = SECMOD_CloseUserDB(public_slot_.get());
168*635a8641SAndroid Build Coastguard Worker       if (status != SECSuccess)
169*635a8641SAndroid Build Coastguard Worker         PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
170*635a8641SAndroid Build Coastguard Worker     }
171*635a8641SAndroid Build Coastguard Worker   }
172*635a8641SAndroid Build Coastguard Worker 
GetPublicSlot()173*635a8641SAndroid Build Coastguard Worker   ScopedPK11Slot GetPublicSlot() {
174*635a8641SAndroid Build Coastguard Worker     return ScopedPK11Slot(public_slot_ ? PK11_ReferenceSlot(public_slot_.get())
175*635a8641SAndroid Build Coastguard Worker                                        : nullptr);
176*635a8641SAndroid Build Coastguard Worker   }
177*635a8641SAndroid Build Coastguard Worker 
GetPrivateSlot(base::OnceCallback<void (ScopedPK11Slot)> callback)178*635a8641SAndroid Build Coastguard Worker   ScopedPK11Slot GetPrivateSlot(
179*635a8641SAndroid Build Coastguard Worker       base::OnceCallback<void(ScopedPK11Slot)> callback) {
180*635a8641SAndroid Build Coastguard Worker     if (private_slot_)
181*635a8641SAndroid Build Coastguard Worker       return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()));
182*635a8641SAndroid Build Coastguard Worker     if (!callback.is_null())
183*635a8641SAndroid Build Coastguard Worker       tpm_ready_callback_list_.push_back(std::move(callback));
184*635a8641SAndroid Build Coastguard Worker     return ScopedPK11Slot();
185*635a8641SAndroid Build Coastguard Worker   }
186*635a8641SAndroid Build Coastguard Worker 
SetPrivateSlot(ScopedPK11Slot private_slot)187*635a8641SAndroid Build Coastguard Worker   void SetPrivateSlot(ScopedPK11Slot private_slot) {
188*635a8641SAndroid Build Coastguard Worker     DCHECK(!private_slot_);
189*635a8641SAndroid Build Coastguard Worker     private_slot_ = std::move(private_slot);
190*635a8641SAndroid Build Coastguard Worker 
191*635a8641SAndroid Build Coastguard Worker     SlotReadyCallbackList callback_list;
192*635a8641SAndroid Build Coastguard Worker     callback_list.swap(tpm_ready_callback_list_);
193*635a8641SAndroid Build Coastguard Worker     for (SlotReadyCallbackList::iterator i = callback_list.begin();
194*635a8641SAndroid Build Coastguard Worker          i != callback_list.end();
195*635a8641SAndroid Build Coastguard Worker          ++i) {
196*635a8641SAndroid Build Coastguard Worker       std::move(*i).Run(
197*635a8641SAndroid Build Coastguard Worker           ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())));
198*635a8641SAndroid Build Coastguard Worker     }
199*635a8641SAndroid Build Coastguard Worker   }
200*635a8641SAndroid Build Coastguard Worker 
private_slot_initialization_started() const201*635a8641SAndroid Build Coastguard Worker   bool private_slot_initialization_started() const {
202*635a8641SAndroid Build Coastguard Worker       return private_slot_initialization_started_;
203*635a8641SAndroid Build Coastguard Worker   }
204*635a8641SAndroid Build Coastguard Worker 
set_private_slot_initialization_started()205*635a8641SAndroid Build Coastguard Worker   void set_private_slot_initialization_started() {
206*635a8641SAndroid Build Coastguard Worker       private_slot_initialization_started_ = true;
207*635a8641SAndroid Build Coastguard Worker   }
208*635a8641SAndroid Build Coastguard Worker 
209*635a8641SAndroid Build Coastguard Worker  private:
210*635a8641SAndroid Build Coastguard Worker   ScopedPK11Slot public_slot_;
211*635a8641SAndroid Build Coastguard Worker   ScopedPK11Slot private_slot_;
212*635a8641SAndroid Build Coastguard Worker 
213*635a8641SAndroid Build Coastguard Worker   bool private_slot_initialization_started_;
214*635a8641SAndroid Build Coastguard Worker 
215*635a8641SAndroid Build Coastguard Worker   typedef std::vector<base::OnceCallback<void(ScopedPK11Slot)>>
216*635a8641SAndroid Build Coastguard Worker       SlotReadyCallbackList;
217*635a8641SAndroid Build Coastguard Worker   SlotReadyCallbackList tpm_ready_callback_list_;
218*635a8641SAndroid Build Coastguard Worker };
219*635a8641SAndroid Build Coastguard Worker 
220*635a8641SAndroid Build Coastguard Worker class ScopedChapsLoadFixup {
221*635a8641SAndroid Build Coastguard Worker  public:
222*635a8641SAndroid Build Coastguard Worker   ScopedChapsLoadFixup();
223*635a8641SAndroid Build Coastguard Worker   ~ScopedChapsLoadFixup();
224*635a8641SAndroid Build Coastguard Worker 
225*635a8641SAndroid Build Coastguard Worker  private:
226*635a8641SAndroid Build Coastguard Worker #if defined(COMPONENT_BUILD)
227*635a8641SAndroid Build Coastguard Worker   void* chaps_handle_;
228*635a8641SAndroid Build Coastguard Worker #endif
229*635a8641SAndroid Build Coastguard Worker };
230*635a8641SAndroid Build Coastguard Worker 
231*635a8641SAndroid Build Coastguard Worker #if defined(COMPONENT_BUILD)
232*635a8641SAndroid Build Coastguard Worker 
ScopedChapsLoadFixup()233*635a8641SAndroid Build Coastguard Worker ScopedChapsLoadFixup::ScopedChapsLoadFixup() {
234*635a8641SAndroid Build Coastguard Worker   // HACK: libchaps links the system protobuf and there are symbol conflicts
235*635a8641SAndroid Build Coastguard Worker   // with the bundled copy. Load chaps with RTLD_DEEPBIND to workaround.
236*635a8641SAndroid Build Coastguard Worker   chaps_handle_ = dlopen(kChapsPath, RTLD_LOCAL | RTLD_NOW | RTLD_DEEPBIND);
237*635a8641SAndroid Build Coastguard Worker }
238*635a8641SAndroid Build Coastguard Worker 
~ScopedChapsLoadFixup()239*635a8641SAndroid Build Coastguard Worker ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {
240*635a8641SAndroid Build Coastguard Worker   // LoadModule() will have taken a 2nd reference.
241*635a8641SAndroid Build Coastguard Worker   if (chaps_handle_)
242*635a8641SAndroid Build Coastguard Worker     dlclose(chaps_handle_);
243*635a8641SAndroid Build Coastguard Worker }
244*635a8641SAndroid Build Coastguard Worker 
245*635a8641SAndroid Build Coastguard Worker #else
246*635a8641SAndroid Build Coastguard Worker 
ScopedChapsLoadFixup()247*635a8641SAndroid Build Coastguard Worker ScopedChapsLoadFixup::ScopedChapsLoadFixup() {}
~ScopedChapsLoadFixup()248*635a8641SAndroid Build Coastguard Worker ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {}
249*635a8641SAndroid Build Coastguard Worker 
250*635a8641SAndroid Build Coastguard Worker #endif  // defined(COMPONENT_BUILD)
251*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
252*635a8641SAndroid Build Coastguard Worker 
253*635a8641SAndroid Build Coastguard Worker class NSSInitSingleton {
254*635a8641SAndroid Build Coastguard Worker  public:
255*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
256*635a8641SAndroid Build Coastguard Worker   // Used with PostTaskAndReply to pass handles to worker thread and back.
257*635a8641SAndroid Build Coastguard Worker   struct TPMModuleAndSlot {
TPMModuleAndSlotcrypto::__anon1d0ef6600111::NSSInitSingleton::TPMModuleAndSlot258*635a8641SAndroid Build Coastguard Worker     explicit TPMModuleAndSlot(SECMODModule* init_chaps_module)
259*635a8641SAndroid Build Coastguard Worker         : chaps_module(init_chaps_module) {}
260*635a8641SAndroid Build Coastguard Worker     SECMODModule* chaps_module;
261*635a8641SAndroid Build Coastguard Worker     crypto::ScopedPK11Slot tpm_slot;
262*635a8641SAndroid Build Coastguard Worker   };
263*635a8641SAndroid Build Coastguard Worker 
OpenPersistentNSSDBForPath(const std::string & db_name,const base::FilePath & path)264*635a8641SAndroid Build Coastguard Worker   ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name,
265*635a8641SAndroid Build Coastguard Worker                                             const base::FilePath& path) {
266*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
267*635a8641SAndroid Build Coastguard Worker     // NSS is allowed to do IO on the current thread since dispatching
268*635a8641SAndroid Build Coastguard Worker     // to a dedicated thread would still have the affect of blocking
269*635a8641SAndroid Build Coastguard Worker     // the current thread, due to NSS's internal locking requirements
270*635a8641SAndroid Build Coastguard Worker     base::ThreadRestrictions::ScopedAllowIO allow_io;
271*635a8641SAndroid Build Coastguard Worker 
272*635a8641SAndroid Build Coastguard Worker     base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb");
273*635a8641SAndroid Build Coastguard Worker     if (!base::CreateDirectory(nssdb_path)) {
274*635a8641SAndroid Build Coastguard Worker       LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory.";
275*635a8641SAndroid Build Coastguard Worker       return ScopedPK11Slot();
276*635a8641SAndroid Build Coastguard Worker     }
277*635a8641SAndroid Build Coastguard Worker     return OpenSoftwareNSSDB(nssdb_path, db_name);
278*635a8641SAndroid Build Coastguard Worker   }
279*635a8641SAndroid Build Coastguard Worker 
EnableTPMTokenForNSS()280*635a8641SAndroid Build Coastguard Worker   void EnableTPMTokenForNSS() {
281*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
282*635a8641SAndroid Build Coastguard Worker 
283*635a8641SAndroid Build Coastguard Worker     // If this gets set, then we'll use the TPM for certs with
284*635a8641SAndroid Build Coastguard Worker     // private keys, otherwise we'll fall back to the software
285*635a8641SAndroid Build Coastguard Worker     // implementation.
286*635a8641SAndroid Build Coastguard Worker     tpm_token_enabled_for_nss_ = true;
287*635a8641SAndroid Build Coastguard Worker   }
288*635a8641SAndroid Build Coastguard Worker 
IsTPMTokenEnabledForNSS()289*635a8641SAndroid Build Coastguard Worker   bool IsTPMTokenEnabledForNSS() {
290*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
291*635a8641SAndroid Build Coastguard Worker     return tpm_token_enabled_for_nss_;
292*635a8641SAndroid Build Coastguard Worker   }
293*635a8641SAndroid Build Coastguard Worker 
InitializeTPMTokenAndSystemSlot(int system_slot_id,base::OnceCallback<void (bool)> callback)294*635a8641SAndroid Build Coastguard Worker   void InitializeTPMTokenAndSystemSlot(
295*635a8641SAndroid Build Coastguard Worker       int system_slot_id,
296*635a8641SAndroid Build Coastguard Worker       base::OnceCallback<void(bool)> callback) {
297*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
298*635a8641SAndroid Build Coastguard Worker     // Should not be called while there is already an initialization in
299*635a8641SAndroid Build Coastguard Worker     // progress.
300*635a8641SAndroid Build Coastguard Worker     DCHECK(!initializing_tpm_token_);
301*635a8641SAndroid Build Coastguard Worker     // If EnableTPMTokenForNSS hasn't been called, return false.
302*635a8641SAndroid Build Coastguard Worker     if (!tpm_token_enabled_for_nss_) {
303*635a8641SAndroid Build Coastguard Worker       base::ThreadTaskRunnerHandle::Get()->PostTask(
304*635a8641SAndroid Build Coastguard Worker           FROM_HERE, base::BindOnce(std::move(callback), false));
305*635a8641SAndroid Build Coastguard Worker       return;
306*635a8641SAndroid Build Coastguard Worker     }
307*635a8641SAndroid Build Coastguard Worker 
308*635a8641SAndroid Build Coastguard Worker     // If everything is already initialized, then return true.
309*635a8641SAndroid Build Coastguard Worker     // Note that only |tpm_slot_| is checked, since |chaps_module_| could be
310*635a8641SAndroid Build Coastguard Worker     // nullptr in tests while |tpm_slot_| has been set to the test DB.
311*635a8641SAndroid Build Coastguard Worker     if (tpm_slot_) {
312*635a8641SAndroid Build Coastguard Worker       base::ThreadTaskRunnerHandle::Get()->PostTask(
313*635a8641SAndroid Build Coastguard Worker           FROM_HERE, base::BindOnce(std::move(callback), true));
314*635a8641SAndroid Build Coastguard Worker       return;
315*635a8641SAndroid Build Coastguard Worker     }
316*635a8641SAndroid Build Coastguard Worker 
317*635a8641SAndroid Build Coastguard Worker     // Note that a reference is not taken to chaps_module_. This is safe since
318*635a8641SAndroid Build Coastguard Worker     // NSSInitSingleton is Leaky, so the reference it holds is never released.
319*635a8641SAndroid Build Coastguard Worker     std::unique_ptr<TPMModuleAndSlot> tpm_args(
320*635a8641SAndroid Build Coastguard Worker         new TPMModuleAndSlot(chaps_module_));
321*635a8641SAndroid Build Coastguard Worker     TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
322*635a8641SAndroid Build Coastguard Worker     base::PostTaskWithTraitsAndReply(
323*635a8641SAndroid Build Coastguard Worker         FROM_HERE,
324*635a8641SAndroid Build Coastguard Worker         {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
325*635a8641SAndroid Build Coastguard Worker         base::BindOnce(&NSSInitSingleton::InitializeTPMTokenInThreadPool,
326*635a8641SAndroid Build Coastguard Worker                        system_slot_id, tpm_args_ptr),
327*635a8641SAndroid Build Coastguard Worker         base::BindOnce(&NSSInitSingleton::OnInitializedTPMTokenAndSystemSlot,
328*635a8641SAndroid Build Coastguard Worker                        base::Unretained(this),  // NSSInitSingleton is leaky
329*635a8641SAndroid Build Coastguard Worker                        std::move(callback), std::move(tpm_args)));
330*635a8641SAndroid Build Coastguard Worker     initializing_tpm_token_ = true;
331*635a8641SAndroid Build Coastguard Worker   }
332*635a8641SAndroid Build Coastguard Worker 
InitializeTPMTokenInThreadPool(CK_SLOT_ID token_slot_id,TPMModuleAndSlot * tpm_args)333*635a8641SAndroid Build Coastguard Worker   static void InitializeTPMTokenInThreadPool(CK_SLOT_ID token_slot_id,
334*635a8641SAndroid Build Coastguard Worker                                              TPMModuleAndSlot* tpm_args) {
335*635a8641SAndroid Build Coastguard Worker     // NSS functions may reenter //net via extension hooks. If the reentered
336*635a8641SAndroid Build Coastguard Worker     // code needs to synchronously wait for a task to run but the thread pool in
337*635a8641SAndroid Build Coastguard Worker     // which that task must run doesn't have enough threads to schedule it, a
338*635a8641SAndroid Build Coastguard Worker     // deadlock occurs. To prevent that, the base::ScopedBlockingCall below
339*635a8641SAndroid Build Coastguard Worker     // increments the thread pool capacity for the duration of the TPM
340*635a8641SAndroid Build Coastguard Worker     // initialization.
341*635a8641SAndroid Build Coastguard Worker     base::ScopedBlockingCall scoped_blocking_call(
342*635a8641SAndroid Build Coastguard Worker         base::BlockingType::WILL_BLOCK);
343*635a8641SAndroid Build Coastguard Worker 
344*635a8641SAndroid Build Coastguard Worker     if (!tpm_args->chaps_module) {
345*635a8641SAndroid Build Coastguard Worker       ScopedChapsLoadFixup chaps_loader;
346*635a8641SAndroid Build Coastguard Worker 
347*635a8641SAndroid Build Coastguard Worker       DVLOG(3) << "Loading chaps...";
348*635a8641SAndroid Build Coastguard Worker       tpm_args->chaps_module = LoadModule(
349*635a8641SAndroid Build Coastguard Worker           kChapsModuleName,
350*635a8641SAndroid Build Coastguard Worker           kChapsPath,
351*635a8641SAndroid Build Coastguard Worker           // For more details on these parameters, see:
352*635a8641SAndroid Build Coastguard Worker           // https://developer.mozilla.org/en/PKCS11_Module_Specs
353*635a8641SAndroid Build Coastguard Worker           // slotFlags=[PublicCerts] -- Certificates and public keys can be
354*635a8641SAndroid Build Coastguard Worker           //   read from this slot without requiring a call to C_Login.
355*635a8641SAndroid Build Coastguard Worker           // askpw=only -- Only authenticate to the token when necessary.
356*635a8641SAndroid Build Coastguard Worker           "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\"");
357*635a8641SAndroid Build Coastguard Worker     }
358*635a8641SAndroid Build Coastguard Worker     if (tpm_args->chaps_module) {
359*635a8641SAndroid Build Coastguard Worker       tpm_args->tpm_slot =
360*635a8641SAndroid Build Coastguard Worker           GetTPMSlotForIdInThreadPool(tpm_args->chaps_module, token_slot_id);
361*635a8641SAndroid Build Coastguard Worker     }
362*635a8641SAndroid Build Coastguard Worker   }
363*635a8641SAndroid Build Coastguard Worker 
OnInitializedTPMTokenAndSystemSlot(base::OnceCallback<void (bool)> callback,std::unique_ptr<TPMModuleAndSlot> tpm_args)364*635a8641SAndroid Build Coastguard Worker   void OnInitializedTPMTokenAndSystemSlot(
365*635a8641SAndroid Build Coastguard Worker       base::OnceCallback<void(bool)> callback,
366*635a8641SAndroid Build Coastguard Worker       std::unique_ptr<TPMModuleAndSlot> tpm_args) {
367*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
368*635a8641SAndroid Build Coastguard Worker     DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module
369*635a8641SAndroid Build Coastguard Worker              << ", got tpm slot: " << !!tpm_args->tpm_slot;
370*635a8641SAndroid Build Coastguard Worker 
371*635a8641SAndroid Build Coastguard Worker     chaps_module_ = tpm_args->chaps_module;
372*635a8641SAndroid Build Coastguard Worker     tpm_slot_ = std::move(tpm_args->tpm_slot);
373*635a8641SAndroid Build Coastguard Worker     if (!chaps_module_ && test_system_slot_) {
374*635a8641SAndroid Build Coastguard Worker       // chromeos_unittests try to test the TPM initialization process. If we
375*635a8641SAndroid Build Coastguard Worker       // have a test DB open, pretend that it is the TPM slot.
376*635a8641SAndroid Build Coastguard Worker       tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
377*635a8641SAndroid Build Coastguard Worker     }
378*635a8641SAndroid Build Coastguard Worker     initializing_tpm_token_ = false;
379*635a8641SAndroid Build Coastguard Worker 
380*635a8641SAndroid Build Coastguard Worker     if (tpm_slot_)
381*635a8641SAndroid Build Coastguard Worker       RunAndClearTPMReadyCallbackList();
382*635a8641SAndroid Build Coastguard Worker 
383*635a8641SAndroid Build Coastguard Worker     std::move(callback).Run(!!tpm_slot_);
384*635a8641SAndroid Build Coastguard Worker   }
385*635a8641SAndroid Build Coastguard Worker 
RunAndClearTPMReadyCallbackList()386*635a8641SAndroid Build Coastguard Worker   void RunAndClearTPMReadyCallbackList() {
387*635a8641SAndroid Build Coastguard Worker     TPMReadyCallbackList callback_list;
388*635a8641SAndroid Build Coastguard Worker     callback_list.swap(tpm_ready_callback_list_);
389*635a8641SAndroid Build Coastguard Worker     for (TPMReadyCallbackList::iterator i = callback_list.begin();
390*635a8641SAndroid Build Coastguard Worker          i != callback_list.end();
391*635a8641SAndroid Build Coastguard Worker          ++i) {
392*635a8641SAndroid Build Coastguard Worker       std::move(*i).Run();
393*635a8641SAndroid Build Coastguard Worker     }
394*635a8641SAndroid Build Coastguard Worker   }
395*635a8641SAndroid Build Coastguard Worker 
IsTPMTokenReady(base::OnceClosure callback)396*635a8641SAndroid Build Coastguard Worker   bool IsTPMTokenReady(base::OnceClosure callback) {
397*635a8641SAndroid Build Coastguard Worker     if (!callback.is_null()) {
398*635a8641SAndroid Build Coastguard Worker       // Cannot DCHECK in the general case yet, but since the callback is
399*635a8641SAndroid Build Coastguard Worker       // a new addition to the API, DCHECK to make sure at least the new uses
400*635a8641SAndroid Build Coastguard Worker       // don't regress.
401*635a8641SAndroid Build Coastguard Worker       DCHECK(thread_checker_.CalledOnValidThread());
402*635a8641SAndroid Build Coastguard Worker     } else if (!thread_checker_.CalledOnValidThread()) {
403*635a8641SAndroid Build Coastguard Worker       // TODO(mattm): Change to DCHECK when callers have been fixed.
404*635a8641SAndroid Build Coastguard Worker       DVLOG(1) << "Called on wrong thread.\n"
405*635a8641SAndroid Build Coastguard Worker                << base::debug::StackTrace().ToString();
406*635a8641SAndroid Build Coastguard Worker     }
407*635a8641SAndroid Build Coastguard Worker 
408*635a8641SAndroid Build Coastguard Worker     if (tpm_slot_)
409*635a8641SAndroid Build Coastguard Worker       return true;
410*635a8641SAndroid Build Coastguard Worker 
411*635a8641SAndroid Build Coastguard Worker     if (!callback.is_null())
412*635a8641SAndroid Build Coastguard Worker       tpm_ready_callback_list_.push_back(std::move(callback));
413*635a8641SAndroid Build Coastguard Worker 
414*635a8641SAndroid Build Coastguard Worker     return false;
415*635a8641SAndroid Build Coastguard Worker   }
416*635a8641SAndroid Build Coastguard Worker 
417*635a8641SAndroid Build Coastguard Worker   // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot
418*635a8641SAndroid Build Coastguard Worker   // id as an int. This should be safe since this is only used with chaps, which
419*635a8641SAndroid Build Coastguard Worker   // we also control.
GetTPMSlotForIdInThreadPool(SECMODModule * chaps_module,CK_SLOT_ID slot_id)420*635a8641SAndroid Build Coastguard Worker   static crypto::ScopedPK11Slot GetTPMSlotForIdInThreadPool(
421*635a8641SAndroid Build Coastguard Worker       SECMODModule* chaps_module,
422*635a8641SAndroid Build Coastguard Worker       CK_SLOT_ID slot_id) {
423*635a8641SAndroid Build Coastguard Worker     DCHECK(chaps_module);
424*635a8641SAndroid Build Coastguard Worker 
425*635a8641SAndroid Build Coastguard Worker     DVLOG(3) << "Poking chaps module.";
426*635a8641SAndroid Build Coastguard Worker     SECStatus rv = SECMOD_UpdateSlotList(chaps_module);
427*635a8641SAndroid Build Coastguard Worker     if (rv != SECSuccess)
428*635a8641SAndroid Build Coastguard Worker       PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError();
429*635a8641SAndroid Build Coastguard Worker 
430*635a8641SAndroid Build Coastguard Worker     PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module->moduleID, slot_id);
431*635a8641SAndroid Build Coastguard Worker     if (!slot)
432*635a8641SAndroid Build Coastguard Worker       LOG(ERROR) << "TPM slot " << slot_id << " not found.";
433*635a8641SAndroid Build Coastguard Worker     return crypto::ScopedPK11Slot(slot);
434*635a8641SAndroid Build Coastguard Worker   }
435*635a8641SAndroid Build Coastguard Worker 
InitializeNSSForChromeOSUser(const std::string & username_hash,const base::FilePath & path)436*635a8641SAndroid Build Coastguard Worker   bool InitializeNSSForChromeOSUser(const std::string& username_hash,
437*635a8641SAndroid Build Coastguard Worker                                     const base::FilePath& path) {
438*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
439*635a8641SAndroid Build Coastguard Worker     if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) {
440*635a8641SAndroid Build Coastguard Worker       // This user already exists in our mapping.
441*635a8641SAndroid Build Coastguard Worker       DVLOG(2) << username_hash << " already initialized.";
442*635a8641SAndroid Build Coastguard Worker       return false;
443*635a8641SAndroid Build Coastguard Worker     }
444*635a8641SAndroid Build Coastguard Worker 
445*635a8641SAndroid Build Coastguard Worker     DVLOG(2) << "Opening NSS DB " << path.value();
446*635a8641SAndroid Build Coastguard Worker     std::string db_name = base::StringPrintf(
447*635a8641SAndroid Build Coastguard Worker         "%s %s", kUserNSSDatabaseName, username_hash.c_str());
448*635a8641SAndroid Build Coastguard Worker     ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path));
449*635a8641SAndroid Build Coastguard Worker     chromeos_user_map_[username_hash] =
450*635a8641SAndroid Build Coastguard Worker         std::make_unique<ChromeOSUserData>(std::move(public_slot));
451*635a8641SAndroid Build Coastguard Worker     return true;
452*635a8641SAndroid Build Coastguard Worker   }
453*635a8641SAndroid Build Coastguard Worker 
ShouldInitializeTPMForChromeOSUser(const std::string & username_hash)454*635a8641SAndroid Build Coastguard Worker   bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
455*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
456*635a8641SAndroid Build Coastguard Worker     DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
457*635a8641SAndroid Build Coastguard Worker 
458*635a8641SAndroid Build Coastguard Worker     return !chromeos_user_map_[username_hash]
459*635a8641SAndroid Build Coastguard Worker                 ->private_slot_initialization_started();
460*635a8641SAndroid Build Coastguard Worker   }
461*635a8641SAndroid Build Coastguard Worker 
WillInitializeTPMForChromeOSUser(const std::string & username_hash)462*635a8641SAndroid Build Coastguard Worker   void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
463*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
464*635a8641SAndroid Build Coastguard Worker     DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
465*635a8641SAndroid Build Coastguard Worker 
466*635a8641SAndroid Build Coastguard Worker     chromeos_user_map_[username_hash]
467*635a8641SAndroid Build Coastguard Worker         ->set_private_slot_initialization_started();
468*635a8641SAndroid Build Coastguard Worker   }
469*635a8641SAndroid Build Coastguard Worker 
InitializeTPMForChromeOSUser(const std::string & username_hash,CK_SLOT_ID slot_id)470*635a8641SAndroid Build Coastguard Worker   void InitializeTPMForChromeOSUser(const std::string& username_hash,
471*635a8641SAndroid Build Coastguard Worker                                     CK_SLOT_ID slot_id) {
472*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
473*635a8641SAndroid Build Coastguard Worker     DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
474*635a8641SAndroid Build Coastguard Worker     DCHECK(chromeos_user_map_[username_hash]->
475*635a8641SAndroid Build Coastguard Worker                private_slot_initialization_started());
476*635a8641SAndroid Build Coastguard Worker 
477*635a8641SAndroid Build Coastguard Worker     if (!chaps_module_)
478*635a8641SAndroid Build Coastguard Worker       return;
479*635a8641SAndroid Build Coastguard Worker 
480*635a8641SAndroid Build Coastguard Worker     // Note that a reference is not taken to chaps_module_. This is safe since
481*635a8641SAndroid Build Coastguard Worker     // NSSInitSingleton is Leaky, so the reference it holds is never released.
482*635a8641SAndroid Build Coastguard Worker     std::unique_ptr<TPMModuleAndSlot> tpm_args(
483*635a8641SAndroid Build Coastguard Worker         new TPMModuleAndSlot(chaps_module_));
484*635a8641SAndroid Build Coastguard Worker     TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
485*635a8641SAndroid Build Coastguard Worker     base::PostTaskWithTraitsAndReply(
486*635a8641SAndroid Build Coastguard Worker         FROM_HERE,
487*635a8641SAndroid Build Coastguard Worker         {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
488*635a8641SAndroid Build Coastguard Worker         base::BindOnce(&NSSInitSingleton::InitializeTPMTokenInThreadPool,
489*635a8641SAndroid Build Coastguard Worker                        slot_id, tpm_args_ptr),
490*635a8641SAndroid Build Coastguard Worker         base::BindOnce(&NSSInitSingleton::OnInitializedTPMForChromeOSUser,
491*635a8641SAndroid Build Coastguard Worker                        base::Unretained(this),  // NSSInitSingleton is leaky
492*635a8641SAndroid Build Coastguard Worker                        username_hash, std::move(tpm_args)));
493*635a8641SAndroid Build Coastguard Worker   }
494*635a8641SAndroid Build Coastguard Worker 
OnInitializedTPMForChromeOSUser(const std::string & username_hash,std::unique_ptr<TPMModuleAndSlot> tpm_args)495*635a8641SAndroid Build Coastguard Worker   void OnInitializedTPMForChromeOSUser(
496*635a8641SAndroid Build Coastguard Worker       const std::string& username_hash,
497*635a8641SAndroid Build Coastguard Worker       std::unique_ptr<TPMModuleAndSlot> tpm_args) {
498*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
499*635a8641SAndroid Build Coastguard Worker     DVLOG(2) << "Got tpm slot for " << username_hash << " "
500*635a8641SAndroid Build Coastguard Worker              << !!tpm_args->tpm_slot;
501*635a8641SAndroid Build Coastguard Worker     chromeos_user_map_[username_hash]->SetPrivateSlot(
502*635a8641SAndroid Build Coastguard Worker         std::move(tpm_args->tpm_slot));
503*635a8641SAndroid Build Coastguard Worker   }
504*635a8641SAndroid Build Coastguard Worker 
InitializePrivateSoftwareSlotForChromeOSUser(const std::string & username_hash)505*635a8641SAndroid Build Coastguard Worker   void InitializePrivateSoftwareSlotForChromeOSUser(
506*635a8641SAndroid Build Coastguard Worker       const std::string& username_hash) {
507*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
508*635a8641SAndroid Build Coastguard Worker     VLOG(1) << "using software private slot for " << username_hash;
509*635a8641SAndroid Build Coastguard Worker     DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
510*635a8641SAndroid Build Coastguard Worker     DCHECK(chromeos_user_map_[username_hash]->
511*635a8641SAndroid Build Coastguard Worker                private_slot_initialization_started());
512*635a8641SAndroid Build Coastguard Worker 
513*635a8641SAndroid Build Coastguard Worker     if (prepared_test_private_slot_) {
514*635a8641SAndroid Build Coastguard Worker       chromeos_user_map_[username_hash]->SetPrivateSlot(
515*635a8641SAndroid Build Coastguard Worker           std::move(prepared_test_private_slot_));
516*635a8641SAndroid Build Coastguard Worker       return;
517*635a8641SAndroid Build Coastguard Worker     }
518*635a8641SAndroid Build Coastguard Worker 
519*635a8641SAndroid Build Coastguard Worker     chromeos_user_map_[username_hash]->SetPrivateSlot(
520*635a8641SAndroid Build Coastguard Worker         chromeos_user_map_[username_hash]->GetPublicSlot());
521*635a8641SAndroid Build Coastguard Worker   }
522*635a8641SAndroid Build Coastguard Worker 
GetPublicSlotForChromeOSUser(const std::string & username_hash)523*635a8641SAndroid Build Coastguard Worker   ScopedPK11Slot GetPublicSlotForChromeOSUser(
524*635a8641SAndroid Build Coastguard Worker       const std::string& username_hash) {
525*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
526*635a8641SAndroid Build Coastguard Worker 
527*635a8641SAndroid Build Coastguard Worker     if (username_hash.empty()) {
528*635a8641SAndroid Build Coastguard Worker       DVLOG(2) << "empty username_hash";
529*635a8641SAndroid Build Coastguard Worker       return ScopedPK11Slot();
530*635a8641SAndroid Build Coastguard Worker     }
531*635a8641SAndroid Build Coastguard Worker 
532*635a8641SAndroid Build Coastguard Worker     if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) {
533*635a8641SAndroid Build Coastguard Worker       LOG(ERROR) << username_hash << " not initialized.";
534*635a8641SAndroid Build Coastguard Worker       return ScopedPK11Slot();
535*635a8641SAndroid Build Coastguard Worker     }
536*635a8641SAndroid Build Coastguard Worker     return chromeos_user_map_[username_hash]->GetPublicSlot();
537*635a8641SAndroid Build Coastguard Worker   }
538*635a8641SAndroid Build Coastguard Worker 
GetPrivateSlotForChromeOSUser(const std::string & username_hash,base::OnceCallback<void (ScopedPK11Slot)> callback)539*635a8641SAndroid Build Coastguard Worker   ScopedPK11Slot GetPrivateSlotForChromeOSUser(
540*635a8641SAndroid Build Coastguard Worker       const std::string& username_hash,
541*635a8641SAndroid Build Coastguard Worker       base::OnceCallback<void(ScopedPK11Slot)> callback) {
542*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
543*635a8641SAndroid Build Coastguard Worker 
544*635a8641SAndroid Build Coastguard Worker     if (username_hash.empty()) {
545*635a8641SAndroid Build Coastguard Worker       DVLOG(2) << "empty username_hash";
546*635a8641SAndroid Build Coastguard Worker       if (!callback.is_null()) {
547*635a8641SAndroid Build Coastguard Worker         base::ThreadTaskRunnerHandle::Get()->PostTask(
548*635a8641SAndroid Build Coastguard Worker             FROM_HERE, base::BindOnce(std::move(callback), ScopedPK11Slot()));
549*635a8641SAndroid Build Coastguard Worker       }
550*635a8641SAndroid Build Coastguard Worker       return ScopedPK11Slot();
551*635a8641SAndroid Build Coastguard Worker     }
552*635a8641SAndroid Build Coastguard Worker 
553*635a8641SAndroid Build Coastguard Worker     DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
554*635a8641SAndroid Build Coastguard Worker 
555*635a8641SAndroid Build Coastguard Worker     return chromeos_user_map_[username_hash]->GetPrivateSlot(
556*635a8641SAndroid Build Coastguard Worker         std::move(callback));
557*635a8641SAndroid Build Coastguard Worker   }
558*635a8641SAndroid Build Coastguard Worker 
CloseChromeOSUserForTesting(const std::string & username_hash)559*635a8641SAndroid Build Coastguard Worker   void CloseChromeOSUserForTesting(const std::string& username_hash) {
560*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
561*635a8641SAndroid Build Coastguard Worker     auto i = chromeos_user_map_.find(username_hash);
562*635a8641SAndroid Build Coastguard Worker     DCHECK(i != chromeos_user_map_.end());
563*635a8641SAndroid Build Coastguard Worker     chromeos_user_map_.erase(i);
564*635a8641SAndroid Build Coastguard Worker   }
565*635a8641SAndroid Build Coastguard Worker 
SetSystemKeySlotForTesting(ScopedPK11Slot slot)566*635a8641SAndroid Build Coastguard Worker   void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
567*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
568*635a8641SAndroid Build Coastguard Worker 
569*635a8641SAndroid Build Coastguard Worker     // Ensure that a previous value of test_system_slot_ is not overwritten.
570*635a8641SAndroid Build Coastguard Worker     // Unsetting, i.e. setting a nullptr, however is allowed.
571*635a8641SAndroid Build Coastguard Worker     DCHECK(!slot || !test_system_slot_);
572*635a8641SAndroid Build Coastguard Worker     test_system_slot_ = std::move(slot);
573*635a8641SAndroid Build Coastguard Worker     if (test_system_slot_) {
574*635a8641SAndroid Build Coastguard Worker       tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
575*635a8641SAndroid Build Coastguard Worker       RunAndClearTPMReadyCallbackList();
576*635a8641SAndroid Build Coastguard Worker     } else {
577*635a8641SAndroid Build Coastguard Worker       tpm_slot_.reset();
578*635a8641SAndroid Build Coastguard Worker     }
579*635a8641SAndroid Build Coastguard Worker   }
580*635a8641SAndroid Build Coastguard Worker 
SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot)581*635a8641SAndroid Build Coastguard Worker   void SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot) {
582*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
583*635a8641SAndroid Build Coastguard Worker 
584*635a8641SAndroid Build Coastguard Worker     // Ensure that a previous value of prepared_test_private_slot_ is not
585*635a8641SAndroid Build Coastguard Worker     // overwritten. Unsetting, i.e. setting a nullptr, however is allowed.
586*635a8641SAndroid Build Coastguard Worker     DCHECK(!slot || !prepared_test_private_slot_);
587*635a8641SAndroid Build Coastguard Worker     prepared_test_private_slot_ = std::move(slot);
588*635a8641SAndroid Build Coastguard Worker   }
589*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
590*635a8641SAndroid Build Coastguard Worker 
591*635a8641SAndroid Build Coastguard Worker #if !defined(OS_CHROMEOS)
GetPersistentNSSKeySlot()592*635a8641SAndroid Build Coastguard Worker   PK11SlotInfo* GetPersistentNSSKeySlot() {
593*635a8641SAndroid Build Coastguard Worker     // TODO(mattm): Change to DCHECK when callers have been fixed.
594*635a8641SAndroid Build Coastguard Worker     if (!thread_checker_.CalledOnValidThread()) {
595*635a8641SAndroid Build Coastguard Worker       DVLOG(1) << "Called on wrong thread.\n"
596*635a8641SAndroid Build Coastguard Worker                << base::debug::StackTrace().ToString();
597*635a8641SAndroid Build Coastguard Worker     }
598*635a8641SAndroid Build Coastguard Worker 
599*635a8641SAndroid Build Coastguard Worker     return PK11_GetInternalKeySlot();
600*635a8641SAndroid Build Coastguard Worker   }
601*635a8641SAndroid Build Coastguard Worker #endif
602*635a8641SAndroid Build Coastguard Worker 
603*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
GetSystemNSSKeySlotCallback(base::OnceCallback<void (ScopedPK11Slot)> callback)604*635a8641SAndroid Build Coastguard Worker   void GetSystemNSSKeySlotCallback(
605*635a8641SAndroid Build Coastguard Worker       base::OnceCallback<void(ScopedPK11Slot)> callback) {
606*635a8641SAndroid Build Coastguard Worker     std::move(callback).Run(
607*635a8641SAndroid Build Coastguard Worker         ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get())));
608*635a8641SAndroid Build Coastguard Worker   }
609*635a8641SAndroid Build Coastguard Worker 
GetSystemNSSKeySlot(base::OnceCallback<void (ScopedPK11Slot)> callback)610*635a8641SAndroid Build Coastguard Worker   ScopedPK11Slot GetSystemNSSKeySlot(
611*635a8641SAndroid Build Coastguard Worker       base::OnceCallback<void(ScopedPK11Slot)> callback) {
612*635a8641SAndroid Build Coastguard Worker     DCHECK(thread_checker_.CalledOnValidThread());
613*635a8641SAndroid Build Coastguard Worker     // TODO(mattm): chromeos::TPMTokenloader always calls
614*635a8641SAndroid Build Coastguard Worker     // InitializeTPMTokenAndSystemSlot with slot 0.  If the system slot is
615*635a8641SAndroid Build Coastguard Worker     // disabled, tpm_slot_ will be the first user's slot instead. Can that be
616*635a8641SAndroid Build Coastguard Worker     // detected and return nullptr instead?
617*635a8641SAndroid Build Coastguard Worker 
618*635a8641SAndroid Build Coastguard Worker     base::OnceClosure wrapped_callback;
619*635a8641SAndroid Build Coastguard Worker     if (!callback.is_null()) {
620*635a8641SAndroid Build Coastguard Worker       wrapped_callback = base::BindOnce(
621*635a8641SAndroid Build Coastguard Worker           &NSSInitSingleton::GetSystemNSSKeySlotCallback,
622*635a8641SAndroid Build Coastguard Worker           base::Unretained(this) /* singleton is leaky */, std::move(callback));
623*635a8641SAndroid Build Coastguard Worker     }
624*635a8641SAndroid Build Coastguard Worker     if (IsTPMTokenReady(std::move(wrapped_callback)))
625*635a8641SAndroid Build Coastguard Worker       return ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get()));
626*635a8641SAndroid Build Coastguard Worker     return ScopedPK11Slot();
627*635a8641SAndroid Build Coastguard Worker   }
628*635a8641SAndroid Build Coastguard Worker #endif
629*635a8641SAndroid Build Coastguard Worker 
630*635a8641SAndroid Build Coastguard Worker  private:
631*635a8641SAndroid Build Coastguard Worker   friend struct base::LazyInstanceTraitsBase<NSSInitSingleton>;
632*635a8641SAndroid Build Coastguard Worker 
NSSInitSingleton()633*635a8641SAndroid Build Coastguard Worker   NSSInitSingleton()
634*635a8641SAndroid Build Coastguard Worker       : tpm_token_enabled_for_nss_(false),
635*635a8641SAndroid Build Coastguard Worker         initializing_tpm_token_(false),
636*635a8641SAndroid Build Coastguard Worker         chaps_module_(nullptr),
637*635a8641SAndroid Build Coastguard Worker         root_(nullptr) {
638*635a8641SAndroid Build Coastguard Worker     // Initializing NSS causes us to do blocking IO.
639*635a8641SAndroid Build Coastguard Worker     // Temporarily allow it until we fix
640*635a8641SAndroid Build Coastguard Worker     //   http://code.google.com/p/chromium/issues/detail?id=59847
641*635a8641SAndroid Build Coastguard Worker     base::ThreadRestrictions::ScopedAllowIO allow_io;
642*635a8641SAndroid Build Coastguard Worker 
643*635a8641SAndroid Build Coastguard Worker     // It's safe to construct on any thread, since LazyInstance will prevent any
644*635a8641SAndroid Build Coastguard Worker     // other threads from accessing until the constructor is done.
645*635a8641SAndroid Build Coastguard Worker     thread_checker_.DetachFromThread();
646*635a8641SAndroid Build Coastguard Worker 
647*635a8641SAndroid Build Coastguard Worker     EnsureNSPRInit();
648*635a8641SAndroid Build Coastguard Worker 
649*635a8641SAndroid Build Coastguard Worker     // We *must* have NSS >= 3.26 at compile time.
650*635a8641SAndroid Build Coastguard Worker     static_assert((NSS_VMAJOR == 3 && NSS_VMINOR >= 26) || (NSS_VMAJOR > 3),
651*635a8641SAndroid Build Coastguard Worker                   "nss version check failed");
652*635a8641SAndroid Build Coastguard Worker     // Also check the run-time NSS version.
653*635a8641SAndroid Build Coastguard Worker     // NSS_VersionCheck is a >= check, not strict equality.
654*635a8641SAndroid Build Coastguard Worker     if (!NSS_VersionCheck("3.26")) {
655*635a8641SAndroid Build Coastguard Worker       LOG(FATAL) << "NSS_VersionCheck(\"3.26\") failed. NSS >= 3.26 is "
656*635a8641SAndroid Build Coastguard Worker                     "required. Please upgrade to the latest NSS, and if you "
657*635a8641SAndroid Build Coastguard Worker                     "still get this error, contact your distribution "
658*635a8641SAndroid Build Coastguard Worker                     "maintainer.";
659*635a8641SAndroid Build Coastguard Worker     }
660*635a8641SAndroid Build Coastguard Worker 
661*635a8641SAndroid Build Coastguard Worker     SECStatus status = SECFailure;
662*635a8641SAndroid Build Coastguard Worker     base::FilePath database_dir = GetInitialConfigDirectory();
663*635a8641SAndroid Build Coastguard Worker     if (!database_dir.empty()) {
664*635a8641SAndroid Build Coastguard Worker       // Initialize with a persistent database (likely, ~/.pki/nssdb).
665*635a8641SAndroid Build Coastguard Worker       // Use "sql:" which can be shared by multiple processes safely.
666*635a8641SAndroid Build Coastguard Worker       std::string nss_config_dir =
667*635a8641SAndroid Build Coastguard Worker           base::StringPrintf("sql:%s", database_dir.value().c_str());
668*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
669*635a8641SAndroid Build Coastguard Worker       status = NSS_Init(nss_config_dir.c_str());
670*635a8641SAndroid Build Coastguard Worker #else
671*635a8641SAndroid Build Coastguard Worker       status = NSS_InitReadWrite(nss_config_dir.c_str());
672*635a8641SAndroid Build Coastguard Worker #endif
673*635a8641SAndroid Build Coastguard Worker       if (status != SECSuccess) {
674*635a8641SAndroid Build Coastguard Worker         LOG(ERROR) << "Error initializing NSS with a persistent "
675*635a8641SAndroid Build Coastguard Worker                       "database (" << nss_config_dir
676*635a8641SAndroid Build Coastguard Worker                    << "): " << GetNSSErrorMessage();
677*635a8641SAndroid Build Coastguard Worker       }
678*635a8641SAndroid Build Coastguard Worker     }
679*635a8641SAndroid Build Coastguard Worker     if (status != SECSuccess) {
680*635a8641SAndroid Build Coastguard Worker       VLOG(1) << "Initializing NSS without a persistent database.";
681*635a8641SAndroid Build Coastguard Worker       status = NSS_NoDB_Init(nullptr);
682*635a8641SAndroid Build Coastguard Worker       if (status != SECSuccess) {
683*635a8641SAndroid Build Coastguard Worker         CrashOnNSSInitFailure();
684*635a8641SAndroid Build Coastguard Worker         return;
685*635a8641SAndroid Build Coastguard Worker       }
686*635a8641SAndroid Build Coastguard Worker     }
687*635a8641SAndroid Build Coastguard Worker 
688*635a8641SAndroid Build Coastguard Worker     PK11_SetPasswordFunc(PKCS11PasswordFunc);
689*635a8641SAndroid Build Coastguard Worker 
690*635a8641SAndroid Build Coastguard Worker     // If we haven't initialized the password for the NSS databases,
691*635a8641SAndroid Build Coastguard Worker     // initialize an empty-string password so that we don't need to
692*635a8641SAndroid Build Coastguard Worker     // log in.
693*635a8641SAndroid Build Coastguard Worker     PK11SlotInfo* slot = PK11_GetInternalKeySlot();
694*635a8641SAndroid Build Coastguard Worker     if (slot) {
695*635a8641SAndroid Build Coastguard Worker       // PK11_InitPin may write to the keyDB, but no other thread can use NSS
696*635a8641SAndroid Build Coastguard Worker       // yet, so we don't need to lock.
697*635a8641SAndroid Build Coastguard Worker       if (PK11_NeedUserInit(slot))
698*635a8641SAndroid Build Coastguard Worker         PK11_InitPin(slot, nullptr, nullptr);
699*635a8641SAndroid Build Coastguard Worker       PK11_FreeSlot(slot);
700*635a8641SAndroid Build Coastguard Worker     }
701*635a8641SAndroid Build Coastguard Worker 
702*635a8641SAndroid Build Coastguard Worker     root_ = InitDefaultRootCerts();
703*635a8641SAndroid Build Coastguard Worker 
704*635a8641SAndroid Build Coastguard Worker     // Disable MD5 certificate signatures. (They are disabled by default in
705*635a8641SAndroid Build Coastguard Worker     // NSS 3.14.)
706*635a8641SAndroid Build Coastguard Worker     NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
707*635a8641SAndroid Build Coastguard Worker     NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
708*635a8641SAndroid Build Coastguard Worker                            0, NSS_USE_ALG_IN_CERT_SIGNATURE);
709*635a8641SAndroid Build Coastguard Worker   }
710*635a8641SAndroid Build Coastguard Worker 
711*635a8641SAndroid Build Coastguard Worker   // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS
712*635a8641SAndroid Build Coastguard Worker   // to prevent non-joinable threads from using NSS after it's already been
713*635a8641SAndroid Build Coastguard Worker   // shut down.
714*635a8641SAndroid Build Coastguard Worker   ~NSSInitSingleton() = delete;
715*635a8641SAndroid Build Coastguard Worker 
716*635a8641SAndroid Build Coastguard Worker   // Load nss's built-in root certs.
InitDefaultRootCerts()717*635a8641SAndroid Build Coastguard Worker   SECMODModule* InitDefaultRootCerts() {
718*635a8641SAndroid Build Coastguard Worker     SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", nullptr);
719*635a8641SAndroid Build Coastguard Worker     if (root)
720*635a8641SAndroid Build Coastguard Worker       return root;
721*635a8641SAndroid Build Coastguard Worker 
722*635a8641SAndroid Build Coastguard Worker     // Aw, snap.  Can't find/load root cert shared library.
723*635a8641SAndroid Build Coastguard Worker     // This will make it hard to talk to anybody via https.
724*635a8641SAndroid Build Coastguard Worker     // TODO(mattm): Re-add the NOTREACHED here when crbug.com/310972 is fixed.
725*635a8641SAndroid Build Coastguard Worker     return nullptr;
726*635a8641SAndroid Build Coastguard Worker   }
727*635a8641SAndroid Build Coastguard Worker 
728*635a8641SAndroid Build Coastguard Worker   // Load the given module for this NSS session.
LoadModule(const char * name,const char * library_path,const char * params)729*635a8641SAndroid Build Coastguard Worker   static SECMODModule* LoadModule(const char* name,
730*635a8641SAndroid Build Coastguard Worker                                   const char* library_path,
731*635a8641SAndroid Build Coastguard Worker                                   const char* params) {
732*635a8641SAndroid Build Coastguard Worker     std::string modparams = base::StringPrintf(
733*635a8641SAndroid Build Coastguard Worker         "name=\"%s\" library=\"%s\" %s",
734*635a8641SAndroid Build Coastguard Worker         name, library_path, params ? params : "");
735*635a8641SAndroid Build Coastguard Worker 
736*635a8641SAndroid Build Coastguard Worker     // Shouldn't need to const_cast here, but SECMOD doesn't properly
737*635a8641SAndroid Build Coastguard Worker     // declare input string arguments as const.  Bug
738*635a8641SAndroid Build Coastguard Worker     // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed
739*635a8641SAndroid Build Coastguard Worker     // on NSS codebase to address this.
740*635a8641SAndroid Build Coastguard Worker     SECMODModule* module = SECMOD_LoadUserModule(
741*635a8641SAndroid Build Coastguard Worker         const_cast<char*>(modparams.c_str()), nullptr, PR_FALSE);
742*635a8641SAndroid Build Coastguard Worker     if (!module) {
743*635a8641SAndroid Build Coastguard Worker       LOG(ERROR) << "Error loading " << name << " module into NSS: "
744*635a8641SAndroid Build Coastguard Worker                  << GetNSSErrorMessage();
745*635a8641SAndroid Build Coastguard Worker       return nullptr;
746*635a8641SAndroid Build Coastguard Worker     }
747*635a8641SAndroid Build Coastguard Worker     if (!module->loaded) {
748*635a8641SAndroid Build Coastguard Worker       LOG(ERROR) << "After loading " << name << ", loaded==false: "
749*635a8641SAndroid Build Coastguard Worker                  << GetNSSErrorMessage();
750*635a8641SAndroid Build Coastguard Worker       SECMOD_DestroyModule(module);
751*635a8641SAndroid Build Coastguard Worker       return nullptr;
752*635a8641SAndroid Build Coastguard Worker     }
753*635a8641SAndroid Build Coastguard Worker     return module;
754*635a8641SAndroid Build Coastguard Worker   }
755*635a8641SAndroid Build Coastguard Worker 
756*635a8641SAndroid Build Coastguard Worker   bool tpm_token_enabled_for_nss_;
757*635a8641SAndroid Build Coastguard Worker   bool initializing_tpm_token_;
758*635a8641SAndroid Build Coastguard Worker   typedef std::vector<base::OnceClosure> TPMReadyCallbackList;
759*635a8641SAndroid Build Coastguard Worker   TPMReadyCallbackList tpm_ready_callback_list_;
760*635a8641SAndroid Build Coastguard Worker   SECMODModule* chaps_module_;
761*635a8641SAndroid Build Coastguard Worker   crypto::ScopedPK11Slot tpm_slot_;
762*635a8641SAndroid Build Coastguard Worker   SECMODModule* root_;
763*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
764*635a8641SAndroid Build Coastguard Worker   std::map<std::string, std::unique_ptr<ChromeOSUserData>> chromeos_user_map_;
765*635a8641SAndroid Build Coastguard Worker   ScopedPK11Slot test_system_slot_;
766*635a8641SAndroid Build Coastguard Worker   ScopedPK11Slot prepared_test_private_slot_;
767*635a8641SAndroid Build Coastguard Worker #endif
768*635a8641SAndroid Build Coastguard Worker 
769*635a8641SAndroid Build Coastguard Worker   base::ThreadChecker thread_checker_;
770*635a8641SAndroid Build Coastguard Worker };
771*635a8641SAndroid Build Coastguard Worker 
772*635a8641SAndroid Build Coastguard Worker base::LazyInstance<NSSInitSingleton>::Leaky
773*635a8641SAndroid Build Coastguard Worker     g_nss_singleton = LAZY_INSTANCE_INITIALIZER;
774*635a8641SAndroid Build Coastguard Worker }  // namespace
775*635a8641SAndroid Build Coastguard Worker 
OpenSoftwareNSSDB(const base::FilePath & path,const std::string & description)776*635a8641SAndroid Build Coastguard Worker ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
777*635a8641SAndroid Build Coastguard Worker                                  const std::string& description) {
778*635a8641SAndroid Build Coastguard Worker   const std::string modspec =
779*635a8641SAndroid Build Coastguard Worker       base::StringPrintf("configDir='sql:%s' tokenDescription='%s'",
780*635a8641SAndroid Build Coastguard Worker                          path.value().c_str(),
781*635a8641SAndroid Build Coastguard Worker                          description.c_str());
782*635a8641SAndroid Build Coastguard Worker   PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str());
783*635a8641SAndroid Build Coastguard Worker   if (db_slot) {
784*635a8641SAndroid Build Coastguard Worker     if (PK11_NeedUserInit(db_slot))
785*635a8641SAndroid Build Coastguard Worker       PK11_InitPin(db_slot, nullptr, nullptr);
786*635a8641SAndroid Build Coastguard Worker   } else {
787*635a8641SAndroid Build Coastguard Worker     LOG(ERROR) << "Error opening persistent database (" << modspec
788*635a8641SAndroid Build Coastguard Worker                << "): " << GetNSSErrorMessage();
789*635a8641SAndroid Build Coastguard Worker   }
790*635a8641SAndroid Build Coastguard Worker   return ScopedPK11Slot(db_slot);
791*635a8641SAndroid Build Coastguard Worker }
792*635a8641SAndroid Build Coastguard Worker 
EnsureNSPRInit()793*635a8641SAndroid Build Coastguard Worker void EnsureNSPRInit() {
794*635a8641SAndroid Build Coastguard Worker   g_nspr_singleton.Get();
795*635a8641SAndroid Build Coastguard Worker }
796*635a8641SAndroid Build Coastguard Worker 
EnsureNSSInit()797*635a8641SAndroid Build Coastguard Worker void EnsureNSSInit() {
798*635a8641SAndroid Build Coastguard Worker   g_nss_singleton.Get();
799*635a8641SAndroid Build Coastguard Worker }
800*635a8641SAndroid Build Coastguard Worker 
CheckNSSVersion(const char * version)801*635a8641SAndroid Build Coastguard Worker bool CheckNSSVersion(const char* version) {
802*635a8641SAndroid Build Coastguard Worker   return !!NSS_VersionCheck(version);
803*635a8641SAndroid Build Coastguard Worker }
804*635a8641SAndroid Build Coastguard Worker 
AutoSECMODListReadLock()805*635a8641SAndroid Build Coastguard Worker AutoSECMODListReadLock::AutoSECMODListReadLock()
806*635a8641SAndroid Build Coastguard Worker       : lock_(SECMOD_GetDefaultModuleListLock()) {
807*635a8641SAndroid Build Coastguard Worker     SECMOD_GetReadLock(lock_);
808*635a8641SAndroid Build Coastguard Worker   }
809*635a8641SAndroid Build Coastguard Worker 
~AutoSECMODListReadLock()810*635a8641SAndroid Build Coastguard Worker AutoSECMODListReadLock::~AutoSECMODListReadLock() {
811*635a8641SAndroid Build Coastguard Worker   SECMOD_ReleaseReadLock(lock_);
812*635a8641SAndroid Build Coastguard Worker }
813*635a8641SAndroid Build Coastguard Worker 
814*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
GetSystemNSSKeySlot(base::OnceCallback<void (ScopedPK11Slot)> callback)815*635a8641SAndroid Build Coastguard Worker ScopedPK11Slot GetSystemNSSKeySlot(
816*635a8641SAndroid Build Coastguard Worker     base::OnceCallback<void(ScopedPK11Slot)> callback) {
817*635a8641SAndroid Build Coastguard Worker   return g_nss_singleton.Get().GetSystemNSSKeySlot(std::move(callback));
818*635a8641SAndroid Build Coastguard Worker }
819*635a8641SAndroid Build Coastguard Worker 
SetSystemKeySlotForTesting(ScopedPK11Slot slot)820*635a8641SAndroid Build Coastguard Worker void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
821*635a8641SAndroid Build Coastguard Worker   g_nss_singleton.Get().SetSystemKeySlotForTesting(std::move(slot));
822*635a8641SAndroid Build Coastguard Worker }
823*635a8641SAndroid Build Coastguard Worker 
EnableTPMTokenForNSS()824*635a8641SAndroid Build Coastguard Worker void EnableTPMTokenForNSS() {
825*635a8641SAndroid Build Coastguard Worker   g_nss_singleton.Get().EnableTPMTokenForNSS();
826*635a8641SAndroid Build Coastguard Worker }
827*635a8641SAndroid Build Coastguard Worker 
IsTPMTokenEnabledForNSS()828*635a8641SAndroid Build Coastguard Worker bool IsTPMTokenEnabledForNSS() {
829*635a8641SAndroid Build Coastguard Worker   return g_nss_singleton.Get().IsTPMTokenEnabledForNSS();
830*635a8641SAndroid Build Coastguard Worker }
831*635a8641SAndroid Build Coastguard Worker 
IsTPMTokenReady(base::OnceClosure callback)832*635a8641SAndroid Build Coastguard Worker bool IsTPMTokenReady(base::OnceClosure callback) {
833*635a8641SAndroid Build Coastguard Worker   return g_nss_singleton.Get().IsTPMTokenReady(std::move(callback));
834*635a8641SAndroid Build Coastguard Worker }
835*635a8641SAndroid Build Coastguard Worker 
InitializeTPMTokenAndSystemSlot(int token_slot_id,base::OnceCallback<void (bool)> callback)836*635a8641SAndroid Build Coastguard Worker void InitializeTPMTokenAndSystemSlot(int token_slot_id,
837*635a8641SAndroid Build Coastguard Worker                                      base::OnceCallback<void(bool)> callback) {
838*635a8641SAndroid Build Coastguard Worker   g_nss_singleton.Get().InitializeTPMTokenAndSystemSlot(token_slot_id,
839*635a8641SAndroid Build Coastguard Worker                                                         std::move(callback));
840*635a8641SAndroid Build Coastguard Worker }
841*635a8641SAndroid Build Coastguard Worker 
InitializeNSSForChromeOSUser(const std::string & username_hash,const base::FilePath & path)842*635a8641SAndroid Build Coastguard Worker bool InitializeNSSForChromeOSUser(const std::string& username_hash,
843*635a8641SAndroid Build Coastguard Worker                                   const base::FilePath& path) {
844*635a8641SAndroid Build Coastguard Worker   return g_nss_singleton.Get().InitializeNSSForChromeOSUser(username_hash,
845*635a8641SAndroid Build Coastguard Worker                                                             path);
846*635a8641SAndroid Build Coastguard Worker }
847*635a8641SAndroid Build Coastguard Worker 
ShouldInitializeTPMForChromeOSUser(const std::string & username_hash)848*635a8641SAndroid Build Coastguard Worker bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
849*635a8641SAndroid Build Coastguard Worker   return g_nss_singleton.Get().ShouldInitializeTPMForChromeOSUser(
850*635a8641SAndroid Build Coastguard Worker       username_hash);
851*635a8641SAndroid Build Coastguard Worker }
852*635a8641SAndroid Build Coastguard Worker 
WillInitializeTPMForChromeOSUser(const std::string & username_hash)853*635a8641SAndroid Build Coastguard Worker void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
854*635a8641SAndroid Build Coastguard Worker   g_nss_singleton.Get().WillInitializeTPMForChromeOSUser(username_hash);
855*635a8641SAndroid Build Coastguard Worker }
856*635a8641SAndroid Build Coastguard Worker 
InitializeTPMForChromeOSUser(const std::string & username_hash,CK_SLOT_ID slot_id)857*635a8641SAndroid Build Coastguard Worker void InitializeTPMForChromeOSUser(
858*635a8641SAndroid Build Coastguard Worker     const std::string& username_hash,
859*635a8641SAndroid Build Coastguard Worker     CK_SLOT_ID slot_id) {
860*635a8641SAndroid Build Coastguard Worker   g_nss_singleton.Get().InitializeTPMForChromeOSUser(username_hash, slot_id);
861*635a8641SAndroid Build Coastguard Worker }
862*635a8641SAndroid Build Coastguard Worker 
InitializePrivateSoftwareSlotForChromeOSUser(const std::string & username_hash)863*635a8641SAndroid Build Coastguard Worker void InitializePrivateSoftwareSlotForChromeOSUser(
864*635a8641SAndroid Build Coastguard Worker     const std::string& username_hash) {
865*635a8641SAndroid Build Coastguard Worker   g_nss_singleton.Get().InitializePrivateSoftwareSlotForChromeOSUser(
866*635a8641SAndroid Build Coastguard Worker       username_hash);
867*635a8641SAndroid Build Coastguard Worker }
868*635a8641SAndroid Build Coastguard Worker 
GetPublicSlotForChromeOSUser(const std::string & username_hash)869*635a8641SAndroid Build Coastguard Worker ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) {
870*635a8641SAndroid Build Coastguard Worker   return g_nss_singleton.Get().GetPublicSlotForChromeOSUser(username_hash);
871*635a8641SAndroid Build Coastguard Worker }
872*635a8641SAndroid Build Coastguard Worker 
GetPrivateSlotForChromeOSUser(const std::string & username_hash,base::OnceCallback<void (ScopedPK11Slot)> callback)873*635a8641SAndroid Build Coastguard Worker ScopedPK11Slot GetPrivateSlotForChromeOSUser(
874*635a8641SAndroid Build Coastguard Worker     const std::string& username_hash,
875*635a8641SAndroid Build Coastguard Worker     base::OnceCallback<void(ScopedPK11Slot)> callback) {
876*635a8641SAndroid Build Coastguard Worker   return g_nss_singleton.Get().GetPrivateSlotForChromeOSUser(
877*635a8641SAndroid Build Coastguard Worker       username_hash, std::move(callback));
878*635a8641SAndroid Build Coastguard Worker }
879*635a8641SAndroid Build Coastguard Worker 
CloseChromeOSUserForTesting(const std::string & username_hash)880*635a8641SAndroid Build Coastguard Worker void CloseChromeOSUserForTesting(const std::string& username_hash) {
881*635a8641SAndroid Build Coastguard Worker   g_nss_singleton.Get().CloseChromeOSUserForTesting(username_hash);
882*635a8641SAndroid Build Coastguard Worker }
883*635a8641SAndroid Build Coastguard Worker 
SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot)884*635a8641SAndroid Build Coastguard Worker void SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot) {
885*635a8641SAndroid Build Coastguard Worker   g_nss_singleton.Get().SetPrivateSoftwareSlotForChromeOSUserForTesting(
886*635a8641SAndroid Build Coastguard Worker       std::move(slot));
887*635a8641SAndroid Build Coastguard Worker }
888*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
889*635a8641SAndroid Build Coastguard Worker 
PRTimeToBaseTime(PRTime prtime)890*635a8641SAndroid Build Coastguard Worker base::Time PRTimeToBaseTime(PRTime prtime) {
891*635a8641SAndroid Build Coastguard Worker   return base::Time::FromInternalValue(
892*635a8641SAndroid Build Coastguard Worker       prtime + base::Time::UnixEpoch().ToInternalValue());
893*635a8641SAndroid Build Coastguard Worker }
894*635a8641SAndroid Build Coastguard Worker 
BaseTimeToPRTime(base::Time time)895*635a8641SAndroid Build Coastguard Worker PRTime BaseTimeToPRTime(base::Time time) {
896*635a8641SAndroid Build Coastguard Worker   return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue();
897*635a8641SAndroid Build Coastguard Worker }
898*635a8641SAndroid Build Coastguard Worker 
899*635a8641SAndroid Build Coastguard Worker #if !defined(OS_CHROMEOS)
GetPersistentNSSKeySlot()900*635a8641SAndroid Build Coastguard Worker PK11SlotInfo* GetPersistentNSSKeySlot() {
901*635a8641SAndroid Build Coastguard Worker   return g_nss_singleton.Get().GetPersistentNSSKeySlot();
902*635a8641SAndroid Build Coastguard Worker }
903*635a8641SAndroid Build Coastguard Worker #endif
904*635a8641SAndroid Build Coastguard Worker 
905*635a8641SAndroid Build Coastguard Worker }  // namespace crypto
906