| Index: net/socket_stream/socket_stream.cc
|
| diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc
|
| index 8ea686a53e66b44ed95e38c90f18743a631cf966..cb8f0970d95985515068e3ae2d6861d46909c0e5 100644
|
| --- a/net/socket_stream/socket_stream.cc
|
| +++ b/net/socket_stream/socket_stream.cc
|
| @@ -21,9 +21,12 @@
|
| #include "net/base/io_buffer.h"
|
| #include "net/base/net_errors.h"
|
| #include "net/base/net_util.h"
|
| +#include "net/base/ssl_cert_request_info.h"
|
| #include "net/http/http_auth_handler_factory.h"
|
| +#include "net/http/http_network_session.h"
|
| #include "net/http/http_request_info.h"
|
| #include "net/http/http_response_headers.h"
|
| +#include "net/http/http_transaction_factory.h"
|
| #include "net/http/http_util.h"
|
| #include "net/socket/client_socket_factory.h"
|
| #include "net/socket/socks5_client_socket.h"
|
| @@ -132,8 +135,10 @@ void SocketStream::Connect() {
|
| "The current MessageLoop must exist";
|
| DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) <<
|
| "The current MessageLoop must be TYPE_IO";
|
| - if (context_)
|
| - ssl_config_service()->GetSSLConfig(&ssl_config_);
|
| + if (context_) {
|
| + ssl_config_service()->GetSSLConfig(&server_ssl_config_);
|
| + proxy_ssl_config_ = server_ssl_config_;
|
| + }
|
| DCHECK_EQ(next_state_, STATE_NONE);
|
|
|
| AddRef(); // Released in Finish()
|
| @@ -304,7 +309,8 @@ void SocketStream::Finish(int result) {
|
| Release();
|
| }
|
|
|
| -int SocketStream::DidEstablishSSL(int result) {
|
| +int SocketStream::DidEstablishSSL(int result, SSLConfig* ssl_config) {
|
| + DCHECK(ssl_config);
|
| if (IsCertificateError(result)) {
|
| if (socket_->IsConnectedAndIdle()) {
|
| result = HandleCertificateError(result);
|
| @@ -313,15 +319,15 @@ int SocketStream::DidEstablishSSL(int result) {
|
| // if it returns cert verification error. It didn't perform
|
| // SSLHandshake yet.
|
| // So, we should restart establishing connection with the
|
| - // certificate in allowed bad certificates in |ssl_config_|.
|
| + // certificate in allowed bad certificates in |ssl_config|.
|
| // See also net/http/http_network_transaction.cc
|
| // HandleCertificateError() and RestartIgnoringLastError().
|
| SSLClientSocket* ssl_socket =
|
| - reinterpret_cast<SSLClientSocket*>(socket_.get());
|
| + static_cast<SSLClientSocket*>(socket_.get());
|
| SSLInfo ssl_info;
|
| ssl_socket->GetSSLInfo(&ssl_info);
|
| if (ssl_info.cert == NULL ||
|
| - ssl_config_.IsAllowedBadCert(ssl_info.cert, NULL)) {
|
| + ssl_config->IsAllowedBadCert(ssl_info.cert, NULL)) {
|
| // If we already have the certificate in the set of allowed bad
|
| // certificates, we did try it and failed again, so we should not
|
| // retry again: the connection should fail at last.
|
| @@ -336,7 +342,7 @@ int SocketStream::DidEstablishSSL(int result) {
|
| return result;
|
| }
|
| bad_cert.cert_status = ssl_info.cert_status;
|
| - ssl_config_.allowed_bad_certs.push_back(bad_cert);
|
| + ssl_config->allowed_bad_certs.push_back(bad_cert);
|
| // Restart connection ignoring the bad certificate.
|
| socket_->Disconnect();
|
| socket_.reset();
|
| @@ -910,7 +916,7 @@ int SocketStream::DoSecureProxyConnect() {
|
| socket_.reset(factory_->CreateSSLClientSocket(
|
| socket_.release(),
|
| proxy_info_.proxy_server().host_port_pair(),
|
| - ssl_config_,
|
| + proxy_ssl_config_,
|
| NULL /* ssl_host_info */,
|
| ssl_context));
|
| next_state_ = STATE_SECURE_PROXY_CONNECT_COMPLETE;
|
| @@ -920,9 +926,11 @@ int SocketStream::DoSecureProxyConnect() {
|
|
|
| int SocketStream::DoSecureProxyConnectComplete(int result) {
|
| DCHECK_EQ(STATE_NONE, next_state_);
|
| - result = DidEstablishSSL(result);
|
| + result = DidEstablishSSL(result, &proxy_ssl_config_);
|
| if (next_state_ != STATE_NONE)
|
| return result;
|
| + if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED)
|
| + return HandleCertificateRequest(result);
|
| if (result == OK)
|
| next_state_ = STATE_WRITE_TUNNEL_HEADERS;
|
| else
|
| @@ -938,7 +946,7 @@ int SocketStream::DoSSLConnect() {
|
| // TODO(agl): look into plumbing SSLHostInfo here.
|
| socket_.reset(factory_->CreateSSLClientSocket(socket_.release(),
|
| HostPortPair::FromURL(url_),
|
| - ssl_config_,
|
| + server_ssl_config_,
|
| NULL /* ssl_host_info */,
|
| ssl_context));
|
| next_state_ = STATE_SSL_CONNECT_COMPLETE;
|
| @@ -948,7 +956,7 @@ int SocketStream::DoSSLConnect() {
|
|
|
| int SocketStream::DoSSLConnectComplete(int result) {
|
| DCHECK_EQ(STATE_NONE, next_state_);
|
| - result = DidEstablishSSL(result);
|
| + result = DidEstablishSSL(result, &server_ssl_config_);
|
| if (next_state_ != STATE_NONE)
|
| return result;
|
| // TODO(toyoshim): Upgrade to SPDY through TLS NPN extension if possible.
|
| @@ -1088,6 +1096,53 @@ int SocketStream::HandleAuthChallenge(const HttpResponseHeaders* headers) {
|
| return ERR_TUNNEL_CONNECTION_FAILED;
|
| }
|
|
|
| +int SocketStream::HandleCertificateRequest(int result) {
|
| + // TODO(toyoshim): We must support SSL client authentication for not only
|
| + // secure proxy but also secure server.
|
| +
|
| + if (proxy_ssl_config_.send_client_cert)
|
| + // We already have performed SSL client authentication once and failed.
|
| + return result;
|
| +
|
| + DCHECK(socket_.get());
|
| + scoped_refptr<SSLCertRequestInfo> cert_request_info = new SSLCertRequestInfo;
|
| + SSLClientSocket* ssl_socket =
|
| + static_cast<SSLClientSocket*>(socket_.get());
|
| + ssl_socket->GetSSLCertRequestInfo(cert_request_info);
|
| +
|
| + HttpTransactionFactory* factory = context_->http_transaction_factory();
|
| + if (!factory)
|
| + return result;
|
| + scoped_refptr<HttpNetworkSession> session = factory->GetSession();
|
| + if (!session.get())
|
| + return result;
|
| +
|
| + scoped_refptr<X509Certificate> client_cert;
|
| + bool found_cached_cert = session->ssl_client_auth_cache()->Lookup(
|
| + cert_request_info->host_and_port, &client_cert);
|
| + if (!found_cached_cert)
|
| + return result;
|
| + if (!client_cert)
|
| + return result;
|
| +
|
| + const std::vector<scoped_refptr<X509Certificate> >& client_certs =
|
| + cert_request_info->client_certs;
|
| + bool cert_still_valid = false;
|
| + for (size_t i = 0; i < client_certs.size(); ++i) {
|
| + if (client_cert->Equals(client_certs[i])) {
|
| + cert_still_valid = true;
|
| + break;
|
| + }
|
| + }
|
| + if (!cert_still_valid)
|
| + return result;
|
| +
|
| + proxy_ssl_config_.send_client_cert = true;
|
| + proxy_ssl_config_.client_cert = client_cert;
|
| + next_state_ = STATE_TCP_CONNECT;
|
| + return OK;
|
| +}
|
| +
|
| void SocketStream::DoAuthRequired() {
|
| if (delegate_ && auth_info_.get())
|
| delegate_->OnAuthRequired(this, auth_info_.get());
|
|
|