summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/BUILD.gn3
-rw-r--r--net/net.gyp1
-rw-r--r--net/net.gypi3
-rw-r--r--net/net_common.gypi2
-rw-r--r--net/socket/ssl_client_socket_openssl_unittest.cc267
-rw-r--r--net/socket/ssl_client_socket_unittest.cc119
-rw-r--r--net/ssl/test_ssl_private_key.cc128
-rw-r--r--net/ssl/test_ssl_private_key.h25
8 files changed, 278 insertions, 270 deletions
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 5653169..b8c44cb 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -225,6 +225,8 @@ if (!is_nacl) {
"ssl/ssl_platform_key.h",
"ssl/ssl_platform_key_task_runner.cc",
"ssl/ssl_platform_key_task_runner.h",
+ "ssl/test_ssl_private_key.cc",
+ "ssl/test_ssl_private_key.h",
"ssl/threaded_ssl_private_key.cc",
"ssl/threaded_ssl_private_key.h",
"ssl/token_binding_openssl.cc",
@@ -1481,7 +1483,6 @@ test("net_unittests") {
} else {
sources -= [
"quic/test_tools/crypto_test_utils_openssl.cc",
- "socket/ssl_client_socket_openssl_unittest.cc",
"ssl/ssl_client_session_cache_openssl_unittest.cc",
]
}
diff --git a/net/net.gyp b/net/net.gyp
index 16c2f7b..68a4cc0 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -255,7 +255,6 @@
}, { # else !use_openssl: remove the unneeded files and pull in NSS.
'sources!': [
'quic/test_tools/crypto_test_utils_openssl.cc',
- 'socket/ssl_client_socket_openssl_unittest.cc',
'ssl/ssl_client_session_cache_openssl_unittest.cc',
],
},
diff --git a/net/net.gypi b/net/net.gypi
index a6394f6..472941f 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -1183,6 +1183,8 @@
'ssl/ssl_platform_key_task_runner.cc',
'ssl/ssl_platform_key_task_runner.h',
'ssl/ssl_platform_key_win.cc',
+ 'ssl/test_ssl_private_key.cc',
+ 'ssl/test_ssl_private_key.h',
'ssl/threaded_ssl_private_key.cc',
'ssl/threaded_ssl_private_key.h',
'ssl/token_binding.h',
@@ -1689,7 +1691,6 @@
'socket/socks5_client_socket_unittest.cc',
'socket/socks_client_socket_pool_unittest.cc',
'socket/socks_client_socket_unittest.cc',
- 'socket/ssl_client_socket_openssl_unittest.cc',
'socket/ssl_client_socket_pool_unittest.cc',
'socket/ssl_client_socket_unittest.cc',
'socket/ssl_server_socket_unittest.cc',
diff --git a/net/net_common.gypi b/net/net_common.gypi
index 6d7f943..fe14edd 100644
--- a/net/net_common.gypi
+++ b/net/net_common.gypi
@@ -188,6 +188,8 @@
'ssl/ssl_platform_key_nss.cc',
'ssl/ssl_platform_key_task_runner.cc',
'ssl/ssl_platform_key_task_runner.h',
+ 'ssl/test_ssl_private_key.cc',
+ 'ssl/test_ssl_private_key.h',
'ssl/threaded_ssl_private_key.cc',
'ssl/threaded_ssl_private_key.h',
'ssl/token_binding_openssl.cc',
diff --git a/net/socket/ssl_client_socket_openssl_unittest.cc b/net/socket/ssl_client_socket_openssl_unittest.cc
deleted file mode 100644
index a1ab91a..0000000
--- a/net/socket/ssl_client_socket_openssl_unittest.cc
+++ /dev/null
@@ -1,267 +0,0 @@
-// Copyright (c) 2012 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/socket/ssl_client_socket.h"
-
-#include <errno.h>
-#include <openssl/bio.h>
-#include <openssl/bn.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/rsa.h>
-#include <string.h>
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/values.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-#include "net/base/address_list.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/base/test_completion_callback.h"
-#include "net/base/test_data_directory.h"
-#include "net/cert/mock_cert_verifier.h"
-#include "net/cert/test_root_certs.h"
-#include "net/dns/host_resolver.h"
-#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
-#include "net/socket/client_socket_factory.h"
-#include "net/socket/client_socket_handle.h"
-#include "net/socket/socket_test_util.h"
-#include "net/socket/tcp_client_socket.h"
-#include "net/ssl/openssl_client_key_store.h"
-#include "net/ssl/ssl_cert_request_info.h"
-#include "net/ssl/ssl_config_service.h"
-#include "net/ssl/ssl_platform_key.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace net {
-
-namespace {
-
-// These client auth tests are currently dependent on OpenSSL's struct X509.
-#if defined(USE_OPENSSL_CERTS)
-
-// Loads a PEM-encoded private key file into a scoped EVP_PKEY object.
-// |filepath| is the private key file path.
-// |*pkey| is reset to the new EVP_PKEY on success, untouched otherwise.
-// Returns true on success, false on failure.
-bool LoadPrivateKeyOpenSSL(
- const base::FilePath& filepath,
- crypto::ScopedEVP_PKEY* pkey) {
- std::string data;
- if (!base::ReadFileToString(filepath, &data)) {
- LOG(ERROR) << "Could not read private key file: "
- << filepath.value() << ": " << strerror(errno);
- return false;
- }
- crypto::ScopedBIO bio(BIO_new_mem_buf(
- const_cast<char*>(reinterpret_cast<const char*>(data.data())),
- static_cast<int>(data.size())));
- if (!bio.get()) {
- LOG(ERROR) << "Could not allocate BIO for buffer?";
- return false;
- }
- EVP_PKEY* result = PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL);
- if (result == NULL) {
- LOG(ERROR) << "Could not decode private key file: "
- << filepath.value();
- return false;
- }
- pkey->reset(result);
- return true;
-}
-
-class SSLClientSocketOpenSSLClientAuthTest : public PlatformTest {
- public:
- SSLClientSocketOpenSSLClientAuthTest()
- : socket_factory_(ClientSocketFactory::GetDefaultFactory()),
- cert_verifier_(new MockCertVerifier),
- transport_security_state_(new TransportSecurityState) {
- cert_verifier_->set_default_result(OK);
- context_.cert_verifier = cert_verifier_.get();
- context_.transport_security_state = transport_security_state_.get();
- key_store_ = OpenSSLClientKeyStore::GetInstance();
- }
-
- ~SSLClientSocketOpenSSLClientAuthTest() override { key_store_->Flush(); }
-
- protected:
- scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
- scoped_ptr<StreamSocket> transport_socket,
- const HostPortPair& host_and_port,
- const SSLConfig& ssl_config) {
- scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
- connection->SetSocket(std::move(transport_socket));
- return socket_factory_->CreateSSLClientSocket(
- std::move(connection), host_and_port, ssl_config, context_);
- }
-
- // Connect to a HTTPS test server.
- bool ConnectToTestServer(SpawnedTestServer::SSLOptions& ssl_options) {
- test_server_.reset(new SpawnedTestServer(SpawnedTestServer::TYPE_HTTPS,
- ssl_options,
- base::FilePath()));
- if (!test_server_->Start()) {
- LOG(ERROR) << "Could not start SpawnedTestServer";
- return false;
- }
-
- if (!test_server_->GetAddressList(&addr_)) {
- LOG(ERROR) << "Could not get SpawnedTestServer address list";
- return false;
- }
-
- transport_.reset(new TCPClientSocket(
- addr_, &log_, NetLog::Source()));
- int rv = callback_.GetResult(
- transport_->Connect(callback_.callback()));
- if (rv != OK) {
- LOG(ERROR) << "Could not connect to SpawnedTestServer";
- return false;
- }
- return true;
- }
-
- // Record a certificate's private key to ensure it can be used
- // by the OpenSSL-based SSLClientSocket implementation.
- // |ssl_config| provides a client certificate.
- // |private_key| must be an EVP_PKEY for the corresponding private key.
- // Returns true on success, false on failure.
- bool RecordPrivateKey(SSLConfig& ssl_config,
- EVP_PKEY* private_key) {
- return key_store_->RecordClientCertPrivateKey(
- ssl_config.client_cert.get(), private_key);
- }
-
- // Create an SSLClientSocket object and use it to connect to a test
- // server, then wait for connection results. This must be called after
- // a succesful ConnectToTestServer() call.
- // |ssl_config| the SSL configuration to use.
- // |result| will retrieve the ::Connect() result value.
- // Returns true on succes, false otherwise. Success means that the socket
- // could be created and its Connect() was called, not that the connection
- // itself was a success.
- bool CreateAndConnectSSLClientSocket(const SSLConfig& ssl_config,
- int* result) {
- sock_ = CreateSSLClientSocket(std::move(transport_),
- test_server_->host_port_pair(), ssl_config);
-
- if (sock_->IsConnected()) {
- LOG(ERROR) << "SSL Socket prematurely connected";
- return false;
- }
-
- *result = callback_.GetResult(sock_->Connect(callback_.callback()));
- return true;
- }
-
-
- // Check that the client certificate was sent.
- // Returns true on success.
- bool CheckSSLClientSocketSentCert() {
- SSLInfo ssl_info;
- sock_->GetSSLInfo(&ssl_info);
- return ssl_info.client_cert_sent;
- }
-
- ClientSocketFactory* socket_factory_;
- scoped_ptr<MockCertVerifier> cert_verifier_;
- scoped_ptr<TransportSecurityState> transport_security_state_;
- SSLClientSocketContext context_;
- OpenSSLClientKeyStore* key_store_;
- scoped_ptr<SpawnedTestServer> test_server_;
- AddressList addr_;
- TestCompletionCallback callback_;
- NetLog log_;
- scoped_ptr<StreamSocket> transport_;
- scoped_ptr<SSLClientSocket> sock_;
-};
-
-// Connect to a server requesting client authentication, do not send
-// any client certificates. It should refuse the connection.
-TEST_F(SSLClientSocketOpenSSLClientAuthTest, NoCert) {
- SpawnedTestServer::SSLOptions ssl_options;
- ssl_options.request_client_certificate = true;
-
- ASSERT_TRUE(ConnectToTestServer(ssl_options));
-
- base::FilePath certs_dir = GetTestCertsDirectory();
-
- int rv;
- ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
-
- EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
- EXPECT_FALSE(sock_->IsConnected());
-}
-
-// Connect to a server requesting client authentication, and send it
-// an empty certificate. It should refuse the connection.
-TEST_F(SSLClientSocketOpenSSLClientAuthTest, SendEmptyCert) {
- SpawnedTestServer::SSLOptions ssl_options;
- ssl_options.request_client_certificate = true;
- ssl_options.client_authorities.push_back(
- GetTestClientCertsDirectory().AppendASCII("client_1_ca.pem"));
-
- ASSERT_TRUE(ConnectToTestServer(ssl_options));
-
- base::FilePath certs_dir = GetTestCertsDirectory();
- SSLConfig ssl_config;
- ssl_config.send_client_cert = true;
- ssl_config.client_cert = NULL;
- ssl_config.client_private_key = NULL;
-
- int rv;
- ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
-
- EXPECT_EQ(OK, rv);
- EXPECT_TRUE(sock_->IsConnected());
-}
-
-// Connect to a server requesting client authentication. Send it a
-// matching certificate. It should allow the connection.
-TEST_F(SSLClientSocketOpenSSLClientAuthTest, SendGoodCert) {
- SpawnedTestServer::SSLOptions ssl_options;
- ssl_options.request_client_certificate = true;
- ssl_options.client_authorities.push_back(
- GetTestClientCertsDirectory().AppendASCII("client_1_ca.pem"));
-
- ASSERT_TRUE(ConnectToTestServer(ssl_options));
-
- base::FilePath certs_dir = GetTestCertsDirectory();
- SSLConfig ssl_config;
- ssl_config.send_client_cert = true;
- ssl_config.client_cert = ImportCertFromFile(certs_dir, "client_1.pem");
-
- // This is required to ensure that signing works with the client
- // certificate's private key.
- crypto::ScopedEVP_PKEY client_private_key;
- ASSERT_TRUE(LoadPrivateKeyOpenSSL(certs_dir.AppendASCII("client_1.key"),
- &client_private_key));
- EXPECT_TRUE(RecordPrivateKey(ssl_config, client_private_key.get()));
-
- ssl_config.client_private_key =
- FetchClientCertPrivateKey(ssl_config.client_cert.get());
-
- int rv;
- ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
-
- EXPECT_EQ(OK, rv);
- EXPECT_TRUE(sock_->IsConnected());
-
- EXPECT_TRUE(CheckSSLClientSocketSentCert());
-
- sock_->Disconnect();
- EXPECT_FALSE(sock_->IsConnected());
-}
-#endif // defined(USE_OPENSSL_CERTS)
-
-} // namespace
-} // namespace net
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 6a9d465..141f629 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/callback_helpers.h"
+#include "base/files/file_util.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
@@ -49,6 +50,17 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+#if defined(USE_OPENSSL)
+#include <errno.h>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <string.h>
+
+#include "crypto/scoped_openssl_types.h"
+#include "net/ssl/test_ssl_private_key.h"
+#endif
+
using testing::_;
using testing::Return;
using testing::Truly;
@@ -3240,4 +3252,111 @@ TEST_F(SSLClientSocketTest, NPNServerDisabled) {
sock_->GetNextProto(&proto));
}
+// Client auth is not supported in NSS ports.
+#if defined(USE_OPENSSL)
+
+namespace {
+
+// Loads a PEM-encoded private key file into a SSLPrivateKey object.
+// |filepath| is the private key file path.
+// Returns the new SSLPrivateKey.
+scoped_refptr<SSLPrivateKey> LoadPrivateKeyOpenSSL(
+ const base::FilePath& filepath) {
+ std::string data;
+ if (!base::ReadFileToString(filepath, &data)) {
+ LOG(ERROR) << "Could not read private key file: " << filepath.value();
+ return nullptr;
+ }
+ crypto::ScopedBIO bio(BIO_new_mem_buf(const_cast<char*>(data.data()),
+ static_cast<int>(data.size())));
+ if (!bio) {
+ LOG(ERROR) << "Could not allocate BIO for buffer?";
+ return nullptr;
+ }
+ crypto::ScopedEVP_PKEY result(
+ PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+ if (!result) {
+ LOG(ERROR) << "Could not decode private key file: " << filepath.value();
+ return nullptr;
+ }
+ return WrapOpenSSLPrivateKey(std::move(result));
+}
+
+} // namespace
+
+// Connect to a server requesting client authentication, do not send
+// any client certificates. It should refuse the connection.
+TEST_F(SSLClientSocketTest, NoCert) {
+ SpawnedTestServer::SSLOptions ssl_options;
+ ssl_options.request_client_certificate = true;
+ ASSERT_TRUE(StartTestServer(ssl_options));
+
+ int rv;
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
+
+ EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
+ EXPECT_FALSE(sock_->IsConnected());
+}
+
+// Connect to a server requesting client authentication, and send it
+// an empty certificate.
+TEST_F(SSLClientSocketTest, SendEmptyCert) {
+ SpawnedTestServer::SSLOptions ssl_options;
+ ssl_options.request_client_certificate = true;
+ ssl_options.client_authorities.push_back(
+ GetTestClientCertsDirectory().AppendASCII("client_1_ca.pem"));
+
+ ASSERT_TRUE(StartTestServer(ssl_options));
+
+ SSLConfig ssl_config;
+ ssl_config.send_client_cert = true;
+ ssl_config.client_cert = nullptr;
+ ssl_config.client_private_key = nullptr;
+
+ int rv;
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(sock_->IsConnected());
+
+ SSLInfo ssl_info;
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_FALSE(ssl_info.client_cert_sent);
+}
+
+// Connect to a server requesting client authentication. Send it a
+// matching certificate. It should allow the connection.
+TEST_F(SSLClientSocketTest, SendGoodCert) {
+ SpawnedTestServer::SSLOptions ssl_options;
+ ssl_options.request_client_certificate = true;
+ ssl_options.client_authorities.push_back(
+ GetTestClientCertsDirectory().AppendASCII("client_1_ca.pem"));
+
+ ASSERT_TRUE(StartTestServer(ssl_options));
+
+ base::FilePath certs_dir = GetTestCertsDirectory();
+ SSLConfig ssl_config;
+ ssl_config.send_client_cert = true;
+ ssl_config.client_cert = ImportCertFromFile(certs_dir, "client_1.pem");
+
+ // This is required to ensure that signing works with the client
+ // certificate's private key.
+ ssl_config.client_private_key =
+ LoadPrivateKeyOpenSSL(certs_dir.AppendASCII("client_1.key"));
+
+ int rv;
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(sock_->IsConnected());
+
+ SSLInfo ssl_info;
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_TRUE(ssl_info.client_cert_sent);
+
+ sock_->Disconnect();
+ EXPECT_FALSE(sock_->IsConnected());
+}
+#endif // defined(USE_OPENSSL)
+
} // namespace net
diff --git a/net/ssl/test_ssl_private_key.cc b/net/ssl/test_ssl_private_key.cc
new file mode 100644
index 0000000..99ed33b
--- /dev/null
+++ b/net/ssl/test_ssl_private_key.cc
@@ -0,0 +1,128 @@
+// 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/test_ssl_private_key.h"
+
+#include <openssl/digest.h>
+#include <openssl/evp.h>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "crypto/scoped_openssl_types.h"
+#include "net/base/net_errors.h"
+#include "net/ssl/ssl_platform_key_task_runner.h"
+#include "net/ssl/ssl_private_key.h"
+#include "net/ssl/threaded_ssl_private_key.h"
+
+namespace net {
+
+namespace {
+
+class TestSSLPlatformKey : public ThreadedSSLPrivateKey::Delegate {
+ public:
+ TestSSLPlatformKey(crypto::ScopedEVP_PKEY key, SSLPrivateKey::Type type)
+ : key_(std::move(key)), type_(type) {}
+
+ ~TestSSLPlatformKey() override {}
+
+ SSLPrivateKey::Type GetType() override { return type_; }
+
+ std::vector<SSLPrivateKey::Hash> GetDigestPreferences() override {
+ static const SSLPrivateKey::Hash kHashes[] = {
+ SSLPrivateKey::Hash::SHA512, SSLPrivateKey::Hash::SHA384,
+ SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1};
+ return std::vector<SSLPrivateKey::Hash>(kHashes,
+ kHashes + arraysize(kHashes));
+ }
+
+ size_t GetMaxSignatureLengthInBytes() override {
+ return EVP_PKEY_size(key_.get());
+ }
+
+ Error SignDigest(SSLPrivateKey::Hash hash,
+ const base::StringPiece& input,
+ std::vector<uint8_t>* signature) override {
+ crypto::ScopedEVP_PKEY_CTX ctx =
+ crypto::ScopedEVP_PKEY_CTX(EVP_PKEY_CTX_new(key_.get(), NULL));
+ if (!ctx)
+ return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
+ if (!EVP_PKEY_sign_init(ctx.get()))
+ return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
+
+ if (type_ == SSLPrivateKey::Type::RSA) {
+ const EVP_MD* digest = nullptr;
+ switch (hash) {
+ case SSLPrivateKey::Hash::MD5_SHA1:
+ digest = EVP_md5_sha1();
+ break;
+ case SSLPrivateKey::Hash::SHA1:
+ digest = EVP_sha1();
+ break;
+ case SSLPrivateKey::Hash::SHA256:
+ digest = EVP_sha256();
+ break;
+ case SSLPrivateKey::Hash::SHA384:
+ digest = EVP_sha384();
+ break;
+ case SSLPrivateKey::Hash::SHA512:
+ digest = EVP_sha512();
+ break;
+ default:
+ return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
+ }
+ DCHECK(digest);
+ if (!EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING))
+ return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
+ if (!EVP_PKEY_CTX_set_signature_md(ctx.get(), digest))
+ return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
+ }
+
+ const uint8_t* input_ptr = reinterpret_cast<const uint8_t*>(input.data());
+ size_t input_len = input.size();
+ size_t sig_len = 0;
+ if (!EVP_PKEY_sign(ctx.get(), NULL, &sig_len, input_ptr, input_len))
+ return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
+ signature->resize(sig_len);
+ if (!EVP_PKEY_sign(ctx.get(), signature->data(), &sig_len, input_ptr,
+ input_len)) {
+ return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
+ }
+
+ signature->resize(sig_len);
+
+ return OK;
+ }
+
+ private:
+ crypto::ScopedEVP_PKEY key_;
+ SSLPrivateKey::Type type_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSSLPlatformKey);
+};
+
+} // namespace
+
+scoped_refptr<SSLPrivateKey> WrapOpenSSLPrivateKey(crypto::ScopedEVP_PKEY key) {
+ if (!key)
+ return nullptr;
+
+ SSLPrivateKey::Type type;
+ switch (EVP_PKEY_id(key.get())) {
+ case EVP_PKEY_RSA:
+ type = SSLPrivateKey::Type::RSA;
+ break;
+ case EVP_PKEY_EC:
+ type = SSLPrivateKey::Type::ECDSA;
+ break;
+ default:
+ LOG(ERROR) << "Unknown key type: " << EVP_PKEY_id(key.get());
+ return nullptr;
+ }
+ return make_scoped_refptr(new ThreadedSSLPrivateKey(
+ make_scoped_ptr(new TestSSLPlatformKey(std::move(key), type)),
+ GetSSLPlatformKeyTaskRunner()));
+}
+
+} // namespace net
diff --git a/net/ssl/test_ssl_private_key.h b/net/ssl/test_ssl_private_key.h
new file mode 100644
index 0000000..f9ae906
--- /dev/null
+++ b/net/ssl/test_ssl_private_key.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef NET_SSL_TEST_SSL_PLATFORM_KEY_H_
+#define NET_SSL_TEST_SSL_PLATFORM_KEY_H_
+
+#include <openssl/evp.h>
+
+#include "base/memory/ref_counted.h"
+#include "crypto/scoped_openssl_types.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+class SSLPrivateKey;
+
+// Returns a new SSLPrivateKey which uses |key| for signing operations or
+// nullptr on error.
+NET_EXPORT scoped_refptr<SSLPrivateKey> WrapOpenSSLPrivateKey(
+ crypto::ScopedEVP_PKEY key);
+
+} // namespace net
+
+#endif // NET_SSL_TEST_SSL_PLATFORM_KEY_H_