Skip to content

Commit

Permalink
Fix TLS 1.3 post-handshake auth
Browse files Browse the repository at this point in the history
Post-hanshake auth was accidentally broken while removing support for Python 3.7
  • Loading branch information
jborean93 authored Jan 29, 2024
1 parent 8c8e26d commit d7bb83b
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 10 deletions.
1 change: 1 addition & 0 deletions changelog/3325.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed TLS 1.3 Post Handshake Auth when the server certificate validation was disabled.
11 changes: 3 additions & 8 deletions src/urllib3/util/ssl_.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,14 +319,9 @@ def create_urllib3_context(

# Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is
# necessary for conditional client cert authentication with TLS 1.3.
# The attribute is None for OpenSSL <= 1.1.0 or does not exist in older
# versions of Python. We only enable if certificate verification is enabled to work
# around Python issue #37428
# See: https://bugs.python.org/issue37428
if (
cert_reqs == ssl.CERT_REQUIRED
and getattr(context, "post_handshake_auth", None) is not None
):
# The attribute is None for OpenSSL <= 1.1.0 or does not exist when using
# an SSLContext created by pyOpenSSL.
if getattr(context, "post_handshake_auth", None) is not None:
context.post_handshake_auth = True

# The order of the below lines setting verify_mode and check_hostname
Expand Down
19 changes: 17 additions & 2 deletions test/test_ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,36 @@ def test_wrap_socket_no_ssltransport(self) -> None:
ssl_.ssl_wrap_socket(sock, tls_in_tls=True)

@pytest.mark.parametrize(
["pha", "expected_pha"], [(None, None), (False, True), (True, True)]
["pha", "expected_pha", "cert_reqs"],
[
(None, None, None),
(None, None, ssl.CERT_NONE),
(None, None, ssl.CERT_OPTIONAL),
(None, None, ssl.CERT_REQUIRED),
(False, True, None),
(False, True, ssl.CERT_NONE),
(False, True, ssl.CERT_OPTIONAL),
(False, True, ssl.CERT_REQUIRED),
(True, True, None),
(True, True, ssl.CERT_NONE),
(True, True, ssl.CERT_OPTIONAL),
(True, True, ssl.CERT_REQUIRED),
],
)
def test_create_urllib3_context_pha(
self,
monkeypatch: pytest.MonkeyPatch,
pha: bool | None,
expected_pha: bool | None,
cert_reqs: int | None,
) -> None:
context = mock.create_autospec(ssl_.SSLContext)
context.set_ciphers = mock.Mock()
context.options = 0
context.post_handshake_auth = pha
monkeypatch.setattr(ssl_, "SSLContext", lambda *_, **__: context)

assert ssl_.create_urllib3_context() is context
assert ssl_.create_urllib3_context(cert_reqs=cert_reqs) is context

assert context.post_handshake_auth == expected_pha

Expand Down

0 comments on commit d7bb83b

Please sign in to comment.