CVE-2025-15346
Description
A vulnerability in the handling of verify_mode = CERT_REQUIRED in the wolfssl Python package (wolfssl-py) causes client certificate requirements to not be fully enforced.
Because the WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT flag was not included, the behavior effectively matched CERT_OPTIONAL: a peer certificate was verified if presented, but connections were incorrectly authenticated when no client certificate was provided.
This results in improper authentication, allowing attackers to bypass mutual TLS (mTLS) client authentication by omitting a client certificate during the TLS handshake.
The issue affects versions up to and including 5.8.2.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
wolfsslPyPI | < 5.8.4.post0 | 5.8.4.post0 |
Affected products
1- Range: v3.12.2, v3.13.0-0, v3.13.0-1, …
Patches
305433e92b6faMerge pull request #63 from kareem-wolfssl/v5.8.4
3 files changed · +10 −3
ChangeLog.rst+7 −0 modified@@ -1,3 +1,10 @@ +wolfSSL-py Release 5.8.4 (Dec 29, 2025) +============================================ +* Fix an issue which allowed a client without a cert to connect despite setting verify_mode to CERT_REQUIRED (CVE-2025-15346): +A vulnerability in the handling of verify_mode = CERT_REQUIRED in the wolfssl Python package (wolfssl-py) causes client certificate requirements to not be fully enforced. Because the WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT flag was not included, the behavior effectively matched CERT_OPTIONAL: a peer certificate was verified if presented, but connections were incorrectly authenticated when no client certificate was provided. This results in improper authentication, allowing attackers to bypass mutual TLS (mTLS) client authentication by omitting a client certificate during the TLS handshake. +Thanks to Matan Radomski from Microsoft for the report. +* Update wolfSSL to version 5.8.4 + wolfSSL-py Release 5.8.2 (Jul 24, 2025) ============================================ * Update wolfSSL to version 5.8.2
lib/wolfssl+1 −1 modified@@ -1 +1 @@ -Subproject commit decea12e223869c8f8f3ab5a53dc90b69f436eb2 +Subproject commit 59f4fa568615396fbf381b073b220d1e8d61e4c2
wolfssl/_version.py+2 −2 modified@@ -1,11 +1,11 @@ # When bumping the C library version, reset the POST count to 0 -__wolfssl_version__ = "v5.8.2-stable" +__wolfssl_version__ = "v5.8.4-stable" # We're using implicit post releases [PEP 440] to bump package version # while maintaining the C library version intact for better reference. # https://www.python.org/dev/peps/pep-0440/#implicit-post-releases # # MAJOR.MINOR.BUILD-POST -__version__ = "5.8.2-0" +__version__ = "5.8.4-0"
b4517dece79fFix CERT_REQUIRED verify mode not setting SSL_VERIFY_FAIL_IF_NO_PEER_CERT and therefore failing to verify the client cert.
2 files changed · +11 −3
tests/test_context.py+3 −0 modified@@ -39,6 +39,9 @@ def test_verify_mode(ssl_provider, ssl_context): assert ssl_context.verify_mode == ssl_provider.CERT_NONE + ssl_context.verify_mode = ssl_provider.CERT_OPTIONAL + assert ssl_context.verify_mode == ssl_provider.CERT_OPTIONAL + ssl_context.verify_mode = ssl_provider.CERT_REQUIRED assert ssl_context.verify_mode == ssl_provider.CERT_REQUIRED
wolfssl/__init__.py+8 −3 modified@@ -55,10 +55,15 @@ PROTOCOL_DTLSv1_3, WolfSSLMethod as _WolfSSLMethod ) -CERT_NONE = 0 -CERT_REQUIRED = 1 +_SSL_VERIFY_NONE = 0 +_SSL_VERIFY_PEER = 1 +_SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2 -_VERIFY_MODE_LIST = [CERT_NONE, CERT_REQUIRED] +CERT_NONE = _SSL_VERIFY_NONE +CERT_OPTIONAL = _SSL_VERIFY_PEER +CERT_REQUIRED = (_SSL_VERIFY_PEER | _SSL_VERIFY_FAIL_IF_NO_PEER_CERT) + +_VERIFY_MODE_LIST = [CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED] _SSL_SUCCESS = 1 _SSL_FILETYPE_PEM = 1
45a4151d02beMerge pull request #62 from kareem-wolfssl/verifyMode
3 files changed · +74 −3
tests/test_client.py+63 −0 modified@@ -25,6 +25,8 @@ import pytest import wolfssl +from wolfssltestserver import wolfSSLTestServer +from threading import Thread HOST = "www.python.org" PORT = 443 @@ -89,3 +91,64 @@ def test_get_version(ssl_server, ssl_version, tcp_socket): assert secure_socket.version() == protocol_name secure_socket.write(b'hello wolfssl') secure_socket.read(1024) + + +def test_client_cert_verification_failure(): + """ + Test that a connection fails when the server requires client certificates + but the server's CA (globalsign) does not verify the client's certificate. + """ + import socket + import time + + # Create a server with CERT_REQUIRED and globalsign CA + # This server will require client certificates but won't accept + # certificates signed by a different CA + port = 11111 + with wolfSSLTestServer( + ('localhost', port), + version=wolfssl.PROTOCOL_TLS, + verify=wolfssl.CERT_REQUIRED + ) as server: + server_thread = Thread(target=server.handle_request) + server_thread.daemon = True + server_thread.start() + + # Give the server a moment to start + time.sleep(0.1) + + # Create a client socket + client_tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # Create a client context + client_ctx = wolfssl.SSLContext(wolfssl.PROTOCOL_TLS) + + # Wrap the socket with the client context + # Set do_handshake_on_connect=False so we can explicitly call do_handshake() + # and catch the error + client_socket = client_ctx.wrap_socket( + client_tcp_socket, + do_handshake_on_connect=False + ) + + # Connect the TCP socket first + client_socket.connect(('127.0.0.1', port)) + + # Attempt handshake - this should fail because the client does not + # send a cert/key. + with pytest.raises(wolfssl.SSLError) as exc_info: + client_socket.do_handshake() + # Handshake appeared to succeed, try to read/write to trigger the error + # The server should reject the connection due to certificate verification failure + client_socket.write(b'hello') + client_socket.read(1024) + + # Clean up (errors during close are expected if connection failed) + try: + client_socket.close() + except Exception: + pass + try: + client_tcp_socket.close() + except Exception: + pass
tests/test_context.py+3 −0 modified@@ -39,6 +39,9 @@ def test_verify_mode(ssl_provider, ssl_context): assert ssl_context.verify_mode == ssl_provider.CERT_NONE + ssl_context.verify_mode = ssl_provider.CERT_OPTIONAL + assert ssl_context.verify_mode == ssl_provider.CERT_OPTIONAL + ssl_context.verify_mode = ssl_provider.CERT_REQUIRED assert ssl_context.verify_mode == ssl_provider.CERT_REQUIRED
wolfssl/__init__.py+8 −3 modified@@ -55,10 +55,15 @@ PROTOCOL_DTLSv1_3, WolfSSLMethod as _WolfSSLMethod ) -CERT_NONE = 0 -CERT_REQUIRED = 1 +_SSL_VERIFY_NONE = 0 +_SSL_VERIFY_PEER = 1 +_SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2 -_VERIFY_MODE_LIST = [CERT_NONE, CERT_REQUIRED] +CERT_NONE = _SSL_VERIFY_NONE +CERT_OPTIONAL = _SSL_VERIFY_PEER +CERT_REQUIRED = (_SSL_VERIFY_PEER | _SSL_VERIFY_FAIL_IF_NO_PEER_CERT) + +_VERIFY_MODE_LIST = [CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED] _SSL_SUCCESS = 1 _SSL_FILETYPE_PEM = 1
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5News mentions
0No linked articles in our index yet.