| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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> |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 return PK11_ReferenceSlot(real_db_slot_); | 197 return PK11_ReferenceSlot(real_db_slot_); |
| 198 return PK11_GetInternalKeySlot(); | 198 return PK11_GetInternalKeySlot(); |
| 199 } | 199 } |
| 200 | 200 |
| 201 #if defined(USE_NSS) | 201 #if defined(USE_NSS) |
| 202 Lock* write_lock() { | 202 Lock* write_lock() { |
| 203 return &write_lock_; | 203 return &write_lock_; |
| 204 } | 204 } |
| 205 #endif // defined(USE_NSS) | 205 #endif // defined(USE_NSS) |
| 206 | 206 |
| 207 // This method is used to force NSS to ne initialized without a DB. |
| 208 // Call this method before NSSInitSingleton() is constructed. |
| 209 static void ForceNoDBInit() { |
| 210 force_nodb_init_ = true; |
| 211 } |
| 212 |
| 207 private: | 213 private: |
| 208 friend struct DefaultLazyInstanceTraits<NSSInitSingleton>; | 214 friend struct DefaultLazyInstanceTraits<NSSInitSingleton>; |
| 209 | 215 |
| 210 NSSInitSingleton() | 216 NSSInitSingleton() |
| 211 : real_db_slot_(NULL), | 217 : real_db_slot_(NULL), |
| 212 test_db_slot_(NULL), | 218 test_db_slot_(NULL), |
| 213 root_(NULL), | 219 root_(NULL), |
| 214 chromeos_user_logged_in_(false) { | 220 chromeos_user_logged_in_(false) { |
| 215 EnsureNSPRInit(); | 221 EnsureNSPRInit(); |
| 216 | 222 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 229 LOG(ERROR) << "NSS_VersionCheck(\"3.12.3\") failed. " | 235 LOG(ERROR) << "NSS_VersionCheck(\"3.12.3\") failed. " |
| 230 "We depend on NSS >= 3.12.3, and this error is not fatal " | 236 "We depend on NSS >= 3.12.3, and this error is not fatal " |
| 231 "only because many people have busted NSS setups (for " | 237 "only because many people have busted NSS setups (for " |
| 232 "example, using the wrong version of NSPR). " | 238 "example, using the wrong version of NSPR). " |
| 233 "Please upgrade to the latest NSS and NSPR, and if you " | 239 "Please upgrade to the latest NSS and NSPR, and if you " |
| 234 "still get this error, contact your distribution " | 240 "still get this error, contact your distribution " |
| 235 "maintainer."; | 241 "maintainer."; |
| 236 } | 242 } |
| 237 | 243 |
| 238 SECStatus status = SECFailure; | 244 SECStatus status = SECFailure; |
| 245 bool nodb_init = force_nodb_init_; |
| 246 |
| 239 #if !defined(USE_NSS) | 247 #if !defined(USE_NSS) |
| 240 // Use the system certificate store, so initialize NSS without database. | 248 // Use the system certificate store, so initialize NSS without database. |
| 241 status = NSS_NoDB_Init(NULL); | 249 nodb_init = true; |
| 242 if (status != SECSuccess) { | 250 #endif |
| 243 LOG(ERROR) << "Error initializing NSS without a persistent " | |
| 244 "database: NSS error code " << PR_GetError(); | |
| 245 } | |
| 246 #else | |
| 247 FilePath database_dir = GetInitialConfigDirectory(); | |
| 248 if (!database_dir.empty()) { | |
| 249 // This duplicates the work which should have been done in | |
| 250 // EarlySetupForNSSInit. However, this function is idempotent so there's | |
| 251 // no harm done. | |
| 252 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); | |
| 253 | 251 |
| 254 // Initialize with a persistent database (likely, ~/.pki/nssdb). | 252 if (nodb_init) { |
| 255 // Use "sql:" which can be shared by multiple processes safely. | |
| 256 std::string nss_config_dir = | |
| 257 StringPrintf("sql:%s", database_dir.value().c_str()); | |
| 258 #if defined(OS_CHROMEOS) | |
| 259 status = NSS_Init(nss_config_dir.c_str()); | |
| 260 #else | |
| 261 status = NSS_InitReadWrite(nss_config_dir.c_str()); | |
| 262 #endif | |
| 263 if (status != SECSuccess) { | |
| 264 LOG(ERROR) << "Error initializing NSS with a persistent " | |
| 265 "database (" << nss_config_dir | |
| 266 << "): NSS error code " << PR_GetError(); | |
| 267 } | |
| 268 } | |
| 269 if (status != SECSuccess) { | |
| 270 LOG(WARNING) << "Initialize NSS without a persistent database " | |
| 271 "(~/.pki/nssdb)."; | |
| 272 status = NSS_NoDB_Init(NULL); | 253 status = NSS_NoDB_Init(NULL); |
| 273 if (status != SECSuccess) { | 254 if (status != SECSuccess) { |
| 274 LOG(ERROR) << "Error initializing NSS without a persistent " | 255 LOG(ERROR) << "Error initializing NSS without a persistent " |
| 275 "database: NSS error code " << PR_GetError(); | 256 "database: NSS error code " << PR_GetError(); |
| 276 return; | |
| 277 } | 257 } |
| 258 } else { |
| 259 FilePath database_dir = GetInitialConfigDirectory(); |
| 260 if (!database_dir.empty()) { |
| 261 // This duplicates the work which should have been done in |
| 262 // EarlySetupForNSSInit. However, this function is idempotent so |
| 263 // there's no harm done. |
| 264 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); |
| 265 |
| 266 // Initialize with a persistent database (likely, ~/.pki/nssdb). |
| 267 // Use "sql:" which can be shared by multiple processes safely. |
| 268 std::string nss_config_dir = |
| 269 StringPrintf("sql:%s", database_dir.value().c_str()); |
| 270 #if defined(OS_CHROMEOS) |
| 271 status = NSS_Init(nss_config_dir.c_str()); |
| 272 #else |
| 273 status = NSS_InitReadWrite(nss_config_dir.c_str()); |
| 274 #endif |
| 275 if (status != SECSuccess) { |
| 276 LOG(ERROR) << "Error initializing NSS with a persistent " |
| 277 "database (" << nss_config_dir |
| 278 << "): NSS error code " << PR_GetError(); |
| 279 } |
| 280 } |
| 281 if (status != SECSuccess) { |
| 282 LOG(WARNING) << "Initialize NSS without a persistent database " |
| 283 "(~/.pki/nssdb)."; |
| 284 status = NSS_NoDB_Init(NULL); |
| 285 if (status != SECSuccess) { |
| 286 LOG(ERROR) << "Error initializing NSS without a persistent " |
| 287 "database: NSS error code " << PR_GetError(); |
| 288 return; |
| 289 } |
| 290 } |
| 291 |
| 292 PK11_SetPasswordFunc(PKCS11PasswordFunc); |
| 293 |
| 294 // If we haven't initialized the password for the NSS databases, |
| 295 // initialize an empty-string password so that we don't need to |
| 296 // log in. |
| 297 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); |
| 298 if (slot) { |
| 299 // PK11_InitPin may write to the keyDB, but no other thread can use NSS |
| 300 // yet, so we don't need to lock. |
| 301 if (PK11_NeedUserInit(slot)) |
| 302 PK11_InitPin(slot, NULL, NULL); |
| 303 PK11_FreeSlot(slot); |
| 304 } |
| 305 |
| 306 root_ = InitDefaultRootCerts(); |
| 278 } | 307 } |
| 279 | |
| 280 PK11_SetPasswordFunc(PKCS11PasswordFunc); | |
| 281 | |
| 282 // If we haven't initialized the password for the NSS databases, | |
| 283 // initialize an empty-string password so that we don't need to | |
| 284 // log in. | |
| 285 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); | |
| 286 if (slot) { | |
| 287 // PK11_InitPin may write to the keyDB, but no other thread can use NSS | |
| 288 // yet, so we don't need to lock. | |
| 289 if (PK11_NeedUserInit(slot)) | |
| 290 PK11_InitPin(slot, NULL, NULL); | |
| 291 PK11_FreeSlot(slot); | |
| 292 } | |
| 293 | |
| 294 root_ = InitDefaultRootCerts(); | |
| 295 #endif // !defined(USE_NSS) | |
| 296 } | 308 } |
| 297 | 309 |
| 298 // NOTE(willchan): We don't actually execute this code since we leak NSS to | 310 // NOTE(willchan): We don't actually execute this code since we leak NSS to |
| 299 // prevent non-joinable threads from using NSS after it's already been shut | 311 // prevent non-joinable threads from using NSS after it's already been shut |
| 300 // down. | 312 // down. |
| 301 ~NSSInitSingleton() { | 313 ~NSSInitSingleton() { |
| 302 if (real_db_slot_) { | 314 if (real_db_slot_) { |
| 303 SECMOD_CloseUserDB(real_db_slot_); | 315 SECMOD_CloseUserDB(real_db_slot_); |
| 304 PK11_FreeSlot(real_db_slot_); | 316 PK11_FreeSlot(real_db_slot_); |
| 305 real_db_slot_ = NULL; | 317 real_db_slot_ = NULL; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 330 if (PK11_NeedUserInit(db_slot)) | 342 if (PK11_NeedUserInit(db_slot)) |
| 331 PK11_InitPin(db_slot, NULL, NULL); | 343 PK11_InitPin(db_slot, NULL, NULL); |
| 332 } | 344 } |
| 333 else { | 345 else { |
| 334 LOG(ERROR) << "Error opening persistent database (" << modspec | 346 LOG(ERROR) << "Error opening persistent database (" << modspec |
| 335 << "): NSS error code " << PR_GetError(); | 347 << "): NSS error code " << PR_GetError(); |
| 336 } | 348 } |
| 337 return db_slot; | 349 return db_slot; |
| 338 } | 350 } |
| 339 | 351 |
| 352 // If this is set to true NSS is forced to be initialized without a DB. |
| 353 static bool force_nodb_init_; |
| 354 |
| 340 PK11SlotInfo* real_db_slot_; // Overrides internal key slot if non-NULL. | 355 PK11SlotInfo* real_db_slot_; // Overrides internal key slot if non-NULL. |
| 341 PK11SlotInfo* test_db_slot_; // Overrides internal key slot and real_db_slot_ | 356 PK11SlotInfo* test_db_slot_; // Overrides internal key slot and real_db_slot_ |
| 342 SECMODModule *root_; | 357 SECMODModule *root_; |
| 343 bool chromeos_user_logged_in_; | 358 bool chromeos_user_logged_in_; |
| 344 #if defined(USE_NSS) | 359 #if defined(USE_NSS) |
| 345 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 | 360 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 |
| 346 // is fixed, we will no longer need the lock. | 361 // is fixed, we will no longer need the lock. |
| 347 Lock write_lock_; | 362 Lock write_lock_; |
| 348 #endif // defined(USE_NSS) | 363 #endif // defined(USE_NSS) |
| 349 }; | 364 }; |
| 350 | 365 |
| 366 bool NSSInitSingleton::force_nodb_init_ = false; |
| 367 |
| 351 LazyInstance<NSSInitSingleton, LeakyLazyInstanceTraits<NSSInitSingleton> > | 368 LazyInstance<NSSInitSingleton, LeakyLazyInstanceTraits<NSSInitSingleton> > |
| 352 g_nss_singleton(LINKER_INITIALIZED); | 369 g_nss_singleton(LINKER_INITIALIZED); |
| 353 | 370 |
| 354 } // namespace | 371 } // namespace |
| 355 | 372 |
| 356 #if defined(USE_NSS) | 373 #if defined(USE_NSS) |
| 357 void EarlySetupForNSSInit() { | 374 void EarlySetupForNSSInit() { |
| 358 FilePath database_dir = GetInitialConfigDirectory(); | 375 FilePath database_dir = GetInitialConfigDirectory(); |
| 359 if (!database_dir.empty()) | 376 if (!database_dir.empty()) |
| 360 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); | 377 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); |
| 361 } | 378 } |
| 362 #endif | 379 #endif |
| 363 | 380 |
| 364 void EnsureNSPRInit() { | 381 void EnsureNSPRInit() { |
| 365 g_nspr_singleton.Get(); | 382 g_nspr_singleton.Get(); |
| 366 } | 383 } |
| 367 | 384 |
| 368 void EnsureNSSInit() { | 385 void EnsureNSSInit() { |
| 369 // Initializing SSL causes us to do blocking IO. | 386 // Initializing SSL causes us to do blocking IO. |
| 370 // Temporarily allow it until we fix | 387 // Temporarily allow it until we fix |
| 371 // http://code.google.com/p/chromium/issues/detail?id=59847 | 388 // http://code.google.com/p/chromium/issues/detail?id=59847 |
| 372 ThreadRestrictions::ScopedAllowIO allow_io; | 389 ThreadRestrictions::ScopedAllowIO allow_io; |
| 373 g_nss_singleton.Get(); | 390 g_nss_singleton.Get(); |
| 374 } | 391 } |
| 375 | 392 |
| 393 void EnsureNSSNoDBInit() { |
| 394 ThreadRestrictions::ScopedAllowIO allow_io; |
| 395 |
| 396 // Force NSS to be initialized without a DB. |
| 397 NSSInitSingleton::ForceNoDBInit(); |
| 398 g_nss_singleton.Get(); |
| 399 } |
| 400 |
| 401 void DisableNSSForkCheck() { |
| 402 scoped_ptr<Environment> env(Environment::Create()); |
| 403 env->SetVar("NSS_STRICT_NOFORK", "DISABLED"); |
| 404 } |
| 405 |
| 376 bool CheckNSSVersion(const char* version) { | 406 bool CheckNSSVersion(const char* version) { |
| 377 return !!NSS_VersionCheck(version); | 407 return !!NSS_VersionCheck(version); |
| 378 } | 408 } |
| 379 | 409 |
| 380 #if defined(USE_NSS) | 410 #if defined(USE_NSS) |
| 381 bool OpenTestNSSDB(const FilePath& path, const char* description) { | 411 bool OpenTestNSSDB(const FilePath& path, const char* description) { |
| 382 return g_nss_singleton.Get().OpenTestNSSDB(path, description); | 412 return g_nss_singleton.Get().OpenTestNSSDB(path, description); |
| 383 } | 413 } |
| 384 | 414 |
| 385 void CloseTestNSSDB() { | 415 void CloseTestNSSDB() { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 exploded.millisecond = prxtime.tm_usec / 1000; | 457 exploded.millisecond = prxtime.tm_usec / 1000; |
| 428 | 458 |
| 429 return Time::FromUTCExploded(exploded); | 459 return Time::FromUTCExploded(exploded); |
| 430 } | 460 } |
| 431 | 461 |
| 432 PK11SlotInfo* GetDefaultNSSKeySlot() { | 462 PK11SlotInfo* GetDefaultNSSKeySlot() { |
| 433 return g_nss_singleton.Get().GetDefaultKeySlot(); | 463 return g_nss_singleton.Get().GetDefaultKeySlot(); |
| 434 } | 464 } |
| 435 | 465 |
| 436 } // namespace base | 466 } // namespace base |
| OLD | NEW |