Bug 2272940 - python-trustme fails to build with Python 3.13: ssl.SSLError: [SSL: SSLV3_ALERT_CERTIFICATE_UNKNOWN] ssl/tls alert certificate unknown (_ssl.c:1033)
Summary: python-trustme fails to build with Python 3.13: ssl.SSLError: [SSL: SSLV3_ALE...
Keywords:
Status: NEW
Alias: None
Product: Fedora
Classification: Fedora
Component: python-trustme
Version: rawhide
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Carl George 🤠
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks: PYTHON3.13
TreeView+ depends on / blocked
 
Reported: 2024-04-03 11:36 UTC by Karolina Surma
Modified: 2024-04-03 11:36 UTC (History)
5 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed:
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Karolina Surma 2024-04-03 11:36:37 UTC
python-trustme fails to build with Python 3.13.0a5.

=================================== FAILURES ===================================
_____________________ test_stdlib_end_to_end[KeyType.RSA] ______________________

key_type = <KeyType.RSA: 0>

    @pytest.mark.parametrize("key_type", [KeyType.RSA, KeyType.ECDSA])
    def test_stdlib_end_to_end(key_type: KeyType) -> None:
        def wrap_client(ca: CA, raw_client_sock: socket.socket, hostname: str) -> ssl.SSLSocket:
            ctx = ssl.create_default_context()
            ca.configure_trust(ctx)
            wrapped_client_sock = ctx.wrap_socket(
                raw_client_sock, server_hostname=hostname)
            print("Client got server cert:", wrapped_client_sock.getpeercert())
            peercert = wrapped_client_sock.getpeercert()
            assert peercert is not None
            san = peercert["subjectAltName"]
            assert san == (("DNS", "my-test-host.example.org"),)
            return wrapped_client_sock
    
        def wrap_server(server_cert: LeafCert, raw_server_sock: socket.socket) -> ssl.SSLSocket:
            ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
            server_cert.configure_cert(ctx)
            wrapped_server_sock = ctx.wrap_socket(
                raw_server_sock, server_side=True)
            print("server encrypted with:", wrapped_server_sock.cipher())
            return wrapped_server_sock
    
>       check_connection_end_to_end(wrap_client, wrap_server, key_type)

tests/test_trustme.py:360: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/test_trustme.py:322: in check_connection_end_to_end
    doit(ca, hostname, intermediate_ca.issue_cert(hostname, key_type=key_type))
tests/test_trustme.py:311: in doit
    f1.result()
/usr/lib64/python3.13/concurrent/futures/_base.py:456: in result
    return self.__get_result()
/usr/lib64/python3.13/concurrent/futures/_base.py:401: in __get_result
    raise self._exception
/usr/lib64/python3.13/concurrent/futures/thread.py:58: in run
    result = self.fn(*self.args, **self.kwargs)
tests/test_trustme.py:273: in fake_ssl_client
    wrapped_client_sock = wrap_client(ca, raw_client_sock, hostname)
tests/test_trustme.py:343: in wrap_client
    wrapped_client_sock = ctx.wrap_socket(
/usr/lib64/python3.13/ssl.py:455: in wrap_socket
    return self.sslsocket_class._create(
/usr/lib64/python3.13/ssl.py:1077: in _create
    self.do_handshake()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ssl.SSLSocket [closed] fd=-1, family=2, type=1, proto=0>, block = False

    @_sslcopydoc
    def do_handshake(self, block=False):
        self._check_connected()
        timeout = self.gettimeout()
        try:
            if timeout == 0.0 and block:
                self.settimeout(None)
>           self._sslobj.do_handshake()
E           ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Missing Authority Key Identifier (_ssl.c:1033)

/usr/lib64/python3.13/ssl.py:1363: SSLCertVerificationError
----------------------------- Captured stdout call -----------------------------
Client got server cert: {'subject': ((('organizationName', 'trustme v1.1.0'),), (('organizationalUnitName', 'Testing cert #96W9j5UYkuUF5Fbv'),)), 'issuer': ((('organizationName', 'trustme v1.1.0'),), (('organizationalUnitName', 'Testing CA #PP01mAWDwALt4Y9c'),)), 'version': 3, 'serialNumber': '5047EEEC796A3AEA83E3456871BDF88B54961E7C', 'notBefore': 'Jan  1 00:00:00 2000 GMT', 'notAfter': 'Jan  1 00:00:00 2038 GMT', 'subjectAltName': (('DNS', 'my-test-host.example.org'),)}
server encrypted with: ('TLS_AES_256_GCM_SHA384', 'TLSv1.3', 256)
----------------------------- Captured stderr call -----------------------------
Traceback (most recent call last):
  File "/builddir/build/BUILD/trustme-1.1.0/tests/test_trustme.py", line 273, in fake_ssl_client
    wrapped_client_sock = wrap_client(ca, raw_client_sock, hostname)
                          ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/builddir/build/BUILD/trustme-1.1.0/tests/test_trustme.py", line 343, in wrap_client
    wrapped_client_sock = ctx.wrap_socket(
                          ~~~~~~~~~~~~~~~^
        raw_client_sock, server_hostname=hostname)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/ssl.py", line 455, in wrap_socket
    return self.sslsocket_class._create(
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        sock=sock,
        ^^^^^^^^^^
    ...<5 lines>...
        session=session
        ^^^^^^^^^^^^^^^
    )
    ^
  File "/usr/lib64/python3.13/ssl.py", line 1077, in _create
    self.do_handshake()
    ~~~~~~~~~~~~~~~~~^^
  File "/usr/lib64/python3.13/ssl.py", line 1363, in do_handshake
    self._sslobj.do_handshake()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Missing Authority Key Identifier (_ssl.c:1033)
Traceback (most recent call last):
  File "/builddir/build/BUILD/trustme-1.1.0/tests/test_trustme.py", line 287, in fake_ssl_server
    wrapped_server_sock = wrap_server(server_cert, raw_server_sock)
                          ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/builddir/build/BUILD/trustme-1.1.0/tests/test_trustme.py", line 355, in wrap_server
    wrapped_server_sock = ctx.wrap_socket(
                          ~~~~~~~~~~~~~~~^
        raw_server_sock, server_side=True)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/ssl.py", line 455, in wrap_socket
    return self.sslsocket_class._create(
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        sock=sock,
        ^^^^^^^^^^
    ...<5 lines>...
        session=session
        ^^^^^^^^^^^^^^^
    )
    ^
  File "/usr/lib64/python3.13/ssl.py", line 1077, in _create
    self.do_handshake()
    ~~~~~~~~~~~~~~~~~^^
  File "/usr/lib64/python3.13/ssl.py", line 1363, in do_handshake
    self._sslobj.do_handshake()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
ssl.SSLError: [SSL: SSLV3_ALERT_CERTIFICATE_UNKNOWN] ssl/tls alert certificate unknown (_ssl.c:1033)
____________________ test_stdlib_end_to_end[KeyType.ECDSA] _____________________

key_type = <KeyType.ECDSA: 1>

    @pytest.mark.parametrize("key_type", [KeyType.RSA, KeyType.ECDSA])
    def test_stdlib_end_to_end(key_type: KeyType) -> None:
        def wrap_client(ca: CA, raw_client_sock: socket.socket, hostname: str) -> ssl.SSLSocket:
            ctx = ssl.create_default_context()
            ca.configure_trust(ctx)
            wrapped_client_sock = ctx.wrap_socket(
                raw_client_sock, server_hostname=hostname)
            print("Client got server cert:", wrapped_client_sock.getpeercert())
            peercert = wrapped_client_sock.getpeercert()
            assert peercert is not None
            san = peercert["subjectAltName"]
            assert san == (("DNS", "my-test-host.example.org"),)
            return wrapped_client_sock
    
        def wrap_server(server_cert: LeafCert, raw_server_sock: socket.socket) -> ssl.SSLSocket:
            ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
            server_cert.configure_cert(ctx)
            wrapped_server_sock = ctx.wrap_socket(
                raw_server_sock, server_side=True)
            print("server encrypted with:", wrapped_server_sock.cipher())
            return wrapped_server_sock
    
>       check_connection_end_to_end(wrap_client, wrap_server, key_type)

tests/test_trustme.py:360: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/test_trustme.py:322: in check_connection_end_to_end
    doit(ca, hostname, intermediate_ca.issue_cert(hostname, key_type=key_type))
tests/test_trustme.py:311: in doit
    f1.result()
/usr/lib64/python3.13/concurrent/futures/_base.py:456: in result
    return self.__get_result()
/usr/lib64/python3.13/concurrent/futures/_base.py:401: in __get_result
    raise self._exception
/usr/lib64/python3.13/concurrent/futures/thread.py:58: in run
    result = self.fn(*self.args, **self.kwargs)
tests/test_trustme.py:273: in fake_ssl_client
    wrapped_client_sock = wrap_client(ca, raw_client_sock, hostname)
tests/test_trustme.py:343: in wrap_client
    wrapped_client_sock = ctx.wrap_socket(
/usr/lib64/python3.13/ssl.py:455: in wrap_socket
    return self.sslsocket_class._create(
/usr/lib64/python3.13/ssl.py:1077: in _create
    self.do_handshake()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ssl.SSLSocket [closed] fd=-1, family=2, type=1, proto=0>, block = False

    @_sslcopydoc
    def do_handshake(self, block=False):
        self._check_connected()
        timeout = self.gettimeout()
        try:
            if timeout == 0.0 and block:
                self.settimeout(None)
>           self._sslobj.do_handshake()
E           ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Missing Authority Key Identifier (_ssl.c:1033)

/usr/lib64/python3.13/ssl.py:1363: SSLCertVerificationError
----------------------------- Captured stdout call -----------------------------
Client got server cert: {'subject': ((('organizationName', 'trustme v1.1.0'),), (('organizationalUnitName', 'Testing cert #_Kfb3HeSyY0YS7d8'),)), 'issuer': ((('organizationName', 'trustme v1.1.0'),), (('organizationalUnitName', 'Testing CA #YBPqEoBWHr_qQlyq'),)), 'version': 3, 'serialNumber': '784C1FED786F0977E7C5B9CB23246A65242CB558', 'notBefore': 'Jan  1 00:00:00 2000 GMT', 'notAfter': 'Jan  1 00:00:00 2038 GMT', 'subjectAltName': (('DNS', 'my-test-host.example.org'),)}
server encrypted with: ('TLS_AES_256_GCM_SHA384', 'TLSv1.3', 256)
----------------------------- Captured stderr call -----------------------------
Traceback (most recent call last):
  File "/builddir/build/BUILD/trustme-1.1.0/tests/test_trustme.py", line 273, in fake_ssl_client
    wrapped_client_sock = wrap_client(ca, raw_client_sock, hostname)
                          ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/builddir/build/BUILD/trustme-1.1.0/tests/test_trustme.py", line 343, in wrap_client
    wrapped_client_sock = ctx.wrap_socket(
                          ~~~~~~~~~~~~~~~^
        raw_client_sock, server_hostname=hostname)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/ssl.py", line 455, in wrap_socket
    return self.sslsocket_class._create(
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        sock=sock,
        ^^^^^^^^^^
    ...<5 lines>...
        session=session
        ^^^^^^^^^^^^^^^
    )
    ^
  File "/usr/lib64/python3.13/ssl.py", line 1077, in _create
    self.do_handshake()
    ~~~~~~~~~~~~~~~~~^^
  File "/usr/lib64/python3.13/ssl.py", line 1363, in do_handshake
    self._sslobj.do_handshake()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Missing Authority Key Identifier (_ssl.c:1033)
Traceback (most recent call last):
  File "/builddir/build/BUILD/trustme-1.1.0/tests/test_trustme.py", line 287, in fake_ssl_server
    wrapped_server_sock = wrap_server(server_cert, raw_server_sock)
                          ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/builddir/build/BUILD/trustme-1.1.0/tests/test_trustme.py", line 355, in wrap_server
    wrapped_server_sock = ctx.wrap_socket(
                          ~~~~~~~~~~~~~~~^
        raw_server_sock, server_side=True)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/ssl.py", line 455, in wrap_socket
    return self.sslsocket_class._create(
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        sock=sock,
        ^^^^^^^^^^
    ...<5 lines>...
        session=session
        ^^^^^^^^^^^^^^^
    )
    ^
  File "/usr/lib64/python3.13/ssl.py", line 1077, in _create
    self.do_handshake()
    ~~~~~~~~~~~~~~~~~^^
  File "/usr/lib64/python3.13/ssl.py", line 1363, in do_handshake
    self._sslobj.do_handshake()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
ssl.SSLError: [SSL: SSLV3_ALERT_CERTIFICATE_UNKNOWN] ssl/tls alert certificate unknown (_ssl.c:1033)
=========================== short test summary info ============================
FAILED tests/test_trustme.py::test_stdlib_end_to_end[KeyType.RSA] - ssl.SSLCe...
FAILED tests/test_trustme.py::test_stdlib_end_to_end[KeyType.ECDSA] - ssl.SSL...
========================= 2 failed, 25 passed in 1.10s =========================

In https://docs.python.org/3.13/whatsnew/3.13.html there's this bit which may have something to do with the failure:
"The ssl.create_default_context() API now includes ssl.VERIFY_X509_PARTIAL_CHAIN and ssl.VERIFY_X509_STRICT in its default flags.

Note: ssl.VERIFY_X509_STRICT may reject pre-RFC 5280 or malformed certificates that the underlying OpenSSL implementation otherwise would accept. While disabling this is not recommended, you can do so using:

ctx = ssl.create_default_context()
ctx.verify_flags &= ~ssl.VERIFY_X509_STRICT

(Contributed by William Woodruff in gh-112389.)"


For the build logs, see:
https://copr-be.cloud.fedoraproject.org/results/@python/python3.13/fedora-rawhide-x86_64/07221477-python-trustme/

For all our attempts to build python-trustme with Python 3.13, see:
https://copr.fedorainfracloud.org/coprs/g/python/python3.13/package/python-trustme/

Testing and mass rebuild of packages is happening in copr.
You can follow these instructions to test locally in mock if your package builds with Python 3.13:
https://copr.fedorainfracloud.org/coprs/g/python/python3.13/

Let us know here if you have any questions.

Python 3.13 is planned to be included in Fedora 41.
To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.13.
A build failure prevents us from testing all dependent packages (transitive [Build]Requires),
so if this package is required a lot, it's important for us to get it fixed soon.

We'd appreciate help from the people who know this package best,
but if you don't want to work on this now, let us know so we can try to work around it on our side.


Note You need to log in before you can comment on or make changes to this bug.