Chromium Code Reviews| Index: net/socket/ssl_client_socket_openssl_unittest.cc |
| diff --git a/net/socket/ssl_client_socket_openssl_unittest.cc b/net/socket/ssl_client_socket_openssl_unittest.cc |
| index 00cf9f35cb4b612841207513f112780a405880df..1dfc48a24646d11d9c597c5b4dd5429feda6cab9 100644 |
| --- a/net/socket/ssl_client_socket_openssl_unittest.cc |
| +++ b/net/socket/ssl_client_socket_openssl_unittest.cc |
| @@ -18,6 +18,7 @@ |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_handle.h" |
| #include "base/message_loop/message_loop_proxy.h" |
| +#include "base/run_loop.h" |
|
wtc
2014/07/31 02:02:24
Do we need to include this?
|
| #include "base/values.h" |
| #include "crypto/openssl_util.h" |
| #include "net/base/address_list.h" |
| @@ -38,6 +39,7 @@ |
| #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/socket/ssl_client_socket_test_util.cc" |
|
wtc
2014/07/31 02:02:24
Delete this line. Note that you are including a .c
|
| #include "net/test/cert_test_util.h" |
| #include "net/test/spawned_test_server/spawned_test_server.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| @@ -98,7 +100,8 @@ class SSLClientSocketOpenSSLClientAuthTest : public PlatformTest { |
| SSLClientSocketOpenSSLClientAuthTest() |
| : socket_factory_(net::ClientSocketFactory::GetDefaultFactory()), |
| cert_verifier_(new net::MockCertVerifier), |
| - transport_security_state_(new net::TransportSecurityState) { |
| + transport_security_state_(new net::TransportSecurityState), |
| + ran_handshake_completion_callback_(false) { |
| cert_verifier_->set_default_result(net::OK); |
| context_.cert_verifier = cert_verifier_.get(); |
| context_.transport_security_state = transport_security_state_.get(); |
| @@ -109,6 +112,11 @@ class SSLClientSocketOpenSSLClientAuthTest : public PlatformTest { |
| key_store_->Flush(); |
| } |
| + void RecordCompletedHandshake() { |
| + ran_handshake_completion_callback_ = true; |
| + printf("%s\n", "hi"); |
|
wtc
2014/07/31 02:02:24
Delete this debug printf statement.
(By the way,
|
| + } |
| + |
| protected: |
| scoped_ptr<SSLClientSocket> CreateSSLClientSocket( |
| scoped_ptr<StreamSocket> transport_socket, |
| @@ -173,6 +181,10 @@ class SSLClientSocketOpenSSLClientAuthTest : public PlatformTest { |
| test_server_->host_port_pair(), |
| ssl_config); |
| + sock_->SetHandshakeCompletionCallback(base::Bind( |
| + &SSLClientSocketOpenSSLClientAuthTest::RecordCompletedHandshake, |
| + base::Unretained(this))); |
| + |
| if (sock_->IsConnected()) { |
| LOG(ERROR) << "SSL Socket prematurely connected"; |
| return false; |
| @@ -202,6 +214,7 @@ class SSLClientSocketOpenSSLClientAuthTest : public PlatformTest { |
| CapturingNetLog log_; |
| scoped_ptr<StreamSocket> transport_; |
| scoped_ptr<SSLClientSocket> sock_; |
| + bool ran_handshake_completion_callback_; |
| }; |
| // Connect to a server requesting client authentication, do not send |
| @@ -220,6 +233,7 @@ TEST_F(SSLClientSocketOpenSSLClientAuthTest, NoCert) { |
| EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); |
| EXPECT_FALSE(sock_->IsConnected()); |
| + EXPECT_TRUE(ran_handshake_completion_callback_); |
| } |
| // Connect to a server requesting client authentication, and send it |
| @@ -277,7 +291,175 @@ TEST_F(SSLClientSocketOpenSSLClientAuthTest, SendGoodCert) { |
| sock_->Disconnect(); |
| EXPECT_FALSE(sock_->IsConnected()); |
| } |
| + |
| +TEST_F(SSLClientSocketOpenSSLClientAuthTest, |
| + CompletionCallbackIsRun_WithFailure) { |
| + SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS, |
| + SpawnedTestServer::kLocalhost, |
| + base::FilePath()); |
| + ASSERT_TRUE(test_server.Start()); |
| + |
| + AddressList addr; |
| + ASSERT_TRUE(test_server.GetAddressList(&addr)); |
| + |
| + TestCompletionCallback callback; |
| + scoped_ptr<StreamSocket> real_transport( |
| + new TCPClientSocket(addr, NULL, NetLog::Source())); |
| + scoped_ptr<SynchronousErrorStreamSocket> transport( |
| + new SynchronousErrorStreamSocket(real_transport.Pass())); |
| + int rv = callback.GetResult(transport->Connect(callback.callback())); |
| + EXPECT_EQ(OK, rv); |
| + |
| + // Disable TLS False Start to avoid handshake non-determinism. |
| + SSLConfig ssl_config; |
| + ssl_config.false_start_enabled = false; |
| + |
| + SynchronousErrorStreamSocket* raw_transport = transport.get(); |
| + scoped_ptr<SSLClientSocket> sock( |
| + CreateSSLClientSocket(transport.PassAs<StreamSocket>(), |
| + test_server.host_port_pair(), |
| + ssl_config)); |
| + |
| + sock->SetHandshakeCompletionCallback(base::Bind( |
| + &SSLClientSocketOpenSSLClientAuthTest::RecordCompletedHandshake, |
| + base::Unretained(this))); |
| + |
| + rv = callback.GetResult(sock->Connect(callback.callback())); |
| + EXPECT_EQ(OK, rv); |
| + EXPECT_TRUE(sock->IsConnected()); |
| + |
| + const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; |
| + static const int kRequestTextSize = |
| + static_cast<int>(arraysize(request_text) - 1); |
| + scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kRequestTextSize)); |
| + memcpy(request_buffer->data(), request_text, kRequestTextSize); |
| + |
| + rv = callback.GetResult( |
| + sock->Write(request_buffer.get(), kRequestTextSize, callback.callback())); |
| + EXPECT_EQ(kRequestTextSize, rv); |
| + |
| + // Simulate an unclean/forcible shutdown. |
| + raw_transport->SetNextReadError(ERR_CONNECTION_RESET); |
| + |
| + scoped_refptr<IOBuffer> buf(new IOBuffer(4096)); |
| + |
| + // Note: This test will hang if this bug has regressed. Simply checking that |
| + // rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING is a legitimate |
| + // result when using a dedicated task runner for NSS. |
| + rv = callback.GetResult(sock->Read(buf.get(), 4096, callback.callback())); |
| + |
| + EXPECT_TRUE(ran_handshake_completion_callback_); |
| +} |
| + |
| +TEST_F(SSLClientSocketOpenSSLClientAuthTest, |
| + CompletionCallbackIsRun_WithFalseStartFailure) { |
| + SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS, |
| + SpawnedTestServer::kLocalhost, |
| + base::FilePath()); |
| + ASSERT_TRUE(test_server.Start()); |
| + |
| + AddressList addr; |
| + ASSERT_TRUE(test_server.GetAddressList(&addr)); |
| + |
| + TestCompletionCallback callback; |
| + scoped_ptr<StreamSocket> real_transport( |
| + new TCPClientSocket(addr, NULL, NetLog::Source())); |
| + // Note: |error_socket|'s ownership is handed to |transport|, but a pointer |
| + // is retained in order to configure additional errors. |
| + scoped_ptr<SynchronousErrorStreamSocket> error_socket( |
| + new SynchronousErrorStreamSocket(real_transport.Pass())); |
| + SynchronousErrorStreamSocket* raw_error_socket = error_socket.get(); |
| + scoped_ptr<FakeBlockingStreamSocket> transport( |
| + new FakeBlockingStreamSocket(error_socket.PassAs<StreamSocket>())); |
| + FakeBlockingStreamSocket* raw_transport = transport.get(); |
| + int rv = callback.GetResult(transport->Connect(callback.callback())); |
| + EXPECT_EQ(OK, rv); |
| + |
| + SSLConfig ssl_config; |
| + ssl_config.false_start_enabled = true; |
| + |
| + scoped_ptr<SSLClientSocket> sock( |
| + CreateSSLClientSocket(transport.PassAs<StreamSocket>(), |
| + test_server.host_port_pair(), |
| + ssl_config)); |
| + |
| + sock->SetHandshakeCompletionCallback(base::Bind( |
| + &SSLClientSocketOpenSSLClientAuthTest::RecordCompletedHandshake, |
| + base::Unretained(this))); |
| + |
| + rv = callback.GetResult(sock->Connect(callback.callback())); |
| + EXPECT_EQ(OK, rv); |
| + EXPECT_TRUE(sock->IsConnected()); |
| + |
| + const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; |
| + static const int kRequestTextSize = |
| + static_cast<int>(arraysize(request_text) - 1); |
| + scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kRequestTextSize)); |
| + memcpy(request_buffer->data(), request_text, kRequestTextSize); |
| + |
| + // Simulate an unclean/forcible shutdown on the underlying socket. |
| + // However, simulate this error asynchronously. |
| + raw_error_socket->SetNextWriteError(ERR_CONNECTION_RESET); |
| + raw_transport->BlockWrite(); |
| + |
| + // This write should complete synchronously, because the TLS ciphertext |
| + // can be created and placed into the outgoing buffers independent of the |
| + // underlying transport. |
| + rv = callback.GetResult( |
| + sock->Write(request_buffer.get(), kRequestTextSize, callback.callback())); |
| + EXPECT_EQ(kRequestTextSize, rv); |
| + |
| + scoped_refptr<IOBuffer> buf(new IOBuffer(4096)); |
| + |
| + rv = sock->Read(buf.get(), 4096, callback.callback()); |
| + EXPECT_EQ(ERR_IO_PENDING, rv); |
| + |
| + // Now unblock the outgoing request, having it fail with the connection |
| + // being reset. |
| + raw_transport->UnblockWrite(); |
| + |
| + // Note: This will cause an inifite loop if this bug has regressed. Simply |
| + // checking that rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING |
| + // is a legitimate result when using a dedicated task runner for NSS. |
| + rv = callback.GetResult(rv); |
| + |
| + EXPECT_TRUE(ran_handshake_completion_callback_); |
| +} |
| + |
| +// Connect to a server requesting client authentication. Send it a |
| +// matching certificate. It should allow the connection. |
| +TEST_F(SSLClientSocketOpenSSLClientAuthTest, |
| + CompletionCallbackIsRun_WithSuccess) { |
| + 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 = kDefaultSSLConfig; |
| + 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. |
| + OpenSSLClientKeyStore::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())); |
| + |
| + int rv; |
| + ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); |
| + EXPECT_EQ(OK, rv); |
| + |
| + EXPECT_TRUE(sock_->IsConnected()); |
| + |
| + EXPECT_TRUE(ran_handshake_completion_callback_); |
| +} |
| + |
| #endif // defined(USE_OPENSSL_CERTS) |
| } // namespace |
| + |
| } // namespace net |