pyopenssl
pyopenssl copied to clipboard
21.0.0: pytest is failing and `DeprecationWarning` warnings
I'm trying to package your module as an rpm package. So I'm using the typical PEP517 based build, install and test cycle used on building packages from non-root account.
python3 -sBm build -w- install .whl file in </install/prefix>
- run pytest with PYTHONPATH pointing to sitearch and sitelib inside </install/prefix>
- I'm using openssl 3.0.0
Here is pytest output:
+ SETUPTOOLS_SCM_PRETEND_VERSION=21.0.0
+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-pyOpenSSL-21.0.0-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-pyOpenSSL-21.0.0-2.fc35.x86_64/usr/lib/python3.8/site-packages
+ /usr/bin/pytest -ra
=========================================================================== test session starts ============================================================================
platform linux -- Python 3.8.12, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
OpenSSL: b'OpenSSL 3.0.0 7 sep 2021'
cryptography: 36.0.1
rootdir: /home/tkloczko/rpmbuild/BUILD/pyopenssl-21.0.0, configfile: setup.cfg, testpaths: tests
plugins: flaky-3.7.0
collected 526 items
tests/test_crypto.py ...............................................................................................F............................................... [ 27%]
..............................................................................................................F................................. [ 54%]
tests/test_debug.py . [ 54%]
tests/test_rand.py .... [ 55%]
tests/test_ssl.py .....F....F..................................F.................................................................................................... [ 83%]
.............................................................F......................... [ 99%]
tests/test_util.py . [100%]
================================================================================= FAILURES =================================================================================
__________________________________________________________________ TestX509.test_nullbyte_subjectAltName ___________________________________________________________________
self = <tests.test_crypto.TestX509 object at 0x7f62e0419910>
def test_nullbyte_subjectAltName(self):
"""
The fields of a `subjectAltName` extension on an X509 may contain NUL
bytes and this value is reflected in the string representation of the
extension object.
"""
cert = load_certificate(FILETYPE_PEM, nulbyteSubjectAltNamePEM)
ext = cert.get_extension(3)
assert ext.get_short_name() == b"subjectAltName"
> assert (
b"DNS:altnull.python.org\x00example.com, "
b"email:[email protected]\[email protected], "
b"URI:http://null.python.org\x00http://example.org, "
b"IP Address:192.0.2.1, IP Address:2001:DB8:0:0:0:0:0:1\n"
== str(ext).encode("ascii")
)
E AssertionError: assert b'DNS:altnull...0:0:0:0:0:1\n' == b'DNS:altnull...8:0:0:0:0:0:1'
E Use -v to get the full diff
tests/test_crypto.py:2035: AssertionError
_____________________________________________________________ TestX509StoreContext.test_untrusted_self_signed ______________________________________________________________
self = <tests.test_crypto.TestX509StoreContext object at 0x7f62e0c87130>
def test_untrusted_self_signed(self):
"""
`verify_certificate` raises error when a self-signed certificate is
verified without itself in the chain.
"""
store = X509Store()
store_ctx = X509StoreContext(store, self.root_cert)
with pytest.raises(X509StoreContextError) as exc:
store_ctx.verify_certificate()
> assert exc.value.args[0][2] == "self signed certificate"
E AssertionError: assert 'self-signed certificate' == 'self signed certificate'
E - self signed certificate
E ? ^
E + self-signed certificate
E ? ^
tests/test_crypto.py:4054: AssertionError
_____________________________________________________________ TestContext.test_set_cipher_list_no_cipher_match _____________________________________________________________
self = <tests.test_ssl.TestContext object at 0x7f62e0c487c0>, context = <OpenSSL.SSL.Context object at 0x7f62e0c48df0>
@flaky.flaky
def test_set_cipher_list_no_cipher_match(self, context):
"""
`Context.set_cipher_list` raises `OpenSSL.SSL.Error` with a
`"no cipher match"` reason string regardless of the TLS
version.
"""
with pytest.raises(Error) as excinfo:
context.set_cipher_list(b"imaginary-cipher")
> assert excinfo.value.args == (
[
(
"SSL routines",
"SSL_CTX_set_cipher_list",
"no cipher match",
)
],
)
E AssertionError: assert ([('SSL routi...her match')],) == ([('SSL routi...her match')],)
E At index 0 diff: [('SSL routines', '', 'no cipher match')] != [('SSL routines', 'SSL_CTX_set_cipher_list', 'no cipher match')]
E Use -v to get the full diff
tests/test_ssl.py:531: AssertionError
___________________________________________________________________ TestContext.test_set_session_id_fail ___________________________________________________________________
self = <tests.test_ssl.TestContext object at 0x7f62e094af10>, context = <OpenSSL.SSL.Context object at 0x7f62e0c74460>
def test_set_session_id_fail(self, context):
"""
`Context.set_session_id` errors are propagated.
"""
with pytest.raises(Error) as e:
context.set_session_id(b"abc" * 1000)
> assert [
(
"SSL routines",
"SSL_CTX_set_session_id_context",
"ssl session id context too long",
)
] == e.value.args[0]
E AssertionError: assert [('SSL routin...xt too long')] == [('SSL routin...xt too long')]
E At index 0 diff: ('SSL routines', 'SSL_CTX_set_session_id_context', 'ssl session id context too long') != ('SSL routines', '', 'ssl session id context too long')
E Use -v to get the full diff
tests/test_ssl.py:578: AssertionError
________________________________________________________________ TestContext.test_passwd_callback_too_long _________________________________________________________________
self = <tests.test_ssl.TestContext object at 0x7f62e063c730>, tmpfile = b'/tmp/pytest-of-tkloczko/pytest-444/tmp_ips1zbx'
def test_passwd_callback_too_long(self, tmpfile):
"""
If the passphrase returned by the passphrase callback returns a string
longer than the indicated maximum length, it is truncated.
"""
# A priori knowledge!
passphrase = b"x" * 1024
pemFile = self._write_encrypted_pem(passphrase, tmpfile)
def passphraseCallback(maxlen, verify, extra):
assert maxlen == 1024
return passphrase + b"y"
context = Context(SSLv23_METHOD)
context.set_passwd_cb(passphraseCallback)
# This shall succeed because the truncated result is the correct
# passphrase.
> context.use_privatekey_file(pemFile)
tests/test_ssl.py:986:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../BUILDROOT/python-pyOpenSSL-21.0.0-2.fc35.x86_64/usr/lib/python3.8/site-packages/OpenSSL/SSL.py:1012: in use_privatekey_file
self._raise_passphrase_exception()
../../BUILDROOT/python-pyOpenSSL-21.0.0-2.fc35.x86_64/usr/lib/python3.8/site-packages/OpenSSL/SSL.py:986: in _raise_passphrase_exception
self._passphrase_helper.raise_if_problem(Error)
../../BUILDROOT/python-pyOpenSSL-21.0.0-2.fc35.x86_64/usr/lib/python3.8/site-packages/OpenSSL/crypto.py:2836: in raise_if_problem
raise self._problems.pop(0)
../../BUILDROOT/python-pyOpenSSL-21.0.0-2.fc35.x86_64/usr/lib/python3.8/site-packages/OpenSSL/crypto.py:2842: in _read_passphrase
result = self._passphrase(size, rwflag, userdata)
../../BUILDROOT/python-pyOpenSSL-21.0.0-2.fc35.x86_64/usr/lib/python3.8/site-packages/OpenSSL/SSL.py:800: in wrapper
return callback(size, verify, self._passphrase_userdata)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
maxlen = 1022, verify = 0, extra = None
def passphraseCallback(maxlen, verify, extra):
> assert maxlen == 1024
E assert 1022 == 1024
tests/test_ssl.py:979: AssertionError
____________________________________________________________________ TestMemoryBIO.test_unexpected_EOF _____________________________________________________________________
self = <tests.test_ssl.TestMemoryBIO object at 0x7f62e0405be0>
def test_unexpected_EOF(self):
"""
If the connection is lost before an orderly SSL shutdown occurs,
`OpenSSL.SSL.SysCallError` is raised with a message of
"Unexpected EOF".
"""
server_conn, client_conn = loopback()
client_conn.sock_shutdown(SHUT_RDWR)
with pytest.raises(SysCallError) as err:
> server_conn.recv(1024)
tests/test_ssl.py:3682:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../BUILDROOT/python-pyOpenSSL-21.0.0-2.fc35.x86_64/usr/lib/python3.8/site-packages/OpenSSL/SSL.py:1865: in recv
self._raise_ssl_error(self._ssl, result)
../../BUILDROOT/python-pyOpenSSL-21.0.0-2.fc35.x86_64/usr/lib/python3.8/site-packages/OpenSSL/SSL.py:1700: in _raise_ssl_error
_raise_current_error()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
exception_type = <class 'OpenSSL.SSL.Error'>
def exception_from_error_queue(exception_type):
"""
Convert an OpenSSL library failure into a Python exception.
When a call to the native OpenSSL library fails, this is usually signalled
by the return value, and an error code is stored in an error queue
associated with the current thread. The err library provides functions to
obtain these error codes and textual error messages.
"""
errors = []
while True:
error = lib.ERR_get_error()
if error == 0:
break
errors.append(
(
text(lib.ERR_lib_error_string(error)),
text(lib.ERR_func_error_string(error)),
text(lib.ERR_reason_error_string(error)),
)
)
> raise exception_type(errors)
E OpenSSL.SSL.Error: [('SSL routines', '', 'unexpected eof while reading')]
../../BUILDROOT/python-pyOpenSSL-21.0.0-2.fc35.x86_64/usr/lib/python3.8/site-packages/OpenSSL/_util.py:55: Error
============================================================================= warnings summary =============================================================================
../../../../../usr/lib/python3.8/site-packages/_pytest/config/__init__.py:1233
/usr/lib/python3.8/site-packages/_pytest/config/__init__.py:1233: PytestConfigWarning: Unknown config option: strict
self._warn_or_fail_if_strict(f"Unknown config option: {key}\n")
tests/test_crypto.py:39
/home/tkloczko/rpmbuild/BUILD/pyopenssl-21.0.0/tests/test_crypto.py:39: DeprecationWarning: PKCS#7 support in pyOpenSSL is deprecated. You should use the APIs in cryptography.
from OpenSSL.crypto import PKCS7, load_pkcs7_data
tests/test_crypto.py:40
/home/tkloczko/rpmbuild/BUILD/pyopenssl-21.0.0/tests/test_crypto.py:40: DeprecationWarning: PKCS#12 support in pyOpenSSL is deprecated. You should use the APIs in cryptography.
from OpenSSL.crypto import PKCS12, load_pkcs12
tests/test_ssl.py::TestContext::test_set_cipher_list[hello world:AES128-SHA1]
/home/tkloczko/rpmbuild/BUILD/pyopenssl-21.0.0/tests/test_ssl.py:509: DeprecationWarning: str for cipher_list is no longer accepted, use bytes
context.set_cipher_list(cipher_string)
tests/test_ssl.py::TestConnection::test_client_set_session
/home/tkloczko/rpmbuild/BUILD/pyopenssl-21.0.0/tests/test_ssl.py:2686: DeprecationWarning: str for buf is no longer accepted, use bytes
ctx.set_session_id("unity-test")
-- Docs: https://docs.pytest.org/en/stable/warnings.html
===Flaky Test Report===
test_gmtime_adj_notBefore passed 1 out of the required 1 times. Success!
test_gmtime_adj_notAfter passed 1 out of the required 1 times. Success!
test_set_cipher_list_no_cipher_match failed (1 runs remaining out of 2).
<class 'AssertionError'>
assert ([('SSL routi...her match')],) == ([('SSL routi...her match')],)
At index 0 diff: [('SSL routines', '', 'no cipher match')] != [('SSL routines', 'SSL_CTX_set_cipher_list', 'no cipher match')]
Use -v to get the full diff
[<TracebackEntry /home/tkloczko/rpmbuild/BUILD/pyopenssl-21.0.0/tests/test_ssl.py:531>]
test_set_cipher_list_no_cipher_match failed; it passed 0 out of the required 1 times.
<class 'AssertionError'>
assert ([('SSL routi...her match')],) == ([('SSL routi...her match')],)
At index 0 diff: [('SSL routines', '', 'no cipher match')] != [('SSL routines', 'SSL_CTX_set_cipher_list', 'no cipher match')]
Use -v to get the full diff
[<TracebackEntry /home/tkloczko/rpmbuild/BUILD/pyopenssl-21.0.0/tests/test_ssl.py:531>]
===End Flaky Test Report===
========================================================================= short test summary info ==========================================================================
FAILED tests/test_crypto.py::TestX509::test_nullbyte_subjectAltName - AssertionError: assert b'DNS:altnull...0:0:0:0:0:1\n' == b'DNS:altnull...8:0:0:0:0:0:1'
FAILED tests/test_crypto.py::TestX509StoreContext::test_untrusted_self_signed - AssertionError: assert 'self-signed certificate' == 'self signed certificate'
FAILED tests/test_ssl.py::TestContext::test_set_cipher_list_no_cipher_match - AssertionError: assert ([('SSL routi...her match')],) == ([('SSL routi...her match')],)
FAILED tests/test_ssl.py::TestContext::test_set_session_id_fail - AssertionError: assert [('SSL routin...xt too long')] == [('SSL routin...xt too long')]
FAILED tests/test_ssl.py::TestContext::test_passwd_callback_too_long - assert 1022 == 1024
FAILED tests/test_ssl.py::TestMemoryBIO::test_unexpected_EOF - OpenSSL.SSL.Error: [('SSL routines', '', 'unexpected eof while reading')]
================================================================ 6 failed, 520 passed, 5 warnings in 15.10s ================================================================
I just tested as well 21.0.0 + all commits from master and result is the same.
All the test failures (with the exception of the last one) appear to be textual output from OpenSSL, which is unfortunately not stable between all versions (and pyOpenSSL, even more unfortunately, depends on its test suite). What version of OpenSSL are you packaging against?
Oops, sorry I saw you said 3.0.0 in your initial report. That's likely the culprit for the failures. I believe they also changed EOF behavior in 3.0.0. pyOpenSSL needs to add a 3.0.0 test builder and improve the test suite to understand 3.0.0's output.
I understand .. Neverthe less more and more distribuions is usimg mopw openssl 3.0. I've manage to switch 100% of my distro packages to openssl 3.x. There are only some minor issues with such change (on scale of the whole duistribition not more than it was with oleder openssl).
KInd of question: despite pyopenssl test suite do you know about any problem with using pyopenssl with openssl 3.x?
I believe it will work fine in almost all cases, although test_unexpected_EOF suggests there is an edge case where it will not raise the appropriate error type due to behavioral change between 1.1.x and 3.0.0.
Any update? (just asking 😄 ) Just tested everything up to fb26edde and looks like pytest is failing in the same units.
Kind of question: despite tose fails pyopenssl should be ok with openssl 3.x or still some work needs to be done to make it ready for that version of openssl?
Thx.
I think I already answered the question in my previous reply, but no updates on getting this fixed. Someone has to step forward to do the work 😄
Just test ed 23.1.1 and none of the unis are failing (which is good) however I see some warnings Here is pytest output:
+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-pyOpenSSL-23.1.1-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-pyOpenSSL-23.1.1-2.fc35.x86_64/usr/lib/python3.8/site-packages
+ /usr/bin/pytest -ra -m 'not network'
==================================================================================== test session starts ====================================================================================
platform linux -- Python 3.8.16, pytest-7.3.1, pluggy-1.0.0
OpenSSL: b'OpenSSL 3.0.5 5 Jul 2022'
cryptography: 40.0.2
rootdir: /home/tkloczko/rpmbuild/BUILD/pyopenssl-23.1.1
configfile: setup.cfg
testpaths: tests
plugins: flaky-3.7.0
collected 542 items
tests/test_crypto.py ................................................................................................................................................................ [ 29%]
.................................................................................................................................... [ 53%]
tests/test_debug.py . [ 54%]
tests/test_rand.py .... [ 54%]
tests/test_ssl.py ................................................................................................................................................................... [ 84%]
................................................................................. [ 99%]
tests/test_util.py . [100%]
===================================================================================== warnings summary ======================================================================================
../../../../../usr/lib/python3.8/site-packages/_pytest/config/__init__.py:1302
/usr/lib/python3.8/site-packages/_pytest/config/__init__.py:1302: PytestConfigWarning: Unknown config option: strict
self._warn_or_fail_if_strict(f"Unknown config option: {key}\n")
tests/test_crypto.py:22
/home/tkloczko/rpmbuild/BUILD/pyopenssl-23.1.1/tests/test_crypto.py:22: DeprecationWarning: PKCS#12 support in pyOpenSSL is deprecated. You should use the APIs in cryptography.
from OpenSSL.crypto import (
tests/test_crypto.py:22
/home/tkloczko/rpmbuild/BUILD/pyopenssl-23.1.1/tests/test_crypto.py:22: DeprecationWarning: PKCS#7 support in pyOpenSSL is deprecated. You should use the APIs in cryptography.
from OpenSSL.crypto import (
tests/test_crypto.py::TestCRL::test_export_md5_digest
/usr/lib/python3.8/site-packages/_pytest/python.py:199: PytestRemovedIn8Warning: Passing None has been deprecated.
See https://docs.pytest.org/en/latest/how-to/capture-warnings.html#additional-use-cases-of-warnings-in-tests for alternatives in common use cases.
result = testfunction(**testargs)
tests/test_ssl.py::TestContext::test_set_cipher_list[hello world:AES128-SHA1]
/home/tkloczko/rpmbuild/BUILD/pyopenssl-23.1.1/tests/test_ssl.py:502: DeprecationWarning: str for cipher_list is no longer accepted, use bytes
context.set_cipher_list(cipher_string)
tests/test_ssl.py::TestConnection::test_client_set_session
/home/tkloczko/rpmbuild/BUILD/pyopenssl-23.1.1/tests/test_ssl.py:2772: DeprecationWarning: str for buf is no longer accepted, use bytes
ctx.set_session_id("unity-test")
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
===Flaky Test Report===
test_gmtime_adj_notBefore passed 1 out of the required 1 times. Success!
test_gmtime_adj_notAfter passed 1 out of the required 1 times. Success!
test_set_cipher_list_no_cipher_match passed 1 out of the required 1 times. Success!
===End Flaky Test Report===
============================================================================= 542 passed, 6 warnings in 11.28s ==============================================================================
Thank you for your time :
Warnigs are covered by https://github.com/pyca/pyopenssl/issues/1024 so look slike this ticked can be closed.
Closing and one more time than you.