Use trustme to generate IP_SAN cert
DELETE
dummyserver/certs/server.ip_san.crt
------BEGIN CERTIFICATE-----
-MIIDeTCCAuKgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UEBhMCRkkx
-DjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQHDAVkdW1teTEOMAwGA1UECgwFZHVtbXkx
-DjAMBgNVBAsMBWR1bW15MREwDwYDVQQDDAhTbmFrZU9pbDEfMB0GCSqGSIb3DQEJ
-ARYQZHVtbXlAdGVzdC5sb2NhbDAeFw0xMTEyMjIwNzU4NDBaFw0yMTEyMTgwNzU4
-NDBaMGExCzAJBgNVBAYTAkZJMQ4wDAYDVQQIDAVkdW1teTEOMAwGA1UEBwwFZHVt
-bXkxDjAMBgNVBAoMBWR1bW15MQ4wDAYDVQQLDAVkdW1teTESMBAGA1UEAwwJbG9j
-YWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXe3FqmCWvP8XPxqtT
-+0bfL1Tvzvebi46k0WIcUV8bP3vyYiSRXG9ALmyzZH4GHY9UVs4OEDkCMDOBSezB
-0y9ai/9doTNcaictdEBu8nfdXKoTtzrn+VX4UPrkH5hm7NQ1fTQuj1MR7yBCmYqN
-3Q2Q+Efuujyx0FwBzAuy1aKYuwIDAQABo4IBHjCCARowCQYDVR0TBAIwADAdBgNV
-HQ4EFgQUG+dK5Uos08QUwAWofDb3a8YcYlIwgbYGA1UdIwSBrjCBq4AUGXd/I2Ji
-QllF+3Wdx3NyBLszCi2hgYekgYQwgYExCzAJBgNVBAYTAkZJMQ4wDAYDVQQIDAVk
-dW1teTEOMAwGA1UEBwwFZHVtbXkxDjAMBgNVBAoMBWR1bW15MQ4wDAYDVQQLDAVk
-dW1teTERMA8GA1UEAwwIU25ha2VPaWwxHzAdBgkqhkiG9w0BCQEWEGR1bW15QHRl
-c3QubG9jYWyCCQCz67HKL+G/4zAJBgNVHRIEAjAAMCoGA1UdEQQjMCGBDnJvb3RA
-bG9jYWxob3N0gglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQEFBQADgYEAFEAy
-O9rxM14W0pVJWHTZkWBcDTqp8A8OB3JFVxeuCNcbtyfyYLWs2juv4YMmo1EKBOQe
-7LYfGuIvtIzT7KBa2QAPmX9JR+F6yl0IVSrYYt9hS7w9Cqr8+jK9QRpNwm3k25hp
-BmmoT5b9Q+AYcLMtdMu3uFjLmQBI2XobI/9vCT4=
------END CERTIFICATE-----

MODIFY
dummyserver/server.py
dummyserver/server.py
@@ -39,10 +39,6 @@ CLIENT_INTERMEDIATE_KEY = "client_intermediate.key"
CLIENT_CERT = os.path.join(CERTS_PATH, CLIENT_INTERMEDIATE_PEM)
PASSWORD_KEYFILE = os.path.join(CERTS_PATH, "server_password.key")
PASSWORD_CLIENT_KEYFILE = os.path.join(CERTS_PATH, "client_password.key")
-IP_SAN_CERTS = {
- "certfile": os.path.join(CERTS_PATH, "server.ip_san.crt"),
- "keyfile": DEFAULT_CERTS["keyfile"],
-}
IPV6_ADDR_CERTS = {
"certfile": os.path.join(CERTS_PATH, "server.ipv6addr.crt"),
"keyfile": os.path.join(CERTS_PATH, "server.ipv6addr.key"),

MODIFY
test/conftest.py
test/conftest.py
@@ -89,3 +89,26 @@ def no_san_server(tmp_path_factory):
{"keyfile": server_key_path, "certfile": server_cert_path},
) as cfg:
yield cfg
+
+
+@pytest.fixture
+def ip_san_server(tmp_path_factory):
+ tmpdir = tmp_path_factory.mktemp("certs")
+ ca = trustme.CA()
+ # IP address in Subject Alternative Name
+ server_cert = ca.issue_cert(u"127.0.0.1")
+
+ ca_cert_path = str(tmpdir / "ca.pem")
+ server_cert_path = str(tmpdir / "server.pem")
+ server_key_path = str(tmpdir / "server.key")
+ ca.cert_pem.write_to_path(ca_cert_path)
+ server_cert.private_key_pem.write_to_path(server_key_path)
+ server_cert.cert_chain_pems[0].write_to_path(server_cert_path)
+
+ with run_server_in_thread(
+ "https",
+ "127.0.0.1",
+ ca_cert_path,
+ {"keyfile": server_key_path, "certfile": server_cert_path},
+ ) as cfg:
+ yield cfg

MODIFY
test/with_dummyserver/test_https.py
test/with_dummyserver/test_https.py
@@ -21,7 +21,6 @@ from dummyserver.server import (
IPV6_ADDR_CERTS,
IPV6_ADDR_CA,
HAS_IPV6,
- IP_SAN_CERTS,
IPV6_SAN_CERTS,
IPV6_SAN_CA,
PASSWORD_CLIENT_KEYFILE,
@@ -721,10 +720,8 @@ class TestHTTPS_NoSAN:
assert warn.called
-class TestHTTPS_IPSAN(HTTPSDummyServerTestCase):
- certs = IP_SAN_CERTS
-
- def test_can_validate_ip_san(self):
+class TestHTTPS_IPSAN:
+ def test_can_validate_ip_san(self, ip_san_server):
"""Ensure that urllib3 can validate SANs with IP addresses in them."""
try:
import ipaddress # noqa: F401
@@ -732,7 +729,10 @@ class TestHTTPS_IPSAN(HTTPSDummyServerTestCase):
pytest.skip("Only runs on systems with an ipaddress module")
with HTTPSConnectionPool(
- "127.0.0.1", self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA
+ ip_san_server.host,
+ ip_san_server.port,
+ cert_reqs="CERT_REQUIRED",
+ ca_certs=ip_san_server.ca_certs,
) as https_pool:
r = https_pool.request("GET", "/")
assert r.status == 200

Use trustme to generate IP_SAN cert