From 79b9c79148f51fc9321ab4450947b259cb5804fb Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sat, 8 Aug 2020 03:08:17 +0200 Subject: Context.set_verify: allow omission of callback (#933) * Context.set_verify: allow omission of callback * squeeze to 80 chars * make it clear that default callback is used --- CHANGELOG.rst | 3 +++ src/OpenSSL/SSL.py | 28 +++++++++++++++++----------- tests/test_ssl.py | 31 ++++++++++++++++++++++++++----- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9ceedd0..e8c52c2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,6 +29,9 @@ Changes: - Added ``OpenSSL.SSL.Connection.get_verified_chain`` to retrieve the verified certificate chain of the peer. `#894 `_. +- Make verification callback optional in ``Context.set_verify``. + If omitted, OpenSSL's default verification is used. + `#933 `_ 19.1.0 (2019-11-18) diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py index 29e489a..d889624 100644 --- a/src/OpenSSL/SSL.py +++ b/src/OpenSSL/SSL.py @@ -1003,7 +1003,7 @@ class Context(object): """ return _lib.SSL_CTX_get_session_cache_mode(self._context) - def set_verify(self, mode, callback): + def set_verify(self, mode, callback=None): """ et the verification flags for this Context object to *mode* and specify that *callback* should be used for verification callbacks. @@ -1013,11 +1013,12 @@ class Context(object): :const:`VERIFY_PEER` is used, *mode* can be OR:ed with :const:`VERIFY_FAIL_IF_NO_PEER_CERT` and :const:`VERIFY_CLIENT_ONCE` to further control the behaviour. - :param callback: The Python callback to use. This should take five - arguments: A Connection object, an X509 object, and three integer - variables, which are in turn potential error number, error depth - and return code. *callback* should return True if verification - passes and False otherwise. + :param callback: The optional Python verification callback to use. + This should take five arguments: A Connection object, an X509 + object, and three integer variables, which are in turn potential + error number, error depth and return code. *callback* should + return True if verification passes and False otherwise. + If omitted, OpenSSL's default verification is used. :return: None See SSL_CTX_set_verify(3SSL) for further details. @@ -1025,12 +1026,17 @@ class Context(object): if not isinstance(mode, integer_types): raise TypeError("mode must be an integer") - if not callable(callback): - raise TypeError("callback must be callable") + if callback is None: + self._verify_helper = None + self._verify_callback = None + _lib.SSL_CTX_set_verify(self._context, 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_CTX_set_verify(self._context, mode, self._verify_callback) + self._verify_helper = _VerifyHelper(callback) + self._verify_callback = self._verify_helper.callback + _lib.SSL_CTX_set_verify(self._context, mode, self._verify_callback) def set_verify_depth(self, depth): """ diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 9f134b4..0860eb8 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -1378,6 +1378,29 @@ class TestContext(object): assert "silly verify failure" == str(exc.value) + @pytest.mark.parametrize("mode", [SSL.VERIFY_PEER, SSL.VERIFY_NONE]) + def test_set_verify_default_callback(self, mode): + """ + If the verify callback is omitted, the preverify value is used. + """ + serverContext = Context(TLSv1_2_METHOD) + serverContext.use_privatekey( + load_privatekey(FILETYPE_PEM, root_key_pem) + ) + serverContext.use_certificate( + load_certificate(FILETYPE_PEM, root_cert_pem) + ) + + clientContext = Context(TLSv1_2_METHOD) + clientContext.set_verify(mode, None) + + if mode == SSL.VERIFY_PEER: + with pytest.raises(Exception) as exc: + self._handshake_test(serverContext, clientContext) + assert "certificate verify failed" in str(exc.value) + else: + self._handshake_test(serverContext, clientContext) + def test_add_extra_chain_cert(self, tmpdir): """ `Context.add_extra_chain_cert` accepts an `X509` @@ -1509,9 +1532,7 @@ class TestContext(object): """ context = Context(SSLv23_METHOD) assert context.get_verify_mode() == 0 - context.set_verify( - VERIFY_PEER | VERIFY_CLIENT_ONCE, lambda *args: None - ) + context.set_verify(VERIFY_PEER | VERIFY_CLIENT_ONCE) assert context.get_verify_mode() == (VERIFY_PEER | VERIFY_CLIENT_ONCE) @pytest.mark.parametrize("mode", [None, 1.0, object(), "mode"]) @@ -1522,9 +1543,9 @@ class TestContext(object): """ context = Context(SSLv23_METHOD) with pytest.raises(TypeError): - context.set_verify(mode=mode, callback=lambda *args: None) + context.set_verify(mode=mode) - @pytest.mark.parametrize("callback", [None, 1.0, "mode", ("foo", "bar")]) + @pytest.mark.parametrize("callback", [1.0, "mode", ("foo", "bar")]) def test_set_verify_wrong_callable_arg(self, callback): """ `Context.set_verify` raises `TypeError` if the second argument -- cgit v1.2.3