summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
authormattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-13 01:48:43 +0000
committermattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-13 01:48:43 +0000
commit88b9db7d713a9e156fa66694844c4d98ee48d875 (patch)
treea06b93ff3319bc3512051372ecadd693ebeeaf80 /net/base
parent6fd024b93e4a708a767c1892e5091e3585a5c72f (diff)
downloadchromium_src-88b9db7d713a9e156fa66694844c4d98ee48d875.zip
chromium_src-88b9db7d713a9e156fa66694844c4d98ee48d875.tar.gz
chromium_src-88b9db7d713a9e156fa66694844c4d98ee48d875.tar.bz2
NSS: PKCS 11 password prompt.
This was based off of davidben's WIP cl http://codereview.chromium.org/3186021/show. BUG=42073 TEST=add password to NSS DB with "certutil -d sql:.pki/nssdb -W", try client auth, <keygen>, cert manager Review URL: http://codereview.chromium.org/5686002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71281 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base')
-rw-r--r--net/base/cert_database.h11
-rw-r--r--net/base/cert_database_nss.cc20
-rw-r--r--net/base/cert_database_nss_unittest.cc49
-rw-r--r--net/base/crypto_module.h51
-rw-r--r--net/base/crypto_module_nss.cc28
-rw-r--r--net/base/keygen_handler.cc29
-rw-r--r--net/base/keygen_handler.h36
-rw-r--r--net/base/keygen_handler_nss.cc29
8 files changed, 214 insertions, 39 deletions
diff --git a/net/base/cert_database.h b/net/base/cert_database.h
index 5ffb6a2..69290ab 100644
--- a/net/base/cert_database.h
+++ b/net/base/cert_database.h
@@ -16,6 +16,7 @@
namespace net {
+class CryptoModule;
class X509Certificate;
typedef std::vector<scoped_refptr<X509Certificate> > CertificateList;
@@ -72,10 +73,16 @@ class CertDatabase {
// instance of all certificates.)
void ListCerts(CertificateList* certs);
- // Import certificates and private keys from PKCS #12 blob.
+ // Get the default module.
+ // The returned pointer must be stored in a scoped_refptr<CryptoModule>.
+ CryptoModule* GetDefaultModule() const;
+
+ // Import certificates and private keys from PKCS #12 blob into the module.
// Returns OK or a network error code such as ERR_PKCS12_IMPORT_BAD_PASSWORD
// or ERR_PKCS12_IMPORT_ERROR.
- int ImportFromPKCS12(const std::string& data, const string16& password);
+ int ImportFromPKCS12(net::CryptoModule* module,
+ const std::string& data,
+ const string16& password);
// Export the given certificates and private keys into a PKCS #12 blob,
// storing into |output|.
diff --git a/net/base/cert_database_nss.cc b/net/base/cert_database_nss.cc
index a32a7a3..db2c47a 100644
--- a/net/base/cert_database_nss.cc
+++ b/net/base/cert_database_nss.cc
@@ -12,7 +12,9 @@
#include "base/logging.h"
#include "base/nss_util.h"
+#include "base/nss_util_internal.h"
#include "base/scoped_ptr.h"
+#include "net/base/crypto_module.h"
#include "net/base/net_errors.h"
#include "net/base/x509_certificate.h"
#include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
@@ -106,9 +108,23 @@ void CertDatabase::ListCerts(CertificateList* certs) {
CERT_DestroyCertList(cert_list);
}
+CryptoModule* CertDatabase::GetDefaultModule() const {
+ CryptoModule* module =
+ CryptoModule::CreateFromHandle(base::GetDefaultNSSKeySlot());
+ // The module is already referenced when returned from GetDefaultNSSKeymodule,
+ // so we need to deref it once.
+ PK11_FreeSlot(module->os_module_handle());
+
+ return module;
+}
+
int CertDatabase::ImportFromPKCS12(
- const std::string& data, const string16& password) {
- return psm::nsPKCS12Blob_Import(data.data(), data.size(), password);
+ net::CryptoModule* module,
+ const std::string& data,
+ const string16& password) {
+ return psm::nsPKCS12Blob_Import(module->os_module_handle(),
+ data.data(), data.size(),
+ password);
}
int CertDatabase::ExportToPKCS12(
diff --git a/net/base/cert_database_nss_unittest.cc b/net/base/cert_database_nss_unittest.cc
index 8e69104..468c870 100644
--- a/net/base/cert_database_nss_unittest.cc
+++ b/net/base/cert_database_nss_unittest.cc
@@ -20,6 +20,7 @@
#include "net/base/cert_database.h"
#include "net/base/cert_status_flags.h"
#include "net/base/cert_verify_result.h"
+#include "net/base/crypto_module.h"
#include "net/base/net_errors.h"
#include "net/base/x509_certificate.h"
#include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
@@ -107,21 +108,21 @@ class CertDatabaseNSSTest : public testing::Test {
ASSERT_TRUE(temp_db_dir_.CreateUniqueTempDir());
ASSERT_TRUE(
base::OpenTestNSSDB(temp_db_dir_.path(), "CertDatabaseNSSTest db"));
- slot_.reset(base::GetDefaultNSSKeySlot());
+ slot_ = cert_db_.GetDefaultModule();
// Test db should be empty at start of test.
- EXPECT_EQ(0U, ListCertsInSlot(slot_.get()).size());
+ EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size());
}
virtual void TearDown() {
// Don't try to cleanup if the setup failed.
- ASSERT_TRUE(slot_.get());
+ ASSERT_TRUE(slot_->os_module_handle());
- EXPECT_TRUE(CleanupSlotContents(slot_.get()));
- EXPECT_EQ(0U, ListCertsInSlot(slot_.get()).size());
+ EXPECT_TRUE(CleanupSlotContents(slot_->os_module_handle()));
+ EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size());
}
protected:
- base::ScopedPK11Slot slot_;
+ scoped_refptr<CryptoModule> slot_;
CertDatabase cert_db_;
private:
@@ -142,18 +143,22 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12WrongPassword) {
std::string pkcs12_data = ReadTestFile("client.p12");
EXPECT_EQ(ERR_PKCS12_IMPORT_BAD_PASSWORD,
- cert_db_.ImportFromPKCS12(pkcs12_data, ASCIIToUTF16("")));
+ cert_db_.ImportFromPKCS12(slot_,
+ pkcs12_data,
+ ASCIIToUTF16("")));
// Test db should still be empty.
- EXPECT_EQ(0U, ListCertsInSlot(slot_.get()).size());
+ EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size());
}
TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AndExportAgain) {
std::string pkcs12_data = ReadTestFile("client.p12");
- EXPECT_EQ(OK, cert_db_.ImportFromPKCS12(pkcs12_data, ASCIIToUTF16("12345")));
+ EXPECT_EQ(OK, cert_db_.ImportFromPKCS12(slot_,
+ pkcs12_data,
+ ASCIIToUTF16("12345")));
- CertificateList cert_list = ListCertsInSlot(slot_.get());
+ CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
scoped_refptr<X509Certificate> cert(cert_list[0]);
@@ -184,7 +189,7 @@ TEST_F(CertDatabaseNSSTest, ImportCACert_SSLTrust) {
EXPECT_EQ(0U, failed.size());
- CertificateList cert_list = ListCertsInSlot(slot_.get());
+ CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
scoped_refptr<X509Certificate> cert(cert_list[0]);
EXPECT_EQ("Test CA", cert->subject().common_name);
@@ -216,7 +221,7 @@ TEST_F(CertDatabaseNSSTest, ImportCACert_EmailTrust) {
EXPECT_EQ(0U, failed.size());
- CertificateList cert_list = ListCertsInSlot(slot_.get());
+ CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
scoped_refptr<X509Certificate> cert(cert_list[0]);
EXPECT_EQ("Test CA", cert->subject().common_name);
@@ -247,7 +252,7 @@ TEST_F(CertDatabaseNSSTest, ImportCACert_ObjSignTrust) {
EXPECT_EQ(0U, failed.size());
- CertificateList cert_list = ListCertsInSlot(slot_.get());
+ CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
scoped_refptr<X509Certificate> cert(cert_list[0]);
EXPECT_EQ("Test CA", cert->subject().common_name);
@@ -282,7 +287,7 @@ TEST_F(CertDatabaseNSSTest, ImportCA_NotCACert) {
EXPECT_EQ(certs[0], failed[0].certificate);
EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[0].net_error);
- EXPECT_EQ(0U, ListCertsInSlot(slot_.get()).size());
+ EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size());
}
TEST_F(CertDatabaseNSSTest, ImportCACertHierarchy) {
@@ -305,7 +310,7 @@ TEST_F(CertDatabaseNSSTest, ImportCACertHierarchy) {
EXPECT_EQ("www.us.army.mil", failed[0].certificate->subject().common_name);
EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[0].net_error);
- CertificateList cert_list = ListCertsInSlot(slot_.get());
+ CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(2U, cert_list.size());
EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name);
EXPECT_EQ("DOD CA-17", cert_list[1]->subject().common_name);
@@ -322,7 +327,7 @@ TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyDupeRoot) {
&failed));
EXPECT_EQ(0U, failed.size());
- CertificateList cert_list = ListCertsInSlot(slot_.get());
+ CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name);
@@ -342,7 +347,7 @@ TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyDupeRoot) {
EXPECT_EQ("www.us.army.mil", failed[1].certificate->subject().common_name);
EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[1].net_error);
- cert_list = ListCertsInSlot(slot_.get());
+ cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(2U, cert_list.size());
EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name);
EXPECT_EQ("DOD CA-17", cert_list[1]->subject().common_name);
@@ -364,7 +369,7 @@ TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyUntrusted) {
// SEC_ERROR_UNTRUSTED_ISSUER
EXPECT_EQ(ERR_FAILED, failed[0].net_error);
- CertificateList cert_list = ListCertsInSlot(slot_.get());
+ CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name);
}
@@ -383,7 +388,7 @@ TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyTree) {
EXPECT_EQ(0U, failed.size());
- CertificateList cert_list = ListCertsInSlot(slot_.get());
+ CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(3U, cert_list.size());
EXPECT_EQ("DOD CA-13", cert_list[0]->subject().common_name);
EXPECT_EQ("DoD Root CA 2", cert_list[1]->subject().common_name);
@@ -413,7 +418,7 @@ TEST_F(CertDatabaseNSSTest, ImportCACertNotHierarchy) {
EXPECT_EQ("DOD CA-17", failed[1].certificate->subject().common_name);
EXPECT_EQ(ERR_FAILED, failed[1].net_error);
- CertificateList cert_list = ListCertsInSlot(slot_.get());
+ CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
EXPECT_EQ("Test CA", cert_list[0]->subject().common_name);
}
@@ -433,7 +438,7 @@ TEST_F(CertDatabaseNSSTest, ImportServerCert) {
EXPECT_EQ(0U, failed.size());
- CertificateList cert_list = ListCertsInSlot(slot_.get());
+ CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(2U, cert_list.size());
scoped_refptr<X509Certificate> goog_cert(cert_list[0]);
scoped_refptr<X509Certificate> thawte_cert(cert_list[1]);
@@ -461,7 +466,7 @@ TEST_F(CertDatabaseNSSTest, ImportServerCert_SelfSigned) {
EXPECT_EQ(0U, failed.size());
- CertificateList cert_list = ListCertsInSlot(slot_.get());
+ CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
scoped_refptr<X509Certificate> puny_cert(cert_list[0]);
diff --git a/net/base/crypto_module.h b/net/base/crypto_module.h
new file mode 100644
index 0000000..d02bb71
--- /dev/null
+++ b/net/base/crypto_module.h
@@ -0,0 +1,51 @@
+// 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 NET_BASE_CRYPTO_MODULE_H_
+#define NET_BASE_CRYPTO_MODULE_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/ref_counted.h"
+
+#if defined(USE_NSS)
+typedef struct PK11SlotInfoStr PK11SlotInfo;
+#endif
+
+namespace net {
+
+class CryptoModule;
+
+typedef std::vector<scoped_refptr<CryptoModule> > CryptoModuleList;
+
+class CryptoModule : public base::RefCountedThreadSafe<CryptoModule> {
+ public:
+#if defined(USE_NSS)
+ typedef PK11SlotInfo* OSModuleHandle;
+#else
+ typedef void* OSModuleHandle;
+#endif
+
+ OSModuleHandle os_module_handle() const { return module_handle_; }
+
+ std::string GetTokenName() const;
+
+ static CryptoModule* CreateFromHandle(OSModuleHandle handle);
+
+ private:
+ friend class base::RefCountedThreadSafe<CryptoModule>;
+
+ explicit CryptoModule(OSModuleHandle handle);
+ ~CryptoModule();
+
+ OSModuleHandle module_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(CryptoModule);
+};
+
+} // namespace net
+
+#endif // NET_BASE_CRYPTO_MODULE_H_
diff --git a/net/base/crypto_module_nss.cc b/net/base/crypto_module_nss.cc
new file mode 100644
index 0000000..df52ae9
--- /dev/null
+++ b/net/base/crypto_module_nss.cc
@@ -0,0 +1,28 @@
+// 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.
+
+#include "net/base/crypto_module.h"
+
+#include <pk11pub.h>
+
+namespace net {
+
+std::string CryptoModule::GetTokenName() const {
+ return PK11_GetTokenName(module_handle_);
+}
+
+// static
+CryptoModule* CryptoModule::CreateFromHandle(OSModuleHandle handle) {
+ return new CryptoModule(handle);
+}
+
+CryptoModule::CryptoModule(OSModuleHandle handle) : module_handle_(handle) {
+ PK11_ReferenceSlot(module_handle_);
+}
+
+CryptoModule::~CryptoModule() {
+ PK11_FreeSlot(module_handle_);
+}
+
+} // namespace net
diff --git a/net/base/keygen_handler.cc b/net/base/keygen_handler.cc
new file mode 100644
index 0000000..771ad73
--- /dev/null
+++ b/net/base/keygen_handler.cc
@@ -0,0 +1,29 @@
+// 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.
+
+#include "net/base/keygen_handler.h"
+
+#if defined(USE_NSS)
+#include "base/crypto/pk11_blocking_password_delegate.h"
+#endif
+
+namespace net {
+
+// The constructor and destructor must be defined in a .cc file so that
+// PK11BlockingPasswordDelegate can be forward-declared on platforms which use
+// NSS.
+
+KeygenHandler::KeygenHandler(int key_size_in_bits,
+ const std::string& challenge,
+ const GURL& url)
+ : key_size_in_bits_(key_size_in_bits),
+ challenge_(challenge),
+ url_(url),
+ stores_key_(true) {
+}
+
+KeygenHandler::~KeygenHandler() {
+}
+
+} // namespace net
diff --git a/net/base/keygen_handler.h b/net/base/keygen_handler.h
index 5ca6027..d12d084 100644
--- a/net/base/keygen_handler.h
+++ b/net/base/keygen_handler.h
@@ -8,8 +8,16 @@
#include <string>
+#include "base/scoped_ptr.h"
+#include "build/build_config.h"
#include "googleurl/src/gurl.h"
+#if defined(USE_NSS)
+namespace base {
+class PK11BlockingPasswordDelegate;
+};
+#endif // defined(USE_NSS)
+
namespace net {
// This class handles keypair generation for generating client
@@ -22,9 +30,10 @@ class KeygenHandler {
// Creates a handler that will generate a key with the given key size and
// incorporate the |challenge| into the Netscape SPKAC structure. The request
// for the key originated from |url|.
- inline KeygenHandler(int key_size_in_bits,
- const std::string& challenge,
- const GURL& url);
+ KeygenHandler(int key_size_in_bits,
+ const std::string& challenge,
+ const GURL& url);
+ ~KeygenHandler();
// Actually generates the key-pair and the cert request (SPKAC), and returns
// a base64-encoded string suitable for use as the form value of <keygen>.
@@ -33,22 +42,25 @@ class KeygenHandler {
// Exposed only for unit tests.
void set_stores_key(bool store) { stores_key_ = store;}
+#if defined(USE_NSS)
+ // Register the password delegate to be used if the token is unauthenticated.
+ // GenKeyAndSignChallenge runs on a worker thread, so using the blocking
+ // password callback is okay here.
+ // Takes ownership of the delegate.
+ void set_pk11_password_delegate(base::PK11BlockingPasswordDelegate* delegate);
+#endif // defined(USE_NSS)
+
private:
int key_size_in_bits_; // key size in bits (usually 2048)
std::string challenge_; // challenge string sent by server
GURL url_; // the URL that requested the key
bool stores_key_; // should the generated key-pair be stored persistently?
+#if defined(USE_NSS)
+ // The callback for requesting a password to the PKCS#11 token.
+ scoped_ptr<base::PK11BlockingPasswordDelegate> pk11_password_delegate_;
+#endif // defined(USE_NSS)
};
-KeygenHandler::KeygenHandler(int key_size_in_bits,
- const std::string& challenge,
- const GURL& url)
- : key_size_in_bits_(key_size_in_bits),
- challenge_(challenge),
- url_(url),
- stores_key_(true) {
-}
-
} // namespace net
#endif // NET_BASE_KEYGEN_HANDLER_H_
diff --git a/net/base/keygen_handler_nss.cc b/net/base/keygen_handler_nss.cc
index 215244c..a3505c4 100644
--- a/net/base/keygen_handler_nss.cc
+++ b/net/base/keygen_handler_nss.cc
@@ -4,6 +4,11 @@
#include "net/base/keygen_handler.h"
+#include "base/crypto/pk11_blocking_password_delegate.h"
+#include "base/crypto/scoped_nss_types.h"
+#include "base/logging.h"
+#include "base/nss_util.h"
+#include "base/nss_util_internal.h"
#include "net/third_party/mozilla_security_manager/nsKeygenHandler.h"
// PSM = Mozilla's Personal Security Manager.
@@ -12,8 +17,30 @@ namespace psm = mozilla_security_manager;
namespace net {
std::string KeygenHandler::GenKeyAndSignChallenge() {
+ // Ensure NSS is initialized.
+ base::EnsureNSSInit();
+
+ // TODO(mattm): allow choosing which slot to generate and store the key?
+ base::ScopedPK11Slot slot(base::GetDefaultNSSKeySlot());
+ if (!slot.get()) {
+ LOG(ERROR) << "Couldn't get internal key slot!";
+ return std::string();
+ }
+
+ // Authenticate to the token.
+ if (SECSuccess != PK11_Authenticate(slot.get(), PR_TRUE,
+ pk11_password_delegate_.get())) {
+ LOG(ERROR) << "Couldn't authenticate to internal key slot!";
+ return std::string();
+ }
+
return psm::GenKeyAndSignChallenge(key_size_in_bits_, challenge_, url_,
- stores_key_);
+ slot.get(), stores_key_);
+}
+
+void KeygenHandler::set_pk11_password_delegate(
+ base::PK11BlockingPasswordDelegate* delegate) {
+ pk11_password_delegate_.reset(delegate);
}
} // namespace net