OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/nss_util.h" | 5 #include "base/nss_util.h" |
6 #include "base/nss_util_internal.h" | 6 #include "base/nss_util_internal.h" |
7 | 7 |
8 #include <nss.h> | 8 #include <nss.h> |
9 #include <plarena.h> | 9 #include <plarena.h> |
10 #include <prerror.h> | 10 #include <prerror.h> |
11 #include <prinit.h> | 11 #include <prinit.h> |
12 #include <prtime.h> | 12 #include <prtime.h> |
13 #include <pk11pub.h> | 13 #include <pk11pub.h> |
14 #include <secmod.h> | 14 #include <secmod.h> |
15 | 15 |
16 #if defined(OS_LINUX) | 16 #if defined(OS_LINUX) |
17 #include <linux/nfs_fs.h> | 17 #include <linux/nfs_fs.h> |
18 #include <sys/vfs.h> | 18 #include <sys/vfs.h> |
19 #endif | 19 #endif |
20 | 20 |
21 #include <vector> | 21 #include <vector> |
22 | 22 |
23 #include "base/crypto/scoped_nss_types.h" | |
23 #include "base/environment.h" | 24 #include "base/environment.h" |
24 #include "base/file_path.h" | 25 #include "base/file_path.h" |
25 #include "base/file_util.h" | 26 #include "base/file_util.h" |
26 #include "base/lazy_instance.h" | 27 #include "base/lazy_instance.h" |
27 #include "base/logging.h" | 28 #include "base/logging.h" |
28 #include "base/memory/scoped_ptr.h" | 29 #include "base/memory/scoped_ptr.h" |
29 #include "base/native_library.h" | 30 #include "base/native_library.h" |
30 #include "base/stringprintf.h" | 31 #include "base/stringprintf.h" |
31 #include "base/threading/thread_restrictions.h" | 32 #include "base/threading/thread_restrictions.h" |
32 | 33 |
33 // USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not | 34 // USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not |
34 // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't | 35 // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't |
35 // use NSS for crypto or certificate verification, and we don't use the NSS | 36 // use NSS for crypto or certificate verification, and we don't use the NSS |
36 // certificate and key databases. | 37 // certificate and key databases. |
37 #if defined(USE_NSS) | 38 #if defined(USE_NSS) |
38 #include "base/crypto/crypto_module_blocking_password_delegate.h" | 39 #include "base/crypto/crypto_module_blocking_password_delegate.h" |
39 #include "base/synchronization/lock.h" | 40 #include "base/synchronization/lock.h" |
40 #endif // defined(USE_NSS) | 41 #endif // defined(USE_NSS) |
41 | 42 |
42 namespace base { | 43 namespace base { |
43 | 44 |
44 namespace { | 45 namespace { |
45 | 46 |
47 #if defined(OS_CHROMEOS) | |
48 const char kNSSDatabaseName[] = "Real NSS database"; | |
49 | |
50 // Constants for loading opencryptoki. | |
51 const char kOpencryptokiModuleName[] = "opencryptoki"; | |
52 const char kOpencryptokiPath[] = "/usr/lib/opencryptoki/libopencryptoki.so"; | |
53 | |
54 // TODO(gspencer): Get these values from cryptohomed's dbus API when | |
55 // we ask if it has initialized the TPM yet. These should not be | |
56 // hard-coded here. | |
57 const char kTPMTokenName[] = "Initialized by CrOS"; | |
58 const char kTPMUserPIN[] = "111111"; | |
59 const char kTPMSecurityOfficerPIN[] = "000000"; | |
60 | |
61 // Fake certificate authority database used for testing. | |
62 static const FilePath::CharType kReadOnlyCertDB[] = | |
63 FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb"); | |
64 #endif // defined(OS_CHROMEOS) | |
65 | |
66 std::string GetNSSErrorMessage() { | |
67 std::string result; | |
68 if (PR_GetErrorTextLength()) { | |
69 scoped_array<char> error_text(new char[PR_GetErrorTextLength() + 1]); | |
70 PRInt32 copied = PR_GetErrorText(error_text.get()); | |
71 result = std::string(error_text.get(), copied); | |
72 } else { | |
73 result = StringPrintf("NSS error code: %d", PR_GetError()); | |
74 } | |
75 return result; | |
76 } | |
77 | |
46 #if defined(USE_NSS) | 78 #if defined(USE_NSS) |
47 FilePath GetDefaultConfigDirectory() { | 79 FilePath GetDefaultConfigDirectory() { |
48 FilePath dir = file_util::GetHomeDir(); | 80 FilePath dir = file_util::GetHomeDir(); |
49 if (dir.empty()) { | 81 if (dir.empty()) { |
50 LOG(ERROR) << "Failed to get home directory."; | 82 LOG(ERROR) << "Failed to get home directory."; |
51 return dir; | 83 return dir; |
52 } | 84 } |
53 dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); | 85 dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); |
54 if (!file_util::CreateDirectory(dir)) { | 86 if (!file_util::CreateDirectory(dir)) { |
55 LOG(ERROR) << "Failed to create ~/.pki/nssdb directory."; | 87 LOG(ERROR) << "Failed to create ~/.pki/nssdb directory."; |
56 dir.clear(); | 88 dir.clear(); |
57 } | 89 } |
58 return dir; | 90 return dir; |
59 } | 91 } |
60 | 92 |
61 // On non-chromeos platforms, return the default config directory. | 93 // On non-chromeos platforms, return the default config directory. |
62 // On chromeos, return a read-only directory with fake root CA certs for testing | 94 // On chromeos, return a read-only directory with fake root CA certs for testing |
63 // (which will not exist on non-testing images). These root CA certs are used | 95 // (which will not exist on non-testing images). These root CA certs are used |
64 // by the local Google Accounts server mock we use when testing our login code. | 96 // by the local Google Accounts server mock we use when testing our login code. |
65 // If this directory is not present, NSS_Init() will fail. It is up to the | 97 // If this directory is not present, NSS_Init() will fail. It is up to the |
66 // caller to failover to NSS_NoDB_Init() at that point. | 98 // caller to failover to NSS_NoDB_Init() at that point. |
67 FilePath GetInitialConfigDirectory() { | 99 FilePath GetInitialConfigDirectory() { |
68 #if defined(OS_CHROMEOS) | 100 #if defined(OS_CHROMEOS) |
69 static const FilePath::CharType kReadOnlyCertDB[] = | |
70 FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb"); | |
71 return FilePath(kReadOnlyCertDB); | 101 return FilePath(kReadOnlyCertDB); |
72 #else | 102 #else |
73 return GetDefaultConfigDirectory(); | 103 return GetDefaultConfigDirectory(); |
74 #endif // defined(OS_CHROMEOS) | 104 #endif // defined(OS_CHROMEOS) |
75 } | 105 } |
76 | 106 |
77 // This callback for NSS forwards all requests to a caller-specified | 107 // This callback for NSS forwards all requests to a caller-specified |
78 // CryptoModuleBlockingPasswordDelegate object. | 108 // CryptoModuleBlockingPasswordDelegate object. |
79 char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) { | 109 char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) { |
110 #if defined(OS_CHROMEOS) | |
111 // If we get asked for a password for the TPM, then return the | |
112 // static password we use. | |
113 if (PK11_GetTokenName(slot) == base::GetTPMTokenName()) | |
114 return PORT_Strdup(kTPMUserPIN); | |
115 #endif | |
80 base::CryptoModuleBlockingPasswordDelegate* delegate = | 116 base::CryptoModuleBlockingPasswordDelegate* delegate = |
81 reinterpret_cast<base::CryptoModuleBlockingPasswordDelegate*>(arg); | 117 reinterpret_cast<base::CryptoModuleBlockingPasswordDelegate*>(arg); |
82 if (delegate) { | 118 if (delegate) { |
83 bool cancelled = false; | 119 bool cancelled = false; |
84 std::string password = delegate->RequestPassword(PK11_GetTokenName(slot), | 120 std::string password = delegate->RequestPassword(PK11_GetTokenName(slot), |
85 retry != PR_FALSE, | 121 retry != PR_FALSE, |
86 &cancelled); | 122 &cancelled); |
87 if (cancelled) | 123 if (cancelled) |
88 return NULL; | 124 return NULL; |
89 char* result = PORT_Strdup(password.c_str()); | 125 char* result = PORT_Strdup(password.c_str()); |
(...skipping 23 matching lines...) Expand all Loading... | |
113 if (buf.f_type == NFS_SUPER_MAGIC) { | 149 if (buf.f_type == NFS_SUPER_MAGIC) { |
114 scoped_ptr<Environment> env(Environment::Create()); | 150 scoped_ptr<Environment> env(Environment::Create()); |
115 const char* use_cache_env_var = "NSS_SDB_USE_CACHE"; | 151 const char* use_cache_env_var = "NSS_SDB_USE_CACHE"; |
116 if (!env->HasVar(use_cache_env_var)) | 152 if (!env->HasVar(use_cache_env_var)) |
117 env->SetVar(use_cache_env_var, "yes"); | 153 env->SetVar(use_cache_env_var, "yes"); |
118 } | 154 } |
119 } | 155 } |
120 #endif // defined(OS_LINUX) | 156 #endif // defined(OS_LINUX) |
121 } | 157 } |
122 | 158 |
123 // Load nss's built-in root certs. | 159 // A helper class that acquires the SECMOD list read lock while the |
124 SECMODModule *InitDefaultRootCerts() { | 160 // AutoSECMODListReadLock is in scope. |
125 const char* kModulePath = "libnssckbi.so"; | 161 class AutoSECMODListReadLock { |
126 char modparams[1024]; | 162 public: |
127 snprintf(modparams, sizeof(modparams), | 163 AutoSECMODListReadLock() |
128 "name=\"Root Certs\" library=\"%s\"", kModulePath); | 164 : lock_(SECMOD_GetDefaultModuleListLock()) { |
129 SECMODModule *root = SECMOD_LoadUserModule(modparams, NULL, PR_FALSE); | 165 SECMOD_GetReadLock(lock_); |
130 if (root) | 166 } |
131 return root; | |
132 | 167 |
133 // Aw, snap. Can't find/load root cert shared library. | 168 ~AutoSECMODListReadLock() { |
134 // This will make it hard to talk to anybody via https. | 169 SECMOD_ReleaseReadLock(lock_); |
135 NOTREACHED(); | 170 } |
171 | |
172 private: | |
173 SECMODListLock* lock_; | |
174 DISALLOW_COPY_AND_ASSIGN(AutoSECMODListReadLock); | |
175 }; | |
176 | |
177 PK11SlotInfo* FindSlotWithTokenName(const std::string& token_name) { | |
178 AutoSECMODListReadLock auto_lock; | |
179 SECMODModuleList* head = SECMOD_GetDefaultModuleList(); | |
180 for (SECMODModuleList* item = head; item != NULL; item = item->next) { | |
181 int slot_count = item->module->loaded ? item->module->slotCount : 0; | |
182 for (int i = 0; i < slot_count; i++) { | |
183 PK11SlotInfo* slot = item->module->slots[i]; | |
184 if (PK11_GetTokenName(slot) == token_name) | |
185 return PK11_ReferenceSlot(slot); | |
186 } | |
187 } | |
136 return NULL; | 188 return NULL; |
137 } | 189 } |
190 | |
138 #endif // defined(USE_NSS) | 191 #endif // defined(USE_NSS) |
139 | 192 |
140 // A singleton to initialize/deinitialize NSPR. | 193 // A singleton to initialize/deinitialize NSPR. |
141 // Separate from the NSS singleton because we initialize NSPR on the UI thread. | 194 // Separate from the NSS singleton because we initialize NSPR on the UI thread. |
142 // Now that we're leaking the singleton, we could merge back with the NSS | 195 // Now that we're leaking the singleton, we could merge back with the NSS |
143 // singleton. | 196 // singleton. |
144 class NSPRInitSingleton { | 197 class NSPRInitSingleton { |
145 private: | 198 private: |
146 friend struct DefaultLazyInstanceTraits<NSPRInitSingleton>; | 199 friend struct DefaultLazyInstanceTraits<NSPRInitSingleton>; |
147 | 200 |
(...skipping 15 matching lines...) Expand all Loading... | |
163 | 216 |
164 LazyInstance<NSPRInitSingleton, LeakyLazyInstanceTraits<NSPRInitSingleton> > | 217 LazyInstance<NSPRInitSingleton, LeakyLazyInstanceTraits<NSPRInitSingleton> > |
165 g_nspr_singleton(LINKER_INITIALIZED); | 218 g_nspr_singleton(LINKER_INITIALIZED); |
166 | 219 |
167 class NSSInitSingleton { | 220 class NSSInitSingleton { |
168 public: | 221 public: |
169 #if defined(OS_CHROMEOS) | 222 #if defined(OS_CHROMEOS) |
170 void OpenPersistentNSSDB() { | 223 void OpenPersistentNSSDB() { |
171 if (!chromeos_user_logged_in_) { | 224 if (!chromeos_user_logged_in_) { |
172 // GetDefaultConfigDirectory causes us to do blocking IO on UI thread. | 225 // GetDefaultConfigDirectory causes us to do blocking IO on UI thread. |
173 // Temporarily allow it until we fix http://crbug.com.70119 | 226 // Temporarily allow it until we fix http://crbug.com/70119 |
174 ThreadRestrictions::ScopedAllowIO allow_io; | 227 ThreadRestrictions::ScopedAllowIO allow_io; |
175 chromeos_user_logged_in_ = true; | 228 chromeos_user_logged_in_ = true; |
176 real_db_slot_ = OpenUserDB(GetDefaultConfigDirectory(), | 229 |
177 "Real NSS database"); | 230 // This creates another DB slot in NSS that is read/write, unlike |
231 // the fake root CA cert DB and the "default" crypto key | |
232 // provider, which are still read-only (because we initialized | |
233 // NSS before we had a cryptohome mounted). | |
234 software_db_slot_ = OpenUserDB(GetDefaultConfigDirectory(), | |
235 kNSSDatabaseName); | |
178 } | 236 } |
179 } | 237 } |
238 | |
239 bool EnableTPMForNSS() { | |
240 if (!opencryptoki_module_) { | |
241 // This loads the opencryptoki module so we can talk to the | |
242 // hardware TPM. | |
243 opencryptoki_module_ = LoadModule( | |
244 kOpencryptokiModuleName, | |
245 kOpencryptokiPath, | |
246 // trustOrder=100 -- means it'll select this as the most | |
247 // trusted slot for the mechanisms it provides. | |
248 // slotParams=... -- selects RSA as only mechanism, and only | |
249 // asks for the password when necessary (instead of every | |
250 // time, or after a timeout). | |
251 "trustOrder=100 slotParams=(1={slotFlags=[RSA] askpw=only})"); | |
252 if (opencryptoki_module_) { | |
253 // We shouldn't need to initialize the TPM PIN here because | |
254 // it'll be taken care of by cryptohomed, but we have to make | |
255 // sure that it is initialized. | |
256 | |
257 // TODO(gspencer): replace this with a dbus call that will | |
258 // check to see that cryptohomed has initialized the PINs, and | |
259 // will fetch the token name and PINs for accessing the TPM. | |
260 EnsureTPMInit(); | |
261 | |
262 // If this is set, then we'll use the TPM by default. | |
263 tpm_db_slot_ = GetTPMSlot(); | |
264 return true; | |
265 } | |
266 } | |
267 return false; | |
268 } | |
269 | |
270 std::string GetTPMTokenName() { | |
271 // TODO(gspencer): This should come from the dbus interchange with | |
272 // cryptohomed instead of being hard-coded. | |
273 return std::string(kTPMTokenName); | |
274 } | |
275 | |
276 PK11SlotInfo* GetTPMSlot() { | |
277 return FindSlotWithTokenName(GetTPMTokenName()); | |
278 } | |
180 #endif // defined(OS_CHROMEOS) | 279 #endif // defined(OS_CHROMEOS) |
181 | 280 |
281 | |
182 bool OpenTestNSSDB(const FilePath& path, const char* description) { | 282 bool OpenTestNSSDB(const FilePath& path, const char* description) { |
183 test_db_slot_ = OpenUserDB(path, description); | 283 test_db_slot_ = OpenUserDB(path, description); |
184 return !!test_db_slot_; | 284 return !!test_db_slot_; |
185 } | 285 } |
186 | 286 |
187 void CloseTestNSSDB() { | 287 void CloseTestNSSDB() { |
188 if (test_db_slot_) { | 288 if (test_db_slot_) { |
189 SECStatus status = SECMOD_CloseUserDB(test_db_slot_); | 289 SECStatus status = SECMOD_CloseUserDB(test_db_slot_); |
190 if (status != SECSuccess) | 290 if (status != SECSuccess) |
191 LOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); | 291 LOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); |
192 PK11_FreeSlot(test_db_slot_); | 292 PK11_FreeSlot(test_db_slot_); |
193 test_db_slot_ = NULL; | 293 test_db_slot_ = NULL; |
194 } | 294 } |
195 } | 295 } |
196 | 296 |
197 PK11SlotInfo* GetDefaultKeySlot() { | 297 PK11SlotInfo* GetPublicNSSKeySlot() { |
198 if (test_db_slot_) | 298 if (test_db_slot_) |
199 return PK11_ReferenceSlot(test_db_slot_); | 299 return PK11_ReferenceSlot(test_db_slot_); |
200 if (real_db_slot_) | 300 if (software_db_slot_) |
201 return PK11_ReferenceSlot(real_db_slot_); | 301 return PK11_ReferenceSlot(software_db_slot_); |
202 return PK11_GetInternalKeySlot(); | 302 return PK11_GetInternalKeySlot(); |
203 } | 303 } |
204 | 304 |
305 PK11SlotInfo* GetPrivateNSSKeySlot() { | |
306 if (test_db_slot_) | |
307 return PK11_ReferenceSlot(test_db_slot_); | |
308 // If the TPM slot has been opened, then return that one. | |
309 if (tpm_db_slot_) | |
310 return PK11_ReferenceSlot(tpm_db_slot_); | |
311 // If it hasn't, then return the software slot. | |
312 if (software_db_slot_) | |
313 return PK11_ReferenceSlot(software_db_slot_); | |
314 return PK11_GetInternalKeySlot(); | |
315 } | |
316 | |
205 #if defined(USE_NSS) | 317 #if defined(USE_NSS) |
206 Lock* write_lock() { | 318 Lock* write_lock() { |
207 return &write_lock_; | 319 return &write_lock_; |
208 } | 320 } |
209 #endif // defined(USE_NSS) | 321 #endif // defined(USE_NSS) |
210 | 322 |
211 // This method is used to force NSS to be initialized without a DB. | 323 // This method is used to force NSS to be initialized without a DB. |
212 // Call this method before NSSInitSingleton() is constructed. | 324 // Call this method before NSSInitSingleton() is constructed. |
213 static void ForceNoDBInit() { | 325 static void ForceNoDBInit() { |
214 force_nodb_init_ = true; | 326 force_nodb_init_ = true; |
215 } | 327 } |
216 | 328 |
217 private: | 329 private: |
218 friend struct DefaultLazyInstanceTraits<NSSInitSingleton>; | 330 friend struct DefaultLazyInstanceTraits<NSSInitSingleton>; |
219 | 331 |
220 NSSInitSingleton() | 332 NSSInitSingleton() |
221 : real_db_slot_(NULL), | 333 : opencryptoki_module_(NULL), |
334 software_db_slot_(NULL), | |
222 test_db_slot_(NULL), | 335 test_db_slot_(NULL), |
336 tpm_db_slot_(NULL), | |
223 root_(NULL), | 337 root_(NULL), |
224 chromeos_user_logged_in_(false) { | 338 chromeos_user_logged_in_(false) { |
225 EnsureNSPRInit(); | 339 EnsureNSPRInit(); |
226 | 340 |
227 // We *must* have NSS >= 3.12.3. See bug 26448. | 341 // We *must* have NSS >= 3.12.3. See bug 26448. |
228 COMPILE_ASSERT( | 342 COMPILE_ASSERT( |
229 (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 3) || | 343 (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 3) || |
230 (NSS_VMAJOR == 3 && NSS_VMINOR > 12) || | 344 (NSS_VMAJOR == 3 && NSS_VMINOR > 12) || |
231 (NSS_VMAJOR > 3), | 345 (NSS_VMAJOR > 3), |
232 nss_version_check_failed); | 346 nss_version_check_failed); |
(...skipping 17 matching lines...) Expand all Loading... | |
250 | 364 |
251 #if !defined(USE_NSS) | 365 #if !defined(USE_NSS) |
252 // Use the system certificate store, so initialize NSS without database. | 366 // Use the system certificate store, so initialize NSS without database. |
253 nodb_init = true; | 367 nodb_init = true; |
254 #endif | 368 #endif |
255 | 369 |
256 if (nodb_init) { | 370 if (nodb_init) { |
257 status = NSS_NoDB_Init(NULL); | 371 status = NSS_NoDB_Init(NULL); |
258 if (status != SECSuccess) { | 372 if (status != SECSuccess) { |
259 LOG(ERROR) << "Error initializing NSS without a persistent " | 373 LOG(ERROR) << "Error initializing NSS without a persistent " |
260 "database: NSS error code " << PR_GetError(); | 374 "database: " << GetNSSErrorMessage(); |
261 } | 375 } |
262 } else { | 376 } else { |
263 #if defined(USE_NSS) | 377 #if defined(USE_NSS) |
264 FilePath database_dir = GetInitialConfigDirectory(); | 378 FilePath database_dir = GetInitialConfigDirectory(); |
265 if (!database_dir.empty()) { | 379 if (!database_dir.empty()) { |
266 // This duplicates the work which should have been done in | 380 // This duplicates the work which should have been done in |
267 // EarlySetupForNSSInit. However, this function is idempotent so | 381 // EarlySetupForNSSInit. However, this function is idempotent so |
268 // there's no harm done. | 382 // there's no harm done. |
269 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); | 383 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); |
270 | 384 |
271 // Initialize with a persistent database (likely, ~/.pki/nssdb). | 385 // Initialize with a persistent database (likely, ~/.pki/nssdb). |
272 // Use "sql:" which can be shared by multiple processes safely. | 386 // Use "sql:" which can be shared by multiple processes safely. |
273 std::string nss_config_dir = | 387 std::string nss_config_dir = |
274 StringPrintf("sql:%s", database_dir.value().c_str()); | 388 StringPrintf("sql:%s", database_dir.value().c_str()); |
275 #if defined(OS_CHROMEOS) | 389 #if defined(OS_CHROMEOS) |
276 status = NSS_Init(nss_config_dir.c_str()); | 390 status = NSS_Init(nss_config_dir.c_str()); |
277 #else | 391 #else |
278 status = NSS_InitReadWrite(nss_config_dir.c_str()); | 392 status = NSS_InitReadWrite(nss_config_dir.c_str()); |
279 #endif | 393 #endif |
280 if (status != SECSuccess) { | 394 if (status != SECSuccess) { |
281 LOG(ERROR) << "Error initializing NSS with a persistent " | 395 LOG(ERROR) << "Error initializing NSS with a persistent " |
282 "database (" << nss_config_dir | 396 "database (" << nss_config_dir |
283 << "): NSS error code " << PR_GetError(); | 397 << "): " << GetNSSErrorMessage(); |
284 } | 398 } |
285 } | 399 } |
286 if (status != SECSuccess) { | 400 if (status != SECSuccess) { |
287 LOG(WARNING) << "Initialize NSS without a persistent database " | 401 VLOG(1) << "Initializing NSS without a persistent database."; |
288 "(~/.pki/nssdb)."; | |
289 status = NSS_NoDB_Init(NULL); | 402 status = NSS_NoDB_Init(NULL); |
290 if (status != SECSuccess) { | 403 if (status != SECSuccess) { |
291 LOG(ERROR) << "Error initializing NSS without a persistent " | 404 LOG(ERROR) << "Error initializing NSS without a persistent " |
292 "database: NSS error code " << PR_GetError(); | 405 "database: " << GetNSSErrorMessage(); |
293 return; | 406 return; |
294 } | 407 } |
295 } | 408 } |
296 | 409 |
297 PK11_SetPasswordFunc(PKCS11PasswordFunc); | 410 PK11_SetPasswordFunc(PKCS11PasswordFunc); |
298 | 411 |
299 // If we haven't initialized the password for the NSS databases, | 412 // If we haven't initialized the password for the NSS databases, |
300 // initialize an empty-string password so that we don't need to | 413 // initialize an empty-string password so that we don't need to |
301 // log in. | 414 // log in. |
302 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); | 415 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); |
303 if (slot) { | 416 if (slot) { |
304 // PK11_InitPin may write to the keyDB, but no other thread can use NSS | 417 // PK11_InitPin may write to the keyDB, but no other thread can use NSS |
305 // yet, so we don't need to lock. | 418 // yet, so we don't need to lock. |
306 if (PK11_NeedUserInit(slot)) | 419 if (PK11_NeedUserInit(slot)) |
307 PK11_InitPin(slot, NULL, NULL); | 420 PK11_InitPin(slot, NULL, NULL); |
308 PK11_FreeSlot(slot); | 421 PK11_FreeSlot(slot); |
309 } | 422 } |
310 | 423 |
311 root_ = InitDefaultRootCerts(); | 424 root_ = InitDefaultRootCerts(); |
312 #endif // defined(USE_NSS) | 425 #endif // defined(USE_NSS) |
313 } | 426 } |
314 } | 427 } |
315 | 428 |
316 // NOTE(willchan): We don't actually execute this code since we leak NSS to | 429 // NOTE(willchan): We don't actually execute this code since we leak NSS to |
317 // prevent non-joinable threads from using NSS after it's already been shut | 430 // prevent non-joinable threads from using NSS after it's already been shut |
318 // down. | 431 // down. |
319 ~NSSInitSingleton() { | 432 ~NSSInitSingleton() { |
320 if (real_db_slot_) { | 433 if (tpm_db_slot_) { |
321 SECMOD_CloseUserDB(real_db_slot_); | 434 PK11_FreeSlot(tpm_db_slot_); |
322 PK11_FreeSlot(real_db_slot_); | 435 tpm_db_slot_ = NULL; |
323 real_db_slot_ = NULL; | 436 } |
437 if (software_db_slot_) { | |
438 SECMOD_CloseUserDB(software_db_slot_); | |
439 PK11_FreeSlot(software_db_slot_); | |
440 software_db_slot_ = NULL; | |
324 } | 441 } |
325 CloseTestNSSDB(); | 442 CloseTestNSSDB(); |
326 if (root_) { | 443 if (root_) { |
327 SECMOD_UnloadUserModule(root_); | 444 SECMOD_UnloadUserModule(root_); |
328 SECMOD_DestroyModule(root_); | 445 SECMOD_DestroyModule(root_); |
329 root_ = NULL; | 446 root_ = NULL; |
330 } | 447 } |
448 if (opencryptoki_module_) { | |
449 SECMOD_UnloadUserModule(opencryptoki_module_); | |
450 SECMOD_DestroyModule(opencryptoki_module_); | |
451 opencryptoki_module_ = NULL; | |
452 } | |
331 | 453 |
332 SECStatus status = NSS_Shutdown(); | 454 SECStatus status = NSS_Shutdown(); |
333 if (status != SECSuccess) { | 455 if (status != SECSuccess) { |
334 // We VLOG(1) because this failure is relatively harmless (leaking, but | 456 // We VLOG(1) because this failure is relatively harmless (leaking, but |
335 // we're shutting down anyway). | 457 // we're shutting down anyway). |
336 VLOG(1) << "NSS_Shutdown failed; see " | 458 VLOG(1) << "NSS_Shutdown failed; see http://crbug.com/4609"; |
337 "http://code.google.com/p/chromium/issues/detail?id=4609"; | |
338 } | 459 } |
339 } | 460 } |
340 | 461 |
462 #if defined(USE_NSS) | |
463 // Load nss's built-in root certs. | |
464 SECMODModule* InitDefaultRootCerts() { | |
465 SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", NULL); | |
466 if (root) | |
467 return root; | |
468 | |
469 // Aw, snap. Can't find/load root cert shared library. | |
470 // This will make it hard to talk to anybody via https. | |
471 NOTREACHED(); | |
472 return NULL; | |
473 } | |
474 | |
475 // Load the given module for this NSS session. | |
476 SECMODModule* LoadModule(const char* name, | |
477 const char* library_path, | |
478 const char* params) { | |
479 std::string modparams = StringPrintf( | |
480 "name=\"%s\" library=\"%s\" %s", | |
481 name, library_path, params ? params : ""); | |
482 | |
483 // Shouldn't need to const_cast here, but SECMOD doesn't properly | |
484 // declare input string arguments as const. Bug | |
485 // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed | |
486 // on NSS codebase to address this. | |
487 SECMODModule* module = SECMOD_LoadUserModule( | |
488 const_cast<char*>(modparams.c_str()), NULL, PR_FALSE); | |
489 if (!module) { | |
490 LOG(ERROR) << "Error loading " << name << " module into NSS: " | |
491 << GetNSSErrorMessage(); | |
492 return NULL; | |
493 } | |
494 return module; | |
495 } | |
496 #endif | |
497 | |
498 #if defined(OS_CHROMEOS) | |
499 void EnsureTPMInit() { | |
500 base::ScopedPK11Slot tpm_slot(GetTPMSlot()); | |
501 if (tpm_slot.get()) { | |
502 // TODO(gspencer): Remove this in favor of the dbus API for | |
503 // cryptohomed when that is available. | |
504 if (PK11_NeedUserInit(tpm_slot.get())) { | |
505 PK11_InitPin(tpm_slot.get(), | |
506 kTPMSecurityOfficerPIN, | |
507 kTPMUserPIN); | |
508 } | |
509 } | |
510 } | |
511 #endif | |
512 | |
341 static PK11SlotInfo* OpenUserDB(const FilePath& path, | 513 static PK11SlotInfo* OpenUserDB(const FilePath& path, |
342 const char* description) { | 514 const char* description) { |
343 const std::string modspec = | 515 const std::string modspec = |
344 StringPrintf("configDir='sql:%s' tokenDescription='%s'", | 516 StringPrintf("configDir='sql:%s' tokenDescription='%s'", |
345 path.value().c_str(), description); | 517 path.value().c_str(), description); |
346 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str()); | 518 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str()); |
347 if (db_slot) { | 519 if (db_slot) { |
348 if (PK11_NeedUserInit(db_slot)) | 520 if (PK11_NeedUserInit(db_slot)) |
349 PK11_InitPin(db_slot, NULL, NULL); | 521 PK11_InitPin(db_slot, NULL, NULL); |
350 } | 522 } |
351 else { | 523 else { |
352 LOG(ERROR) << "Error opening persistent database (" << modspec | 524 LOG(ERROR) << "Error opening persistent database (" << modspec |
353 << "): NSS error code " << PR_GetError(); | 525 << "): " << GetNSSErrorMessage(); |
354 } | 526 } |
355 return db_slot; | 527 return db_slot; |
356 } | 528 } |
357 | 529 |
358 // If this is set to true NSS is forced to be initialized without a DB. | 530 // If this is set to true NSS is forced to be initialized without a DB. |
359 static bool force_nodb_init_; | 531 static bool force_nodb_init_; |
360 | 532 |
361 PK11SlotInfo* real_db_slot_; // Overrides internal key slot if non-NULL. | 533 SECMODModule* opencryptoki_module_; |
362 PK11SlotInfo* test_db_slot_; // Overrides internal key slot and real_db_slot_ | 534 PK11SlotInfo* software_db_slot_; |
363 SECMODModule *root_; | 535 PK11SlotInfo* test_db_slot_; |
536 PK11SlotInfo* tpm_db_slot_; | |
wtc
2011/04/07 05:56:33
This should be just tpm_slot_. TPM is not a datab
Greg Spencer (Chromium)
2011/04/07 16:46:28
removed _db from both. I agree that they are not
| |
537 SECMODModule* root_; | |
364 bool chromeos_user_logged_in_; | 538 bool chromeos_user_logged_in_; |
365 #if defined(USE_NSS) | 539 #if defined(USE_NSS) |
366 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 | 540 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 |
367 // is fixed, we will no longer need the lock. | 541 // is fixed, we will no longer need the lock. |
368 Lock write_lock_; | 542 Lock write_lock_; |
369 #endif // defined(USE_NSS) | 543 #endif // defined(USE_NSS) |
370 }; | 544 }; |
371 | 545 |
372 // static | 546 // static |
373 bool NSSInitSingleton::force_nodb_init_ = false; | 547 bool NSSInitSingleton::force_nodb_init_ = false; |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
475 lock_->AssertAcquired(); | 649 lock_->AssertAcquired(); |
476 lock_->Release(); | 650 lock_->Release(); |
477 } | 651 } |
478 } | 652 } |
479 #endif // defined(USE_NSS) | 653 #endif // defined(USE_NSS) |
480 | 654 |
481 #if defined(OS_CHROMEOS) | 655 #if defined(OS_CHROMEOS) |
482 void OpenPersistentNSSDB() { | 656 void OpenPersistentNSSDB() { |
483 g_nss_singleton.Get().OpenPersistentNSSDB(); | 657 g_nss_singleton.Get().OpenPersistentNSSDB(); |
484 } | 658 } |
485 #endif | 659 |
660 bool EnableTPMForNSS() { | |
661 return g_nss_singleton.Get().EnableTPMForNSS(); | |
662 } | |
663 | |
664 std::string GetTPMTokenName() { | |
665 return g_nss_singleton.Get().GetTPMTokenName(); | |
666 } | |
667 #endif // defined(OS_CHROMEOS) | |
486 | 668 |
487 // TODO(port): Implement this more simply. We can convert by subtracting an | 669 // TODO(port): Implement this more simply. We can convert by subtracting an |
488 // offset (the difference between NSPR's and base::Time's epochs). | 670 // offset (the difference between NSPR's and base::Time's epochs). |
489 Time PRTimeToBaseTime(PRTime prtime) { | 671 Time PRTimeToBaseTime(PRTime prtime) { |
490 PRExplodedTime prxtime; | 672 PRExplodedTime prxtime; |
491 PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime); | 673 PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime); |
492 | 674 |
493 Time::Exploded exploded; | 675 Time::Exploded exploded; |
494 exploded.year = prxtime.tm_year; | 676 exploded.year = prxtime.tm_year; |
495 exploded.month = prxtime.tm_month + 1; | 677 exploded.month = prxtime.tm_month + 1; |
496 exploded.day_of_week = prxtime.tm_wday; | 678 exploded.day_of_week = prxtime.tm_wday; |
497 exploded.day_of_month = prxtime.tm_mday; | 679 exploded.day_of_month = prxtime.tm_mday; |
498 exploded.hour = prxtime.tm_hour; | 680 exploded.hour = prxtime.tm_hour; |
499 exploded.minute = prxtime.tm_min; | 681 exploded.minute = prxtime.tm_min; |
500 exploded.second = prxtime.tm_sec; | 682 exploded.second = prxtime.tm_sec; |
501 exploded.millisecond = prxtime.tm_usec / 1000; | 683 exploded.millisecond = prxtime.tm_usec / 1000; |
502 | 684 |
503 return Time::FromUTCExploded(exploded); | 685 return Time::FromUTCExploded(exploded); |
504 } | 686 } |
505 | 687 |
506 PK11SlotInfo* GetDefaultNSSKeySlot() { | 688 PK11SlotInfo* GetPublicNSSKeySlot() { |
507 return g_nss_singleton.Get().GetDefaultKeySlot(); | 689 return g_nss_singleton.Get().GetPublicNSSKeySlot(); |
690 } | |
691 | |
692 PK11SlotInfo* GetPrivateNSSKeySlot() { | |
693 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); | |
508 } | 694 } |
509 | 695 |
510 } // namespace base | 696 } // namespace base |
OLD | NEW |