1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/socket/ssl_client_socket.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/address_list.h"
821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "net/base/cert_verifier.h"
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/host_resolver.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/io_buffer.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_log.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_log_unittest.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/ssl_config_service.h"
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/test_completion_callback.h"
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/socket/client_socket_factory.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/socket/socket_test_util.h"
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/socket/tcp_client_socket.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/test/test_server.h"
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "testing/gtest/include/gtest/gtest.h"
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "testing/platform_test.h"
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//-----------------------------------------------------------------------------
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst net::SSLConfig kDefaultSSLConfig;
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass SSLClientSocketTest : public PlatformTest {
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SSLClientSocketTest()
3021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      : socket_factory_(net::ClientSocketFactory::GetDefaultFactory()),
3121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        cert_verifier_(new net::CertVerifier) {
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott protected:
3521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  net::SSLClientSocket* CreateSSLClientSocket(
3621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      net::ClientSocket* transport_socket,
3721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      const net::HostPortPair& host_and_port,
3821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      const net::SSLConfig& ssl_config) {
3921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return socket_factory_->CreateSSLClientSocket(transport_socket,
4021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                  host_and_port,
4121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                  ssl_config,
4221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                  NULL,
4321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                  cert_verifier_.get());
4421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
4521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::ClientSocketFactory* socket_factory_;
4721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  scoped_ptr<net::CertVerifier> cert_verifier_;
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//-----------------------------------------------------------------------------
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
52731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// LogContainsSSLConnectEndEvent returns true if the given index in the given
53731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// log is an SSL connect end event. The NSS sockets will cork in an attempt to
54731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// merge the first application data record with the Finished message when false
55731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// starting. However, in order to avoid the server timing out the handshake,
56731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// they'll give up waiting for application data and send the Finished after a
57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// timeout. This means that an SSL connect end event may appear as a socket
58731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// write.
59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstatic bool LogContainsSSLConnectEndEvent(
60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const net::CapturingNetLog::EntryList& log, int i) {
613f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  return net::LogContainsEndEvent(log, i, net::NetLog::TYPE_SSL_CONNECT) ||
623f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen         net::LogContainsEvent(log, i, net::NetLog::TYPE_SOCKET_BYTES_SENT,
63731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                net::NetLog::PHASE_NONE);
64731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick};
65731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(SSLClientSocketTest, Connect) {
673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.Start());
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::AddressList addr;
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.GetAddressList(&addr));
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TestCompletionCallback callback;
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::ClientSocket* transport = new net::TCPClientSocket(
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      addr, &log, net::NetLog::Source());
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = transport->Connect(&callback);
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(net::OK, rv);
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_ptr<net::SSLClientSocket> sock(
834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      socket_factory_->CreateSSLClientSocket(
8421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          transport, test_server.host_port_pair(), kDefaultSSLConfig,
8521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          NULL, cert_verifier_.get()));
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_FALSE(sock->IsConnected());
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = sock->Connect(&callback);
9021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
9121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  net::CapturingNetLog::EntryList entries;
9221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(net::LogContainsBeginEvent(
9421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (rv == net::ERR_IO_PENDING)
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(net::OK, rv);
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(sock->IsConnected());
9921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
10021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  sock->Disconnect();
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_FALSE(sock->IsConnected());
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(SSLClientSocketTest, ConnectExpired) {
107513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net::TestServer::HTTPSOptions https_options(
108513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      net::TestServer::HTTPSOptions::CERT_EXPIRED);
109513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net::TestServer test_server(https_options, FilePath());
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.Start());
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::AddressList addr;
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.GetAddressList(&addr));
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TestCompletionCallback callback;
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::ClientSocket* transport = new net::TCPClientSocket(
1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      addr, &log, net::NetLog::Source());
1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = transport->Connect(&callback);
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(net::OK, rv);
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_ptr<net::SSLClientSocket> sock(
12521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CreateSSLClientSocket(transport, test_server.host_port_pair(),
12621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                            kDefaultSSLConfig));
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_FALSE(sock->IsConnected());
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = sock->Connect(&callback);
13121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
13221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  net::CapturingNetLog::EntryList entries;
13321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(net::LogContainsBeginEvent(
13521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
1364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (rv == net::ERR_IO_PENDING)
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(net::ERR_CERT_DATE_INVALID, rv);
1404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Rather than testing whether or not the underlying socket is connected,
1424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // test that the handshake has finished. This is because it may be
1434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // desirable to disconnect the socket before showing a user prompt, since
1444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // the user may take indefinitely long to respond.
14521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
14621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(SSLClientSocketTest, ConnectMismatched) {
150513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net::TestServer::HTTPSOptions https_options(
151513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      net::TestServer::HTTPSOptions::CERT_MISMATCHED_NAME);
152513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net::TestServer test_server(https_options, FilePath());
1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.Start());
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::AddressList addr;
1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.GetAddressList(&addr));
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TestCompletionCallback callback;
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::ClientSocket* transport = new net::TCPClientSocket(
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      addr, &log, net::NetLog::Source());
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = transport->Connect(&callback);
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(net::OK, rv);
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_ptr<net::SSLClientSocket> sock(
16821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CreateSSLClientSocket(transport, test_server.host_port_pair(),
16921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                            kDefaultSSLConfig));
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_FALSE(sock->IsConnected());
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = sock->Connect(&callback);
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  net::CapturingNetLog::EntryList entries;
17621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(net::LogContainsBeginEvent(
17821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
1794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (rv == net::ERR_IO_PENDING)
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(net::ERR_CERT_COMMON_NAME_INVALID, rv);
1834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Rather than testing whether or not the underlying socket is connected,
1854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // test that the handshake has finished. This is because it may be
1864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // desirable to disconnect the socket before showing a user prompt, since
1874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // the user may take indefinitely long to respond.
18821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
18921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Attempt to connect to a page which requests a client certificate. It should
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// return an error code on connect.
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTEST_F(SSLClientSocketTest, ConnectClientAuthCertRequested) {
195513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net::TestServer::HTTPSOptions https_options;
196513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  https_options.request_client_certificate = true;
197513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net::TestServer test_server(https_options, FilePath());
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.Start());
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::AddressList addr;
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.GetAddressList(&addr));
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TestCompletionCallback callback;
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::ClientSocket* transport = new net::TCPClientSocket(
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      addr, &log, net::NetLog::Source());
2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = transport->Connect(&callback);
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (rv == net::ERR_IO_PENDING)
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    rv = callback.WaitForResult();
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ(net::OK, rv);
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<net::SSLClientSocket> sock(
21321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CreateSSLClientSocket(transport, test_server.host_port_pair(),
21421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                            kDefaultSSLConfig));
2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_FALSE(sock->IsConnected());
2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  rv = sock->Connect(&callback);
21921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
22021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  net::CapturingNetLog::EntryList entries;
22121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_TRUE(net::LogContainsBeginEvent(
22321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
2244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (rv == net::ERR_IO_PENDING)
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    rv = callback.WaitForResult();
2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
22721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Because we prematurely kill the handshake at CertificateRequest,
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the server may still send data (notably the ServerHelloDone)
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // after the error is returned. As a result, the SSL_CONNECT may not
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // be the last entry. See http://crbug.com/54445. We use
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // ExpectLogContainsSomewhere instead of
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // LogContainsSSLConnectEndEvent to avoid assuming, e.g., only one
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // extra read instead of two. This occurs before the handshake ends,
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // so the corking logic of LogContainsSSLConnectEndEvent isn't
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // necessary.
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  //
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(davidben): When SSL_RestartHandshakeAfterCertReq in NSS is
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // fixed and we can respond to the first CertificateRequest
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // without closing the socket, add a unit test for sending the
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // certificate. This test may still be useful as we'll want to close
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the socket on a timeout if the user takes a long time to pick a
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // cert. Related bug: https://bugzilla.mozilla.org/show_bug.cgi?id=542832
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  net::ExpectLogContainsSomewhere(
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      entries, 0, net::NetLog::TYPE_SSL_CONNECT, net::NetLog::PHASE_END);
2464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
2474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_FALSE(sock->IsConnected());
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Connect to a server requesting optional client authentication. Send it a
2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// null certificate. It should allow the connection.
2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick//
2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// TODO(davidben): Also test providing an actual certificate.
2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickTEST_F(SSLClientSocketTest, ConnectClientAuthSendNullCert) {
255513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net::TestServer::HTTPSOptions https_options;
256513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  https_options.request_client_certificate = true;
257513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net::TestServer test_server(https_options, FilePath());
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.Start());
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::AddressList addr;
2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.GetAddressList(&addr));
2623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TestCompletionCallback callback;
2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::ClientSocket* transport = new net::TCPClientSocket(
2663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      addr, &log, net::NetLog::Source());
2673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = transport->Connect(&callback);
2683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (rv == net::ERR_IO_PENDING)
2693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    rv = callback.WaitForResult();
2703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ(net::OK, rv);
2713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::SSLConfig ssl_config = kDefaultSSLConfig;
2733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ssl_config.send_client_cert = true;
2743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ssl_config.client_cert = NULL;
2753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<net::SSLClientSocket> sock(
27721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CreateSSLClientSocket(transport, test_server.host_port_pair(),
27821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                            ssl_config));
2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_FALSE(sock->IsConnected());
2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Our test server accepts certificate-less connections.
2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(davidben): Add a test which requires them and verify the error.
2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  rv = sock->Connect(&callback);
28521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
28621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  net::CapturingNetLog::EntryList entries;
28721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
2883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_TRUE(net::LogContainsBeginEvent(
28921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
2904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (rv == net::ERR_IO_PENDING)
2913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    rv = callback.WaitForResult();
2923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(net::OK, rv);
2943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_TRUE(sock->IsConnected());
29521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
29621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
2973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  sock->Disconnect();
2993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_FALSE(sock->IsConnected());
3003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// TODO(wtc): Add unit tests for IsConnectedAndIdle:
303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   - Server closes an SSL connection (with a close_notify alert message).
304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   - Server closes the underlying TCP connection directly.
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   - Server sends data unexpectedly.
306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(SSLClientSocketTest, Read) {
3083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
3093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.Start());
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::AddressList addr;
3123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.GetAddressList(&addr));
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
3143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TestCompletionCallback callback;
3153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::ClientSocket* transport = new net::TCPClientSocket(
3163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      addr, NULL, net::NetLog::Source());
3173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = transport->Connect(&callback);
318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(net::OK, rv);
321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_ptr<net::SSLClientSocket> sock(
32321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CreateSSLClientSocket(transport, test_server.host_port_pair(),
32421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                            kDefaultSSLConfig));
325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = sock->Connect(&callback);
3274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (rv == net::ERR_IO_PENDING)
328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
3294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(net::OK, rv);
330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(sock->IsConnected());
331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
333513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<net::IOBuffer> request_buffer(
334513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      new net::IOBuffer(arraysize(request_text) - 1));
335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
344513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (;;) {
346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = sock->Read(buf, 4096, &callback);
347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (rv == net::ERR_IO_PENDING)
350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      rv = callback.WaitForResult();
351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_GE(rv, 0);
353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (rv <= 0)
354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      break;
355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Test the full duplex mode, with Read and Write pending at the same time.
359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// This test also serves as a regression test for http://crbug.com/29815.
360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(SSLClientSocketTest, Read_FullDuplex) {
3613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
3623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.Start());
363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::AddressList addr;
3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.GetAddressList(&addr));
3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
367c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  TestCompletionCallback callback;  // Used for everything except Write.
368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  TestCompletionCallback callback2;  // Used for Write only.
369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
3703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::ClientSocket* transport = new net::TCPClientSocket(
3713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      addr, NULL, net::NetLog::Source());
3723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = transport->Connect(&callback);
373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(net::OK, rv);
376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_ptr<net::SSLClientSocket> sock(
378731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      socket_factory_->CreateSSLClientSocket(
37921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          transport, test_server.host_port_pair(), kDefaultSSLConfig,
38021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          NULL, cert_verifier_.get()));
381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = sock->Connect(&callback);
3834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (rv == net::ERR_IO_PENDING)
384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
3854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(net::OK, rv);
386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(sock->IsConnected());
387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Issue a "hanging" Read first.
389513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  rv = sock->Read(buf, 4096, &callback);
391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We haven't written the request, so there should be no response yet.
392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ASSERT_EQ(net::ERR_IO_PENDING, rv);
393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Write the request.
395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The request is padded with a User-Agent header to a size that causes the
396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // memio circular buffer (4k bytes) in SSLClientSocketNSS to wrap around.
397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // This tests the fix for http://crbug.com/29815.
398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::string request_text = "GET / HTTP/1.1\r\nUser-Agent: long browser name ";
399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < 3800; ++i)
400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    request_text.push_back('*');
401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  request_text.append("\r\n\r\n");
402513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<net::IOBuffer> request_buffer(
403513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      new net::StringIOBuffer(request_text));
404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  rv = sock->Write(request_buffer, request_text.size(), &callback2);
406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback2.WaitForResult();
410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(static_cast<int>(request_text.size()), rv);
411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Now get the Read result.
413c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  rv = callback.WaitForResult();
414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_GT(rv, 0);
415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(SSLClientSocketTest, Read_SmallChunks) {
4183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
4193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.Start());
420c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
421c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::AddressList addr;
4223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.GetAddressList(&addr));
423c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
4243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TestCompletionCallback callback;
4253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::ClientSocket* transport = new net::TCPClientSocket(
4263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      addr, NULL, net::NetLog::Source());
4273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = transport->Connect(&callback);
428c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
429c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
430c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(net::OK, rv);
431c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
432c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_ptr<net::SSLClientSocket> sock(
43321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CreateSSLClientSocket(transport, test_server.host_port_pair(),
43421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                            kDefaultSSLConfig));
435c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = sock->Connect(&callback);
4374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (rv == net::ERR_IO_PENDING)
438c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
4394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(net::OK, rv);
440c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
441c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
442513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<net::IOBuffer> request_buffer(
443513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      new net::IOBuffer(arraysize(request_text) - 1));
444c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
445c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
446c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
447c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
448c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
449c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
450c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
451c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
452c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
453513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(1));
454c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (;;) {
455c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = sock->Read(buf, 1, &callback);
456c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
457c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
458c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (rv == net::ERR_IO_PENDING)
459c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      rv = callback.WaitForResult();
460c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
461c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_GE(rv, 0);
462c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (rv <= 0)
463c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      break;
464c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
465c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
466c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
467c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(SSLClientSocketTest, Read_Interrupted) {
4683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
4693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.Start());
470c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
471c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::AddressList addr;
4723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.GetAddressList(&addr));
473c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
4743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TestCompletionCallback callback;
4753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::ClientSocket* transport = new net::TCPClientSocket(
4763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      addr, NULL, net::NetLog::Source());
4773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = transport->Connect(&callback);
478c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
479c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
480c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(net::OK, rv);
481c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
482c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_ptr<net::SSLClientSocket> sock(
48321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CreateSSLClientSocket(transport, test_server.host_port_pair(),
48421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                            kDefaultSSLConfig));
485c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = sock->Connect(&callback);
4874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (rv == net::ERR_IO_PENDING)
488c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
4894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(net::OK, rv);
490c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
491c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
492513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<net::IOBuffer> request_buffer(
493513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      new net::IOBuffer(arraysize(request_text) - 1));
494c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
495c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
496c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
497c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
498c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
499c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
500c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
501c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
502c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
503c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Do a partial read and then exit.  This test should not crash!
504513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(512));
505c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  rv = sock->Read(buf, 512, &callback);
506c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(rv > 0 || rv == net::ERR_IO_PENDING);
507c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
508c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == net::ERR_IO_PENDING)
509c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = callback.WaitForResult();
510c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
511c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_GT(rv, 0);
512c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Regression test for http://crbug.com/42538
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SSLClientSocketTest, PrematureApplicationData) {
5163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
5173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(test_server.Start());
5183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::AddressList addr;
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TestCompletionCallback callback;
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const unsigned char application_data[] = {
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x17, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00, 0x46, 0x03, 0x01, 0x4b,
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0xc2, 0xf8, 0xb2, 0xc1, 0x56, 0x42, 0xb9, 0x57, 0x7f, 0xde, 0x87, 0x46,
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0xf7, 0xa3, 0x52, 0x42, 0x21, 0xf0, 0x13, 0x1c, 0x9c, 0x83, 0x88, 0xd6,
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x93, 0x0c, 0xf6, 0x36, 0x30, 0x05, 0x7e, 0x20, 0xb5, 0xb5, 0x73, 0x36,
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x53, 0x83, 0x0a, 0xfc, 0x17, 0x63, 0xbf, 0xa0, 0xe4, 0x42, 0x90, 0x0d,
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x2f, 0x18, 0x6d, 0x20, 0xd8, 0x36, 0x3f, 0xfc, 0xe6, 0x01, 0xfa, 0x0f,
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0xa5, 0x75, 0x7f, 0x09, 0x00, 0x04, 0x00, 0x16, 0x03, 0x01, 0x11, 0x57,
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x0b, 0x00, 0x11, 0x53, 0x00, 0x11, 0x50, 0x00, 0x06, 0x22, 0x30, 0x82,
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x06, 0x1e, 0x30, 0x82, 0x05, 0x06, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x0a
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // All reads and writes complete synchronously (async=false).
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::MockRead data_reads[] = {
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net::MockRead(false, reinterpret_cast<const char*>(application_data),
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  arraysize(application_data)),
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net::MockRead(false, net::OK),
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::StaticSocketDataProvider data(data_reads, arraysize(data_reads),
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     NULL, 0);
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::ClientSocket* transport =
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new net::MockTCPClientSocket(addr, NULL, &data);
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = transport->Connect(&callback);
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv == net::ERR_IO_PENDING)
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = callback.WaitForResult();
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(net::OK, rv);
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<net::SSLClientSocket> sock(
55321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CreateSSLClientSocket(transport, test_server.host_port_pair(),
55421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                            kDefaultSSLConfig));
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = sock->Connect(&callback);
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv);
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
5594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
56021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// TODO(rsleevi): Not implemented for Schannel. As Schannel is only used when
5614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// performing client authentication, it will not be tested here.
56221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTEST_F(SSLClientSocketTest, CipherSuiteDisables) {
5634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Rather than exhaustively disabling every RC4 ciphersuite defined at
5644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml,
5654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // only disabling those cipher suites that the test server actually
5664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // implements.
5674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const uint16 kCiphersToDisable[] = {
5684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    0x0005,  // TLS_RSA_WITH_RC4_128_SHA
5694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  };
5704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
5714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  net::TestServer::HTTPSOptions https_options;
5724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Enable only RC4 on the test server.
5734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  https_options.bulk_ciphers =
5744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      net::TestServer::HTTPSOptions::BULK_CIPHER_RC4;
5754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  net::TestServer test_server(https_options, FilePath());
5764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ASSERT_TRUE(test_server.Start());
5774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
5784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  net::AddressList addr;
5794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ASSERT_TRUE(test_server.GetAddressList(&addr));
5804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
5814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  TestCompletionCallback callback;
5824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
5834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  net::ClientSocket* transport = new net::TCPClientSocket(
5844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      addr, &log, net::NetLog::Source());
5854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  int rv = transport->Connect(&callback);
5864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (rv == net::ERR_IO_PENDING)
5874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    rv = callback.WaitForResult();
5884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_EQ(net::OK, rv);
5894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
5904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  net::SSLConfig ssl_config;
5914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  for (size_t i = 0; i < arraysize(kCiphersToDisable); ++i)
5924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    ssl_config.disabled_cipher_suites.push_back(kCiphersToDisable[i]);
5934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
5944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  scoped_ptr<net::SSLClientSocket> sock(
59521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CreateSSLClientSocket(transport, test_server.host_port_pair(),
59621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                            ssl_config));
5974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
5984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_FALSE(sock->IsConnected());
5994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
6004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  rv = sock->Connect(&callback);
60121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  net::CapturingNetLog::EntryList entries;
60221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
6034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_TRUE(net::LogContainsBeginEvent(
60421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
6054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
6064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // NSS has special handling that maps a handshake_failure alert received
6074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // immediately after a client_hello to be a mismatched cipher suite error,
6084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // leading to ERR_SSL_VERSION_OR_CIPHER_MISMATCH. When using OpenSSL or
6094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Secure Transport (OS X), the handshake_failure is bubbled up without any
6104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // interpretation, leading to ERR_SSL_PROTOCOL_ERROR. Either way, a failure
6114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // indicates that no cipher suite was negotiated with the test server.
6124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (rv == net::ERR_IO_PENDING)
6134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    rv = callback.WaitForResult();
6144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXPECT_TRUE(rv == net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH ||
6154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch              rv == net::ERR_SSL_PROTOCOL_ERROR);
6164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // The exact ordering differs between SSLClientSocketNSS (which issues an
6174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // extra read) and SSLClientSocketMac (which does not). Just make sure the
6184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // error appears somewhere in the log.
61921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  log.GetEntries(&entries);
62021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  net::ExpectLogContainsSomewhere(entries, 0,
6214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                  net::NetLog::TYPE_SSL_HANDSHAKE_ERROR,
6224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                  net::NetLog::PHASE_NONE);
6234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
6244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // We cannot test sock->IsConnected(), as the NSS implementation disconnects
6254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // the socket when it encounters an error, whereas other implementations
6264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // leave it connected.
6273f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // Because this an error that the test server is mutually aware of, as opposed
6283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // to being an error such as a certificate name mismatch, which is
6293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // client-only, the exact index of the SSL connect end depends on how
6303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // quickly the test server closes the underlying socket. If the test server
6313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // closes before the IO message loop pumps messages, there may be a 0-byte
6323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // Read event in the NetLog due to TCPClientSocket picking up the EOF. As a
6333f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // result, the SSL connect end event will be the second-to-last entry,
6343f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // rather than the last entry.
6353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1) ||
6363f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen              LogContainsSSLConnectEndEvent(entries, -2));
6374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
638