Skip to content

Commit 8d65ea1

Browse files
authored
Merge pull request from GHSA-5phf-pp7p-vc2r
* Enable hostname verification for HTTPS proxies with default cert. Signed-off-by: Jorge Lopez Silva <jalopezsilva@gmail.com> * Adjust exception check for Python 3.9+ Signed-off-by: Jorge Lopez Silva <jalopezsilva@gmail.com> * Use a SAN instead of a common name. Signed-off-by: Jorge Lopez Silva <jalopezsilva@gmail.com>
1 parent 5e34326 commit 8d65ea1

File tree

3 files changed

+37
-0
lines changed

3 files changed

+37
-0
lines changed

src/urllib3/connection.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,10 @@ def _connect_tls_proxy(self, hostname, conn):
490490
self.ca_cert_dir,
491491
self.ca_cert_data,
492492
)
493+
# By default urllib3's SSLContext disables `check_hostname` and uses
494+
# a custom check. For proxies we're good with relying on the default
495+
# verification.
496+
ssl_context.check_hostname = True
493497

494498
# If no cert was provided, use only the default options for server
495499
# certificate validation

test/conftest.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ def no_san_server(tmp_path_factory):
6464
yield cfg
6565

6666

67+
@pytest.fixture
68+
def no_localhost_san_server(tmp_path_factory):
69+
tmpdir = tmp_path_factory.mktemp("certs")
70+
ca = trustme.CA()
71+
# non localhost common name
72+
server_cert = ca.issue_cert(u"example.com")
73+
74+
with run_server_in_thread("https", "localhost", tmpdir, ca, server_cert) as cfg:
75+
yield cfg
76+
77+
6778
@pytest.fixture
6879
def ip_san_server(tmp_path_factory):
6980
tmpdir = tmp_path_factory.mktemp("certs")

test/with_dummyserver/test_proxy_poolmanager.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,3 +543,25 @@ def test_basic_ipv6_proxy(self):
543543

544544
r = http.request("GET", "%s/" % self.https_url)
545545
assert r.status == 200
546+
547+
548+
class TestHTTPSProxyVerification:
549+
@onlyPy3
550+
def test_https_proxy_hostname_verification(self, no_localhost_san_server):
551+
bad_server = no_localhost_san_server
552+
bad_proxy_url = "https://%s:%s" % (bad_server.host, bad_server.port)
553+
554+
# An exception will be raised before we contact the destination domain.
555+
test_url = "testing.com"
556+
with proxy_from_url(bad_proxy_url, ca_certs=bad_server.ca_certs) as https:
557+
with pytest.raises(MaxRetryError) as e:
558+
https.request("GET", "http://%s/" % test_url)
559+
assert isinstance(e.value.reason, SSLError)
560+
assert "hostname 'localhost' doesn't match" in str(e.value.reason)
561+
562+
with pytest.raises(MaxRetryError) as e:
563+
https.request("GET", "https://%s/" % test_url)
564+
assert isinstance(e.value.reason, SSLError)
565+
assert "hostname 'localhost' doesn't match" in str(
566+
e.value.reason
567+
) or "Hostname mismatch" in str(e.value.reason)

0 commit comments

Comments
 (0)