| Index: net/http/http_network_transaction.cc
 | 
| diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
 | 
| index e0967c60da61f7b86887f153e4b46433bc05d65f..847a59146d81e4660de7d699c0038938620197b2 100644
 | 
| --- a/net/http/http_network_transaction.cc
 | 
| +++ b/net/http/http_network_transaction.cc
 | 
| @@ -17,6 +17,7 @@
 | 
|  #include "base/string_number_conversions.h"
 | 
|  #include "base/string_util.h"
 | 
|  #include "base/stringprintf.h"
 | 
| +#include "base/utf_string_conversions.h"
 | 
|  #include "build/build_config.h"
 | 
|  #include "googleurl/src/gurl.h"
 | 
|  #include "net/base/auth.h"
 | 
| @@ -197,6 +198,49 @@ int HttpNetworkTransaction::RestartWithCertificate(
 | 
|    return rv;
 | 
|  }
 | 
|  
 | 
| +void HttpNetworkTransaction::SetTLSLoginAuthData(AuthData* auth_data) {
 | 
| +  DCHECK(!stream_request_.get()) << "Can't set TLS login on existing stream";
 | 
| +  DCHECK(!stream_.get());
 | 
| +  DCHECK_EQ(STATE_NONE, next_state_);
 | 
| +
 | 
| +  DCHECK(!auth_data->username.empty());
 | 
| +  DCHECK(!auth_data->password.empty());
 | 
| +
 | 
| +  tls_auth_data_ = auth_data;
 | 
| +  ssl_config_.tls_username = UTF16ToUTF8(auth_data->username);
 | 
| +  ssl_config_.tls_password = UTF16ToUTF8(auth_data->password);
 | 
| +  ssl_config_.use_tls_auth = true;
 | 
| +  ssl_config_.ssl3_enabled = false;
 | 
| +  ssl_config_.tls1_enabled = true;
 | 
| +}
 | 
| +
 | 
| +int HttpNetworkTransaction::RestartWithTLSLogin(CompletionCallback* callback) {
 | 
| +  DCHECK(!stream_request_.get());
 | 
| +  DCHECK(!stream_.get());
 | 
| +  DCHECK_EQ(STATE_NONE, next_state_);
 | 
| +
 | 
| +  DCHECK(!ssl_config_.tls_username.empty());
 | 
| +  DCHECK(!ssl_config_.tls_password.empty());
 | 
| +  DCHECK(ssl_config_.use_tls_auth);
 | 
| +  DCHECK(ssl_config_.tls1_enabled);
 | 
| +  DCHECK(!ssl_config_.ssl3_enabled);
 | 
| +
 | 
| +  DCHECK(response_.login_request_info.get());
 | 
| +  DCHECK(tls_auth_data_.get());
 | 
| +  session_->tls_client_login_cache()->Add(
 | 
| +      WideToUTF8(response_.login_request_info->host_and_port),
 | 
| +      tls_auth_data_);
 | 
| +
 | 
| +  // Reset the other member variables.
 | 
| +  // Note: this is necessary only with SSL renegotiation.
 | 
| +  ResetStateForRestart();
 | 
| +  next_state_ = STATE_CREATE_STREAM;
 | 
| +  int rv = DoLoop(OK);
 | 
| +  if (rv == ERR_IO_PENDING)
 | 
| +    user_callback_ = callback;
 | 
| +  return rv;
 | 
| +}
 | 
| +
 | 
|  int HttpNetworkTransaction::RestartWithAuth(
 | 
|      const string16& username,
 | 
|      const string16& password,
 | 
| @@ -330,7 +374,9 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
 | 
|  
 | 
|  const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
 | 
|    return ((headers_valid_ && response_.headers) || response_.ssl_info.cert ||
 | 
| -          response_.cert_request_info) ? &response_ : NULL;
 | 
| +          !response_.ssl_info.tls_username.empty() ||
 | 
| +          response_.cert_request_info || response_.login_request_info) ?
 | 
| +      &response_ : NULL;
 | 
|  }
 | 
|  
 | 
