diff options
author | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 19:57:01 +0000 |
---|---|---|
committer | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 19:57:01 +0000 |
commit | 5e363960aa45fc4a906e51bfe7964db86f1fa656 (patch) | |
tree | f54f261bd8c07234b46f98ba2127fa526ea89f5e /net/http | |
parent | b3c6b7f71bb588570107770b42c00480abe221b6 (diff) | |
download | chromium_src-5e363960aa45fc4a906e51bfe7964db86f1fa656.zip chromium_src-5e363960aa45fc4a906e51bfe7964db86f1fa656.tar.gz chromium_src-5e363960aa45fc4a906e51bfe7964db86f1fa656.tar.bz2 |
Implement the backend of SSL client authentication for
Windows.
Create Schannel SSPI CredHandles with certificates for
SSL client authentication.
Remember the client certificates that the user selected
so that we don't ask the user again and again.
R=rvargas,eroman
BUG=http://crbug.com/318
TEST=none
Review URL: http://codereview.chromium.org/131086
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18841 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http')
-rw-r--r-- | net/http/http_network_transaction.cc | 51 | ||||
-rw-r--r-- | net/http/http_network_transaction.h | 2 |
2 files changed, 49 insertions, 4 deletions
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 2383c38..5a52f2a 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -193,6 +193,10 @@ int HttpNetworkTransaction::RestartWithCertificate( 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 @@ int HttpNetworkTransaction::DoSSLConnectComplete(int result) { 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 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) { << " 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 @@ int HttpNetworkTransaction::HandleCertificateError(int error) { 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 @@ void HttpNetworkTransaction::HandleCertificateRequest() { // 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(), + &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: diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index 13d88b9..6358e6a 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -163,7 +163,7 @@ class HttpNetworkTransaction : public HttpTransaction { int HandleCertificateError(int error); // Called to handle a client certificate request. - void HandleCertificateRequest(); + int HandleCertificateRequest(int error); // Called to possibly recover from an SSL handshake error. Sets next_state_ // and returns OK if recovering from the error. Otherwise, the same error |