summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-12 21:45:11 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-12 21:45:11 +0000
commit0b45559b42825a157d3f468e1a5ee102cc67d9a8 (patch)
tree00d25404d9803f5e905eab058cd175dca9fb68e0
parent37a24e0d9e75a916c13900cf34d7c6b54acc2001 (diff)
downloadchromium_src-0b45559b42825a157d3f468e1a5ee102cc67d9a8.zip
chromium_src-0b45559b42825a157d3f468e1a5ee102cc67d9a8.tar.gz
chromium_src-0b45559b42825a157d3f468e1a5ee102cc67d9a8.tar.bz2
Specify new methods for supporting SSL client authentication.
See the changes to url_request.h and ssl_cert_request_info.h. They are similar to the methods for handling SSL certificate errors and HTTP authentication. The handling of servers that request but don't require SSL client authentication is reimplemented using the new methods. R=rvargas,eroman BUG=http://crbug.com/318 TEST=none Review URL: http://codereview.chromium.org/118039 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18322 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/base/net_error_list.h3
-rw-r--r--net/base/socket_test_util.cc7
-rw-r--r--net/base/ssl_cert_request_info.h37
-rw-r--r--net/base/ssl_client_socket.h8
-rw-r--r--net/base/ssl_client_socket_mac.cc8
-rw-r--r--net/base/ssl_client_socket_mac.h3
-rw-r--r--net/base/ssl_client_socket_nss.cc7
-rw-r--r--net/base/ssl_client_socket_nss.h3
-rw-r--r--net/base/ssl_client_socket_win.cc46
-rw-r--r--net/base/ssl_client_socket_win.h6
-rw-r--r--net/base/ssl_config_service.h12
-rw-r--r--net/http/http_cache.cc45
-rw-r--r--net/http/http_network_transaction.cc55
-rw-r--r--net/http/http_network_transaction.h7
-rw-r--r--net/http/http_response_info.cc2
-rw-r--r--net/http/http_response_info.h9
-rw-r--r--net/http/http_transaction.h7
-rw-r--r--net/http/http_transaction_unittest.h7
-rw-r--r--net/net.gyp1
-rw-r--r--net/url_request/url_request.cc8
-rw-r--r--net/url_request/url_request.h19
-rw-r--r--net/url_request/url_request_http_job.cc26
-rw-r--r--net/url_request/url_request_http_job.h3
-rw-r--r--net/url_request/url_request_job.cc8
-rw-r--r--net/url_request/url_request_job.h5
25 files changed, 282 insertions, 60 deletions
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index e22e11f..d0f91c4 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -106,6 +106,9 @@ NET_ERROR(PROXY_AUTH_REQUESTED, -115)
// certificate error.
NET_ERROR(CERT_ERROR_IN_SSL_RENEGOTIATION, -116)
+// The SSL handshake failed because of a bad or missing client certificate.
+NET_ERROR(BAD_SSL_CLIENT_AUTH_CERT, -117)
+
// Certificate error codes
//
// The values of certificate error codes must be consecutive.
diff --git a/net/base/socket_test_util.cc b/net/base/socket_test_util.cc
index fa7f63e..cd9bd77 100644
--- a/net/base/socket_test_util.cc
+++ b/net/base/socket_test_util.cc
@@ -24,6 +24,8 @@ class MockClientSocket : public net::SSLClientSocket {
// SSLClientSocket methods:
virtual void GetSSLInfo(net::SSLInfo* ssl_info);
+ virtual void GetSSLCertRequestInfo(
+ net::SSLCertRequestInfo* cert_request_info);
virtual void Disconnect();
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
@@ -105,6 +107,11 @@ void MockClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
NOTREACHED();
}
+void MockClientSocket::GetSSLCertRequestInfo(
+ net::SSLCertRequestInfo* cert_request_info) {
+ NOTREACHED();
+}
+
void MockClientSocket::Disconnect() {
connected_ = false;
callback_ = NULL;
diff --git a/net/base/ssl_cert_request_info.h b/net/base/ssl_cert_request_info.h
new file mode 100644
index 0000000..2529d87
--- /dev/null
+++ b/net/base/ssl_cert_request_info.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_SSL_CERT_REQUEST_INFO_H_
+#define NET_BASE_SSL_CERT_REQUEST_INFO_H_
+
+#include <string>
+#include <vector>
+
+#include "base/ref_counted.h"
+
+namespace net {
+
+class X509Certificate;
+
+// The SSLCertRequestInfo class contains the info that allows a user to
+// select a certificate to send to the SSL server for client authentication.
+class SSLCertRequestInfo
+ : public base::RefCountedThreadSafe<SSLCertRequestInfo> {
+ public:
+ // The host and port of the SSL server that requested client authentication.
+ std::string host_and_port;
+
+ // A list of client certificates that match the server's criteria in the
+ // SSL CertificateRequest message. In TLS 1.0, the CertificateRequest
+ // message is defined as:
+ // struct {
+ // ClientCertificateType certificate_types<1..2^8-1>;
+ // DistinguishedName certificate_authorities<3..2^16-1>;
+ // } CertificateRequest;
+ std::vector<scoped_refptr<X509Certificate> > client_certs;
+};
+
+} // namespace net
+
+#endif // NET_BASE_SSL_CERT_REQUEST_INFO_H_
diff --git a/net/base/ssl_client_socket.h b/net/base/ssl_client_socket.h
index 8c9f05b..8b9cca6 100644
--- a/net/base/ssl_client_socket.h
+++ b/net/base/ssl_client_socket.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
namespace net {
+class SSLCertRequestInfo;
class SSLInfo;
// A client socket that uses SSL as the transport layer.
@@ -21,6 +22,11 @@ class SSLClientSocket : public ClientSocket {
public:
// Gets the SSL connection information of the socket.
virtual void GetSSLInfo(SSLInfo* ssl_info) = 0;
+
+ // Gets the SSL CertificateRequest info of the socket after Connect failed
+ // with ERR_SSL_CLIENT_AUTH_CERT_NEEDED.
+ virtual void GetSSLCertRequestInfo(
+ SSLCertRequestInfo* cert_request_info) = 0;
};
} // namespace net
diff --git a/net/base/ssl_client_socket_mac.cc b/net/base/ssl_client_socket_mac.cc
index 2148a2b..7528b13 100644
--- a/net/base/ssl_client_socket_mac.cc
+++ b/net/base/ssl_client_socket_mac.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2008-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -418,6 +418,11 @@ void SSLClientSocketMac::GetSSLInfo(SSLInfo* ssl_info) {
ssl_info->security_bits = KeySizeOfCipherSuite(suite);
}
+void SSLClientSocketMac::GetSSLCertRequestInfo(
+ SSLCertRequestInfo* cert_request_info) {
+ // TODO(wtc): implement this.
+}
+
void SSLClientSocketMac::DoCallback(int rv) {
DCHECK(rv != ERR_IO_PENDING);
DCHECK(user_callback_);
@@ -743,7 +748,6 @@ OSStatus SSLClientSocketMac::SSLWriteCallback(SSLConnectionRef connection,
if (rv > 0) {
us->send_buffer_.erase(us->send_buffer_.begin(),
us->send_buffer_.begin() + rv);
-
}
} while (rv > 0 && !us->send_buffer_.empty());
diff --git a/net/base/ssl_client_socket_mac.h b/net/base/ssl_client_socket_mac.h
index 9d4dec0..6e088bb 100644
--- a/net/base/ssl_client_socket_mac.h
+++ b/net/base/ssl_client_socket_mac.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -31,6 +31,7 @@ class SSLClientSocketMac : public SSLClientSocket {
// SSLClientSocket methods:
virtual void GetSSLInfo(SSLInfo* ssl_info);
+ virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
// ClientSocket methods:
virtual int Connect(CompletionCallback* callback);
diff --git a/net/base/ssl_client_socket_nss.cc b/net/base/ssl_client_socket_nss.cc
index 6c8aeca..d64d791 100644
--- a/net/base/ssl_client_socket_nss.cc
+++ b/net/base/ssl_client_socket_nss.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -490,6 +490,11 @@ void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
LeaveFunction("");
}
+void SSLClientSocketNSS::GetSSLCertRequestInfo(
+ SSLCertRequestInfo* cert_request_info) {
+ // TODO(wtc): implement this.
+}
+
void SSLClientSocketNSS::DoCallback(int rv) {
EnterFunction(rv);
DCHECK(rv != ERR_IO_PENDING);
diff --git a/net/base/ssl_client_socket_nss.h b/net/base/ssl_client_socket_nss.h
index 71decf5..643051f 100644
--- a/net/base/ssl_client_socket_nss.h
+++ b/net/base/ssl_client_socket_nss.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
// SSLClientSocket methods:
virtual void GetSSLInfo(SSLInfo* ssl_info);
+ virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
// ClientSocket methods:
virtual int Connect(CompletionCallback* callback);
diff --git a/net/base/ssl_client_socket_win.cc b/net/base/ssl_client_socket_win.cc
index a839bb3..43641e3 100644
--- a/net/base/ssl_client_socket_win.cc
+++ b/net/base/ssl_client_socket_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -232,7 +232,6 @@ SSLClientSocketWin::SSLClientSocketWin(ClientSocket* transport_socket,
writing_first_token_(false),
completed_handshake_(false),
ignore_ok_result_(false),
- no_client_cert_(false),
renegotiating_(false) {
memset(&stream_sizes_, 0, sizeof(stream_sizes_));
memset(in_buffers_, 0, sizeof(in_buffers_));
@@ -261,6 +260,11 @@ void SSLClientSocketWin::GetSSLInfo(SSLInfo* ssl_info) {
}
}
+void SSLClientSocketWin::GetSSLCertRequestInfo(
+ SSLCertRequestInfo* cert_request_info) {
+ // TODO(wtc): implement this.
+}
+
int SSLClientSocketWin::Connect(CompletionCallback* callback) {
DCHECK(transport_.get());
DCHECK(next_state_ == STATE_NONE);
@@ -544,14 +548,7 @@ int SSLClientSocketWin::DoHandshakeReadComplete(int result) {
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM;
- // When InitializeSecurityContext returns SEC_I_INCOMPLETE_CREDENTIALS,
- // John Banes (a Microsoft security developer) said we need to pass in the
- // ISC_REQ_USE_SUPPLIED_CREDS flag if we skip finding a client certificate
- // and just call InitializeSecurityContext again. (See
- // (http://www.derkeiler.com/Newsgroups/microsoft.public.platformsdk.security/2004-08/0187.html.)
- // My testing on XP SP2 and Vista SP1 shows that it still works without
- // passing in this flag, but I pass it in to be safe.
- if (no_client_cert_)
+ if (ssl_config_.send_client_cert)
flags |= ISC_REQ_USE_SUPPLIED_CREDS;
SecBufferDesc in_buffer_desc, out_buffer_desc;
@@ -623,28 +620,21 @@ int SSLClientSocketWin::DidCallInitializeSecurityContext() {
int result = MapSecurityError(isc_status_);
// We told Schannel to not verify the server certificate
// (SCH_CRED_MANUAL_CRED_VALIDATION), so any certificate error returned by
- // InitializeSecurityContext must be referring to the (missing) client
- // certificate.
+ // InitializeSecurityContext must be referring to the bad or missing
+ // client certificate.
if (IsCertificateError(result)) {
- // TODO(wtc): When we support SSL client authentication, we will need to
- // add new error codes for client certificate errors reported by the
- // server using SSL/TLS alert messages. See http://crbug.com/318. See
- // also the MSDN page "Schannel Error Codes for TLS and SSL Alerts",
- // which maps TLS alert messages to Windows error codes:
+ // TODO(wtc): Add new error codes for client certificate errors reported
+ // by the server using SSL/TLS alert messages. See the MSDN page
+ // "Schannel Error Codes for TLS and SSL Alerts", which maps TLS alert
+ // messages to Windows error codes:
// http://msdn.microsoft.com/en-us/library/dd721886%28VS.85%29.aspx
- return ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
+ return ERR_BAD_SSL_CLIENT_AUTH_CERT;
}
return result;
}
- if (isc_status_ == SEC_I_INCOMPLETE_CREDENTIALS) {
- // We don't support SSL client authentication yet. For now we just set
- // no_client_cert_ to true and call InitializeSecurityContext again.
- no_client_cert_ = true;
- next_state_ = STATE_HANDSHAKE_READ_COMPLETE;
- ignore_ok_result_ = true; // OK doesn't mean EOF.
- return OK;
- }
+ if (isc_status_ == SEC_I_INCOMPLETE_CREDENTIALS)
+ return ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
DCHECK(isc_status_ == SEC_I_CONTINUE_NEEDED);
if (in_buffers_[1].BufferType == SECBUFFER_EXTRA) {
@@ -989,7 +979,7 @@ int SSLClientSocketWin::DidCompleteHandshake() {
SECURITY_STATUS status = QueryContextAttributes(
&ctxt_, SECPKG_ATTR_STREAM_SIZES, &stream_sizes_);
if (status != SEC_E_OK) {
- DLOG(ERROR) << "QueryContextAttributes failed: " << status;
+ DLOG(ERROR) << "QueryContextAttributes (stream sizes) failed: " << status;
return MapSecurityError(status);
}
DCHECK(!server_cert_ || renegotiating_);
@@ -997,7 +987,7 @@ int SSLClientSocketWin::DidCompleteHandshake() {
status = QueryContextAttributes(
&ctxt_, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &server_cert_handle);
if (status != SEC_E_OK) {
- DLOG(ERROR) << "QueryContextAttributes failed: " << status;
+ DLOG(ERROR) << "QueryContextAttributes (remote cert) failed: " << status;
return MapSecurityError(status);
}
if (renegotiating_ &&
diff --git a/net/base/ssl_client_socket_win.h b/net/base/ssl_client_socket_win.h
index 35f1e9e..12bf18f 100644
--- a/net/base/ssl_client_socket_win.h
+++ b/net/base/ssl_client_socket_win.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -36,6 +36,7 @@ class SSLClientSocketWin : public SSLClientSocket {
// SSLClientSocket methods:
virtual void GetSSLInfo(SSLInfo* ssl_info);
+ virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
// ClientSocket methods:
virtual int Connect(CompletionCallback* callback);
@@ -147,9 +148,6 @@ class SSLClientSocketWin : public SSLClientSocket {
// to be interpreted as EOF.
bool ignore_ok_result_;
- // True if the user has no client certificate.
- bool no_client_cert_;
-
// Renegotiation is in progress.
bool renegotiating_;
};
diff --git a/net/base/ssl_config_service.h b/net/base/ssl_config_service.h
index dec6fdb..cf2c9bb 100644
--- a/net/base/ssl_config_service.h
+++ b/net/base/ssl_config_service.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -18,7 +18,7 @@ struct SSLConfig {
// Default to SSL 2.0 off, SSL 3.0 on, and TLS 1.0 on.
SSLConfig()
: rev_checking_enabled(false), ssl2_enabled(false),
- ssl3_enabled(true), tls1_enabled(true) {
+ ssl3_enabled(true), tls1_enabled(true), send_client_cert(false) {
}
bool rev_checking_enabled; // True if server certificate revocation
@@ -27,11 +27,19 @@ struct SSLConfig {
bool ssl3_enabled; // True if SSL 3.0 is enabled.
bool tls1_enabled; // True if TLS 1.0 is enabled.
+ // TODO(wtc): move the following members to a new SSLParams structure. They
+ // are not SSL configuration settings.
+
// Add any known-bad SSL certificates to allowed_bad_certs_ that should not
// trigger an ERR_CERT_*_INVALID error when calling SSLClientSocket::Connect.
// This would normally be done in response to the user explicitly accepting
// the bad certificate.
std::set<scoped_refptr<X509Certificate> > allowed_bad_certs_;
+
+ // True if we should send client_cert to the server.
+ bool send_client_cert;
+
+ scoped_refptr<X509Certificate> client_cert;
};
// This class is responsible for getting and setting the SSL configuration.
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index f87b306..4453480 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -20,6 +20,7 @@
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
+#include "net/base/ssl_cert_request_info.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_network_layer.h"
#include "net/http/http_network_session.h"
@@ -166,6 +167,8 @@ class HttpCache::Transaction
// HttpTransaction methods:
virtual int Start(const HttpRequestInfo*, CompletionCallback*);
virtual int RestartIgnoringLastError(CompletionCallback*);
+ virtual int RestartWithCertificate(X509Certificate* client_cert,
+ CompletionCallback* callback);
virtual int RestartWithAuth(const std::wstring& username,
const std::wstring& password,
CompletionCallback* callback);
@@ -249,6 +252,10 @@ class HttpCache::Transaction
// error code.
int RestartNetworkRequest();
+ // Called to restart a network transaction with a client certificate.
+ // Returns network error code.
+ int RestartNetworkRequestWithCertificate(X509Certificate* client_cert);
+
// Called to restart a network transaction with authentication credentials.
// Returns network error code.
int RestartNetworkRequestWithAuth(const std::wstring& username,
@@ -414,6 +421,25 @@ int HttpCache::Transaction::RestartIgnoringLastError(
return rv;
}
+int HttpCache::Transaction::RestartWithCertificate(
+ X509Certificate* client_cert,
+ CompletionCallback* callback) {
+ DCHECK(callback);
+
+ // ensure that we only have one asynchronous call at a time.
+ DCHECK(!callback_);
+
+ if (revoked())
+ return ERR_UNEXPECTED;
+
+ int rv = RestartNetworkRequestWithCertificate(client_cert);
+
+ if (rv == ERR_IO_PENDING)
+ callback_ = callback;
+
+ return rv;
+}
+
int HttpCache::Transaction::RestartWithAuth(
const std::wstring& username,
const std::wstring& password,
@@ -499,7 +525,8 @@ const HttpResponseInfo* HttpCache::Transaction::GetResponseInfo() const {
// Null headers means we encountered an error or haven't a response yet
if (auth_response_.headers)
return &auth_response_;
- return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL;
+ return (response_.headers || response_.ssl_info.cert ||
+ response_.cert_request_info) ? &response_ : NULL;
}
LoadState HttpCache::Transaction::GetLoadState() const {
@@ -805,6 +832,18 @@ int HttpCache::Transaction::RestartNetworkRequest() {
return rv;
}
+int HttpCache::Transaction::RestartNetworkRequestWithCertificate(
+ X509Certificate* client_cert) {
+ DCHECK(mode_ & WRITE || mode_ == NONE);
+ DCHECK(network_trans_.get());
+
+ int rv = network_trans_->RestartWithCertificate(client_cert,
+ &network_info_callback_);
+ if (rv != ERR_IO_PENDING)
+ OnNetworkInfoAvailable(rv);
+ return rv;
+}
+
int HttpCache::Transaction::RestartNetworkRequestWithAuth(
const std::wstring& username,
const std::wstring& password) {
@@ -1092,6 +1131,10 @@ void HttpCache::Transaction::OnNetworkInfoAvailable(int result) {
// so GetResponseInfo() should never returns NULL here.
DCHECK(response);
response_.ssl_info = response->ssl_info;
+ } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
+ const HttpResponseInfo* response = network_trans_->GetResponseInfo();
+ DCHECK(response);
+ response_.cert_request_info = response->cert_request_info;
}
HandleResult(result);
}
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index dcdd5ec..4fbd5cb 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -17,6 +17,7 @@
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
+#include "net/base/ssl_cert_request_info.h"
#include "net/base/ssl_client_socket.h"
#include "net/base/upload_data_stream.h"
#include "net/http/http_auth.h"
@@ -189,6 +190,21 @@ int HttpNetworkTransaction::RestartIgnoringLastError(
return rv;
}
+int HttpNetworkTransaction::RestartWithCertificate(
+ X509Certificate* client_cert,
+ CompletionCallback* callback) {
+ 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();
+ int rv = DoLoop(OK);
+ if (rv == ERR_IO_PENDING)
+ user_callback_ = callback;
+ return rv;
+}
+
int HttpNetworkTransaction::RestartWithAuth(
const std::wstring& username,
const std::wstring& password,
@@ -346,7 +362,8 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
}
const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
- return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL;
+ return (response_.headers || response_.ssl_info.cert ||
+ response_.cert_request_info) ? &response_ : NULL;
}
LoadState HttpNetworkTransaction::GetLoadState() const {
@@ -603,6 +620,8 @@ int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
if (result == OK) {
next_state_ = STATE_WRITE_HEADERS;
+ } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
+ HandleCertificateRequest();
} else {
result = HandleSSLHandshakeError(result);
}
@@ -746,13 +765,19 @@ int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
}
int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
- if (using_ssl_ && IsCertificateError(result)) {
- // We don't handle a certificate error during SSL renegotiation, so we
- // have to return an error that's not in the certificate error range
- // (-2xx).
- LOG(ERROR) << "Got a server certificate with error " << result
- << " during SSL renegotiation";
- result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
+ // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
+ // due to SSL renegotiation.
+ if (using_ssl_) {
+ if (IsCertificateError(result)) {
+ // We don't handle a certificate error during SSL renegotiation, so we
+ // have to return an error that's not in the certificate error range
+ // (-2xx).
+ LOG(ERROR) << "Got a server certificate with error " << result
+ << " during SSL renegotiation";
+ result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
+ } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
+ HandleCertificateRequest();
+ }
}
if (result < 0)
@@ -1217,6 +1242,18 @@ int HttpNetworkTransaction::HandleCertificateError(int error) {
return error;
}
+void HttpNetworkTransaction::HandleCertificateRequest() {
+ response_.cert_request_info = new SSLCertRequestInfo;
+ SSLClientSocket* ssl_socket =
+ reinterpret_cast<SSLClientSocket*>(connection_.socket());
+ ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
+
+ // Close the connection while the user is selecting a certificate to send
+ // to the server.
+ connection_.socket()->Disconnect();
+ connection_.Reset();
+}
+
int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
switch (error) {
case ERR_SSL_PROTOCOL_ERROR:
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index fb21384..13d88b9 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -44,6 +44,8 @@ class HttpNetworkTransaction : public HttpTransaction {
virtual int Start(const HttpRequestInfo* request_info,
CompletionCallback* callback);
virtual int RestartIgnoringLastError(CompletionCallback* callback);
+ virtual int RestartWithCertificate(X509Certificate* client_cert,
+ CompletionCallback* callback);
virtual int RestartWithAuth(const std::wstring& username,
const std::wstring& password,
CompletionCallback* callback);
@@ -160,6 +162,9 @@ class HttpNetworkTransaction : public HttpTransaction {
// returns the same error code.
int HandleCertificateError(int error);
+ // Called to handle a client certificate request.
+ void HandleCertificateRequest();
+
// Called to possibly recover from an SSL handshake error. Sets next_state_
// and returns OK if recovering from the error. Otherwise, the same error
// code is returned.
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index bc2fbe3..0db95b5 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "net/http/http_response_info.h"
+
+#include "net/base/ssl_cert_request_info.h"
#include "net/http/http_response_headers.h"
namespace net {
diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h
index 88f89e7..7cbe13c 100644
--- a/net/http/http_response_info.h
+++ b/net/http/http_response_info.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,6 +13,7 @@
namespace net {
class HttpResponseHeaders;
+class SSLCertRequestInfo;
class HttpResponseInfo {
public:
@@ -41,6 +42,12 @@ class HttpResponseInfo {
// will contain additional information about the authentication challenge.
scoped_refptr<AuthChallengeInfo> auth_challenge;
+ // The SSL client certificate request info.
+ // TODO(wtc): does this really belong in HttpResponseInfo? I put it here
+ // because it is similar to |auth_challenge|, but unlike HTTP authentication
+ // challenge, client certificate request is not part of an HTTP response.
+ scoped_refptr<SSLCertRequestInfo> cert_request_info;
+
// The SSL connection info (if HTTPS).
SSLInfo ssl_info;
diff --git a/net/http/http_transaction.h b/net/http/http_transaction.h
index cc7dd92..14612e9 100644
--- a/net/http/http_transaction.h
+++ b/net/http/http_transaction.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,6 +13,7 @@ namespace net {
class HttpRequestInfo;
class HttpResponseInfo;
class IOBuffer;
+class X509Certificate;
// Represents a single HTTP transaction (i.e., a single request/response pair).
// HTTP redirects are not followed and authentication challenges are not
@@ -50,6 +51,10 @@ class HttpTransaction {
//
virtual int RestartIgnoringLastError(CompletionCallback* callback) = 0;
+ // Restarts the HTTP transaction with a client certificate.
+ virtual int RestartWithCertificate(X509Certificate* client_cert,
+ CompletionCallback* callback) = 0;
+
// Restarts the HTTP transaction with authentication credentials.
virtual int RestartWithAuth(const std::wstring& username,
const std::wstring& password,
diff --git a/net/http/http_transaction_unittest.h b/net/http/http_transaction_unittest.h
index d0a51b0..f72c305 100644
--- a/net/http/http_transaction_unittest.h
+++ b/net/http/http_transaction_unittest.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -234,6 +234,11 @@ class MockNetworkTransaction : public net::HttpTransaction {
return net::ERR_FAILED;
}
+ virtual int RestartWithCertificate(net::X509Certificate* client_cert,
+ net::CompletionCallback* callback) {
+ return net::ERR_FAILED;
+ }
+
virtual int RestartWithAuth(const std::wstring& username,
const std::wstring& password,
net::CompletionCallback* callback) {
diff --git a/net/net.gyp b/net/net.gyp
index 08d197c..c6c92b5 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -116,6 +116,7 @@
'base/sdch_manager.cc',
'base/sdch_manager.h',
'base/socket.h',
+ 'base/ssl_cert_request_info.h',
'base/ssl_client_socket.h',
'base/ssl_client_socket_mac.cc',
'base/ssl_client_socket_nss.cc',
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index ebfc376..b80ebe0 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -367,6 +367,12 @@ void URLRequest::CancelAuth() {
job_->CancelAuth();
}
+void URLRequest::ContinueWithCertificate(net::X509Certificate* client_cert) {
+ DCHECK(job_);
+
+ job_->ContinueWithCertificate(client_cert);
+}
+
void URLRequest::ContinueDespiteLastError() {
DCHECK(job_);
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 4f65f14..ed38cd7 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -24,6 +24,7 @@ class Time;
namespace net {
class IOBuffer;
+class SSLCertRequestInfo;
class UploadData;
class X509Certificate;
} // namespace net
@@ -145,6 +146,17 @@ class URLRequest {
request->CancelAuth();
}
+ // Called when we receive an SSL CertificateRequest message for client
+ // authentication. The delegate should call
+ // request->ContinueWithCertificate() with the client certificate the user
+ // selected, or request->ContinueWithCertificate(NULL) to continue the SSL
+ // handshake without a client certificate.
+ virtual void OnCertificateRequested(
+ URLRequest* request,
+ net::SSLCertRequestInfo* cert_request_info) {
+ request->ContinueWithCertificate(NULL);
+ }
+
// Called when using SSL and the server responds with a certificate with
// an error, for example, whose common name does not match the common name
// we were expecting for that host. The delegate should either do the
@@ -423,6 +435,11 @@ class URLRequest {
void SetAuth(const std::wstring& username, const std::wstring& password);
void CancelAuth();
+ // This method can be called after the user selects a client certificate to
+ // instruct this URLRequest to continue with the request with the
+ // certificate. Pass NULL if the user doesn't have a client certificate.
+ void ContinueWithCertificate(net::X509Certificate* client_cert);
+
// This method can be called after some error notifications to instruct this
// URLRequest to ignore the current error and continue with the request. To
// cancel the request instead, call Cancel().
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 6ad2dc5..da56c8b 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -20,6 +20,7 @@
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/base/sdch_manager.h"
+#include "net/base/ssl_cert_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/http/http_transaction.h"
@@ -384,6 +385,26 @@ void URLRequestHttpJob::CancelAuth() {
this, &URLRequestHttpJob::OnStartCompleted, net::OK));
}
+void URLRequestHttpJob::ContinueWithCertificate(
+ net::X509Certificate* client_cert) {
+ DCHECK(transaction_.get());
+
+ DCHECK(!response_info_) << "should not have a response yet";
+
+ // No matter what, we want to report our status as IO pending since we will
+ // be notifying our consumer asynchronously via OnStartCompleted.
+ SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
+
+ int rv = transaction_->RestartWithCertificate(client_cert, &start_callback_);
+ if (rv == net::ERR_IO_PENDING)
+ return;
+
+ // The transaction started synchronously, but we need to notify the
+ // URLRequest delegate via the message loop.
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &URLRequestHttpJob::OnStartCompleted, rv));
+}
+
void URLRequestHttpJob::ContinueDespiteLastError() {
// If the transaction was destroyed, then the job was cancelled.
if (!transaction_.get())
@@ -453,6 +474,9 @@ void URLRequestHttpJob::OnStartCompleted(int result) {
// ssl_info.
request_->delegate()->OnSSLCertificateError(
request_, result, transaction_->GetResponseInfo()->ssl_info.cert);
+ } else if (result == net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
+ request_->delegate()->OnCertificateRequested(
+ request_, transaction_->GetResponseInfo()->cert_request_info);
} else {
NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
}
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h
index 7853f83..46078d4 100644
--- a/net/url_request/url_request_http_job.h
+++ b/net/url_request/url_request_http_job.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -54,6 +54,7 @@ class URLRequestHttpJob : public URLRequestJob {
virtual void SetAuth(const std::wstring& username,
const std::wstring& password);
virtual void CancelAuth();
+ virtual void ContinueWithCertificate(net::X509Certificate* client_cert);
virtual void ContinueDespiteLastError();
virtual bool GetMoreData();
virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index 3d7df3e..8f4429d 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -90,6 +90,12 @@ void URLRequestJob::CancelAuth() {
NOTREACHED();
}
+void URLRequestJob::ContinueWithCertificate(
+ net::X509Certificate* client_cert) {
+ // The derived class should implement this!
+ NOTREACHED();
+}
+
void URLRequestJob::ContinueDespiteLastError() {
// Implementations should know how to recover from errors they generate.
// If this code was reached, we are trying to recover from an error that
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h
index 301bb3b..558d9ad 100644
--- a/net/url_request/url_request_job.h
+++ b/net/url_request/url_request_job.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -19,6 +19,7 @@ class AuthChallengeInfo;
class HttpResponseInfo;
class IOBuffer;
class UploadData;
+class X509Certificate;
}
class GURL;
@@ -176,6 +177,8 @@ class URLRequestJob : public base::RefCountedThreadSafe<URLRequestJob>,
// Display the error page without asking for credentials again.
virtual void CancelAuth();
+ virtual void ContinueWithCertificate(net::X509Certificate* client_cert);
+
// Continue processing the request ignoring the last error.
virtual void ContinueDespiteLastError();