diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-09 05:08:51 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-09 05:08:51 +0000 |
commit | eaa60485f027b00047a2e142d9616ede4333a46b (patch) | |
tree | eb20edb20255f8f76d76f3ff4f1399a04a6d9398 /crypto | |
parent | e80f64a0f8ed441443bec21eeb5c732398d11377 (diff) | |
download | chromium_src-eaa60485f027b00047a2e142d9616ede4333a46b.zip chromium_src-eaa60485f027b00047a2e142d9616ede4333a46b.tar.gz chromium_src-eaa60485f027b00047a2e142d9616ede4333a46b.tar.bz2 |
Add ECPrivateKey for Elliptic Curve keypair generation.
The implementation uses NSS on all platforms unless USE_OPENSSL is defined
(which is only stubbed out in this CL).
BUG=88782
TEST=ECPrivateKeyUnitTest
Review URL: http://codereview.chromium.org/8413024
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@109188 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/crypto.gyp | 11 | ||||
-rw-r--r-- | crypto/ec_private_key.h | 124 | ||||
-rw-r--r-- | crypto/ec_private_key_nss.cc | 300 | ||||
-rw-r--r-- | crypto/ec_private_key_openssl.cc | 66 | ||||
-rw-r--r-- | crypto/ec_private_key_unittest.cc | 107 | ||||
-rw-r--r-- | crypto/scoped_nss_types.h | 5 | ||||
-rw-r--r-- | crypto/third_party/nss/chromium-nss.h | 62 | ||||
-rw-r--r-- | crypto/third_party/nss/pk11akey.cc | 98 |
8 files changed, 773 insertions, 0 deletions
diff --git a/crypto/crypto.gyp b/crypto/crypto.gyp index 906cbed..3f1b4ba 100644 --- a/crypto/crypto.gyp +++ b/crypto/crypto.gyp @@ -38,6 +38,7 @@ }, { # os_posix != 1 or OS == "mac" 'sources/': [ ['exclude', '_nss\.cc$'], + ['include', 'ec_private_key_nss\.cc$'], ], 'sources!': [ 'openpgp_symmetric_encryption.cc', @@ -81,6 +82,7 @@ # TODO(joth): Use a glob to match exclude patterns once the # OpenSSL file set is complete. 'sources!': [ + 'ec_private_key_nss.cc', 'encryptor_nss.cc', 'hmac_nss.cc', 'nss_util.cc', @@ -93,11 +95,14 @@ 'symmetric_key_nss.cc', 'third_party/nss/blapi.h', 'third_party/nss/blapit.h', + 'third_party/nss/chromium-nss.h', + 'third_party/nss/pk11akey.cc', 'third_party/nss/sha256.h', 'third_party/nss/sha512.cc', ], }, { 'sources!': [ + 'ec_private_key_openssl.cc', 'encryptor_openssl.cc', 'hmac_openssl.cc', 'openssl_util.cc', @@ -117,6 +122,9 @@ 'crypto_module_blocking_password_delegate.h', 'cssm_init.cc', 'cssm_init.h', + 'ec_private_key.h', + 'ec_private_key_nss.cc', + 'ec_private_key_openssl.cc', 'encryptor.cc', 'encryptor.h', 'encryptor_mac.cc', @@ -172,6 +180,8 @@ 'symmetric_key_win.cc', 'third_party/nss/blapi.h', 'third_party/nss/blapit.h', + 'third_party/nss/chromium-nss.h', + 'third_party/nss/pk11akey.cc', 'third_party/nss/sha256.h', 'third_party/nss/sha512.cc', ], @@ -184,6 +194,7 @@ 'run_all_unittests.cc', # Tests. + 'ec_private_key_unittest.cc', 'encryptor_unittest.cc', 'hmac_unittest.cc', 'p224_unittest.cc', diff --git a/crypto/ec_private_key.h b/crypto/ec_private_key.h new file mode 100644 index 0000000..0d287de --- /dev/null +++ b/crypto/ec_private_key.h @@ -0,0 +1,124 @@ +// 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. + +#ifndef CRYPTO_EC_PRIVATE_KEY_H_ +#define CRYPTO_EC_PRIVATE_KEY_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "build/build_config.h" +#include "crypto/crypto_export.h" + +#if defined(USE_OPENSSL) +// Forward declaration for openssl/*.h +typedef struct evp_pkey_st EVP_PKEY; +#else +// Forward declaration. +typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey; +typedef struct SECKEYPublicKeyStr SECKEYPublicKey; +#endif + +namespace crypto { + +// Encapsulates an elliptic curve (EC) private key. Can be used to generate new +// keys, export keys to other formats, or to extract a public key. +// TODO(mattm): make this and RSAPrivateKey implement some PrivateKey interface. +// (The difference in types of key() and public_key() make this a little +// tricky.) +class CRYPTO_EXPORT ECPrivateKey { + public: + ~ECPrivateKey(); + + // Creates a new random instance. Can return NULL if initialization fails. + // The created key will use the NIST P-256 curve. + // TODO(mattm): Add a curve parameter. + static ECPrivateKey* Create(); + + // Creates 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 ECPrivateKey* CreateSensitive(); + + // Creates a new instance by importing an existing key pair. + // The key pair is given as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo + // block and an X.509 SubjectPublicKeyInfo block. + // Returns NULL if initialization fails. + static ECPrivateKey* CreateFromEncryptedPrivateKeyInfo( + const std::string& password, + const std::vector<uint8>& encrypted_private_key_info, + const std::vector<uint8>& subject_public_key_info); + + // Creates a new instance by importing an existing key pair. + // The key pair is given as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo + // block and an X.509 SubjectPublicKeyInfo block. + // 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 ECPrivateKey* CreateSensitiveFromEncryptedPrivateKeyInfo( + const std::string& password, + const std::vector<uint8>& encrypted_private_key_info, + const std::vector<uint8>& subject_public_key_info); + +#if defined(USE_OPENSSL) + EVP_PKEY* key() { return key_; } +#else + SECKEYPrivateKey* key() { return key_; } + SECKEYPublicKey* public_key() { return public_key_; } +#endif + + // Exports the private key as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo + // block and the public key as an X.509 SubjectPublicKeyInfo block. + // The |password| and |iterations| are used as inputs to the key derivation + // function for generating the encryption key. PKCS #5 recommends a minimum + // of 1000 iterations, on modern systems a larger value may be preferrable. + bool ExportEncryptedPrivateKey(const std::string& password, + int iterations, + std::vector<uint8>* output); + + // Exports the public key to an X.509 SubjectPublicKeyInfo block. + bool ExportPublicKey(std::vector<uint8>* output); + + // Exports private key data for testing. The format of data stored into output + // doesn't matter other than that it is consistent for the same key. + bool ExportValue(std::vector<uint8>* output); + bool ExportECParams(std::vector<uint8>* output); + + private: + // Constructor is private. Use one of the Create*() methods above instead. + ECPrivateKey(); + + // 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 ECPrivateKey* CreateWithParams(bool permanent, + bool sensitive); + + // Shared helper for CreateFromEncryptedPrivateKeyInfo() and + // CreateSensitiveFromEncryptedPrivateKeyInfo(). + static ECPrivateKey* CreateFromEncryptedPrivateKeyInfoWithParams( + const std::string& password, + const std::vector<uint8>& encrypted_private_key_info, + const std::vector<uint8>& subject_public_key_info, + bool permanent, + bool sensitive); + +#if defined(USE_OPENSSL) + EVP_PKEY* key_; +#else + SECKEYPrivateKey* key_; + SECKEYPublicKey* public_key_; +#endif + + DISALLOW_COPY_AND_ASSIGN(ECPrivateKey); +}; + + +} // namespace crypto + +#endif // CRYPTO_EC_PRIVATE_KEY_H_ diff --git a/crypto/ec_private_key_nss.cc b/crypto/ec_private_key_nss.cc new file mode 100644 index 0000000..cc46101 --- /dev/null +++ b/crypto/ec_private_key_nss.cc @@ -0,0 +1,300 @@ +// 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/ec_private_key.h" + +extern "C" { +// Work around NSS missing SEC_BEGIN_PROTOS in secmodt.h. This must come before +// other NSS headers. +#include <secmodt.h> +} + +#include <cryptohi.h> +#include <keyhi.h> +#include <pk11pub.h> +#include <secmod.h> + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "crypto/nss_util.h" +#include "crypto/nss_util_internal.h" +#include "crypto/scoped_nss_types.h" +#include "crypto/third_party/nss/chromium-nss.h" + +namespace { + +// Copied from rsa_private_key_nss.cc. +static bool ReadAttribute(SECKEYPrivateKey* key, + CK_ATTRIBUTE_TYPE type, + std::vector<uint8>* output) { + SECItem item; + SECStatus rv; + rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item); + if (rv != SECSuccess) { + DLOG(ERROR) << "PK11_ReadRawAttribute: " << PORT_GetError(); + return false; + } + + output->assign(item.data, item.data + item.len); + SECITEM_FreeItem(&item, PR_FALSE); + return true; +} + +} // namespace + +namespace crypto { + +ECPrivateKey::~ECPrivateKey() { + if (key_) + SECKEY_DestroyPrivateKey(key_); + if (public_key_) + SECKEY_DestroyPublicKey(public_key_); +} + +// static +ECPrivateKey* ECPrivateKey::Create() { + return CreateWithParams(PR_FALSE /* not permanent */, + PR_FALSE /* not sensitive */); +} + +// static +ECPrivateKey* ECPrivateKey::CreateSensitive() { +#if defined(USE_NSS) + return CreateWithParams(PR_TRUE /* permanent */, + PR_TRUE /* sensitive */); +#else + // If USE_NSS is not defined, we initialize NSS with no databases, so we can't + // create permanent keys. + NOTREACHED(); + return NULL; +#endif +} + +// static +ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + const std::string& password, + const std::vector<uint8>& encrypted_private_key_info, + const std::vector<uint8>& subject_public_key_info) { + return CreateFromEncryptedPrivateKeyInfoWithParams( + password, + encrypted_private_key_info, + subject_public_key_info, + PR_FALSE /* not permanent */, + PR_FALSE /* not sensitive */); +} + +// static +ECPrivateKey* ECPrivateKey::CreateSensitiveFromEncryptedPrivateKeyInfo( + const std::string& password, + const std::vector<uint8>& encrypted_private_key_info, + const std::vector<uint8>& subject_public_key_info) { +#if defined(USE_NSS) + return CreateFromEncryptedPrivateKeyInfoWithParams( + password, + encrypted_private_key_info, + subject_public_key_info, + PR_TRUE /* permanent */, + PR_TRUE /* sensitive */); +#else + // If USE_NSS is not defined, we initialize NSS with no databases, so we can't + // create permanent keys. + NOTREACHED(); + return NULL; +#endif +} + +bool ECPrivateKey::ExportEncryptedPrivateKey( + const std::string& password, + int iterations, + std::vector<uint8>* output) { + // We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8 + // PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't + // support EC keys. + // https://bugzilla.mozilla.org/show_bug.cgi?id=327773 + SECItem password_item = { + siBuffer, + reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())), + password.size() + }; + + SECKEYEncryptedPrivateKeyInfo* encrypted = PK11_ExportEncryptedPrivKeyInfo( + NULL, // Slot, optional. + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC, + &password_item, + key_, + iterations, + NULL); // wincx. + + if (!encrypted) { + DLOG(ERROR) << "PK11_ExportEncryptedPrivKeyInfo: " << PORT_GetError(); + return false; + } + + ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + SECItem der_key = {siBuffer, NULL, 0}; + SECItem* encoded_item = SEC_ASN1EncodeItem( + arena.get(), + &der_key, + encrypted, + SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate)); + SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted, PR_TRUE); + if (!encoded_item) { + DLOG(ERROR) << "SEC_ASN1EncodeItem: " << PORT_GetError(); + return false; + } + + output->assign(der_key.data, der_key.data + der_key.len); + + return true; +} + +bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) { + ScopedSECItem der_pubkey( + SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_)); + if (!der_pubkey.get()) { + return false; + } + + output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len); + return true; +} + +bool ECPrivateKey::ExportValue(std::vector<uint8>* output) { + return ReadAttribute(key_, CKA_VALUE, output); +} + +bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) { + return ReadAttribute(key_, CKA_EC_PARAMS, output); +} + +ECPrivateKey::ECPrivateKey() : key_(NULL), public_key_(NULL) {} + +// static +ECPrivateKey* ECPrivateKey::CreateWithParams(bool permanent, + bool sensitive) { + EnsureNSSInit(); + + scoped_ptr<ECPrivateKey> result(new ECPrivateKey); + + ScopedPK11Slot slot(GetPrivateNSSKeySlot()); + if (!slot.get()) + return NULL; + + SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); + if (!oid_data) { + DLOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError(); + return NULL; + } + + // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters + // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve. + // In addition to the oid data, the encoding requires one byte for the ASN.1 + // tag and one byte for the length (assuming the length is <= 127). + DCHECK_LE(oid_data->oid.len, 127U); + std::vector<unsigned char> parameters_buf(2 + oid_data->oid.len); + SECKEYECParams ec_parameters = { + siDEROID, ¶meters_buf[0], parameters_buf.size() + }; + + ec_parameters.data[0] = SEC_ASN1_OBJECT_ID; + ec_parameters.data[1] = oid_data->oid.len; + memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len); + + result->key_ = PK11_GenerateKeyPair(slot.get(), + CKM_EC_KEY_PAIR_GEN, + &ec_parameters, + &result->public_key_, + permanent, + sensitive, + NULL); + if (!result->key_) { + DLOG(ERROR) << "PK11_GenerateKeyPair: " << PORT_GetError(); + return NULL; + } + + return result.release(); +} + +// static +ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfoWithParams( + const std::string& password, + const std::vector<uint8>& encrypted_private_key_info, + const std::vector<uint8>& subject_public_key_info, + bool permanent, + bool sensitive) { + EnsureNSSInit(); + + scoped_ptr<ECPrivateKey> result(new ECPrivateKey); + + ScopedPK11Slot slot(GetPrivateNSSKeySlot()); + if (!slot.get()) + return NULL; + + SECItem encoded_spki = { + siBuffer, + const_cast<unsigned char*>(&subject_public_key_info[0]), + subject_public_key_info.size() + }; + CERTSubjectPublicKeyInfo* decoded_spki = SECKEY_DecodeDERSubjectPublicKeyInfo( + &encoded_spki); + if (!decoded_spki) { + DLOG(ERROR) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError(); + return NULL; + } + + result->public_key_ = SECKEY_ExtractPublicKey(decoded_spki); + + SECKEY_DestroySubjectPublicKeyInfo(decoded_spki); + + if (!result->public_key_) { + DLOG(ERROR) << "SECKEY_ExtractPublicKey: " << PORT_GetError(); + return NULL; + } + + SECItem encoded_epki = { + siBuffer, + const_cast<unsigned char*>(&encrypted_private_key_info[0]), + encrypted_private_key_info.size() + }; + SECKEYEncryptedPrivateKeyInfo epki; + memset(&epki, 0, sizeof(epki)); + + ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + + SECStatus rv = SEC_QuickDERDecodeItem( + arena.get(), + &epki, + SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), + &encoded_epki); + if (rv != SECSuccess) { + DLOG(ERROR) << "SEC_ASN1DecodeItem: " << PORT_GetError(); + return NULL; + } + + SECItem password_item = { + siBuffer, + reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())), + password.size() + }; + + rv = ImportEncryptedECPrivateKeyInfoAndReturnKey( + slot.get(), + &epki, + &password_item, + NULL, // nickname + &result->public_key_->u.ec.publicValue, + permanent, + sensitive, + &result->key_, + NULL); // wincx + if (rv != SECSuccess) { + DLOG(ERROR) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: " + << PORT_GetError(); + return NULL; + } + + return result.release(); +} + +} // namespace crypto diff --git a/crypto/ec_private_key_openssl.cc b/crypto/ec_private_key_openssl.cc new file mode 100644 index 0000000..40e6f04 --- /dev/null +++ b/crypto/ec_private_key_openssl.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/ec_private_key.h" + +#include "base/logging.h" + +namespace crypto { + +ECPrivateKey::~ECPrivateKey() {} + +// static +ECPrivateKey* ECPrivateKey::Create() { + NOTIMPLEMENTED(); + return NULL; +} + +// static +ECPrivateKey* ECPrivateKey::CreateSensitive() { + NOTIMPLEMENTED(); + return NULL; +} + +// static +ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + const std::string& password, + const std::vector<uint8>& encrypted_private_key_info, + const std::vector<uint8>& subject_public_key_info) { + NOTIMPLEMENTED(); + return NULL; +} + +// static +ECPrivateKey* ECPrivateKey::CreateSensitiveFromEncryptedPrivateKeyInfo( + const std::string& password, + const std::vector<uint8>& encrypted_private_key_info, + const std::vector<uint8>& subject_public_key_info) { + NOTIMPLEMENTED(); + return NULL; +} + +bool ECPrivateKey::ExportEncryptedPrivateKey( + const std::string& password, + int iterations, + std::vector<uint8>* output) { + NOTIMPLEMENTED(); + return false; +} + +bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) { + NOTIMPLEMENTED(); + return false; +} + +bool ECPrivateKey::ExportValue(std::vector<uint8>* output) { + NOTIMPLEMENTED(); + return false; +} + +bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) { + NOTIMPLEMENTED(); + return false; +} + +} // namespace crypto diff --git a/crypto/ec_private_key_unittest.cc b/crypto/ec_private_key_unittest.cc new file mode 100644 index 0000000..a052a9a --- /dev/null +++ b/crypto/ec_private_key_unittest.cc @@ -0,0 +1,107 @@ +// 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/ec_private_key.h" + +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(USE_OPENSSL) +// Once ECPrivateKey is implemented for OpenSSL, remove this #if block. +// TODO(mattm): When that happens, also add some exported keys from each to test +// interop between NSS and OpenSSL. +TEST(ECPrivateKeyUnitTest, OpenSSLStub) { + scoped_ptr<crypto::ECPrivateKey> keypair1( + crypto::ECPrivateKey::Create()); + ASSERT_FALSE(keypair1.get()); +} +#else +// Generate random private keys. Export, then re-import. We should get +// back the same exact public key, and the private key should have the same +// value and elliptic curve params. +TEST(ECPrivateKeyUnitTest, InitRandomTest) { + const std::string password1 = ""; + const std::string password2 = "test"; + + scoped_ptr<crypto::ECPrivateKey> keypair1( + crypto::ECPrivateKey::Create()); + scoped_ptr<crypto::ECPrivateKey> keypair2( + crypto::ECPrivateKey::Create()); + ASSERT_TRUE(keypair1.get()); + ASSERT_TRUE(keypair2.get()); + + std::vector<uint8> key1value; + std::vector<uint8> key2value; + std::vector<uint8> key1params; + std::vector<uint8> key2params; + EXPECT_TRUE(keypair1->ExportValue(&key1value)); + EXPECT_TRUE(keypair2->ExportValue(&key2value)); + EXPECT_TRUE(keypair1->ExportECParams(&key1params)); + EXPECT_TRUE(keypair2->ExportECParams(&key2params)); + + std::vector<uint8> privkey1; + std::vector<uint8> privkey2; + std::vector<uint8> pubkey1; + std::vector<uint8> pubkey2; + ASSERT_TRUE(keypair1->ExportEncryptedPrivateKey( + password1, 1, &privkey1)); + ASSERT_TRUE(keypair2->ExportEncryptedPrivateKey( + password2, 1, &privkey2)); + EXPECT_TRUE(keypair1->ExportPublicKey(&pubkey1)); + EXPECT_TRUE(keypair2->ExportPublicKey(&pubkey2)); + + scoped_ptr<crypto::ECPrivateKey> keypair3( + crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + password1, privkey1, pubkey1)); + scoped_ptr<crypto::ECPrivateKey> keypair4( + crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + password2, privkey2, pubkey2)); + ASSERT_TRUE(keypair3.get()); + ASSERT_TRUE(keypair4.get()); + + std::vector<uint8> key3value; + std::vector<uint8> key4value; + std::vector<uint8> key3params; + std::vector<uint8> key4params; + EXPECT_TRUE(keypair3->ExportValue(&key3value)); + EXPECT_TRUE(keypair4->ExportValue(&key4value)); + EXPECT_TRUE(keypair3->ExportECParams(&key3params)); + EXPECT_TRUE(keypair4->ExportECParams(&key4params)); + + EXPECT_EQ(key1value, key3value); + EXPECT_EQ(key2value, key4value); + EXPECT_EQ(key1params, key3params); + EXPECT_EQ(key2params, key4params); + + std::vector<uint8> pubkey3; + std::vector<uint8> pubkey4; + EXPECT_TRUE(keypair3->ExportPublicKey(&pubkey3)); + EXPECT_TRUE(keypair4->ExportPublicKey(&pubkey4)); + + EXPECT_EQ(pubkey1, pubkey3); + EXPECT_EQ(pubkey2, pubkey4); +} + +TEST(ECPrivateKeyUnitTest, BadPasswordTest) { + const std::string password1 = ""; + const std::string password2 = "test"; + + scoped_ptr<crypto::ECPrivateKey> keypair1( + crypto::ECPrivateKey::Create()); + ASSERT_TRUE(keypair1.get()); + + std::vector<uint8> privkey1; + std::vector<uint8> pubkey1; + ASSERT_TRUE(keypair1->ExportEncryptedPrivateKey( + password1, 1, &privkey1)); + ASSERT_TRUE(keypair1->ExportPublicKey(&pubkey1)); + + scoped_ptr<crypto::ECPrivateKey> keypair2( + crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + password2, privkey1, pubkey1)); + ASSERT_FALSE(keypair2.get()); +} +#endif // !defined(USE_OPENSSL) diff --git a/crypto/scoped_nss_types.h b/crypto/scoped_nss_types.h index d8d78b0..9bb9968 100644 --- a/crypto/scoped_nss_types.h +++ b/crypto/scoped_nss_types.h @@ -9,6 +9,7 @@ #include <keyhi.h> #include <nss.h> #include <pk11pub.h> +#include <plarena.h> #include "base/memory/scoped_ptr.h" @@ -53,6 +54,10 @@ typedef scoped_ptr_malloc< SECItem, NSSDestroyer1<SECItem, SECITEM_FreeItem, PR_TRUE> > ScopedSECItem; +typedef scoped_ptr_malloc< + PLArenaPool, NSSDestroyer1<PLArenaPool, + PORT_FreeArena, + PR_FALSE> > ScopedPLArenaPool; } // namespace crypto diff --git a/crypto/third_party/nss/chromium-nss.h b/crypto/third_party/nss/chromium-nss.h new file mode 100644 index 0000000..af85e36 --- /dev/null +++ b/crypto/third_party/nss/chromium-nss.h @@ -0,0 +1,62 @@ + /* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_ +#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_ +#pragma once + +// This file contains some functions we borrowed from NSS. + +#include <keyhi.h> +#include <secmod.h> + +// Like PK11_ImportEncryptedPrivateKeyInfo, but hardcoded for EC, and returns +// the SECKEYPrivateKey. +// See https://bugzilla.mozilla.org/show_bug.cgi?id=211546 +// When we use NSS 3.13.2 or later, +// PK11_ImportEncryptedPrivateKeyInfoAndReturnKey can be used instead. +SECStatus ImportEncryptedECPrivateKeyInfoAndReturnKey( + PK11SlotInfo* slot, + SECKEYEncryptedPrivateKeyInfo* epki, + SECItem* password, + SECItem* nickname, + SECItem* public_value, + PRBool permanent, + PRBool sensitive, + SECKEYPrivateKey** private_key, + void* wincx); + +#endif // CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_ diff --git a/crypto/third_party/nss/pk11akey.cc b/crypto/third_party/nss/pk11akey.cc new file mode 100644 index 0000000..4db582f --- /dev/null +++ b/crypto/third_party/nss/pk11akey.cc @@ -0,0 +1,98 @@ + /* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Stephen Henson <stephen.henson@gemplus.com> + * Dr Vipul Gupta <vipul.gupta@sun.com>, and + * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "crypto/third_party/nss/chromium-nss.h" + +#include <pk11pub.h> + +#include "base/logging.h" + +// Based on PK11_ImportEncryptedPrivateKeyInfo function in +// mozilla/security/nss/lib/pk11wrap/pk11akey.c. +SECStatus ImportEncryptedECPrivateKeyInfoAndReturnKey( + PK11SlotInfo* slot, + SECKEYEncryptedPrivateKeyInfo* epki, + SECItem* password, + SECItem* nickname, + SECItem* public_value, + PRBool permanent, + PRBool sensitive, + SECKEYPrivateKey** private_key, + void* wincx) { + SECItem* crypto_param = NULL; + + CK_ATTRIBUTE_TYPE usage = CKA_SIGN; + + PK11SymKey* key = PK11_PBEKeyGen(slot, + &epki->algorithm, + password, + PR_FALSE, // faulty3DES + wincx); + if (key == NULL) { + DLOG(ERROR) << "PK11_PBEKeyGen: " << PORT_GetError(); + return SECFailure; + } + + CK_MECHANISM_TYPE crypto_mech_type = PK11_GetPBECryptoMechanism( + &epki->algorithm, &crypto_param, password); + if (crypto_mech_type == CKM_INVALID_MECHANISM) { + DLOG(ERROR) << "PK11_GetPBECryptoMechanism: " << PORT_GetError(); + PK11_FreeSymKey(key); + return SECFailure; + } + + crypto_mech_type = PK11_GetPadMechanism(crypto_mech_type); + + *private_key = PK11_UnwrapPrivKey(slot, key, crypto_mech_type, crypto_param, + &epki->encryptedData, nickname, + public_value, permanent, sensitive, CKK_EC, + &usage, 1, wincx); + + if (crypto_param != NULL) + SECITEM_ZfreeItem(crypto_param, PR_TRUE); + + PK11_FreeSymKey(key); + + if (!*private_key) { + DLOG(ERROR) << "PK11_UnwrapPrivKey: " << PORT_GetError(); + return SECFailure; + } + + return SECSuccess; +} |