summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorspang <spang@chromium.org>2015-05-01 14:01:57 -0700
committerCommit bot <commit-bot@chromium.org>2015-05-01 21:02:38 +0000
commit9ce3458d9a03b38ca717291d08d564e12fd8254a (patch)
treeb0f4570294cfb11e72f16cf0e424f40313ff2fdb /crypto
parentc10dfc7c662c078a7310e6c7d6041763150ce494 (diff)
downloadchromium_src-9ce3458d9a03b38ca717291d08d564e12fd8254a.zip
chromium_src-9ce3458d9a03b38ca717291d08d564e12fd8254a.tar.gz
chromium_src-9ce3458d9a03b38ca717291d08d564e12fd8254a.tar.bz2
Revert of Don't use RSAPrivateKey in NSS integration code. (patchset #6 id:100001 of https://codereview.chromium.org/1106103003/)
Reason for revert: Causes SEGV during login on Chrome OS BUG=483606 Original issue's description: > Don't use RSAPrivateKey in NSS integration code. > > Currently some NSS platform integration logic transits private keys through > RSAPrivateKey on CrOS. This prevents incrementally switching RSAPrivateKey to > BoringSSL while keeping platform integrations on NSS. > > The intent of this change is to clarify RSAPrivateKey as a BoringSSL vs NSS > internal crypto library (use_openssl=0 vs use_openssl=1) abstraction. It's > primarily to be used with SignatureCreator. Code which uses NSS based on > use_nss_certs rather than use_openssl because the underlying platform is NSS > should call NSS routines directly, or introduce different abstractions. > > Remove the problematic RSAPrivateKey methods and instead add > crypto/nss_key_util.h which contains some helper functions for manipulating NSS > keys. This is sufficient to allow consumers of the removed methods to use NSS > directly with about as much code. (This should not set back migrating that > logic to NSS as that code was already very NSS-specific; those APIs assumed > PK11SlotInfo.) > > nss_key_util.h, like nss_util.h, is built whenever NSS is used either > internally or for platform integrations. This is so rsa_private_key_nss.cc can > continue to use the helper functions to implement the NSS-agnostic interface. > > With this, the chimera CrOS configuration should build. The RSAPrivateKey logic > is functional with the exception of some logic in components/ownership. That > will be resolved in a future CL. > > BUG=478777 > > Committed: https://crrev.com/a46a990b2ccae2b66e87b5f76d2866044dc3182e > Cr-Commit-Position: refs/heads/master@{#327909} TBR=rsleevi@chromium.org,pneubeck@chromium.org,dpolukhin@chromium.org,caitkp@chromium.org,davidben@chromium.org NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=483606 Review URL: https://codereview.chromium.org/1118263003 Cr-Commit-Position: refs/heads/master@{#327978}
Diffstat (limited to 'crypto')
-rw-r--r--crypto/BUILD.gn23
-rw-r--r--crypto/crypto.gyp16
-rw-r--r--crypto/crypto.gypi2
-rw-r--r--crypto/nss_key_util.cc161
-rw-r--r--crypto/nss_key_util.h58
-rw-r--r--crypto/nss_key_util_unittest.cc87
-rw-r--r--crypto/rsa_private_key.h69
-rw-r--r--crypto/rsa_private_key_nss.cc233
-rw-r--r--crypto/rsa_private_key_nss_unittest.cc66
9 files changed, 358 insertions, 357 deletions
diff --git a/crypto/BUILD.gn b/crypto/BUILD.gn
index f84c4d4..c1eabe6 100644
--- a/crypto/BUILD.gn
+++ b/crypto/BUILD.gn
@@ -50,8 +50,6 @@ component("crypto") {
"mock_apple_keychain.h",
"mock_apple_keychain_ios.cc",
"mock_apple_keychain_mac.cc",
- "nss_key_util.cc",
- "nss_key_util.h",
"nss_util.cc",
"nss_util.h",
"nss_util_internal.h",
@@ -173,12 +171,10 @@ component("crypto") {
]
}
- # Some files are built when NSS is used at all, either for the internal crypto
- # library or the platform certificate library.
+ # Remove nss_util when NSS is used for neither the internal crypto library
+ # nor the platform certificate library.
if (use_openssl && !use_nss_certs) {
sources -= [
- "nss_key_util.cc",
- "nss_key_util.h",
"nss_util.cc",
"nss_util.h",
"nss_util_internal.h",
@@ -230,12 +226,12 @@ test("crypto_unittests") {
"ghash_unittest.cc",
"hkdf_unittest.cc",
"hmac_unittest.cc",
- "nss_key_util_unittest.cc",
"nss_util_unittest.cc",
"openssl_bio_string_unittest.cc",
"p224_spake_unittest.cc",
"p224_unittest.cc",
"random_unittest.cc",
+ "rsa_private_key_nss_unittest.cc",
"rsa_private_key_unittest.cc",
"secure_hash_unittest.cc",
"sha2_unittest.cc",
@@ -244,16 +240,15 @@ test("crypto_unittests") {
"symmetric_key_unittest.cc",
]
- # Some files are built when NSS is used at all, either for the internal crypto
- # library or the platform certificate library.
+ # Remove nss_util when NSS is used for neither the internal crypto library
+ # nor the platform certificate library.
if (use_openssl && !use_nss_certs) {
- sources -= [
- "nss_key_util_unittest.cc",
- "nss_util_unittest.cc",
- ]
+ sources -= [ "nss_util_unittest.cc" ]
}
- if (!use_openssl) {
+ if (use_openssl) {
+ sources -= [ "rsa_private_key_nss_unittest.cc" ]
+ } else {
sources -= [ "openssl_bio_string_unittest.cc" ]
}
diff --git a/crypto/crypto.gyp b/crypto/crypto.gyp
index e6bff0b..00b59b5 100644
--- a/crypto/crypto.gyp
+++ b/crypto/crypto.gyp
@@ -143,11 +143,9 @@
],
},],
[ 'use_openssl==1 and use_nss_certs==0', {
- # Some files are built when NSS is used at all, either for the
- # internal crypto library or the platform certificate library.
+ # NSS is used for neither the internal crypto library nor the
+ # platform certificate library.
'sources!': [
- 'nss_key_util.cc',
- 'nss_key_util.h',
'nss_util.cc',
'nss_util.h',
'nss_util_internal.h',
@@ -170,13 +168,13 @@
'ghash_unittest.cc',
'hkdf_unittest.cc',
'hmac_unittest.cc',
- 'nss_key_util_unittest.cc',
'nss_util_unittest.cc',
'openssl_bio_string_unittest.cc',
'p224_unittest.cc',
'p224_spake_unittest.cc',
'random_unittest.cc',
'rsa_private_key_unittest.cc',
+ 'rsa_private_key_nss_unittest.cc',
'secure_hash_unittest.cc',
'sha2_unittest.cc',
'signature_creator_unittest.cc',
@@ -207,10 +205,9 @@
],
}],
[ 'use_openssl == 1 and use_nss_certs == 0', {
- # Some files are built when NSS is used at all, either for the
- # internal crypto library or the platform certificate library.
+ # nss_util is built if NSS is used for either the internal crypto
+ # library or the platform certificate library.
'sources!': [
- 'nss_key_util_unittest.cc',
'nss_util_unittest.cc',
],
}],
@@ -227,6 +224,9 @@
'dependencies': [
'../third_party/boringssl/boringssl.gyp:boringssl',
],
+ 'sources!': [
+ 'rsa_private_key_nss_unittest.cc',
+ ],
}, {
'sources!': [
'openssl_bio_string_unittest.cc',
diff --git a/crypto/crypto.gypi b/crypto/crypto.gypi
index 73b3332..4456b10 100644
--- a/crypto/crypto.gypi
+++ b/crypto/crypto.gypi
@@ -67,8 +67,6 @@
'p224_spake.cc',
'p224_spake.h',
'nss_crypto_module_delegate.h',
- 'nss_key_util.cc',
- 'nss_key_util.h',
'nss_util.cc',
'nss_util.h',
'nss_util_internal.h',
diff --git a/crypto/nss_key_util.cc b/crypto/nss_key_util.cc
deleted file mode 100644
index 260d3b6..0000000
--- a/crypto/nss_key_util.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright 2015 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 "crypto/nss_key_util.h"
-
-#include <cryptohi.h>
-#include <keyhi.h>
-#include <pk11pub.h>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "crypto/nss_util.h"
-
-#if defined(USE_NSS_CERTS)
-#include <secmod.h>
-#include "crypto/nss_util_internal.h"
-#endif
-
-namespace crypto {
-
-namespace {
-
-#if defined(USE_NSS_CERTS)
-
-struct PublicKeyInfoDeleter {
- inline void operator()(CERTSubjectPublicKeyInfo* spki) {
- SECKEY_DestroySubjectPublicKeyInfo(spki);
- }
-};
-
-typedef scoped_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter>
- ScopedPublicKeyInfo;
-
-// Decodes |input| as a SubjectPublicKeyInfo and returns a SECItem containing
-// the CKA_ID of that public key or nullptr on error.
-ScopedSECItem MakeIDFromSPKI(const std::vector<uint8_t> input) {
- // First, decode and save the public key.
- SECItem key_der;
- key_der.type = siBuffer;
- key_der.data = const_cast<unsigned char*>(vector_as_array(&input));
- key_der.len = input.size();
-
- ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der));
- if (!spki)
- return nullptr;
-
- ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get()));
- if (!result)
- return nullptr;
-
- // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA keys are
- // supported.
- if (SECKEY_GetPublicKeyType(result.get()) != rsaKey)
- return nullptr;
-
- return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus));
-}
-
-#endif // defined(USE_NSS_CERTS)
-
-} // namespace
-
-bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot,
- uint16_t num_bits,
- bool permanent,
- ScopedSECKEYPublicKey* public_key,
- ScopedSECKEYPrivateKey* private_key) {
- PK11RSAGenParams param;
- param.keySizeInBits = num_bits;
- param.pe = 65537L;
- SECKEYPublicKey* public_key_raw = nullptr;
- private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
- &param, &public_key_raw, permanent,
- permanent /* sensitive */, nullptr));
- if (!*private_key)
- return false;
-
- public_key->reset(public_key_raw);
- return true;
-}
-
-ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo(
- PK11SlotInfo* slot,
- const std::vector<uint8_t>& input,
- bool permanent) {
- DCHECK(slot);
-
- ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
- DCHECK(arena);
-
- // Excess data is illegal, but NSS silently accepts it, so first ensure that
- // |input| consists of a single ASN.1 element.
- SECItem input_item;
- input_item.data = const_cast<unsigned char*>(vector_as_array(&input));
- input_item.len = input.size();
- SECItem der_private_key_info;
- SECStatus rv =
- SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info,
- SEC_ASN1_GET(SEC_AnyTemplate), &input_item);
- if (rv != SECSuccess)
- return nullptr;
-
- // Allow the private key to be used for key unwrapping, data decryption,
- // and signature generation.
- const unsigned int key_usage =
- KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE;
- SECKEYPrivateKey* key_raw = nullptr;
- rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
- slot, &der_private_key_info, nullptr, nullptr, permanent,
- permanent /* sensitive */, key_usage, &key_raw, nullptr);
- if (rv != SECSuccess)
- return nullptr;
- return ScopedSECKEYPrivateKey(key_raw);
-}
-
-#if defined(USE_NSS_CERTS)
-
-ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo(
- const std::vector<uint8_t>& input) {
- EnsureNSSInit();
-
- ScopedSECItem cka_id(MakeIDFromSPKI(input));
- if (!cka_id)
- return nullptr;
-
- // Search all slots in all modules for the key with the given ID.
- AutoSECMODListReadLock auto_lock;
- const SECMODModuleList* head = SECMOD_GetDefaultModuleList();
- for (const SECMODModuleList* item = head; item != nullptr;
- item = item->next) {
- int slot_count = item->module->loaded ? item->module->slotCount : 0;
- for (int i = 0; i < slot_count; i++) {
- // Look for the key in slot |i|.
- ScopedSECKEYPrivateKey key(
- PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr));
- if (key)
- return key.Pass();
- }
- }
-
- // The key wasn't found in any module.
- return nullptr;
-}
-
-ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot(
- const std::vector<uint8_t>& input,
- PK11SlotInfo* slot) {
- DCHECK(slot);
-
- ScopedSECItem cka_id(MakeIDFromSPKI(input));
- if (!cka_id)
- return nullptr;
-
- return ScopedSECKEYPrivateKey(
- PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr));
-}
-
-#endif // defined(USE_NSS_CERTS)
-
-} // namespace crypto
diff --git a/crypto/nss_key_util.h b/crypto/nss_key_util.h
deleted file mode 100644
index 12b948d..0000000
--- a/crypto/nss_key_util.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2015 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 CRYPTO_NSS_KEY_UTIL_H_
-#define CRYPTO_NSS_KEY_UTIL_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "build/build_config.h"
-#include "crypto/crypto_export.h"
-#include "crypto/scoped_nss_types.h"
-
-typedef struct PK11SlotInfoStr PK11SlotInfo;
-
-namespace crypto {
-
-// Generates a new RSA keypair of size |num_bits| in |slot|. Returns true on
-// success and false on failure. If |permanent| is true, the resulting key is
-// permanent and is not exportable in plaintext form.
-CRYPTO_EXPORT bool GenerateRSAKeyPairNSS(
- PK11SlotInfo* slot,
- uint16_t num_bits,
- bool permanent,
- ScopedSECKEYPublicKey* out_public_key,
- ScopedSECKEYPrivateKey* out_private_key);
-
-// Imports a private key from |input| into |slot|. |input| is interpreted as a
-// DER-encoded PrivateKeyInfo block from PKCS #8. Returns nullptr on error. If
-// |permanent| is true, the resulting key is permanent and is not exportable in
-// plaintext form.
-CRYPTO_EXPORT ScopedSECKEYPrivateKey
-ImportNSSKeyFromPrivateKeyInfo(PK11SlotInfo* slot,
- const std::vector<uint8_t>& input,
- bool permanent);
-
-#if defined(USE_NSS_CERTS)
-
-// Decodes |input| as a DER-encoded X.509 SubjectPublicKeyInfo and searches for
-// the private key half in the key database. Returns the private key on success
-// or nullptr on error.
-CRYPTO_EXPORT ScopedSECKEYPrivateKey
-FindNSSKeyFromPublicKeyInfo(const std::vector<uint8_t>& input);
-
-// Decodes |input| as a DER-encoded X.509 SubjectPublicKeyInfo and searches for
-// the private key half in the slot specified by |slot|. Returns the private key
-// on success or nullptr on error.
-CRYPTO_EXPORT ScopedSECKEYPrivateKey
-FindNSSKeyFromPublicKeyInfoInSlot(const std::vector<uint8_t>& input,
- PK11SlotInfo* slot);
-
-#endif // defined(USE_NSS_CERTS)
-
-} // namespace crypto
-
-#endif // CRYPTO_NSS_KEY_UTIL_H_
diff --git a/crypto/nss_key_util_unittest.cc b/crypto/nss_key_util_unittest.cc
deleted file mode 100644
index f8de8e2..0000000
--- a/crypto/nss_key_util_unittest.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2015 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 "crypto/nss_key_util.h"
-
-#include <keyhi.h>
-#include <pk11pub.h>
-
-#include <vector>
-
-#include "crypto/nss_util.h"
-#include "crypto/scoped_nss_types.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace crypto {
-
-class NSSKeyUtilTest : public testing::Test {
- public:
- void SetUp() override {
- EnsureNSSInit();
-
- internal_slot_.reset(PK11_GetInternalSlot());
- ASSERT_TRUE(internal_slot_);
- }
-
- PK11SlotInfo* internal_slot() { return internal_slot_.get(); }
-
- private:
- ScopedPK11Slot internal_slot_;
-};
-
-TEST_F(NSSKeyUtilTest, GenerateRSAKeyPairNSS) {
- const int kKeySizeBits = 1024;
-
- ScopedSECKEYPublicKey public_key;
- ScopedSECKEYPrivateKey private_key;
- ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), kKeySizeBits,
- false /* not permanent */, &public_key,
- &private_key));
-
- EXPECT_EQ(rsaKey, SECKEY_GetPublicKeyType(public_key.get()));
- EXPECT_EQ(rsaKey, SECKEY_GetPrivateKeyType(private_key.get()));
- EXPECT_EQ((kKeySizeBits + 7) / 8,
- PK11_GetPrivateModulusLen(private_key.get()));
-}
-
-#if defined(USE_NSS_CERTS)
-TEST_F(NSSKeyUtilTest, FindNSSKeyFromPublicKeyInfo) {
- // Create an NSS keypair, which will put the keys in the user's NSSDB.
- ScopedSECKEYPublicKey public_key;
- ScopedSECKEYPrivateKey private_key;
- ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 256,
- false /* not permanent */, &public_key,
- &private_key));
-
- ScopedSECItem item(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key.get()));
- ASSERT_TRUE(item);
- std::vector<uint8_t> public_key_der(item->data, item->data + item->len);
-
- ScopedSECKEYPrivateKey private_key2 =
- FindNSSKeyFromPublicKeyInfo(public_key_der);
- ASSERT_TRUE(private_key2);
- EXPECT_EQ(private_key->pkcs11ID, private_key2->pkcs11ID);
-}
-
-TEST_F(NSSKeyUtilTest, FailedFindNSSKeyFromPublicKeyInfo) {
- // Create an NSS keypair, which will put the keys in the user's NSSDB.
- ScopedSECKEYPublicKey public_key;
- ScopedSECKEYPrivateKey private_key;
- ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 256,
- false /* not permanent */, &public_key,
- &private_key));
-
- ScopedSECItem item(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key.get()));
- ASSERT_TRUE(item);
- std::vector<uint8_t> public_key_der(item->data, item->data + item->len);
-
- // Remove the keys from the DB, and make sure we can't find them again.
- PK11_DestroyTokenObject(private_key->pkcs11Slot, private_key->pkcs11ID);
- PK11_DestroyTokenObject(public_key->pkcs11Slot, public_key->pkcs11ID);
-
- EXPECT_FALSE(FindNSSKeyFromPublicKeyInfo(public_key_der));
-}
-#endif // defined(USE_NSS_CERTS)
-
-} // namespace crypto
diff --git a/crypto/rsa_private_key.h b/crypto/rsa_private_key.h
index 637be38..9ab9c57 100644
--- a/crypto/rsa_private_key.h
+++ b/crypto/rsa_private_key.h
@@ -191,6 +191,44 @@ class CRYPTO_EXPORT RSAPrivateKey {
static RSAPrivateKey* CreateFromKey(SECKEYPrivateKey* key);
#endif
+ // TODO(davidben): These functions are used when NSS is the platform key
+ // store, but they also assume that the internal crypto library is NSS. Split
+ // out the convenience NSS platform key methods from the logic which expects
+ // an RSAPrivateKey. See https://crbug.com/478777.
+#if defined(USE_NSS_CERTS) && !defined(USE_OPENSSL)
+ // Create a new random instance in |slot|. Can return NULL if initialization
+ // fails. The created key is permanent and is not exportable in plaintext
+ // form.
+ static RSAPrivateKey* CreateSensitive(PK11SlotInfo* slot, uint16 num_bits);
+
+ // Create a new instance in |slot| 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.
+ static RSAPrivateKey* CreateSensitiveFromPrivateKeyInfo(
+ PK11SlotInfo* slot,
+ 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.
+ static RSAPrivateKey* FindFromPublicKeyInfo(
+ const std::vector<uint8>& input);
+
+ // Import an existing public key, and then search for the private
+ // half in the slot specified by |slot|. 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 slot.
+ static RSAPrivateKey* FindFromPublicKeyInfoInSlot(
+ const std::vector<uint8>& input,
+ PK11SlotInfo* slot);
+#endif // USE_NSS_CERTS && !USE_OPENSSL
+
#if defined(USE_OPENSSL)
EVP_PKEY* key() { return key_; }
#else
@@ -213,9 +251,38 @@ class CRYPTO_EXPORT RSAPrivateKey {
FRIEND_TEST_ALL_PREFIXES(RSAPrivateKeyNSSTest, FailedFindFromPublicKey);
#endif
- // Constructor is private. Use one of the Create*() methods above instead.
+ // Constructor is private. Use one of the Create*() or Find*()
+ // methods above instead.
RSAPrivateKey();
+#if !defined(USE_OPENSSL)
+ // Shared helper for Create() and CreateSensitive().
+ // TODO(cmasone): consider replacing |permanent| and |sensitive| with a
+ // flags arg created by ORing together some enumerated values.
+ // Note: |permanent| is only supported when USE_NSS_CERTS is defined.
+ static RSAPrivateKey* CreateWithParams(PK11SlotInfo* slot,
+ uint16 num_bits,
+ bool permanent,
+ bool sensitive);
+
+ // Shared helper for CreateFromPrivateKeyInfo() and
+ // CreateSensitiveFromPrivateKeyInfo().
+ // Note: |permanent| is only supported when USE_NSS_CERTS is defined.
+ static RSAPrivateKey* CreateFromPrivateKeyInfoWithParams(
+ PK11SlotInfo* slot,
+ const std::vector<uint8>& input,
+ bool permanent,
+ bool sensitive);
+#endif
+
+#if defined(USE_NSS_CERTS)
+ // Import an existing public key. The format of the public key blob
+ // is an X509 SubjectPublicKeyInfo block. This can return NULL if
+ // initialization fails. The caller takes ownership of the returned
+ // object. Note that this method doesn't initialize the |key_| member.
+ static RSAPrivateKey* InitPublicPart(const std::vector<uint8>& input);
+#endif
+
#if defined(USE_OPENSSL)
EVP_PKEY* key_;
#else
diff --git a/crypto/rsa_private_key_nss.cc b/crypto/rsa_private_key_nss.cc
index 88e55fa..c9e6a87 100644
--- a/crypto/rsa_private_key_nss.cc
+++ b/crypto/rsa_private_key_nss.cc
@@ -7,6 +7,7 @@
#include <cryptohi.h>
#include <keyhi.h>
#include <pk11pub.h>
+#include <secmod.h>
#include <list>
@@ -14,8 +15,8 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
-#include "crypto/nss_key_util.h"
#include "crypto/nss_util.h"
+#include "crypto/nss_util_internal.h"
#include "crypto/scoped_nss_types.h"
// TODO(rafaelw): Consider using NSS's ASN.1 encoder.
@@ -37,6 +38,37 @@ static bool ReadAttribute(SECKEYPrivateKey* key,
return true;
}
+#if defined(USE_NSS_CERTS)
+struct PublicKeyInfoDeleter {
+ inline void operator()(CERTSubjectPublicKeyInfo* spki) {
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ }
+};
+
+typedef scoped_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter>
+ ScopedPublicKeyInfo;
+
+// The function decodes RSA public key from the |input|.
+crypto::ScopedSECKEYPublicKey GetRSAPublicKey(const std::vector<uint8>& input) {
+ // 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();
+
+ ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der));
+ if (!spki)
+ return crypto::ScopedSECKEYPublicKey();
+
+ crypto::ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get()));
+
+ // Make sure the key is an RSA key.. If not, that's an error.
+ if (!result || result->keyType != rsaKey)
+ return crypto::ScopedSECKEYPublicKey();
+ return result.Pass();
+}
+#endif // defined(USE_NSS_CERTS)
+
} // namespace
namespace crypto {
@@ -53,22 +85,10 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
EnsureNSSInit();
ScopedPK11Slot slot(PK11_GetInternalSlot());
- if (!slot) {
- NOTREACHED();
- return nullptr;
- }
-
- ScopedSECKEYPublicKey public_key;
- ScopedSECKEYPrivateKey private_key;
- if (!GenerateRSAKeyPairNSS(slot.get(), num_bits, false /* not permanent */,
- &public_key, &private_key)) {
- return nullptr;
- }
-
- RSAPrivateKey* rsa_key = new RSAPrivateKey;
- rsa_key->public_key_ = public_key.release();
- rsa_key->key_ = private_key.release();
- return rsa_key;
+ return CreateWithParams(slot.get(),
+ num_bits,
+ false /* not permanent */,
+ false /* not sensitive */);
}
// static
@@ -77,15 +97,11 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
EnsureNSSInit();
ScopedPK11Slot slot(PK11_GetInternalSlot());
- if (!slot) {
- NOTREACHED();
- return nullptr;
- }
- ScopedSECKEYPrivateKey key(ImportNSSKeyFromPrivateKeyInfo(
- slot.get(), input, false /* not permanent */));
- if (!key || SECKEY_GetPrivateKeyType(key.get()) != rsaKey)
- return nullptr;
- return RSAPrivateKey::CreateFromKey(key.get());
+ return CreateFromPrivateKeyInfoWithParams(
+ slot.get(),
+ input,
+ false /* not permanent */,
+ false /* not sensitive */);
}
// static
@@ -104,6 +120,83 @@ RSAPrivateKey* RSAPrivateKey::CreateFromKey(SECKEYPrivateKey* key) {
return copy;
}
+#if defined(USE_NSS_CERTS)
+// static
+RSAPrivateKey* RSAPrivateKey::CreateSensitive(PK11SlotInfo* slot,
+ uint16 num_bits) {
+ return CreateWithParams(slot,
+ num_bits,
+ true /* permanent */,
+ true /* sensitive */);
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
+ PK11SlotInfo* slot,
+ const std::vector<uint8>& input) {
+ return CreateFromPrivateKeyInfoWithParams(slot,
+ input,
+ true /* permanent */,
+ true /* sensitive */);
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
+ const std::vector<uint8>& input) {
+ scoped_ptr<RSAPrivateKey> result(InitPublicPart(input));
+ if (!result)
+ return NULL;
+
+ ScopedSECItem ck_id(
+ PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus)));
+ if (!ck_id.get()) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ // Search all slots in all modules for the key with the given ID.
+ AutoSECMODListReadLock auto_lock;
+ SECMODModuleList* head = SECMOD_GetDefaultModuleList();
+ for (SECMODModuleList* item = head; item != NULL; item = item->next) {
+ int slot_count = item->module->loaded ? item->module->slotCount : 0;
+ for (int i = 0; i < slot_count; i++) {
+ // Finally...Look for the key!
+ result->key_ = PK11_FindKeyByKeyID(item->module->slots[i],
+ ck_id.get(), NULL);
+ if (result->key_)
+ return result.release();
+ }
+ }
+
+ // We didn't find the key.
+ return NULL;
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfoInSlot(
+ const std::vector<uint8>& input,
+ PK11SlotInfo* slot) {
+ if (!slot)
+ return NULL;
+
+ scoped_ptr<RSAPrivateKey> result(InitPublicPart(input));
+ if (!result)
+ return NULL;
+
+ ScopedSECItem ck_id(
+ PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus)));
+ if (!ck_id.get()) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ result->key_ = PK11_FindKeyByKeyID(slot, ck_id.get(), NULL);
+ if (!result->key_)
+ return NULL;
+ return result.release();
+}
+#endif
+
RSAPrivateKey* RSAPrivateKey::Copy() const {
RSAPrivateKey* copy = new RSAPrivateKey();
copy->key_ = SECKEY_CopyPrivateKey(key_);
@@ -148,4 +241,92 @@ RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
EnsureNSSInit();
}
+// static
+RSAPrivateKey* RSAPrivateKey::CreateWithParams(PK11SlotInfo* slot,
+ uint16 num_bits,
+ bool permanent,
+ bool sensitive) {
+ if (!slot)
+ return NULL;
+
+ scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
+
+ PK11RSAGenParams param;
+ param.keySizeInBits = num_bits;
+ param.pe = 65537L;
+ result->key_ = PK11_GenerateKeyPair(slot,
+ CKM_RSA_PKCS_KEY_PAIR_GEN,
+ &param,
+ &result->public_key_,
+ permanent,
+ sensitive,
+ NULL);
+ if (!result->key_)
+ return NULL;
+
+ return result.release();
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
+ PK11SlotInfo* slot,
+ const std::vector<uint8>& input,
+ bool permanent,
+ bool sensitive) {
+ if (!slot)
+ return NULL;
+
+ scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
+
+ ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+ if (!arena) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ // Excess data is illegal, but NSS silently accepts it, so first ensure that
+ // |input| consists of a single ASN.1 element.
+ SECItem input_item;
+ input_item.data = const_cast<unsigned char*>(&input.front());
+ input_item.len = input.size();
+ SECItem der_private_key_info;
+ SECStatus rv = SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info,
+ SEC_ASN1_GET(SEC_AnyTemplate),
+ &input_item);
+ if (rv != SECSuccess)
+ return NULL;
+
+ // Allow the private key to be used for key unwrapping, data decryption,
+ // and signature generation.
+ const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
+ KU_DIGITAL_SIGNATURE;
+ rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+ slot, &der_private_key_info, NULL, NULL, permanent, sensitive,
+ key_usage, &result->key_, NULL);
+ if (rv != SECSuccess)
+ return NULL;
+
+ result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
+ if (!result->public_key_)
+ return NULL;
+
+ return result.release();
+}
+
+#if defined(USE_NSS_CERTS)
+// static
+RSAPrivateKey* RSAPrivateKey::InitPublicPart(const std::vector<uint8>& input) {
+ EnsureNSSInit();
+
+ scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey());
+ result->public_key_ = GetRSAPublicKey(input).release();
+ if (!result->public_key_) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ return result.release();
+}
+#endif // defined(USE_NSS_CERTS)
+
} // namespace crypto
diff --git a/crypto/rsa_private_key_nss_unittest.cc b/crypto/rsa_private_key_nss_unittest.cc
new file mode 100644
index 0000000..dad6688
--- /dev/null
+++ b/crypto/rsa_private_key_nss_unittest.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2011 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 "crypto/rsa_private_key.h"
+
+#include <keyhi.h>
+#include <pk11pub.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "crypto/scoped_test_nss_db.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace crypto {
+
+// TODO(davidben): These tests assume NSS is used for both the internal crypto
+// library and the platform key store. See https://crbug.com/478777.
+#if defined(USE_NSS_CERTS)
+
+class RSAPrivateKeyNSSTest : public testing::Test {
+ public:
+ RSAPrivateKeyNSSTest() {}
+ ~RSAPrivateKeyNSSTest() override {}
+
+ private:
+ ScopedTestNSSDB test_nssdb_;
+
+ DISALLOW_COPY_AND_ASSIGN(RSAPrivateKeyNSSTest);
+};
+
+TEST_F(RSAPrivateKeyNSSTest, FindFromPublicKey) {
+ // Create a keypair, which will put the keys in the user's NSSDB.
+ scoped_ptr<crypto::RSAPrivateKey> key_pair(RSAPrivateKey::Create(256));
+
+ std::vector<uint8> public_key;
+ ASSERT_TRUE(key_pair->ExportPublicKey(&public_key));
+
+ scoped_ptr<crypto::RSAPrivateKey> key_pair_2(
+ crypto::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<crypto::RSAPrivateKey> key_pair(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, crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key));
+}
+
+#endif // USE_NSS_CERTS
+
+} // namespace crypto