| 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 d6fca9b48bd60d01534c0321e03a88108c754971..6ef573c1939c4195948a1bb782eab5ee3f3d9a0d 100644
|
| --- a/net/socket/ssl_client_socket_mac.cc
|
| +++ b/net/socket/ssl_client_socket_mac.cc
|
| @@ -9,6 +9,8 @@
|
| #include <sys/socket.h>
|
| #include <sys/types.h>
|
|
|
| +#include <algorithm>
|
| +
|
| #include "base/mac/scoped_cftyperef.h"
|
| #include "base/singleton.h"
|
| #include "base/string_util.h"
|
| @@ -21,6 +23,7 @@
|
| #include "net/base/ssl_connection_status_flags.h"
|
| #include "net/base/ssl_info.h"
|
| #include "net/socket/client_socket_handle.h"
|
| +#include "net/socket/ssl_error_params.h"
|
|
|
| // Welcome to Mac SSL. We've been waiting for you.
|
| //
|
| @@ -143,6 +146,7 @@ int NetErrorFromOSStatus(OSStatus status) {
|
| switch (status) {
|
| case errSSLWouldBlock:
|
| return ERR_IO_PENDING;
|
| + case paramErr:
|
| case errSSLBadCipherSuite:
|
| case errSSLBadConfiguration:
|
| return ERR_INVALID_ARGUMENT;
|
| @@ -200,13 +204,13 @@ int NetErrorFromOSStatus(OSStatus status) {
|
| LOG(WARNING) << "Server rejected client cert (OSStatus=" << status << ")";
|
| return ERR_BAD_SSL_CLIENT_AUTH_CERT;
|
|
|
| + case errSSLNegotiation:
|
| case errSSLPeerInsufficientSecurity:
|
| case errSSLPeerProtocolVersion:
|
| return ERR_SSL_VERSION_OR_CIPHER_MISMATCH;
|
|
|
| case errSSLBufferOverflow:
|
| case errSSLModuleAttach:
|
| - case errSSLNegotiation:
|
| case errSSLSessionNotFound:
|
| default:
|
| LOG(WARNING) << "Unknown error " << status <<
|
| @@ -448,20 +452,33 @@ FNTYPE LookupFunction(CFStringRef bundleName, CFStringRef fnName) {
|
| CFBundleGetFunctionPointerForName(bundle, fnName));
|
| }
|
|
|
| -// A class that wraps an array of enabled cipher suites that can be passed to
|
| -// SSLSetEnabledCiphers.
|
| -//
|
| -// Used as a singleton.
|
| +struct CipherSuiteIsDisabledFunctor {
|
| + explicit CipherSuiteIsDisabledFunctor(
|
| + const std::vector<uint16>& disabled_cipher_suites)
|
| + : disabled_cipher_suites_(disabled_cipher_suites) {}
|
| +
|
| + // Returns true if the given |cipher_suite| appears within the set of
|
| + // |disabled_cipher_suites|.
|
| + bool operator()(SSLCipherSuite cipher_suite) const {
|
| + return binary_search(disabled_cipher_suites_.begin(),
|
| + disabled_cipher_suites_.end(),
|
| + static_cast<uint16>(cipher_suite));
|
| + }
|
| +
|
| + const std::vector<uint16>& disabled_cipher_suites_;
|
| +};
|
| +
|
| +// Class to determine what cipher suites are available and which cipher
|
| +// suites should be enabled, based on the overall security policy.
|
| class EnabledCipherSuites {
|
| public:
|
| - EnabledCipherSuites();
|
| -
|
| - const SSLCipherSuite* ciphers() const {
|
| - return ciphers_.empty() ? NULL : &ciphers_[0];
|
| - }
|
| - size_t num_ciphers() const { return ciphers_.size(); }
|
| + const std::vector<SSLCipherSuite>& ciphers() const { return ciphers_; }
|
|
|
| private:
|
| + friend struct DefaultSingletonTraits<EnabledCipherSuites>;
|
| + EnabledCipherSuites();
|
| + ~EnabledCipherSuites() {}
|
| +
|
| std::vector<SSLCipherSuite> ciphers_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(EnabledCipherSuites);
|
| @@ -520,6 +537,11 @@ SSLClientSocketMac::SSLClientSocketMac(ClientSocketHandle* transport_socket,
|
| ssl_context_(NULL),
|
| pending_send_error_(OK),
|
| net_log_(transport_socket->socket()->NetLog()) {
|
| + // Sort the list of ciphers to disable, since disabling ciphers on Mac
|
| + // requires subtracting from a list of enabled ciphers while maintaining
|
| + // ordering, as opposed to merely needing to iterate them as with NSS.
|
| + sort(ssl_config_.disabled_cipher_suites.begin(),
|
| + ssl_config_.disabled_cipher_suites.end());
|
| }
|
|
|
| SSLClientSocketMac::~SSLClientSocketMac() {
|
| @@ -761,10 +783,22 @@ int SSLClientSocketMac::InitializeSSLContext() {
|
| if (status)
|
| return NetErrorFromOSStatus(status);
|
|
|
| - const EnabledCipherSuites* enabled_ciphers =
|
| - Singleton<EnabledCipherSuites>::get();
|
| - status = SSLSetEnabledCiphers(ssl_context_, enabled_ciphers->ciphers(),
|
| - enabled_ciphers->num_ciphers());
|
| + std::vector<SSLCipherSuite> enabled_ciphers =
|
| + Singleton<EnabledCipherSuites>::get()->ciphers();
|
| +
|
| + CipherSuiteIsDisabledFunctor is_disabled_cipher(
|
| + ssl_config_.disabled_cipher_suites);
|
| + std::vector<SSLCipherSuite>::iterator new_end =
|
| + std::remove_if(enabled_ciphers.begin(), enabled_ciphers.end(),
|
| + is_disabled_cipher);
|
| + if (new_end != enabled_ciphers.end())
|
| + enabled_ciphers.erase(new_end, enabled_ciphers.end());
|
| +
|
| + status = SSLSetEnabledCiphers(
|
| + ssl_context_,
|
| + enabled_ciphers.empty() ? NULL : &enabled_ciphers[0],
|
| + enabled_ciphers.size());
|
| +
|
| if (status)
|
| return NetErrorFromOSStatus(status);
|
|
|
| @@ -970,39 +1004,50 @@ int SSLClientSocketMac::DoHandshake() {
|
| if (client_cert_state > kSSLClientCertNone)
|
| client_cert_requested_ = true;
|
|
|
| + int net_error = ERR_FAILED;
|
| switch (status) {
|
| case noErr:
|
| return DidCompleteHandshake();
|
| case errSSLWouldBlock:
|
| next_handshake_state_ = STATE_HANDSHAKE;
|
| - break;
|
| + return ERR_IO_PENDING;
|
| case errSSLClosedGraceful:
|
| // The server unexpectedly closed on us.
|
| - return ERR_SSL_PROTOCOL_ERROR;
|
| + net_error = ERR_SSL_PROTOCOL_ERROR;
|
| + break;
|
| case errSSLClosedAbort:
|
| case errSSLPeerHandshakeFail:
|
| if (client_cert_requested_) {
|
| - // See if the server aborted due to client cert checking.
|
| if (!ssl_config_.send_client_cert) {
|
| + // The server aborted, likely due to requiring a client certificate
|
| + // and one wasn't sent.
|
| VLOG(1) << "Server requested SSL cert during handshake";
|
| - return ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
|
| + net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
|
| + } else {
|
| + // The server aborted, likely due to not liking the client
|
| + // certificate that was sent.
|
| + LOG(WARNING) << "Server aborted SSL handshake";
|
| + net_error = ERR_BAD_SSL_CLIENT_AUTH_CERT;
|
| }
|
| - LOG(WARNING) << "Server aborted SSL handshake";
|
| - return ERR_BAD_SSL_CLIENT_AUTH_CERT;
|
| + // Don't fall through - the error was intentionally remapped.
|
| + break;
|
| + }
|
| + // Fall through if a client cert wasn't requested.
|
| + default:
|
| + net_error = NetErrorFromOSStatus(status);
|
| + DCHECK(!IsCertificateError(net_error));
|
| + if (!ssl_config_.send_client_cert &&
|
| + (client_cert_state == kSSLClientCertRejected ||
|
| + net_error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
|
| + // The server unexpectedly sent a peer certificate error alert when no
|
| + // certificate had been sent.
|
| + net_error = ERR_SSL_PROTOCOL_ERROR;
|
| }
|
| break;
|
| }
|
|
|
| - int net_error = NetErrorFromOSStatus(status);
|
| - DCHECK(!IsCertificateError(net_error));
|
| -
|
| - if (!ssl_config_.send_client_cert &&
|
| - (client_cert_state == kSSLClientCertRejected ||
|
| - net_error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
|
| - // The server unexpectedly sent a peer certificate error alert when no
|
| - // certificate had been sent.
|
| - net_error = ERR_SSL_PROTOCOL_ERROR;
|
| - }
|
| + net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR,
|
| + new SSLErrorParams(net_error, status));
|
| return net_error;
|
| }
|
|
|
|
|