OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 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/http/http_network_transaction.h" | 5 #include "net/http/http_network_transaction.h" |
6 | 6 |
7 #include <math.h> // ceil | 7 #include <math.h> // ceil |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
12 #include "base/file_path.h" | 12 #include "base/file_path.h" |
13 #include "base/file_util.h" | 13 #include "base/file_util.h" |
14 #include "base/scoped_ptr.h" | 14 #include "base/scoped_ptr.h" |
| 15 #include "base/time.h" |
15 #include "base/utf_string_conversions.h" | 16 #include "base/utf_string_conversions.h" |
16 #include "net/base/auth.h" | 17 #include "net/base/auth.h" |
17 #include "net/base/capturing_net_log.h" | 18 #include "net/base/capturing_net_log.h" |
18 #include "net/base/completion_callback.h" | 19 #include "net/base/completion_callback.h" |
19 #include "net/base/mock_host_resolver.h" | 20 #include "net/base/mock_host_resolver.h" |
20 #include "net/base/net_log.h" | 21 #include "net/base/net_log.h" |
21 #include "net/base/net_log_unittest.h" | 22 #include "net/base/net_log_unittest.h" |
22 #include "net/base/request_priority.h" | 23 #include "net/base/request_priority.h" |
23 #include "net/base/ssl_cert_request_info.h" | 24 #include "net/base/ssl_cert_request_info.h" |
24 #include "net/base/ssl_config_service_defaults.h" | 25 #include "net/base/ssl_config_service_defaults.h" |
(...skipping 8431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8456 // Now that the new handshake has failed, ensure that the client | 8457 // Now that the new handshake has failed, ensure that the client |
8457 // certificate was removed from the client auth cache. | 8458 // certificate was removed from the client auth cache. |
8458 ASSERT_EQ(net::ERR_PROXY_CONNECTION_FAILED, rv); | 8459 ASSERT_EQ(net::ERR_PROXY_CONNECTION_FAILED, rv); |
8459 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("proxy:70", | 8460 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("proxy:70", |
8460 &client_cert)); | 8461 &client_cert)); |
8461 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | 8462 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", |
8462 &client_cert)); | 8463 &client_cert)); |
8463 } | 8464 } |
8464 } | 8465 } |
8465 | 8466 |
| 8467 // Tests that the client certificate used to authenticate with an HTTPS proxy |
| 8468 // is different than the client certificate used to authenticate to an SSL |
| 8469 // endpoint, and that the HTTPS proxy certificate will not be sent to the SSL |
| 8470 // endpoint. |
| 8471 TEST_F(HttpNetworkTransactionTest, HTTPSProxyAuthAndSSLClientAuth) { |
| 8472 SessionDependencies session_deps( |
| 8473 ProxyService::CreateFixed("https://proxy:70")); |
| 8474 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); |
| 8475 session_deps.net_log = log.bound().net_log(); |
| 8476 |
| 8477 // Certificate request from the HTTPS proxy. |
| 8478 scoped_refptr<SSLCertRequestInfo> proxy_cert_request( |
| 8479 new SSLCertRequestInfo()); |
| 8480 proxy_cert_request->host_and_port = "proxy:70"; |
| 8481 |
| 8482 // The client certificate to use when authenticating with the proxy. |
| 8483 base::Time start_date = base::Time::Now(); |
| 8484 base::Time expiration_date = start_date + base::TimeDelta::FromDays(1); |
| 8485 scoped_refptr<X509Certificate> proxy_cert( |
| 8486 new X509Certificate("proxy", "me", start_date, expiration_date)); |
| 8487 |
| 8488 // Certificate request from the SSL endpoint. |
| 8489 scoped_refptr<SSLCertRequestInfo> endpoint_cert_request( |
| 8490 new net::SSLCertRequestInfo()); |
| 8491 endpoint_cert_request->host_and_port = "www.example.com:443"; |
| 8492 |
| 8493 // The client certificate to use when authenticating with the SSL endpoint. |
| 8494 scoped_refptr<X509Certificate> endpoint_cert( |
| 8495 new X509Certificate("endpoint", "you", start_date, expiration_date)); |
| 8496 |
| 8497 // ssl_data1 is the initial connection to the HTTPS proxy, which is |
| 8498 // requesting a client certificate. data1 is needed to initialize the |
| 8499 // underlying transport socket, but no data is exchanged due to the SSL |
| 8500 // handshake failure. |
| 8501 SSLSocketDataProvider ssl_data1(true /* async */, |
| 8502 net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); |
| 8503 ssl_data1.cert_request_info = proxy_cert_request.get(); |
| 8504 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1); |
| 8505 |
| 8506 StaticSocketDataProvider data1(NULL, 0, NULL, 0); |
| 8507 session_deps.socket_factory.AddSocketDataProvider(&data1); |
| 8508 |
| 8509 // ssl_data2 is the re-connection to the HTTPS proxy, now with a valid |
| 8510 // client certificate. data2 contains the data exchanged with the proxy to |
| 8511 // set up the tunnel, and then the following reads/writes contain the data |
| 8512 // exchanged with the endpoint, which there should be none, due to the |
| 8513 // endpoint SSL handshake failure. |
| 8514 SSLSocketDataProvider ssl_data2(true /* async */, net::OK); |
| 8515 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2); |
| 8516 |
| 8517 MockWrite data_writes2[] = { |
| 8518 MockWrite("CONNECT www.example.com:443 HTTP/1.1\r\n" |
| 8519 "Host: www.example.com\r\n" |
| 8520 "Proxy-Connection: keep-alive\r\n\r\n"), |
| 8521 }; |
| 8522 MockRead data_reads2[] = { |
| 8523 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), |
| 8524 }; |
| 8525 |
| 8526 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), |
| 8527 data_writes2, arraysize(data_writes2)); |
| 8528 session_deps.socket_factory.AddSocketDataProvider(&data2); |
| 8529 |
| 8530 // ssl_data3 is the initial connection to the SSL endpoint, which is also |
| 8531 // requesting a client certificate. There is no data3, because ssl_data3's |
| 8532 // client socket handle comes from the proxy, which is using data2. |
| 8533 SSLSocketDataProvider ssl_data3(true /* async */, |
| 8534 net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); |
| 8535 ssl_data3.cert_request_info = endpoint_cert_request.get(); |
| 8536 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); |
| 8537 |
| 8538 // ssl_data4 is the reconnection to the HTTPS proxy, after the connection |
| 8539 // to the SSL endpoint has failed due to requiring a client certificate. |
| 8540 // data4 contains the data exchanged with the proxy to set up the tunnel, |
| 8541 // and then the subsequent reads/writes contains the data exchanged with |
| 8542 // the endpoint. |
| 8543 SSLSocketDataProvider ssl_data4(true /* async */, net::OK); |
| 8544 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data4); |
| 8545 |
| 8546 MockWrite data_writes4[] = { |
| 8547 MockWrite("CONNECT www.example.com:443 HTTP/1.1\r\n" |
| 8548 "Host: www.example.com\r\n" |
| 8549 "Proxy-Connection: keep-alive\r\n\r\n"), |
| 8550 |
| 8551 MockWrite("GET / HTTP/1.1\r\n" |
| 8552 "Host: www.example.com\r\n" |
| 8553 "Connection: keep-alive\r\n\r\n"), |
| 8554 }; |
| 8555 MockRead data_reads4[] = { |
| 8556 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), |
| 8557 |
| 8558 MockRead("HTTP/1.1 200 OK\r\n\r\n"), |
| 8559 MockRead("hello, world"), |
| 8560 MockRead(false, OK), |
| 8561 }; |
| 8562 StaticSocketDataProvider data4(data_reads4, arraysize(data_reads4), |
| 8563 data_writes4, arraysize(data_writes4)); |
| 8564 session_deps.socket_factory.AddSocketDataProvider(&data4); |
| 8565 |
| 8566 // ssl_data5 is the SSL handshake with the endpoint, after the proxy has |
| 8567 // been negotiated. There is no data5, because ssl_data5's client socket |
| 8568 // handle comes from the proxy, which is using data4. |
| 8569 SSLSocketDataProvider ssl_data5(true /* async */, net::OK); |
| 8570 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data5); |
| 8571 |
| 8572 net::HttpRequestInfo request; |
| 8573 request.url = GURL("https://www.example.com/"); |
| 8574 request.method = "GET"; |
| 8575 request.load_flags = net::LOAD_NORMAL; |
| 8576 |
| 8577 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); |
| 8578 scoped_ptr<HttpNetworkTransaction> trans( |
| 8579 new HttpNetworkTransaction(session)); |
| 8580 |
| 8581 // Make the initial connection to the HTTPS proxy. |
| 8582 TestCompletionCallback callback; |
| 8583 int rv = trans->Start(&request, &callback, net::BoundNetLog()); |
| 8584 ASSERT_EQ(net::ERR_IO_PENDING, rv); |
| 8585 // Finish the SSL handshake to the HTTPS proxy (ssl_data1). |
| 8586 rv = callback.WaitForResult(); |
| 8587 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); |
| 8588 |
| 8589 // Make sure that the certificate request matches that from ssl_data1. |
| 8590 const HttpResponseInfo* response = trans->GetResponseInfo(); |
| 8591 ASSERT_TRUE(response); |
| 8592 ASSERT_TRUE(response->cert_request_info); |
| 8593 ASSERT_EQ("proxy:70", response->cert_request_info->host_and_port); |
| 8594 |
| 8595 // Restart the connection to the HTTPS proxy, now with a client |
| 8596 // certificate (ssl_data2). |
| 8597 rv = trans->RestartWithCertificate(proxy_cert, &callback); |
| 8598 ASSERT_EQ(net::ERR_IO_PENDING, rv); |
| 8599 |
| 8600 // Make sure that SSL client auth cache is only updated for the proxy and |
| 8601 // not for the endpoint. |
| 8602 scoped_refptr<X509Certificate> cached_cert; |
| 8603 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("proxy:70", |
| 8604 &cached_cert)); |
| 8605 ASSERT_EQ(proxy_cert, cached_cert); |
| 8606 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", |
| 8607 &cached_cert)); |
| 8608 |
| 8609 // Utility class to interject ourselves into the handshake. |callback|, |
| 8610 // the TestCompletionCallback, can only wait until the |
| 8611 // HttpNetworkTransaction callback is invoked. However, on an SSL failure, |
| 8612 // the MockSSLClientSocket will be destroyed by the ClientSocketHandle, |
| 8613 // meaning the parameters that were passed in it's construction will no |
| 8614 // longer be available. This is just a hack-job substitute to demonstrate |
| 8615 // the problem without having to shave the Mock*Factory yak to allow us to |
| 8616 // break after creating a socket, and DOES NOT represent code I'd ever |
| 8617 // check in. |
| 8618 class WaitForSSLCreationObserver : public MessageLoop::TaskObserver { |
| 8619 public: |
| 8620 WaitForSSLCreationObserver(SessionDependencies* session_deps, |
| 8621 size_t expected_ssl_sockets) |
| 8622 : session_deps_(session_deps), |
| 8623 expected_ssl_sockets_(expected_ssl_sockets) { |
| 8624 } |
| 8625 |
| 8626 // TaskObserver |
| 8627 virtual void WillProcessTask(const Task* task) OVERRIDE {} |
| 8628 virtual void DidProcessTask(const Task* task) OVERRIDE { |
| 8629 if (session_deps_->socket_factory.ssl_client_sockets().size() >= |
| 8630 expected_ssl_sockets_) { |
| 8631 MessageLoop::current()->QuitNow(); |
| 8632 } |
| 8633 } |
| 8634 private: |
| 8635 SessionDependencies* session_deps_; |
| 8636 size_t expected_ssl_sockets_; |
| 8637 }; |
| 8638 |
| 8639 // Finish the SSL handshake with the HTTPS proxy and begin |
| 8640 // the SSL handshake with the endpoint (ssl_data3). |
| 8641 WaitForSSLCreationObserver wait_for_endpoint(&session_deps, 3); |
| 8642 MessageLoop::current()->AddTaskObserver(&wait_for_endpoint); |
| 8643 MessageLoop::current()->Run(); |
| 8644 MessageLoop::current()->RemoveTaskObserver(&wait_for_endpoint); |
| 8645 |
| 8646 // Make sure that the SSL handshake to the endpoint is NOT set to send the |
| 8647 // client certificate used for the proxy. |
| 8648 MockSSLClientSocket* endpoint_socket = |
| 8649 session_deps.socket_factory.GetMockSSLClientSocket(2); |
| 8650 ASSERT_TRUE(endpoint_socket); |
| 8651 ASSERT_EQ("www.example.com:443", |
| 8652 endpoint_socket->GetHostAndPort().ToString()); |
| 8653 ASSERT_FALSE(endpoint_socket->GetSSLConfig().send_client_cert); |
| 8654 ASSERT_FALSE(endpoint_socket->GetSSLConfig().client_cert); |
| 8655 |
| 8656 rv = callback.WaitForResult(); |
| 8657 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); |
| 8658 |
| 8659 // Make sure that the certificate request matches that from ssl_data3. |
| 8660 response = trans->GetResponseInfo(); |
| 8661 ASSERT_TRUE(response); |
| 8662 ASSERT_TRUE(response->cert_request_info); |
| 8663 ASSERT_EQ("www.example.com:443", |
| 8664 response->cert_request_info->host_and_port); |
| 8665 |
| 8666 // Restart the SSL handshake with the endpoint. This will cause ssl_data4 |
| 8667 // to be consumed, because |trans| has to first re-establish a connection |
| 8668 // with the proxy. |
| 8669 rv = trans->RestartWithCertificate(endpoint_cert, &callback); |
| 8670 ASSERT_EQ(net::ERR_IO_PENDING, rv); |
| 8671 |
| 8672 // Ensure that the SSL socket for the HTTPS proxy is still configured to |
| 8673 // use the proxy client certificate, and NOT the client certificate for |
| 8674 // the endpoint. |
| 8675 MockSSLClientSocket* proxy_socket = |
| 8676 session_deps.socket_factory.GetMockSSLClientSocket(3); |
| 8677 ASSERT_TRUE(proxy_socket); |
| 8678 ASSERT_EQ("proxy:70", proxy_socket->GetHostAndPort().ToString()); |
| 8679 ASSERT_TRUE(proxy_socket->GetSSLConfig().send_client_cert); |
| 8680 ASSERT_EQ(proxy_cert, proxy_socket->GetSSLConfig().client_cert); |
| 8681 |
| 8682 // Finish the SSL handshake with HTTPS proxy and start the SSL handshake |
| 8683 // with the endpoint. This will consume ssl_data5. |
| 8684 WaitForSSLCreationObserver wait_for_endpoint_again(&session_deps, 5); |
| 8685 MessageLoop::current()->AddTaskObserver(&wait_for_endpoint_again); |
| 8686 MessageLoop::current()->Run(); |
| 8687 MessageLoop::current()->RemoveTaskObserver(&wait_for_endpoint_again); |
| 8688 |
| 8689 // Ensure that the SSL socket for the SSL endpoint is configured to use |
| 8690 // the endpoint client certificate, and NOT the client certificate for the |
| 8691 // HTTPS proxy. |
| 8692 endpoint_socket = session_deps.socket_factory.GetMockSSLClientSocket(4); |
| 8693 ASSERT_TRUE(endpoint_socket); |
| 8694 ASSERT_EQ("www.example.com:443", |
| 8695 endpoint_socket->GetHostAndPort().ToString()); |
| 8696 ASSERT_TRUE(endpoint_socket->GetSSLConfig().send_client_cert); |
| 8697 ASSERT_EQ(endpoint_cert, endpoint_socket->GetSSLConfig().client_cert); |
| 8698 |
| 8699 rv = callback.WaitForResult(); |
| 8700 ASSERT_EQ(net::OK, rv); |
| 8701 |
| 8702 // Make sure that the request was consumed from data4. |
| 8703 response = trans->GetResponseInfo(); |
| 8704 ASSERT_TRUE(response); |
| 8705 EXPECT_EQ(200, response->headers->response_code()); |
| 8706 EXPECT_EQ(HttpVersion(1, 1), response->headers->GetHttpVersion()); |
| 8707 std::string response_data; |
| 8708 rv = ReadTransaction(trans.get(), &response_data); |
| 8709 EXPECT_EQ(net::OK, rv); |
| 8710 EXPECT_EQ("hello, world", response_data); |
| 8711 } |
| 8712 |
8466 } // namespace net | 8713 } // namespace net |
OLD | NEW |