From 1b1a264ad3d0ecf0e0e19468b3e4b9e1553c2e88 Mon Sep 17 00:00:00 2001 From: "mattm@chromium.org" Date: Thu, 14 Jan 2010 22:36:35 +0000 Subject: Linux: Add Certificate Info dialog (part 1) Rename base/nss_init.{h,cc} to base/nss_util.{h,cc}, move PRTimeToBaseTime there. BUG=18119 TEST=Load https://www.google.com, compare to firefox cert dialog. Review URL: http://codereview.chromium.org/500141 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36291 0039d316-1c4b-4281-b951-d872f2087c98 --- base/base.gypi | 8 +- base/crypto/rsa_private_key_nss.cc | 2 +- base/crypto/signature_creator_nss.cc | 2 +- base/crypto/signature_verifier_nss.cc | 3 +- base/hmac_nss.cc | 2 +- base/nss_init.cc | 180 ------------------------------ base/nss_init.h | 22 ---- base/nss_util.cc | 200 ++++++++++++++++++++++++++++++++++ base/nss_util.h | 30 +++++ base/test/test_suite.h | 2 +- 10 files changed, 239 insertions(+), 212 deletions(-) delete mode 100644 base/nss_init.cc delete mode 100644 base/nss_init.h create mode 100644 base/nss_util.cc create mode 100644 base/nss_util.h (limited to 'base') diff --git a/base/base.gypi b/base/base.gypi index f7584c4..ecdc0a0 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -287,8 +287,8 @@ 'directory_watcher_inotify.cc', 'linux_util.cc', 'message_pump_glib.cc', - 'nss_init.cc', - 'nss_init.h', + 'nss_util.cc', + 'nss_util.h', ], },], [ 'OS != "linux"', { @@ -547,8 +547,8 @@ 'message_pump_mac.mm', 'nsimage_cache_mac.h', 'nsimage_cache_mac.mm', - 'nss_init.cc', - 'nss_init.h', + 'nss_util.cc', + 'nss_util.h', 'pe_image.cc', 'pe_image.h', 'setproctitle_linux.c', diff --git a/base/crypto/rsa_private_key_nss.cc b/base/crypto/rsa_private_key_nss.cc index 7e10b36..26bb10cc 100644 --- a/base/crypto/rsa_private_key_nss.cc +++ b/base/crypto/rsa_private_key_nss.cc @@ -12,7 +12,7 @@ #include #include "base/logging.h" -#include "base/nss_init.h" +#include "base/nss_util.h" #include "base/scoped_ptr.h" #include "base/string_util.h" diff --git a/base/crypto/signature_creator_nss.cc b/base/crypto/signature_creator_nss.cc index e0de4b7..ff1d271 100644 --- a/base/crypto/signature_creator_nss.cc +++ b/base/crypto/signature_creator_nss.cc @@ -9,7 +9,7 @@ #include #include "base/logging.h" -#include "base/nss_init.h" +#include "base/nss_util.h" #include "base/scoped_ptr.h" namespace base { diff --git a/base/crypto/signature_verifier_nss.cc b/base/crypto/signature_verifier_nss.cc index 901f1fc..369f275 100644 --- a/base/crypto/signature_verifier_nss.cc +++ b/base/crypto/signature_verifier_nss.cc @@ -9,7 +9,7 @@ #include #include "base/logging.h" -#include "base/nss_init.h" +#include "base/nss_util.h" namespace base { @@ -111,4 +111,3 @@ void SignatureVerifier::Reset() { } } // namespace base - diff --git a/base/hmac_nss.cc b/base/hmac_nss.cc index ce705c5..d55bc64 100644 --- a/base/hmac_nss.cc +++ b/base/hmac_nss.cc @@ -8,7 +8,7 @@ #include #include "base/logging.h" -#include "base/nss_init.h" +#include "base/nss_util.h" #include "base/scoped_ptr.h" namespace { diff --git a/base/nss_init.cc b/base/nss_init.cc deleted file mode 100644 index 7f65504..0000000 --- a/base/nss_init.cc +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) 2008-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/nss_init.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/singleton.h" -#include "base/string_util.h" - -namespace { - -std::string GetDefaultConfigDirectory() { - const char* home = getenv("HOME"); - if (home == NULL) { - LOG(ERROR) << "$HOME is not set."; - return ""; - } - FilePath dir(home); - dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); - if (!file_util::CreateDirectory(dir)) { - LOG(ERROR) << "Failed to create ~/.pki/nssdb directory."; - return ""; - } - return dir.value(); -} - -// Load nss's built-in root certs. -SECMODModule *InitDefaultRootCerts() { - const char* kModulePath = "libnssckbi.so"; - char modparams[1024]; - snprintf(modparams, sizeof(modparams), - "name=\"Root Certs\" library=\"%s\"", kModulePath); - SECMODModule *root = SECMOD_LoadUserModule(modparams, NULL, PR_FALSE); - if (root) - return root; - - // Aw, snap. Can't find/load root cert shared library. - // This will make it hard to talk to anybody via https. - NOTREACHED(); - return NULL; -} - -// A singleton to initialize/deinitialize NSPR. -// Separate from the NSS singleton because we initialize NSPR on the UI thread. -class NSPRInitSingleton { - public: - NSPRInitSingleton() { - PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); - } - - ~NSPRInitSingleton() { - PRStatus prstatus = PR_Cleanup(); - if (prstatus != PR_SUCCESS) { - LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?"; - } - } -}; - -class NSSInitSingleton { - public: - NSSInitSingleton() { - base::EnsureNSPRInit(); - - SECStatus status = SECFailure; - std::string database_dir = GetDefaultConfigDirectory(); - if (!database_dir.empty()) { - // Initialize with a persistant database (~/.pki/nssdb). - // Use "sql:" which can be shared by multiple processes safely. - std::string nss_config_dir = - StringPrintf("sql:%s", database_dir.c_str()); - status = NSS_InitReadWrite(nss_config_dir.c_str()); - if (status != SECSuccess) { - LOG(ERROR) << "Error initializing NSS with a persistent " - "database (" << nss_config_dir - << "): NSS error code " << PR_GetError(); - } - } - if (status != SECSuccess) { - LOG(WARNING) << "Initialize NSS without a persistent database " - "(~/.pki/nssdb)."; - status = NSS_NoDB_Init(NULL); - if (status != SECSuccess) { - LOG(ERROR) << "Error initializing NSS without a persistent " - "database: NSS error code " << PR_GetError(); - } - } - - // If we haven't initialized the password for the NSS databases, - // initialize an empty-string password so that we don't need to - // log in. - PK11SlotInfo* slot = PK11_GetInternalKeySlot(); - if (slot) { - if (PK11_NeedUserInit(slot)) - PK11_InitPin(slot, NULL, NULL); - PK11_FreeSlot(slot); - } - - root_ = InitDefaultRootCerts(); - - NSS_SetDomesticPolicy(); - -#if defined(USE_SYSTEM_SSL) - // Use late binding to avoid scary but benign warning - // "Symbol `SSL_ImplementedCiphers' has different size in shared object, - // consider re-linking" - const PRUint16* pSSL_ImplementedCiphers = static_cast( - dlsym(RTLD_DEFAULT, "SSL_ImplementedCiphers")); - if (pSSL_ImplementedCiphers == NULL) { - NOTREACHED() << "Can't get list of supported ciphers"; - return; - } -#else -#define pSSL_ImplementedCiphers SSL_ImplementedCiphers -#endif - - // Explicitly enable exactly those ciphers with keys of at least 80 bits - for (int i = 0; i < SSL_NumImplementedCiphers; i++) { - SSLCipherSuiteInfo info; - if (SSL_GetCipherSuiteInfo(pSSL_ImplementedCiphers[i], &info, - sizeof(info)) == SECSuccess) { - SSL_CipherPrefSetDefault(pSSL_ImplementedCiphers[i], - (info.effectiveKeyBits >= 80)); - } - } - - // Enable SSL - SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE); - - // All other SSL options are set per-session by SSLClientSocket. - } - - ~NSSInitSingleton() { - if (root_) { - SECMOD_UnloadUserModule(root_); - SECMOD_DestroyModule(root_); - root_ = NULL; - } - - // Have to clear the cache, or NSS_Shutdown fails with SEC_ERROR_BUSY - SSL_ClearSessionCache(); - - SECStatus status = NSS_Shutdown(); - if (status != SECSuccess) { - // We LOG(INFO) because this failure is relatively harmless - // (leaking, but we're shutting down anyway). - LOG(INFO) << "NSS_Shutdown failed; see " - "http://code.google.com/p/chromium/issues/detail?id=4609"; - } - - PL_ArenaFinish(); - } - - private: - SECMODModule *root_; -}; - -} // namespace - -namespace base { - -void EnsureNSPRInit() { - Singleton::get(); -} - -void EnsureNSSInit() { - Singleton::get(); -} - -} // namespace base diff --git a/base/nss_init.h b/base/nss_init.h deleted file mode 100644 index cd8ee77..0000000 --- a/base/nss_init.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_NSS_INIT_H_ -#define BASE_NSS_INIT_H_ - -namespace base { - -// Initialize NRPR if it isn't already initialized. This function is -// thread-safe, and NSPR will only ever be initialized once. NSPR will be -// properly shut down on program exit. -void EnsureNSPRInit(); - -// Initialize NSS if it isn't already initialized. This must be called before -// any other NSS functions. This function is thread-safe, and NSS will only -// ever be initialized once. NSS will be properly shut down on program exit. -void EnsureNSSInit(); - -} // namespace base - -#endif // BASE_NSS_INIT_H_ diff --git a/base/nss_util.cc b/base/nss_util.cc new file mode 100644 index 0000000..757b437 --- /dev/null +++ b/base/nss_util.cc @@ -0,0 +1,200 @@ +// Copyright (c) 2008-2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/nss_util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "base/file_util.h" +#include "base/logging.h" +#include "base/singleton.h" +#include "base/string_util.h" + +namespace { + +std::string GetDefaultConfigDirectory() { + const char* home = getenv("HOME"); + if (home == NULL) { + LOG(ERROR) << "$HOME is not set."; + return ""; + } + FilePath dir(home); + dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); + if (!file_util::CreateDirectory(dir)) { + LOG(ERROR) << "Failed to create ~/.pki/nssdb directory."; + return ""; + } + return dir.value(); +} + +// Load nss's built-in root certs. +SECMODModule *InitDefaultRootCerts() { + const char* kModulePath = "libnssckbi.so"; + char modparams[1024]; + snprintf(modparams, sizeof(modparams), + "name=\"Root Certs\" library=\"%s\"", kModulePath); + SECMODModule *root = SECMOD_LoadUserModule(modparams, NULL, PR_FALSE); + if (root) + return root; + + // Aw, snap. Can't find/load root cert shared library. + // This will make it hard to talk to anybody via https. + NOTREACHED(); + return NULL; +} + +// A singleton to initialize/deinitialize NSPR. +// Separate from the NSS singleton because we initialize NSPR on the UI thread. +class NSPRInitSingleton { + public: + NSPRInitSingleton() { + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + } + + ~NSPRInitSingleton() { + PRStatus prstatus = PR_Cleanup(); + if (prstatus != PR_SUCCESS) { + LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?"; + } + } +}; + +class NSSInitSingleton { + public: + NSSInitSingleton() { + base::EnsureNSPRInit(); + + SECStatus status = SECFailure; + std::string database_dir = GetDefaultConfigDirectory(); + if (!database_dir.empty()) { + // Initialize with a persistant database (~/.pki/nssdb). + // Use "sql:" which can be shared by multiple processes safely. + std::string nss_config_dir = + StringPrintf("sql:%s", database_dir.c_str()); + status = NSS_InitReadWrite(nss_config_dir.c_str()); + if (status != SECSuccess) { + LOG(ERROR) << "Error initializing NSS with a persistent " + "database (" << nss_config_dir + << "): NSS error code " << PR_GetError(); + } + } + if (status != SECSuccess) { + LOG(WARNING) << "Initialize NSS without a persistent database " + "(~/.pki/nssdb)."; + status = NSS_NoDB_Init(NULL); + if (status != SECSuccess) { + LOG(ERROR) << "Error initializing NSS without a persistent " + "database: NSS error code " << PR_GetError(); + } + } + + // If we haven't initialized the password for the NSS databases, + // initialize an empty-string password so that we don't need to + // log in. + PK11SlotInfo* slot = PK11_GetInternalKeySlot(); + if (slot) { + if (PK11_NeedUserInit(slot)) + PK11_InitPin(slot, NULL, NULL); + PK11_FreeSlot(slot); + } + + root_ = InitDefaultRootCerts(); + + NSS_SetDomesticPolicy(); + +#if defined(USE_SYSTEM_SSL) + // Use late binding to avoid scary but benign warning + // "Symbol `SSL_ImplementedCiphers' has different size in shared object, + // consider re-linking" + const PRUint16* pSSL_ImplementedCiphers = static_cast( + dlsym(RTLD_DEFAULT, "SSL_ImplementedCiphers")); + if (pSSL_ImplementedCiphers == NULL) { + NOTREACHED() << "Can't get list of supported ciphers"; + return; + } +#else +#define pSSL_ImplementedCiphers SSL_ImplementedCiphers +#endif + + // Explicitly enable exactly those ciphers with keys of at least 80 bits + for (int i = 0; i < SSL_NumImplementedCiphers; i++) { + SSLCipherSuiteInfo info; + if (SSL_GetCipherSuiteInfo(pSSL_ImplementedCiphers[i], &info, + sizeof(info)) == SECSuccess) { + SSL_CipherPrefSetDefault(pSSL_ImplementedCiphers[i], + (info.effectiveKeyBits >= 80)); + } + } + + // Enable SSL + SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE); + + // All other SSL options are set per-session by SSLClientSocket. + } + + ~NSSInitSingleton() { + if (root_) { + SECMOD_UnloadUserModule(root_); + SECMOD_DestroyModule(root_); + root_ = NULL; + } + + // Have to clear the cache, or NSS_Shutdown fails with SEC_ERROR_BUSY + SSL_ClearSessionCache(); + + SECStatus status = NSS_Shutdown(); + if (status != SECSuccess) { + // We LOG(INFO) because this failure is relatively harmless + // (leaking, but we're shutting down anyway). + LOG(INFO) << "NSS_Shutdown failed; see " + "http://code.google.com/p/chromium/issues/detail?id=4609"; + } + + PL_ArenaFinish(); + } + + private: + SECMODModule *root_; +}; + +} // namespace + +namespace base { + +void EnsureNSPRInit() { + Singleton::get(); +} + +void EnsureNSSInit() { + Singleton::get(); +} + +// TODO(port): Implement this more simply. We can convert by subtracting an +// offset (the difference between NSPR's and base::Time's epochs). +Time PRTimeToBaseTime(PRTime prtime) { + PRExplodedTime prxtime; + PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime); + + base::Time::Exploded exploded; + exploded.year = prxtime.tm_year; + exploded.month = prxtime.tm_month + 1; + exploded.day_of_week = prxtime.tm_wday; + exploded.day_of_month = prxtime.tm_mday; + exploded.hour = prxtime.tm_hour; + exploded.minute = prxtime.tm_min; + exploded.second = prxtime.tm_sec; + exploded.millisecond = prxtime.tm_usec / 1000; + + return Time::FromUTCExploded(exploded); +} + +} // namespace base diff --git a/base/nss_util.h b/base/nss_util.h new file mode 100644 index 0000000..f766228 --- /dev/null +++ b/base/nss_util.h @@ -0,0 +1,30 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NSS_UTIL_H_ +#define BASE_NSS_UTIL_H_ + +#include "base/basictypes.h" + +namespace base { + +class Time; + +// Initialize NRPR if it isn't already initialized. This function is +// thread-safe, and NSPR will only ever be initialized once. NSPR will be +// properly shut down on program exit. +void EnsureNSPRInit(); + +// Initialize NSS if it isn't already initialized. This must be called before +// any other NSS functions. This function is thread-safe, and NSS will only +// ever be initialized once. NSS will be properly shut down on program exit. +void EnsureNSSInit(); + +// Convert a NSS PRTime value into a base::Time object. +// We use a int64 instead of PRTime here to avoid depending on NSPR headers. +Time PRTimeToBaseTime(int64 prtime); + +} // namespace base + +#endif // BASE_NSS_UTIL_H_ diff --git a/base/test/test_suite.h b/base/test/test_suite.h index aa006fc..c738518 100644 --- a/base/test/test_suite.h +++ b/base/test/test_suite.h @@ -14,7 +14,7 @@ #include "base/debug_on_start.h" #include "base/i18n/icu_util.h" #include "base/multiprocess_test.h" -#include "base/nss_init.h" +#include "base/nss_util.h" #include "base/path_service.h" #include "base/process_util.h" #include "base/scoped_nsautorelease_pool.h" -- cgit v1.1