xref: /aosp_15_r20/external/cronet/crypto/nss_util.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 <memory>
16*6777b538SAndroid Build Coastguard Worker #include <utility>
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker #include "base/base_paths.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/containers/flat_map.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/containers/heap_array.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/debug/alias.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/files/file_path.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/lazy_instance.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/path_service.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
30*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
31*6777b538SAndroid Build Coastguard Worker #include "build/chromeos_buildflags.h"
32*6777b538SAndroid Build Coastguard Worker #include "crypto/nss_crypto_module_delegate.h"
33*6777b538SAndroid Build Coastguard Worker #include "crypto/nss_util_internal.h"
34*6777b538SAndroid Build Coastguard Worker 
35*6777b538SAndroid Build Coastguard Worker namespace crypto {
36*6777b538SAndroid Build Coastguard Worker 
37*6777b538SAndroid Build Coastguard Worker namespace {
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker #if !(BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS))
GetDefaultConfigDirectory()40*6777b538SAndroid Build Coastguard Worker base::FilePath GetDefaultConfigDirectory() {
41*6777b538SAndroid Build Coastguard Worker   base::FilePath dir;
42*6777b538SAndroid Build Coastguard Worker   base::PathService::Get(base::DIR_HOME, &dir);
43*6777b538SAndroid Build Coastguard Worker   if (dir.empty()) {
44*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to get home directory.";
45*6777b538SAndroid Build Coastguard Worker     return dir;
46*6777b538SAndroid Build Coastguard Worker   }
47*6777b538SAndroid Build Coastguard Worker   dir = dir.AppendASCII(".pki").AppendASCII("nssdb");
48*6777b538SAndroid Build Coastguard Worker   if (!base::CreateDirectory(dir)) {
49*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to create " << dir.value() << " directory.";
50*6777b538SAndroid Build Coastguard Worker     dir.clear();
51*6777b538SAndroid Build Coastguard Worker   }
52*6777b538SAndroid Build Coastguard Worker   DVLOG(2) << "DefaultConfigDirectory: " << dir.value();
53*6777b538SAndroid Build Coastguard Worker   return dir;
54*6777b538SAndroid Build Coastguard Worker }
55*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker // On non-Chrome OS platforms, return the default config directory. On Chrome
58*6777b538SAndroid Build Coastguard Worker // OS return a empty path which will result in NSS being initialized without a
59*6777b538SAndroid Build Coastguard Worker // persistent database.
GetInitialConfigDirectory()60*6777b538SAndroid Build Coastguard Worker base::FilePath GetInitialConfigDirectory() {
61*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
62*6777b538SAndroid Build Coastguard Worker   return base::FilePath();
63*6777b538SAndroid Build Coastguard Worker #else
64*6777b538SAndroid Build Coastguard Worker   return GetDefaultConfigDirectory();
65*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
66*6777b538SAndroid Build Coastguard Worker }
67*6777b538SAndroid Build Coastguard Worker 
68*6777b538SAndroid Build Coastguard Worker // This callback for NSS forwards all requests to a caller-specified
69*6777b538SAndroid Build Coastguard Worker // CryptoModuleBlockingPasswordDelegate object.
PKCS11PasswordFunc(PK11SlotInfo * slot,PRBool retry,void * arg)70*6777b538SAndroid Build Coastguard Worker char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) {
71*6777b538SAndroid Build Coastguard Worker   crypto::CryptoModuleBlockingPasswordDelegate* delegate =
72*6777b538SAndroid Build Coastguard Worker       reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg);
73*6777b538SAndroid Build Coastguard Worker   if (delegate) {
74*6777b538SAndroid Build Coastguard Worker     bool cancelled = false;
75*6777b538SAndroid Build Coastguard Worker     std::string password = delegate->RequestPassword(
76*6777b538SAndroid Build Coastguard Worker         PK11_GetTokenName(slot), retry != PR_FALSE, &cancelled);
77*6777b538SAndroid Build Coastguard Worker     if (cancelled)
78*6777b538SAndroid Build Coastguard Worker       return nullptr;
79*6777b538SAndroid Build Coastguard Worker     char* result = PORT_Strdup(password.c_str());
80*6777b538SAndroid Build Coastguard Worker     password.replace(0, password.size(), password.size(), 0);
81*6777b538SAndroid Build Coastguard Worker     return result;
82*6777b538SAndroid Build Coastguard Worker   }
83*6777b538SAndroid Build Coastguard Worker   DLOG(ERROR) << "PK11 password requested with nullptr arg";
84*6777b538SAndroid Build Coastguard Worker   return nullptr;
85*6777b538SAndroid Build Coastguard Worker }
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker // A singleton to initialize/deinitialize NSPR.
88*6777b538SAndroid Build Coastguard Worker // Separate from the NSS singleton because we initialize NSPR on the UI thread.
89*6777b538SAndroid Build Coastguard Worker // Now that we're leaking the singleton, we could merge back with the NSS
90*6777b538SAndroid Build Coastguard Worker // singleton.
91*6777b538SAndroid Build Coastguard Worker class NSPRInitSingleton {
92*6777b538SAndroid Build Coastguard Worker  private:
93*6777b538SAndroid Build Coastguard Worker   friend struct base::LazyInstanceTraitsBase<NSPRInitSingleton>;
94*6777b538SAndroid Build Coastguard Worker 
NSPRInitSingleton()95*6777b538SAndroid Build Coastguard Worker   NSPRInitSingleton() { PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); }
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker   // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS
98*6777b538SAndroid Build Coastguard Worker   // to prevent non-joinable threads from using NSS after it's already been
99*6777b538SAndroid Build Coastguard Worker   // shut down.
100*6777b538SAndroid Build Coastguard Worker   ~NSPRInitSingleton() = delete;
101*6777b538SAndroid Build Coastguard Worker };
102*6777b538SAndroid Build Coastguard Worker 
103*6777b538SAndroid Build Coastguard Worker base::LazyInstance<NSPRInitSingleton>::Leaky g_nspr_singleton =
104*6777b538SAndroid Build Coastguard Worker     LAZY_INSTANCE_INITIALIZER;
105*6777b538SAndroid Build Coastguard Worker 
106*6777b538SAndroid Build Coastguard Worker // Force a crash with error info on NSS_NoDB_Init failure.
CrashOnNSSInitFailure()107*6777b538SAndroid Build Coastguard Worker void CrashOnNSSInitFailure() {
108*6777b538SAndroid Build Coastguard Worker   int nss_error = PR_GetError();
109*6777b538SAndroid Build Coastguard Worker   int os_error = PR_GetOSError();
110*6777b538SAndroid Build Coastguard Worker   base::debug::Alias(&nss_error);
111*6777b538SAndroid Build Coastguard Worker   base::debug::Alias(&os_error);
112*6777b538SAndroid Build Coastguard Worker   LOG(ERROR) << "Error initializing NSS without a persistent database: "
113*6777b538SAndroid Build Coastguard Worker              << GetNSSErrorMessage();
114*6777b538SAndroid Build Coastguard Worker   LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error;
115*6777b538SAndroid Build Coastguard Worker }
116*6777b538SAndroid Build Coastguard Worker 
117*6777b538SAndroid Build Coastguard Worker class NSSInitSingleton {
118*6777b538SAndroid Build Coastguard Worker  public:
119*6777b538SAndroid Build Coastguard Worker   // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS
120*6777b538SAndroid Build Coastguard Worker   // to prevent non-joinable threads from using NSS after it's already been
121*6777b538SAndroid Build Coastguard Worker   // shut down.
122*6777b538SAndroid Build Coastguard Worker   ~NSSInitSingleton() = delete;
123*6777b538SAndroid Build Coastguard Worker 
OpenSoftwareNSSDB(const base::FilePath & path,const std::string & description)124*6777b538SAndroid Build Coastguard Worker   ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
125*6777b538SAndroid Build Coastguard Worker                                    const std::string& description) {
126*6777b538SAndroid Build Coastguard Worker     base::AutoLock lock(slot_map_lock_);
127*6777b538SAndroid Build Coastguard Worker 
128*6777b538SAndroid Build Coastguard Worker     auto slot_map_iter = slot_map_.find(path);
129*6777b538SAndroid Build Coastguard Worker     if (slot_map_iter != slot_map_.end()) {
130*6777b538SAndroid Build Coastguard Worker       // PK11_ReferenceSlot returns a new PK11Slot instance which refers
131*6777b538SAndroid Build Coastguard Worker       // to the same slot.
132*6777b538SAndroid Build Coastguard Worker       return ScopedPK11Slot(PK11_ReferenceSlot(slot_map_iter->second.get()));
133*6777b538SAndroid Build Coastguard Worker     }
134*6777b538SAndroid Build Coastguard Worker 
135*6777b538SAndroid Build Coastguard Worker     const std::string modspec =
136*6777b538SAndroid Build Coastguard Worker         base::StringPrintf("configDir='sql:%s' tokenDescription='%s'",
137*6777b538SAndroid Build Coastguard Worker                            path.value().c_str(), description.c_str());
138*6777b538SAndroid Build Coastguard Worker 
139*6777b538SAndroid Build Coastguard Worker     // TODO(crbug.com/1163303): Presumably there's a race condition with
140*6777b538SAndroid Build Coastguard Worker     // session_manager around creating/opening the software NSS database. The
141*6777b538SAndroid Build Coastguard Worker     // retry loop is a temporary workaround that should at least reduce the
142*6777b538SAndroid Build Coastguard Worker     // amount of failures until a proper fix is implemented.
143*6777b538SAndroid Build Coastguard Worker     PK11SlotInfo* db_slot_info = nullptr;
144*6777b538SAndroid Build Coastguard Worker     int attempts_counter = 0;
145*6777b538SAndroid Build Coastguard Worker     for (; !db_slot_info && (attempts_counter < 10); ++attempts_counter) {
146*6777b538SAndroid Build Coastguard Worker       db_slot_info = SECMOD_OpenUserDB(modspec.c_str());
147*6777b538SAndroid Build Coastguard Worker     }
148*6777b538SAndroid Build Coastguard Worker     if (db_slot_info && (attempts_counter > 1)) {
149*6777b538SAndroid Build Coastguard Worker       LOG(ERROR) << "Opening persistent database failed "
150*6777b538SAndroid Build Coastguard Worker                  << attempts_counter - 1 << " times before succeeding";
151*6777b538SAndroid Build Coastguard Worker     }
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker     if (db_slot_info) {
154*6777b538SAndroid Build Coastguard Worker       if (PK11_NeedUserInit(db_slot_info))
155*6777b538SAndroid Build Coastguard Worker         PK11_InitPin(db_slot_info, nullptr, nullptr);
156*6777b538SAndroid Build Coastguard Worker       slot_map_[path] = ScopedPK11Slot(PK11_ReferenceSlot(db_slot_info));
157*6777b538SAndroid Build Coastguard Worker     } else {
158*6777b538SAndroid Build Coastguard Worker       LOG(ERROR) << "Error opening persistent database (" << modspec
159*6777b538SAndroid Build Coastguard Worker                  << "): " << GetNSSErrorMessage();
160*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH)
161*6777b538SAndroid Build Coastguard Worker       DiagnosePublicSlotAndCrash(path);
162*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
163*6777b538SAndroid Build Coastguard Worker     }
164*6777b538SAndroid Build Coastguard Worker 
165*6777b538SAndroid Build Coastguard Worker     return ScopedPK11Slot(db_slot_info);
166*6777b538SAndroid Build Coastguard Worker   }
167*6777b538SAndroid Build Coastguard Worker 
CloseSoftwareNSSDB(PK11SlotInfo * slot)168*6777b538SAndroid Build Coastguard Worker   SECStatus CloseSoftwareNSSDB(PK11SlotInfo* slot) {
169*6777b538SAndroid Build Coastguard Worker     if (!slot) {
170*6777b538SAndroid Build Coastguard Worker       return SECFailure;
171*6777b538SAndroid Build Coastguard Worker     }
172*6777b538SAndroid Build Coastguard Worker 
173*6777b538SAndroid Build Coastguard Worker     base::AutoLock lock(slot_map_lock_);
174*6777b538SAndroid Build Coastguard Worker     CK_SLOT_ID slot_id = PK11_GetSlotID(slot);
175*6777b538SAndroid Build Coastguard Worker     for (auto const& [stored_path, stored_slot] : slot_map_) {
176*6777b538SAndroid Build Coastguard Worker       if (PK11_GetSlotID(stored_slot.get()) == slot_id) {
177*6777b538SAndroid Build Coastguard Worker         slot_map_.erase(stored_path);
178*6777b538SAndroid Build Coastguard Worker         return SECMOD_CloseUserDB(slot);
179*6777b538SAndroid Build Coastguard Worker       }
180*6777b538SAndroid Build Coastguard Worker     }
181*6777b538SAndroid Build Coastguard Worker     return SECFailure;
182*6777b538SAndroid Build Coastguard Worker   }
183*6777b538SAndroid Build Coastguard Worker 
184*6777b538SAndroid Build Coastguard Worker  private:
185*6777b538SAndroid Build Coastguard Worker   friend struct base::LazyInstanceTraitsBase<NSSInitSingleton>;
186*6777b538SAndroid Build Coastguard Worker 
NSSInitSingleton()187*6777b538SAndroid Build Coastguard Worker   NSSInitSingleton() {
188*6777b538SAndroid Build Coastguard Worker     // Initializing NSS causes us to do blocking IO.
189*6777b538SAndroid Build Coastguard Worker     // Temporarily allow it until we fix
190*6777b538SAndroid Build Coastguard Worker     //   http://code.google.com/p/chromium/issues/detail?id=59847
191*6777b538SAndroid Build Coastguard Worker     ScopedAllowBlockingForNSS allow_blocking;
192*6777b538SAndroid Build Coastguard Worker 
193*6777b538SAndroid Build Coastguard Worker     EnsureNSPRInit();
194*6777b538SAndroid Build Coastguard Worker 
195*6777b538SAndroid Build Coastguard Worker     // We *must* have NSS >= 3.35 at compile time.
196*6777b538SAndroid Build Coastguard Worker     static_assert((NSS_VMAJOR == 3 && NSS_VMINOR >= 35) || (NSS_VMAJOR > 3),
197*6777b538SAndroid Build Coastguard Worker                   "nss version check failed");
198*6777b538SAndroid Build Coastguard Worker     // Also check the run-time NSS version.
199*6777b538SAndroid Build Coastguard Worker     // NSS_VersionCheck is a >= check, not strict equality.
200*6777b538SAndroid Build Coastguard Worker     if (!NSS_VersionCheck("3.35")) {
201*6777b538SAndroid Build Coastguard Worker       LOG(FATAL) << "NSS_VersionCheck(\"3.35\") failed. NSS >= 3.35 is "
202*6777b538SAndroid Build Coastguard Worker                     "required. Please upgrade to the latest NSS, and if you "
203*6777b538SAndroid Build Coastguard Worker                     "still get this error, contact your distribution "
204*6777b538SAndroid Build Coastguard Worker                     "maintainer.";
205*6777b538SAndroid Build Coastguard Worker     }
206*6777b538SAndroid Build Coastguard Worker 
207*6777b538SAndroid Build Coastguard Worker     SECStatus status = SECFailure;
208*6777b538SAndroid Build Coastguard Worker     base::FilePath database_dir = GetInitialConfigDirectory();
209*6777b538SAndroid Build Coastguard Worker     // In MSAN, all loaded libraries needs to be instrumented. But the user
210*6777b538SAndroid Build Coastguard Worker     // config may reference an uninstrumented module, so load NSS without cert
211*6777b538SAndroid Build Coastguard Worker     // DBs instead. Tests should ideally be run under
212*6777b538SAndroid Build Coastguard Worker     // testing/run_with_dummy_home.py to eliminate dependencies on user
213*6777b538SAndroid Build Coastguard Worker     // configuration, but the bots are not currently configured to do so. This
214*6777b538SAndroid Build Coastguard Worker     // workaround may be removed if/when the bots use run_with_dummy_home.py.
215*6777b538SAndroid Build Coastguard Worker #if !defined(MEMORY_SANITIZER)
216*6777b538SAndroid Build Coastguard Worker     if (!database_dir.empty()) {
217*6777b538SAndroid Build Coastguard Worker       // Initialize with a persistent database (likely, ~/.pki/nssdb).
218*6777b538SAndroid Build Coastguard Worker       // Use "sql:" which can be shared by multiple processes safely.
219*6777b538SAndroid Build Coastguard Worker       std::string nss_config_dir =
220*6777b538SAndroid Build Coastguard Worker           base::StringPrintf("sql:%s", database_dir.value().c_str());
221*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
222*6777b538SAndroid Build Coastguard Worker       status = NSS_Init(nss_config_dir.c_str());
223*6777b538SAndroid Build Coastguard Worker #else
224*6777b538SAndroid Build Coastguard Worker       status = NSS_InitReadWrite(nss_config_dir.c_str());
225*6777b538SAndroid Build Coastguard Worker #endif
226*6777b538SAndroid Build Coastguard Worker       if (status != SECSuccess) {
227*6777b538SAndroid Build Coastguard Worker         LOG(ERROR) << "Error initializing NSS with a persistent "
228*6777b538SAndroid Build Coastguard Worker                       "database ("
229*6777b538SAndroid Build Coastguard Worker                    << nss_config_dir << "): " << GetNSSErrorMessage();
230*6777b538SAndroid Build Coastguard Worker       }
231*6777b538SAndroid Build Coastguard Worker     }
232*6777b538SAndroid Build Coastguard Worker #endif  // !defined(MEMORY_SANITIZER)
233*6777b538SAndroid Build Coastguard Worker     if (status != SECSuccess) {
234*6777b538SAndroid Build Coastguard Worker       VLOG(1) << "Initializing NSS without a persistent database.";
235*6777b538SAndroid Build Coastguard Worker       status = NSS_NoDB_Init(nullptr);
236*6777b538SAndroid Build Coastguard Worker       if (status != SECSuccess) {
237*6777b538SAndroid Build Coastguard Worker         CrashOnNSSInitFailure();
238*6777b538SAndroid Build Coastguard Worker         return;
239*6777b538SAndroid Build Coastguard Worker       }
240*6777b538SAndroid Build Coastguard Worker     }
241*6777b538SAndroid Build Coastguard Worker 
242*6777b538SAndroid Build Coastguard Worker     PK11_SetPasswordFunc(PKCS11PasswordFunc);
243*6777b538SAndroid Build Coastguard Worker 
244*6777b538SAndroid Build Coastguard Worker     // If we haven't initialized the password for the NSS databases,
245*6777b538SAndroid Build Coastguard Worker     // initialize an empty-string password so that we don't need to
246*6777b538SAndroid Build Coastguard Worker     // log in.
247*6777b538SAndroid Build Coastguard Worker     PK11SlotInfo* slot = PK11_GetInternalKeySlot();
248*6777b538SAndroid Build Coastguard Worker     if (slot) {
249*6777b538SAndroid Build Coastguard Worker       // PK11_InitPin may write to the keyDB, but no other thread can use NSS
250*6777b538SAndroid Build Coastguard Worker       // yet, so we don't need to lock.
251*6777b538SAndroid Build Coastguard Worker       if (PK11_NeedUserInit(slot))
252*6777b538SAndroid Build Coastguard Worker         PK11_InitPin(slot, nullptr, nullptr);
253*6777b538SAndroid Build Coastguard Worker       PK11_FreeSlot(slot);
254*6777b538SAndroid Build Coastguard Worker     }
255*6777b538SAndroid Build Coastguard Worker 
256*6777b538SAndroid Build Coastguard Worker     // Load nss's built-in root certs.
257*6777b538SAndroid Build Coastguard Worker     //
258*6777b538SAndroid Build Coastguard Worker     // TODO(mattm): DCHECK this succeeded when crbug.com/310972 is fixed.
259*6777b538SAndroid Build Coastguard Worker     // Failing to load root certs will it hard to talk to anybody via https.
260*6777b538SAndroid Build Coastguard Worker     LoadNSSModule("Root Certs", "libnssckbi.so", nullptr);
261*6777b538SAndroid Build Coastguard Worker 
262*6777b538SAndroid Build Coastguard Worker     // Disable MD5 certificate signatures. (They are disabled by default in
263*6777b538SAndroid Build Coastguard Worker     // NSS 3.14.)
264*6777b538SAndroid Build Coastguard Worker     NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
265*6777b538SAndroid Build Coastguard Worker     NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, 0,
266*6777b538SAndroid Build Coastguard Worker                            NSS_USE_ALG_IN_CERT_SIGNATURE);
267*6777b538SAndroid Build Coastguard Worker   }
268*6777b538SAndroid Build Coastguard Worker 
269*6777b538SAndroid Build Coastguard Worker   // Stores opened software NSS databases.
270*6777b538SAndroid Build Coastguard Worker   base::flat_map<base::FilePath, /*slot=*/ScopedPK11Slot> slot_map_
271*6777b538SAndroid Build Coastguard Worker       GUARDED_BY(slot_map_lock_);
272*6777b538SAndroid Build Coastguard Worker   // Ensures thread-safety for the methods that modify slot_map_.
273*6777b538SAndroid Build Coastguard Worker   // Performance considerations:
274*6777b538SAndroid Build Coastguard Worker   // Opening/closing a database is a rare operation in Chrome. Actually opening
275*6777b538SAndroid Build Coastguard Worker   // a database is a blocking I/O operation. Chrome doesn't open a lot of
276*6777b538SAndroid Build Coastguard Worker   // different databases in parallel. So, waiting for another thread to finish
277*6777b538SAndroid Build Coastguard Worker   // opening a database and (almost certainly) reusing the result is comparable
278*6777b538SAndroid Build Coastguard Worker   // to opening the same database twice in parallel (but the latter is not
279*6777b538SAndroid Build Coastguard Worker   // supported by NSS).
280*6777b538SAndroid Build Coastguard Worker   base::Lock slot_map_lock_;
281*6777b538SAndroid Build Coastguard Worker };
282*6777b538SAndroid Build Coastguard Worker 
283*6777b538SAndroid Build Coastguard Worker base::LazyInstance<NSSInitSingleton>::Leaky g_nss_singleton =
284*6777b538SAndroid Build Coastguard Worker     LAZY_INSTANCE_INITIALIZER;
285*6777b538SAndroid Build Coastguard Worker }  // namespace
286*6777b538SAndroid Build Coastguard Worker 
OpenSoftwareNSSDB(const base::FilePath & path,const std::string & description)287*6777b538SAndroid Build Coastguard Worker ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
288*6777b538SAndroid Build Coastguard Worker                                  const std::string& description) {
289*6777b538SAndroid Build Coastguard Worker   return g_nss_singleton.Get().OpenSoftwareNSSDB(path, description);
290*6777b538SAndroid Build Coastguard Worker }
291*6777b538SAndroid Build Coastguard Worker 
CloseSoftwareNSSDB(PK11SlotInfo * slot)292*6777b538SAndroid Build Coastguard Worker SECStatus CloseSoftwareNSSDB(PK11SlotInfo* slot) {
293*6777b538SAndroid Build Coastguard Worker   return g_nss_singleton.Get().CloseSoftwareNSSDB(slot);
294*6777b538SAndroid Build Coastguard Worker }
295*6777b538SAndroid Build Coastguard Worker 
EnsureNSPRInit()296*6777b538SAndroid Build Coastguard Worker void EnsureNSPRInit() {
297*6777b538SAndroid Build Coastguard Worker   g_nspr_singleton.Get();
298*6777b538SAndroid Build Coastguard Worker }
299*6777b538SAndroid Build Coastguard Worker 
EnsureNSSInit()300*6777b538SAndroid Build Coastguard Worker void EnsureNSSInit() {
301*6777b538SAndroid Build Coastguard Worker   g_nss_singleton.Get();
302*6777b538SAndroid Build Coastguard Worker }
303*6777b538SAndroid Build Coastguard Worker 
CheckNSSVersion(const char * version)304*6777b538SAndroid Build Coastguard Worker bool CheckNSSVersion(const char* version) {
305*6777b538SAndroid Build Coastguard Worker   return !!NSS_VersionCheck(version);
306*6777b538SAndroid Build Coastguard Worker }
307*6777b538SAndroid Build Coastguard Worker 
AutoSECMODListReadLock()308*6777b538SAndroid Build Coastguard Worker AutoSECMODListReadLock::AutoSECMODListReadLock()
309*6777b538SAndroid Build Coastguard Worker     : lock_(SECMOD_GetDefaultModuleListLock()) {
310*6777b538SAndroid Build Coastguard Worker   SECMOD_GetReadLock(lock_);
311*6777b538SAndroid Build Coastguard Worker }
312*6777b538SAndroid Build Coastguard Worker 
~AutoSECMODListReadLock()313*6777b538SAndroid Build Coastguard Worker AutoSECMODListReadLock::~AutoSECMODListReadLock() {
314*6777b538SAndroid Build Coastguard Worker   SECMOD_ReleaseReadLock(lock_);
315*6777b538SAndroid Build Coastguard Worker }
316*6777b538SAndroid Build Coastguard Worker 
PRTimeToBaseTime(PRTime prtime)317*6777b538SAndroid Build Coastguard Worker base::Time PRTimeToBaseTime(PRTime prtime) {
318*6777b538SAndroid Build Coastguard Worker   return base::Time::FromInternalValue(
319*6777b538SAndroid Build Coastguard Worker       prtime + base::Time::UnixEpoch().ToInternalValue());
320*6777b538SAndroid Build Coastguard Worker }
321*6777b538SAndroid Build Coastguard Worker 
BaseTimeToPRTime(base::Time time)322*6777b538SAndroid Build Coastguard Worker PRTime BaseTimeToPRTime(base::Time time) {
323*6777b538SAndroid Build Coastguard Worker   return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue();
324*6777b538SAndroid Build Coastguard Worker }
325*6777b538SAndroid Build Coastguard Worker 
LoadNSSModule(const char * name,const char * library_path,const char * params)326*6777b538SAndroid Build Coastguard Worker SECMODModule* LoadNSSModule(const char* name,
327*6777b538SAndroid Build Coastguard Worker                             const char* library_path,
328*6777b538SAndroid Build Coastguard Worker                             const char* params) {
329*6777b538SAndroid Build Coastguard Worker   std::string modparams =
330*6777b538SAndroid Build Coastguard Worker       base::StringPrintf("name=\"%s\" library=\"%s\" %s", name, library_path,
331*6777b538SAndroid Build Coastguard Worker                          params ? params : "");
332*6777b538SAndroid Build Coastguard Worker 
333*6777b538SAndroid Build Coastguard Worker   // Shouldn't need to const_cast here, but SECMOD doesn't properly declare
334*6777b538SAndroid Build Coastguard Worker   // input string arguments as const.  Bug
335*6777b538SAndroid Build Coastguard Worker   // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed on NSS
336*6777b538SAndroid Build Coastguard Worker   // codebase to address this.
337*6777b538SAndroid Build Coastguard Worker   SECMODModule* module = SECMOD_LoadUserModule(
338*6777b538SAndroid Build Coastguard Worker       const_cast<char*>(modparams.c_str()), nullptr, PR_FALSE);
339*6777b538SAndroid Build Coastguard Worker   if (!module) {
340*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "Error loading " << name
341*6777b538SAndroid Build Coastguard Worker                << " module into NSS: " << GetNSSErrorMessage();
342*6777b538SAndroid Build Coastguard Worker     return nullptr;
343*6777b538SAndroid Build Coastguard Worker   }
344*6777b538SAndroid Build Coastguard Worker   if (!module->loaded) {
345*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "After loading " << name
346*6777b538SAndroid Build Coastguard Worker                << ", loaded==false: " << GetNSSErrorMessage();
347*6777b538SAndroid Build Coastguard Worker     SECMOD_DestroyModule(module);
348*6777b538SAndroid Build Coastguard Worker     return nullptr;
349*6777b538SAndroid Build Coastguard Worker   }
350*6777b538SAndroid Build Coastguard Worker   return module;
351*6777b538SAndroid Build Coastguard Worker }
352*6777b538SAndroid Build Coastguard Worker 
GetNSSErrorMessage()353*6777b538SAndroid Build Coastguard Worker std::string GetNSSErrorMessage() {
354*6777b538SAndroid Build Coastguard Worker   std::string result;
355*6777b538SAndroid Build Coastguard Worker   if (PR_GetErrorTextLength()) {
356*6777b538SAndroid Build Coastguard Worker     auto error_text =
357*6777b538SAndroid Build Coastguard Worker         base::HeapArray<char>::Uninit(PR_GetErrorTextLength() + 1);
358*6777b538SAndroid Build Coastguard Worker     PRInt32 copied = PR_GetErrorText(error_text.data());
359*6777b538SAndroid Build Coastguard Worker     result = std::string(error_text.data(), copied);
360*6777b538SAndroid Build Coastguard Worker   } else {
361*6777b538SAndroid Build Coastguard Worker     result = base::StringPrintf("NSS error code: %d", PR_GetError());
362*6777b538SAndroid Build Coastguard Worker   }
363*6777b538SAndroid Build Coastguard Worker   return result;
364*6777b538SAndroid Build Coastguard Worker }
365*6777b538SAndroid Build Coastguard Worker 
366*6777b538SAndroid Build Coastguard Worker }  // namespace crypto
367