blob: d369529c6768736a5c7f4ec349b612eefbb1cfee [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"
[email protected]99e5e9522013-12-16 13:05:2730#include "crypto/nss_crypto_module_delegate.h"
David Benjamin839b74b2017-06-26 21:45:2231#include "crypto/nss_util_internal.h"
32
[email protected]4b559b4d2011-04-14 17:37:1433namespace crypto {
[email protected]f1633932010-08-17 23:05:2834
[email protected]bc1e07c72008-09-16 14:32:4435namespace {
36
[email protected]6a89ef22011-04-07 17:34:2137#if defined(OS_CHROMEOS)
[email protected]6a89ef22011-04-07 17:34:2138// Fake certificate authority database used for testing.
[email protected]9e275712013-02-10 19:20:1439static const base::FilePath::CharType kReadOnlyCertDB[] =
[email protected]6a89ef22011-04-07 17:34:2140 FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb");
41#endif // defined(OS_CHROMEOS)
42
[email protected]4071e6ac2014-07-12 12:46:1743#if !defined(OS_CHROMEOS)
[email protected]9e275712013-02-10 19:20:1444base::FilePath GetDefaultConfigDirectory() {
[email protected]6bdc52272014-05-27 00:12:3345 base::FilePath dir;
Avi Drissmanea15ea02018-05-07 18:55:1246 base::PathService::Get(base::DIR_HOME, &dir);
[email protected]a8b58f42010-07-14 20:21:3547 if (dir.empty()) {
48 LOG(ERROR) << "Failed to get home directory.";
49 return dir;
[email protected]86913342009-05-25 02:14:3450 }
[email protected]86913342009-05-25 02:14:3451 dir = dir.AppendASCII(".pki").AppendASCII("nssdb");
[email protected]426d1c92013-12-03 20:08:5452 if (!base::CreateDirectory(dir)) {
[email protected]948a707b2011-06-07 22:51:4453 LOG(ERROR) << "Failed to create " << dir.value() << " directory.";
[email protected]a8b58f42010-07-14 20:21:3554 dir.clear();
[email protected]86913342009-05-25 02:14:3455 }
[email protected]557737f72013-12-06 22:24:0756 DVLOG(2) << "DefaultConfigDirectory: " << dir.value();
[email protected]a8b58f42010-07-14 20:21:3557 return dir;
[email protected]86913342009-05-25 02:14:3458}
Michael Giuffridadc8030c2017-08-02 13:22:4459#endif // !defined(OS_CHROMEOS)
[email protected]86913342009-05-25 02:14:3460
[email protected]259c42f2013-09-12 20:32:2261// On non-Chrome OS platforms, return the default config directory. On Chrome OS
62// test images, return a read-only directory with fake root CA certs (which are
63// used by the local Google Accounts server mock we use when testing our login
64// code). On Chrome OS non-test images (where the read-only directory doesn't
65// exist), return an empty path.
[email protected]9e275712013-02-10 19:20:1466base::FilePath GetInitialConfigDirectory() {
[email protected]dcce6cf2010-04-29 17:50:0667#if defined(OS_CHROMEOS)
[email protected]259c42f2013-09-12 20:32:2268 base::FilePath database_dir = base::FilePath(kReadOnlyCertDB);
69 if (!base::PathExists(database_dir))
70 database_dir.clear();
71 return database_dir;
[email protected]dcce6cf2010-04-29 17:50:0672#else
73 return GetDefaultConfigDirectory();
74#endif // defined(OS_CHROMEOS)
75}
76
[email protected]88b9db72011-01-13 01:48:4377// This callback for NSS forwards all requests to a caller-specified
[email protected]3f1f8412011-01-19 03:01:2378// CryptoModuleBlockingPasswordDelegate object.
79char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) {
[email protected]4b559b4d2011-04-14 17:37:1480 crypto::CryptoModuleBlockingPasswordDelegate* delegate =
81 reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg);
[email protected]88b9db72011-01-13 01:48:4382 if (delegate) {
83 bool cancelled = false;
84 std::string password = delegate->RequestPassword(PK11_GetTokenName(slot),
85 retry != PR_FALSE,
86 &cancelled);
87 if (cancelled)
rsleeviffe5a132016-06-28 01:51:5288 return nullptr;
[email protected]88b9db72011-01-13 01:48:4389 char* result = PORT_Strdup(password.c_str());
90 password.replace(0, password.size(), password.size(), 0);
91 return result;
92 }
rsleeviffe5a132016-06-28 01:51:5293 DLOG(ERROR) << "PK11 password requested with nullptr arg";
94 return nullptr;
[email protected]88b9db72011-01-13 01:48:4395}
96
[email protected]730fb132009-09-02 22:50:2597// A singleton to initialize/deinitialize NSPR.
98// Separate from the NSS singleton because we initialize NSPR on the UI thread.
[email protected]f615bda32010-11-21 01:04:5699// Now that we're leaking the singleton, we could merge back with the NSS
100// singleton.
[email protected]730fb132009-09-02 22:50:25101class NSPRInitSingleton {
[email protected]f615bda32010-11-21 01:04:56102 private:
scottmg5e65e3a2017-03-08 08:48:46103 friend struct base::LazyInstanceTraitsBase<NSPRInitSingleton>;
[email protected]f615bda32010-11-21 01:04:56104
[email protected]730fb132009-09-02 22:50:25105 NSPRInitSingleton() {
106 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
107 }
108
Matt Muellere82b3a542017-07-21 17:44:55109 // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS
110 // to prevent non-joinable threads from using NSS after it's already been
111 // shut down.
112 ~NSPRInitSingleton() = delete;
[email protected]730fb132009-09-02 22:50:25113};
114
[email protected]9fc44162012-01-23 22:56:41115base::LazyInstance<NSPRInitSingleton>::Leaky
[email protected]6de0fd1d2011-11-15 13:31:49116 g_nspr_singleton = LAZY_INSTANCE_INITIALIZER;
[email protected]f615bda32010-11-21 01:04:56117
[email protected]007f5122012-11-21 16:00:21118// Force a crash with error info on NSS_NoDB_Init failure.
119void CrashOnNSSInitFailure() {
120 int nss_error = PR_GetError();
121 int os_error = PR_GetOSError();
[email protected]716fb112012-11-15 05:41:25122 base::debug::Alias(&nss_error);
123 base::debug::Alias(&os_error);
[email protected]007f5122012-11-21 16:00:21124 LOG(ERROR) << "Error initializing NSS without a persistent database: "
125 << GetNSSErrorMessage();
[email protected]2b12459a2012-11-16 03:45:32126 LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error;
[email protected]716fb112012-11-15 05:41:25127}
128
[email protected]bc1e07c72008-09-16 14:32:44129class NSSInitSingleton {
[email protected]f615bda32010-11-21 01:04:56130 private:
scottmg5e65e3a2017-03-08 08:48:46131 friend struct base::LazyInstanceTraitsBase<NSSInitSingleton>;
[email protected]f615bda32010-11-21 01:04:56132
David Benjamin87ccc992019-10-12 01:09:03133 NSSInitSingleton() {
Matt Mueller7858f422018-03-27 03:25:02134 // Initializing NSS causes us to do blocking IO.
135 // Temporarily allow it until we fix
136 // http://code.google.com/p/chromium/issues/detail?id=59847
137 base::ThreadRestrictions::ScopedAllowIO allow_io;
138
[email protected]f615bda32010-11-21 01:04:56139 EnsureNSPRInit();
[email protected]730fb132009-09-02 22:50:25140
rsleevib52a2df2017-06-08 18:28:11141 // We *must* have NSS >= 3.26 at compile time.
142 static_assert((NSS_VMAJOR == 3 && NSS_VMINOR >= 26) || (NSS_VMAJOR > 3),
143 "nss version check failed");
[email protected]dc36c9c2010-01-20 20:45:00144 // Also check the run-time NSS version.
145 // NSS_VersionCheck is a >= check, not strict equality.
rsleevib52a2df2017-06-08 18:28:11146 if (!NSS_VersionCheck("3.26")) {
147 LOG(FATAL) << "NSS_VersionCheck(\"3.26\") failed. NSS >= 3.26 is "
[email protected]805acdc2013-08-07 22:57:00148 "required. Please upgrade to the latest NSS, and if you "
[email protected]1b8082d2010-02-19 12:21:48149 "still get this error, contact your distribution "
150 "maintainer.";
151 }
[email protected]dc36c9c2010-01-20 20:45:00152
[email protected]897f5202009-09-08 17:40:27153 SECStatus status = SECFailure;
rsleevia3ad8d02016-06-07 18:22:33154 base::FilePath database_dir = GetInitialConfigDirectory();
155 if (!database_dir.empty()) {
rsleevia3ad8d02016-06-07 18:22:33156 // Initialize with a persistent database (likely, ~/.pki/nssdb).
157 // Use "sql:" which can be shared by multiple processes safely.
158 std::string nss_config_dir =
159 base::StringPrintf("sql:%s", database_dir.value().c_str());
160#if defined(OS_CHROMEOS)
161 status = NSS_Init(nss_config_dir.c_str());
162#else
163 status = NSS_InitReadWrite(nss_config_dir.c_str());
[email protected]dcce6cf2010-04-29 17:50:06164#endif
rsleevia3ad8d02016-06-07 18:22:33165 if (status != SECSuccess) {
166 LOG(ERROR) << "Error initializing NSS with a persistent "
167 "database (" << nss_config_dir
168 << "): " << GetNSSErrorMessage();
169 }
170 }
171 if (status != SECSuccess) {
172 VLOG(1) << "Initializing NSS without a persistent database.";
rsleeviffe5a132016-06-28 01:51:52173 status = NSS_NoDB_Init(nullptr);
[email protected]897f5202009-09-08 17:40:27174 if (status != SECSuccess) {
[email protected]007f5122012-11-21 16:00:21175 CrashOnNSSInitFailure();
[email protected]716fb112012-11-15 05:41:25176 return;
[email protected]897f5202009-09-08 17:40:27177 }
[email protected]6e7e8062009-04-13 17:35:09178 }
[email protected]fa2d3dc2012-11-20 07:58:44179
rsleevia3ad8d02016-06-07 18:22:33180 PK11_SetPasswordFunc(PKCS11PasswordFunc);
181
182 // If we haven't initialized the password for the NSS databases,
183 // initialize an empty-string password so that we don't need to
184 // log in.
185 PK11SlotInfo* slot = PK11_GetInternalKeySlot();
186 if (slot) {
187 // PK11_InitPin may write to the keyDB, but no other thread can use NSS
188 // yet, so we don't need to lock.
189 if (PK11_NeedUserInit(slot))
rsleeviffe5a132016-06-28 01:51:52190 PK11_InitPin(slot, nullptr, nullptr);
rsleevia3ad8d02016-06-07 18:22:33191 PK11_FreeSlot(slot);
192 }
193
David Benjamine838004a2019-10-13 08:03:08194 // Load nss's built-in root certs.
195 //
196 // TODO(mattm): DCHECK this succeeded when crbug.com/310972 is fixed.
197 // Failing to load root certs will it hard to talk to anybody via https.
David Benjamin2f2cb362019-10-15 22:51:05198 LoadNSSModule("Root Certs", "libnssckbi.so", nullptr);
rsleevia3ad8d02016-06-07 18:22:33199
[email protected]fa2d3dc2012-11-20 07:58:44200 // Disable MD5 certificate signatures. (They are disabled by default in
201 // NSS 3.14.)
202 NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
203 NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
204 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
[email protected]bc1e07c72008-09-16 14:32:44205 }
206
Matt Muellere82b3a542017-07-21 17:44:55207 // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS
208 // to prevent non-joinable threads from using NSS after it's already been
209 // shut down.
210 ~NSSInitSingleton() = delete;
[email protected]bc1e07c72008-09-16 14:32:44211};
212
[email protected]9fc44162012-01-23 22:56:41213base::LazyInstance<NSSInitSingleton>::Leaky
[email protected]6de0fd1d2011-11-15 13:31:49214 g_nss_singleton = LAZY_INSTANCE_INITIALIZER;
[email protected]bc1e07c72008-09-16 14:32:44215} // namespace
216
[email protected]190933f2014-07-28 09:56:51217ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
218 const std::string& description) {
219 const std::string modspec =
220 base::StringPrintf("configDir='sql:%s' tokenDescription='%s'",
221 path.value().c_str(),
222 description.c_str());
223 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str());
224 if (db_slot) {
225 if (PK11_NeedUserInit(db_slot))
rsleeviffe5a132016-06-28 01:51:52226 PK11_InitPin(db_slot, nullptr, nullptr);
[email protected]190933f2014-07-28 09:56:51227 } else {
228 LOG(ERROR) << "Error opening persistent database (" << modspec
229 << "): " << GetNSSErrorMessage();
230 }
231 return ScopedPK11Slot(db_slot);
232}
233
[email protected]730fb132009-09-02 22:50:25234void EnsureNSPRInit() {
[email protected]f615bda32010-11-21 01:04:56235 g_nspr_singleton.Get();
[email protected]730fb132009-09-02 22:50:25236}
237
[email protected]bc1e07c72008-09-16 14:32:44238void EnsureNSSInit() {
[email protected]f615bda32010-11-21 01:04:56239 g_nss_singleton.Get();
[email protected]bc1e07c72008-09-16 14:32:44240}
241
[email protected]f61c3972010-12-23 09:54:15242bool CheckNSSVersion(const char* version) {
243 return !!NSS_VersionCheck(version);
244}
245
[email protected]dd24ffc2011-06-08 19:46:42246AutoSECMODListReadLock::AutoSECMODListReadLock()
247 : lock_(SECMOD_GetDefaultModuleListLock()) {
248 SECMOD_GetReadLock(lock_);
249 }
250
251AutoSECMODListReadLock::~AutoSECMODListReadLock() {
252 SECMOD_ReleaseReadLock(lock_);
253}
[email protected]69138472010-06-25 22:44:48254
[email protected]4b559b4d2011-04-14 17:37:14255base::Time PRTimeToBaseTime(PRTime prtime) {
[email protected]ca929ed32011-12-15 20:37:28256 return base::Time::FromInternalValue(
257 prtime + base::Time::UnixEpoch().ToInternalValue());
258}
[email protected]1b1a264a2010-01-14 22:36:35259
[email protected]ca929ed32011-12-15 20:37:28260PRTime BaseTimeToPRTime(base::Time time) {
261 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue();
[email protected]1b1a264a2010-01-14 22:36:35262}
263
David Benjamin2f2cb362019-10-15 22:51:05264SECMODModule* LoadNSSModule(const char* name,
265 const char* library_path,
266 const char* params) {
267 std::string modparams =
268 base::StringPrintf("name=\"%s\" library=\"%s\" %s", name, library_path,
269 params ? params : "");
270
271 // Shouldn't need to const_cast here, but SECMOD doesn't properly declare
272 // input string arguments as const. Bug
273 // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed on NSS
274 // codebase to address this.
275 SECMODModule* module = SECMOD_LoadUserModule(
276 const_cast<char*>(modparams.c_str()), nullptr, PR_FALSE);
277 if (!module) {
278 LOG(ERROR) << "Error loading " << name
279 << " module into NSS: " << GetNSSErrorMessage();
280 return nullptr;
281 }
282 if (!module->loaded) {
283 LOG(ERROR) << "After loading " << name
284 << ", loaded==false: " << GetNSSErrorMessage();
285 SECMOD_DestroyModule(module);
286 return nullptr;
287 }
288 return module;
289}
290
291std::string GetNSSErrorMessage() {
292 std::string result;
293 if (PR_GetErrorTextLength()) {
294 std::unique_ptr<char[]> error_text(new char[PR_GetErrorTextLength() + 1]);
295 PRInt32 copied = PR_GetErrorText(error_text.get());
296 result = std::string(error_text.get(), copied);
297 } else {
298 result = base::StringPrintf("NSS error code: %d", PR_GetError());
299 }
300 return result;
301}
302
[email protected]4b559b4d2011-04-14 17:37:14303} // namespace crypto