OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/socket/ssl_client_socket_mac.h" | 5 #include "net/socket/ssl_client_socket_mac.h" |
6 | 6 |
7 #include <CoreServices/CoreServices.h> | 7 #include <CoreServices/CoreServices.h> |
8 #include <netdb.h> | 8 #include <netdb.h> |
9 #include <sys/socket.h> | 9 #include <sys/socket.h> |
10 #include <sys/types.h> | 10 #include <sys/types.h> |
11 | 11 |
12 #include <algorithm> | |
13 | |
12 #include "base/mac/scoped_cftyperef.h" | 14 #include "base/mac/scoped_cftyperef.h" |
13 #include "base/singleton.h" | 15 #include "base/singleton.h" |
14 #include "base/string_util.h" | 16 #include "base/string_util.h" |
15 #include "net/base/address_list.h" | 17 #include "net/base/address_list.h" |
16 #include "net/base/cert_verifier.h" | 18 #include "net/base/cert_verifier.h" |
17 #include "net/base/io_buffer.h" | 19 #include "net/base/io_buffer.h" |
18 #include "net/base/net_errors.h" | 20 #include "net/base/net_errors.h" |
19 #include "net/base/net_log.h" | 21 #include "net/base/net_log.h" |
20 #include "net/base/ssl_cert_request_info.h" | 22 #include "net/base/ssl_cert_request_info.h" |
21 #include "net/base/ssl_connection_status_flags.h" | 23 #include "net/base/ssl_connection_status_flags.h" |
22 #include "net/base/ssl_info.h" | 24 #include "net/base/ssl_info.h" |
23 #include "net/socket/client_socket_handle.h" | 25 #include "net/socket/client_socket_handle.h" |
26 #include "net/socket/ssl_error_params.h" | |
24 | 27 |
25 // Welcome to Mac SSL. We've been waiting for you. | 28 // Welcome to Mac SSL. We've been waiting for you. |
26 // | 29 // |
27 // The Mac SSL implementation is, like the Windows and NSS implementations, a | 30 // The Mac SSL implementation is, like the Windows and NSS implementations, a |
28 // giant state machine. This design constraint is due to the asynchronous nature | 31 // giant state machine. This design constraint is due to the asynchronous nature |
29 // of our underlying transport mechanism. We can call down to read/write on the | 32 // of our underlying transport mechanism. We can call down to read/write on the |
30 // network, but what happens is that either it completes immediately or returns | 33 // network, but what happens is that either it completes immediately or returns |
31 // saying that we'll get a callback sometime in the future. In that case, we | 34 // saying that we'll get a callback sometime in the future. In that case, we |
32 // have to return to our caller but pick up where we left off when we | 35 // have to return to our caller but pick up where we left off when we |
33 // resume. Thus the fun. | 36 // resume. Thus the fun. |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
136 TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019, | 139 TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019, |
137 }; | 140 }; |
138 #endif | 141 #endif |
139 | 142 |
140 // For an explanation of the Mac OS X error codes, please refer to: | 143 // For an explanation of the Mac OS X error codes, please refer to: |
141 // http://developer.apple.com/mac/library/documentation/Security/Reference/secur eTransportRef/Reference/reference.html | 144 // http://developer.apple.com/mac/library/documentation/Security/Reference/secur eTransportRef/Reference/reference.html |
142 int NetErrorFromOSStatus(OSStatus status) { | 145 int NetErrorFromOSStatus(OSStatus status) { |
143 switch (status) { | 146 switch (status) { |
144 case errSSLWouldBlock: | 147 case errSSLWouldBlock: |
145 return ERR_IO_PENDING; | 148 return ERR_IO_PENDING; |
149 case paramErr: | |
146 case errSSLBadCipherSuite: | 150 case errSSLBadCipherSuite: |
147 case errSSLBadConfiguration: | 151 case errSSLBadConfiguration: |
148 return ERR_INVALID_ARGUMENT; | 152 return ERR_INVALID_ARGUMENT; |
149 case errSSLClosedNoNotify: | 153 case errSSLClosedNoNotify: |
150 return ERR_CONNECTION_RESET; | 154 return ERR_CONNECTION_RESET; |
151 case errSSLClosedAbort: | 155 case errSSLClosedAbort: |
152 return ERR_CONNECTION_ABORTED; | 156 return ERR_CONNECTION_ABORTED; |
153 case errSSLInternal: | 157 case errSSLInternal: |
154 return ERR_UNEXPECTED; | 158 return ERR_UNEXPECTED; |
155 case errSSLBadRecordMac: | 159 case errSSLBadRecordMac: |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
193 // certificate_expired | 197 // certificate_expired |
194 // certificate_revoked | 198 // certificate_revoked |
195 // certificate_unknown | 199 // certificate_unknown |
196 // unknown_ca | 200 // unknown_ca |
197 case errSSLPeerCertUnknown...errSSLPeerBadCert: | 201 case errSSLPeerCertUnknown...errSSLPeerBadCert: |
198 case errSSLPeerUnknownCA: | 202 case errSSLPeerUnknownCA: |
199 case errSSLPeerAccessDenied: | 203 case errSSLPeerAccessDenied: |
200 LOG(WARNING) << "Server rejected client cert (OSStatus=" << status << ")"; | 204 LOG(WARNING) << "Server rejected client cert (OSStatus=" << status << ")"; |
201 return ERR_BAD_SSL_CLIENT_AUTH_CERT; | 205 return ERR_BAD_SSL_CLIENT_AUTH_CERT; |
202 | 206 |
207 case errSSLNegotiation: | |
203 case errSSLPeerInsufficientSecurity: | 208 case errSSLPeerInsufficientSecurity: |
204 case errSSLPeerProtocolVersion: | 209 case errSSLPeerProtocolVersion: |
205 return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; | 210 return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; |
206 | 211 |
207 case errSSLBufferOverflow: | 212 case errSSLBufferOverflow: |
208 case errSSLModuleAttach: | 213 case errSSLModuleAttach: |
209 case errSSLNegotiation: | |
210 case errSSLSessionNotFound: | 214 case errSSLSessionNotFound: |
211 default: | 215 default: |
212 LOG(WARNING) << "Unknown error " << status << | 216 LOG(WARNING) << "Unknown error " << status << |
213 " mapped to net::ERR_FAILED"; | 217 " mapped to net::ERR_FAILED"; |
214 return ERR_FAILED; | 218 return ERR_FAILED; |
215 } | 219 } |
216 } | 220 } |
217 | 221 |
218 OSStatus OSStatusFromNetError(int net_error) { | 222 OSStatus OSStatusFromNetError(int net_error) { |
219 switch (net_error) { | 223 switch (net_error) { |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
441 // Dynamically look up a pointer to a function exported by a bundle. | 445 // Dynamically look up a pointer to a function exported by a bundle. |
442 template <typename FNTYPE> | 446 template <typename FNTYPE> |
443 FNTYPE LookupFunction(CFStringRef bundleName, CFStringRef fnName) { | 447 FNTYPE LookupFunction(CFStringRef bundleName, CFStringRef fnName) { |
444 CFBundleRef bundle = CFBundleGetBundleWithIdentifier(bundleName); | 448 CFBundleRef bundle = CFBundleGetBundleWithIdentifier(bundleName); |
445 if (!bundle) | 449 if (!bundle) |
446 return NULL; | 450 return NULL; |
447 return reinterpret_cast<FNTYPE>( | 451 return reinterpret_cast<FNTYPE>( |
448 CFBundleGetFunctionPointerForName(bundle, fnName)); | 452 CFBundleGetFunctionPointerForName(bundle, fnName)); |
449 } | 453 } |
450 | 454 |
451 // A class that wraps an array of enabled cipher suites that can be passed to | 455 struct CipherSuiteIsDisabledFunctor { |
452 // SSLSetEnabledCiphers. | 456 explicit CipherSuiteIsDisabledFunctor( |
453 // | 457 const std::vector<uint16>& disabled_cipher_suites) |
454 // Used as a singleton. | 458 : disabled_cipher_suites_(disabled_cipher_suites) {} |
459 | |
460 // Returns true if the given |cipher_suite| appears within the set of | |
461 // |disabled_cipher_suites|. | |
462 bool operator()(SSLCipherSuite cipher_suite) const { | |
463 return binary_search(disabled_cipher_suites_.begin(), | |
464 disabled_cipher_suites_.end(), | |
465 static_cast<uint16>(cipher_suite)); | |
466 } | |
467 | |
468 const std::vector<uint16>& disabled_cipher_suites_; | |
469 }; | |
470 | |
471 // Class to determine what cipher suites are available and which cipher | |
472 // suites should be enabled, based on the overall security policy. | |
455 class EnabledCipherSuites { | 473 class EnabledCipherSuites { |
456 public: | 474 public: |
457 EnabledCipherSuites(); | 475 const std::vector<SSLCipherSuite>& ciphers() const { return ciphers_; } |
458 | |
459 const SSLCipherSuite* ciphers() const { | |
460 return ciphers_.empty() ? NULL : &ciphers_[0]; | |
461 } | |
462 size_t num_ciphers() const { return ciphers_.size(); } | |
463 | 476 |
464 private: | 477 private: |
478 friend struct DefaultSingletonTraits<EnabledCipherSuites>; | |
479 EnabledCipherSuites(); | |
480 ~EnabledCipherSuites() {} | |
481 | |
465 std::vector<SSLCipherSuite> ciphers_; | 482 std::vector<SSLCipherSuite> ciphers_; |
466 | 483 |
467 DISALLOW_COPY_AND_ASSIGN(EnabledCipherSuites); | 484 DISALLOW_COPY_AND_ASSIGN(EnabledCipherSuites); |
468 }; | 485 }; |
469 | 486 |
470 EnabledCipherSuites::EnabledCipherSuites() { | 487 EnabledCipherSuites::EnabledCipherSuites() { |
471 SSLContextRef ssl_context; | 488 SSLContextRef ssl_context; |
472 OSStatus status = SSLNewContext(false, &ssl_context); | 489 OSStatus status = SSLNewContext(false, &ssl_context); |
473 if (status != noErr) | 490 if (status != noErr) |
474 return; | 491 return; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
513 user_read_callback_(NULL), | 530 user_read_callback_(NULL), |
514 user_write_callback_(NULL), | 531 user_write_callback_(NULL), |
515 user_read_buf_len_(0), | 532 user_read_buf_len_(0), |
516 user_write_buf_len_(0), | 533 user_write_buf_len_(0), |
517 next_handshake_state_(STATE_NONE), | 534 next_handshake_state_(STATE_NONE), |
518 renegotiating_(false), | 535 renegotiating_(false), |
519 client_cert_requested_(false), | 536 client_cert_requested_(false), |
520 ssl_context_(NULL), | 537 ssl_context_(NULL), |
521 pending_send_error_(OK), | 538 pending_send_error_(OK), |
522 net_log_(transport_socket->socket()->NetLog()) { | 539 net_log_(transport_socket->socket()->NetLog()) { |
540 // Sort the list of ciphers to disable, since disabling ciphers on Mac | |
541 // requires subtracting from a list of enabled ciphers while maintaining | |
542 // ordering, as opposed to merely needing to iterate them as with NSS. | |
543 sort(ssl_config_.disabled_cipher_suites.begin(), | |
544 ssl_config_.disabled_cipher_suites.end()); | |
523 } | 545 } |
524 | 546 |
525 SSLClientSocketMac::~SSLClientSocketMac() { | 547 SSLClientSocketMac::~SSLClientSocketMac() { |
526 Disconnect(); | 548 Disconnect(); |
527 } | 549 } |
528 | 550 |
529 int SSLClientSocketMac::Connect(CompletionCallback* callback) { | 551 int SSLClientSocketMac::Connect(CompletionCallback* callback) { |
530 DCHECK(transport_.get()); | 552 DCHECK(transport_.get()); |
531 DCHECK(next_handshake_state_ == STATE_NONE); | 553 DCHECK(next_handshake_state_ == STATE_NONE); |
532 DCHECK(!user_connect_callback_); | 554 DCHECK(!user_connect_callback_); |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
754 ssl_config_.ssl3_enabled); | 776 ssl_config_.ssl3_enabled); |
755 if (status) | 777 if (status) |
756 return NetErrorFromOSStatus(status); | 778 return NetErrorFromOSStatus(status); |
757 | 779 |
758 status = SSLSetProtocolVersionEnabled(ssl_context_, | 780 status = SSLSetProtocolVersionEnabled(ssl_context_, |
759 kTLSProtocol1, | 781 kTLSProtocol1, |
760 ssl_config_.tls1_enabled); | 782 ssl_config_.tls1_enabled); |
761 if (status) | 783 if (status) |
762 return NetErrorFromOSStatus(status); | 784 return NetErrorFromOSStatus(status); |
763 | 785 |
764 const EnabledCipherSuites* enabled_ciphers = | 786 std::vector<SSLCipherSuite> enabled_ciphers = |
765 Singleton<EnabledCipherSuites>::get(); | 787 Singleton<EnabledCipherSuites>::get()->ciphers(); |
wtc
2010/11/10 00:43:37
My concern about the sorted disabled cipher list i
| |
766 status = SSLSetEnabledCiphers(ssl_context_, enabled_ciphers->ciphers(), | 788 |
767 enabled_ciphers->num_ciphers()); | 789 CipherSuiteIsDisabledFunctor is_disabled_cipher( |
790 ssl_config_.disabled_cipher_suites); | |
791 std::vector<SSLCipherSuite>::iterator new_end = | |
792 std::remove_if(enabled_ciphers.begin(), enabled_ciphers.end(), | |
793 is_disabled_cipher); | |
794 if (new_end != enabled_ciphers.end()) | |
795 enabled_ciphers.erase(new_end, enabled_ciphers.end()); | |
796 | |
797 status = SSLSetEnabledCiphers( | |
798 ssl_context_, | |
799 enabled_ciphers.empty() ? NULL : &enabled_ciphers[0], | |
800 enabled_ciphers.size()); | |
801 | |
768 if (status) | 802 if (status) |
769 return NetErrorFromOSStatus(status); | 803 return NetErrorFromOSStatus(status); |
770 | 804 |
771 status = SSLSetIOFuncs(ssl_context_, SSLReadCallback, SSLWriteCallback); | 805 status = SSLSetIOFuncs(ssl_context_, SSLReadCallback, SSLWriteCallback); |
772 if (status) | 806 if (status) |
773 return NetErrorFromOSStatus(status); | 807 return NetErrorFromOSStatus(status); |
774 | 808 |
775 status = SSLSetConnection(ssl_context_, this); | 809 status = SSLSetConnection(ssl_context_, this); |
776 if (status) | 810 if (status) |
777 return NetErrorFromOSStatus(status); | 811 return NetErrorFromOSStatus(status); |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
963 client_cert_requested_ = false; | 997 client_cert_requested_ = false; |
964 | 998 |
965 OSStatus status = SSLHandshake(ssl_context_); | 999 OSStatus status = SSLHandshake(ssl_context_); |
966 | 1000 |
967 SSLClientCertificateState client_cert_state; | 1001 SSLClientCertificateState client_cert_state; |
968 if (SSLGetClientCertificateState(ssl_context_, &client_cert_state) != noErr) | 1002 if (SSLGetClientCertificateState(ssl_context_, &client_cert_state) != noErr) |
969 client_cert_state = kSSLClientCertNone; | 1003 client_cert_state = kSSLClientCertNone; |
970 if (client_cert_state > kSSLClientCertNone) | 1004 if (client_cert_state > kSSLClientCertNone) |
971 client_cert_requested_ = true; | 1005 client_cert_requested_ = true; |
972 | 1006 |
1007 int net_error = ERR_FAILED; | |
973 switch (status) { | 1008 switch (status) { |
974 case noErr: | 1009 case noErr: |
975 return DidCompleteHandshake(); | 1010 return DidCompleteHandshake(); |
976 case errSSLWouldBlock: | 1011 case errSSLWouldBlock: |
977 next_handshake_state_ = STATE_HANDSHAKE; | 1012 next_handshake_state_ = STATE_HANDSHAKE; |
978 break; | 1013 return ERR_IO_PENDING; |
979 case errSSLClosedGraceful: | 1014 case errSSLClosedGraceful: |
980 // The server unexpectedly closed on us. | 1015 // The server unexpectedly closed on us. |
981 return ERR_SSL_PROTOCOL_ERROR; | 1016 net_error = ERR_SSL_PROTOCOL_ERROR; |
1017 break; | |
982 case errSSLClosedAbort: | 1018 case errSSLClosedAbort: |
983 case errSSLPeerHandshakeFail: | 1019 case errSSLPeerHandshakeFail: |
984 if (client_cert_requested_) { | 1020 if (client_cert_requested_) { |
985 // See if the server aborted due to client cert checking. | |
986 if (!ssl_config_.send_client_cert) { | 1021 if (!ssl_config_.send_client_cert) { |
1022 // The server aborted, likely due to requiring a client certificate | |
1023 // and one wasn't sent. | |
987 VLOG(1) << "Server requested SSL cert during handshake"; | 1024 VLOG(1) << "Server requested SSL cert during handshake"; |
988 return ERR_SSL_CLIENT_AUTH_CERT_NEEDED; | 1025 net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED; |
1026 } else { | |
1027 // The server aborted, likely due to not liking the client | |
1028 // certificate that was sent. | |
1029 LOG(WARNING) << "Server aborted SSL handshake"; | |
1030 net_error = ERR_BAD_SSL_CLIENT_AUTH_CERT; | |
989 } | 1031 } |
990 LOG(WARNING) << "Server aborted SSL handshake"; | 1032 // Don't fall through - the error was intentionally remapped. |
991 return ERR_BAD_SSL_CLIENT_AUTH_CERT; | 1033 break; |
1034 } | |
1035 // Fall through if a client cert wasn't requested. | |
1036 default: | |
1037 net_error = NetErrorFromOSStatus(status); | |
1038 DCHECK(!IsCertificateError(net_error)); | |
1039 if (!ssl_config_.send_client_cert && | |
1040 (client_cert_state == kSSLClientCertRejected || | |
1041 net_error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) { | |
1042 // The server unexpectedly sent a peer certificate error alert when no | |
1043 // certificate had been sent. | |
1044 net_error = ERR_SSL_PROTOCOL_ERROR; | |
992 } | 1045 } |
993 break; | 1046 break; |
994 } | 1047 } |
995 | 1048 |
996 int net_error = NetErrorFromOSStatus(status); | 1049 net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR, |
997 DCHECK(!IsCertificateError(net_error)); | 1050 new SSLErrorParams(net_error, status)); |
998 | |
999 if (!ssl_config_.send_client_cert && | |
1000 (client_cert_state == kSSLClientCertRejected || | |
1001 net_error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) { | |
1002 // The server unexpectedly sent a peer certificate error alert when no | |
1003 // certificate had been sent. | |
1004 net_error = ERR_SSL_PROTOCOL_ERROR; | |
1005 } | |
1006 return net_error; | 1051 return net_error; |
1007 } | 1052 } |
1008 | 1053 |
1009 int SSLClientSocketMac::DoVerifyCert() { | 1054 int SSLClientSocketMac::DoVerifyCert() { |
1010 next_handshake_state_ = STATE_VERIFY_CERT_COMPLETE; | 1055 next_handshake_state_ = STATE_VERIFY_CERT_COMPLETE; |
1011 | 1056 |
1012 DCHECK(server_cert_); | 1057 DCHECK(server_cert_); |
1013 | 1058 |
1014 VLOG(1) << "DoVerifyCert..."; | 1059 VLOG(1) << "DoVerifyCert..."; |
1015 int flags = 0; | 1060 int flags = 0; |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1273 if (rv < 0 && rv != ERR_IO_PENDING) { | 1318 if (rv < 0 && rv != ERR_IO_PENDING) { |
1274 us->write_io_buf_ = NULL; | 1319 us->write_io_buf_ = NULL; |
1275 return OSStatusFromNetError(rv); | 1320 return OSStatusFromNetError(rv); |
1276 } | 1321 } |
1277 | 1322 |
1278 // always lie to our caller | 1323 // always lie to our caller |
1279 return noErr; | 1324 return noErr; |
1280 } | 1325 } |
1281 | 1326 |
1282 } // namespace net | 1327 } // namespace net |
OLD | NEW |