ssl_client_socket_unittest.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
1// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/socket/ssl_client_socket.h"
6
7#include "net/base/address_list.h"
8#include "net/base/host_resolver.h"
9#include "net/base/io_buffer.h"
10#include "net/base/net_log.h"
11#include "net/base/net_log_unittest.h"
12#include "net/base/net_errors.h"
13#include "net/base/ssl_config_service.h"
14#include "net/base/test_completion_callback.h"
15#include "net/socket/client_socket_factory.h"
16#include "net/socket/socket_test_util.h"
17#include "net/socket/tcp_client_socket.h"
18#include "net/test/test_server.h"
19#include "testing/gtest/include/gtest/gtest.h"
20#include "testing/platform_test.h"
21
22//-----------------------------------------------------------------------------
23
24const net::SSLConfig kDefaultSSLConfig;
25
26class SSLClientSocketTest : public PlatformTest {
27 public:
28  SSLClientSocketTest()
29      : socket_factory_(net::ClientSocketFactory::GetDefaultFactory()) {
30  }
31
32 protected:
33  net::ClientSocketFactory* socket_factory_;
34};
35
36//-----------------------------------------------------------------------------
37
38// LogContainsSSLConnectEndEvent returns true if the given index in the given
39// log is an SSL connect end event. The NSS sockets will cork in an attempt to
40// merge the first application data record with the Finished message when false
41// starting. However, in order to avoid the server timing out the handshake,
42// they'll give up waiting for application data and send the Finished after a
43// timeout. This means that an SSL connect end event may appear as a socket
44// write.
45static bool LogContainsSSLConnectEndEvent(
46    const net::CapturingNetLog::EntryList& log, int i) {
47  return  net::LogContainsEndEvent(log, -1, net::NetLog::TYPE_SSL_CONNECT) ||
48          net::LogContainsEvent(log, -1, net::NetLog::TYPE_SOCKET_BYTES_SENT,
49                                net::NetLog::PHASE_NONE);
50};
51
52TEST_F(SSLClientSocketTest, Connect) {
53  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
54  ASSERT_TRUE(test_server.Start());
55
56  net::AddressList addr;
57  ASSERT_TRUE(test_server.GetAddressList(&addr));
58
59  TestCompletionCallback callback;
60  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
61  net::ClientSocket* transport = new net::TCPClientSocket(
62      addr, &log, net::NetLog::Source());
63  int rv = transport->Connect(&callback);
64  if (rv == net::ERR_IO_PENDING)
65    rv = callback.WaitForResult();
66  EXPECT_EQ(net::OK, rv);
67
68  scoped_ptr<net::SSLClientSocket> sock(
69      socket_factory_->CreateSSLClientSocket(
70          transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
71
72  EXPECT_FALSE(sock->IsConnected());
73
74  rv = sock->Connect(&callback);
75  EXPECT_TRUE(net::LogContainsBeginEvent(
76      log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
77  if (rv == net::ERR_IO_PENDING)
78    rv = callback.WaitForResult();
79  EXPECT_EQ(net::OK, rv);
80  EXPECT_TRUE(sock->IsConnected());
81  EXPECT_TRUE(LogContainsSSLConnectEndEvent(log.entries(), -1));
82
83  sock->Disconnect();
84  EXPECT_FALSE(sock->IsConnected());
85}
86
87TEST_F(SSLClientSocketTest, ConnectExpired) {
88  net::TestServer::HTTPSOptions https_options(
89      net::TestServer::HTTPSOptions::CERT_EXPIRED);
90  net::TestServer test_server(https_options, FilePath());
91  ASSERT_TRUE(test_server.Start());
92
93  net::AddressList addr;
94  ASSERT_TRUE(test_server.GetAddressList(&addr));
95
96  TestCompletionCallback callback;
97  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
98  net::ClientSocket* transport = new net::TCPClientSocket(
99      addr, &log, net::NetLog::Source());
100  int rv = transport->Connect(&callback);
101  if (rv == net::ERR_IO_PENDING)
102    rv = callback.WaitForResult();
103  EXPECT_EQ(net::OK, rv);
104
105  scoped_ptr<net::SSLClientSocket> sock(
106      socket_factory_->CreateSSLClientSocket(
107          transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
108
109  EXPECT_FALSE(sock->IsConnected());
110
111  rv = sock->Connect(&callback);
112  EXPECT_TRUE(net::LogContainsBeginEvent(
113      log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
114  if (rv == net::ERR_IO_PENDING)
115    rv = callback.WaitForResult();
116
117  EXPECT_EQ(net::ERR_CERT_DATE_INVALID, rv);
118
119  // Rather than testing whether or not the underlying socket is connected,
120  // test that the handshake has finished. This is because it may be
121  // desirable to disconnect the socket before showing a user prompt, since
122  // the user may take indefinitely long to respond.
123  EXPECT_TRUE(LogContainsSSLConnectEndEvent(log.entries(), -1));
124}
125
126TEST_F(SSLClientSocketTest, ConnectMismatched) {
127  net::TestServer::HTTPSOptions https_options(
128      net::TestServer::HTTPSOptions::CERT_MISMATCHED_NAME);
129  net::TestServer test_server(https_options, FilePath());
130  ASSERT_TRUE(test_server.Start());
131
132  net::AddressList addr;
133  ASSERT_TRUE(test_server.GetAddressList(&addr));
134
135  TestCompletionCallback callback;
136  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
137  net::ClientSocket* transport = new net::TCPClientSocket(
138      addr, &log, net::NetLog::Source());
139  int rv = transport->Connect(&callback);
140  if (rv == net::ERR_IO_PENDING)
141    rv = callback.WaitForResult();
142  EXPECT_EQ(net::OK, rv);
143
144  scoped_ptr<net::SSLClientSocket> sock(
145      socket_factory_->CreateSSLClientSocket(
146          transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
147
148  EXPECT_FALSE(sock->IsConnected());
149
150  rv = sock->Connect(&callback);
151
152  EXPECT_TRUE(net::LogContainsBeginEvent(
153      log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
154  if (rv == net::ERR_IO_PENDING)
155    rv = callback.WaitForResult();
156
157  EXPECT_EQ(net::ERR_CERT_COMMON_NAME_INVALID, rv);
158
159  // Rather than testing whether or not the underlying socket is connected,
160  // test that the handshake has finished. This is because it may be
161  // desirable to disconnect the socket before showing a user prompt, since
162  // the user may take indefinitely long to respond.
163  EXPECT_TRUE(LogContainsSSLConnectEndEvent(log.entries(), -1));
164}
165
166// Attempt to connect to a page which requests a client certificate. It should
167// return an error code on connect.
168// Flaky: http://crbug.com/54445
169TEST_F(SSLClientSocketTest, FLAKY_ConnectClientAuthCertRequested) {
170  net::TestServer::HTTPSOptions https_options;
171  https_options.request_client_certificate = true;
172  net::TestServer test_server(https_options, FilePath());
173  ASSERT_TRUE(test_server.Start());
174
175  net::AddressList addr;
176  ASSERT_TRUE(test_server.GetAddressList(&addr));
177
178  TestCompletionCallback callback;
179  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
180  net::ClientSocket* transport = new net::TCPClientSocket(
181      addr, &log, net::NetLog::Source());
182  int rv = transport->Connect(&callback);
183  if (rv == net::ERR_IO_PENDING)
184    rv = callback.WaitForResult();
185  EXPECT_EQ(net::OK, rv);
186
187  scoped_ptr<net::SSLClientSocket> sock(
188      socket_factory_->CreateSSLClientSocket(
189          transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
190
191  EXPECT_FALSE(sock->IsConnected());
192
193  rv = sock->Connect(&callback);
194  EXPECT_TRUE(net::LogContainsBeginEvent(
195      log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
196  if (rv == net::ERR_IO_PENDING)
197    rv = callback.WaitForResult();
198
199  EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
200  EXPECT_FALSE(sock->IsConnected());
201}
202
203// Connect to a server requesting optional client authentication. Send it a
204// null certificate. It should allow the connection.
205//
206// TODO(davidben): Also test providing an actual certificate.
207TEST_F(SSLClientSocketTest, ConnectClientAuthSendNullCert) {
208  net::TestServer::HTTPSOptions https_options;
209  https_options.request_client_certificate = true;
210  net::TestServer test_server(https_options, FilePath());
211  ASSERT_TRUE(test_server.Start());
212
213  net::AddressList addr;
214  ASSERT_TRUE(test_server.GetAddressList(&addr));
215
216  TestCompletionCallback callback;
217  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
218  net::ClientSocket* transport = new net::TCPClientSocket(
219      addr, &log, net::NetLog::Source());
220  int rv = transport->Connect(&callback);
221  if (rv == net::ERR_IO_PENDING)
222    rv = callback.WaitForResult();
223  EXPECT_EQ(net::OK, rv);
224
225  net::SSLConfig ssl_config = kDefaultSSLConfig;
226  ssl_config.send_client_cert = true;
227  ssl_config.client_cert = NULL;
228
229  scoped_ptr<net::SSLClientSocket> sock(
230      socket_factory_->CreateSSLClientSocket(
231          transport, test_server.host_port_pair(), ssl_config, NULL));
232
233  EXPECT_FALSE(sock->IsConnected());
234
235  // Our test server accepts certificate-less connections.
236  // TODO(davidben): Add a test which requires them and verify the error.
237  rv = sock->Connect(&callback);
238  EXPECT_TRUE(net::LogContainsBeginEvent(
239      log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
240  if (rv == net::ERR_IO_PENDING)
241    rv = callback.WaitForResult();
242
243  EXPECT_EQ(net::OK, rv);
244  EXPECT_TRUE(sock->IsConnected());
245  EXPECT_TRUE(LogContainsSSLConnectEndEvent(log.entries(), -1));
246
247  sock->Disconnect();
248  EXPECT_FALSE(sock->IsConnected());
249}
250
251// TODO(wtc): Add unit tests for IsConnectedAndIdle:
252//   - Server closes an SSL connection (with a close_notify alert message).
253//   - Server closes the underlying TCP connection directly.
254//   - Server sends data unexpectedly.
255
256TEST_F(SSLClientSocketTest, Read) {
257  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
258  ASSERT_TRUE(test_server.Start());
259
260  net::AddressList addr;
261  ASSERT_TRUE(test_server.GetAddressList(&addr));
262
263  TestCompletionCallback callback;
264  net::ClientSocket* transport = new net::TCPClientSocket(
265      addr, NULL, net::NetLog::Source());
266  int rv = transport->Connect(&callback);
267  if (rv == net::ERR_IO_PENDING)
268    rv = callback.WaitForResult();
269  EXPECT_EQ(net::OK, rv);
270
271  scoped_ptr<net::SSLClientSocket> sock(
272      socket_factory_->CreateSSLClientSocket(
273          transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
274
275  rv = sock->Connect(&callback);
276  if (rv == net::ERR_IO_PENDING)
277    rv = callback.WaitForResult();
278  EXPECT_EQ(net::OK, rv);
279  EXPECT_TRUE(sock->IsConnected());
280
281  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
282  scoped_refptr<net::IOBuffer> request_buffer(
283      new net::IOBuffer(arraysize(request_text) - 1));
284  memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
285
286  rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
287  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
288
289  if (rv == net::ERR_IO_PENDING)
290    rv = callback.WaitForResult();
291  EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
292
293  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
294  for (;;) {
295    rv = sock->Read(buf, 4096, &callback);
296    EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
297
298    if (rv == net::ERR_IO_PENDING)
299      rv = callback.WaitForResult();
300
301    EXPECT_GE(rv, 0);
302    if (rv <= 0)
303      break;
304  }
305}
306
307// Test the full duplex mode, with Read and Write pending at the same time.
308// This test also serves as a regression test for http://crbug.com/29815.
309TEST_F(SSLClientSocketTest, Read_FullDuplex) {
310  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
311  ASSERT_TRUE(test_server.Start());
312
313  net::AddressList addr;
314  ASSERT_TRUE(test_server.GetAddressList(&addr));
315
316  TestCompletionCallback callback;  // Used for everything except Write.
317  TestCompletionCallback callback2;  // Used for Write only.
318
319  net::ClientSocket* transport = new net::TCPClientSocket(
320      addr, NULL, net::NetLog::Source());
321  int rv = transport->Connect(&callback);
322  if (rv == net::ERR_IO_PENDING)
323    rv = callback.WaitForResult();
324  EXPECT_EQ(net::OK, rv);
325
326  scoped_ptr<net::SSLClientSocket> sock(
327      socket_factory_->CreateSSLClientSocket(
328          transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
329
330  rv = sock->Connect(&callback);
331  if (rv == net::ERR_IO_PENDING)
332    rv = callback.WaitForResult();
333  EXPECT_EQ(net::OK, rv);
334  EXPECT_TRUE(sock->IsConnected());
335
336  // Issue a "hanging" Read first.
337  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
338  rv = sock->Read(buf, 4096, &callback);
339  // We haven't written the request, so there should be no response yet.
340  ASSERT_EQ(net::ERR_IO_PENDING, rv);
341
342  // Write the request.
343  // The request is padded with a User-Agent header to a size that causes the
344  // memio circular buffer (4k bytes) in SSLClientSocketNSS to wrap around.
345  // This tests the fix for http://crbug.com/29815.
346  std::string request_text = "GET / HTTP/1.1\r\nUser-Agent: long browser name ";
347  for (int i = 0; i < 3800; ++i)
348    request_text.push_back('*');
349  request_text.append("\r\n\r\n");
350  scoped_refptr<net::IOBuffer> request_buffer(
351      new net::StringIOBuffer(request_text));
352
353  rv = sock->Write(request_buffer, request_text.size(), &callback2);
354  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
355
356  if (rv == net::ERR_IO_PENDING)
357    rv = callback2.WaitForResult();
358  EXPECT_EQ(static_cast<int>(request_text.size()), rv);
359
360  // Now get the Read result.
361  rv = callback.WaitForResult();
362  EXPECT_GT(rv, 0);
363}
364
365TEST_F(SSLClientSocketTest, Read_SmallChunks) {
366  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
367  ASSERT_TRUE(test_server.Start());
368
369  net::AddressList addr;
370  ASSERT_TRUE(test_server.GetAddressList(&addr));
371
372  TestCompletionCallback callback;
373  net::ClientSocket* transport = new net::TCPClientSocket(
374      addr, NULL, net::NetLog::Source());
375  int rv = transport->Connect(&callback);
376  if (rv == net::ERR_IO_PENDING)
377    rv = callback.WaitForResult();
378  EXPECT_EQ(net::OK, rv);
379
380  scoped_ptr<net::SSLClientSocket> sock(
381      socket_factory_->CreateSSLClientSocket(
382          transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
383
384  rv = sock->Connect(&callback);
385  if (rv == net::ERR_IO_PENDING)
386    rv = callback.WaitForResult();
387  EXPECT_EQ(net::OK, rv);
388
389  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
390  scoped_refptr<net::IOBuffer> request_buffer(
391      new net::IOBuffer(arraysize(request_text) - 1));
392  memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
393
394  rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
395  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
396
397  if (rv == net::ERR_IO_PENDING)
398    rv = callback.WaitForResult();
399  EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
400
401  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(1));
402  for (;;) {
403    rv = sock->Read(buf, 1, &callback);
404    EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
405
406    if (rv == net::ERR_IO_PENDING)
407      rv = callback.WaitForResult();
408
409    EXPECT_GE(rv, 0);
410    if (rv <= 0)
411      break;
412  }
413}
414
415TEST_F(SSLClientSocketTest, Read_Interrupted) {
416  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
417  ASSERT_TRUE(test_server.Start());
418
419  net::AddressList addr;
420  ASSERT_TRUE(test_server.GetAddressList(&addr));
421
422  TestCompletionCallback callback;
423  net::ClientSocket* transport = new net::TCPClientSocket(
424      addr, NULL, net::NetLog::Source());
425  int rv = transport->Connect(&callback);
426  if (rv == net::ERR_IO_PENDING)
427    rv = callback.WaitForResult();
428  EXPECT_EQ(net::OK, rv);
429
430  scoped_ptr<net::SSLClientSocket> sock(
431      socket_factory_->CreateSSLClientSocket(
432          transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
433
434  rv = sock->Connect(&callback);
435  if (rv == net::ERR_IO_PENDING)
436    rv = callback.WaitForResult();
437  EXPECT_EQ(net::OK, rv);
438
439  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
440  scoped_refptr<net::IOBuffer> request_buffer(
441      new net::IOBuffer(arraysize(request_text) - 1));
442  memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
443
444  rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
445  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
446
447  if (rv == net::ERR_IO_PENDING)
448    rv = callback.WaitForResult();
449  EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
450
451  // Do a partial read and then exit.  This test should not crash!
452  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(512));
453  rv = sock->Read(buf, 512, &callback);
454  EXPECT_TRUE(rv > 0 || rv == net::ERR_IO_PENDING);
455
456  if (rv == net::ERR_IO_PENDING)
457    rv = callback.WaitForResult();
458
459  EXPECT_GT(rv, 0);
460}
461
462// Regression test for http://crbug.com/42538
463TEST_F(SSLClientSocketTest, PrematureApplicationData) {
464  net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
465  ASSERT_TRUE(test_server.Start());
466
467  net::AddressList addr;
468  TestCompletionCallback callback;
469
470  static const unsigned char application_data[] = {
471    0x17, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00, 0x46, 0x03, 0x01, 0x4b,
472    0xc2, 0xf8, 0xb2, 0xc1, 0x56, 0x42, 0xb9, 0x57, 0x7f, 0xde, 0x87, 0x46,
473    0xf7, 0xa3, 0x52, 0x42, 0x21, 0xf0, 0x13, 0x1c, 0x9c, 0x83, 0x88, 0xd6,
474    0x93, 0x0c, 0xf6, 0x36, 0x30, 0x05, 0x7e, 0x20, 0xb5, 0xb5, 0x73, 0x36,
475    0x53, 0x83, 0x0a, 0xfc, 0x17, 0x63, 0xbf, 0xa0, 0xe4, 0x42, 0x90, 0x0d,
476    0x2f, 0x18, 0x6d, 0x20, 0xd8, 0x36, 0x3f, 0xfc, 0xe6, 0x01, 0xfa, 0x0f,
477    0xa5, 0x75, 0x7f, 0x09, 0x00, 0x04, 0x00, 0x16, 0x03, 0x01, 0x11, 0x57,
478    0x0b, 0x00, 0x11, 0x53, 0x00, 0x11, 0x50, 0x00, 0x06, 0x22, 0x30, 0x82,
479    0x06, 0x1e, 0x30, 0x82, 0x05, 0x06, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
480    0x0a
481  };
482
483  // All reads and writes complete synchronously (async=false).
484  net::MockRead data_reads[] = {
485    net::MockRead(false, reinterpret_cast<const char*>(application_data),
486                  arraysize(application_data)),
487    net::MockRead(false, net::OK),
488  };
489
490  net::StaticSocketDataProvider data(data_reads, arraysize(data_reads),
491                                     NULL, 0);
492
493  net::ClientSocket* transport =
494      new net::MockTCPClientSocket(addr, NULL, &data);
495  int rv = transport->Connect(&callback);
496  if (rv == net::ERR_IO_PENDING)
497    rv = callback.WaitForResult();
498  EXPECT_EQ(net::OK, rv);
499
500  scoped_ptr<net::SSLClientSocket> sock(
501      socket_factory_->CreateSSLClientSocket(
502          transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
503
504  rv = sock->Connect(&callback);
505  EXPECT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv);
506}
507
508#if defined(USE_OPENSSL)
509// TODO(rsleevi): Not implemented for Schannel or OpenSSL. Schannel is
510// controlled by the SSL client socket factory, rather than a define, so it
511// cannot be conditionally disabled here. As Schannel is only used when
512// performing client authentication, it will not be tested here.
513#define MAYBE_CipherSuiteDisables DISABLED_CipherSuiteDisables
514#else
515#define MAYBE_CipherSuiteDisables CipherSuiteDisables
516#endif
517TEST_F(SSLClientSocketTest, MAYBE_CipherSuiteDisables) {
518  // Rather than exhaustively disabling every RC4 ciphersuite defined at
519  // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml,
520  // only disabling those cipher suites that the test server actually
521  // implements.
522  const uint16 kCiphersToDisable[] = {
523    0x0005,  // TLS_RSA_WITH_RC4_128_SHA
524  };
525
526  net::TestServer::HTTPSOptions https_options;
527  // Enable only RC4 on the test server.
528  https_options.bulk_ciphers =
529      net::TestServer::HTTPSOptions::BULK_CIPHER_RC4;
530  net::TestServer test_server(https_options, FilePath());
531  ASSERT_TRUE(test_server.Start());
532
533  net::AddressList addr;
534  ASSERT_TRUE(test_server.GetAddressList(&addr));
535
536  TestCompletionCallback callback;
537  net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
538  net::ClientSocket* transport = new net::TCPClientSocket(
539      addr, &log, net::NetLog::Source());
540  int rv = transport->Connect(&callback);
541  if (rv == net::ERR_IO_PENDING)
542    rv = callback.WaitForResult();
543  EXPECT_EQ(net::OK, rv);
544
545  net::SSLConfig ssl_config;
546  for (size_t i = 0; i < arraysize(kCiphersToDisable); ++i)
547    ssl_config.disabled_cipher_suites.push_back(kCiphersToDisable[i]);
548
549  scoped_ptr<net::SSLClientSocket> sock(
550      socket_factory_->CreateSSLClientSocket(
551          transport, test_server.host_port_pair(), ssl_config, NULL));
552
553  EXPECT_FALSE(sock->IsConnected());
554
555  rv = sock->Connect(&callback);
556  EXPECT_TRUE(net::LogContainsBeginEvent(
557      log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
558
559  // NSS has special handling that maps a handshake_failure alert received
560  // immediately after a client_hello to be a mismatched cipher suite error,
561  // leading to ERR_SSL_VERSION_OR_CIPHER_MISMATCH. When using OpenSSL or
562  // Secure Transport (OS X), the handshake_failure is bubbled up without any
563  // interpretation, leading to ERR_SSL_PROTOCOL_ERROR. Either way, a failure
564  // indicates that no cipher suite was negotiated with the test server.
565  if (rv == net::ERR_IO_PENDING)
566    rv = callback.WaitForResult();
567  EXPECT_TRUE(rv == net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH ||
568              rv == net::ERR_SSL_PROTOCOL_ERROR);
569  // The exact ordering differs between SSLClientSocketNSS (which issues an
570  // extra read) and SSLClientSocketMac (which does not). Just make sure the
571  // error appears somewhere in the log.
572  net::ExpectLogContainsSomewhere(log.entries(), 0,
573                                  net::NetLog::TYPE_SSL_HANDSHAKE_ERROR,
574                                  net::NetLog::PHASE_NONE);
575
576  // We cannot test sock->IsConnected(), as the NSS implementation disconnects
577  // the socket when it encounters an error, whereas other implementations
578  // leave it connected.
579  EXPECT_TRUE(LogContainsSSLConnectEndEvent(log.entries(), -1));
580}
581