summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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();