blob: 66114cd0e0cd17f95c813a100b25f9e16ec0e95b [file] [log] [blame]
[email protected]9fc44162012-01-23 22:56:411// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]bc1e07c72008-09-16 14:32:442// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]4b559b4d2011-04-14 17:37:145#include "crypto/nss_util.h"
[email protected]bc1e07c72008-09-16 14:32:446
[email protected]bc1e07c72008-09-16 14:32:447#include <nss.h>
[email protected]ea1a3f62012-11-16 20:34:238#include <pk11pub.h>
[email protected]c72f16a2009-03-19 16:02:319#include <plarena.h>
[email protected]6e7e8062009-04-13 17:35:0910#include <prerror.h>
[email protected]c72f16a2009-03-19 16:02:3111#include <prinit.h>
[email protected]1b1a264a2010-01-14 22:36:3512#include <prtime.h>
[email protected]ea224582008-12-07 20:25:4613#include <secmod.h>
thakisd1a18472016-04-08 22:30:4114
15#include <memory>
dchengcf738a92015-12-31 16:11:4516#include <utility>
17
fdoray34e1fb82016-06-08 14:43:2218#include "base/location.h"
19#include "base/single_thread_task_runner.h"
20#include "base/threading/thread_task_runner_handle.h"
dchengcf738a92015-12-31 16:11:4521#include "crypto/nss_util_internal.h"
[email protected]b43c97c2008-10-22 19:50:5822
[email protected]5a77df52014-02-05 08:37:4823#if defined(OS_OPENBSD)
[email protected]d816516f2011-10-25 19:11:5924#include <sys/mount.h>
25#include <sys/param.h>
[email protected]a8b58f42010-07-14 20:21:3526#endif
27
spangba254c42015-05-14 00:00:2328#if defined(OS_CHROMEOS)
29#include <dlfcn.h>
30#endif
31
[email protected]557737f72013-12-06 22:24:0732#include <map>
[email protected]f6a67b42011-03-17 23:49:2133#include <vector>
34
[email protected]6bdc52272014-05-27 00:12:3335#include "base/base_paths.h"
[email protected]7037a43c2014-01-14 14:00:4636#include "base/bind.h"
[email protected]f3d445e2013-11-22 18:35:0337#include "base/cpu.h"
[email protected]716fb112012-11-15 05:41:2538#include "base/debug/alias.h"
[email protected]0f8f69c2013-11-12 02:56:3139#include "base/debug/stack_trace.h"
[email protected]ed450f32011-03-16 01:26:4940#include "base/environment.h"
[email protected]57999812013-02-24 05:40:5241#include "base/files/file_path.h"
thestigc9e38a22014-09-13 01:02:1142#include "base/files/file_util.h"
[email protected]f615bda32010-11-21 01:04:5643#include "base/lazy_instance.h"
[email protected]c1444fe2008-09-17 09:42:5144#include "base/logging.h"
[email protected]f6a67b42011-03-17 23:49:2145#include "base/native_library.h"
[email protected]6bdc52272014-05-27 00:12:3346#include "base/path_service.h"
[email protected]557737f72013-12-06 22:24:0747#include "base/stl_util.h"
[email protected]0d8db082013-06-11 07:27:0148#include "base/strings/stringprintf.h"
rsleevia3ad8d02016-06-07 18:22:3349#include "base/synchronization/lock.h"
[email protected]0f8f69c2013-11-12 02:56:3150#include "base/threading/thread_checker.h"
[email protected]34b99632011-01-01 01:01:0651#include "base/threading/thread_restrictions.h"
[email protected]e2ea5ca2014-02-27 22:27:2152#include "base/threading/worker_pool.h"
[email protected]26661c22011-10-07 01:33:5853#include "build/build_config.h"
[email protected]99e5e9522013-12-16 13:05:2754#include "crypto/nss_crypto_module_delegate.h"
[email protected]abd4aba2010-01-27 19:36:2255
[email protected]4b559b4d2011-04-14 17:37:1456namespace crypto {
[email protected]f1633932010-08-17 23:05:2857
[email protected]bc1e07c72008-09-16 14:32:4458namespace {
59
[email protected]6a89ef22011-04-07 17:34:2160#if defined(OS_CHROMEOS)
[email protected]83e1ae32014-07-18 10:57:0761const char kUserNSSDatabaseName[] = "UserNSSDB";
[email protected]6a89ef22011-04-07 17:34:2162
[email protected]84e47722011-11-17 05:12:0263// Constants for loading the Chrome OS TPM-backed PKCS #11 library.
64const char kChapsModuleName[] = "Chaps";
65const char kChapsPath[] = "libchaps.so";
[email protected]6a89ef22011-04-07 17:34:2166
[email protected]6a89ef22011-04-07 17:34:2167// Fake certificate authority database used for testing.
[email protected]9e275712013-02-10 19:20:1468static const base::FilePath::CharType kReadOnlyCertDB[] =
[email protected]6a89ef22011-04-07 17:34:2169 FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb");
70#endif // defined(OS_CHROMEOS)
71
72std::string GetNSSErrorMessage() {
73 std::string result;
74 if (PR_GetErrorTextLength()) {
thakisd1a18472016-04-08 22:30:4175 std::unique_ptr<char[]> error_text(new char[PR_GetErrorTextLength() + 1]);
[email protected]6a89ef22011-04-07 17:34:2176 PRInt32 copied = PR_GetErrorText(error_text.get());
77 result = std::string(error_text.get(), copied);
78 } else {
[email protected]7d3cbc92013-03-18 22:33:0479 result = base::StringPrintf("NSS error code: %d", PR_GetError());
[email protected]6a89ef22011-04-07 17:34:2180 }
81 return result;
82}
83
[email protected]4071e6ac2014-07-12 12:46:1784#if !defined(OS_CHROMEOS)
[email protected]9e275712013-02-10 19:20:1485base::FilePath GetDefaultConfigDirectory() {
[email protected]6bdc52272014-05-27 00:12:3386 base::FilePath dir;
87 PathService::Get(base::DIR_HOME, &dir);
[email protected]a8b58f42010-07-14 20:21:3588 if (dir.empty()) {
89 LOG(ERROR) << "Failed to get home directory.";
90 return dir;
[email protected]86913342009-05-25 02:14:3491 }
[email protected]86913342009-05-25 02:14:3492 dir = dir.AppendASCII(".pki").AppendASCII("nssdb");
[email protected]426d1c92013-12-03 20:08:5493 if (!base::CreateDirectory(dir)) {
[email protected]948a707b2011-06-07 22:51:4494 LOG(ERROR) << "Failed to create " << dir.value() << " directory.";
[email protected]a8b58f42010-07-14 20:21:3595 dir.clear();
[email protected]86913342009-05-25 02:14:3496 }
[email protected]557737f72013-12-06 22:24:0797 DVLOG(2) << "DefaultConfigDirectory: " << dir.value();
[email protected]a8b58f42010-07-14 20:21:3598 return dir;
[email protected]86913342009-05-25 02:14:3499}
[email protected]4071e6ac2014-07-12 12:46:17100#endif // !defined(IS_CHROMEOS)
[email protected]86913342009-05-25 02:14:34101
[email protected]259c42f2013-09-12 20:32:22102// On non-Chrome OS platforms, return the default config directory. On Chrome OS
103// test images, return a read-only directory with fake root CA certs (which are
104// used by the local Google Accounts server mock we use when testing our login
105// code). On Chrome OS non-test images (where the read-only directory doesn't
106// exist), return an empty path.
[email protected]9e275712013-02-10 19:20:14107base::FilePath GetInitialConfigDirectory() {
[email protected]dcce6cf2010-04-29 17:50:06108#if defined(OS_CHROMEOS)
[email protected]259c42f2013-09-12 20:32:22109 base::FilePath database_dir = base::FilePath(kReadOnlyCertDB);
110 if (!base::PathExists(database_dir))
111 database_dir.clear();
112 return database_dir;
[email protected]dcce6cf2010-04-29 17:50:06113#else
114 return GetDefaultConfigDirectory();
115#endif // defined(OS_CHROMEOS)
116}
117
[email protected]88b9db72011-01-13 01:48:43118// This callback for NSS forwards all requests to a caller-specified
[email protected]3f1f8412011-01-19 03:01:23119// CryptoModuleBlockingPasswordDelegate object.
120char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) {
[email protected]4b559b4d2011-04-14 17:37:14121 crypto::CryptoModuleBlockingPasswordDelegate* delegate =
122 reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg);
[email protected]88b9db72011-01-13 01:48:43123 if (delegate) {
124 bool cancelled = false;
125 std::string password = delegate->RequestPassword(PK11_GetTokenName(slot),
126 retry != PR_FALSE,
127 &cancelled);
128 if (cancelled)
rsleeviffe5a132016-06-28 01:51:52129 return nullptr;
[email protected]88b9db72011-01-13 01:48:43130 char* result = PORT_Strdup(password.c_str());
131 password.replace(0, password.size(), password.size(), 0);
132 return result;
133 }
rsleeviffe5a132016-06-28 01:51:52134 DLOG(ERROR) << "PK11 password requested with nullptr arg";
135 return nullptr;
[email protected]88b9db72011-01-13 01:48:43136}
137
[email protected]a8b58f42010-07-14 20:21:35138// NSS creates a local cache of the sqlite database if it detects that the
139// filesystem the database is on is much slower than the local disk. The
140// detection doesn't work with the latest versions of sqlite, such as 3.6.22
141// (NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=578561). So we set
142// the NSS environment variable NSS_SDB_USE_CACHE to "yes" to override NSS's
143// detection when database_dir is on NFS. See http://crbug.com/48585.
144//
[email protected]ac3d5972011-01-13 20:33:45145// Because this function sets an environment variable it must be run before we
146// go multi-threaded.
[email protected]9e275712013-02-10 19:20:14147void UseLocalCacheOfNSSDatabaseIfNFS(const base::FilePath& database_dir) {
[email protected]5a77df52014-02-05 08:37:48148 bool db_on_nfs = false;
[email protected]d816516f2011-10-25 19:11:59149#if defined(OS_LINUX)
[email protected]a26f4ae2014-03-13 17:26:21150 base::FileSystemType fs_type = base::FILE_SYSTEM_UNKNOWN;
151 if (base::GetFileSystemType(database_dir, &fs_type))
152 db_on_nfs = (fs_type == base::FILE_SYSTEM_NFS);
[email protected]d816516f2011-10-25 19:11:59153#elif defined(OS_OPENBSD)
[email protected]5a77df52014-02-05 08:37:48154 struct statfs buf;
155 if (statfs(database_dir.value().c_str(), &buf) == 0)
156 db_on_nfs = (strcmp(buf.f_fstypename, MOUNT_NFS) == 0);
157#else
158 NOTIMPLEMENTED();
[email protected]d816516f2011-10-25 19:11:59159#endif
[email protected]5a77df52014-02-05 08:37:48160
161 if (db_on_nfs) {
thakisd1a18472016-04-08 22:30:41162 std::unique_ptr<base::Environment> env(base::Environment::Create());
[email protected]5a77df52014-02-05 08:37:48163 static const char kUseCacheEnvVar[] = "NSS_SDB_USE_CACHE";
164 if (!env->HasVar(kUseCacheEnvVar))
165 env->SetVar(kUseCacheEnvVar, "yes");
[email protected]a8b58f42010-07-14 20:21:35166 }
[email protected]a8b58f42010-07-14 20:21:35167}
168
[email protected]730fb132009-09-02 22:50:25169// A singleton to initialize/deinitialize NSPR.
170// Separate from the NSS singleton because we initialize NSPR on the UI thread.
[email protected]f615bda32010-11-21 01:04:56171// Now that we're leaking the singleton, we could merge back with the NSS
172// singleton.
[email protected]730fb132009-09-02 22:50:25173class NSPRInitSingleton {
[email protected]f615bda32010-11-21 01:04:56174 private:
[email protected]4b559b4d2011-04-14 17:37:14175 friend struct base::DefaultLazyInstanceTraits<NSPRInitSingleton>;
[email protected]f615bda32010-11-21 01:04:56176
[email protected]730fb132009-09-02 22:50:25177 NSPRInitSingleton() {
178 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
179 }
180
[email protected]f615bda32010-11-21 01:04:56181 // NOTE(willchan): We don't actually execute this code since we leak NSS to
182 // prevent non-joinable threads from using NSS after it's already been shut
183 // down.
[email protected]730fb132009-09-02 22:50:25184 ~NSPRInitSingleton() {
[email protected]829296f2010-01-27 02:58:03185 PL_ArenaFinish();
[email protected]730fb132009-09-02 22:50:25186 PRStatus prstatus = PR_Cleanup();
[email protected]450b4ad72012-05-17 10:04:17187 if (prstatus != PR_SUCCESS)
[email protected]730fb132009-09-02 22:50:25188 LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?";
[email protected]730fb132009-09-02 22:50:25189 }
190};
191
[email protected]9fc44162012-01-23 22:56:41192base::LazyInstance<NSPRInitSingleton>::Leaky
[email protected]6de0fd1d2011-11-15 13:31:49193 g_nspr_singleton = LAZY_INSTANCE_INITIALIZER;
[email protected]f615bda32010-11-21 01:04:56194
[email protected]007f5122012-11-21 16:00:21195// Force a crash with error info on NSS_NoDB_Init failure.
196void CrashOnNSSInitFailure() {
197 int nss_error = PR_GetError();
198 int os_error = PR_GetOSError();
[email protected]716fb112012-11-15 05:41:25199 base::debug::Alias(&nss_error);
200 base::debug::Alias(&os_error);
[email protected]007f5122012-11-21 16:00:21201 LOG(ERROR) << "Error initializing NSS without a persistent database: "
202 << GetNSSErrorMessage();
[email protected]2b12459a2012-11-16 03:45:32203 LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error;
[email protected]716fb112012-11-15 05:41:25204}
205
[email protected]557737f72013-12-06 22:24:07206#if defined(OS_CHROMEOS)
207class ChromeOSUserData {
208 public:
[email protected]4071e6ac2014-07-12 12:46:17209 explicit ChromeOSUserData(ScopedPK11Slot public_slot)
dchengcf738a92015-12-31 16:11:45210 : public_slot_(std::move(public_slot)),
[email protected]4071e6ac2014-07-12 12:46:17211 private_slot_initialization_started_(false) {}
[email protected]557737f72013-12-06 22:24:07212 ~ChromeOSUserData() {
[email protected]4071e6ac2014-07-12 12:46:17213 if (public_slot_) {
[email protected]557737f72013-12-06 22:24:07214 SECStatus status = SECMOD_CloseUserDB(public_slot_.get());
215 if (status != SECSuccess)
216 PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
217 }
218 }
219
220 ScopedPK11Slot GetPublicSlot() {
rsleeviffe5a132016-06-28 01:51:52221 return ScopedPK11Slot(public_slot_ ? PK11_ReferenceSlot(public_slot_.get())
222 : nullptr);
[email protected]557737f72013-12-06 22:24:07223 }
224
225 ScopedPK11Slot GetPrivateSlot(
226 const base::Callback<void(ScopedPK11Slot)>& callback) {
227 if (private_slot_)
228 return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()));
229 if (!callback.is_null())
230 tpm_ready_callback_list_.push_back(callback);
231 return ScopedPK11Slot();
232 }
233
234 void SetPrivateSlot(ScopedPK11Slot private_slot) {
235 DCHECK(!private_slot_);
dchengcf738a92015-12-31 16:11:45236 private_slot_ = std::move(private_slot);
[email protected]557737f72013-12-06 22:24:07237
238 SlotReadyCallbackList callback_list;
239 callback_list.swap(tpm_ready_callback_list_);
240 for (SlotReadyCallbackList::iterator i = callback_list.begin();
241 i != callback_list.end();
242 ++i) {
243 (*i).Run(ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())));
244 }
245 }
246
[email protected]4071e6ac2014-07-12 12:46:17247 bool private_slot_initialization_started() const {
248 return private_slot_initialization_started_;
249 }
250
251 void set_private_slot_initialization_started() {
252 private_slot_initialization_started_ = true;
253 }
254
[email protected]557737f72013-12-06 22:24:07255 private:
256 ScopedPK11Slot public_slot_;
257 ScopedPK11Slot private_slot_;
[email protected]4071e6ac2014-07-12 12:46:17258
259 bool private_slot_initialization_started_;
[email protected]557737f72013-12-06 22:24:07260
261 typedef std::vector<base::Callback<void(ScopedPK11Slot)> >
262 SlotReadyCallbackList;
263 SlotReadyCallbackList tpm_ready_callback_list_;
264};
spangba254c42015-05-14 00:00:23265
266class ScopedChapsLoadFixup {
267 public:
268 ScopedChapsLoadFixup();
269 ~ScopedChapsLoadFixup();
270
271 private:
272#if defined(COMPONENT_BUILD)
273 void *chaps_handle_;
274#endif
275};
276
277#if defined(COMPONENT_BUILD)
278
279ScopedChapsLoadFixup::ScopedChapsLoadFixup() {
280 // HACK: libchaps links the system protobuf and there are symbol conflicts
281 // with the bundled copy. Load chaps with RTLD_DEEPBIND to workaround.
282 chaps_handle_ = dlopen(kChapsPath, RTLD_LOCAL | RTLD_NOW | RTLD_DEEPBIND);
283}
284
285ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {
286 // LoadModule() will have taken a 2nd reference.
287 if (chaps_handle_)
288 dlclose(chaps_handle_);
289}
290
291#else
292
293ScopedChapsLoadFixup::ScopedChapsLoadFixup() {}
294ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {}
295
296#endif // defined(COMPONENT_BUILD)
[email protected]557737f72013-12-06 22:24:07297#endif // defined(OS_CHROMEOS)
298
[email protected]bc1e07c72008-09-16 14:32:44299class NSSInitSingleton {
300 public:
[email protected]f615bda32010-11-21 01:04:56301#if defined(OS_CHROMEOS)
[email protected]e2ea5ca2014-02-27 22:27:21302 // Used with PostTaskAndReply to pass handles to worker thread and back.
303 struct TPMModuleAndSlot {
304 explicit TPMModuleAndSlot(SECMODModule* init_chaps_module)
[email protected]966669ae2014-07-30 21:03:45305 : chaps_module(init_chaps_module) {}
[email protected]e2ea5ca2014-02-27 22:27:21306 SECMODModule* chaps_module;
[email protected]966669ae2014-07-30 21:03:45307 crypto::ScopedPK11Slot tpm_slot;
[email protected]e2ea5ca2014-02-27 22:27:21308 };
309
[email protected]190933f2014-07-28 09:56:51310 ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name,
311 const base::FilePath& path) {
[email protected]557737f72013-12-06 22:24:07312 DCHECK(thread_checker_.CalledOnValidThread());
313 // NSS is allowed to do IO on the current thread since dispatching
314 // to a dedicated thread would still have the affect of blocking
315 // the current thread, due to NSS's internal locking requirements
316 base::ThreadRestrictions::ScopedAllowIO allow_io;
317
318 base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb");
319 if (!base::CreateDirectory(nssdb_path)) {
320 LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory.";
[email protected]190933f2014-07-28 09:56:51321 return ScopedPK11Slot();
[email protected]557737f72013-12-06 22:24:07322 }
[email protected]190933f2014-07-28 09:56:51323 return OpenSoftwareNSSDB(nssdb_path, db_name);
[email protected]557737f72013-12-06 22:24:07324 }
325
[email protected]450b4ad72012-05-17 10:04:17326 void EnableTPMTokenForNSS() {
[email protected]0f8f69c2013-11-12 02:56:31327 DCHECK(thread_checker_.CalledOnValidThread());
328
[email protected]3f3b9b12013-10-25 22:03:26329 // If this gets set, then we'll use the TPM for certs with
330 // private keys, otherwise we'll fall back to the software
331 // implementation.
[email protected]450b4ad72012-05-17 10:04:17332 tpm_token_enabled_for_nss_ = true;
[email protected]6a89ef22011-04-07 17:34:21333 }
334
[email protected]557737f72013-12-06 22:24:07335 bool IsTPMTokenEnabledForNSS() {
336 DCHECK(thread_checker_.CalledOnValidThread());
337 return tpm_token_enabled_for_nss_;
338 }
339
[email protected]496318862014-07-13 07:19:00340 void InitializeTPMTokenAndSystemSlot(
341 int system_slot_id,
342 const base::Callback<void(bool)>& callback) {
[email protected]0f8f69c2013-11-12 02:56:31343 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]e2ea5ca2014-02-27 22:27:21344 // Should not be called while there is already an initialization in
345 // progress.
346 DCHECK(!initializing_tpm_token_);
[email protected]450b4ad72012-05-17 10:04:17347 // If EnableTPMTokenForNSS hasn't been called, return false.
[email protected]e2ea5ca2014-02-27 22:27:21348 if (!tpm_token_enabled_for_nss_) {
fdoray34e1fb82016-06-08 14:43:22349 base::ThreadTaskRunnerHandle::Get()->PostTask(
350 FROM_HERE, base::Bind(callback, false));
[email protected]e2ea5ca2014-02-27 22:27:21351 return;
352 }
[email protected]14172c82012-02-28 10:34:21353
[email protected]450b4ad72012-05-17 10:04:17354 // If everything is already initialized, then return true.
[email protected]e2ea5ca2014-02-27 22:27:21355 // Note that only |tpm_slot_| is checked, since |chaps_module_| could be
rsleeviffe5a132016-06-28 01:51:52356 // nullptr in tests while |tpm_slot_| has been set to the test DB.
[email protected]e2ea5ca2014-02-27 22:27:21357 if (tpm_slot_) {
fdoray34e1fb82016-06-08 14:43:22358 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
359 base::Bind(callback, true));
[email protected]e2ea5ca2014-02-27 22:27:21360 return;
361 }
[email protected]450b4ad72012-05-17 10:04:17362
[email protected]e2ea5ca2014-02-27 22:27:21363 // Note that a reference is not taken to chaps_module_. This is safe since
364 // NSSInitSingleton is Leaky, so the reference it holds is never released.
thakisd1a18472016-04-08 22:30:41365 std::unique_ptr<TPMModuleAndSlot> tpm_args(
366 new TPMModuleAndSlot(chaps_module_));
[email protected]e2ea5ca2014-02-27 22:27:21367 TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
368 if (base::WorkerPool::PostTaskAndReply(
369 FROM_HERE,
370 base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread,
[email protected]496318862014-07-13 07:19:00371 system_slot_id,
[email protected]e2ea5ca2014-02-27 22:27:21372 tpm_args_ptr),
[email protected]496318862014-07-13 07:19:00373 base::Bind(&NSSInitSingleton::OnInitializedTPMTokenAndSystemSlot,
[email protected]e2ea5ca2014-02-27 22:27:21374 base::Unretained(this), // NSSInitSingleton is leaky
375 callback,
376 base::Passed(&tpm_args)),
377 true /* task_is_slow */
378 )) {
379 initializing_tpm_token_ = true;
380 } else {
fdoray34e1fb82016-06-08 14:43:22381 base::ThreadTaskRunnerHandle::Get()->PostTask(
382 FROM_HERE, base::Bind(callback, false));
[email protected]e2ea5ca2014-02-27 22:27:21383 }
384 }
385
386 static void InitializeTPMTokenOnWorkerThread(CK_SLOT_ID token_slot_id,
387 TPMModuleAndSlot* tpm_args) {
[email protected]450b4ad72012-05-17 10:04:17388 // This tries to load the Chaps module so NSS can talk to the hardware
389 // TPM.
[email protected]e2ea5ca2014-02-27 22:27:21390 if (!tpm_args->chaps_module) {
spangba254c42015-05-14 00:00:23391 ScopedChapsLoadFixup chaps_loader;
392
[email protected]e2ea5ca2014-02-27 22:27:21393 DVLOG(3) << "Loading chaps...";
394 tpm_args->chaps_module = LoadModule(
[email protected]450b4ad72012-05-17 10:04:17395 kChapsModuleName,
396 kChapsPath,
397 // For more details on these parameters, see:
398 // https://developer.mozilla.org/en/PKCS11_Module_Specs
399 // slotFlags=[PublicCerts] -- Certificates and public keys can be
400 // read from this slot without requiring a call to C_Login.
401 // askpw=only -- Only authenticate to the token when necessary.
402 "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\"");
[email protected]14172c82012-02-28 10:34:21403 }
[email protected]e2ea5ca2014-02-27 22:27:21404 if (tpm_args->chaps_module) {
405 tpm_args->tpm_slot =
406 GetTPMSlotForIdOnWorkerThread(tpm_args->chaps_module, token_slot_id);
407 }
408 }
[email protected]450b4ad72012-05-17 10:04:17409
[email protected]496318862014-07-13 07:19:00410 void OnInitializedTPMTokenAndSystemSlot(
411 const base::Callback<void(bool)>& callback,
thakisd1a18472016-04-08 22:30:41412 std::unique_ptr<TPMModuleAndSlot> tpm_args) {
[email protected]e2ea5ca2014-02-27 22:27:21413 DCHECK(thread_checker_.CalledOnValidThread());
414 DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module
415 << ", got tpm slot: " << !!tpm_args->tpm_slot;
[email protected]557737f72013-12-06 22:24:07416
[email protected]e2ea5ca2014-02-27 22:27:21417 chaps_module_ = tpm_args->chaps_module;
dchengcf738a92015-12-31 16:11:45418 tpm_slot_ = std::move(tpm_args->tpm_slot);
[email protected]190933f2014-07-28 09:56:51419 if (!chaps_module_ && test_system_slot_) {
[email protected]e2ea5ca2014-02-27 22:27:21420 // chromeos_unittests try to test the TPM initialization process. If we
421 // have a test DB open, pretend that it is the TPM slot.
[email protected]966669ae2014-07-30 21:03:45422 tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
[email protected]e2ea5ca2014-02-27 22:27:21423 }
424 initializing_tpm_token_ = false;
425
[email protected]442233d42014-08-02 07:37:24426 if (tpm_slot_)
427 RunAndClearTPMReadyCallbackList();
[email protected]e2ea5ca2014-02-27 22:27:21428
429 callback.Run(!!tpm_slot_);
[email protected]c175cdb2011-06-28 20:41:55430 }
431
[email protected]442233d42014-08-02 07:37:24432 void RunAndClearTPMReadyCallbackList() {
433 TPMReadyCallbackList callback_list;
434 callback_list.swap(tpm_ready_callback_list_);
435 for (TPMReadyCallbackList::iterator i = callback_list.begin();
436 i != callback_list.end();
437 ++i) {
438 i->Run();
439 }
440 }
441
[email protected]557737f72013-12-06 22:24:07442 bool IsTPMTokenReady(const base::Closure& callback) {
443 if (!callback.is_null()) {
444 // Cannot DCHECK in the general case yet, but since the callback is
445 // a new addition to the API, DCHECK to make sure at least the new uses
446 // don't regress.
447 DCHECK(thread_checker_.CalledOnValidThread());
448 } else if (!thread_checker_.CalledOnValidThread()) {
449 // TODO(mattm): Change to DCHECK when callers have been fixed.
[email protected]0f8f69c2013-11-12 02:56:31450 DVLOG(1) << "Called on wrong thread.\n"
451 << base::debug::StackTrace().ToString();
452 }
453
[email protected]966669ae2014-07-30 21:03:45454 if (tpm_slot_)
[email protected]557737f72013-12-06 22:24:07455 return true;
456
457 if (!callback.is_null())
458 tpm_ready_callback_list_.push_back(callback);
459
460 return false;
[email protected]74beead2011-04-12 20:40:12461 }
462
[email protected]3f3b9b12013-10-25 22:03:26463 // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot
464 // id as an int. This should be safe since this is only used with chaps, which
465 // we also control.
[email protected]966669ae2014-07-30 21:03:45466 static crypto::ScopedPK11Slot GetTPMSlotForIdOnWorkerThread(
467 SECMODModule* chaps_module,
468 CK_SLOT_ID slot_id) {
[email protected]e2ea5ca2014-02-27 22:27:21469 DCHECK(chaps_module);
[email protected]3f3b9b12013-10-25 22:03:26470
[email protected]557737f72013-12-06 22:24:07471 DVLOG(3) << "Poking chaps module.";
[email protected]e2ea5ca2014-02-27 22:27:21472 SECStatus rv = SECMOD_UpdateSlotList(chaps_module);
[email protected]3f3b9b12013-10-25 22:03:26473 if (rv != SECSuccess)
474 PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError();
475
[email protected]e2ea5ca2014-02-27 22:27:21476 PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module->moduleID, slot_id);
[email protected]3f3b9b12013-10-25 22:03:26477 if (!slot)
478 LOG(ERROR) << "TPM slot " << slot_id << " not found.";
[email protected]966669ae2014-07-30 21:03:45479 return crypto::ScopedPK11Slot(slot);
[email protected]6a89ef22011-04-07 17:34:21480 }
[email protected]557737f72013-12-06 22:24:07481
pneubeckfa32f2e2014-09-12 09:59:00482 bool InitializeNSSForChromeOSUser(const std::string& username_hash,
483 const base::FilePath& path) {
[email protected]557737f72013-12-06 22:24:07484 DCHECK(thread_checker_.CalledOnValidThread());
485 if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) {
486 // This user already exists in our mapping.
487 DVLOG(2) << username_hash << " already initialized.";
488 return false;
489 }
[email protected]4071e6ac2014-07-12 12:46:17490
[email protected]4071e6ac2014-07-12 12:46:17491 DVLOG(2) << "Opening NSS DB " << path.value();
[email protected]83e1ae32014-07-18 10:57:07492 std::string db_name = base::StringPrintf(
493 "%s %s", kUserNSSDatabaseName, username_hash.c_str());
494 ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path));
[email protected]557737f72013-12-06 22:24:07495 chromeos_user_map_[username_hash] =
dchengcf738a92015-12-31 16:11:45496 new ChromeOSUserData(std::move(public_slot));
[email protected]557737f72013-12-06 22:24:07497 return true;
498 }
499
[email protected]4071e6ac2014-07-12 12:46:17500 bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
501 DCHECK(thread_checker_.CalledOnValidThread());
502 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
503
504 return !chromeos_user_map_[username_hash]
505 ->private_slot_initialization_started();
506 }
507
508 void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
509 DCHECK(thread_checker_.CalledOnValidThread());
510 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
511
512 chromeos_user_map_[username_hash]
513 ->set_private_slot_initialization_started();
514 }
515
[email protected]557737f72013-12-06 22:24:07516 void InitializeTPMForChromeOSUser(const std::string& username_hash,
517 CK_SLOT_ID slot_id) {
518 DCHECK(thread_checker_.CalledOnValidThread());
519 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
[email protected]4071e6ac2014-07-12 12:46:17520 DCHECK(chromeos_user_map_[username_hash]->
521 private_slot_initialization_started());
[email protected]e2ea5ca2014-02-27 22:27:21522
523 if (!chaps_module_)
524 return;
525
526 // Note that a reference is not taken to chaps_module_. This is safe since
527 // NSSInitSingleton is Leaky, so the reference it holds is never released.
thakisd1a18472016-04-08 22:30:41528 std::unique_ptr<TPMModuleAndSlot> tpm_args(
529 new TPMModuleAndSlot(chaps_module_));
[email protected]e2ea5ca2014-02-27 22:27:21530 TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
531 base::WorkerPool::PostTaskAndReply(
532 FROM_HERE,
533 base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread,
534 slot_id,
535 tpm_args_ptr),
536 base::Bind(&NSSInitSingleton::OnInitializedTPMForChromeOSUser,
537 base::Unretained(this), // NSSInitSingleton is leaky
538 username_hash,
539 base::Passed(&tpm_args)),
540 true /* task_is_slow */
541 );
542 }
543
thakisd1a18472016-04-08 22:30:41544 void OnInitializedTPMForChromeOSUser(
545 const std::string& username_hash,
546 std::unique_ptr<TPMModuleAndSlot> tpm_args) {
[email protected]e2ea5ca2014-02-27 22:27:21547 DCHECK(thread_checker_.CalledOnValidThread());
548 DVLOG(2) << "Got tpm slot for " << username_hash << " "
549 << !!tpm_args->tpm_slot;
550 chromeos_user_map_[username_hash]->SetPrivateSlot(
dchengcf738a92015-12-31 16:11:45551 std::move(tpm_args->tpm_slot));
[email protected]557737f72013-12-06 22:24:07552 }
553
554 void InitializePrivateSoftwareSlotForChromeOSUser(
555 const std::string& username_hash) {
556 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]31946992014-01-31 22:29:02557 VLOG(1) << "using software private slot for " << username_hash;
[email protected]557737f72013-12-06 22:24:07558 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
[email protected]4071e6ac2014-07-12 12:46:17559 DCHECK(chromeos_user_map_[username_hash]->
560 private_slot_initialization_started());
561
[email protected]557737f72013-12-06 22:24:07562 chromeos_user_map_[username_hash]->SetPrivateSlot(
563 chromeos_user_map_[username_hash]->GetPublicSlot());
564 }
565
566 ScopedPK11Slot GetPublicSlotForChromeOSUser(
567 const std::string& username_hash) {
568 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]7037a43c2014-01-14 14:00:46569
570 if (username_hash.empty()) {
571 DVLOG(2) << "empty username_hash";
572 return ScopedPK11Slot();
573 }
574
[email protected]557737f72013-12-06 22:24:07575 if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) {
576 LOG(ERROR) << username_hash << " not initialized.";
577 return ScopedPK11Slot();
578 }
579 return chromeos_user_map_[username_hash]->GetPublicSlot();
580 }
581
582 ScopedPK11Slot GetPrivateSlotForChromeOSUser(
583 const std::string& username_hash,
584 const base::Callback<void(ScopedPK11Slot)>& callback) {
585 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]7037a43c2014-01-14 14:00:46586
587 if (username_hash.empty()) {
588 DVLOG(2) << "empty username_hash";
589 if (!callback.is_null()) {
fdoray34e1fb82016-06-08 14:43:22590 base::ThreadTaskRunnerHandle::Get()->PostTask(
[email protected]7037a43c2014-01-14 14:00:46591 FROM_HERE, base::Bind(callback, base::Passed(ScopedPK11Slot())));
592 }
593 return ScopedPK11Slot();
594 }
595
[email protected]557737f72013-12-06 22:24:07596 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
597
[email protected]557737f72013-12-06 22:24:07598 return chromeos_user_map_[username_hash]->GetPrivateSlot(callback);
599 }
[email protected]e53c02322013-12-17 00:09:00600
[email protected]190933f2014-07-28 09:56:51601 void CloseChromeOSUserForTesting(const std::string& username_hash) {
[email protected]e53c02322013-12-17 00:09:00602 DCHECK(thread_checker_.CalledOnValidThread());
603 ChromeOSUserMap::iterator i = chromeos_user_map_.find(username_hash);
604 DCHECK(i != chromeos_user_map_.end());
605 delete i->second;
606 chromeos_user_map_.erase(i);
607 }
[email protected]190933f2014-07-28 09:56:51608
609 void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
610 // Ensure that a previous value of test_system_slot_ is not overwritten.
rsleeviffe5a132016-06-28 01:51:52611 // Unsetting, i.e. setting a nullptr, however is allowed.
[email protected]190933f2014-07-28 09:56:51612 DCHECK(!slot || !test_system_slot_);
dchengcf738a92015-12-31 16:11:45613 test_system_slot_ = std::move(slot);
[email protected]442233d42014-08-02 07:37:24614 if (test_system_slot_) {
615 tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
616 RunAndClearTPMReadyCallbackList();
617 } else {
618 tpm_slot_.reset();
619 }
[email protected]190933f2014-07-28 09:56:51620 }
[email protected]f615bda32010-11-21 01:04:56621#endif // defined(OS_CHROMEOS)
622
[email protected]190933f2014-07-28 09:56:51623#if !defined(OS_CHROMEOS)
[email protected]496318862014-07-13 07:19:00624 PK11SlotInfo* GetPersistentNSSKeySlot() {
[email protected]0f8f69c2013-11-12 02:56:31625 // TODO(mattm): Change to DCHECK when callers have been fixed.
626 if (!thread_checker_.CalledOnValidThread()) {
627 DVLOG(1) << "Called on wrong thread.\n"
628 << base::debug::StackTrace().ToString();
629 }
630
[email protected]6a89ef22011-04-07 17:34:21631 return PK11_GetInternalKeySlot();
632 }
[email protected]190933f2014-07-28 09:56:51633#endif
[email protected]6a89ef22011-04-07 17:34:21634
[email protected]c64b9142011-04-19 18:49:54635#if defined(OS_CHROMEOS)
[email protected]8edd7212014-07-30 12:24:29636 void GetSystemNSSKeySlotCallback(
637 const base::Callback<void(ScopedPK11Slot)>& callback) {
[email protected]966669ae2014-07-30 21:03:45638 callback.Run(ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get())));
[email protected]8edd7212014-07-30 12:24:29639 }
[email protected]496318862014-07-13 07:19:00640
[email protected]8edd7212014-07-30 12:24:29641 ScopedPK11Slot GetSystemNSSKeySlot(
642 const base::Callback<void(ScopedPK11Slot)>& callback) {
643 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]496318862014-07-13 07:19:00644 // TODO(mattm): chromeos::TPMTokenloader always calls
645 // InitializeTPMTokenAndSystemSlot with slot 0. If the system slot is
646 // disabled, tpm_slot_ will be the first user's slot instead. Can that be
rsleeviffe5a132016-06-28 01:51:52647 // detected and return nullptr instead?
[email protected]8edd7212014-07-30 12:24:29648
649 base::Closure wrapped_callback;
650 if (!callback.is_null()) {
651 wrapped_callback =
652 base::Bind(&NSSInitSingleton::GetSystemNSSKeySlotCallback,
653 base::Unretained(this) /* singleton is leaky */,
654 callback);
655 }
656 if (IsTPMTokenReady(wrapped_callback))
[email protected]966669ae2014-07-30 21:03:45657 return ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get()));
[email protected]8edd7212014-07-30 12:24:29658 return ScopedPK11Slot();
[email protected]f615bda32010-11-21 01:04:56659 }
[email protected]496318862014-07-13 07:19:00660#endif
[email protected]f615bda32010-11-21 01:04:56661
[email protected]4b559b4d2011-04-14 17:37:14662 base::Lock* write_lock() {
[email protected]f615bda32010-11-21 01:04:56663 return &write_lock_;
664 }
[email protected]f615bda32010-11-21 01:04:56665
666 private:
[email protected]4b559b4d2011-04-14 17:37:14667 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>;
[email protected]f615bda32010-11-21 01:04:56668
[email protected]dcce6cf2010-04-29 17:50:06669 NSSInitSingleton()
[email protected]450b4ad72012-05-17 10:04:17670 : tpm_token_enabled_for_nss_(false),
[email protected]e2ea5ca2014-02-27 22:27:21671 initializing_tpm_token_(false),
rsleeviffe5a132016-06-28 01:51:52672 chaps_module_(nullptr),
673 root_(nullptr) {
[email protected]0f8f69c2013-11-12 02:56:31674 // It's safe to construct on any thread, since LazyInstance will prevent any
675 // other threads from accessing until the constructor is done.
676 thread_checker_.DetachFromThread();
677
[email protected]f615bda32010-11-21 01:04:56678 EnsureNSPRInit();
[email protected]730fb132009-09-02 22:50:25679
[email protected]805acdc2013-08-07 22:57:00680 // We *must* have NSS >= 3.14.3.
anujk.sharma3cec2ab2015-01-22 02:35:02681 static_assert(
[email protected]805acdc2013-08-07 22:57:00682 (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) ||
683 (NSS_VMAJOR == 3 && NSS_VMINOR > 14) ||
[email protected]dc36c9c2010-01-20 20:45:00684 (NSS_VMAJOR > 3),
anujk.sharma3cec2ab2015-01-22 02:35:02685 "nss version check failed");
[email protected]dc36c9c2010-01-20 20:45:00686 // Also check the run-time NSS version.
687 // NSS_VersionCheck is a >= check, not strict equality.
[email protected]805acdc2013-08-07 22:57:00688 if (!NSS_VersionCheck("3.14.3")) {
689 LOG(FATAL) << "NSS_VersionCheck(\"3.14.3\") failed. NSS >= 3.14.3 is "
690 "required. Please upgrade to the latest NSS, and if you "
[email protected]1b8082d2010-02-19 12:21:48691 "still get this error, contact your distribution "
692 "maintainer.";
693 }
[email protected]dc36c9c2010-01-20 20:45:00694
[email protected]897f5202009-09-08 17:40:27695 SECStatus status = SECFailure;
rsleevia3ad8d02016-06-07 18:22:33696 base::FilePath database_dir = GetInitialConfigDirectory();
697 if (!database_dir.empty()) {
698 // This duplicates the work which should have been done in
699 // EarlySetupForNSSInit. However, this function is idempotent so
700 // there's no harm done.
701 UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
davidben2e6b3792015-08-11 18:18:58702
rsleevia3ad8d02016-06-07 18:22:33703 // Initialize with a persistent database (likely, ~/.pki/nssdb).
704 // Use "sql:" which can be shared by multiple processes safely.
705 std::string nss_config_dir =
706 base::StringPrintf("sql:%s", database_dir.value().c_str());
707#if defined(OS_CHROMEOS)
708 status = NSS_Init(nss_config_dir.c_str());
709#else
710 status = NSS_InitReadWrite(nss_config_dir.c_str());
[email protected]dcce6cf2010-04-29 17:50:06711#endif
rsleevia3ad8d02016-06-07 18:22:33712 if (status != SECSuccess) {
713 LOG(ERROR) << "Error initializing NSS with a persistent "
714 "database (" << nss_config_dir
715 << "): " << GetNSSErrorMessage();
716 }
717 }
718 if (status != SECSuccess) {
719 VLOG(1) << "Initializing NSS without a persistent database.";
rsleeviffe5a132016-06-28 01:51:52720 status = NSS_NoDB_Init(nullptr);
[email protected]897f5202009-09-08 17:40:27721 if (status != SECSuccess) {
[email protected]007f5122012-11-21 16:00:21722 CrashOnNSSInitFailure();
[email protected]716fb112012-11-15 05:41:25723 return;
[email protected]897f5202009-09-08 17:40:27724 }
[email protected]6e7e8062009-04-13 17:35:09725 }
[email protected]fa2d3dc2012-11-20 07:58:44726
rsleevia3ad8d02016-06-07 18:22:33727 PK11_SetPasswordFunc(PKCS11PasswordFunc);
728
729 // If we haven't initialized the password for the NSS databases,
730 // initialize an empty-string password so that we don't need to
731 // log in.
732 PK11SlotInfo* slot = PK11_GetInternalKeySlot();
733 if (slot) {
734 // PK11_InitPin may write to the keyDB, but no other thread can use NSS
735 // yet, so we don't need to lock.
736 if (PK11_NeedUserInit(slot))
rsleeviffe5a132016-06-28 01:51:52737 PK11_InitPin(slot, nullptr, nullptr);
rsleevia3ad8d02016-06-07 18:22:33738 PK11_FreeSlot(slot);
739 }
740
741 root_ = InitDefaultRootCerts();
742
[email protected]fa2d3dc2012-11-20 07:58:44743 // Disable MD5 certificate signatures. (They are disabled by default in
744 // NSS 3.14.)
745 NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
746 NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
747 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
[email protected]bc1e07c72008-09-16 14:32:44748 }
749
[email protected]f615bda32010-11-21 01:04:56750 // NOTE(willchan): We don't actually execute this code since we leak NSS to
751 // prevent non-joinable threads from using NSS after it's already been shut
752 // down.
[email protected]bc1e07c72008-09-16 14:32:44753 ~NSSInitSingleton() {
[email protected]557737f72013-12-06 22:24:07754#if defined(OS_CHROMEOS)
755 STLDeleteValues(&chromeos_user_map_);
756#endif
[email protected]966669ae2014-07-30 21:03:45757 tpm_slot_.reset();
[email protected]ea224582008-12-07 20:25:46758 if (root_) {
759 SECMOD_UnloadUserModule(root_);
760 SECMOD_DestroyModule(root_);
rsleeviffe5a132016-06-28 01:51:52761 root_ = nullptr;
[email protected]ea224582008-12-07 20:25:46762 }
[email protected]84e47722011-11-17 05:12:02763 if (chaps_module_) {
764 SECMOD_UnloadUserModule(chaps_module_);
765 SECMOD_DestroyModule(chaps_module_);
rsleeviffe5a132016-06-28 01:51:52766 chaps_module_ = nullptr;
[email protected]6a89ef22011-04-07 17:34:21767 }
[email protected]ea224582008-12-07 20:25:46768
[email protected]c1444fe2008-09-17 09:42:51769 SECStatus status = NSS_Shutdown();
[email protected]f8adef52009-08-04 17:52:06770 if (status != SECSuccess) {
[email protected]b026e35d2010-10-19 02:31:03771 // We VLOG(1) because this failure is relatively harmless (leaking, but
772 // we're shutting down anyway).
[email protected]6a89ef22011-04-07 17:34:21773 VLOG(1) << "NSS_Shutdown failed; see http://crbug.com/4609";
[email protected]f8adef52009-08-04 17:52:06774 }
[email protected]bc1e07c72008-09-16 14:32:44775 }
[email protected]c72f16a2009-03-19 16:02:31776
[email protected]6a89ef22011-04-07 17:34:21777 // Load nss's built-in root certs.
778 SECMODModule* InitDefaultRootCerts() {
rsleeviffe5a132016-06-28 01:51:52779 SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", nullptr);
[email protected]6a89ef22011-04-07 17:34:21780 if (root)
781 return root;
782
783 // Aw, snap. Can't find/load root cert shared library.
784 // This will make it hard to talk to anybody via https.
[email protected]3f3b9b12013-10-25 22:03:26785 // TODO(mattm): Re-add the NOTREACHED here when crbug.com/310972 is fixed.
rsleeviffe5a132016-06-28 01:51:52786 return nullptr;
[email protected]6a89ef22011-04-07 17:34:21787 }
788
789 // Load the given module for this NSS session.
[email protected]e2ea5ca2014-02-27 22:27:21790 static SECMODModule* LoadModule(const char* name,
791 const char* library_path,
792 const char* params) {
[email protected]7d3cbc92013-03-18 22:33:04793 std::string modparams = base::StringPrintf(
[email protected]6a89ef22011-04-07 17:34:21794 "name=\"%s\" library=\"%s\" %s",
795 name, library_path, params ? params : "");
796
797 // Shouldn't need to const_cast here, but SECMOD doesn't properly
798 // declare input string arguments as const. Bug
799 // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed
800 // on NSS codebase to address this.
801 SECMODModule* module = SECMOD_LoadUserModule(
rsleeviffe5a132016-06-28 01:51:52802 const_cast<char*>(modparams.c_str()), nullptr, PR_FALSE);
[email protected]6a89ef22011-04-07 17:34:21803 if (!module) {
804 LOG(ERROR) << "Error loading " << name << " module into NSS: "
805 << GetNSSErrorMessage();
rsleeviffe5a132016-06-28 01:51:52806 return nullptr;
[email protected]6a89ef22011-04-07 17:34:21807 }
[email protected]3f3b9b12013-10-25 22:03:26808 if (!module->loaded) {
809 LOG(ERROR) << "After loading " << name << ", loaded==false: "
810 << GetNSSErrorMessage();
811 SECMOD_DestroyModule(module);
rsleeviffe5a132016-06-28 01:51:52812 return nullptr;
[email protected]3f3b9b12013-10-25 22:03:26813 }
[email protected]6a89ef22011-04-07 17:34:21814 return module;
815 }
[email protected]6a89ef22011-04-07 17:34:21816
[email protected]450b4ad72012-05-17 10:04:17817 bool tpm_token_enabled_for_nss_;
[email protected]e2ea5ca2014-02-27 22:27:21818 bool initializing_tpm_token_;
[email protected]557737f72013-12-06 22:24:07819 typedef std::vector<base::Closure> TPMReadyCallbackList;
820 TPMReadyCallbackList tpm_ready_callback_list_;
[email protected]84e47722011-11-17 05:12:02821 SECMODModule* chaps_module_;
[email protected]966669ae2014-07-30 21:03:45822 crypto::ScopedPK11Slot tpm_slot_;
[email protected]6a89ef22011-04-07 17:34:21823 SECMODModule* root_;
[email protected]557737f72013-12-06 22:24:07824#if defined(OS_CHROMEOS)
825 typedef std::map<std::string, ChromeOSUserData*> ChromeOSUserMap;
826 ChromeOSUserMap chromeos_user_map_;
[email protected]190933f2014-07-28 09:56:51827 ScopedPK11Slot test_system_slot_;
[email protected]557737f72013-12-06 22:24:07828#endif
[email protected]f615bda32010-11-21 01:04:56829 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011
830 // is fixed, we will no longer need the lock.
[email protected]4b559b4d2011-04-14 17:37:14831 base::Lock write_lock_;
[email protected]0f8f69c2013-11-12 02:56:31832
833 base::ThreadChecker thread_checker_;
[email protected]bc1e07c72008-09-16 14:32:44834};
835
[email protected]9fc44162012-01-23 22:56:41836base::LazyInstance<NSSInitSingleton>::Leaky
[email protected]6de0fd1d2011-11-15 13:31:49837 g_nss_singleton = LAZY_INSTANCE_INITIALIZER;
[email protected]bc1e07c72008-09-16 14:32:44838} // namespace
839
[email protected]190933f2014-07-28 09:56:51840ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
841 const std::string& description) {
842 const std::string modspec =
843 base::StringPrintf("configDir='sql:%s' tokenDescription='%s'",
844 path.value().c_str(),
845 description.c_str());
846 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str());
847 if (db_slot) {
848 if (PK11_NeedUserInit(db_slot))
rsleeviffe5a132016-06-28 01:51:52849 PK11_InitPin(db_slot, nullptr, nullptr);
[email protected]190933f2014-07-28 09:56:51850 } else {
851 LOG(ERROR) << "Error opening persistent database (" << modspec
852 << "): " << GetNSSErrorMessage();
853 }
854 return ScopedPK11Slot(db_slot);
855}
856
[email protected]ac3d5972011-01-13 20:33:45857void EarlySetupForNSSInit() {
[email protected]9e275712013-02-10 19:20:14858 base::FilePath database_dir = GetInitialConfigDirectory();
[email protected]ac3d5972011-01-13 20:33:45859 if (!database_dir.empty())
860 UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
861}
[email protected]ac3d5972011-01-13 20:33:45862
[email protected]730fb132009-09-02 22:50:25863void EnsureNSPRInit() {
[email protected]f615bda32010-11-21 01:04:56864 g_nspr_singleton.Get();
[email protected]730fb132009-09-02 22:50:25865}
866
[email protected]bc1e07c72008-09-16 14:32:44867void EnsureNSSInit() {
[email protected]a8e4b5a82010-10-27 00:05:47868 // Initializing SSL causes us to do blocking IO.
869 // Temporarily allow it until we fix
870 // http://code.google.com/p/chromium/issues/detail?id=59847
[email protected]4b559b4d2011-04-14 17:37:14871 base::ThreadRestrictions::ScopedAllowIO allow_io;
[email protected]f615bda32010-11-21 01:04:56872 g_nss_singleton.Get();
[email protected]bc1e07c72008-09-16 14:32:44873}
874
[email protected]f61c3972010-12-23 09:54:15875bool CheckNSSVersion(const char* version) {
876 return !!NSS_VersionCheck(version);
877}
878
[email protected]4b559b4d2011-04-14 17:37:14879base::Lock* GetNSSWriteLock() {
[email protected]f615bda32010-11-21 01:04:56880 return g_nss_singleton.Get().write_lock();
[email protected]69138472010-06-25 22:44:48881}
882
883AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) {
rsleeviffe5a132016-06-28 01:51:52884 // May be nullptr if the lock is not needed in our version of NSS.
[email protected]69138472010-06-25 22:44:48885 if (lock_)
886 lock_->Acquire();
887}
888
889AutoNSSWriteLock::~AutoNSSWriteLock() {
890 if (lock_) {
891 lock_->AssertAcquired();
892 lock_->Release();
893 }
894}
[email protected]dd24ffc2011-06-08 19:46:42895
896AutoSECMODListReadLock::AutoSECMODListReadLock()
897 : lock_(SECMOD_GetDefaultModuleListLock()) {
898 SECMOD_GetReadLock(lock_);
899 }
900
901AutoSECMODListReadLock::~AutoSECMODListReadLock() {
902 SECMOD_ReleaseReadLock(lock_);
903}
[email protected]69138472010-06-25 22:44:48904
[email protected]dcce6cf2010-04-29 17:50:06905#if defined(OS_CHROMEOS)
[email protected]8edd7212014-07-30 12:24:29906ScopedPK11Slot GetSystemNSSKeySlot(
907 const base::Callback<void(ScopedPK11Slot)>& callback) {
908 return g_nss_singleton.Get().GetSystemNSSKeySlot(callback);
[email protected]496318862014-07-13 07:19:00909}
910
[email protected]190933f2014-07-28 09:56:51911void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
dchengcf738a92015-12-31 16:11:45912 g_nss_singleton.Get().SetSystemKeySlotForTesting(std::move(slot));
[email protected]190933f2014-07-28 09:56:51913}
914
[email protected]450b4ad72012-05-17 10:04:17915void EnableTPMTokenForNSS() {
916 g_nss_singleton.Get().EnableTPMTokenForNSS();
[email protected]6a89ef22011-04-07 17:34:21917}
918
[email protected]557737f72013-12-06 22:24:07919bool IsTPMTokenEnabledForNSS() {
920 return g_nss_singleton.Get().IsTPMTokenEnabledForNSS();
921}
922
923bool IsTPMTokenReady(const base::Closure& callback) {
924 return g_nss_singleton.Get().IsTPMTokenReady(callback);
[email protected]74beead2011-04-12 20:40:12925}
[email protected]c64b9142011-04-19 18:49:54926
[email protected]496318862014-07-13 07:19:00927void InitializeTPMTokenAndSystemSlot(
928 int token_slot_id,
929 const base::Callback<void(bool)>& callback) {
930 g_nss_singleton.Get().InitializeTPMTokenAndSystemSlot(token_slot_id,
931 callback);
[email protected]c175cdb2011-06-28 20:41:55932}
[email protected]557737f72013-12-06 22:24:07933
pneubeckfa32f2e2014-09-12 09:59:00934bool InitializeNSSForChromeOSUser(const std::string& username_hash,
935 const base::FilePath& path) {
936 return g_nss_singleton.Get().InitializeNSSForChromeOSUser(username_hash,
937 path);
[email protected]557737f72013-12-06 22:24:07938}
[email protected]4071e6ac2014-07-12 12:46:17939
940bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
941 return g_nss_singleton.Get().ShouldInitializeTPMForChromeOSUser(
942 username_hash);
943}
944
945void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
946 g_nss_singleton.Get().WillInitializeTPMForChromeOSUser(username_hash);
947}
948
[email protected]557737f72013-12-06 22:24:07949void InitializeTPMForChromeOSUser(
950 const std::string& username_hash,
951 CK_SLOT_ID slot_id) {
952 g_nss_singleton.Get().InitializeTPMForChromeOSUser(username_hash, slot_id);
953}
[email protected]190933f2014-07-28 09:56:51954
[email protected]557737f72013-12-06 22:24:07955void InitializePrivateSoftwareSlotForChromeOSUser(
956 const std::string& username_hash) {
957 g_nss_singleton.Get().InitializePrivateSoftwareSlotForChromeOSUser(
958 username_hash);
959}
[email protected]190933f2014-07-28 09:56:51960
[email protected]557737f72013-12-06 22:24:07961ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) {
962 return g_nss_singleton.Get().GetPublicSlotForChromeOSUser(username_hash);
963}
[email protected]190933f2014-07-28 09:56:51964
[email protected]557737f72013-12-06 22:24:07965ScopedPK11Slot GetPrivateSlotForChromeOSUser(
966 const std::string& username_hash,
967 const base::Callback<void(ScopedPK11Slot)>& callback) {
968 return g_nss_singleton.Get().GetPrivateSlotForChromeOSUser(username_hash,
969 callback);
970}
[email protected]190933f2014-07-28 09:56:51971
972void CloseChromeOSUserForTesting(const std::string& username_hash) {
973 g_nss_singleton.Get().CloseChromeOSUserForTesting(username_hash);
974}
[email protected]6a89ef22011-04-07 17:34:21975#endif // defined(OS_CHROMEOS)
[email protected]dcce6cf2010-04-29 17:50:06976
[email protected]4b559b4d2011-04-14 17:37:14977base::Time PRTimeToBaseTime(PRTime prtime) {
[email protected]ca929ed32011-12-15 20:37:28978 return base::Time::FromInternalValue(
979 prtime + base::Time::UnixEpoch().ToInternalValue());
980}
[email protected]1b1a264a2010-01-14 22:36:35981
[email protected]ca929ed32011-12-15 20:37:28982PRTime BaseTimeToPRTime(base::Time time) {
983 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue();
[email protected]1b1a264a2010-01-14 22:36:35984}
985
[email protected]190933f2014-07-28 09:56:51986#if !defined(OS_CHROMEOS)
[email protected]496318862014-07-13 07:19:00987PK11SlotInfo* GetPersistentNSSKeySlot() {
988 return g_nss_singleton.Get().GetPersistentNSSKeySlot();
[email protected]dcce6cf2010-04-29 17:50:06989}
[email protected]190933f2014-07-28 09:56:51990#endif
[email protected]dcce6cf2010-04-29 17:50:06991
[email protected]4b559b4d2011-04-14 17:37:14992} // namespace crypto