diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-14 22:36:35 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-14 22:36:35 +0000 |
commit | 1b1a264ad3d0ecf0e0e19468b3e4b9e1553c2e88 (patch) | |
tree | c3617b3e5e0590ed2f01096929ddbb0edac000e2 /base/nss_util.cc | |
parent | 7105ea549a113d4c1d473c305475caa0a866e286 (diff) | |
download | chromium_src-1b1a264ad3d0ecf0e0e19468b3e4b9e1553c2e88.zip chromium_src-1b1a264ad3d0ecf0e0e19468b3e4b9e1553c2e88.tar.gz chromium_src-1b1a264ad3d0ecf0e0e19468b3e4b9e1553c2e88.tar.bz2 |
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
Diffstat (limited to 'base/nss_util.cc')
-rw-r--r-- | base/nss_util.cc | 200 |
1 files changed, 200 insertions, 0 deletions
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 <dlfcn.h> +#include <nss.h> +#include <plarena.h> +#include <prerror.h> +#include <prinit.h> +#include <prtime.h> +#include <pk11pub.h> +#include <secmod.h> +#include <ssl.h> + +#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<const PRUint16*>( + 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<NSPRInitSingleton>::get(); +} + +void EnsureNSSInit() { + Singleton<NSSInitSingleton>::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 |