Skip to content

Commit

Permalink
Context.set_verify: allow omission of callback
Browse files Browse the repository at this point in the history
  • Loading branch information
mhils committed Aug 7, 2020
1 parent 33c5499 commit 3b58e8f
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 13 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Changes:
- Added ``OpenSSL.SSL.Connection.get_verified_chain`` to retrieve the
verified certificate chain of the peer.
`#894 <https://github.com/pyca/pyopenssl/pull/894>`_.
- Allow omission of the verification callback in ``Context.set_verify``.
`#933 <https://github.com/pyca/pyopenssl/pull/933>`_


19.1.0 (2019-11-18)
Expand Down
22 changes: 14 additions & 8 deletions src/OpenSSL/SSL.py
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ def get_session_cache_mode(self):
"""
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.
Expand All @@ -1013,24 +1013,30 @@ def set_verify(self, mode, callback):
: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
:param callback: The optional 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.
passes and False otherwise. If omitted, OpenSSL's verification result
(the return code) is passed through.
:return: None
See SSL_CTX_set_verify(3SSL) for further details.
"""
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):
"""
Expand Down
31 changes: 26 additions & 5 deletions tests/test_ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,29 @@ def verify_callback(*args):

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`
Expand Down Expand Up @@ -1509,9 +1532,7 @@ def test_set_verify_mode(self):
"""
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"])
Expand All @@ -1522,9 +1543,9 @@ def test_set_verify_wrong_mode_arg(self, mode):
"""
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
Expand Down

0 comments on commit 3b58e8f

Please sign in to comment.