Index: net/socket/ssl_client_socket_unittest.cc |
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc |
index 05844cd0ef327d6c01ccbc847826cd1e3e0a7b76..8d8e2fd942af1a170d3c63ebb8b34a209e235be6 100644 |
--- a/net/socket/ssl_client_socket_unittest.cc |
+++ b/net/socket/ssl_client_socket_unittest.cc |
@@ -22,6 +22,7 @@ |
#include "net/socket/client_socket_handle.h" |
#include "net/socket/socket_test_util.h" |
#include "net/socket/tcp_client_socket.h" |
+#include "net/ssl/default_server_bound_cert_store.h" |
#include "net/ssl/ssl_cert_request_info.h" |
#include "net/ssl/ssl_config_service.h" |
#include "net/test/cert_test_util.h" |
@@ -557,6 +558,35 @@ class DeleteSocketCallback : public TestCompletionCallbackBase { |
DISALLOW_COPY_AND_ASSIGN(DeleteSocketCallback); |
}; |
+// A ServerBoundCertStore that always returns an error when asked for a |
+// certificate. |
+class FailingServerBoundCertStore : public ServerBoundCertStore { |
+ virtual int GetServerBoundCert(const std::string& server_identifier, |
+ base::Time* expiration_time, |
+ std::string* private_key_result, |
+ std::string* cert_result, |
+ const GetCertCallback& callback) OVERRIDE { |
+ return ERR_UNEXPECTED; |
+ } |
+ virtual void SetServerBoundCert(const std::string& server_identifier, |
+ base::Time creation_time, |
+ base::Time expiration_time, |
+ const std::string& private_key, |
+ const std::string& cert) OVERRIDE {} |
+ virtual void DeleteServerBoundCert(const std::string& server_identifier, |
+ const base::Closure& completion_callback) |
+ OVERRIDE {} |
+ virtual void DeleteAllCreatedBetween(base::Time delete_begin, |
+ base::Time delete_end, |
+ const base::Closure& completion_callback) |
+ OVERRIDE {} |
+ virtual void DeleteAll(const base::Closure& completion_callback) OVERRIDE {} |
+ virtual void GetAllServerBoundCerts(const GetCertListCallback& callback) |
+ OVERRIDE {} |
+ virtual int GetCertCount() OVERRIDE { return 0; } |
+ virtual void SetForceKeepSessionState() OVERRIDE {} |
+}; |
+ |
class SSLClientSocketTest : public PlatformTest { |
public: |
SSLClientSocketTest() |
@@ -569,6 +599,30 @@ class SSLClientSocketTest : public PlatformTest { |
} |
protected: |
+ // Sets up a TCP connection to a HTTPS server. To actually do the SSL |
+ // handshake, follow up with call to CreateAndConnectSSLClientSocket() below. |
+ 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; |
+ } |
+ |
scoped_ptr<SSLClientSocket> CreateSSLClientSocket( |
scoped_ptr<StreamSocket> transport_socket, |
const HostPortPair& host_and_port, |
@@ -579,10 +633,39 @@ class SSLClientSocketTest : public PlatformTest { |
connection.Pass(), host_and_port, ssl_config, context_); |
} |
+ // Create an SSLClientSocket object and use it to connect to a test |
+ // server, then wait for connection results. This must be called after |
+ // a successful ConnectToTestServer() call. |
+ // |ssl_config| the SSL configuration to use. |
+ // |result| will retrieve the ::Connect() result value. |
+ // Returns true on success, 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(SSLConfig& ssl_config, int* result) { |
+ sock_ = CreateSSLClientSocket( |
+ transport_.Pass(), 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; |
+ } |
+ |
ClientSocketFactory* socket_factory_; |
scoped_ptr<MockCertVerifier> cert_verifier_; |
scoped_ptr<TransportSecurityState> transport_security_state_; |
SSLClientSocketContext context_; |
+ scoped_ptr<SSLClientSocket> sock_; |
+ CapturingNetLog log_; |
+ |
+ private: |
+ scoped_ptr<StreamSocket> transport_; |
+ scoped_ptr<SpawnedTestServer> test_server_; |
+ TestCompletionCallback callback_; |
+ AddressList addr_; |
}; |
// Verifies the correctness of GetSSLCertRequestInfo. |
@@ -713,6 +796,25 @@ class SSLClientSocketFalseStartTest : public SSLClientSocketTest { |
} |
}; |
+class SSLClientSocketChannelIDTest : public SSLClientSocketTest { |
+ protected: |
+ void EnableChannelID() { |
+ cert_service_.reset( |
+ new ServerBoundCertService(new DefaultServerBoundCertStore(NULL), |
+ base::MessageLoopProxy::current())); |
+ context_.server_bound_cert_service = cert_service_.get(); |
+ } |
+ |
+ void EnableFailingChannelID() { |
+ cert_service_.reset(new ServerBoundCertService( |
+ new FailingServerBoundCertStore(), base::MessageLoopProxy::current())); |
+ context_.server_bound_cert_service = cert_service_.get(); |
+ } |
+ |
+ private: |
+ scoped_ptr<ServerBoundCertService> cert_service_; |
+}; |
+ |
//----------------------------------------------------------------------------- |
// LogContainsSSLConnectEndEvent returns true if the given index in the given |
@@ -2363,4 +2465,47 @@ TEST_F(SSLClientSocketFalseStartTest, NoForwardSecrecy) { |
TestFalseStart(server_options, client_config, false); |
} |
+// Connect to a server using channel id. It should allow the connection. |
+TEST_F(SSLClientSocketChannelIDTest, SendChannelID) { |
+ SpawnedTestServer::SSLOptions ssl_options; |
+ |
+ ASSERT_TRUE(ConnectToTestServer(ssl_options)); |
+ |
+ EnableChannelID(); |
+ SSLConfig ssl_config = kDefaultSSLConfig; |
+ ssl_config.channel_id_enabled = true; |
+ |
+ int rv; |
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); |
+ |
+ EXPECT_EQ(OK, rv); |
+ EXPECT_TRUE(sock_->IsConnected()); |
+ EXPECT_TRUE(sock_->WasChannelIDSent()); |
+ |
+ sock_->Disconnect(); |
+ EXPECT_FALSE(sock_->IsConnected()); |
+} |
+ |
+// Connect to a server using channel id but without sending a key. It should |
+// fail. |
+TEST_F(SSLClientSocketChannelIDTest, FailingChannelID) { |
+ SpawnedTestServer::SSLOptions ssl_options; |
+ |
+ ASSERT_TRUE(ConnectToTestServer(ssl_options)); |
+ |
+ EnableFailingChannelID(); |
+ SSLConfig ssl_config = kDefaultSSLConfig; |
+ ssl_config.channel_id_enabled = true; |
+ |
+ int rv; |
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); |
+ |
+ // TODO(haavardm@opera.com): Due to differences in threading, Linux returns |
+ // ERR_UNEXPECTED while Mac and Windows return ERR_PROTOCOL_ERROR. Accept all |
+ // error codes for now. |
+ // http://crbug.com/373670 |
+ EXPECT_NE(OK, rv); |
+ EXPECT_FALSE(sock_->IsConnected()); |
+} |
+ |
} // namespace net |