diff options
author | cmasone@google.com <cmasone@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-10 19:37:51 +0000 |
---|---|---|
committer | cmasone@google.com <cmasone@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-10 19:37:51 +0000 |
commit | 746480537e2c6043d8f5d5dac624aee812a39991 (patch) | |
tree | 9cfc16140c0ff8a8053bbbbd772c384e9a683c0b | |
parent | 76951557d48f011a54c4f30852a69da172af194e (diff) | |
download | chromium_src-746480537e2c6043d8f5d5dac624aee812a39991.zip chromium_src-746480537e2c6043d8f5d5dac624aee812a39991.tar.gz chromium_src-746480537e2c6043d8f5d5dac624aee812a39991.tar.bz2 |
On NSS-using platforms, add a way to use an existing keypair given only the pubkey
I'm reworking Chrome OS' OwnerManager class to leverage code in base/crypto.
For my code, I need a way to get at a keypair that was
previously generated and stored in the user's NSSDB, given only the public
half of the keypair. Given that, I should be able to toss most of the code
in chrome/browser/chromeos/login/owner_key_utils.* and just use RSAPrivateKey
and the signature generation/verification code here in base/crypto
BUG=chromium-os:4485
TEST=base_unittests
Review URL: http://codereview.chromium.org/3032060
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55604 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/base.gyp | 2 | ||||
-rw-r--r-- | base/crypto/rsa_private_key.h | 50 | ||||
-rw-r--r-- | base/crypto/rsa_private_key_mac.cc | 20 | ||||
-rw-r--r-- | base/crypto/rsa_private_key_nss.cc | 114 | ||||
-rw-r--r-- | base/crypto/rsa_private_key_nss_unittest.cc | 64 | ||||
-rw-r--r-- | base/crypto/rsa_private_key_win.cc | 20 |
6 files changed, 261 insertions, 9 deletions
diff --git a/base/base.gyp b/base/base.gyp index 213b5f3..ad183ef 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -70,6 +70,7 @@ 'condition_variable_unittest.cc', 'crypto/encryptor_unittest.cc', 'crypto/rsa_private_key_unittest.cc', + 'crypto/rsa_private_key_nss_unittest.cc', 'crypto/signature_creator_unittest.cc', 'crypto/signature_verifier_unittest.cc', 'crypto/symmetric_key_unittest.cc', @@ -189,6 +190,7 @@ }, { # OS != "linux" and OS != "freebsd" and OS != "openbsd" and OS != "solaris" 'sources!': [ 'message_pump_glib_unittest.cc', + 'crypto/rsa_private_key_nss_unittest.cc', ] }], # This is needed to trigger the dll copy step on windows. diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h index 64095fb..0349ade 100644 --- a/base/crypto/rsa_private_key.h +++ b/base/crypto/rsa_private_key.h @@ -24,6 +24,9 @@ struct SECKEYPublicKeyStr; #if defined(OS_WIN) #include "base/crypto/scoped_capi_types.h" #endif +#if defined(USE_NSS) +#include "base/gtest_prod_util.h" +#endif namespace base { @@ -162,12 +165,38 @@ class RSAPrivateKey { // Create a new random instance. Can return NULL if initialization fails. static RSAPrivateKey* Create(uint16 num_bits); + // Create a new random instance. Can return NULL if initialization fails. + // The created key is permanent and is not exportable in plaintext form. + // + // NOTE: Currently only available if USE_NSS is defined. + static RSAPrivateKey* CreateSensitive(uint16 num_bits); + // Create a new instance by importing an existing private key. The format is // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return NULL if // initialization fails. static RSAPrivateKey* CreateFromPrivateKeyInfo( const std::vector<uint8>& input); + // Create a new instance by importing an existing private key. The format is + // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return NULL if + // initialization fails. + // The created key is permanent and is not exportable in plaintext form. + // + // NOTE: Currently only available if USE_NSS is defined. + static RSAPrivateKey* CreateSensitiveFromPrivateKeyInfo( + const std::vector<uint8>& input); + + // Import an existing public key, and then search for the private + // half in the key database. The format of the public key blob is is + // an X509 SubjectPublicKeyInfo block. This can return NULL if + // initialization fails or the private key cannot be found. The + // caller takes ownership of the returned object, but nothing new is + // created in the key database. + // + // NOTE: Currently only available if USE_NSS is defined. + static RSAPrivateKey* FindFromPublicKeyInfo( + const std::vector<uint8>& input); + ~RSAPrivateKey(); #if defined(USE_NSS) @@ -186,10 +215,27 @@ class RSAPrivateKey { bool ExportPublicKey(std::vector<uint8>* output); private: - // Constructor is private. Use Create() or CreateFromPrivateKeyInfo() - // instead. +#if defined(USE_NSS) + FRIEND_TEST_ALL_PREFIXES(RSAPrivateKeyNSSTest, FindFromPublicKey); + FRIEND_TEST_ALL_PREFIXES(RSAPrivateKeyNSSTest, FailedFindFromPublicKey); +#endif + + // Constructor is private. Use one of the Create*() or Find*() + // methods above instead. RSAPrivateKey(); + // Shared helper for Create() and CreateSensitive(). + // TODO(cmasone): consider replacing |permanent| and |sensitive| with a + // flags arg created by ORing together some enumerated values. + static RSAPrivateKey* CreateWithParams(uint16 num_bits, + bool permanent, + bool sensitive); + + // Shared helper for CreateFromPrivateKeyInfo() and + // CreateSensitiveFromPrivateKeyInfo(). + static RSAPrivateKey* CreateFromPrivateKeyInfoWithParams( + const std::vector<uint8>& input, bool permanent, bool sensitive); + #if defined(USE_NSS) SECKEYPrivateKeyStr* key_; SECKEYPublicKeyStr* public_key_; diff --git a/base/crypto/rsa_private_key_mac.cc b/base/crypto/rsa_private_key_mac.cc index 6dc6a42..e46e93e 100644 --- a/base/crypto/rsa_private_key_mac.cc +++ b/base/crypto/rsa_private_key_mac.cc @@ -49,6 +49,12 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { } // static +RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) { + NOTIMPLEMENTED(); + return NULL; +} + +// static RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( const std::vector<uint8>& input) { if (input.empty()) @@ -103,6 +109,20 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( return result.release(); } +// static +RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( + const std::vector<uint8>& input) { + NOTIMPLEMENTED(); + return NULL; +} + +// static +RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( + const std::vector<uint8>& input) { + NOTIMPLEMENTED(); + return NULL; +} + RSAPrivateKey::RSAPrivateKey() { memset(&key_, 0, sizeof(key_)); diff --git a/base/crypto/rsa_private_key_nss.cc b/base/crypto/rsa_private_key_nss.cc index 4fc0650..13e4f1f 100644 --- a/base/crypto/rsa_private_key_nss.cc +++ b/base/crypto/rsa_private_key_nss.cc @@ -13,6 +13,7 @@ #include "base/leak_annotations.h" #include "base/logging.h" #include "base/nss_util.h" +#include "base/nss_util_internal.h" #include "base/scoped_ptr.h" #include "base/string_util.h" @@ -41,10 +42,14 @@ static bool ReadAttribute(SECKEYPrivateKey* key, namespace base { // static -RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { +RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits, + bool permanent, + bool sensitive) { + base::EnsureNSSInit(); + scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - PK11SlotInfo *slot = PK11_GetInternalSlot(); + PK11SlotInfo *slot = GetDefaultNSSKeySlot(); if (!slot) return NULL; @@ -52,7 +57,7 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { param.keySizeInBits = num_bits; param.pe = 65537L; result->key_ = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, ¶m, - &result->public_key_, PR_FALSE, PR_FALSE, NULL); + &result->public_key_, permanent, sensitive, NULL); PK11_FreeSlot(slot); if (!result->key_) return NULL; @@ -61,14 +66,30 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { } // static -RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( - const std::vector<uint8>& input) { +RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { + return CreateWithParams(num_bits, + PR_FALSE /* not permanent */, + PR_FALSE /* not sensitive */); +} + +// static +RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) { + return CreateWithParams(num_bits, + PR_TRUE /* permanent */, + PR_TRUE /* sensitive */); +} + +// static +RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams( + const std::vector<uint8>& input, bool permanent, bool sensitive) { // This method currently leaks some memory. // See http://crbug.com/34742. ANNOTATE_SCOPED_MEMORY_LEAK; + base::EnsureNSSInit(); + scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - PK11SlotInfo *slot = PK11_GetInternalSlot(); + PK11SlotInfo *slot = GetDefaultNSSKeySlot(); if (!slot) return NULL; @@ -76,7 +97,7 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( der_private_key_info.data = const_cast<unsigned char*>(&input.front()); der_private_key_info.len = input.size(); SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, - &der_private_key_info, NULL, NULL, PR_FALSE, PR_FALSE, + &der_private_key_info, NULL, NULL, permanent, sensitive, KU_DIGITAL_SIGNATURE, &result->key_, NULL); PK11_FreeSlot(slot); if (rv != SECSuccess) { @@ -93,6 +114,85 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( return result.release(); } +// static +RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( + const std::vector<uint8>& input) { + return CreateFromPrivateKeyInfoWithParams(input, + PR_FALSE /* not permanent */, + PR_FALSE /* not sensitive */); +} + +// static +RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( + const std::vector<uint8>& input) { + return CreateFromPrivateKeyInfoWithParams(input, + PR_TRUE /* permanent */, + PR_TRUE /* seneitive */); +} + +// static +RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( + const std::vector<uint8>& input) { + base::EnsureNSSInit(); + + scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); + + // First, decode and save the public key. + SECItem key_der; + key_der.type = siBuffer; + key_der.data = const_cast<unsigned char*>(&input[0]); + key_der.len = input.size(); + + CERTSubjectPublicKeyInfo *spki = + SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der); + if (!spki) { + NOTREACHED(); + return NULL; + } + + result->public_key_ = SECKEY_ExtractPublicKey(spki); + SECKEY_DestroySubjectPublicKeyInfo(spki); + if (!result->public_key_) { + NOTREACHED(); + return NULL; + } + + // Now, look for the associated private key in the user's NSS DB. If it's + // not there, consider that an error. + PK11SlotInfo *slot = GetDefaultNSSKeySlot(); + if (!slot) { + NOTREACHED(); + return NULL; + } + + // Make sure the key is an RSA key. If not, that's an error + if (result->public_key_->keyType != rsaKey) { + PK11_FreeSlot(slot); + NOTREACHED(); + return NULL; + } + + SECItem *ck_id = PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus)); + if (!ck_id) { + PK11_FreeSlot(slot); + NOTREACHED(); + return NULL; + } + + // Finally...Look for the key! + result->key_ = PK11_FindKeyByKeyID(slot, ck_id, NULL); + + // Cleanup... + PK11_FreeSlot(slot); + SECITEM_FreeItem(ck_id, PR_TRUE); + + // If we didn't find it, that's ok. + if (!result->key_) + return NULL; + + return result.release(); +} + RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) { EnsureNSSInit(); } diff --git a/base/crypto/rsa_private_key_nss_unittest.cc b/base/crypto/rsa_private_key_nss_unittest.cc new file mode 100644 index 0000000..7dbe628 --- /dev/null +++ b/base/crypto/rsa_private_key_nss_unittest.cc @@ -0,0 +1,64 @@ +// 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 "base/crypto/rsa_private_key.h" + +#include <keyhi.h> +#include <pk11pub.h> + +#include "base/nss_util.h" +#include "base/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { + +class RSAPrivateKeyNSSTest : public testing::Test { + public: + RSAPrivateKeyNSSTest() {} + virtual ~RSAPrivateKeyNSSTest() {} + + virtual void SetUp() { +#if defined(OS_CHROMEOS) + base::OpenPersistentNSSDB(); +#endif + } + + private: + DISALLOW_COPY_AND_ASSIGN(RSAPrivateKeyNSSTest); +}; + +TEST_F(RSAPrivateKeyNSSTest, FindFromPublicKey) { + // Create a keypair, which will put the keys in the user's NSSDB. + scoped_ptr<base::RSAPrivateKey> key_pair(base::RSAPrivateKey::Create(256)); + + std::vector<uint8> public_key; + ASSERT_TRUE(key_pair->ExportPublicKey(&public_key)); + + scoped_ptr<base::RSAPrivateKey> key_pair_2( + base::RSAPrivateKey::FindFromPublicKeyInfo(public_key)); + + EXPECT_EQ(key_pair->key_->pkcs11ID, key_pair_2->key_->pkcs11ID); +} + +TEST_F(RSAPrivateKeyNSSTest, FailedFindFromPublicKey) { + // Create a keypair, which will put the keys in the user's NSSDB. + scoped_ptr<base::RSAPrivateKey> key_pair(base::RSAPrivateKey::Create(256)); + + std::vector<uint8> public_key; + ASSERT_TRUE(key_pair->ExportPublicKey(&public_key)); + + // Remove the keys from the DB, and make sure we can't find them again. + if (key_pair->key_) { + PK11_DestroyTokenObject(key_pair->key_->pkcs11Slot, + key_pair->key_->pkcs11ID); + } + if (key_pair->public_key_) { + PK11_DestroyTokenObject(key_pair->public_key_->pkcs11Slot, + key_pair->public_key_->pkcs11ID); + } + + EXPECT_EQ(NULL, base::RSAPrivateKey::FindFromPublicKeyInfo(public_key)); +} + +} // namespace base diff --git a/base/crypto/rsa_private_key_win.cc b/base/crypto/rsa_private_key_win.cc index b02ef3c..5dd8cca 100644 --- a/base/crypto/rsa_private_key_win.cc +++ b/base/crypto/rsa_private_key_win.cc @@ -39,6 +39,12 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { } // static +RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) { + NOTIMPLEMENTED(); + return NULL; +} + +// static RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( const std::vector<uint8>& input) { scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); @@ -103,6 +109,20 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( return result.release(); } +// static +RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( + const std::vector<uint8>& input) { + NOTIMPLEMENTED(); + return NULL; +} + +// static +RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( + const std::vector<uint8>& input) { + NOTIMPLEMENTED(); + return NULL; +} + RSAPrivateKey::RSAPrivateKey() : provider_(NULL), key_(NULL) {} RSAPrivateKey::~RSAPrivateKey() {} |