Skip to content

Commit

Permalink
🐛 Fix retrieving the dict peer certificate when cert_reqs=0 aka. disa…
Browse files Browse the repository at this point in the history
…bled TLS over TCP verification (#102)
  • Loading branch information
Ousret authored Apr 3, 2024
1 parent 0a59d94 commit dc7c91f
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ jobs:
- name: "Traefik: Start stack"
if: ${{ matrix.traefik-server && !contains(matrix.os, 'windows') }}
run: docker-compose up -d
run: docker compose up -d || docker-compose up -d

- name: "Traefik: Wait for service"
uses: nick-fields/retry@v3
Expand Down
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
2.7.902 (2024-04-03)
====================

- Fixed a rare racing condition occurring on PyPy when using DNS-over-HTTPS leading to a socket.gaierror exception.
- Fixed retrieving the dict peer certificate when ``cert_reqs=0`` aka. disabled TLS over TCP verification.

2.7.901 (2024-03-27)
====================

Expand Down
2 changes: 1 addition & 1 deletion src/urllib3/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This file is protected via CODEOWNERS
from __future__ import annotations

__version__ = "2.7.901"
__version__ = "2.7.902"
4 changes: 4 additions & 0 deletions src/urllib3/backend/_async/hface.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,10 @@ async def _post_conn(self) -> None: # type: ignore[override]
):
chain = self.sock.sslobj._sslobj.get_verified_chain()

# When cert_reqs=0 CPython returns an empty dict for the peer cert.
if not self.conn_info.certificate_dict and chain:
self.conn_info.certificate_dict = chain[0].get_info()

if (
len(chain) > 1
and Certificate is not None
Expand Down
8 changes: 8 additions & 0 deletions src/urllib3/backend/hface.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,10 @@ def _post_conn(self) -> None:
if hasattr(self.sock.sslobj, "get_verified_chain"):
chain = self.sock.sslobj.get_verified_chain()

# When cert_reqs=0 CPython returns an empty dict for the peer cert.
if not self.conn_info.certificate_dict and chain:
self.conn_info.certificate_dict = chain[0].get_info()

if (
len(chain) > 1
and Certificate is not None
Expand Down Expand Up @@ -380,6 +384,10 @@ def _post_conn(self) -> None:
):
chain = self.sock._sslobj.get_verified_chain()

# When cert_reqs=0 CPython returns an empty dict for the peer cert.
if not self.conn_info.certificate_dict and chain:
self.conn_info.certificate_dict = chain[0].get_info()

if (
len(chain) > 1
and Certificate is not None
Expand Down
30 changes: 30 additions & 0 deletions test/with_traefik/test_conn_info.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
from __future__ import annotations

import sys

import pytest

from urllib3 import ConnectionInfo, HttpVersion, PoolManager
from urllib3.exceptions import InsecureRequestWarning

from . import TraefikTestCase

Expand Down Expand Up @@ -43,6 +48,31 @@ def on_post_connection(o: ConnectionInfo) -> None:
assert conn_info.tls_version is not None
assert conn_info.cipher is not None

@pytest.mark.skipif(
sys.version_info < (3, 10),
reason="unsupported due missing API (3.10+)",
)
def test_tls_on_tcp_disabled_cert_reqs(self) -> None:
p = PoolManager(ca_certs=self.ca_authority, cert_reqs=0)

conn_info: ConnectionInfo | None = None

def on_post_connection(o: ConnectionInfo) -> None:
nonlocal conn_info
conn_info = o

with pytest.warns(InsecureRequestWarning):
p.urlopen(
method="GET", url=self.https_url, on_post_connection=on_post_connection
)

assert conn_info is not None
assert conn_info.certificate_der is not None
assert conn_info.certificate_dict is not None
assert conn_info.http_version == HttpVersion.h2
assert conn_info.tls_version is not None
assert conn_info.cipher is not None

def test_tls_on_udp(self) -> None:
p = PoolManager(
preemptive_quic_cache={
Expand Down

0 comments on commit dc7c91f

Please sign in to comment.