OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/socket/ssl_client_socket.h" | 5 #include "net/socket/ssl_client_socket.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <string.h> | 8 #include <string.h> |
9 | 9 |
10 #include <openssl/bio.h> | 10 #include <openssl/bio.h> |
11 #include <openssl/bn.h> | 11 #include <openssl/bn.h> |
12 #include <openssl/evp.h> | 12 #include <openssl/evp.h> |
13 #include <openssl/pem.h> | 13 #include <openssl/pem.h> |
14 #include <openssl/rsa.h> | 14 #include <openssl/rsa.h> |
15 | 15 |
16 #include "base/file_util.h" | 16 #include "base/file_util.h" |
17 #include "base/files/file_path.h" | 17 #include "base/files/file_path.h" |
18 #include "base/memory/ref_counted.h" | 18 #include "base/memory/ref_counted.h" |
19 #include "base/memory/scoped_handle.h" | 19 #include "base/memory/scoped_handle.h" |
20 #include "base/message_loop/message_loop_proxy.h" | 20 #include "base/message_loop/message_loop_proxy.h" |
21 #include "base/run_loop.h" | |
wtc
2014/07/31 02:02:24
Do we need to include this?
| |
21 #include "base/values.h" | 22 #include "base/values.h" |
22 #include "crypto/openssl_util.h" | 23 #include "crypto/openssl_util.h" |
23 #include "net/base/address_list.h" | 24 #include "net/base/address_list.h" |
24 #include "net/base/io_buffer.h" | 25 #include "net/base/io_buffer.h" |
25 #include "net/base/net_errors.h" | 26 #include "net/base/net_errors.h" |
26 #include "net/base/net_log.h" | 27 #include "net/base/net_log.h" |
27 #include "net/base/net_log_unittest.h" | 28 #include "net/base/net_log_unittest.h" |
28 #include "net/base/test_completion_callback.h" | 29 #include "net/base/test_completion_callback.h" |
29 #include "net/base/test_data_directory.h" | 30 #include "net/base/test_data_directory.h" |
30 #include "net/cert/mock_cert_verifier.h" | 31 #include "net/cert/mock_cert_verifier.h" |
31 #include "net/cert/test_root_certs.h" | 32 #include "net/cert/test_root_certs.h" |
32 #include "net/dns/host_resolver.h" | 33 #include "net/dns/host_resolver.h" |
33 #include "net/http/transport_security_state.h" | 34 #include "net/http/transport_security_state.h" |
34 #include "net/socket/client_socket_factory.h" | 35 #include "net/socket/client_socket_factory.h" |
35 #include "net/socket/client_socket_handle.h" | 36 #include "net/socket/client_socket_handle.h" |
36 #include "net/socket/socket_test_util.h" | 37 #include "net/socket/socket_test_util.h" |
37 #include "net/socket/tcp_client_socket.h" | 38 #include "net/socket/tcp_client_socket.h" |
38 #include "net/ssl/openssl_client_key_store.h" | 39 #include "net/ssl/openssl_client_key_store.h" |
39 #include "net/ssl/ssl_cert_request_info.h" | 40 #include "net/ssl/ssl_cert_request_info.h" |
40 #include "net/ssl/ssl_config_service.h" | 41 #include "net/ssl/ssl_config_service.h" |
42 #include "net/socket/ssl_client_socket_test_util.cc" | |
wtc
2014/07/31 02:02:24
Delete this line. Note that you are including a .c
| |
41 #include "net/test/cert_test_util.h" | 43 #include "net/test/cert_test_util.h" |
42 #include "net/test/spawned_test_server/spawned_test_server.h" | 44 #include "net/test/spawned_test_server/spawned_test_server.h" |
43 #include "testing/gtest/include/gtest/gtest.h" | 45 #include "testing/gtest/include/gtest/gtest.h" |
44 #include "testing/platform_test.h" | 46 #include "testing/platform_test.h" |
45 | 47 |
46 namespace net { | 48 namespace net { |
47 | 49 |
48 namespace { | 50 namespace { |
49 | 51 |
50 // These client auth tests are currently dependent on OpenSSL's struct X509. | 52 // These client auth tests are currently dependent on OpenSSL's struct X509. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
91 } | 93 } |
92 pkey->reset(result); | 94 pkey->reset(result); |
93 return true; | 95 return true; |
94 } | 96 } |
95 | 97 |
96 class SSLClientSocketOpenSSLClientAuthTest : public PlatformTest { | 98 class SSLClientSocketOpenSSLClientAuthTest : public PlatformTest { |
97 public: | 99 public: |
98 SSLClientSocketOpenSSLClientAuthTest() | 100 SSLClientSocketOpenSSLClientAuthTest() |
99 : socket_factory_(net::ClientSocketFactory::GetDefaultFactory()), | 101 : socket_factory_(net::ClientSocketFactory::GetDefaultFactory()), |
100 cert_verifier_(new net::MockCertVerifier), | 102 cert_verifier_(new net::MockCertVerifier), |
101 transport_security_state_(new net::TransportSecurityState) { | 103 transport_security_state_(new net::TransportSecurityState), |
104 ran_handshake_completion_callback_(false) { | |
102 cert_verifier_->set_default_result(net::OK); | 105 cert_verifier_->set_default_result(net::OK); |
103 context_.cert_verifier = cert_verifier_.get(); | 106 context_.cert_verifier = cert_verifier_.get(); |
104 context_.transport_security_state = transport_security_state_.get(); | 107 context_.transport_security_state = transport_security_state_.get(); |
105 key_store_ = net::OpenSSLClientKeyStore::GetInstance(); | 108 key_store_ = net::OpenSSLClientKeyStore::GetInstance(); |
106 } | 109 } |
107 | 110 |
108 virtual ~SSLClientSocketOpenSSLClientAuthTest() { | 111 virtual ~SSLClientSocketOpenSSLClientAuthTest() { |
109 key_store_->Flush(); | 112 key_store_->Flush(); |
110 } | 113 } |
111 | 114 |
115 void RecordCompletedHandshake() { | |
116 ran_handshake_completion_callback_ = true; | |
117 printf("%s\n", "hi"); | |
wtc
2014/07/31 02:02:24
Delete this debug printf statement.
(By the way,
| |
118 } | |
119 | |
112 protected: | 120 protected: |
113 scoped_ptr<SSLClientSocket> CreateSSLClientSocket( | 121 scoped_ptr<SSLClientSocket> CreateSSLClientSocket( |
114 scoped_ptr<StreamSocket> transport_socket, | 122 scoped_ptr<StreamSocket> transport_socket, |
115 const HostPortPair& host_and_port, | 123 const HostPortPair& host_and_port, |
116 const SSLConfig& ssl_config) { | 124 const SSLConfig& ssl_config) { |
117 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | 125 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); |
118 connection->SetSocket(transport_socket.Pass()); | 126 connection->SetSocket(transport_socket.Pass()); |
119 return socket_factory_->CreateSSLClientSocket(connection.Pass(), | 127 return socket_factory_->CreateSSLClientSocket(connection.Pass(), |
120 host_and_port, | 128 host_and_port, |
121 ssl_config, | 129 ssl_config, |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
166 // |result| will retrieve the ::Connect() result value. | 174 // |result| will retrieve the ::Connect() result value. |
167 // Returns true on succes, false otherwise. Success means that the socket | 175 // Returns true on succes, false otherwise. Success means that the socket |
168 // could be created and its Connect() was called, not that the connection | 176 // could be created and its Connect() was called, not that the connection |
169 // itself was a success. | 177 // itself was a success. |
170 bool CreateAndConnectSSLClientSocket(SSLConfig& ssl_config, | 178 bool CreateAndConnectSSLClientSocket(SSLConfig& ssl_config, |
171 int* result) { | 179 int* result) { |
172 sock_ = CreateSSLClientSocket(transport_.Pass(), | 180 sock_ = CreateSSLClientSocket(transport_.Pass(), |
173 test_server_->host_port_pair(), | 181 test_server_->host_port_pair(), |
174 ssl_config); | 182 ssl_config); |
175 | 183 |
184 sock_->SetHandshakeCompletionCallback(base::Bind( | |
185 &SSLClientSocketOpenSSLClientAuthTest::RecordCompletedHandshake, | |
186 base::Unretained(this))); | |
187 | |
176 if (sock_->IsConnected()) { | 188 if (sock_->IsConnected()) { |
177 LOG(ERROR) << "SSL Socket prematurely connected"; | 189 LOG(ERROR) << "SSL Socket prematurely connected"; |
178 return false; | 190 return false; |
179 } | 191 } |
180 | 192 |
181 *result = callback_.GetResult(sock_->Connect(callback_.callback())); | 193 *result = callback_.GetResult(sock_->Connect(callback_.callback())); |
182 return true; | 194 return true; |
183 } | 195 } |
184 | 196 |
185 | 197 |
186 // Check that the client certificate was sent. | 198 // Check that the client certificate was sent. |
187 // Returns true on success. | 199 // Returns true on success. |
188 bool CheckSSLClientSocketSentCert() { | 200 bool CheckSSLClientSocketSentCert() { |
189 SSLInfo ssl_info; | 201 SSLInfo ssl_info; |
190 sock_->GetSSLInfo(&ssl_info); | 202 sock_->GetSSLInfo(&ssl_info); |
191 return ssl_info.client_cert_sent; | 203 return ssl_info.client_cert_sent; |
192 } | 204 } |
193 | 205 |
194 ClientSocketFactory* socket_factory_; | 206 ClientSocketFactory* socket_factory_; |
195 scoped_ptr<MockCertVerifier> cert_verifier_; | 207 scoped_ptr<MockCertVerifier> cert_verifier_; |
196 scoped_ptr<TransportSecurityState> transport_security_state_; | 208 scoped_ptr<TransportSecurityState> transport_security_state_; |
197 SSLClientSocketContext context_; | 209 SSLClientSocketContext context_; |
198 OpenSSLClientKeyStore* key_store_; | 210 OpenSSLClientKeyStore* key_store_; |
199 scoped_ptr<SpawnedTestServer> test_server_; | 211 scoped_ptr<SpawnedTestServer> test_server_; |
200 AddressList addr_; | 212 AddressList addr_; |
201 TestCompletionCallback callback_; | 213 TestCompletionCallback callback_; |
202 CapturingNetLog log_; | 214 CapturingNetLog log_; |
203 scoped_ptr<StreamSocket> transport_; | 215 scoped_ptr<StreamSocket> transport_; |
204 scoped_ptr<SSLClientSocket> sock_; | 216 scoped_ptr<SSLClientSocket> sock_; |
217 bool ran_handshake_completion_callback_; | |
205 }; | 218 }; |
206 | 219 |
207 // Connect to a server requesting client authentication, do not send | 220 // Connect to a server requesting client authentication, do not send |
208 // any client certificates. It should refuse the connection. | 221 // any client certificates. It should refuse the connection. |
209 TEST_F(SSLClientSocketOpenSSLClientAuthTest, NoCert) { | 222 TEST_F(SSLClientSocketOpenSSLClientAuthTest, NoCert) { |
210 SpawnedTestServer::SSLOptions ssl_options; | 223 SpawnedTestServer::SSLOptions ssl_options; |
211 ssl_options.request_client_certificate = true; | 224 ssl_options.request_client_certificate = true; |
212 | 225 |
213 ASSERT_TRUE(ConnectToTestServer(ssl_options)); | 226 ASSERT_TRUE(ConnectToTestServer(ssl_options)); |
214 | 227 |
215 base::FilePath certs_dir = GetTestCertsDirectory(); | 228 base::FilePath certs_dir = GetTestCertsDirectory(); |
216 SSLConfig ssl_config = kDefaultSSLConfig; | 229 SSLConfig ssl_config = kDefaultSSLConfig; |
217 | 230 |
218 int rv; | 231 int rv; |
219 ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); | 232 ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); |
220 | 233 |
221 EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); | 234 EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); |
222 EXPECT_FALSE(sock_->IsConnected()); | 235 EXPECT_FALSE(sock_->IsConnected()); |
236 EXPECT_TRUE(ran_handshake_completion_callback_); | |
223 } | 237 } |
224 | 238 |
225 // Connect to a server requesting client authentication, and send it | 239 // Connect to a server requesting client authentication, and send it |
226 // an empty certificate. It should refuse the connection. | 240 // an empty certificate. It should refuse the connection. |
227 TEST_F(SSLClientSocketOpenSSLClientAuthTest, SendEmptyCert) { | 241 TEST_F(SSLClientSocketOpenSSLClientAuthTest, SendEmptyCert) { |
228 SpawnedTestServer::SSLOptions ssl_options; | 242 SpawnedTestServer::SSLOptions ssl_options; |
229 ssl_options.request_client_certificate = true; | 243 ssl_options.request_client_certificate = true; |
230 ssl_options.client_authorities.push_back( | 244 ssl_options.client_authorities.push_back( |
231 GetTestClientCertsDirectory().AppendASCII("client_1_ca.pem")); | 245 GetTestClientCertsDirectory().AppendASCII("client_1_ca.pem")); |
232 | 246 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
270 ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); | 284 ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); |
271 | 285 |
272 EXPECT_EQ(OK, rv); | 286 EXPECT_EQ(OK, rv); |
273 EXPECT_TRUE(sock_->IsConnected()); | 287 EXPECT_TRUE(sock_->IsConnected()); |
274 | 288 |
275 EXPECT_TRUE(CheckSSLClientSocketSentCert()); | 289 EXPECT_TRUE(CheckSSLClientSocketSentCert()); |
276 | 290 |
277 sock_->Disconnect(); | 291 sock_->Disconnect(); |
278 EXPECT_FALSE(sock_->IsConnected()); | 292 EXPECT_FALSE(sock_->IsConnected()); |
279 } | 293 } |
294 | |
295 TEST_F(SSLClientSocketOpenSSLClientAuthTest, | |
296 CompletionCallbackIsRun_WithFailure) { | |
297 SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS, | |
298 SpawnedTestServer::kLocalhost, | |
299 base::FilePath()); | |
300 ASSERT_TRUE(test_server.Start()); | |
301 | |
302 AddressList addr; | |
303 ASSERT_TRUE(test_server.GetAddressList(&addr)); | |
304 | |
305 TestCompletionCallback callback; | |
306 scoped_ptr<StreamSocket> real_transport( | |
307 new TCPClientSocket(addr, NULL, NetLog::Source())); | |
308 scoped_ptr<SynchronousErrorStreamSocket> transport( | |
309 new SynchronousErrorStreamSocket(real_transport.Pass())); | |
310 int rv = callback.GetResult(transport->Connect(callback.callback())); | |
311 EXPECT_EQ(OK, rv); | |
312 | |
313 // Disable TLS False Start to avoid handshake non-determinism. | |
314 SSLConfig ssl_config; | |
315 ssl_config.false_start_enabled = false; | |
316 | |
317 SynchronousErrorStreamSocket* raw_transport = transport.get(); | |
318 scoped_ptr<SSLClientSocket> sock( | |
319 CreateSSLClientSocket(transport.PassAs<StreamSocket>(), | |
320 test_server.host_port_pair(), | |
321 ssl_config)); | |
322 | |
323 sock->SetHandshakeCompletionCallback(base::Bind( | |
324 &SSLClientSocketOpenSSLClientAuthTest::RecordCompletedHandshake, | |
325 base::Unretained(this))); | |
326 | |
327 rv = callback.GetResult(sock->Connect(callback.callback())); | |
328 EXPECT_EQ(OK, rv); | |
329 EXPECT_TRUE(sock->IsConnected()); | |
330 | |
331 const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; | |
332 static const int kRequestTextSize = | |
333 static_cast<int>(arraysize(request_text) - 1); | |
334 scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kRequestTextSize)); | |
335 memcpy(request_buffer->data(), request_text, kRequestTextSize); | |
336 | |
337 rv = callback.GetResult( | |
338 sock->Write(request_buffer.get(), kRequestTextSize, callback.callback())); | |
339 EXPECT_EQ(kRequestTextSize, rv); | |
340 | |
341 // Simulate an unclean/forcible shutdown. | |
342 raw_transport->SetNextReadError(ERR_CONNECTION_RESET); | |
343 | |
344 scoped_refptr<IOBuffer> buf(new IOBuffer(4096)); | |
345 | |
346 // Note: This test will hang if this bug has regressed. Simply checking that | |
347 // rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING is a legitimate | |
348 // result when using a dedicated task runner for NSS. | |
349 rv = callback.GetResult(sock->Read(buf.get(), 4096, callback.callback())); | |
350 | |
351 EXPECT_TRUE(ran_handshake_completion_callback_); | |
352 } | |
353 | |
354 TEST_F(SSLClientSocketOpenSSLClientAuthTest, | |
355 CompletionCallbackIsRun_WithFalseStartFailure) { | |
356 SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS, | |
357 SpawnedTestServer::kLocalhost, | |
358 base::FilePath()); | |
359 ASSERT_TRUE(test_server.Start()); | |
360 | |
361 AddressList addr; | |
362 ASSERT_TRUE(test_server.GetAddressList(&addr)); | |
363 | |
364 TestCompletionCallback callback; | |
365 scoped_ptr<StreamSocket> real_transport( | |
366 new TCPClientSocket(addr, NULL, NetLog::Source())); | |
367 // Note: |error_socket|'s ownership is handed to |transport|, but a pointer | |
368 // is retained in order to configure additional errors. | |
369 scoped_ptr<SynchronousErrorStreamSocket> error_socket( | |
370 new SynchronousErrorStreamSocket(real_transport.Pass())); | |
371 SynchronousErrorStreamSocket* raw_error_socket = error_socket.get(); | |
372 scoped_ptr<FakeBlockingStreamSocket> transport( | |
373 new FakeBlockingStreamSocket(error_socket.PassAs<StreamSocket>())); | |
374 FakeBlockingStreamSocket* raw_transport = transport.get(); | |
375 int rv = callback.GetResult(transport->Connect(callback.callback())); | |
376 EXPECT_EQ(OK, rv); | |
377 | |
378 SSLConfig ssl_config; | |
379 ssl_config.false_start_enabled = true; | |
380 | |
381 scoped_ptr<SSLClientSocket> sock( | |
382 CreateSSLClientSocket(transport.PassAs<StreamSocket>(), | |
383 test_server.host_port_pair(), | |
384 ssl_config)); | |
385 | |
386 sock->SetHandshakeCompletionCallback(base::Bind( | |
387 &SSLClientSocketOpenSSLClientAuthTest::RecordCompletedHandshake, | |
388 base::Unretained(this))); | |
389 | |
390 rv = callback.GetResult(sock->Connect(callback.callback())); | |
391 EXPECT_EQ(OK, rv); | |
392 EXPECT_TRUE(sock->IsConnected()); | |
393 | |
394 const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; | |
395 static const int kRequestTextSize = | |
396 static_cast<int>(arraysize(request_text) - 1); | |
397 scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kRequestTextSize)); | |
398 memcpy(request_buffer->data(), request_text, kRequestTextSize); | |
399 | |
400 // Simulate an unclean/forcible shutdown on the underlying socket. | |
401 // However, simulate this error asynchronously. | |
402 raw_error_socket->SetNextWriteError(ERR_CONNECTION_RESET); | |
403 raw_transport->BlockWrite(); | |
404 | |
405 // This write should complete synchronously, because the TLS ciphertext | |
406 // can be created and placed into the outgoing buffers independent of the | |
407 // underlying transport. | |
408 rv = callback.GetResult( | |
409 sock->Write(request_buffer.get(), kRequestTextSize, callback.callback())); | |
410 EXPECT_EQ(kRequestTextSize, rv); | |
411 | |
412 scoped_refptr<IOBuffer> buf(new IOBuffer(4096)); | |
413 | |
414 rv = sock->Read(buf.get(), 4096, callback.callback()); | |
415 EXPECT_EQ(ERR_IO_PENDING, rv); | |
416 | |
417 // Now unblock the outgoing request, having it fail with the connection | |
418 // being reset. | |
419 raw_transport->UnblockWrite(); | |
420 | |
421 // Note: This will cause an inifite loop if this bug has regressed. Simply | |
422 // checking that rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING | |
423 // is a legitimate result when using a dedicated task runner for NSS. | |
424 rv = callback.GetResult(rv); | |
425 | |
426 EXPECT_TRUE(ran_handshake_completion_callback_); | |
427 } | |
428 | |
429 // Connect to a server requesting client authentication. Send it a | |
430 // matching certificate. It should allow the connection. | |
431 TEST_F(SSLClientSocketOpenSSLClientAuthTest, | |
432 CompletionCallbackIsRun_WithSuccess) { | |
433 SpawnedTestServer::SSLOptions ssl_options; | |
434 ssl_options.request_client_certificate = true; | |
435 ssl_options.client_authorities.push_back( | |
436 GetTestClientCertsDirectory().AppendASCII("client_1_ca.pem")); | |
437 | |
438 ASSERT_TRUE(ConnectToTestServer(ssl_options)); | |
439 | |
440 base::FilePath certs_dir = GetTestCertsDirectory(); | |
441 SSLConfig ssl_config = kDefaultSSLConfig; | |
442 ssl_config.send_client_cert = true; | |
443 ssl_config.client_cert = ImportCertFromFile(certs_dir, "client_1.pem"); | |
444 | |
445 // This is required to ensure that signing works with the client | |
446 // certificate's private key. | |
447 OpenSSLClientKeyStore::ScopedEVP_PKEY client_private_key; | |
448 ASSERT_TRUE(LoadPrivateKeyOpenSSL(certs_dir.AppendASCII("client_1.key"), | |
449 &client_private_key)); | |
450 EXPECT_TRUE(RecordPrivateKey(ssl_config, client_private_key.get())); | |
451 | |
452 int rv; | |
453 ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); | |
454 EXPECT_EQ(OK, rv); | |
455 | |
456 EXPECT_TRUE(sock_->IsConnected()); | |
457 | |
458 EXPECT_TRUE(ran_handshake_completion_callback_); | |
459 } | |
460 | |
280 #endif // defined(USE_OPENSSL_CERTS) | 461 #endif // defined(USE_OPENSSL_CERTS) |
281 | 462 |
282 } // namespace | 463 } // namespace |
464 | |
283 } // namespace net | 465 } // namespace net |
OLD | NEW |