Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(640)

Side by Side Diff: net/http/http_network_transaction_unittest.cc

Issue 6120003: Unit test for testing SSL client auth with both a proxy and an SSL endpoint (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | net/socket/socket_test_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
OLDNEW
« no previous file with comments | « no previous file | net/socket/socket_test_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698