| Index: net/ssl/ssl_platform_key_nss_unittest.cc
|
| diff --git a/net/ssl/ssl_platform_key_nss_unittest.cc b/net/ssl/ssl_platform_key_nss_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..85799cae131deb2504eaea6801d1d7e4082c8336
|
| --- /dev/null
|
| +++ b/net/ssl/ssl_platform_key_nss_unittest.cc
|
| @@ -0,0 +1,141 @@
|
| +// Copyright 2016 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 "net/ssl/ssl_platform_key.h"
|
| +
|
| +#include <keyhi.h>
|
| +#include <pk11pub.h>
|
| +#include <stdint.h>
|
| +#include <string.h>
|
| +
|
| +#include <memory>
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "base/files/file_path.h"
|
| +#include "base/files/file_util.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "crypto/ec_private_key.h"
|
| +#include "crypto/scoped_nss_types.h"
|
| +#include "crypto/scoped_test_nss_db.h"
|
| +#include "net/ssl/ssl_private_key.h"
|
| +#include "net/ssl/ssl_private_key_test_util.h"
|
| +#include "net/test/cert_test_util.h"
|
| +#include "net/test/test_data_directory.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "third_party/boringssl/src/include/openssl/bytestring.h"
|
| +#include "third_party/boringssl/src/include/openssl/ec.h"
|
| +#include "third_party/boringssl/src/include/openssl/ec_key.h"
|
| +#include "third_party/boringssl/src/include/openssl/evp.h"
|
| +#include "third_party/boringssl/src/include/openssl/mem.h"
|
| +
|
| +namespace net {
|
| +
|
| +namespace {
|
| +
|
| +struct TestKey {
|
| + const char* cert_file;
|
| + const char* key_file;
|
| + SSLPrivateKey::Type key_type;
|
| +};
|
| +
|
| +const TestKey kTestKeys[] = {
|
| + {"client_1.pem", "client_1.pk8", SSLPrivateKey::Type::RSA},
|
| + {"client_4.pem", "client_4.pk8", SSLPrivateKey::Type::ECDSA_P256},
|
| + {"client_5.pem", "client_5.pk8", SSLPrivateKey::Type::ECDSA_P384},
|
| + {"client_6.pem", "client_6.pk8", SSLPrivateKey::Type::ECDSA_P521},
|
| +};
|
| +
|
| +std::string TestKeyToString(const testing::TestParamInfo<TestKey>& params) {
|
| + return SSLPrivateKeyTypeToString(params.param.key_type);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class SSLPlatformKeyNSSTest : public testing::TestWithParam<TestKey> {};
|
| +
|
| +TEST_P(SSLPlatformKeyNSSTest, KeyMatches) {
|
| + const TestKey& test_key = GetParam();
|
| +
|
| + std::string pkcs8;
|
| + base::FilePath pkcs8_path =
|
| + GetTestCertsDirectory().AppendASCII(test_key.key_file);
|
| + ASSERT_TRUE(base::ReadFileToString(pkcs8_path, &pkcs8));
|
| +
|
| + // Import the key into a test NSS database.
|
| + crypto::ScopedTestNSSDB test_db;
|
| + scoped_refptr<X509Certificate> cert;
|
| + if (SSLPrivateKey::IsECDSAType(test_key.key_type)) {
|
| + // NSS cannot import unencrypted ECDSA keys, so we encrypt it with an empty
|
| + // password and import manually.
|
| + std::vector<uint8_t> pkcs8_vector(pkcs8.begin(), pkcs8.end());
|
| + std::unique_ptr<crypto::ECPrivateKey> ec_private_key =
|
| + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(pkcs8_vector);
|
| + ASSERT_TRUE(ec_private_key);
|
| + std::vector<uint8_t> encrypted;
|
| + ASSERT_TRUE(ec_private_key->ExportEncryptedPrivateKey("", 1, &encrypted));
|
| +
|
| + SECItem encrypted_item = {siBuffer, encrypted.data(),
|
| + static_cast<unsigned>(encrypted.size())};
|
| + SECKEYEncryptedPrivateKeyInfo epki;
|
| + memset(&epki, 0, sizeof(epki));
|
| + crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
|
| + ASSERT_EQ(SECSuccess,
|
| + SEC_QuickDERDecodeItem(
|
| + arena.get(), &epki,
|
| + SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate),
|
| + &encrypted_item));
|
| +
|
| + // NSS uses the serialized public key in X9.62 form as the "public value"
|
| + // for key ID purposes.
|
| + bssl::ScopedCBB cbb;
|
| + ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
| + EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(ec_private_key->key());
|
| + ASSERT_TRUE(EC_POINT_point2cbb(cbb.get(), EC_KEY_get0_group(ec_key),
|
| + EC_KEY_get0_public_key(ec_key),
|
| + POINT_CONVERSION_UNCOMPRESSED, nullptr));
|
| + uint8_t* public_value;
|
| + size_t public_value_len;
|
| + ASSERT_TRUE(CBB_finish(cbb.get(), &public_value, &public_value_len));
|
| + bssl::UniquePtr<uint8_t> scoped_public_value(public_value);
|
| + SECItem public_item = {siBuffer, public_value,
|
| + static_cast<unsigned>(public_value_len)};
|
| +
|
| + SECItem password_item = {siBuffer, nullptr, 0};
|
| + ASSERT_EQ(SECSuccess,
|
| + PK11_ImportEncryptedPrivateKeyInfo(
|
| + test_db.slot(), &epki, &password_item, nullptr /* nickname */,
|
| + &public_item, PR_TRUE /* permanent */, PR_TRUE /* private */,
|
| + ecKey, KU_DIGITAL_SIGNATURE, nullptr /* wincx */));
|
| +
|
| + cert = ImportCertFromFile(GetTestCertsDirectory(), test_key.cert_file);
|
| + ASSERT_TRUE(cert);
|
| + ASSERT_TRUE(ImportClientCertToSlot(cert, test_db.slot()));
|
| + } else {
|
| + cert = ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
|
| + test_key.cert_file, test_key.key_file,
|
| + test_db.slot());
|
| + ASSERT_TRUE(cert);
|
| + }
|
| +
|
| + // Look up the key.
|
| + scoped_refptr<SSLPrivateKey> key = FetchClientCertPrivateKey(cert.get());
|
| + ASSERT_TRUE(key);
|
| +
|
| + // All NSS keys are expected to have the same hash preferences.
|
| + std::vector<SSLPrivateKey::Hash> expected_hashes = {
|
| + SSLPrivateKey::Hash::SHA512, SSLPrivateKey::Hash::SHA384,
|
| + SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1,
|
| + };
|
| + EXPECT_EQ(expected_hashes, key->GetDigestPreferences());
|
| +
|
| + TestSSLPrivateKeyMatches(key.get(), pkcs8);
|
| +}
|
| +
|
| +INSTANTIATE_TEST_CASE_P(,
|
| + SSLPlatformKeyNSSTest,
|
| + testing::ValuesIn(kTestKeys),
|
| + TestKeyToString);
|
| +
|
| +} // namespace net
|
|
|