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