diff --git a/src/truststore/_api.py b/src/truststore/_api.py index 189c393..3c3acb8 100644 --- a/src/truststore/_api.py +++ b/src/truststore/_api.py @@ -334,6 +334,12 @@ def _verify_peercerts( pass cert_bytes = _get_unverified_chain_bytes(sslobj) + + # If the peer didn't send any certificates then + # we can't do verification. Raise an error. + if not cert_bytes: + raise ssl.SSLCertVerificationError("Peer sent no certificates to verify") + _verify_peercerts_impl( sock_or_sslobj.context, cert_bytes, server_hostname=server_hostname ) diff --git a/src/truststore/_macos.py b/src/truststore/_macos.py index 3450307..5ba070a 100644 --- a/src/truststore/_macos.py +++ b/src/truststore/_macos.py @@ -382,7 +382,8 @@ def _verify_peercerts_impl( cert_chain: list[bytes], server_hostname: str | None = None, ) -> None: - certs = None + """Verify the cert_chain from the server using macOS APIs.""" + policies = None trust = None try: diff --git a/src/truststore/_windows.py b/src/truststore/_windows.py index e048203..2dac6e9 100644 --- a/src/truststore/_windows.py +++ b/src/truststore/_windows.py @@ -327,11 +327,6 @@ def _verify_peercerts_impl( ) -> None: """Verify the cert_chain from the server using Windows APIs.""" - # If the peer didn't send any certificates then - # we can't do verification. Raise an error. - if not cert_chain: - raise ssl.SSLCertVerificationError("Peer sent no certificates to verify") - pCertContext = None hIntermediateCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, None, 0, None) try: diff --git a/tests/test_api.py b/tests/test_api.py index 2a515aa..5e3d869 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -17,6 +17,7 @@ from pytest_httpserver import HTTPServer import truststore +import truststore._api as api from tests import SSLContextAdapter from tests.conftest import decorator_requires_internet @@ -452,3 +453,29 @@ def test_macos_10_7_import_error(): importlib.reload(truststore._macos) assert str(e.value) == "Only OS X 10.8 and newer are supported, not 10.7" + + +@pytest.mark.parametrize("empty_value", [None, []]) +def test_verify_peercerts_no_cert_chain_raises(monkeypatch, empty_value): + # Simulate no certs returned from peer + monkeypatch.setattr(api, "_get_unverified_chain_bytes", lambda sslobj: empty_value) + + # Track whether impl gets called (it shouldn't) + called = False + + def fake_impl(*args, **kwargs): + nonlocal called + called = True + + monkeypatch.setattr(api, "_verify_peercerts_impl", fake_impl) + + class DummySSLObject: + def __init__(self): + self.context = object() + + sslobj = DummySSLObject() + + with pytest.raises(ssl.SSLCertVerificationError, match="Peer sent no certificates"): + api._verify_peercerts(sslobj, server_hostname="example.com") + + assert called is False