From e3a8c9fcd7ee646eb3e755af1a4a6e07f58cd883 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 6 Apr 2020 12:17:21 -0400 Subject: Drop OpenSSL 1.0.1 --- .travis.yml | 21 +-- CHANGELOG.rst | 1 + INSTALL.rst | 1 - src/OpenSSL/SSL.py | 16 +-- tests/test_ssl.py | 395 +++++++++++++++++++++++++---------------------------- 5 files changed, 198 insertions(+), 236 deletions(-) diff --git a/.travis.yml b/.travis.yml index cddbaa8..5cc9418 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,10 +15,7 @@ matrix: - language: generic os: osx osx_image: xcode10.1 - env: TOXENV=py27 OPENSSL=1.1.1 - - python: "2.7" # these are just to make travis's UI a bit prettier env: TOXENV=py27 - dist: trusty # For OpenSSL 1.0.1 coverage - python: "2.7" env: TOXENV=py27 - python: "3.5" @@ -108,11 +105,7 @@ install: - | if [[ "$(uname -s)" == 'Darwin' ]]; then brew update - if [[ "${OPENSSL}" == "1.1.1" ]]; then - brew upgrade openssl@1.1 - else - brew upgrade openssl - fi + brew upgrade openssl@1.1 curl -O https://bootstrap.pypa.io/get-pip.py python get-pip.py --user python -m pip install --user virtualenv @@ -126,15 +119,9 @@ script: - | if [[ "$(uname -s)" == 'Darwin' ]]; then # set our flags to use homebrew openssl - if [[ "${OPENSSL}" == "1.1.1" ]]; then - export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" - export CFLAGS="-I/usr/local/opt/openssl@1.1/include" - export PATH="/usr/local/opt/openssl@1.1/bin:$PATH" - else - export LDFLAGS="-L/usr/local/opt/openssl/lib" - export CFLAGS="-I/usr/local/opt/openssl/include" - export PATH="/usr/local/opt/openssl/bin:$PATH" - fi + export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" + export CFLAGS="-I/usr/local/opt/openssl@1.1/include" + export PATH="/usr/local/opt/openssl@1.1/bin:$PATH" fi openssl version ~/.venv/bin/tox -v diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c971970..f72d0a6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,7 @@ Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Drop support for Python 3.4 +- Drop support for OpenSSL 1.0.1 Deprecations: ^^^^^^^^^^^^^ diff --git a/INSTALL.rst b/INSTALL.rst index 8c9c8dc..75540d5 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -25,7 +25,6 @@ Supported OpenSSL Versions pyOpenSSL supports the same platforms and releases as the upstream cryptography project `does `_. Currently that means: -- 1.0.1 - 1.0.2 - 1.1.0 - 1.1.1 diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py index 03f1455..25308f1 100644 --- a/src/OpenSSL/SSL.py +++ b/src/OpenSSL/SSL.py @@ -727,14 +727,11 @@ class Context(object): _openssl_assert(context != _ffi.NULL) context = _ffi.gc(context, _lib.SSL_CTX_free) - # If SSL_CTX_set_ecdh_auto is available then set it so the ECDH curve - # will be auto-selected. This function was added in 1.0.2 and made a - # noop in 1.1.0+ (where it is set automatically). - try: - res = _lib.SSL_CTX_set_ecdh_auto(context, 1) - _openssl_assert(res == 1) - except AttributeError: - pass + # Set SSL_CTX_set_ecdh_auto so that the ECDH curve will be + # auto-selected. This function was added in 1.0.2 and made a noop in + # 1.1.0+ (where it is set automatically). + res = _lib.SSL_CTX_set_ecdh_auto(context, 1) + _openssl_assert(res == 1) self._context = context self._passphrase_helper = None @@ -2309,8 +2306,7 @@ class Connection(object): raise TypeError("session must be a Session instance") result = _lib.SSL_set_session(self._ssl, session._session) - if not result: - _raise_current_error() + _openssl_assert(result == 1) def _get_finished_message(self, function): """ diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 9a3f294..50e2026 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -1846,277 +1846,256 @@ class TestApplicationLayerProtoNegotiation(object): """ Tests for ALPN in PyOpenSSL. """ - # Skip tests on versions that don't support ALPN. - if _lib.Cryptography_HAS_ALPN: - - def test_alpn_success(self): - """ - Clients and servers that agree on the negotiated ALPN protocol can - correct establish a connection, and the agreed protocol is reported - by the connections. - """ - select_args = [] - - def select(conn, options): - select_args.append((conn, options)) - return b'spdy/2' + def test_alpn_success(self): + """ + Clients and servers that agree on the negotiated ALPN protocol can + correct establish a connection, and the agreed protocol is reported + by the connections. + """ + select_args = [] - client_context = Context(TLSv1_METHOD) - client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) + def select(conn, options): + select_args.append((conn, options)) + return b'spdy/2' - server_context = Context(TLSv1_METHOD) - server_context.set_alpn_select_callback(select) + client_context = Context(TLSv1_METHOD) + client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) - # Necessary to actually accept the connection - server_context.use_privatekey( - load_privatekey(FILETYPE_PEM, server_key_pem)) - server_context.use_certificate( - load_certificate(FILETYPE_PEM, server_cert_pem)) + server_context = Context(TLSv1_METHOD) + server_context.set_alpn_select_callback(select) - # Do a little connection to trigger the logic - server = Connection(server_context, None) - server.set_accept_state() + # Necessary to actually accept the connection + server_context.use_privatekey( + load_privatekey(FILETYPE_PEM, server_key_pem)) + server_context.use_certificate( + load_certificate(FILETYPE_PEM, server_cert_pem)) - client = Connection(client_context, None) - client.set_connect_state() + # Do a little connection to trigger the logic + server = Connection(server_context, None) + server.set_accept_state() - interact_in_memory(server, client) + client = Connection(client_context, None) + client.set_connect_state() - assert select_args == [(server, [b'http/1.1', b'spdy/2'])] + interact_in_memory(server, client) - assert server.get_alpn_proto_negotiated() == b'spdy/2' - assert client.get_alpn_proto_negotiated() == b'spdy/2' + assert select_args == [(server, [b'http/1.1', b'spdy/2'])] - def test_alpn_set_on_connection(self): - """ - The same as test_alpn_success, but setting the ALPN protocols on - the connection rather than the context. - """ - select_args = [] + assert server.get_alpn_proto_negotiated() == b'spdy/2' + assert client.get_alpn_proto_negotiated() == b'spdy/2' - def select(conn, options): - select_args.append((conn, options)) - return b'spdy/2' + def test_alpn_set_on_connection(self): + """ + The same as test_alpn_success, but setting the ALPN protocols on + the connection rather than the context. + """ + select_args = [] - # Setup the client context but don't set any ALPN protocols. - client_context = Context(TLSv1_METHOD) + def select(conn, options): + select_args.append((conn, options)) + return b'spdy/2' - server_context = Context(TLSv1_METHOD) - server_context.set_alpn_select_callback(select) + # Setup the client context but don't set any ALPN protocols. + client_context = Context(TLSv1_METHOD) - # Necessary to actually accept the connection - server_context.use_privatekey( - load_privatekey(FILETYPE_PEM, server_key_pem)) - server_context.use_certificate( - load_certificate(FILETYPE_PEM, server_cert_pem)) + server_context = Context(TLSv1_METHOD) + server_context.set_alpn_select_callback(select) - # Do a little connection to trigger the logic - server = Connection(server_context, None) - server.set_accept_state() + # Necessary to actually accept the connection + server_context.use_privatekey( + load_privatekey(FILETYPE_PEM, server_key_pem)) + server_context.use_certificate( + load_certificate(FILETYPE_PEM, server_cert_pem)) - # Set the ALPN protocols on the client connection. - client = Connection(client_context, None) - client.set_alpn_protos([b'http/1.1', b'spdy/2']) - client.set_connect_state() + # Do a little connection to trigger the logic + server = Connection(server_context, None) + server.set_accept_state() - interact_in_memory(server, client) + # Set the ALPN protocols on the client connection. + client = Connection(client_context, None) + client.set_alpn_protos([b'http/1.1', b'spdy/2']) + client.set_connect_state() - assert select_args == [(server, [b'http/1.1', b'spdy/2'])] + interact_in_memory(server, client) - assert server.get_alpn_proto_negotiated() == b'spdy/2' - assert client.get_alpn_proto_negotiated() == b'spdy/2' + assert select_args == [(server, [b'http/1.1', b'spdy/2'])] - def test_alpn_server_fail(self): - """ - When clients and servers cannot agree on what protocol to use next - the TLS connection does not get established. - """ - select_args = [] + assert server.get_alpn_proto_negotiated() == b'spdy/2' + assert client.get_alpn_proto_negotiated() == b'spdy/2' - def select(conn, options): - select_args.append((conn, options)) - return b'' + def test_alpn_server_fail(self): + """ + When clients and servers cannot agree on what protocol to use next + the TLS connection does not get established. + """ + select_args = [] - client_context = Context(TLSv1_METHOD) - client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) + def select(conn, options): + select_args.append((conn, options)) + return b'' - server_context = Context(TLSv1_METHOD) - server_context.set_alpn_select_callback(select) + client_context = Context(TLSv1_METHOD) + client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) - # Necessary to actually accept the connection - server_context.use_privatekey( - load_privatekey(FILETYPE_PEM, server_key_pem)) - server_context.use_certificate( - load_certificate(FILETYPE_PEM, server_cert_pem)) + server_context = Context(TLSv1_METHOD) + server_context.set_alpn_select_callback(select) - # Do a little connection to trigger the logic - server = Connection(server_context, None) - server.set_accept_state() + # Necessary to actually accept the connection + server_context.use_privatekey( + load_privatekey(FILETYPE_PEM, server_key_pem)) + server_context.use_certificate( + load_certificate(FILETYPE_PEM, server_cert_pem)) - client = Connection(client_context, None) - client.set_connect_state() + # Do a little connection to trigger the logic + server = Connection(server_context, None) + server.set_accept_state() - # If the client doesn't return anything, the connection will fail. - with pytest.raises(Error): - interact_in_memory(server, client) + client = Connection(client_context, None) + client.set_connect_state() - assert select_args == [(server, [b'http/1.1', b'spdy/2'])] + # If the client doesn't return anything, the connection will fail. + with pytest.raises(Error): + interact_in_memory(server, client) - def test_alpn_no_server_overlap(self): - """ - A server can allow a TLS handshake to complete without - agreeing to an application protocol by returning - ``NO_OVERLAPPING_PROTOCOLS``. - """ - refusal_args = [] + assert select_args == [(server, [b'http/1.1', b'spdy/2'])] - def refusal(conn, options): - refusal_args.append((conn, options)) - return NO_OVERLAPPING_PROTOCOLS + def test_alpn_no_server_overlap(self): + """ + A server can allow a TLS handshake to complete without + agreeing to an application protocol by returning + ``NO_OVERLAPPING_PROTOCOLS``. + """ + refusal_args = [] - client_context = Context(SSLv23_METHOD) - client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) + def refusal(conn, options): + refusal_args.append((conn, options)) + return NO_OVERLAPPING_PROTOCOLS - server_context = Context(SSLv23_METHOD) - server_context.set_alpn_select_callback(refusal) + client_context = Context(SSLv23_METHOD) + client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) - # Necessary to actually accept the connection - server_context.use_privatekey( - load_privatekey(FILETYPE_PEM, server_key_pem)) - server_context.use_certificate( - load_certificate(FILETYPE_PEM, server_cert_pem)) + server_context = Context(SSLv23_METHOD) + server_context.set_alpn_select_callback(refusal) - # Do a little connection to trigger the logic - server = Connection(server_context, None) - server.set_accept_state() + # Necessary to actually accept the connection + server_context.use_privatekey( + load_privatekey(FILETYPE_PEM, server_key_pem)) + server_context.use_certificate( + load_certificate(FILETYPE_PEM, server_cert_pem)) - client = Connection(client_context, None) - client.set_connect_state() + # Do a little connection to trigger the logic + server = Connection(server_context, None) + server.set_accept_state() - # Do the dance. - interact_in_memory(server, client) + client = Connection(client_context, None) + client.set_connect_state() - assert refusal_args == [(server, [b'http/1.1', b'spdy/2'])] + # Do the dance. + interact_in_memory(server, client) - assert client.get_alpn_proto_negotiated() == b'' + assert refusal_args == [(server, [b'http/1.1', b'spdy/2'])] - def test_alpn_select_cb_returns_invalid_value(self): - """ - If the ALPN selection callback returns anything other than - a bytestring or ``NO_OVERLAPPING_PROTOCOLS``, a - :py:exc:`TypeError` is raised. - """ - invalid_cb_args = [] + assert client.get_alpn_proto_negotiated() == b'' - def invalid_cb(conn, options): - invalid_cb_args.append((conn, options)) - return u"can't return unicode" + def test_alpn_select_cb_returns_invalid_value(self): + """ + If the ALPN selection callback returns anything other than + a bytestring or ``NO_OVERLAPPING_PROTOCOLS``, a + :py:exc:`TypeError` is raised. + """ + invalid_cb_args = [] - client_context = Context(SSLv23_METHOD) - client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) + def invalid_cb(conn, options): + invalid_cb_args.append((conn, options)) + return u"can't return unicode" - server_context = Context(SSLv23_METHOD) - server_context.set_alpn_select_callback(invalid_cb) + client_context = Context(SSLv23_METHOD) + client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) - # Necessary to actually accept the connection - server_context.use_privatekey( - load_privatekey(FILETYPE_PEM, server_key_pem)) - server_context.use_certificate( - load_certificate(FILETYPE_PEM, server_cert_pem)) + server_context = Context(SSLv23_METHOD) + server_context.set_alpn_select_callback(invalid_cb) - # Do a little connection to trigger the logic - server = Connection(server_context, None) - server.set_accept_state() + # Necessary to actually accept the connection + server_context.use_privatekey( + load_privatekey(FILETYPE_PEM, server_key_pem)) + server_context.use_certificate( + load_certificate(FILETYPE_PEM, server_cert_pem)) - client = Connection(client_context, None) - client.set_connect_state() + # Do a little connection to trigger the logic + server = Connection(server_context, None) + server.set_accept_state() - # Do the dance. - with pytest.raises(TypeError): - interact_in_memory(server, client) + client = Connection(client_context, None) + client.set_connect_state() - assert invalid_cb_args == [(server, [b'http/1.1', b'spdy/2'])] + # Do the dance. + with pytest.raises(TypeError): + interact_in_memory(server, client) - assert client.get_alpn_proto_negotiated() == b'' + assert invalid_cb_args == [(server, [b'http/1.1', b'spdy/2'])] - def test_alpn_no_server(self): - """ - When clients and servers cannot agree on what protocol to use next - because the server doesn't offer ALPN, no protocol is negotiated. - """ - client_context = Context(TLSv1_METHOD) - client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) + assert client.get_alpn_proto_negotiated() == b'' - server_context = Context(TLSv1_METHOD) + def test_alpn_no_server(self): + """ + When clients and servers cannot agree on what protocol to use next + because the server doesn't offer ALPN, no protocol is negotiated. + """ + client_context = Context(TLSv1_METHOD) + client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) - # Necessary to actually accept the connection - server_context.use_privatekey( - load_privatekey(FILETYPE_PEM, server_key_pem)) - server_context.use_certificate( - load_certificate(FILETYPE_PEM, server_cert_pem)) + server_context = Context(TLSv1_METHOD) - # Do a little connection to trigger the logic - server = Connection(server_context, None) - server.set_accept_state() + # Necessary to actually accept the connection + server_context.use_privatekey( + load_privatekey(FILETYPE_PEM, server_key_pem)) + server_context.use_certificate( + load_certificate(FILETYPE_PEM, server_cert_pem)) - client = Connection(client_context, None) - client.set_connect_state() + # Do a little connection to trigger the logic + server = Connection(server_context, None) + server.set_accept_state() - # Do the dance. - interact_in_memory(server, client) + client = Connection(client_context, None) + client.set_connect_state() - assert client.get_alpn_proto_negotiated() == b'' + # Do the dance. + interact_in_memory(server, client) - def test_alpn_callback_exception(self): - """ - We can handle exceptions in the ALPN select callback. - """ - select_args = [] + assert client.get_alpn_proto_negotiated() == b'' - def select(conn, options): - select_args.append((conn, options)) - raise TypeError() + def test_alpn_callback_exception(self): + """ + We can handle exceptions in the ALPN select callback. + """ + select_args = [] - client_context = Context(TLSv1_METHOD) - client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) + def select(conn, options): + select_args.append((conn, options)) + raise TypeError() - server_context = Context(TLSv1_METHOD) - server_context.set_alpn_select_callback(select) + client_context = Context(TLSv1_METHOD) + client_context.set_alpn_protos([b'http/1.1', b'spdy/2']) - # Necessary to actually accept the connection - server_context.use_privatekey( - load_privatekey(FILETYPE_PEM, server_key_pem)) - server_context.use_certificate( - load_certificate(FILETYPE_PEM, server_cert_pem)) + server_context = Context(TLSv1_METHOD) + server_context.set_alpn_select_callback(select) - # Do a little connection to trigger the logic - server = Connection(server_context, None) - server.set_accept_state() + # Necessary to actually accept the connection + server_context.use_privatekey( + load_privatekey(FILETYPE_PEM, server_key_pem)) + server_context.use_certificate( + load_certificate(FILETYPE_PEM, server_cert_pem)) - client = Connection(client_context, None) - client.set_connect_state() + # Do a little connection to trigger the logic + server = Connection(server_context, None) + server.set_accept_state() - with pytest.raises(TypeError): - interact_in_memory(server, client) - assert select_args == [(server, [b'http/1.1', b'spdy/2'])] + client = Connection(client_context, None) + client.set_connect_state() - else: - # No ALPN. - def test_alpn_not_implemented(self): - """ - If ALPN is not in OpenSSL, we should raise NotImplementedError. - """ - # Test the context methods first. - context = Context(TLSv1_METHOD) - with pytest.raises(NotImplementedError): - context.set_alpn_protos(None) - with pytest.raises(NotImplementedError): - context.set_alpn_select_callback(None) - - # Now test a connection. - conn = Connection(context) - with pytest.raises(NotImplementedError): - conn.set_alpn_protos(None) + with pytest.raises(TypeError): + interact_in_memory(server, client) + assert select_args == [(server, [b'http/1.1', b'spdy/2'])] class TestSession(object): -- cgit v1.2.1