22import platform
33import socket
44import ssl
5+ import sys
56import typing
67
7- import _ssl # type: ignore[import]
8-
98from ._ssl_constants import (
109 _original_SSLContext ,
1110 _original_super_SSLContext ,
@@ -49,7 +48,7 @@ def extract_from_ssl() -> None:
4948 try :
5049 import pip ._vendor .urllib3 .util .ssl_ as urllib3_ssl
5150
52- urllib3_ssl .SSLContext = _original_SSLContext
51+ urllib3_ssl .SSLContext = _original_SSLContext # type: ignore[assignment]
5352 except ImportError :
5453 pass
5554
@@ -171,16 +170,13 @@ def cert_store_stats(self) -> dict[str, int]:
171170 @typing .overload
172171 def get_ca_certs (
173172 self , binary_form : typing .Literal [False ] = ...
174- ) -> list [typing .Any ]:
175- ...
173+ ) -> list [typing .Any ]: ...
176174
177175 @typing .overload
178- def get_ca_certs (self , binary_form : typing .Literal [True ] = ...) -> list [bytes ]:
179- ...
176+ def get_ca_certs (self , binary_form : typing .Literal [True ] = ...) -> list [bytes ]: ...
180177
181178 @typing .overload
182- def get_ca_certs (self , binary_form : bool = ...) -> typing .Any :
183- ...
179+ def get_ca_certs (self , binary_form : bool = ...) -> typing .Any : ...
184180
185181 def get_ca_certs (self , binary_form : bool = False ) -> list [typing .Any ] | list [bytes ]:
186182 raise NotImplementedError ()
@@ -276,6 +272,23 @@ def verify_mode(self, value: ssl.VerifyMode) -> None:
276272 )
277273
278274
275+ # Python 3.13+ makes get_unverified_chain() a public API that only returns DER
276+ # encoded certificates. We detect whether we need to call public_bytes() for 3.10->3.12
277+ # Pre-3.13 returned None instead of an empty list from get_unverified_chain()
278+ if sys .version_info >= (3 , 13 ):
279+
280+ def _get_unverified_chain_bytes (sslobj : ssl .SSLObject ) -> list [bytes ]:
281+ unverified_chain = sslobj .get_unverified_chain () or () # type: ignore[attr-defined]
282+ return [cert for cert in unverified_chain ]
283+
284+ else :
285+ import _ssl # type: ignore[import-not-found]
286+
287+ def _get_unverified_chain_bytes (sslobj : ssl .SSLObject ) -> list [bytes ]:
288+ unverified_chain = sslobj .get_unverified_chain () or () # type: ignore[attr-defined]
289+ return [cert .public_bytes (_ssl .ENCODING_DER ) for cert in unverified_chain ]
290+
291+
279292def _verify_peercerts (
280293 sock_or_sslobj : ssl .SSLSocket | ssl .SSLObject , server_hostname : str | None
281294) -> None :
@@ -290,13 +303,7 @@ def _verify_peercerts(
290303 except AttributeError :
291304 pass
292305
293- # SSLObject.get_unverified_chain() returns 'None'
294- # if the peer sends no certificates. This is common
295- # for the server-side scenario.
296- unverified_chain : typing .Sequence [_ssl .Certificate ] = (
297- sslobj .get_unverified_chain () or () # type: ignore[attr-defined]
298- )
299- cert_bytes = [cert .public_bytes (_ssl .ENCODING_DER ) for cert in unverified_chain ]
306+ cert_bytes = _get_unverified_chain_bytes (sslobj )
300307 _verify_peercerts_impl (
301308 sock_or_sslobj .context , cert_bytes , server_hostname = server_hostname
302309 )
0 commit comments