Chromium Code Reviews| Index: net/socket/ssl_client_socket_mac.cc | 
| diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc | 
| index ebb31f2d6c11ce54ab8303b7c7c5ba3cd340ffa6..ee6cc79134b0a0e44a2a9ca4594d782fb40c4f21 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"; | 
| 
 
wtc
2010/03/16 00:42:48
Nit: please align "<<" with the first "<<" on the
 
 | 
| + 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,42 @@ 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: | 
| 
 
wtc
2010/03/16 00:42:48
IMPORTANT:
1. Please document that if we get errS
 
Jens Alfke
2010/03/16 18:50:10
No, because we always abort the connection in this
 
 | 
| + SSL_LOG << "Received client cert request in DoHandshakeStart"; | 
| + // 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 +976,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 +992,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 +1005,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 +1019,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 +1034,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 +1049,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 +1099,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: |