22import platform
33import socket
44import ssl
5+ import sys
56import typing
67
7- import _ssl # type: ignore[import]
8+ import _ssl # type: ignore[import-not-found ]
89
910from ._ssl_constants import (
1011 _original_SSLContext ,
@@ -49,7 +50,7 @@ def extract_from_ssl() -> None:
4950 try :
5051 import pip ._vendor .urllib3 .util .ssl_ as urllib3_ssl
5152
52- urllib3_ssl .SSLContext = _original_SSLContext
53+ urllib3_ssl .SSLContext = _original_SSLContext # type: ignore[assignment]
5354 except ImportError :
5455 pass
5556
@@ -171,16 +172,13 @@ def cert_store_stats(self) -> dict[str, int]:
171172 @typing .overload
172173 def get_ca_certs (
173174 self , binary_form : typing .Literal [False ] = ...
174- ) -> list [typing .Any ]:
175- ...
175+ ) -> list [typing .Any ]: ...
176176
177177 @typing .overload
178- def get_ca_certs (self , binary_form : typing .Literal [True ] = ...) -> list [bytes ]:
179- ...
178+ def get_ca_certs (self , binary_form : typing .Literal [True ] = ...) -> list [bytes ]: ...
180179
181180 @typing .overload
182- def get_ca_certs (self , binary_form : bool = ...) -> typing .Any :
183- ...
181+ def get_ca_certs (self , binary_form : bool = ...) -> typing .Any : ...
184182
185183 def get_ca_certs (self , binary_form : bool = False ) -> list [typing .Any ] | list [bytes ]:
186184 raise NotImplementedError ()
@@ -276,6 +274,25 @@ def verify_mode(self, value: ssl.VerifyMode) -> None:
276274 )
277275
278276
277+ # Python 3.13+ makes get_unverified_chain() a public API that only returns DER
278+ # encoded certificates. We detect whether we need to call public_bytes() for 3.10->3.12
279+ # Pre-3.13 returned None instead of an empty list from get_unverified_chain()
280+ if sys .version_info >= (3 , 13 ):
281+
282+ def _get_unverified_chain_bytes (sslobj : ssl .SSLObject ) -> list [bytes ]:
283+ unverified_chain = sslobj .get_unverified_chain () or () # type: ignore[attr-defined]
284+ return [
285+ cert if isinstance (cert , bytes ) else cert .public_bytes (_ssl .ENCODING_DER )
286+ for cert in unverified_chain
287+ ]
288+
289+ else :
290+
291+ def _get_unverified_chain_bytes (sslobj : ssl .SSLObject ) -> list [bytes ]:
292+ unverified_chain = sslobj .get_unverified_chain () or () # type: ignore[attr-defined]
293+ return [cert .public_bytes (_ssl .ENCODING_DER ) for cert in unverified_chain ]
294+
295+
279296def _verify_peercerts (
280297 sock_or_sslobj : ssl .SSLSocket | ssl .SSLObject , server_hostname : str | None
281298) -> None :
@@ -290,13 +307,7 @@ def _verify_peercerts(
290307 except AttributeError :
291308 pass
292309
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 ]
310+ cert_bytes = _get_unverified_chain_bytes (sslobj )
300311 _verify_peercerts_impl (
301312 sock_or_sslobj .context , cert_bytes , server_hostname = server_hostname
302313 )
0 commit comments