|  LoadState HttpNetworkTransaction::GetLoadState() const {
 | 
| @@ -425,6 +471,14 @@ void HttpNetworkTransaction::OnNeedsClientAuth(
 | 
|    OnIOComplete(ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
 | 
|  }
 | 
|  
 | 
| +void HttpNetworkTransaction::OnNeedsTLSLogin(
 | 
| +    AuthChallengeInfo* login_info) {
 | 
| +  DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
 | 
| +
 | 
| +  response_.login_request_info = login_info;
 | 
| +  OnIOComplete(ERR_TLS_CLIENT_LOGIN_NEEDED);
 | 
| +}
 | 
| +
 | 
|  void HttpNetworkTransaction::OnHttpsProxyTunnelResponse(
 | 
|      const HttpResponseInfo& response_info,
 | 
|      HttpStream* stream) {
 | 
| @@ -542,6 +596,33 @@ int HttpNetworkTransaction::DoLoop(int result) {
 | 
|  }
 | 
|  
 | 
|  int HttpNetworkTransaction::DoCreateStream() {
 | 
| +  DCHECK(request_);
 | 
| +
 | 
| +  // Set TLS login, if available.
 | 
| +  if (ssl_config_.use_tls_auth) {
 | 
| +    // TODO(sqs): implement some way of forcing TLS auth (as right below)
 | 
| +    // if (...) ssl_config_.require_tls_auth = true;
 | 
| +    if (ssl_config_.tls_username.empty()) {
 | 
| +      scoped_refptr<AuthData> tls_auth_data;
 | 
| +      bool found_login = session_->tls_client_login_cache()->Lookup(
 | 
| +          net::GetHostAndPort(request_->url),
 | 
| +          &tls_auth_data);
 | 
| +      if (found_login) {
 | 
| +        LOG(INFO) << "Got TLS login from cache";
 | 
| +        SetTLSLoginAuthData(tls_auth_data);
 | 
| +        DCHECK(!ssl_config_.tls_username.empty());
 | 
| +        DCHECK(!ssl_config_.tls_password.empty());
 | 
| +      } else if (ssl_config_.require_tls_auth) {
 | 
| +        response_.login_request_info = new AuthChallengeInfo;
 | 
| +        response_.login_request_info->host_and_port =
 | 
| +            UTF8ToWide(net::GetHostAndPort(request_->url));
 | 
| +        response_.login_request_info->scheme = ASCIIToWide(net::kTLSSRPScheme);
 | 
| +        response_.login_request_info->over_protocol = AUTH_OVER_TLS;
 | 
| +        return ERR_TLS_CLIENT_LOGIN_NEEDED;
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
|    next_state_ = STATE_CREATE_STREAM_COMPLETE;
 | 
|  
 | 
|    stream_request_.reset(
 | 
| @@ -1037,16 +1118,56 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
 | 
|          GetHostAndPort(request_->url));
 | 
|    }
 | 
|  
 | 
| +  // Check for TLS-SRP-related errors.
 | 
| +  if (ssl_config_.use_tls_auth) {
 | 
| +    if (ssl_config_.tls_username.empty() && ssl_config_.tls_password.empty()) {
 | 
| +      if (error == ERR_SSL_UNKNOWN_PSK_IDENTITY_ALERT) {
 | 
| +        // RFC 5054 unknown_psk_identity idiom: The Client Hello contained no
 | 
| +        // SRP username, but the server wishes to connect using an SRP cipher
 | 
| +        // suite.
 | 
| +        error = ERR_TLS_CLIENT_LOGIN_NEEDED;
 | 
| +      }
 | 
| +    } else if (!ssl_config_.tls_username.empty() &&
 | 
| +               ssl_config_.tls_password.empty()) {
 | 
| +      LOG(WARNING) << "SSL handshake error: empty TLS password";
 | 
| +    } else if (!ssl_config_.tls_username.empty() &&
 | 
| +               !ssl_config_.tls_password.empty()) {
 | 
| +      if (error == ERR_SSL_BAD_RECORD_MAC_ALERT ||
 | 
| +          error == ERR_SSL_UNKNOWN_PSK_IDENTITY_ALERT) {
 | 
| +        // The TLS-SRP login probably failed.
 | 
| +        // TODO(sqs): also verify that we did attempt to use an SRP cipher suite
 | 
| +        error = ERR_TLS_CLIENT_LOGIN_FAILED;
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    if (error == ERR_TLS_CLIENT_LOGIN_FAILED)
 | 
| +      session_->tls_client_login_cache()->Remove(GetHostAndPort(request_->url));
 | 
| +
 | 
| +    // Handle TLS-SRP errors now.
 | 
| +    if (error == ERR_TLS_CLIENT_LOGIN_FAILED ||
 | 
| +        error == ERR_TLS_CLIENT_LOGIN_NEEDED) {
 | 
| +      DCHECK(!response_.login_request_info.get());
 | 
| +      response_.login_request_info = new AuthChallengeInfo;
 | 
| +      response_.login_request_info->host_and_port =
 | 
| +          UTF8ToWide(GetHostAndPort(request_->url));
 | 
| +      response_.login_request_info->scheme = ASCIIToWide(net::kTLSSRPScheme);
 | 
| +      response_.login_request_info->over_protocol = AUTH_OVER_TLS;
 | 
| +      return error;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
|    switch (error) {
 | 
|      case ERR_SSL_PROTOCOL_ERROR:
 | 
|      case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
 | 
|      case ERR_SSL_DECOMPRESSION_FAILURE_ALERT:
 | 
|      case ERR_SSL_BAD_RECORD_MAC_ALERT:
 | 
|        if (ssl_config_.tls1_enabled &&
 | 
| -          !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())) {
 | 
| +          !SSLConfigService::IsKnownStrictTLSServer(request_->url.host()) &&
 | 
| +          !ssl_config_.require_tls_auth) {
 | 
|          // This could be a TLS-intolerant server, an SSL 3.0 server that
 | 
|          // chose a TLS-only cipher suite or a server with buggy DEFLATE
 | 
|          // support. Turn off TLS 1.0, DEFLATE support and retry.
 | 
| +        LOG(WARNING) << "Set server TLS intolerant: " << request_->url;
 | 
|          session_->http_stream_factory()->AddTLSIntolerantServer(request_->url);
 | 
|          ResetConnectionAndRequestForResend();
 | 
|          error = OK;
 | 
| 
 |