Chromium Code Reviews| Index: net/http/http_network_transaction.cc |
| =================================================================== |
| --- net/http/http_network_transaction.cc (revision 18735) |
| +++ net/http/http_network_transaction.cc (working copy) |
| @@ -193,6 +193,10 @@ |
| X509Certificate* client_cert, |
| CompletionCallback* callback) { |
| ssl_config_.client_cert = client_cert; |
| + if (client_cert) { |
| + session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url), |
| + client_cert); |
| + } |
| ssl_config_.send_client_cert = true; |
| next_state_ = STATE_INIT_CONNECTION; |
| // Reset the other member variables. |
| @@ -634,7 +638,7 @@ |
| if (result == OK) { |
| next_state_ = STATE_WRITE_HEADERS; |
| } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { |
| - HandleCertificateRequest(); |
| + result = HandleCertificateRequest(result); |
| } else { |
| result = HandleSSLHandshakeError(result); |
| } |
| @@ -789,7 +793,9 @@ |
| << " during SSL renegotiation"; |
| result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION; |
| } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { |
| - HandleCertificateRequest(); |
| + result = HandleCertificateRequest(result); |
| + if (result == OK) |
| + return result; |
| } |
| } |
| @@ -1255,7 +1261,17 @@ |
| return error; |
| } |
| -void HttpNetworkTransaction::HandleCertificateRequest() { |
| +int HttpNetworkTransaction::HandleCertificateRequest(int error) { |
| + // Assert that the socket did not send a client certificate. |
| + // Note: If we got a reused socket, it was created with some other |
| + // transaction's ssl_config_, so we need to disable this assertion. We can |
| + // get a certificate request on a reused socket when the server requested |
| + // renegotiation (rehandshake). |
| + // TODO(wtc): add a GetSSLParams method to SSLClientSocket so we can query |
| + // the SSL parameters it was created with and get rid of the reused_socket_ |
| + // test. |
| + DCHECK(reused_socket_ || !ssl_config_.send_client_cert); |
| + |
| response_.cert_request_info = new SSLCertRequestInfo; |
| SSLClientSocket* ssl_socket = |
| reinterpret_cast<SSLClientSocket*>(connection_.socket()); |
| @@ -1265,9 +1281,38 @@ |
| // to the server. |
| connection_.socket()->Disconnect(); |
| connection_.Reset(); |
| + |
| + // If the user selected one of the certificate in client_certs for this |
| + // server before, use it automatically. |
| + X509Certificate* client_cert = session_->ssl_client_auth_cache()-> |
| + Lookup(GetHostAndPort(request_->url)); |
| + if (client_cert) { |
| + const std::vector<scoped_refptr<X509Certificate> >& client_certs = |
| + response_.cert_request_info->client_certs; |
| + for (size_t i = 0; i < client_certs.size(); ++i) { |
| + if (memcmp(&client_cert->fingerprint(), |
|
eroman
2009/06/19 21:42:24
I suggesting moving this into operator==.
struct
|
| + &client_certs[i]->fingerprint(), |
| + sizeof(X509Certificate::Fingerprint)) == 0) { |
| + ssl_config_.client_cert = client_cert; |
| + ssl_config_.send_client_cert = true; |
| + next_state_ = STATE_INIT_CONNECTION; |
| + // Reset the other member variables. |
| + // Note: this is necessary only with SSL renegotiation. |
| + ResetStateForRestart(); |
| + return OK; |
| + } |
| + } |
| + } |
| + return error; |
| } |
| int HttpNetworkTransaction::HandleSSLHandshakeError(int error) { |
| + if (ssl_config_.send_client_cert && |
| + (error == ERR_SSL_PROTOCOL_ERROR || |
| + error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) { |
| + session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url)); |
| + } |
| + |
| switch (error) { |
| case ERR_SSL_PROTOCOL_ERROR: |
| case ERR_SSL_VERSION_OR_CIPHER_MISMATCH: |