From 30a4832669a17c87e825a9984203974fa1b0e720 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 6 Jan 2022 18:07:05 +0100 Subject: [PATCH 1/4] add `Connection.set_verify`, fix #255 --- CHANGELOG.rst | 4 ++++ src/OpenSSL/SSL.py | 29 +++++++++++++++++++++++++++++ tests/test_ssl.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d91b1a197..5f2589f72 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,6 +19,10 @@ Deprecations: Changes: ^^^^^^^^ +- Add ``OpenSSL.SSL.Connection.set_verify`` and ``OpenSSL.SSL.Connection.get_verify_mode`` + to override the context object's verification flags. + `#1073 `_ + 22.0.0 (2022-01-29) ------------------- diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py index d100e6c0f..f47046005 100644 --- a/src/OpenSSL/SSL.py +++ b/src/OpenSSL/SSL.py @@ -1745,6 +1745,35 @@ def get_servername(self): return _ffi.string(name) + def set_verify(self, mode, callback=None): + """ + Override the Context object's verification flags for this specific + connection. See :py:meth:`Context.set_verify` for details. + """ + if not isinstance(mode, int): + raise TypeError("mode must be an integer") + + if callback is None: + self._verify_helper = None + self._verify_callback = None + _lib.SSL_set_verify(self._ssl, mode, _ffi.NULL) + else: + if not callable(callback): + raise TypeError("callback must be callable") + + self._verify_helper = _VerifyHelper(callback) + self._verify_callback = self._verify_helper.callback + _lib.SSL_set_verify(self._ssl, mode, self._verify_callback) + + def get_verify_mode(self): + """ + Retrieve the Connection object's verify mode, as set by + :meth:`set_verify`. + + :return: The verify mode + """ + return _lib.SSL_get_verify_mode(self._ssl) + def set_ciphertext_mtu(self, mtu): """ For DTLS, set the maximum UDP payload size (*not* including IP/UDP diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 56748fad9..c7e61b645 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -2630,6 +2630,51 @@ def test_get_verified_chain_unconnected(self): server = Connection(ctx, None) assert None is server.get_verified_chain() + def test_set_verify_overrides_context(self): + context = Context(SSLv23_METHOD) + context.set_verify(VERIFY_PEER) + conn = Connection(context, None) + conn.set_verify(VERIFY_NONE) + + assert context.get_verify_mode() == VERIFY_PEER + assert conn.get_verify_mode() == VERIFY_NONE + + with pytest.raises(TypeError): + conn.set_verify(None) + + with pytest.raises(TypeError): + conn.set_verify(VERIFY_PEER, "not a callable") + + def test_set_verify_callback_reference(self): + """ + The callback for certificate verification should only be forgotten if the context and all connections + created by it do not use it anymore. + """ + def callback(conn, cert, errnum, depth, ok): # pragma: no cover + return ok + + tracker = ref(callback) + + context = Context(SSLv23_METHOD) + context.set_verify(VERIFY_PEER, callback) + del callback + + conn = Connection(context, None) + context.set_verify(VERIFY_NONE) + + collect() + collect() + assert tracker() + + conn.set_verify(VERIFY_PEER, lambda conn, cert, errnum, depth, ok: ok) + collect() + collect() + callback = tracker() + if callback is not None: # pragma: nocover + referrers = get_referrers(callback) + if len(referrers) > 1: + pytest.fail("Some references remain: %r" % (referrers,)) + def test_get_session_unconnected(self): """ `Connection.get_session` returns `None` when used with an object From d437280672b03ca2f343fddfd3e1da588825c557 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 6 Jan 2022 18:15:14 +0100 Subject: [PATCH 2/4] show that it works with cryptography main --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 841016f82..720f10dc9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,7 +65,6 @@ jobs: strategy: matrix: TEST: - - {CONTAINER: "ubuntu-bionic", TOXENV: "py36"} # cryptographyMain used since there's no wheel - {CONTAINER: "ubuntu-rolling", TOXENV: "py310-cryptographyMain"} name: "${{ matrix.TEST.TOXENV }} on ${{ matrix.TEST.CONTAINER }}" From db63e1097278e858c0db4e6e79d895eb69d13e20 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Fri, 7 Jan 2022 19:19:29 +0100 Subject: [PATCH 3/4] Revert "show that it works with cryptography main" This reverts commit fb0136a8e5aa5d2c6e0c16f8f4ecee2f3c72a16b. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 720f10dc9..841016f82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,7 @@ jobs: strategy: matrix: TEST: + - {CONTAINER: "ubuntu-bionic", TOXENV: "py36"} # cryptographyMain used since there's no wheel - {CONTAINER: "ubuntu-rolling", TOXENV: "py310-cryptographyMain"} name: "${{ matrix.TEST.TOXENV }} on ${{ matrix.TEST.CONTAINER }}" From 46661cadf120ce5f6b6876c76be0e436fbc73394 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 11 May 2022 15:49:00 +0200 Subject: [PATCH 4/4] make it black --- tests/test_ssl.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index c7e61b645..5e69acee0 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -2647,9 +2647,10 @@ def test_set_verify_overrides_context(self): def test_set_verify_callback_reference(self): """ - The callback for certificate verification should only be forgotten if the context and all connections - created by it do not use it anymore. + The callback for certificate verification should only be forgotten if + the context and all connections created by it do not use it anymore. """ + def callback(conn, cert, errnum, depth, ok): # pragma: no cover return ok