blob: ad5fb8a87ae4e7d5b3b293492b101452d0a5e404 [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>
[email protected]f6a67b42011-03-17 23:49:2117
[email protected]6bdc52272014-05-27 00:12:3318#include "base/base_paths.h"
[email protected]716fb112012-11-15 05:41:2519#include "base/debug/alias.h"
[email protected]57999812013-02-24 05:40:5220#include "base/files/file_path.h"
thestigc9e38a22014-09-13 01:02:1121#include "base/files/file_util.h"
[email protected]f615bda32010-11-21 01:04:5622#include "base/lazy_instance.h"
[email protected]c1444fe2008-09-17 09:42:5123#include "base/logging.h"
[email protected]6bdc52272014-05-27 00:12:3324#include "base/path_service.h"
[email protected]0d8db082013-06-11 07:27:0125#include "base/strings/stringprintf.h"
Gabriel Charette44db1422018-08-06 11:19:3326#include "base/task/post_task.h"
Francois Doraya4d445c2017-08-28 16:36:2827#include "base/threading/scoped_blocking_call.h"
[email protected]34b99632011-01-01 01:01:0628#include "base/threading/thread_restrictions.h"
[email protected]26661c22011-10-07 01:33:5829#include "build/build_config.h"
Yuta Hijikatabf953202020-11-12 08:43:5530#include "build/chromeos_buildflags.h"
[email protected]99e5e9522013-12-16 13:05:2731#include "crypto/nss_crypto_module_delegate.h"
David Benjamin839b74b2017-06-26 21:45:2232#include "crypto/nss_util_internal.h"
33
[email protected]4b559b4d2011-04-14 17:37:1434namespace crypto {
[email protected]f1633932010-08-17 23:05:2835
[email protected]bc1e07c72008-09-16 14:32:4436namespace {
37
Yuta Hijikata2eecbe22021-01-13 05:39:2238#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
Michael Ershov1c50ac952020-12-02 21:01:1739
[email protected]6a89ef22011-04-07 17:34:2140// Fake certificate authority database used for testing.
[email protected]9e275712013-02-10 19:20:1441static const base::FilePath::CharType kReadOnlyCertDB[] =
[email protected]6a89ef22011-04-07 17:34:2142 FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb");
[email protected]6a89ef22011-04-07 17:34:2143
Michael Ershov1c50ac952020-12-02 21:01:1744#else
45
[email protected]9e275712013-02-10 19:20:1446base::FilePath GetDefaultConfigDirectory() {
[email protected]6bdc52272014-05-27 00:12:3347 base::FilePath dir;
Avi Drissmanea15ea02018-05-07 18:55:1248 base::PathService::Get(base::DIR_HOME, &dir);
[email protected]a8b58f42010-07-14 20:21:3549 if (dir.empty()) {
50 LOG(ERROR) << "Failed to get home directory.";
51 return dir;
[email protected]86913342009-05-25 02:14:3452 }
[email protected]86913342009-05-25 02:14:3453 dir = dir.AppendASCII(".pki").AppendASCII("nssdb");
[email protected]426d1c92013-12-03 20:08:5454 if (!base::CreateDirectory(dir)) {
[email protected]948a707b2011-06-07 22:51:4455 LOG(ERROR) << "Failed to create " << dir.value() << " directory.";
[email protected]a8b58f42010-07-14 20:21:3556 dir.clear();
[email protected]86913342009-05-25 02:14:3457 }
[email protected]557737f72013-12-06 22:24:0758 DVLOG(2) << "DefaultConfigDirectory: " << dir.value();
[email protected]a8b58f42010-07-14 20:21:3559 return dir;
[email protected]86913342009-05-25 02:14:3460}
Michael Ershov1c50ac952020-12-02 21:01:1761
Yuta Hijikata2eecbe22021-01-13 05:39:2262#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
[email protected]86913342009-05-25 02:14:3463
[email protected]259c42f2013-09-12 20:32:2264// On non-Chrome OS platforms, return the default config directory. On Chrome OS
65// test images, return a read-only directory with fake root CA certs (which are
66// used by the local Google Accounts server mock we use when testing our login
67// code). On Chrome OS non-test images (where the read-only directory doesn't
68// exist), return an empty path.
[email protected]9e275712013-02-10 19:20:1469base::FilePath GetInitialConfigDirectory() {
Yuta Hijikata2eecbe22021-01-13 05:39:2270#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
[email protected]259c42f2013-09-12 20:32:2271 base::FilePath database_dir = base::FilePath(kReadOnlyCertDB);
72 if (!base::PathExists(database_dir))
73 database_dir.clear();
74 return database_dir;
[email protected]dcce6cf2010-04-29 17:50:0675#else
76 return GetDefaultConfigDirectory();
Yuta Hijikatabf953202020-11-12 08:43:5577#endif // BUILDFLAG(IS_CHROMEOS_ASH)
[email protected]dcce6cf2010-04-29 17:50:0678}
79
[email protected]88b9db72011-01-13 01:48:4380// This callback for NSS forwards all requests to a caller-specified
[email protected]3f1f8412011-01-19 03:01:2381// CryptoModuleBlockingPasswordDelegate object.
82char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) {
[email protected]4b559b4d2011-04-14 17:37:1483 crypto::CryptoModuleBlockingPasswordDelegate* delegate =
84 reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg);
[email protected]88b9db72011-01-13 01:48:4385 if (delegate) {
86 bool cancelled = false;
87 std::string password = delegate->RequestPassword(PK11_GetTokenName(slot),
88 retry != PR_FALSE,
89 &cancelled);
90 if (cancelled)
rsleeviffe5a132016-06-28 01:51:5291 return nullptr;
[email protected]88b9db72011-01-13 01:48:4392 char* result = PORT_Strdup(password.c_str());
93 password.replace(0, password.size(), password.size(), 0);
94 return result;
95 }
rsleeviffe5a132016-06-28 01:51:5296 DLOG(ERROR) << "PK11 password requested with nullptr arg";
97 return nullptr;
[email protected]88b9db72011-01-13 01:48:4398}
99
[email protected]730fb132009-09-02 22:50:25100// A singleton to initialize/deinitialize NSPR.
101// Separate from the NSS singleton because we initialize NSPR on the UI thread.
[email protected]f615bda32010-11-21 01:04:56102// Now that we're leaking the singleton, we could merge back with the NSS
103// singleton.
[email protected]730fb132009-09-02 22:50:25104class NSPRInitSingleton {
[email protected]f615bda32010-11-21 01:04:56105 private:
scottmg5e65e3a2017-03-08 08:48:46106 friend struct base::LazyInstanceTraitsBase<NSPRInitSingleton>;
[email protected]f615bda32010-11-21 01:04:56107
[email protected]730fb132009-09-02 22:50:25108 NSPRInitSingleton() {
109 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
110 }
111
Matt Muellere82b3a542017-07-21 17:44:55112 // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS
113 // to prevent non-joinable threads from using NSS after it's already been
114 // shut down.
115 ~NSPRInitSingleton() = delete;
[email protected]730fb132009-09-02 22:50:25116};
117
[email protected]9fc44162012-01-23 22:56:41118base::LazyInstance<NSPRInitSingleton>::Leaky
[email protected]6de0fd1d2011-11-15 13:31:49119 g_nspr_singleton = LAZY_INSTANCE_INITIALIZER;
[email protected]f615bda32010-11-21 01:04:56120
[email protected]007f5122012-11-21 16:00:21121// Force a crash with error info on NSS_NoDB_Init failure.
122void CrashOnNSSInitFailure() {
123 int nss_error = PR_GetError();
124 int os_error = PR_GetOSError();
[email protected]716fb112012-11-15 05:41:25125 base::debug::Alias(&nss_error);
126 base::debug::Alias(&os_error);
[email protected]007f5122012-11-21 16:00:21127 LOG(ERROR) << "Error initializing NSS without a persistent database: "
128 << GetNSSErrorMessage();
[email protected]2b12459a2012-11-16 03:45:32129 LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error;
[email protected]716fb112012-11-15 05:41:25130}
131
[email protected]bc1e07c72008-09-16 14:32:44132class NSSInitSingleton {
[email protected]f615bda32010-11-21 01:04:56133 private:
scottmg5e65e3a2017-03-08 08:48:46134 friend struct base::LazyInstanceTraitsBase<NSSInitSingleton>;
[email protected]f615bda32010-11-21 01:04:56135
David Benjamin87ccc992019-10-12 01:09:03136 NSSInitSingleton() {
Matt Mueller7858f422018-03-27 03:25:02137 // Initializing NSS causes us to do blocking IO.
138 // Temporarily allow it until we fix
139 // http://code.google.com/p/chromium/issues/detail?id=59847
140 base::ThreadRestrictions::ScopedAllowIO allow_io;
141
[email protected]f615bda32010-11-21 01:04:56142 EnsureNSPRInit();
[email protected]730fb132009-09-02 22:50:25143
rsleevib52a2df2017-06-08 18:28:11144 // We *must* have NSS >= 3.26 at compile time.
145 static_assert((NSS_VMAJOR == 3 && NSS_VMINOR >= 26) || (NSS_VMAJOR > 3),
146 "nss version check failed");
[email protected]dc36c9c2010-01-20 20:45:00147 // Also check the run-time NSS version.
148 // NSS_VersionCheck is a >= check, not strict equality.
rsleevib52a2df2017-06-08 18:28:11149 if (!NSS_VersionCheck("3.26")) {
150 LOG(FATAL) << "NSS_VersionCheck(\"3.26\") failed. NSS >= 3.26 is "
[email protected]805acdc2013-08-07 22:57:00151 "required. Please upgrade to the latest NSS, and if you "
[email protected]1b8082d2010-02-19 12:21:48152 "still get this error, contact your distribution "
153 "maintainer.";
154 }
[email protected]dc36c9c2010-01-20 20:45:00155
[email protected]897f5202009-09-08 17:40:27156 SECStatus status = SECFailure;
rsleevia3ad8d02016-06-07 18:22:33157 base::FilePath database_dir = GetInitialConfigDirectory();
158 if (!database_dir.empty()) {
rsleevia3ad8d02016-06-07 18:22:33159 // Initialize with a persistent database (likely, ~/.pki/nssdb).
160 // Use "sql:" which can be shared by multiple processes safely.
161 std::string nss_config_dir =
162 base::StringPrintf("sql:%s", database_dir.value().c_str());
Yuta Hijikata2eecbe22021-01-13 05:39:22163#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
rsleevia3ad8d02016-06-07 18:22:33164 status = NSS_Init(nss_config_dir.c_str());
165#else
166 status = NSS_InitReadWrite(nss_config_dir.c_str());
[email protected]dcce6cf2010-04-29 17:50:06167#endif
rsleevia3ad8d02016-06-07 18:22:33168 if (status != SECSuccess) {
169 LOG(ERROR) << "Error initializing NSS with a persistent "
170 "database (" << nss_config_dir
171 << "): " << GetNSSErrorMessage();
172 }
173 }
174 if (status != SECSuccess) {
175 VLOG(1) << "Initializing NSS without a persistent database.";
rsleeviffe5a132016-06-28 01:51:52176 status = NSS_NoDB_Init(nullptr);
[email protected]897f5202009-09-08 17:40:27177 if (status != SECSuccess) {
[email protected]007f5122012-11-21 16:00:21178 CrashOnNSSInitFailure();
[email protected]716fb112012-11-15 05:41:25179 return;
[email protected]897f5202009-09-08 17:40:27180 }
[email protected]6e7e8062009-04-13 17:35:09181 }
[email protected]fa2d3dc2012-11-20 07:58:44182
rsleevia3ad8d02016-06-07 18:22:33183 PK11_SetPasswordFunc(PKCS11PasswordFunc);
184
185 // If we haven't initialized the password for the NSS databases,
186 // initialize an empty-string password so that we don't need to
187 // log in.
188 PK11SlotInfo* slot = PK11_GetInternalKeySlot();
189 if (slot) {
190 // PK11_InitPin may write to the keyDB, but no other thread can use NSS
191 // yet, so we don't need to lock.
192 if (PK11_NeedUserInit(slot))
rsleeviffe5a132016-06-28 01:51:52193 PK11_InitPin(slot, nullptr, nullptr);
rsleevia3ad8d02016-06-07 18:22:33194 PK11_FreeSlot(slot);
195 }
196
David Benjamine838004a2019-10-13 08:03:08197 // Load nss's built-in root certs.
198 //
199 // TODO(mattm): DCHECK this succeeded when crbug.com/310972 is fixed.
200 // Failing to load root certs will it hard to talk to anybody via https.
David Benjamin2f2cb362019-10-15 22:51:05201 LoadNSSModule("Root Certs", "libnssckbi.so", nullptr);
rsleevia3ad8d02016-06-07 18:22:33202
[email protected]fa2d3dc2012-11-20 07:58:44203 // Disable MD5 certificate signatures. (They are disabled by default in
204 // NSS 3.14.)
205 NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
206 NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
207 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
[email protected]bc1e07c72008-09-16 14:32:44208 }
209
Matt Muellere82b3a542017-07-21 17:44:55210 // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS
211 // to prevent non-joinable threads from using NSS after it's already been
212 // shut down.
213 ~NSSInitSingleton() = delete;
[email protected]bc1e07c72008-09-16 14:32:44214};
215
[email protected]9fc44162012-01-23 22:56:41216base::LazyInstance<NSSInitSingleton>::Leaky
[email protected]6de0fd1d2011-11-15 13:31:49217 g_nss_singleton = LAZY_INSTANCE_INITIALIZER;
[email protected]bc1e07c72008-09-16 14:32:44218} // namespace
219
[email protected]190933f2014-07-28 09:56:51220ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
221 const std::string& description) {
222 const std::string modspec =
223 base::StringPrintf("configDir='sql:%s' tokenDescription='%s'",
224 path.value().c_str(),
225 description.c_str());
226 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str());
227 if (db_slot) {
228 if (PK11_NeedUserInit(db_slot))
rsleeviffe5a132016-06-28 01:51:52229 PK11_InitPin(db_slot, nullptr, nullptr);
[email protected]190933f2014-07-28 09:56:51230 } else {
231 LOG(ERROR) << "Error opening persistent database (" << modspec
232 << "): " << GetNSSErrorMessage();
233 }
234 return ScopedPK11Slot(db_slot);
235}
236
[email protected]730fb132009-09-02 22:50:25237void EnsureNSPRInit() {
[email protected]f615bda32010-11-21 01:04:56238 g_nspr_singleton.Get();
[email protected]730fb132009-09-02 22:50:25239}
240
[email protected]bc1e07c72008-09-16 14:32:44241void EnsureNSSInit() {
[email protected]f615bda32010-11-21 01:04:56242 g_nss_singleton.Get();
[email protected]bc1e07c72008-09-16 14:32:44243}
244
[email protected]f61c3972010-12-23 09:54:15245bool CheckNSSVersion(const char* version) {
246 return !!NSS_VersionCheck(version);
247}
248
[email protected]dd24ffc2011-06-08 19:46:42249AutoSECMODListReadLock::AutoSECMODListReadLock()
250 : lock_(SECMOD_GetDefaultModuleListLock()) {
251 SECMOD_GetReadLock(lock_);
252 }
253
254AutoSECMODListReadLock::~AutoSECMODListReadLock() {
255 SECMOD_ReleaseReadLock(lock_);
256}
[email protected]69138472010-06-25 22:44:48257
[email protected]4b559b4d2011-04-14 17:37:14258base::Time PRTimeToBaseTime(PRTime prtime) {
[email protected]ca929ed32011-12-15 20:37:28259 return base::Time::FromInternalValue(
260 prtime + base::Time::UnixEpoch().ToInternalValue());
261}
[email protected]1b1a264a2010-01-14 22:36:35262
[email protected]ca929ed32011-12-15 20:37:28263PRTime BaseTimeToPRTime(base::Time time) {
264 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue();
[email protected]1b1a264a2010-01-14 22:36:35265}
266
David Benjamin2f2cb362019-10-15 22:51:05267SECMODModule* LoadNSSModule(const char* name,
268 const char* library_path,
269 const char* params) {
270 std::string modparams =
271 base::StringPrintf("name=\"%s\" library=\"%s\" %s", name, library_path,
272 params ? params : "");
273
274 // Shouldn't need to const_cast here, but SECMOD doesn't properly declare
275 // input string arguments as const. Bug
276 // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed on NSS
277 // codebase to address this.
278 SECMODModule* module = SECMOD_LoadUserModule(
279 const_cast<char*>(modparams.c_str()), nullptr, PR_FALSE);
280 if (!module) {
281 LOG(ERROR) << "Error loading " << name
282 << " module into NSS: " << GetNSSErrorMessage();
283 return nullptr;
284 }
285 if (!module->loaded) {
286 LOG(ERROR) << "After loading " << name
287 << ", loaded==false: " << GetNSSErrorMessage();
288 SECMOD_DestroyModule(module);
289 return nullptr;
290 }
291 return module;
292}
293
294std::string GetNSSErrorMessage() {
295 std::string result;
296 if (PR_GetErrorTextLength()) {
297 std::unique_ptr<char[]> error_text(new char[PR_GetErrorTextLength() + 1]);
298 PRInt32 copied = PR_GetErrorText(error_text.get());
299 result = std::string(error_text.get(), copied);
300 } else {
301 result = base::StringPrintf("NSS error code: %d", PR_GetError());
302 }
303 return result;
304}
305
[email protected]4b559b4d2011-04-14 17:37:14306} // namespace crypto