Commit dcce6cf6 authored by cmasone@google.com's avatar cmasone@google.com

Enable Chrome OS to load the user's nssdb later.

Review URL: http://codereview.chromium.org/1730001

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45954 0039d316-1c4b-4281-b951-d872f2087c98
parent b6128aab
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/nss_util.h"
#include "base/nss_util_internal.h"
#include <nss.h>
#include <plarena.h>
......@@ -42,6 +43,21 @@ std::string GetDefaultConfigDirectory() {
return dir.value();
}
// On non-chromeos platforms, return the default config directory.
// On chromeos, return a read-only directory with fake root CA certs for testing
// (which will not exist on non-testing images). These root CA certs are used
// by the local Google Accounts server mock we use when testing our login code.
// If this directory is not present, NSS_Init() will fail. It is up to the
// caller to failover to NSS_NoDB_Init() at that point.
std::string GetInitialConfigDirectory() {
#if defined(OS_CHROMEOS)
static const char kReadOnlyCertDB[] = "/etc/fake_root_ca/nssdb";
return std::string(kReadOnlyCertDB);
#else
return GetDefaultConfigDirectory();
#endif // defined(OS_CHROMEOS)
}
// Load nss's built-in root certs.
SECMODModule *InitDefaultRootCerts() {
const char* kModulePath = "libnssckbi.so";
......@@ -78,7 +94,10 @@ class NSPRInitSingleton {
class NSSInitSingleton {
public:
NSSInitSingleton() : root_(NULL) {
NSSInitSingleton()
: real_db_slot_(NULL),
root_(NULL),
chromeos_user_logged_in_(false) {
base::EnsureNSPRInit();
// We *must* have NSS >= 3.12.3. See bug 26448.
......@@ -111,13 +130,17 @@ class NSSInitSingleton {
"database: NSS error code " << PR_GetError();
}
#else
std::string database_dir = GetDefaultConfigDirectory();
std::string database_dir = GetInitialConfigDirectory();
if (!database_dir.empty()) {
// Initialize with a persistant database (~/.pki/nssdb).
// Initialize with a persistent database (likely, ~/.pki/nssdb).
// Use "sql:" which can be shared by multiple processes safely.
std::string nss_config_dir =
StringPrintf("sql:%s", database_dir.c_str());
#if defined(OS_CHROMEOS)
status = NSS_Init(nss_config_dir.c_str());
#else
status = NSS_InitReadWrite(nss_config_dir.c_str());
#endif
if (status != SECSuccess) {
LOG(ERROR) << "Error initializing NSS with a persistent "
"database (" << nss_config_dir
......@@ -150,6 +173,11 @@ class NSSInitSingleton {
}
~NSSInitSingleton() {
if (real_db_slot_) {
SECMOD_CloseUserDB(real_db_slot_);
PK11_FreeSlot(real_db_slot_);
real_db_slot_ = NULL;
}
if (root_) {
SECMOD_UnloadUserModule(root_);
SECMOD_DestroyModule(root_);
......@@ -165,8 +193,36 @@ class NSSInitSingleton {
}
}
#if defined(OS_CHROMEOS)
void OpenPersistentNSSDB() {
if (!chromeos_user_logged_in_) {
chromeos_user_logged_in_ = true;
const std::string modspec =
StringPrintf("configDir='%s' tokenDescription='Real NSS database'",
GetDefaultConfigDirectory().c_str());
real_db_slot_ = SECMOD_OpenUserDB(modspec.c_str());
if (real_db_slot_ == NULL) {
LOG(ERROR) << "Error opening persistent database (" << modspec
<< "): NSS error code " << PR_GetError();
} else {
if (PK11_NeedUserInit(real_db_slot_))
PK11_InitPin(real_db_slot_, NULL, NULL);
}
}
}
#endif // defined(OS_CHROMEOS)
PK11SlotInfo* GetDefaultKeySlot() {
if (real_db_slot_)
return real_db_slot_;
return PK11_GetInternalKeySlot();
}
private:
PK11SlotInfo* real_db_slot_; // Overrides internal key slot if non-NULL.
SECMODModule *root_;
bool chromeos_user_logged_in_;
};
} // namespace
......@@ -181,6 +237,12 @@ void EnsureNSSInit() {
Singleton<NSSInitSingleton>::get();
}
#if defined(OS_CHROMEOS)
void OpenPersistentNSSDB() {
Singleton<NSSInitSingleton>::get()->OpenPersistentNSSDB();
}
#endif
// 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) {
......@@ -200,4 +262,8 @@ Time PRTimeToBaseTime(PRTime prtime) {
return Time::FromUTCExploded(exploded);
}
PK11SlotInfo* GetDefaultNSSKeySlot() {
return Singleton<NSSInitSingleton>::get()->GetDefaultKeySlot();
}
} // namespace base
......@@ -24,6 +24,11 @@ void EnsureNSPRInit();
// ever be initialized once. NSS will be properly shut down on program exit.
void EnsureNSSInit();
#if defined(OS_CHROMEOS)
// Open the r/w nssdb that's stored inside the user's encrypted home directory.
void OpenPersistentNSSDB();
#endif
// 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);
......
// 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_SLOT_UTIL_H_
#define BASE_NSS_SLOT_UTIL_H_
#include <secmodt.h>
// These functions return a type defined in an NSS header, and so cannot be
// declared in nss_util.h. Hence, they are declared here.
namespace base {
PK11SlotInfo* GetDefaultNSSKeySlot();
} // namespace base
#endif // BASE_NSS_UTIL_H_
......@@ -6,6 +6,8 @@
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/lock.h"
#include "base/nss_util.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/singleton.h"
......@@ -22,6 +24,10 @@
#include "chrome/browser/profile_manager.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "googleurl/src/gurl.h"
#include "net/base/cookie_store.h"
#include "net/url_request/url_request_context.h"
......@@ -29,9 +35,15 @@
namespace chromeos {
class LoginUtilsImpl : public LoginUtils {
class LoginUtilsImpl : public LoginUtils,
public NotificationObserver {
public:
LoginUtilsImpl() {}
LoginUtilsImpl() {
registrar_.Add(
this,
NotificationType::LOGIN_USER_CHANGED,
NotificationService::AllSources());
}
// Invoked after the user has successfully logged in. This launches a browser
// and does other bookkeeping after logging in.
......@@ -42,16 +54,25 @@ class LoginUtilsImpl : public LoginUtils {
// Authenticator and must delete it when done.
virtual Authenticator* CreateAuthenticator(LoginStatusConsumer* consumer);
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
private:
NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(LoginUtilsImpl);
};
class LoginUtilsWrapper {
public:
LoginUtilsWrapper() : ptr_(new LoginUtilsImpl) {
}
LoginUtilsWrapper() {}
LoginUtils* get() {
AutoLock create(create_lock_);
if (!ptr_.get())
reset(new LoginUtilsImpl);
return ptr_.get();
}
......@@ -60,6 +81,7 @@ class LoginUtilsWrapper {
}
private:
Lock create_lock_;
scoped_ptr<LoginUtils> ptr_;
DISALLOW_COPY_AND_ASSIGN(LoginUtilsWrapper);
......@@ -105,6 +127,13 @@ Authenticator* LoginUtilsImpl::CreateAuthenticator(
return new PamGoogleAuthenticator(consumer);
}
void LoginUtilsImpl::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::LOGIN_USER_CHANGED)
base::OpenPersistentNSSDB();
}
LoginUtils* LoginUtils::Get() {
return Singleton<LoginUtilsWrapper>::get()->get();
}
......
......@@ -12,6 +12,7 @@
#include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo()
#include "base/base64.h"
#include "base/nss_util_internal.h"
#include "base/nss_util.h"
#include "base/logging.h"
......@@ -97,7 +98,7 @@ std::string KeygenHandler::GenKeyAndSignChallenge() {
// Ensure NSS is initialized.
base::EnsureNSSInit();
slot = PK11_GetInternalKeySlot();
slot = base::GetDefaultNSSKeySlot();
if (!slot) {
LOG(ERROR) << "Couldn't get Internal key slot!";
isSuccess = false;
......
......@@ -8,6 +8,7 @@
#include "base/base64.h"
#include "base/logging.h"
#include "base/nss_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
......@@ -28,7 +29,19 @@ KeygenHandler::KeyLocation ValidKeyLocation() {
return result;
}
TEST(KeygenHandlerTest, FLAKY_SmokeTest) {
class KeygenHandlerTest : public ::testing::Test {
public:
KeygenHandlerTest() {}
virtual ~KeygenHandlerTest() {}
virtual void SetUp() {
#if defined(OS_CHROMEOS)
base::OpenPersistentNSSDB();
#endif
}
};
TEST_F(KeygenHandlerTest, FLAKY_SmokeTest) {
KeygenHandler handler(2048, "some challenge");
handler.set_stores_key(false); // Don't leave the key-pair behind
std::string result = handler.GenKeyAndSignChallenge();
......@@ -65,7 +78,7 @@ TEST(KeygenHandlerTest, FLAKY_SmokeTest) {
// openssl asn1parse -inform DER
}
TEST(KeygenHandlerTest, Cache) {
TEST_F(KeygenHandlerTest, Cache) {
KeygenHandler::Cache* cache = KeygenHandler::Cache::GetInstance();
KeygenHandler::KeyLocation location1;
KeygenHandler::KeyLocation location2;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment