summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authormattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-09 05:08:51 +0000
committermattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-09 05:08:51 +0000
commiteaa60485f027b00047a2e142d9616ede4333a46b (patch)
treeeb20edb20255f8f76d76f3ff4f1399a04a6d9398 /crypto
parente80f64a0f8ed441443bec21eeb5c732398d11377 (diff)
downloadchromium_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.gyp11
-rw-r--r--crypto/ec_private_key.h124
-rw-r--r--crypto/ec_private_key_nss.cc300
-rw-r--r--crypto/ec_private_key_openssl.cc66
-rw-r--r--crypto/ec_private_key_unittest.cc107
-rw-r--r--crypto/scoped_nss_types.h5
-rw-r--r--crypto/third_party/nss/chromium-nss.h62
-rw-r--r--crypto/third_party/nss/pk11akey.cc98
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, &parameters_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;
+}