diff options
author | svaldez <svaldez@chromium.org> | 2016-01-29 13:17:11 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-29 21:18:15 +0000 |
commit | 0e6a4c6d35b9081b2bbbba9b07591e64369e0604 (patch) | |
tree | 0744f135b1b0589f19970e96ebb15b084bf3b623 /net/socket | |
parent | d7da16f3e98469f15f389f81d42143c01b10c3dd (diff) | |
download | chromium_src-0e6a4c6d35b9081b2bbbba9b07591e64369e0604.zip chromium_src-0e6a4c6d35b9081b2bbbba9b07591e64369e0604.tar.gz chromium_src-0e6a4c6d35b9081b2bbbba9b07591e64369e0604.tar.bz2 |
Use SSLPrivateKey for testing client authentication
BUG=51132
Review URL: https://codereview.chromium.org/1639463003
Cr-Commit-Position: refs/heads/master@{#372422}
Diffstat (limited to 'net/socket')
-rw-r--r-- | net/socket/ssl_client_socket_openssl_unittest.cc | 267 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_unittest.cc | 119 |
2 files changed, 119 insertions, 267 deletions
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 |