blob: a7cb9e80002d01b30e930d077845f26e19ce0dfd [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>
dchengcf738a92015-12-31 16:11:4514#include <utility>
15
16#include "crypto/nss_util_internal.h"
[email protected]b43c97c2008-10-22 19:50:5817
[email protected]5a77df52014-02-05 08:37:4818#if defined(OS_OPENBSD)
[email protected]d816516f2011-10-25 19:11:5919#include <sys/mount.h>
20#include <sys/param.h>
[email protected]a8b58f42010-07-14 20:21:3521#endif
22
spangba254c42015-05-14 00:00:2323#if defined(OS_CHROMEOS)
24#include <dlfcn.h>
25#endif
26
[email protected]557737f72013-12-06 22:24:0727#include <map>
[email protected]f6a67b42011-03-17 23:49:2128#include <vector>
29
[email protected]6bdc52272014-05-27 00:12:3330#include "base/base_paths.h"
[email protected]7037a43c2014-01-14 14:00:4631#include "base/bind.h"
[email protected]f3d445e2013-11-22 18:35:0332#include "base/cpu.h"
[email protected]716fb112012-11-15 05:41:2533#include "base/debug/alias.h"
[email protected]0f8f69c2013-11-12 02:56:3134#include "base/debug/stack_trace.h"
[email protected]ed450f32011-03-16 01:26:4935#include "base/environment.h"
[email protected]57999812013-02-24 05:40:5236#include "base/files/file_path.h"
thestigc9e38a22014-09-13 01:02:1137#include "base/files/file_util.h"
[email protected]f615bda32010-11-21 01:04:5638#include "base/lazy_instance.h"
[email protected]c1444fe2008-09-17 09:42:5139#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1540#include "base/memory/scoped_ptr.h"
[email protected]7037a43c2014-01-14 14:00:4641#include "base/message_loop/message_loop.h"
[email protected]f6a67b42011-03-17 23:49:2142#include "base/native_library.h"
[email protected]6bdc52272014-05-27 00:12:3343#include "base/path_service.h"
[email protected]557737f72013-12-06 22:24:0744#include "base/stl_util.h"
[email protected]0d8db082013-06-11 07:27:0145#include "base/strings/stringprintf.h"
[email protected]0f8f69c2013-11-12 02:56:3146#include "base/threading/thread_checker.h"
[email protected]34b99632011-01-01 01:01:0647#include "base/threading/thread_restrictions.h"
[email protected]e2ea5ca2014-02-27 22:27:2148#include "base/threading/worker_pool.h"
[email protected]26661c22011-10-07 01:33:5849#include "build/build_config.h"
[email protected]bc1e07c72008-09-16 14:32:4450
davidben71f35ff2015-04-17 20:54:4851// USE_NSS_CERTS means NSS is used for certificates and platform integration.
52// This requires additional support to manage the platform certificate and key
53// stores.
54#if defined(USE_NSS_CERTS)
[email protected]20305ec2011-01-21 04:55:5255#include "base/synchronization/lock.h"
[email protected]99e5e9522013-12-16 13:05:2756#include "crypto/nss_crypto_module_delegate.h"
davidben71f35ff2015-04-17 20:54:4857#endif // defined(USE_NSS_CERTS)
[email protected]abd4aba82010-01-27 19:36:2258
[email protected]4b559b4d2011-04-14 17:37:1459namespace crypto {
[email protected]f1633932010-08-17 23:05:2860
[email protected]bc1e07c72008-09-16 14:32:4461namespace {
62
[email protected]6a89ef22011-04-07 17:34:2163#if defined(OS_CHROMEOS)
[email protected]83e1ae32014-07-18 10:57:0764const char kUserNSSDatabaseName[] = "UserNSSDB";
[email protected]6a89ef22011-04-07 17:34:2165
[email protected]84e47722011-11-17 05:12:0266// Constants for loading the Chrome OS TPM-backed PKCS #11 library.
67const char kChapsModuleName[] = "Chaps";
68const char kChapsPath[] = "libchaps.so";
[email protected]6a89ef22011-04-07 17:34:2169
[email protected]6a89ef22011-04-07 17:34:2170// Fake certificate authority database used for testing.
[email protected]9e275712013-02-10 19:20:1471static const base::FilePath::CharType kReadOnlyCertDB[] =
[email protected]6a89ef22011-04-07 17:34:2172 FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb");
73#endif // defined(OS_CHROMEOS)
74
75std::string GetNSSErrorMessage() {
76 std::string result;
77 if (PR_GetErrorTextLength()) {
[email protected]e8328952013-04-09 17:35:4278 scoped_ptr<char[]> error_text(new char[PR_GetErrorTextLength() + 1]);
[email protected]6a89ef22011-04-07 17:34:2179 PRInt32 copied = PR_GetErrorText(error_text.get());
80 result = std::string(error_text.get(), copied);
81 } else {
[email protected]7d3cbc92013-03-18 22:33:0482 result = base::StringPrintf("NSS error code: %d", PR_GetError());
[email protected]6a89ef22011-04-07 17:34:2183 }
84 return result;
85}
86
davidben71f35ff2015-04-17 20:54:4887#if defined(USE_NSS_CERTS)
[email protected]4071e6ac2014-07-12 12:46:1788#if !defined(OS_CHROMEOS)
[email protected]9e275712013-02-10 19:20:1489base::FilePath GetDefaultConfigDirectory() {
[email protected]6bdc52272014-05-27 00:12:3390 base::FilePath dir;
91 PathService::Get(base::DIR_HOME, &dir);
[email protected]a8b58f42010-07-14 20:21:3592 if (dir.empty()) {
93 LOG(ERROR) << "Failed to get home directory.";
94 return dir;
[email protected]86913342009-05-25 02:14:3495 }
[email protected]86913342009-05-25 02:14:3496 dir = dir.AppendASCII(".pki").AppendASCII("nssdb");
[email protected]426d1c92013-12-03 20:08:5497 if (!base::CreateDirectory(dir)) {
[email protected]948a707b2011-06-07 22:51:4498 LOG(ERROR) << "Failed to create " << dir.value() << " directory.";
[email protected]a8b58f42010-07-14 20:21:3599 dir.clear();
[email protected]86913342009-05-25 02:14:34100 }
[email protected]557737f72013-12-06 22:24:07101 DVLOG(2) << "DefaultConfigDirectory: " << dir.value();
[email protected]a8b58f42010-07-14 20:21:35102 return dir;
[email protected]86913342009-05-25 02:14:34103}
[email protected]4071e6ac2014-07-12 12:46:17104#endif // !defined(IS_CHROMEOS)
[email protected]86913342009-05-25 02:14:34105
[email protected]259c42f2013-09-12 20:32:22106// On non-Chrome OS platforms, return the default config directory. On Chrome OS
107// test images, return a read-only directory with fake root CA certs (which are
108// used by the local Google Accounts server mock we use when testing our login
109// code). On Chrome OS non-test images (where the read-only directory doesn't
110// exist), return an empty path.
[email protected]9e275712013-02-10 19:20:14111base::FilePath GetInitialConfigDirectory() {
[email protected]dcce6cf2010-04-29 17:50:06112#if defined(OS_CHROMEOS)
[email protected]259c42f2013-09-12 20:32:22113 base::FilePath database_dir = base::FilePath(kReadOnlyCertDB);
114 if (!base::PathExists(database_dir))
115 database_dir.clear();
116 return database_dir;
[email protected]dcce6cf2010-04-29 17:50:06117#else
118 return GetDefaultConfigDirectory();
119#endif // defined(OS_CHROMEOS)
120}
121
[email protected]88b9db72011-01-13 01:48:43122// This callback for NSS forwards all requests to a caller-specified
[email protected]3f1f8412011-01-19 03:01:23123// CryptoModuleBlockingPasswordDelegate object.
124char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) {
[email protected]4b559b4d2011-04-14 17:37:14125 crypto::CryptoModuleBlockingPasswordDelegate* delegate =
126 reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg);
[email protected]88b9db72011-01-13 01:48:43127 if (delegate) {
128 bool cancelled = false;
129 std::string password = delegate->RequestPassword(PK11_GetTokenName(slot),
130 retry != PR_FALSE,
131 &cancelled);
132 if (cancelled)
133 return NULL;
134 char* result = PORT_Strdup(password.c_str());
135 password.replace(0, password.size(), password.size(), 0);
136 return result;
137 }
138 DLOG(ERROR) << "PK11 password requested with NULL arg";
139 return NULL;
140}
141
[email protected]a8b58f42010-07-14 20:21:35142// NSS creates a local cache of the sqlite database if it detects that the
143// filesystem the database is on is much slower than the local disk. The
144// detection doesn't work with the latest versions of sqlite, such as 3.6.22
145// (NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=578561). So we set
146// the NSS environment variable NSS_SDB_USE_CACHE to "yes" to override NSS's
147// detection when database_dir is on NFS. See http://crbug.com/48585.
148//
davidben71f35ff2015-04-17 20:54:48149// TODO(wtc): port this function to other USE_NSS_CERTS platforms. It is
150// defined only for OS_LINUX and OS_OPENBSD simply because the statfs structure
[email protected]d816516f2011-10-25 19:11:59151// is OS-specific.
[email protected]ac3d5972011-01-13 20:33:45152//
153// Because this function sets an environment variable it must be run before we
154// go multi-threaded.
[email protected]9e275712013-02-10 19:20:14155void UseLocalCacheOfNSSDatabaseIfNFS(const base::FilePath& database_dir) {
[email protected]5a77df52014-02-05 08:37:48156 bool db_on_nfs = false;
[email protected]d816516f2011-10-25 19:11:59157#if defined(OS_LINUX)
[email protected]a26f4ae2014-03-13 17:26:21158 base::FileSystemType fs_type = base::FILE_SYSTEM_UNKNOWN;
159 if (base::GetFileSystemType(database_dir, &fs_type))
160 db_on_nfs = (fs_type == base::FILE_SYSTEM_NFS);
[email protected]d816516f2011-10-25 19:11:59161#elif defined(OS_OPENBSD)
[email protected]5a77df52014-02-05 08:37:48162 struct statfs buf;
163 if (statfs(database_dir.value().c_str(), &buf) == 0)
164 db_on_nfs = (strcmp(buf.f_fstypename, MOUNT_NFS) == 0);
165#else
166 NOTIMPLEMENTED();
[email protected]d816516f2011-10-25 19:11:59167#endif
[email protected]5a77df52014-02-05 08:37:48168
169 if (db_on_nfs) {
170 scoped_ptr<base::Environment> env(base::Environment::Create());
171 static const char kUseCacheEnvVar[] = "NSS_SDB_USE_CACHE";
172 if (!env->HasVar(kUseCacheEnvVar))
173 env->SetVar(kUseCacheEnvVar, "yes");
[email protected]a8b58f42010-07-14 20:21:35174 }
[email protected]a8b58f42010-07-14 20:21:35175}
176
davidben71f35ff2015-04-17 20:54:48177#endif // defined(USE_NSS_CERTS)
[email protected]ea224582008-12-07 20:25:46178
[email protected]730fb132009-09-02 22:50:25179// A singleton to initialize/deinitialize NSPR.
180// Separate from the NSS singleton because we initialize NSPR on the UI thread.
[email protected]f615bda32010-11-21 01:04:56181// Now that we're leaking the singleton, we could merge back with the NSS
182// singleton.
[email protected]730fb132009-09-02 22:50:25183class NSPRInitSingleton {
[email protected]f615bda32010-11-21 01:04:56184 private:
[email protected]4b559b4d2011-04-14 17:37:14185 friend struct base::DefaultLazyInstanceTraits<NSPRInitSingleton>;
[email protected]f615bda32010-11-21 01:04:56186
[email protected]730fb132009-09-02 22:50:25187 NSPRInitSingleton() {
188 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
189 }
190
[email protected]f615bda32010-11-21 01:04:56191 // NOTE(willchan): We don't actually execute this code since we leak NSS to
192 // prevent non-joinable threads from using NSS after it's already been shut
193 // down.
[email protected]730fb132009-09-02 22:50:25194 ~NSPRInitSingleton() {
[email protected]829296f2010-01-27 02:58:03195 PL_ArenaFinish();
[email protected]730fb132009-09-02 22:50:25196 PRStatus prstatus = PR_Cleanup();
[email protected]450b4ad72012-05-17 10:04:17197 if (prstatus != PR_SUCCESS)
[email protected]730fb132009-09-02 22:50:25198 LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?";
[email protected]730fb132009-09-02 22:50:25199 }
200};
201
[email protected]9fc44162012-01-23 22:56:41202base::LazyInstance<NSPRInitSingleton>::Leaky
[email protected]6de0fd1d2011-11-15 13:31:49203 g_nspr_singleton = LAZY_INSTANCE_INITIALIZER;
[email protected]f615bda32010-11-21 01:04:56204
[email protected]007f5122012-11-21 16:00:21205// Force a crash with error info on NSS_NoDB_Init failure.
206void CrashOnNSSInitFailure() {
207 int nss_error = PR_GetError();
208 int os_error = PR_GetOSError();
[email protected]716fb112012-11-15 05:41:25209 base::debug::Alias(&nss_error);
210 base::debug::Alias(&os_error);
[email protected]007f5122012-11-21 16:00:21211 LOG(ERROR) << "Error initializing NSS without a persistent database: "
212 << GetNSSErrorMessage();
[email protected]2b12459a2012-11-16 03:45:32213 LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error;
[email protected]716fb112012-11-15 05:41:25214}
215
[email protected]557737f72013-12-06 22:24:07216#if defined(OS_CHROMEOS)
217class ChromeOSUserData {
218 public:
[email protected]4071e6ac2014-07-12 12:46:17219 explicit ChromeOSUserData(ScopedPK11Slot public_slot)
dchengcf738a92015-12-31 16:11:45220 : public_slot_(std::move(public_slot)),
[email protected]4071e6ac2014-07-12 12:46:17221 private_slot_initialization_started_(false) {}
[email protected]557737f72013-12-06 22:24:07222 ~ChromeOSUserData() {
[email protected]4071e6ac2014-07-12 12:46:17223 if (public_slot_) {
[email protected]557737f72013-12-06 22:24:07224 SECStatus status = SECMOD_CloseUserDB(public_slot_.get());
225 if (status != SECSuccess)
226 PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
227 }
228 }
229
230 ScopedPK11Slot GetPublicSlot() {
231 return ScopedPK11Slot(
232 public_slot_ ? PK11_ReferenceSlot(public_slot_.get()) : NULL);
233 }
234
235 ScopedPK11Slot GetPrivateSlot(
236 const base::Callback<void(ScopedPK11Slot)>& callback) {
237 if (private_slot_)
238 return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()));
239 if (!callback.is_null())
240 tpm_ready_callback_list_.push_back(callback);
241 return ScopedPK11Slot();
242 }
243
244 void SetPrivateSlot(ScopedPK11Slot private_slot) {
245 DCHECK(!private_slot_);
dchengcf738a92015-12-31 16:11:45246 private_slot_ = std::move(private_slot);
[email protected]557737f72013-12-06 22:24:07247
248 SlotReadyCallbackList callback_list;
249 callback_list.swap(tpm_ready_callback_list_);
250 for (SlotReadyCallbackList::iterator i = callback_list.begin();
251 i != callback_list.end();
252 ++i) {
253 (*i).Run(ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())));
254 }
255 }
256
[email protected]4071e6ac2014-07-12 12:46:17257 bool private_slot_initialization_started() const {
258 return private_slot_initialization_started_;
259 }
260
261 void set_private_slot_initialization_started() {
262 private_slot_initialization_started_ = true;
263 }
264
[email protected]557737f72013-12-06 22:24:07265 private:
266 ScopedPK11Slot public_slot_;
267 ScopedPK11Slot private_slot_;
[email protected]4071e6ac2014-07-12 12:46:17268
269 bool private_slot_initialization_started_;
[email protected]557737f72013-12-06 22:24:07270
271 typedef std::vector<base::Callback<void(ScopedPK11Slot)> >
272 SlotReadyCallbackList;
273 SlotReadyCallbackList tpm_ready_callback_list_;
274};
spangba254c42015-05-14 00:00:23275
276class ScopedChapsLoadFixup {
277 public:
278 ScopedChapsLoadFixup();
279 ~ScopedChapsLoadFixup();
280
281 private:
282#if defined(COMPONENT_BUILD)
283 void *chaps_handle_;
284#endif
285};
286
287#if defined(COMPONENT_BUILD)
288
289ScopedChapsLoadFixup::ScopedChapsLoadFixup() {
290 // HACK: libchaps links the system protobuf and there are symbol conflicts
291 // with the bundled copy. Load chaps with RTLD_DEEPBIND to workaround.
292 chaps_handle_ = dlopen(kChapsPath, RTLD_LOCAL | RTLD_NOW | RTLD_DEEPBIND);
293}
294
295ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {
296 // LoadModule() will have taken a 2nd reference.
297 if (chaps_handle_)
298 dlclose(chaps_handle_);
299}
300
301#else
302
303ScopedChapsLoadFixup::ScopedChapsLoadFixup() {}
304ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {}
305
306#endif // defined(COMPONENT_BUILD)
[email protected]557737f72013-12-06 22:24:07307#endif // defined(OS_CHROMEOS)
308
[email protected]bc1e07c72008-09-16 14:32:44309class NSSInitSingleton {
310 public:
[email protected]f615bda32010-11-21 01:04:56311#if defined(OS_CHROMEOS)
[email protected]e2ea5ca2014-02-27 22:27:21312 // Used with PostTaskAndReply to pass handles to worker thread and back.
313 struct TPMModuleAndSlot {
314 explicit TPMModuleAndSlot(SECMODModule* init_chaps_module)
[email protected]966669ae2014-07-30 21:03:45315 : chaps_module(init_chaps_module) {}
[email protected]e2ea5ca2014-02-27 22:27:21316 SECMODModule* chaps_module;
[email protected]966669ae2014-07-30 21:03:45317 crypto::ScopedPK11Slot tpm_slot;
[email protected]e2ea5ca2014-02-27 22:27:21318 };
319
[email protected]190933f2014-07-28 09:56:51320 ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name,
321 const base::FilePath& path) {
[email protected]557737f72013-12-06 22:24:07322 DCHECK(thread_checker_.CalledOnValidThread());
323 // NSS is allowed to do IO on the current thread since dispatching
324 // to a dedicated thread would still have the affect of blocking
325 // the current thread, due to NSS's internal locking requirements
326 base::ThreadRestrictions::ScopedAllowIO allow_io;
327
328 base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb");
329 if (!base::CreateDirectory(nssdb_path)) {
330 LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory.";
[email protected]190933f2014-07-28 09:56:51331 return ScopedPK11Slot();
[email protected]557737f72013-12-06 22:24:07332 }
[email protected]190933f2014-07-28 09:56:51333 return OpenSoftwareNSSDB(nssdb_path, db_name);
[email protected]557737f72013-12-06 22:24:07334 }
335
[email protected]450b4ad72012-05-17 10:04:17336 void EnableTPMTokenForNSS() {
[email protected]0f8f69c2013-11-12 02:56:31337 DCHECK(thread_checker_.CalledOnValidThread());
338
[email protected]3f3b9b12013-10-25 22:03:26339 // If this gets set, then we'll use the TPM for certs with
340 // private keys, otherwise we'll fall back to the software
341 // implementation.
[email protected]450b4ad72012-05-17 10:04:17342 tpm_token_enabled_for_nss_ = true;
[email protected]6a89ef22011-04-07 17:34:21343 }
344
[email protected]557737f72013-12-06 22:24:07345 bool IsTPMTokenEnabledForNSS() {
346 DCHECK(thread_checker_.CalledOnValidThread());
347 return tpm_token_enabled_for_nss_;
348 }
349
[email protected]496318862014-07-13 07:19:00350 void InitializeTPMTokenAndSystemSlot(
351 int system_slot_id,
352 const base::Callback<void(bool)>& callback) {
[email protected]0f8f69c2013-11-12 02:56:31353 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]e2ea5ca2014-02-27 22:27:21354 // Should not be called while there is already an initialization in
355 // progress.
356 DCHECK(!initializing_tpm_token_);
[email protected]450b4ad72012-05-17 10:04:17357 // If EnableTPMTokenForNSS hasn't been called, return false.
[email protected]e2ea5ca2014-02-27 22:27:21358 if (!tpm_token_enabled_for_nss_) {
359 base::MessageLoop::current()->PostTask(FROM_HERE,
360 base::Bind(callback, false));
361 return;
362 }
[email protected]14172c82012-02-28 10:34:21363
[email protected]450b4ad72012-05-17 10:04:17364 // If everything is already initialized, then return true.
[email protected]e2ea5ca2014-02-27 22:27:21365 // Note that only |tpm_slot_| is checked, since |chaps_module_| could be
366 // NULL in tests while |tpm_slot_| has been set to the test DB.
367 if (tpm_slot_) {
368 base::MessageLoop::current()->PostTask(FROM_HERE,
369 base::Bind(callback, true));
370 return;
371 }
[email protected]450b4ad72012-05-17 10:04:17372
[email protected]e2ea5ca2014-02-27 22:27:21373 // Note that a reference is not taken to chaps_module_. This is safe since
374 // NSSInitSingleton is Leaky, so the reference it holds is never released.
375 scoped_ptr<TPMModuleAndSlot> tpm_args(new TPMModuleAndSlot(chaps_module_));
376 TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
377 if (base::WorkerPool::PostTaskAndReply(
378 FROM_HERE,
379 base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread,
[email protected]496318862014-07-13 07:19:00380 system_slot_id,
[email protected]e2ea5ca2014-02-27 22:27:21381 tpm_args_ptr),
[email protected]496318862014-07-13 07:19:00382 base::Bind(&NSSInitSingleton::OnInitializedTPMTokenAndSystemSlot,
[email protected]e2ea5ca2014-02-27 22:27:21383 base::Unretained(this), // NSSInitSingleton is leaky
384 callback,
385 base::Passed(&tpm_args)),
386 true /* task_is_slow */
387 )) {
388 initializing_tpm_token_ = true;
389 } else {
390 base::MessageLoop::current()->PostTask(FROM_HERE,
391 base::Bind(callback, false));
392 }
393 }
394
395 static void InitializeTPMTokenOnWorkerThread(CK_SLOT_ID token_slot_id,
396 TPMModuleAndSlot* tpm_args) {
[email protected]450b4ad72012-05-17 10:04:17397 // This tries to load the Chaps module so NSS can talk to the hardware
398 // TPM.
[email protected]e2ea5ca2014-02-27 22:27:21399 if (!tpm_args->chaps_module) {
spangba254c42015-05-14 00:00:23400 ScopedChapsLoadFixup chaps_loader;
401
[email protected]e2ea5ca2014-02-27 22:27:21402 DVLOG(3) << "Loading chaps...";
403 tpm_args->chaps_module = LoadModule(
[email protected]450b4ad72012-05-17 10:04:17404 kChapsModuleName,
405 kChapsPath,
406 // For more details on these parameters, see:
407 // https://developer.mozilla.org/en/PKCS11_Module_Specs
408 // slotFlags=[PublicCerts] -- Certificates and public keys can be
409 // read from this slot without requiring a call to C_Login.
410 // askpw=only -- Only authenticate to the token when necessary.
411 "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\"");
[email protected]14172c82012-02-28 10:34:21412 }
[email protected]e2ea5ca2014-02-27 22:27:21413 if (tpm_args->chaps_module) {
414 tpm_args->tpm_slot =
415 GetTPMSlotForIdOnWorkerThread(tpm_args->chaps_module, token_slot_id);
416 }
417 }
[email protected]450b4ad72012-05-17 10:04:17418
[email protected]496318862014-07-13 07:19:00419 void OnInitializedTPMTokenAndSystemSlot(
420 const base::Callback<void(bool)>& callback,
421 scoped_ptr<TPMModuleAndSlot> tpm_args) {
[email protected]e2ea5ca2014-02-27 22:27:21422 DCHECK(thread_checker_.CalledOnValidThread());
423 DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module
424 << ", got tpm slot: " << !!tpm_args->tpm_slot;
[email protected]557737f72013-12-06 22:24:07425
[email protected]e2ea5ca2014-02-27 22:27:21426 chaps_module_ = tpm_args->chaps_module;
dchengcf738a92015-12-31 16:11:45427 tpm_slot_ = std::move(tpm_args->tpm_slot);
[email protected]190933f2014-07-28 09:56:51428 if (!chaps_module_ && test_system_slot_) {
[email protected]e2ea5ca2014-02-27 22:27:21429 // chromeos_unittests try to test the TPM initialization process. If we
430 // have a test DB open, pretend that it is the TPM slot.
[email protected]966669ae2014-07-30 21:03:45431 tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
[email protected]e2ea5ca2014-02-27 22:27:21432 }
433 initializing_tpm_token_ = false;
434
[email protected]442233d42014-08-02 07:37:24435 if (tpm_slot_)
436 RunAndClearTPMReadyCallbackList();
[email protected]e2ea5ca2014-02-27 22:27:21437
438 callback.Run(!!tpm_slot_);
[email protected]c175cdb2011-06-28 20:41:55439 }
440
[email protected]442233d42014-08-02 07:37:24441 void RunAndClearTPMReadyCallbackList() {
442 TPMReadyCallbackList callback_list;
443 callback_list.swap(tpm_ready_callback_list_);
444 for (TPMReadyCallbackList::iterator i = callback_list.begin();
445 i != callback_list.end();
446 ++i) {
447 i->Run();
448 }
449 }
450
[email protected]557737f72013-12-06 22:24:07451 bool IsTPMTokenReady(const base::Closure& callback) {
452 if (!callback.is_null()) {
453 // Cannot DCHECK in the general case yet, but since the callback is
454 // a new addition to the API, DCHECK to make sure at least the new uses
455 // don't regress.
456 DCHECK(thread_checker_.CalledOnValidThread());
457 } else if (!thread_checker_.CalledOnValidThread()) {
458 // TODO(mattm): Change to DCHECK when callers have been fixed.
[email protected]0f8f69c2013-11-12 02:56:31459 DVLOG(1) << "Called on wrong thread.\n"
460 << base::debug::StackTrace().ToString();
461 }
462
[email protected]966669ae2014-07-30 21:03:45463 if (tpm_slot_)
[email protected]557737f72013-12-06 22:24:07464 return true;
465
466 if (!callback.is_null())
467 tpm_ready_callback_list_.push_back(callback);
468
469 return false;
[email protected]74beead2011-04-12 20:40:12470 }
471
[email protected]3f3b9b12013-10-25 22:03:26472 // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot
473 // id as an int. This should be safe since this is only used with chaps, which
474 // we also control.
[email protected]966669ae2014-07-30 21:03:45475 static crypto::ScopedPK11Slot GetTPMSlotForIdOnWorkerThread(
476 SECMODModule* chaps_module,
477 CK_SLOT_ID slot_id) {
[email protected]e2ea5ca2014-02-27 22:27:21478 DCHECK(chaps_module);
[email protected]3f3b9b12013-10-25 22:03:26479
[email protected]557737f72013-12-06 22:24:07480 DVLOG(3) << "Poking chaps module.";
[email protected]e2ea5ca2014-02-27 22:27:21481 SECStatus rv = SECMOD_UpdateSlotList(chaps_module);
[email protected]3f3b9b12013-10-25 22:03:26482 if (rv != SECSuccess)
483 PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError();
484
[email protected]e2ea5ca2014-02-27 22:27:21485 PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module->moduleID, slot_id);
[email protected]3f3b9b12013-10-25 22:03:26486 if (!slot)
487 LOG(ERROR) << "TPM slot " << slot_id << " not found.";
[email protected]966669ae2014-07-30 21:03:45488 return crypto::ScopedPK11Slot(slot);
[email protected]6a89ef22011-04-07 17:34:21489 }
[email protected]557737f72013-12-06 22:24:07490
pneubeckfa32f2e2014-09-12 09:59:00491 bool InitializeNSSForChromeOSUser(const std::string& username_hash,
492 const base::FilePath& path) {
[email protected]557737f72013-12-06 22:24:07493 DCHECK(thread_checker_.CalledOnValidThread());
494 if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) {
495 // This user already exists in our mapping.
496 DVLOG(2) << username_hash << " already initialized.";
497 return false;
498 }
[email protected]4071e6ac2014-07-12 12:46:17499
[email protected]4071e6ac2014-07-12 12:46:17500 DVLOG(2) << "Opening NSS DB " << path.value();
[email protected]83e1ae32014-07-18 10:57:07501 std::string db_name = base::StringPrintf(
502 "%s %s", kUserNSSDatabaseName, username_hash.c_str());
503 ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path));
[email protected]557737f72013-12-06 22:24:07504 chromeos_user_map_[username_hash] =
dchengcf738a92015-12-31 16:11:45505 new ChromeOSUserData(std::move(public_slot));
[email protected]557737f72013-12-06 22:24:07506 return true;
507 }
508
[email protected]4071e6ac2014-07-12 12:46:17509 bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
510 DCHECK(thread_checker_.CalledOnValidThread());
511 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
512
513 return !chromeos_user_map_[username_hash]
514 ->private_slot_initialization_started();
515 }
516
517 void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
518 DCHECK(thread_checker_.CalledOnValidThread());
519 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
520
521 chromeos_user_map_[username_hash]
522 ->set_private_slot_initialization_started();
523 }
524
[email protected]557737f72013-12-06 22:24:07525 void InitializeTPMForChromeOSUser(const std::string& username_hash,
526 CK_SLOT_ID slot_id) {
527 DCHECK(thread_checker_.CalledOnValidThread());
528 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
[email protected]4071e6ac2014-07-12 12:46:17529 DCHECK(chromeos_user_map_[username_hash]->
530 private_slot_initialization_started());
[email protected]e2ea5ca2014-02-27 22:27:21531
532 if (!chaps_module_)
533 return;
534
535 // Note that a reference is not taken to chaps_module_. This is safe since
536 // NSSInitSingleton is Leaky, so the reference it holds is never released.
537 scoped_ptr<TPMModuleAndSlot> tpm_args(new TPMModuleAndSlot(chaps_module_));
538 TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
539 base::WorkerPool::PostTaskAndReply(
540 FROM_HERE,
541 base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread,
542 slot_id,
543 tpm_args_ptr),
544 base::Bind(&NSSInitSingleton::OnInitializedTPMForChromeOSUser,
545 base::Unretained(this), // NSSInitSingleton is leaky
546 username_hash,
547 base::Passed(&tpm_args)),
548 true /* task_is_slow */
549 );
550 }
551
552 void OnInitializedTPMForChromeOSUser(const std::string& username_hash,
553 scoped_ptr<TPMModuleAndSlot> tpm_args) {
554 DCHECK(thread_checker_.CalledOnValidThread());
555 DVLOG(2) << "Got tpm slot for " << username_hash << " "
556 << !!tpm_args->tpm_slot;
557 chromeos_user_map_[username_hash]->SetPrivateSlot(
dchengcf738a92015-12-31 16:11:45558 std::move(tpm_args->tpm_slot));
[email protected]557737f72013-12-06 22:24:07559 }
560
561 void InitializePrivateSoftwareSlotForChromeOSUser(
562 const std::string& username_hash) {
563 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]31946992014-01-31 22:29:02564 VLOG(1) << "using software private slot for " << username_hash;
[email protected]557737f72013-12-06 22:24:07565 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
[email protected]4071e6ac2014-07-12 12:46:17566 DCHECK(chromeos_user_map_[username_hash]->
567 private_slot_initialization_started());
568
[email protected]557737f72013-12-06 22:24:07569 chromeos_user_map_[username_hash]->SetPrivateSlot(
570 chromeos_user_map_[username_hash]->GetPublicSlot());
571 }
572
573 ScopedPK11Slot GetPublicSlotForChromeOSUser(
574 const std::string& username_hash) {
575 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]7037a43c2014-01-14 14:00:46576
577 if (username_hash.empty()) {
578 DVLOG(2) << "empty username_hash";
579 return ScopedPK11Slot();
580 }
581
[email protected]557737f72013-12-06 22:24:07582 if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) {
583 LOG(ERROR) << username_hash << " not initialized.";
584 return ScopedPK11Slot();
585 }
586 return chromeos_user_map_[username_hash]->GetPublicSlot();
587 }
588
589 ScopedPK11Slot GetPrivateSlotForChromeOSUser(
590 const std::string& username_hash,
591 const base::Callback<void(ScopedPK11Slot)>& callback) {
592 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]7037a43c2014-01-14 14:00:46593
594 if (username_hash.empty()) {
595 DVLOG(2) << "empty username_hash";
596 if (!callback.is_null()) {
597 base::MessageLoop::current()->PostTask(
598 FROM_HERE, base::Bind(callback, base::Passed(ScopedPK11Slot())));
599 }
600 return ScopedPK11Slot();
601 }
602
[email protected]557737f72013-12-06 22:24:07603 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
604
[email protected]557737f72013-12-06 22:24:07605 return chromeos_user_map_[username_hash]->GetPrivateSlot(callback);
606 }
[email protected]e53c02322013-12-17 00:09:00607
[email protected]190933f2014-07-28 09:56:51608 void CloseChromeOSUserForTesting(const std::string& username_hash) {
[email protected]e53c02322013-12-17 00:09:00609 DCHECK(thread_checker_.CalledOnValidThread());
610 ChromeOSUserMap::iterator i = chromeos_user_map_.find(username_hash);
611 DCHECK(i != chromeos_user_map_.end());
612 delete i->second;
613 chromeos_user_map_.erase(i);
614 }
[email protected]190933f2014-07-28 09:56:51615
616 void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
617 // Ensure that a previous value of test_system_slot_ is not overwritten.
618 // Unsetting, i.e. setting a NULL, however is allowed.
619 DCHECK(!slot || !test_system_slot_);
dchengcf738a92015-12-31 16:11:45620 test_system_slot_ = std::move(slot);
[email protected]442233d42014-08-02 07:37:24621 if (test_system_slot_) {
622 tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
623 RunAndClearTPMReadyCallbackList();
624 } else {
625 tpm_slot_.reset();
626 }
[email protected]190933f2014-07-28 09:56:51627 }
[email protected]f615bda32010-11-21 01:04:56628#endif // defined(OS_CHROMEOS)
629
[email protected]190933f2014-07-28 09:56:51630#if !defined(OS_CHROMEOS)
[email protected]496318862014-07-13 07:19:00631 PK11SlotInfo* GetPersistentNSSKeySlot() {
[email protected]0f8f69c2013-11-12 02:56:31632 // TODO(mattm): Change to DCHECK when callers have been fixed.
633 if (!thread_checker_.CalledOnValidThread()) {
634 DVLOG(1) << "Called on wrong thread.\n"
635 << base::debug::StackTrace().ToString();
636 }
637
[email protected]6a89ef22011-04-07 17:34:21638 return PK11_GetInternalKeySlot();
639 }
[email protected]190933f2014-07-28 09:56:51640#endif
[email protected]6a89ef22011-04-07 17:34:21641
[email protected]c64b9142011-04-19 18:49:54642#if defined(OS_CHROMEOS)
[email protected]8edd7212014-07-30 12:24:29643 void GetSystemNSSKeySlotCallback(
644 const base::Callback<void(ScopedPK11Slot)>& callback) {
[email protected]966669ae2014-07-30 21:03:45645 callback.Run(ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get())));
[email protected]8edd7212014-07-30 12:24:29646 }
[email protected]496318862014-07-13 07:19:00647
[email protected]8edd7212014-07-30 12:24:29648 ScopedPK11Slot GetSystemNSSKeySlot(
649 const base::Callback<void(ScopedPK11Slot)>& callback) {
650 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]496318862014-07-13 07:19:00651 // TODO(mattm): chromeos::TPMTokenloader always calls
652 // InitializeTPMTokenAndSystemSlot with slot 0. If the system slot is
653 // disabled, tpm_slot_ will be the first user's slot instead. Can that be
654 // detected and return NULL instead?
[email protected]8edd7212014-07-30 12:24:29655
656 base::Closure wrapped_callback;
657 if (!callback.is_null()) {
658 wrapped_callback =
659 base::Bind(&NSSInitSingleton::GetSystemNSSKeySlotCallback,
660 base::Unretained(this) /* singleton is leaky */,
661 callback);
662 }
663 if (IsTPMTokenReady(wrapped_callback))
[email protected]966669ae2014-07-30 21:03:45664 return ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get()));
[email protected]8edd7212014-07-30 12:24:29665 return ScopedPK11Slot();
[email protected]f615bda32010-11-21 01:04:56666 }
[email protected]496318862014-07-13 07:19:00667#endif
[email protected]f615bda32010-11-21 01:04:56668
davidben71f35ff2015-04-17 20:54:48669#if defined(USE_NSS_CERTS)
[email protected]4b559b4d2011-04-14 17:37:14670 base::Lock* write_lock() {
[email protected]f615bda32010-11-21 01:04:56671 return &write_lock_;
672 }
davidben71f35ff2015-04-17 20:54:48673#endif // defined(USE_NSS_CERTS)
[email protected]f615bda32010-11-21 01:04:56674
675 private:
[email protected]4b559b4d2011-04-14 17:37:14676 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>;
[email protected]f615bda32010-11-21 01:04:56677
[email protected]dcce6cf2010-04-29 17:50:06678 NSSInitSingleton()
[email protected]450b4ad72012-05-17 10:04:17679 : tpm_token_enabled_for_nss_(false),
[email protected]e2ea5ca2014-02-27 22:27:21680 initializing_tpm_token_(false),
[email protected]450b4ad72012-05-17 10:04:17681 chaps_module_(NULL),
[email protected]4071e6ac2014-07-12 12:46:17682 root_(NULL) {
[email protected]0f8f69c2013-11-12 02:56:31683 // It's safe to construct on any thread, since LazyInstance will prevent any
684 // other threads from accessing until the constructor is done.
685 thread_checker_.DetachFromThread();
686
[email protected]f615bda32010-11-21 01:04:56687 EnsureNSPRInit();
[email protected]730fb132009-09-02 22:50:25688
[email protected]805acdc2013-08-07 22:57:00689 // We *must* have NSS >= 3.14.3.
anujk.sharma3cec2ab2015-01-22 02:35:02690 static_assert(
[email protected]805acdc2013-08-07 22:57:00691 (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) ||
692 (NSS_VMAJOR == 3 && NSS_VMINOR > 14) ||
[email protected]dc36c9c2010-01-20 20:45:00693 (NSS_VMAJOR > 3),
anujk.sharma3cec2ab2015-01-22 02:35:02694 "nss version check failed");
[email protected]dc36c9c2010-01-20 20:45:00695 // Also check the run-time NSS version.
696 // NSS_VersionCheck is a >= check, not strict equality.
[email protected]805acdc2013-08-07 22:57:00697 if (!NSS_VersionCheck("3.14.3")) {
698 LOG(FATAL) << "NSS_VersionCheck(\"3.14.3\") failed. NSS >= 3.14.3 is "
699 "required. Please upgrade to the latest NSS, and if you "
[email protected]1b8082d2010-02-19 12:21:48700 "still get this error, contact your distribution "
701 "maintainer.";
702 }
[email protected]dc36c9c2010-01-20 20:45:00703
[email protected]897f5202009-09-08 17:40:27704 SECStatus status = SECFailure;
davidben2e6b3792015-08-11 18:18:58705 bool nodb_init = false;
706
davidben71f35ff2015-04-17 20:54:48707#if !defined(USE_NSS_CERTS)
[email protected]abd4aba82010-01-27 19:36:22708 // Use the system certificate store, so initialize NSS without database.
[email protected]ed450f32011-03-16 01:26:49709 nodb_init = true;
[email protected]dcce6cf2010-04-29 17:50:06710#endif
[email protected]ed450f32011-03-16 01:26:49711
712 if (nodb_init) {
[email protected]897f5202009-09-08 17:40:27713 status = NSS_NoDB_Init(NULL);
714 if (status != SECSuccess) {
[email protected]007f5122012-11-21 16:00:21715 CrashOnNSSInitFailure();
[email protected]716fb112012-11-15 05:41:25716 return;
[email protected]897f5202009-09-08 17:40:27717 }
[email protected]a88f87e2012-08-14 19:46:28718#if defined(OS_IOS)
719 root_ = InitDefaultRootCerts();
720#endif // defined(OS_IOS)
[email protected]ed450f32011-03-16 01:26:49721 } else {
davidben71f35ff2015-04-17 20:54:48722#if defined(USE_NSS_CERTS)
[email protected]9e275712013-02-10 19:20:14723 base::FilePath database_dir = GetInitialConfigDirectory();
[email protected]ed450f32011-03-16 01:26:49724 if (!database_dir.empty()) {
725 // This duplicates the work which should have been done in
726 // EarlySetupForNSSInit. However, this function is idempotent so
727 // there's no harm done.
728 UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
729
730 // Initialize with a persistent database (likely, ~/.pki/nssdb).
731 // Use "sql:" which can be shared by multiple processes safely.
732 std::string nss_config_dir =
[email protected]7d3cbc92013-03-18 22:33:04733 base::StringPrintf("sql:%s", database_dir.value().c_str());
[email protected]ed450f32011-03-16 01:26:49734#if defined(OS_CHROMEOS)
735 status = NSS_Init(nss_config_dir.c_str());
736#else
737 status = NSS_InitReadWrite(nss_config_dir.c_str());
738#endif
739 if (status != SECSuccess) {
740 LOG(ERROR) << "Error initializing NSS with a persistent "
741 "database (" << nss_config_dir
[email protected]6a89ef22011-04-07 17:34:21742 << "): " << GetNSSErrorMessage();
[email protected]ed450f32011-03-16 01:26:49743 }
744 }
745 if (status != SECSuccess) {
[email protected]6a89ef22011-04-07 17:34:21746 VLOG(1) << "Initializing NSS without a persistent database.";
[email protected]ed450f32011-03-16 01:26:49747 status = NSS_NoDB_Init(NULL);
748 if (status != SECSuccess) {
[email protected]007f5122012-11-21 16:00:21749 CrashOnNSSInitFailure();
[email protected]ed450f32011-03-16 01:26:49750 return;
751 }
752 }
753
754 PK11_SetPasswordFunc(PKCS11PasswordFunc);
755
756 // If we haven't initialized the password for the NSS databases,
757 // initialize an empty-string password so that we don't need to
758 // log in.
759 PK11SlotInfo* slot = PK11_GetInternalKeySlot();
760 if (slot) {
761 // PK11_InitPin may write to the keyDB, but no other thread can use NSS
762 // yet, so we don't need to lock.
763 if (PK11_NeedUserInit(slot))
764 PK11_InitPin(slot, NULL, NULL);
765 PK11_FreeSlot(slot);
766 }
767
768 root_ = InitDefaultRootCerts();
davidben71f35ff2015-04-17 20:54:48769#endif // defined(USE_NSS_CERTS)
[email protected]6e7e8062009-04-13 17:35:09770 }
[email protected]fa2d3dc2012-11-20 07:58:44771
[email protected]fa2d3dc2012-11-20 07:58:44772 // Disable MD5 certificate signatures. (They are disabled by default in
773 // NSS 3.14.)
774 NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
775 NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
776 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
[email protected]bc1e07c72008-09-16 14:32:44777 }
778
[email protected]f615bda32010-11-21 01:04:56779 // NOTE(willchan): We don't actually execute this code since we leak NSS to
780 // prevent non-joinable threads from using NSS after it's already been shut
781 // down.
[email protected]bc1e07c72008-09-16 14:32:44782 ~NSSInitSingleton() {
[email protected]557737f72013-12-06 22:24:07783#if defined(OS_CHROMEOS)
784 STLDeleteValues(&chromeos_user_map_);
785#endif
[email protected]966669ae2014-07-30 21:03:45786 tpm_slot_.reset();
[email protected]ea224582008-12-07 20:25:46787 if (root_) {
788 SECMOD_UnloadUserModule(root_);
789 SECMOD_DestroyModule(root_);
790 root_ = NULL;
791 }
[email protected]84e47722011-11-17 05:12:02792 if (chaps_module_) {
793 SECMOD_UnloadUserModule(chaps_module_);
794 SECMOD_DestroyModule(chaps_module_);
795 chaps_module_ = NULL;
[email protected]6a89ef22011-04-07 17:34:21796 }
[email protected]ea224582008-12-07 20:25:46797
[email protected]c1444fe2008-09-17 09:42:51798 SECStatus status = NSS_Shutdown();
[email protected]f8adef52009-08-04 17:52:06799 if (status != SECSuccess) {
[email protected]b026e35d2010-10-19 02:31:03800 // We VLOG(1) because this failure is relatively harmless (leaking, but
801 // we're shutting down anyway).
[email protected]6a89ef22011-04-07 17:34:21802 VLOG(1) << "NSS_Shutdown failed; see http://crbug.com/4609";
[email protected]f8adef52009-08-04 17:52:06803 }
[email protected]bc1e07c72008-09-16 14:32:44804 }
[email protected]c72f16a2009-03-19 16:02:31805
davidben71f35ff2015-04-17 20:54:48806#if defined(USE_NSS_CERTS) || defined(OS_IOS)
[email protected]6a89ef22011-04-07 17:34:21807 // Load nss's built-in root certs.
808 SECMODModule* InitDefaultRootCerts() {
809 SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", NULL);
810 if (root)
811 return root;
812
813 // Aw, snap. Can't find/load root cert shared library.
814 // This will make it hard to talk to anybody via https.
[email protected]3f3b9b12013-10-25 22:03:26815 // TODO(mattm): Re-add the NOTREACHED here when crbug.com/310972 is fixed.
[email protected]6a89ef22011-04-07 17:34:21816 return NULL;
817 }
818
819 // Load the given module for this NSS session.
[email protected]e2ea5ca2014-02-27 22:27:21820 static SECMODModule* LoadModule(const char* name,
821 const char* library_path,
822 const char* params) {
[email protected]7d3cbc92013-03-18 22:33:04823 std::string modparams = base::StringPrintf(
[email protected]6a89ef22011-04-07 17:34:21824 "name=\"%s\" library=\"%s\" %s",
825 name, library_path, params ? params : "");
826
827 // Shouldn't need to const_cast here, but SECMOD doesn't properly
828 // declare input string arguments as const. Bug
829 // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed
830 // on NSS codebase to address this.
831 SECMODModule* module = SECMOD_LoadUserModule(
832 const_cast<char*>(modparams.c_str()), NULL, PR_FALSE);
833 if (!module) {
834 LOG(ERROR) << "Error loading " << name << " module into NSS: "
835 << GetNSSErrorMessage();
836 return NULL;
837 }
[email protected]3f3b9b12013-10-25 22:03:26838 if (!module->loaded) {
839 LOG(ERROR) << "After loading " << name << ", loaded==false: "
840 << GetNSSErrorMessage();
841 SECMOD_DestroyModule(module);
842 return NULL;
843 }
[email protected]6a89ef22011-04-07 17:34:21844 return module;
845 }
846#endif
847
[email protected]450b4ad72012-05-17 10:04:17848 bool tpm_token_enabled_for_nss_;
[email protected]e2ea5ca2014-02-27 22:27:21849 bool initializing_tpm_token_;
[email protected]557737f72013-12-06 22:24:07850 typedef std::vector<base::Closure> TPMReadyCallbackList;
851 TPMReadyCallbackList tpm_ready_callback_list_;
[email protected]84e47722011-11-17 05:12:02852 SECMODModule* chaps_module_;
[email protected]966669ae2014-07-30 21:03:45853 crypto::ScopedPK11Slot tpm_slot_;
[email protected]6a89ef22011-04-07 17:34:21854 SECMODModule* root_;
[email protected]557737f72013-12-06 22:24:07855#if defined(OS_CHROMEOS)
856 typedef std::map<std::string, ChromeOSUserData*> ChromeOSUserMap;
857 ChromeOSUserMap chromeos_user_map_;
[email protected]190933f2014-07-28 09:56:51858 ScopedPK11Slot test_system_slot_;
[email protected]557737f72013-12-06 22:24:07859#endif
davidben71f35ff2015-04-17 20:54:48860#if defined(USE_NSS_CERTS)
[email protected]f615bda32010-11-21 01:04:56861 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011
862 // is fixed, we will no longer need the lock.
[email protected]4b559b4d2011-04-14 17:37:14863 base::Lock write_lock_;
davidben71f35ff2015-04-17 20:54:48864#endif // defined(USE_NSS_CERTS)
[email protected]0f8f69c2013-11-12 02:56:31865
866 base::ThreadChecker thread_checker_;
[email protected]bc1e07c72008-09-16 14:32:44867};
868
[email protected]9fc44162012-01-23 22:56:41869base::LazyInstance<NSSInitSingleton>::Leaky
[email protected]6de0fd1d2011-11-15 13:31:49870 g_nss_singleton = LAZY_INSTANCE_INITIALIZER;
[email protected]bc1e07c72008-09-16 14:32:44871} // namespace
872
davidben71f35ff2015-04-17 20:54:48873#if defined(USE_NSS_CERTS)
[email protected]190933f2014-07-28 09:56:51874ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
875 const std::string& description) {
876 const std::string modspec =
877 base::StringPrintf("configDir='sql:%s' tokenDescription='%s'",
878 path.value().c_str(),
879 description.c_str());
880 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str());
881 if (db_slot) {
882 if (PK11_NeedUserInit(db_slot))
883 PK11_InitPin(db_slot, NULL, NULL);
884 } else {
885 LOG(ERROR) << "Error opening persistent database (" << modspec
886 << "): " << GetNSSErrorMessage();
887 }
888 return ScopedPK11Slot(db_slot);
889}
890
[email protected]ac3d5972011-01-13 20:33:45891void EarlySetupForNSSInit() {
[email protected]9e275712013-02-10 19:20:14892 base::FilePath database_dir = GetInitialConfigDirectory();
[email protected]ac3d5972011-01-13 20:33:45893 if (!database_dir.empty())
894 UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
895}
896#endif
897
[email protected]730fb132009-09-02 22:50:25898void EnsureNSPRInit() {
[email protected]f615bda32010-11-21 01:04:56899 g_nspr_singleton.Get();
[email protected]730fb132009-09-02 22:50:25900}
901
[email protected]bc1e07c72008-09-16 14:32:44902void EnsureNSSInit() {
[email protected]a8e4b5a82010-10-27 00:05:47903 // Initializing SSL causes us to do blocking IO.
904 // Temporarily allow it until we fix
905 // http://code.google.com/p/chromium/issues/detail?id=59847
[email protected]4b559b4d2011-04-14 17:37:14906 base::ThreadRestrictions::ScopedAllowIO allow_io;
[email protected]f615bda32010-11-21 01:04:56907 g_nss_singleton.Get();
[email protected]bc1e07c72008-09-16 14:32:44908}
909
[email protected]f61c3972010-12-23 09:54:15910bool CheckNSSVersion(const char* version) {
911 return !!NSS_VersionCheck(version);
912}
913
davidben71f35ff2015-04-17 20:54:48914#if defined(USE_NSS_CERTS)
[email protected]4b559b4d2011-04-14 17:37:14915base::Lock* GetNSSWriteLock() {
[email protected]f615bda32010-11-21 01:04:56916 return g_nss_singleton.Get().write_lock();
[email protected]69138472010-06-25 22:44:48917}
918
919AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) {
920 // May be NULL if the lock is not needed in our version of NSS.
921 if (lock_)
922 lock_->Acquire();
923}
924
925AutoNSSWriteLock::~AutoNSSWriteLock() {
926 if (lock_) {
927 lock_->AssertAcquired();
928 lock_->Release();
929 }
930}
[email protected]dd24ffc2011-06-08 19:46:42931
932AutoSECMODListReadLock::AutoSECMODListReadLock()
933 : lock_(SECMOD_GetDefaultModuleListLock()) {
934 SECMOD_GetReadLock(lock_);
935 }
936
937AutoSECMODListReadLock::~AutoSECMODListReadLock() {
938 SECMOD_ReleaseReadLock(lock_);
939}
davidben71f35ff2015-04-17 20:54:48940#endif // defined(USE_NSS_CERTS)
[email protected]69138472010-06-25 22:44:48941
[email protected]dcce6cf2010-04-29 17:50:06942#if defined(OS_CHROMEOS)
[email protected]8edd7212014-07-30 12:24:29943ScopedPK11Slot GetSystemNSSKeySlot(
944 const base::Callback<void(ScopedPK11Slot)>& callback) {
945 return g_nss_singleton.Get().GetSystemNSSKeySlot(callback);
[email protected]496318862014-07-13 07:19:00946}
947
[email protected]190933f2014-07-28 09:56:51948void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
dchengcf738a92015-12-31 16:11:45949 g_nss_singleton.Get().SetSystemKeySlotForTesting(std::move(slot));
[email protected]190933f2014-07-28 09:56:51950}
951
[email protected]450b4ad72012-05-17 10:04:17952void EnableTPMTokenForNSS() {
953 g_nss_singleton.Get().EnableTPMTokenForNSS();
[email protected]6a89ef22011-04-07 17:34:21954}
955
[email protected]557737f72013-12-06 22:24:07956bool IsTPMTokenEnabledForNSS() {
957 return g_nss_singleton.Get().IsTPMTokenEnabledForNSS();
958}
959
960bool IsTPMTokenReady(const base::Closure& callback) {
961 return g_nss_singleton.Get().IsTPMTokenReady(callback);
[email protected]74beead2011-04-12 20:40:12962}
[email protected]c64b9142011-04-19 18:49:54963
[email protected]496318862014-07-13 07:19:00964void InitializeTPMTokenAndSystemSlot(
965 int token_slot_id,
966 const base::Callback<void(bool)>& callback) {
967 g_nss_singleton.Get().InitializeTPMTokenAndSystemSlot(token_slot_id,
968 callback);
[email protected]c175cdb2011-06-28 20:41:55969}
[email protected]557737f72013-12-06 22:24:07970
pneubeckfa32f2e2014-09-12 09:59:00971bool InitializeNSSForChromeOSUser(const std::string& username_hash,
972 const base::FilePath& path) {
973 return g_nss_singleton.Get().InitializeNSSForChromeOSUser(username_hash,
974 path);
[email protected]557737f72013-12-06 22:24:07975}
[email protected]4071e6ac2014-07-12 12:46:17976
977bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
978 return g_nss_singleton.Get().ShouldInitializeTPMForChromeOSUser(
979 username_hash);
980}
981
982void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
983 g_nss_singleton.Get().WillInitializeTPMForChromeOSUser(username_hash);
984}
985
[email protected]557737f72013-12-06 22:24:07986void InitializeTPMForChromeOSUser(
987 const std::string& username_hash,
988 CK_SLOT_ID slot_id) {
989 g_nss_singleton.Get().InitializeTPMForChromeOSUser(username_hash, slot_id);
990}
[email protected]190933f2014-07-28 09:56:51991
[email protected]557737f72013-12-06 22:24:07992void InitializePrivateSoftwareSlotForChromeOSUser(
993 const std::string& username_hash) {
994 g_nss_singleton.Get().InitializePrivateSoftwareSlotForChromeOSUser(
995 username_hash);
996}
[email protected]190933f2014-07-28 09:56:51997
[email protected]557737f72013-12-06 22:24:07998ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) {
999 return g_nss_singleton.Get().GetPublicSlotForChromeOSUser(username_hash);
1000}
[email protected]190933f2014-07-28 09:56:511001
[email protected]557737f72013-12-06 22:24:071002ScopedPK11Slot GetPrivateSlotForChromeOSUser(
1003 const std::string& username_hash,
1004 const base::Callback<void(ScopedPK11Slot)>& callback) {
1005 return g_nss_singleton.Get().GetPrivateSlotForChromeOSUser(username_hash,
1006 callback);
1007}
[email protected]190933f2014-07-28 09:56:511008
1009void CloseChromeOSUserForTesting(const std::string& username_hash) {
1010 g_nss_singleton.Get().CloseChromeOSUserForTesting(username_hash);
1011}
[email protected]6a89ef22011-04-07 17:34:211012#endif // defined(OS_CHROMEOS)
[email protected]dcce6cf2010-04-29 17:50:061013
[email protected]4b559b4d2011-04-14 17:37:141014base::Time PRTimeToBaseTime(PRTime prtime) {
[email protected]ca929ed32011-12-15 20:37:281015 return base::Time::FromInternalValue(
1016 prtime + base::Time::UnixEpoch().ToInternalValue());
1017}
[email protected]1b1a264a2010-01-14 22:36:351018
[email protected]ca929ed32011-12-15 20:37:281019PRTime BaseTimeToPRTime(base::Time time) {
1020 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue();
[email protected]1b1a264a2010-01-14 22:36:351021}
1022
[email protected]190933f2014-07-28 09:56:511023#if !defined(OS_CHROMEOS)
[email protected]496318862014-07-13 07:19:001024PK11SlotInfo* GetPersistentNSSKeySlot() {
1025 return g_nss_singleton.Get().GetPersistentNSSKeySlot();
[email protected]dcce6cf2010-04-29 17:50:061026}
[email protected]190933f2014-07-28 09:56:511027#endif
[email protected]dcce6cf2010-04-29 17:50:061028
[email protected]4b559b4d2011-04-14 17:37:141029} // namespace crypto