summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcmasone@google.com <cmasone@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-10 19:37:51 +0000
committercmasone@google.com <cmasone@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-10 19:37:51 +0000
commit746480537e2c6043d8f5d5dac624aee812a39991 (patch)
tree9cfc16140c0ff8a8053bbbbd772c384e9a683c0b
parent76951557d48f011a54c4f30852a69da172af194e (diff)
downloadchromium_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.gyp2
-rw-r--r--base/crypto/rsa_private_key.h50
-rw-r--r--base/crypto/rsa_private_key_mac.cc20
-rw-r--r--base/crypto/rsa_private_key_nss.cc114
-rw-r--r--base/crypto/rsa_private_key_nss_unittest.cc64
-rw-r--r--base/crypto/rsa_private_key_win.cc20
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, &param,
- &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() {}