diff options
author | snej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-16 18:49:04 +0000 |
---|---|---|
committer | snej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-16 18:49:04 +0000 |
commit | c1d3c6fc04293d8fac98412cfc818ddd5978d0c4 (patch) | |
tree | a24bb569ca2f6a94f04a6da07d77c662554a7226 | |
parent | 0b6b23d44924736b829967c7689e066d0b4cee4d (diff) | |
download | chromium_src-c1d3c6fc04293d8fac98412cfc818ddd5978d0c4.zip chromium_src-c1d3c6fc04293d8fac98412cfc818ddd5978d0c4.tar.gz chromium_src-c1d3c6fc04293d8fac98412cfc818ddd5978d0c4.tar.bz2 |
Mac: Ignoring optional client-cert requests from server
BUG=37765
TEST=none
Review URL: http://codereview.chromium.org/746002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@41742 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/socket/ssl_client_socket_mac.cc | 100 |
1 files changed, 76 insertions, 24 deletions
diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc index 0cc34c2..373849f 100644 --- a/net/socket/ssl_client_socket_mac.cc +++ b/net/socket/ssl_client_socket_mac.cc @@ -98,6 +98,9 @@ namespace net { namespace { +// You can change this to LOG(WARNING) during development. +#define SSL_LOG LOG(INFO) << "SSL: " + #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 // Declarations needed to call the 10.5.7 and later SSLSetSessionOption() // function when building with the 10.5.0 SDK. @@ -549,6 +552,7 @@ void SSLClientSocketMac::Disconnect() { SSLClose(ssl_context_); SSLDisposeContext(ssl_context_); ssl_context_ = NULL; + SSL_LOG << "----- Disposed SSLContext"; } // Shut down anything that may call us back. @@ -650,10 +654,22 @@ void SSLClientSocketMac::GetSSLInfo(SSLInfo* ssl_info) { void SSLClientSocketMac::GetSSLCertRequestInfo( SSLCertRequestInfo* cert_request_info) { // I'm being asked for available client certs (identities). + + CFArrayRef allowed_issuer_names = NULL; + if (SSLCopyDistinguishedNames(ssl_context_, &allowed_issuer_names) == noErr && + allowed_issuer_names != NULL) { + SSL_LOG << "Server has " << CFArrayGetCount(allowed_issuer_names) + << " allowed issuer names"; + CFRelease(allowed_issuer_names); + // TODO(snej): Filter GetSSLClientCertificates using this array. + } + cert_request_info->host_and_port = hostname_; cert_request_info->client_certs.clear(); X509Certificate::GetSSLClientCertificates(hostname_, &cert_request_info->client_certs); + SSL_LOG << "Asking user to choose between " + << cert_request_info->client_certs.size() << " client certs..."; } SSLClientSocket::NextProtoStatus @@ -663,6 +679,7 @@ SSLClientSocketMac::GetNextProto(std::string* proto) { } int SSLClientSocketMac::InitializeSSLContext() { + SSL_LOG << "----- InitializeSSLContext"; OSStatus status = noErr; status = SSLNewContext(false, &ssl_context_); @@ -739,10 +756,12 @@ int SSLClientSocketMac::InitializeSSLContext() { status = ssl_set_session_options(ssl_context_, kSSLSessionOptionBreakOnServerAuth, true); - if (!status) + if (!status) { + SSL_LOG << "Setting kSSLSessionOptionBreakOnCertRequested"; status = ssl_set_session_options(ssl_context_, kSSLSessionOptionBreakOnCertRequested, true); + } if (status) return NetErrorFromOSStatus(status); @@ -765,9 +784,10 @@ int SSLClientSocketMac::InitializeSSLContext() { status = SSLSetPeerID(ssl_context_, peer_id.data(), peer_id.length()); if (status) return NetErrorFromOSStatus(status); - } else { + } else if (ssl_config_.send_client_cert) { // If I have a cert, set it up-front, otherwise the server may try to get // it later by renegotiating, which SecureTransport doesn't support well. + SSL_LOG << "Setting client cert in advance because send_client_cert is set"; status = SetClientCert(); if (status) return NetErrorFromOSStatus(status); @@ -903,27 +923,49 @@ int SSLClientSocketMac::DoHandshakeLoop(int last_io_result) { int SSLClientSocketMac::DoHandshakeStart() { OSStatus status = SSLHandshake(ssl_context_); - if (status == errSSLWouldBlock) - next_handshake_state_ = STATE_HANDSHAKE_START; - - if (status == noErr || status == errSSLServerAuthCompleted) { - // TODO(hawk): we verify the certificate chain even on resumed sessions - // so that we have the certificate status (valid, expired but overridden - // by the user, EV, etc.) available. Eliminate this step once we have - // a certificate validation result cache. - next_handshake_state_ = STATE_VERIFY_CERT; - if (status == errSSLServerAuthCompleted) { + + switch (status) { + case errSSLWouldBlock: + next_handshake_state_ = STATE_HANDSHAKE_START; + break; + + case noErr: + // TODO(hawk): we verify the certificate chain even on resumed sessions + // so that we have the certificate status (valid, expired but overridden + // by the user, EV, etc.) available. Eliminate this step once we have + // a certificate validation result cache. (Also applies to the + // errSSLServerAuthCompleted case below.) + next_handshake_state_ = STATE_VERIFY_CERT; + break; + + case errSSLServerAuthCompleted: // Override errSSLServerAuthCompleted as it's not actually an error, // but rather an indication that we're only half way through the // handshake. + SSL_LOG << "Server auth completed (DoHandshakeStart)"; + next_handshake_state_ = STATE_VERIFY_CERT; handshake_interrupted_ = true; status = noErr; - } - } + break; - if (status == errSSLClosedGraceful) { - // The server unexpectedly closed on us. - return ERR_SSL_PROTOCOL_ERROR; + case errSSLClientCertRequested: + SSL_LOG << "Received client cert request in DoHandshakeStart"; + // For some reason it's possible for SSLHandshake to return this code + // without earlier having returned errSSLServerAuthCompleted. + // Currently this isn't an issue for us because we always respond by + // aborting the connection; but if we did decide to continue we should + // first go to STATE_VERIFY_CERT and not send the client cert until that + // succeeded. --snej + + // If we knew the client cert, we would have set it already in + // InitializeSSLContext, instead of asking for this callback. + // So tell the caller that we need a client cert. + DCHECK(!ssl_config_.send_client_cert); + return ERR_SSL_CLIENT_AUTH_CERT_NEEDED; + + case errSSLClosedGraceful: + // The server unexpectedly closed on us. + return ERR_SSL_PROTOCOL_ERROR; } int net_error = NetErrorFromOSStatus(status); @@ -941,6 +983,7 @@ int SSLClientSocketMac::DoVerifyCert() { if (!server_cert_) return ERR_UNEXPECTED; + SSL_LOG << "DoVerifyCert..."; int flags = 0; if (ssl_config_.rev_checking_enabled) flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED; @@ -956,6 +999,7 @@ int SSLClientSocketMac::DoVerifyCertComplete(int result) { DCHECK(verifier_.get()); verifier_.reset(); + SSL_LOG << "...DoVerifyCertComplete (result=" << result << ")"; if (IsCertificateError(result) && ssl_config_.IsAllowedBadCert(server_cert_)) result = OK; @@ -968,6 +1012,7 @@ int SSLClientSocketMac::DoVerifyCertComplete(int result) { } else { // If the session was resumed or session resumption was disabled, we're // done with the handshake. + SSL_LOG << "Handshake finished! (DoVerifyCertComplete)"; completed_handshake_ = true; DCHECK(next_handshake_state_ == STATE_NONE); } @@ -981,6 +1026,7 @@ int SSLClientSocketMac::SetClientCert() { scoped_cftyperef<CFArrayRef> cert_refs( ssl_config_.client_cert->CreateClientCertificateChain()); + SSL_LOG << "SSLSetCertificate(" << CFArrayGetCount(cert_refs) << " certs)"; OSStatus result = SSLSetCertificate(ssl_context_, cert_refs); if (result) LOG(ERROR) << "SSLSetCertificate returned OSStatus " << result; @@ -995,9 +1041,12 @@ int SSLClientSocketMac::DoHandshakeFinish() { next_handshake_state_ = STATE_HANDSHAKE_FINISH; break; case errSSLClientCertRequested: - status = SetClientCert(); - next_handshake_state_ = STATE_HANDSHAKE_FINISH; - break; + SSL_LOG << "Server requested client cert (DoHandshakeFinish)"; + // If we knew the client cert, we would have set it already in + // InitializeSSLContext, instead of asking for this callback. + // So tell the caller that we need a client cert. + DCHECK(!ssl_config_.send_client_cert); + return ERR_SSL_CLIENT_AUTH_CERT_NEEDED; case errSSLClosedGraceful: return ERR_SSL_PROTOCOL_ERROR; case errSSLClosedAbort: @@ -1007,15 +1056,18 @@ int SSLClientSocketMac::DoHandshakeFinish() { if (SSLGetClientCertificateState(ssl_context_, &client_state) == noErr && client_state > kSSLClientCertNone) { if (client_state == kSSLClientCertRequested && - !ssl_config_.send_client_cert) + !ssl_config_.send_client_cert) { + SSL_LOG << "Server requested SSL cert during handshake"; return ERR_SSL_CLIENT_AUTH_CERT_NEEDED; - LOG(WARNING) << "Server aborted SSL handshake; client_state=" << - client_state; + } + LOG(WARNING) << "Server aborted SSL handshake; client_state=" + << client_state; return ERR_BAD_SSL_CLIENT_AUTH_CERT; } break; } case noErr: + SSL_LOG << "Handshake finished! (DoHandshakeFinish)"; completed_handshake_ = true; DCHECK(next_handshake_state_ == STATE_NONE); break; @@ -1054,7 +1106,7 @@ int SSLClientSocketMac::DoPayloadRead() { // Server wants to renegotiate, probably to ask for a client cert, // but SecureTransport doesn't support renegotiation so we have to close. // Tell my caller the server wants a client cert so it can reconnect. - LOG(INFO) << "Server renegotiating for client cert; restarting..."; + SSL_LOG << "Server renegotiating; assuming it wants a client cert..."; return ERR_SSL_CLIENT_AUTH_CERT_NEEDED; default: |