summaryrefslogtreecommitdiffstats
path: root/net/socket
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-13 17:54:42 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-13 17:54:42 +0000
commit127017875991e4a1b3d12dfff23d70265f991ef6 (patch)
treefc697789fb31e1c0fc137163aee660ba79f839d8 /net/socket
parentad8c2293824aecaf34ecdcd1f01720919afac6db (diff)
downloadchromium_src-127017875991e4a1b3d12dfff23d70265f991ef6.zip
chromium_src-127017875991e4a1b3d12dfff23d70265f991ef6.tar.gz
chromium_src-127017875991e4a1b3d12dfff23d70265f991ef6.tar.bz2
Implement SSL certificate error handling on the Mac. If the user gives
us bad certs to allow, we tell SecureTransport to not verify the server cert, and only allow the cert to be one of the bad certs the user allows. In the future we should figure out how to verify the server cert ourselves. R=avi,eroman BUG=http://crbug.com/11983 TEST=Visit https://www.ssl247.com/ and https://alioth.debian.org/. Clicking the "Proceed anyway" button should bring you to the site with a red "https" in the location bar. Review URL: http://codereview.chromium.org/165191 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23321 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket')
-rw-r--r--net/socket/ssl_client_socket_mac.cc99
-rw-r--r--net/socket/ssl_client_socket_mac.h2
-rw-r--r--net/socket/ssl_client_socket_nss.cc8
-rw-r--r--net/socket/ssl_client_socket_win.cc6
4 files changed, 73 insertions, 42 deletions
diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc
index dd56e35..2fe9743 100644
--- a/net/socket/ssl_client_socket_mac.cc
+++ b/net/socket/ssl_client_socket_mac.cc
@@ -241,6 +241,24 @@ int KeySizeOfCipherSuite(SSLCipherSuite suite) {
}
}
+// Returns the server's certificate. The caller must release a reference
+// to the return value when done. Returns NULL on failure.
+X509Certificate* GetServerCert(SSLContextRef ssl_context) {
+ CFArrayRef certs;
+ OSStatus status = SSLCopyPeerCertificates(ssl_context, &certs);
+ if (status != noErr)
+ return NULL;
+
+ DCHECK_GT(CFArrayGetCount(certs), 0);
+
+ SecCertificateRef server_cert = static_cast<SecCertificateRef>(
+ const_cast<void*>(CFArrayGetValueAtIndex(certs, 0)));
+ CFRetain(server_cert);
+ CFRelease(certs);
+ return X509Certificate::CreateFromHandle(
+ server_cert, X509Certificate::SOURCE_FROM_NETWORK);
+}
+
} // namespace
//-----------------------------------------------------------------------------
@@ -305,10 +323,23 @@ int SSLClientSocketMac::Connect(CompletionCallback* callback) {
if (status)
return NetErrorFromOSStatus(status);
- status = SSLSetPeerDomainName(ssl_context_, hostname_.c_str(),
- hostname_.length());
- if (status)
- return NetErrorFromOSStatus(status);
+ if (ssl_config_.allowed_bad_certs.empty()) {
+ // We're going to use the default certificate verification that the system
+ // does, and accept its answer for the cert status.
+ status = SSLSetPeerDomainName(ssl_context_, hostname_.data(),
+ hostname_.length());
+ if (status)
+ return NetErrorFromOSStatus(status);
+
+ // TODO(wtc): for now, always check revocation.
+ server_cert_status_ = CERT_STATUS_REV_CHECKING_ENABLED;
+ } else {
+ // Disable certificate chain validation. We will only allow the certs in
+ // ssl_config_.allowed_bad_certs.
+ status = SSLSetEnableCertVerify(ssl_context_, false);
+ if (status)
+ return NetErrorFromOSStatus(status);
+ }
next_state_ = STATE_HANDSHAKE;
int rv = DoLoop(OK);
@@ -394,26 +425,14 @@ void SSLClientSocketMac::GetSSLInfo(SSLInfo* ssl_info) {
ssl_info->Reset();
// set cert
- CFArrayRef certs;
- OSStatus status = SSLCopyPeerCertificates(ssl_context_, &certs);
- if (!status) {
- DCHECK(CFArrayGetCount(certs) > 0);
-
- SecCertificateRef client_cert =
- static_cast<SecCertificateRef>(
- const_cast<void*>(CFArrayGetValueAtIndex(certs, 0)));
- CFRetain(client_cert);
- ssl_info->cert = X509Certificate::CreateFromHandle(
- client_cert, X509Certificate::SOURCE_FROM_NETWORK);
- CFRelease(certs);
- }
+ ssl_info->cert = server_cert_;
// update status
ssl_info->cert_status = server_cert_status_;
// security info
SSLCipherSuite suite;
- status = SSLGetNegotiatedCipher(ssl_context_, &suite);
+ OSStatus status = SSLGetNegotiatedCipher(ssl_context_, &suite);
if (!status)
ssl_info->security_bits = KeySizeOfCipherSuite(suite);
}
@@ -485,26 +504,36 @@ int SSLClientSocketMac::DoLoop(int last_io_result) {
int SSLClientSocketMac::DoHandshake() {
OSStatus status = SSLHandshake(ssl_context_);
-
- if (status == errSSLWouldBlock)
- next_state_ = STATE_HANDSHAKE;
-
- if (status == noErr)
- completed_handshake_ = true;
-
int net_error = NetErrorFromOSStatus(status);
- // At this point we have a connection. For now, we're going to use the default
- // certificate verification that the system does, and accept its answer for
- // the cert status. In the future, we'll need to call SSLSetEnableCertVerify
- // to disable cert verification and do the verification ourselves. This allows
- // very fine-grained control over what we'll accept for certification.
- // TODO(avi): ditto
-
- // TODO(wtc): for now, always check revocation.
- server_cert_status_ = CERT_STATUS_REV_CHECKING_ENABLED;
- if (net_error)
+ if (status == errSSLWouldBlock) {
+ next_state_ = STATE_HANDSHAKE;
+ } else if (status == noErr) {
+ completed_handshake_ = true; // We have a connection.
+
+ server_cert_ = GetServerCert(ssl_context_);
+ DCHECK(server_cert_);
+ if (!ssl_config_.allowed_bad_certs.empty()) {
+ // Check server_cert_ because SecureTransport didn't verify it.
+ // TODO(wtc): If server_cert_ is not one of the allowed bad certificates,
+ // we should verify server_cert_ ourselves. Since we don't know how to
+ // do that yet, treat it as an invalid certificate.
+ net_error = ERR_CERT_INVALID;
+ server_cert_status_ |= CERT_STATUS_INVALID;
+
+ for (size_t i = 0; i < ssl_config_.allowed_bad_certs.size(); ++i) {
+ if (server_cert_ == ssl_config_.allowed_bad_certs[i].cert) {
+ net_error = OK;
+ server_cert_status_ = ssl_config_.allowed_bad_certs[i].cert_status;
+ break;
+ }
+ }
+ }
+ } else if (IsCertStatusError(net_error)) {
+ server_cert_ = GetServerCert(ssl_context_);
+ DCHECK(server_cert_);
server_cert_status_ |= MapNetErrorToCertStatus(net_error);
+ }
return net_error;
}
diff --git a/net/socket/ssl_client_socket_mac.h b/net/socket/ssl_client_socket_mac.h
index f9a08af..906bde5 100644
--- a/net/socket/ssl_client_socket_mac.h
+++ b/net/socket/ssl_client_socket_mac.h
@@ -84,6 +84,8 @@ class SSLClientSocketMac : public SSLClientSocket {
State next_state_;
State next_io_state_;
+ // Set when handshake finishes.
+ scoped_refptr<X509Certificate> server_cert_;
int server_cert_status_;
bool completed_handshake_;
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 96a8c6d..e6b3e96 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -332,7 +332,7 @@ int SSLClientSocketNSS::Connect(CompletionCallback* callback) {
void SSLClientSocketNSS::InvalidateSessionIfBadCertificate() {
if (UpdateServerCert() != NULL &&
- ssl_config_.allowed_bad_certs_.count(server_cert_)) {
+ ssl_config_.IsAllowedBadCert(server_cert_)) {
SSL_InvalidateSession(nss_fd_);
}
}
@@ -782,10 +782,10 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
// result of verifier_.Verify.
// Eventually, we should cache the cert verification results so that we don't
// need to call verifier_.Verify repeatedly. But for now we need to do this.
- // Alternatively, we might be able to store the cert's status along with
- // the cert in the allowed_bad_certs_ set.
+ // Alternatively, we could use the cert's status that we stored along with
+ // the cert in the allowed_bad_certs vector.
if (IsCertificateError(result) &&
- ssl_config_.allowed_bad_certs_.count(server_cert_)) {
+ ssl_config_.IsAllowedBadCert(server_cert_)) {
LOG(INFO) << "accepting bad SSL certificate, as user told us to";
result = OK;
}
diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc
index fba04ea..474f630 100644
--- a/net/socket/ssl_client_socket_win.cc
+++ b/net/socket/ssl_client_socket_win.cc
@@ -873,10 +873,10 @@ int SSLClientSocketWin::DoVerifyCertComplete(int result) {
// result of verifier_.Verify.
// Eventually, we should cache the cert verification results so that we don't
// need to call verifier_.Verify repeatedly. But for now we need to do this.
- // Alternatively, we might be able to store the cert's status along with
- // the cert in the allowed_bad_certs_ set.
+ // Alternatively, we could use the cert's status that we stored along with
+ // the cert in the allowed_bad_certs vector.
if (IsCertificateError(result) &&
- ssl_config_.allowed_bad_certs_.count(server_cert_))
+ ssl_config_.IsAllowedBadCert(server_cert_))
result = OK;
LogConnectionTypeMetrics();