diff --git a/oscrypto/_openssl/_libssl.py b/oscrypto/_openssl/_libssl.py index 2fa2bce..56d2a25 100644 --- a/oscrypto/_openssl/_libssl.py +++ b/oscrypto/_openssl/_libssl.py @@ -1,7 +1,10 @@ # coding: utf-8 from __future__ import unicode_literals, division, absolute_import, print_function -from .. import ffi +import re +import sys + +from .. import ffi, _backend_config # Initialize OpenSSL from ._libcrypto import libcrypto_version_info @@ -15,6 +18,7 @@ __all__ = [ 'libssl', 'LibsslConst', + 'error_code_version_info', ] @@ -87,3 +91,19 @@ class LibsslConst(): if libcrypto_version_info >= (1, 1, 0): LibsslConst.SSL_R_DH_KEY_TOO_SMALL = 394 + + +# The Apple version of libssl seems to have changed various codes for +# some reason, but the rest of the API is still OpenSSL 1.0.1 +if sys.platform == 'darwin' and re.match(r'/usr/lib/libssl\.\d', _backend_config().get('libssl_path', '')): + LibsslConst.SSL_F_TLS_PROCESS_SERVER_CERTIFICATE = 7 + LibsslConst.SSL_F_SSL3_GET_KEY_EXCHANGE = 9 + LibsslConst.SSL_F_SSL3_READ_BYTES = 4 + LibsslConst.SSL_F_SSL3_GET_RECORD = 4 + LibsslConst.SSL_F_SSL23_GET_SERVER_HELLO = 4 + error_code_version_info = (1, 1, 0) + error_code_variant = 'macos' + +else: + error_code_version_info = libcrypto_version_info + error_code_variant = 'openssl' diff --git a/oscrypto/_openssl/tls.py b/oscrypto/_openssl/tls.py index 6f180f4..4905a47 100644 --- a/oscrypto/_openssl/tls.py +++ b/oscrypto/_openssl/tls.py @@ -7,7 +7,7 @@ import select import numbers -from ._libssl import libssl, LibsslConst +from ._libssl import error_code_version_info, error_code_variant, libssl, LibsslConst from ._libcrypto import libcrypto, libcrypto_version_info, handle_openssl_error, peek_openssl_error from .. import _backend_config from .._asn1 import Certificate as Asn1Certificate @@ -554,7 +554,7 @@ def _handshake(self): if info == dh_key_info_1 or info == dh_key_info_2 or info == dh_key_info_3: raise_dh_params() - if libcrypto_version_info < (1, 1): + if error_code_version_info < (1, 1): unknown_protocol_info = ( LibsslConst.ERR_LIB_SSL, LibsslConst.SSL_F_SSL23_GET_SERVER_HELLO, @@ -580,23 +580,16 @@ def _handshake(self): if info == tls_version_info_error: raise_protocol_version() + # There are multiple functions that can result in a handshake failure, + # but our custom handshake parsing code figures out what really happened, + # and what is more, OpenSSL 3 got rid of function codes. Because of this, + # we skip checking the function code. handshake_error_info = ( LibsslConst.ERR_LIB_SSL, - LibsslConst.SSL_F_SSL23_GET_SERVER_HELLO, LibsslConst.SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE ) - # OpenSSL 3.0 no longer has func codes, so this can be confused - # with the following handler which needs to check for client auth - if libcrypto_version_info < (3, ) and info == handshake_error_info: - raise_handshake() - handshake_failure_info = ( - LibsslConst.ERR_LIB_SSL, - LibsslConst.SSL_F_SSL3_READ_BYTES, - LibsslConst.SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE - ) - handshake_failure_info = _homogenize_openssl3_error(handshake_failure_info) - if info == handshake_failure_info: + if (info[0], info[2]) == handshake_error_info: saw_client_auth = False for record_type, _, record_data in parse_tls_records(handshake_server_bytes): if record_type != b'\x16': @@ -609,7 +602,7 @@ def _handshake(self): raise_client_auth() raise_handshake() - if libcrypto_version_info < (1, 1): + if error_code_version_info < (1, 1): cert_verify_failed_info = ( LibsslConst.ERR_LIB_SSL, LibsslConst.SSL_F_SSL3_GET_SERVER_CERTIFICATE,