diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-13 01:48:43 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-13 01:48:43 +0000 |
commit | 88b9db7d713a9e156fa66694844c4d98ee48d875 (patch) | |
tree | a06b93ff3319bc3512051372ecadd693ebeeaf80 /net/base | |
parent | 6fd024b93e4a708a767c1892e5091e3585a5c72f (diff) | |
download | chromium_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.h | 11 | ||||
-rw-r--r-- | net/base/cert_database_nss.cc | 20 | ||||
-rw-r--r-- | net/base/cert_database_nss_unittest.cc | 49 | ||||
-rw-r--r-- | net/base/crypto_module.h | 51 | ||||
-rw-r--r-- | net/base/crypto_module_nss.cc | 28 | ||||
-rw-r--r-- | net/base/keygen_handler.cc | 29 | ||||
-rw-r--r-- | net/base/keygen_handler.h | 36 | ||||
-rw-r--r-- | net/base/keygen_handler_nss.cc | 29 |
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 |