From 43d4f3885cea9c0f8844b0307f9ebd1e95174504 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Mon, 11 Dec 2023 18:30:30 -0800 Subject: [PATCH 01/22] add _ssl module Really all I needed for fixing the inheritance was _ssl._SSLContext. But then I needed all the other stuff in _ssl, and if I was doing that I wanted to do a thorough job of it. Motivation was originally related to https://github.com/python/typeshed/issues/3968 , but we're well beyond that now, really. --- stdlib/VERSIONS | 1 + stdlib/_ssl.pyi | 330 ++++++++++++++++++++++++++++++++++++++++++++++++ stdlib/ssl.pyi | 147 ++++++++------------- 3 files changed, 381 insertions(+), 97 deletions(-) create mode 100644 stdlib/_ssl.pyi diff --git a/stdlib/VERSIONS b/stdlib/VERSIONS index f5e30c4602b4..888640e6cf8e 100644 --- a/stdlib/VERSIONS +++ b/stdlib/VERSIONS @@ -46,6 +46,7 @@ _pydecimal: 3.5- _random: 2.7- _sitebuiltins: 3.4- _socket: 3.0- # present in 2.7 at runtime, but not in typeshed +_ssl: 2.7- _stat: 3.4- _thread: 2.7- _threading_local: 2.7- diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi new file mode 100644 index 000000000000..45c592d1ed29 --- /dev/null +++ b/stdlib/_ssl.pyi @@ -0,0 +1,330 @@ +import sys +from _typeshed import Incomplete, ReadableBuffer, StrOrBytesPath +from collections.abc import Callable +from ssl import ( + SSLCertVerificationError as SSLCertVerificationError, + SSLContext, + SSLEOFError as SSLEOFError, + SSLError as SSLError, + SSLObject, + SSLSocket, + SSLSyscallError as SSLSyscallError, + SSLWantReadError as SSLWantReadError, + SSLWantWriteError as SSLWantWriteError, + SSLZeroReturnError as SSLZeroReturnError, +) +from typing import Any, overload +from typing_extensions import Literal, NotRequired, Self, TypeAlias, TypedDict, final + +_PasswordType: TypeAlias = Callable[[], str | bytes | bytearray] | str | bytes | bytearray +_PCTRTT: TypeAlias = tuple[tuple[str, str], ...] +_PCTRTTT: TypeAlias = tuple[_PCTRTT, ...] +_PeerCertRetDictType: TypeAlias = dict[str, str | _PCTRTTT | _PCTRTT] + +class _Cipher(TypedDict): + aead: bool + alg_bits: int + auth: str + description: str + digest: str | None + id: int + kea: str + name: str + protocol: str + strength_bits: int + symmetric: str + +class _CertInfo(TypedDict): + subject: tuple[tuple[tuple[str, str], ...], ...] + issuer: tuple[tuple[tuple[str, str], ...], ...] + version: int + serialNumber: str + notBefore: str + notAfter: str + subjectAltName: NotRequired[tuple[tuple[str, str], ...] | None] + OCSP: NotRequired[tuple[str, ...] | None] + caIssuers: NotRequired[tuple[str, ...] | None] + crlDistributionPoints: NotRequired[tuple[str, ...] | None] + +class _EmptyCertInfo(TypedDict): ... + +def _test_decode_cert(__path: str) -> _CertInfo: ... +def RAND_add(__string: str | ReadableBuffer, __entropy: float) -> None: ... +def RAND_bytes(__n: int) -> bytes: ... + +if sys.version_info < (3, 12): + def RAND_pseudo_bytes(__n: int) -> tuple[bytes, bool]: ... + +if sys.version_info < (3, 10): + def RAND_egd(path: str) -> None: ... + +def RAND_status() -> bool: ... +def get_default_verify_paths() -> tuple[str, str, str, str]: ... + +if sys.platform == "win32": + _EnumRetType: TypeAlias = list[tuple[bytes, str, set[str] | bool]] + def enum_certificates(store_name: str) -> _EnumRetType: ... + def enum_crls(store_name: str) -> _EnumRetType: ... + +def txt2obj(txt: str, name: bool = False) -> tuple[int, str, str, str]: ... +def nid2obj(__nid: int) -> tuple[int, str, str, str]: ... + +class _SSLContext: + _host_flags: int + _msg_callback: Callable[..., Incomplete] + check_hostname: bool + if sys.version_info >= (3, 8): + keylog_filename: str | None + maximum_version: int + minimum_version: int + num_tickets: int + options: int + if sys.version_info >= (3, 8): + post_handshake_auth: bool + protocol: int + if sys.version_info >= (3, 10): + security_level: int + sni_callback: Callable[[SSLObject, str, SSLContext], None | int] | None + verify_flags: int + verify_mode: int + def __init__(self, __proto_version: int) -> None: ... + def _set_alpn_protocols(self, __protos: bytearray) -> None: ... + def _wrap_bio( + self, + incoming: MemoryBIO, + outgoing: MemoryBIO, + server_side: bool, + server_hostname: str | bytes | None = None, + *, + owner: object | None = None, + session: SSLSession | None = None, + ) -> Self: ... + def _wrap_socket( + self, + sock: SSLSocket, + server_side: bool, + server_hostname: str | None = None, + *, + owner: SSLSocket | SSLObject | None = None, + session: SSLSession | None = None, + ) -> _SSLSocket: ... + def cert_store_stats(self) -> dict[str, int]: ... + @overload + def get_ca_certs(self, binary_form: Literal[False] = False) -> list[_PeerCertRetDictType]: ... + @overload + def get_ca_certs(self, binary_form: Literal[True]) -> list[bytes]: ... + @overload + def get_ca_certs(self, binary_form: bool = False) -> Any: ... + def get_ciphers(self) -> list[_Cipher]: ... + def load_cert_chain( + self, certfile: StrOrBytesPath, keyfile: StrOrBytesPath | None = None, password: _PasswordType | None = None + ) -> None: ... + def load_dh_params(self, __path: str) -> None: ... + def load_verify_locations( + self, + cafile: StrOrBytesPath | None = None, + capath: StrOrBytesPath | None = None, + cadata: str | ReadableBuffer | None = None, + ) -> None: ... + def session_stats(self) -> dict[str, int]: ... + def set_ciphers(self, __cipherlist: str) -> None: ... + def set_default_verify_paths(self) -> None: ... + def set_ecdh_curve(self, __name: str) -> None: ... + +@final +class _SSLSocket: + context: SSLContext + owner: SSLSocket | SSLObject | None + server_hostname: str | None + server_side: bool + session: SSLSession | None + session_reused: bool + def cipher(self) -> tuple[str, str, int] | None: ... + def compression(self) -> str | None: ... + def do_handshake(self) -> None: ... + def get_channel_binding(self, cb_type: str = "tls-unique") -> bytes | None: ... + def get_unverified_chain(self) -> list[Certificate] | None: ... + def get_verified_chain(self) -> list[Certificate] | None: ... + @overload + def getpeercert(self, __der: Literal[False] = False) -> _CertInfo | _EmptyCertInfo | None: ... + @overload + def getpeercert(self, __der: Literal[True]) -> bytes | None: ... + @overload + def getpeercert(self, __der: bool = False) -> _CertInfo | _EmptyCertInfo | bytes | None: ... + def pending(self) -> int: ... + def read(self, __len: int) -> bytes: ... + def selected_alpn_protocol(self) -> str | None: ... + def shared_ciphers(self) -> tuple[str, str, int] | None: ... + def shutdown(self) -> _SSLSocket | None: ... + def verify_client_post_handshake(self) -> None: ... + def version(self) -> str: ... + def write(self, __b: ReadableBuffer) -> int: ... + +@final +class MemoryBIO: + eof: bool + pending: int + def __init__(self) -> None: ... + def read(self, __size: int = -1) -> bytes: ... + def write(self, __b: ReadableBuffer) -> int: ... + def write_eof(self) -> None: ... + +@final +class SSLSession: + has_ticket: bool + id: bytes + ticket_lifetime_hint: int + time: int + timeout: int + def __eq__(self, other: object) -> bool: ... + def __ge__(self, other: object) -> bool: ... + def __gt__(self, other: object) -> bool: ... + def __le__(self, other: object) -> bool: ... + def __lt__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... + +@final +class Certificate: + def get_info(self) -> _CertInfo: ... + @overload + def public_bytes(self) -> str: ... + @overload + def public_bytes(self, __format: Literal[1]) -> str: ... # ENCODING_PEM + @overload + def public_bytes(self, __format: Literal[2]) -> bytes: ... # ENCODING_DER + @overload + def public_bytes(self, __format: int = 1) -> str | bytes: ... + def __eq__(self, other: object) -> bool: ... + def __ge__(self, other: object) -> bool: ... + def __gt__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def __le__(self, other: object) -> bool: ... + def __lt__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... + +if sys.version_info < (3, 12): + err_codes_to_names: dict[tuple[int, int], str] + err_names_to_codes: dict[str, tuple[int, int]] + lib_codes_to_names: dict[int, str] + +_DEFAULT_CIPHERS: str + +# SSL error numbers +SSL_ERROR_ZERO_RETURN: int +SSL_ERROR_WANT_READ: int +SSL_ERROR_WANT_WRITE: int +SSL_ERROR_WANT_X509_LOOKUP: int +SSL_ERROR_SYSCALL: int +SSL_ERROR_SSL: int +SSL_ERROR_WANT_CONNECT: int +SSL_ERROR_EOF: int +SSL_ERROR_INVALID_ERROR_CODE: int + +# verify modes +CERT_NONE: int +CERT_OPTIONAL: int +CERT_REQUIRED: int + +# verify flags +VERIFY_DEFAULT: int +VERIFY_CRL_CHECK_LEAF: int +VERIFY_CRL_CHECK_CHAIN: int +VERIFY_X509_STRICT: int +VERIFY_ALLOW_PROXY_CERTS: int +VERIFY_X509_TRUSTED_FIRST: int +VERIFY_X509_PARTIAL_CHAIN: int + +# alert descriptions +ALERT_DESCRIPTION_CLOSE_NOTIFY: int +ALERT_DESCRIPTION_UNEXPECTED_MESSAGE: int +ALERT_DESCRIPTION_BAD_RECORD_MAC: int +ALERT_DESCRIPTION_RECORD_OVERFLOW: int +ALERT_DESCRIPTION_DECOMPRESSION_FAILURE: int +ALERT_DESCRIPTION_HANDSHAKE_FAILURE: int +ALERT_DESCRIPTION_BAD_CERTIFICATE: int +ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE: int +ALERT_DESCRIPTION_CERTIFICATE_REVOKED: int +ALERT_DESCRIPTION_CERTIFICATE_EXPIRED: int +ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN: int +ALERT_DESCRIPTION_ILLEGAL_PARAMETER: int +ALERT_DESCRIPTION_UNKNOWN_CA: int +ALERT_DESCRIPTION_ACCESS_DENIED: int +ALERT_DESCRIPTION_DECODE_ERROR: int +ALERT_DESCRIPTION_DECRYPT_ERROR: int +ALERT_DESCRIPTION_PROTOCOL_VERSION: int +ALERT_DESCRIPTION_INSUFFICIENT_SECURITY: int +ALERT_DESCRIPTION_INTERNAL_ERROR: int +ALERT_DESCRIPTION_USER_CANCELLED: int +ALERT_DESCRIPTION_NO_RENEGOTIATION: int +ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION: int +ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE: int +ALERT_DESCRIPTION_UNRECOGNIZED_NAME: int +ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE: int +ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE: int +ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY: int + +# protocol versions +PROTOCOL_SSLv23: int +PROTOCOL_TLS: int +PROTOCOL_TLS_CLIENT: int +PROTOCOL_TLS_SERVER: int +PROTOCOL_TLSv1: int +PROTOCOL_TLSv1_1: int +PROTOCOL_TLSv1_2: int + +# protocol options +OP_ALL: int +OP_NO_SSLv2: int +OP_NO_SSLv3: int +OP_NO_TLSv1: int +OP_NO_TLSv1_1: int +OP_NO_TLSv1_2: int +OP_NO_TLSv1_3: int +OP_CIPHER_SERVER_PREFERENCE: int +OP_SINGLE_DH_USE: int +OP_NO_TICKET: int +OP_SINGLE_ECDH_USE: int +OP_NO_COMPRESSION: int +OP_ENABLE_MIDDLEBOX_COMPAT: int +OP_NO_RENEGOTIATION: int + +# host flags +HOSTFLAG_ALWAYS_CHECK_SUBJECT: int +HOSTFLAG_NEVER_CHECK_SUBJECT: int +HOSTFLAG_NO_WILDCARDS: int +HOSTFLAG_NO_PARTIAL_WILDCARDS: int +HOSTFLAG_MULTI_LABEL_WILDCARDS: int +HOSTFLAG_SINGLE_LABEL_SUBDOMAINS: int + +# certificate file types +# Typed as Literal so the overload on Certificate.public_bytes can work properly. +ENCODING_PEM: Literal[1] +ENCODING_DER: Literal[2] + +# protocol versions +PROTO_MINIMUM_SUPPORTED: int +PROTO_MAXIMUM_SUPPORTED: int +PROTO_SSLv3: int +PROTO_TLSv1: int +PROTO_TLSv1_1: int +PROTO_TLSv1_2: int +PROTO_TLSv1_3: int + +# feature support +HAS_SNI: bool +HAS_TLS_UNIQUE: bool +HAS_ECDH: bool +HAS_NPN: bool +HAS_ALPN: bool +HAS_SSLv2: bool +HAS_SSLv3: bool +HAS_TLSv1: bool +HAS_TLSv1_1: bool +HAS_TLSv1_2: bool +HAS_TLSv1_3: bool + +# version info +OPENSSL_VERSION_NUMBER: int +OPENSSL_VERSION_INFO: tuple[int, int, int, int, int] +OPENSSL_VERSION: str +_OPENSSL_API_VERSION: tuple[int, int, int, int, int] diff --git a/stdlib/ssl.pyi b/stdlib/ssl.pyi index d7f256d031ac..eb04bd60209f 100644 --- a/stdlib/ssl.pyi +++ b/stdlib/ssl.pyi @@ -4,30 +4,48 @@ import sys from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer from collections.abc import Callable, Iterable from typing import Any, NamedTuple, overload -from typing_extensions import Literal, Never, Self, TypeAlias, TypedDict, final +from typing_extensions import Literal, Never, Self, TypeAlias + +from _ssl import ( + _DEFAULT_CIPHERS as _DEFAULT_CIPHERS, + _OPENSSL_API_VERSION as _OPENSSL_API_VERSION, + HAS_ALPN as HAS_ALPN, + HAS_ECDH as HAS_ECDH, + HAS_NPN as HAS_NPN, + HAS_SNI as HAS_SNI, + OPENSSL_VERSION as OPENSSL_VERSION, + OPENSSL_VERSION_INFO as OPENSSL_VERSION_INFO, + OPENSSL_VERSION_NUMBER as OPENSSL_VERSION_NUMBER, + HAS_SSLv2 as HAS_SSLv2, + HAS_SSLv3 as HAS_SSLv3, + HAS_TLSv1 as HAS_TLSv1, + HAS_TLSv1_1 as HAS_TLSv1_1, + HAS_TLSv1_2 as HAS_TLSv1_2, + HAS_TLSv1_3 as HAS_TLSv1_3, + MemoryBIO as MemoryBIO, + RAND_add as RAND_add, + RAND_bytes as RAND_bytes, + RAND_status as RAND_status, + SSLSession as SSLSession, + _SSLContext, + _SSLSocket, +) + +if sys.version_info < (3, 12): + from _ssl import RAND_pseudo_bytes as RAND_pseudo_bytes + +if sys.version_info < (3, 10): + from _ssl import RAND_egd as RAND_egd + +if sys.platform == "win32": + from _ssl import enum_certificates as enum_certificates, enum_crls as enum_crls _PCTRTT: TypeAlias = tuple[tuple[str, str], ...] _PCTRTTT: TypeAlias = tuple[_PCTRTT, ...] _PeerCertRetDictType: TypeAlias = dict[str, str | _PCTRTTT | _PCTRTT] _PeerCertRetType: TypeAlias = _PeerCertRetDictType | bytes | None -_EnumRetType: TypeAlias = list[tuple[bytes, str, set[str] | bool]] -_PasswordType: TypeAlias = Callable[[], str | bytes | bytearray] | str | bytes | bytearray - _SrvnmeCbType: TypeAlias = Callable[[SSLSocket | SSLObject, str | None, SSLSocket], int | None] -class _Cipher(TypedDict): - aead: bool - alg_bits: int - auth: str - description: str - digest: str | None - id: int - kea: str - name: str - protocol: str - strength_bits: int - symmetric: str - class SSLError(OSError): library: str reason: str @@ -96,15 +114,6 @@ else: _create_default_https_context: Callable[..., SSLContext] -def RAND_bytes(__n: int) -> bytes: ... - -if sys.version_info < (3, 12): - def RAND_pseudo_bytes(__n: int) -> tuple[bytes, bool]: ... - -def RAND_status() -> bool: ... -def RAND_egd(path: str) -> None: ... -def RAND_add(__string: str | ReadableBuffer, __entropy: float) -> None: ... - if sys.version_info < (3, 12): def match_hostname(cert: _PeerCertRetDictType, hostname: str) -> None: ... @@ -131,10 +140,6 @@ class DefaultVerifyPaths(NamedTuple): def get_default_verify_paths() -> DefaultVerifyPaths: ... -if sys.platform == "win32": - def enum_certificates(store_name: str) -> _EnumRetType: ... - def enum_crls(store_name: str) -> _EnumRetType: ... - class VerifyMode(enum.IntEnum): CERT_NONE: int CERT_OPTIONAL: int @@ -233,21 +238,8 @@ elif sys.version_info >= (3, 8) and sys.platform == "linux": OP_IGNORE_UNEXPECTED_EOF: Options HAS_NEVER_CHECK_COMMON_NAME: bool -HAS_SSLv2: bool -HAS_SSLv3: bool -HAS_TLSv1: bool -HAS_TLSv1_1: bool -HAS_TLSv1_2: bool -HAS_TLSv1_3: bool -HAS_ALPN: bool -HAS_ECDH: bool -HAS_SNI: bool -HAS_NPN: bool -CHANNEL_BINDING_TYPES: list[str] -OPENSSL_VERSION: str -OPENSSL_VERSION_INFO: tuple[int, int, int, int, int] -OPENSSL_VERSION_NUMBER: int +CHANNEL_BINDING_TYPES: list[str] class AlertDescription(enum.IntEnum): ALERT_DESCRIPTION_ACCESS_DENIED: int @@ -328,6 +320,7 @@ class SSLSocket(socket.socket): server_side: bool server_hostname: str | None session: SSLSession | None + _sslobj: _SSLSocket | None @property def session_reused(self) -> bool | None: ... def __init__(self, *args: Any, **kwargs: Any) -> None: ... @@ -371,6 +364,17 @@ class SSLSocket(socket.socket): def recvmsg(self, *args: Never, **kwargs: Never) -> Never: ... # type: ignore[override] def recvmsg_into(self, *args: Never, **kwargs: Never) -> Never: ... # type: ignore[override] def sendmsg(self, *args: Never, **kwargs: Never) -> Never: ... # type: ignore[override] + @classmethod + def _create( + cls, + sock: socket.socket, + server_side: bool = False, + do_handshake_on_connect: bool = True, + suppress_ragged_eofs: bool = True, + server_hostname: str | bytes | None = None, + context: SSLContext | None = None, + session: SSLSession | None = None, + ) -> SSLSocket: ... class TLSVersion(enum.IntEnum): MINIMUM_SUPPORTED: int @@ -381,27 +385,20 @@ class TLSVersion(enum.IntEnum): TLSv1_2: int TLSv1_3: int -class SSLContext: - check_hostname: bool +class SSLContext(_SSLContext): options: Options verify_flags: VerifyFlags verify_mode: VerifyMode @property - def protocol(self) -> _SSLMethod: ... + def protocol(self) -> _SSLMethod: ... # type: ignore[override] hostname_checks_common_name: bool maximum_version: TLSVersion minimum_version: TLSVersion - sni_callback: Callable[[SSLObject, str, SSLContext], None | int] | None # The following two attributes have class-level defaults. # However, the docs explicitly state that it's OK to override these attributes on instances, # so making these ClassVars wouldn't be appropriate sslobject_class: type[SSLObject] sslsocket_class: type[SSLSocket] - if sys.version_info >= (3, 8): - keylog_filename: str - post_handshake_auth: bool - if sys.version_info >= (3, 10): - security_level: int if sys.version_info >= (3, 10): # Using the default (None) for the `protocol` parameter is deprecated, # but there isn't a good way of marking that in the stub unless/until PEP 702 is accepted @@ -409,31 +406,10 @@ class SSLContext: else: def __new__(cls, protocol: int = ..., *args: Any, **kwargs: Any) -> Self: ... - def cert_store_stats(self) -> dict[str, int]: ... - def load_cert_chain( - self, certfile: StrOrBytesPath, keyfile: StrOrBytesPath | None = None, password: _PasswordType | None = None - ) -> None: ... def load_default_certs(self, purpose: Purpose = ...) -> None: ... - def load_verify_locations( - self, - cafile: StrOrBytesPath | None = None, - capath: StrOrBytesPath | None = None, - cadata: str | ReadableBuffer | None = None, - ) -> None: ... - @overload - def get_ca_certs(self, binary_form: Literal[False] = False) -> list[_PeerCertRetDictType]: ... - @overload - def get_ca_certs(self, binary_form: Literal[True]) -> list[bytes]: ... - @overload - def get_ca_certs(self, binary_form: bool = False) -> Any: ... - def get_ciphers(self) -> list[_Cipher]: ... - def set_default_verify_paths(self) -> None: ... - def set_ciphers(self, __cipherlist: str) -> None: ... def set_alpn_protocols(self, alpn_protocols: Iterable[str]) -> None: ... def set_npn_protocols(self, npn_protocols: Iterable[str]) -> None: ... def set_servername_callback(self, server_name_callback: _SrvnmeCbType | None) -> None: ... - def load_dh_params(self, __path: str) -> None: ... - def set_ecdh_curve(self, __name: str) -> None: ... def wrap_socket( self, sock: socket.socket, @@ -451,7 +427,6 @@ class SSLContext: server_hostname: str | bytes | None = None, session: SSLSession | None = None, ) -> SSLObject: ... - def session_stats(self) -> dict[str, int]: ... class SSLObject: context: SSLContext @@ -484,28 +459,6 @@ class SSLObject: if sys.version_info >= (3, 8): def verify_client_post_handshake(self) -> None: ... -@final -class MemoryBIO: - pending: int - eof: bool - def read(self, __size: int = -1) -> bytes: ... - def write(self, __b: ReadableBuffer) -> int: ... - def write_eof(self) -> None: ... - -@final -class SSLSession: - @property - def has_ticket(self) -> bool: ... - @property - def id(self) -> bytes: ... - @property - def ticket_lifetime_hint(self) -> int: ... - @property - def time(self) -> int: ... - @property - def timeout(self) -> int: ... - def __eq__(self, __value: object) -> bool: ... - class SSLErrorNumber(enum.IntEnum): SSL_ERROR_EOF: int SSL_ERROR_INVALID_ERROR_CODE: int From 0ff1579e17c8669e5f057a79533ecac2e549913e Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 12 Dec 2023 13:30:36 -0800 Subject: [PATCH 02/22] stubtest fixes --- stdlib/_ssl.pyi | 60 ++++++++++++++---------- tests/stubtest_allowlists/py3_common.txt | 4 ++ 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 45c592d1ed29..e2424ccfc2ea 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -143,8 +143,10 @@ class _SSLSocket: def compression(self) -> str | None: ... def do_handshake(self) -> None: ... def get_channel_binding(self, cb_type: str = "tls-unique") -> bytes | None: ... - def get_unverified_chain(self) -> list[Certificate] | None: ... - def get_verified_chain(self) -> list[Certificate] | None: ... + if sys.version_info >= (3, 10): + def get_unverified_chain(self) -> list[Certificate] | None: ... + def get_verified_chain(self) -> list[Certificate] | None: ... + @overload def getpeercert(self, __der: Literal[False] = False) -> _CertInfo | _EmptyCertInfo | None: ... @overload @@ -183,24 +185,25 @@ class SSLSession: def __lt__(self, other: object) -> bool: ... def __ne__(self, other: object) -> bool: ... -@final -class Certificate: - def get_info(self) -> _CertInfo: ... - @overload - def public_bytes(self) -> str: ... - @overload - def public_bytes(self, __format: Literal[1]) -> str: ... # ENCODING_PEM - @overload - def public_bytes(self, __format: Literal[2]) -> bytes: ... # ENCODING_DER - @overload - def public_bytes(self, __format: int = 1) -> str | bytes: ... - def __eq__(self, other: object) -> bool: ... - def __ge__(self, other: object) -> bool: ... - def __gt__(self, other: object) -> bool: ... - def __hash__(self) -> int: ... - def __le__(self, other: object) -> bool: ... - def __lt__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... +if sys.version_info >= (3, 10): + @final + class Certificate: + def get_info(self) -> _CertInfo: ... + @overload + def public_bytes(self) -> str: ... + @overload + def public_bytes(self, __format: Literal[1]) -> str: ... # ENCODING_PEM + @overload + def public_bytes(self, __format: Literal[2]) -> bytes: ... # ENCODING_DER + @overload + def public_bytes(self, __format: int = 1) -> str | bytes: ... + def __eq__(self, other: object) -> bool: ... + def __ge__(self, other: object) -> bool: ... + def __gt__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def __le__(self, other: object) -> bool: ... + def __lt__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... if sys.version_info < (3, 12): err_codes_to_names: dict[tuple[int, int], str] @@ -230,9 +233,10 @@ VERIFY_DEFAULT: int VERIFY_CRL_CHECK_LEAF: int VERIFY_CRL_CHECK_CHAIN: int VERIFY_X509_STRICT: int -VERIFY_ALLOW_PROXY_CERTS: int VERIFY_X509_TRUSTED_FIRST: int -VERIFY_X509_PARTIAL_CHAIN: int +if sys.version_info >= (3, 10): + VERIFY_ALLOW_PROXY_CERTS: int + VERIFY_X509_PARTIAL_CHAIN: int # alert descriptions ALERT_DESCRIPTION_CLOSE_NOTIFY: int @@ -287,6 +291,9 @@ OP_SINGLE_ECDH_USE: int OP_NO_COMPRESSION: int OP_ENABLE_MIDDLEBOX_COMPAT: int OP_NO_RENEGOTIATION: int +if sys.version_info >= (3, 12): + OP_LEGACY_SERVER_CONNECT: int + OP_ENABLE_KTLS: int # host flags HOSTFLAG_ALWAYS_CHECK_SUBJECT: int @@ -296,10 +303,11 @@ HOSTFLAG_NO_PARTIAL_WILDCARDS: int HOSTFLAG_MULTI_LABEL_WILDCARDS: int HOSTFLAG_SINGLE_LABEL_SUBDOMAINS: int -# certificate file types -# Typed as Literal so the overload on Certificate.public_bytes can work properly. -ENCODING_PEM: Literal[1] -ENCODING_DER: Literal[2] +if sys.version_info >= (3, 10): + # certificate file types + # Typed as Literal so the overload on Certificate.public_bytes can work properly. + ENCODING_PEM: Literal[1] + ENCODING_DER: Literal[2] # protocol versions PROTO_MINIMUM_SUPPORTED: int diff --git a/tests/stubtest_allowlists/py3_common.txt b/tests/stubtest_allowlists/py3_common.txt index c79bcacd6565..50f2c392a7e3 100644 --- a/tests/stubtest_allowlists/py3_common.txt +++ b/tests/stubtest_allowlists/py3_common.txt @@ -13,6 +13,7 @@ _collections_abc.KeysView.__reversed__ _collections_abc.ValuesView.__reversed__ _csv.Dialect.__init__ # C __init__ signature is inaccurate _ctypes.CFuncPtr # stubtest erroneously thinks it can't be subclassed +_ssl.MemoryBio.__init__ # takes no arguments except self, but stubtest thinks it's (self, *args, *kwargs) _threading_local.local.__new__ ast.Bytes.__new__ ast.Ellipsis.__new__ @@ -114,6 +115,7 @@ shutil.rmtree # stubtest doesn't like that we have this as an instance of a cal socketserver.BaseServer.fileno # implemented in derived classes socketserver.BaseServer.get_request # implemented in derived classes socketserver.BaseServer.server_bind # implemented in derived classes +ssl.MemoryBio.__init__ # takes no arguments except self, but stubtest thinks it's (self, *args, *kwargs) ssl.Purpose.__new__ # the multiple inheritance confuses mypy sys.UnraisableHookArgs # Not exported from sys tarfile.TarFile.errors # errors is initialized for some reason as None even though it really only accepts str @@ -463,6 +465,8 @@ imaplib.IMAP4_SSL.ssl ssl.PROTOCOL_SSLv2 ssl.PROTOCOL_SSLv3 ssl.RAND_egd +_ssl.RAND_egd +_ssl.OP_IGNORE_UNEXPECTED_EOF pickle._Pickler\..* # Best effort typing for undocumented internals pickle._Unpickler\..* # Best effort typing for undocumented internals From e0915bc66adae8d6bfa404ccd88460cfd54ce618 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 12 Dec 2023 13:51:17 -0800 Subject: [PATCH 03/22] more stubcheck fixes --- stdlib/_ssl.pyi | 4 ++++ stdlib/ssl.pyi | 1 + tests/stubtest_allowlists/py38.txt | 5 +++++ tests/stubtest_allowlists/py39.txt | 4 ++++ tests/stubtest_allowlists/py3_common.txt | 3 --- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index e2424ccfc2ea..d2753ffd0916 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -291,6 +291,10 @@ OP_SINGLE_ECDH_USE: int OP_NO_COMPRESSION: int OP_ENABLE_MIDDLEBOX_COMPAT: int OP_NO_RENEGOTIATION: int +if sys.version_info >= (3, 11): + OP_IGNORE_UNEXPECTED_EOF: int +elif sys.version_info >= (3, 8) and sys.platform == "linux": + OP_IGNORE_UNEXPECTED_EOF: int if sys.version_info >= (3, 12): OP_LEGACY_SERVER_CONNECT: int OP_ENABLE_KTLS: int diff --git a/stdlib/ssl.pyi b/stdlib/ssl.pyi index eb04bd60209f..5bfa93baf745 100644 --- a/stdlib/ssl.pyi +++ b/stdlib/ssl.pyi @@ -27,6 +27,7 @@ from _ssl import ( RAND_bytes as RAND_bytes, RAND_status as RAND_status, SSLSession as SSLSession, + _PasswordType as _PasswordType, # typeshed only, but re-export for other type stubs to use _SSLContext, _SSLSocket, ) diff --git a/tests/stubtest_allowlists/py38.txt b/tests/stubtest_allowlists/py38.txt index 066af3848240..b6c98874a726 100644 --- a/tests/stubtest_allowlists/py38.txt +++ b/tests/stubtest_allowlists/py38.txt @@ -185,3 +185,8 @@ unittest\.test\..+ # These enums derive from (str, Enum) pstats.SortKey.__new__ tkinter.EventType.__new__ + + +# Items that depend on the existence and flags of SSL +ssl.RAND_egd +_ssl.RAND_egd diff --git a/tests/stubtest_allowlists/py39.txt b/tests/stubtest_allowlists/py39.txt index 2d1e93e5695b..b36fe202b67a 100644 --- a/tests/stubtest_allowlists/py39.txt +++ b/tests/stubtest_allowlists/py39.txt @@ -167,3 +167,7 @@ types.CodeType.replace # stubtest thinks default values are None but None doesn # These enums derive from (str, Enum) pstats.SortKey.__new__ tkinter.EventType.__new__ + +# Items that depend on the existence and flags of SSL +ssl.RAND_egd +_ssl.RAND_egd diff --git a/tests/stubtest_allowlists/py3_common.txt b/tests/stubtest_allowlists/py3_common.txt index 50f2c392a7e3..c79f77129f9e 100644 --- a/tests/stubtest_allowlists/py3_common.txt +++ b/tests/stubtest_allowlists/py3_common.txt @@ -464,9 +464,6 @@ queue.SimpleQueue.__init__ imaplib.IMAP4_SSL.ssl ssl.PROTOCOL_SSLv2 ssl.PROTOCOL_SSLv3 -ssl.RAND_egd -_ssl.RAND_egd -_ssl.OP_IGNORE_UNEXPECTED_EOF pickle._Pickler\..* # Best effort typing for undocumented internals pickle._Unpickler\..* # Best effort typing for undocumented internals From f74c6ca5a36c596d7beecd232856a697d800014c Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 12 Dec 2023 13:55:47 -0800 Subject: [PATCH 04/22] last one --- stdlib/_ssl.pyi | 4 +++- tests/stubtest_allowlists/py3_common.txt | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index d2753ffd0916..7398e4b90109 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -166,7 +166,9 @@ class _SSLSocket: class MemoryBIO: eof: bool pending: int - def __init__(self) -> None: ... + # stubtest thinks this is (self, *args, *kwargs) + # and doesn't respect the alowlist entry for some reason + # def __init__(self) -> None: ... def read(self, __size: int = -1) -> bytes: ... def write(self, __b: ReadableBuffer) -> int: ... def write_eof(self) -> None: ... diff --git a/tests/stubtest_allowlists/py3_common.txt b/tests/stubtest_allowlists/py3_common.txt index c79f77129f9e..d38fba17b801 100644 --- a/tests/stubtest_allowlists/py3_common.txt +++ b/tests/stubtest_allowlists/py3_common.txt @@ -13,7 +13,6 @@ _collections_abc.KeysView.__reversed__ _collections_abc.ValuesView.__reversed__ _csv.Dialect.__init__ # C __init__ signature is inaccurate _ctypes.CFuncPtr # stubtest erroneously thinks it can't be subclassed -_ssl.MemoryBio.__init__ # takes no arguments except self, but stubtest thinks it's (self, *args, *kwargs) _threading_local.local.__new__ ast.Bytes.__new__ ast.Ellipsis.__new__ @@ -115,7 +114,6 @@ shutil.rmtree # stubtest doesn't like that we have this as an instance of a cal socketserver.BaseServer.fileno # implemented in derived classes socketserver.BaseServer.get_request # implemented in derived classes socketserver.BaseServer.server_bind # implemented in derived classes -ssl.MemoryBio.__init__ # takes no arguments except self, but stubtest thinks it's (self, *args, *kwargs) ssl.Purpose.__new__ # the multiple inheritance confuses mypy sys.UnraisableHookArgs # Not exported from sys tarfile.TarFile.errors # errors is initialized for some reason as None even though it really only accepts str From d1a30905ee7226ff14ce6e508bc9c7467a10cc66 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 12 Dec 2023 14:06:23 -0800 Subject: [PATCH 05/22] this may or may not make pyright happy --- stdlib/_ssl.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 7398e4b90109..5a7bf2ab1734 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -87,7 +87,7 @@ class _SSLContext: sni_callback: Callable[[SSLObject, str, SSLContext], None | int] | None verify_flags: int verify_mode: int - def __init__(self, __proto_version: int) -> None: ... + def __new__(cls, __protocol: int) -> None: ... def _set_alpn_protocols(self, __protos: bytearray) -> None: ... def _wrap_bio( self, From 5bf63054d9acb93420072f34c5f636d5ae9d40dc Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 12 Dec 2023 14:08:45 -0800 Subject: [PATCH 06/22] fix return type --- stdlib/_ssl.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 5a7bf2ab1734..310686bbecab 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -87,7 +87,7 @@ class _SSLContext: sni_callback: Callable[[SSLObject, str, SSLContext], None | int] | None verify_flags: int verify_mode: int - def __new__(cls, __protocol: int) -> None: ... + def __new__(cls, __protocol: int) -> Self: ... def _set_alpn_protocols(self, __protos: bytearray) -> None: ... def _wrap_bio( self, From 026f4c81b52e2563e5875950da4870a322f24ef5 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 12 Dec 2023 14:16:38 -0800 Subject: [PATCH 07/22] remove stray extra newline --- tests/stubtest_allowlists/py38.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/stubtest_allowlists/py38.txt b/tests/stubtest_allowlists/py38.txt index b6c98874a726..fdd6c365972c 100644 --- a/tests/stubtest_allowlists/py38.txt +++ b/tests/stubtest_allowlists/py38.txt @@ -186,7 +186,6 @@ unittest\.test\..+ pstats.SortKey.__new__ tkinter.EventType.__new__ - # Items that depend on the existence and flags of SSL ssl.RAND_egd _ssl.RAND_egd From 72a5ee8977d6f5c5abc6955f136bda6619841b57 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 12 Dec 2023 16:19:38 -0800 Subject: [PATCH 08/22] remove private unnecessary private objects --- stdlib/_ssl.pyi | 25 +------------------------ stdlib/ssl.pyi | 13 ------------- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 310686bbecab..6f49946d105d 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -1,5 +1,5 @@ import sys -from _typeshed import Incomplete, ReadableBuffer, StrOrBytesPath +from _typeshed import ReadableBuffer, StrOrBytesPath from collections.abc import Callable from ssl import ( SSLCertVerificationError as SSLCertVerificationError, @@ -48,7 +48,6 @@ class _CertInfo(TypedDict): class _EmptyCertInfo(TypedDict): ... -def _test_decode_cert(__path: str) -> _CertInfo: ... def RAND_add(__string: str | ReadableBuffer, __entropy: float) -> None: ... def RAND_bytes(__n: int) -> bytes: ... @@ -70,8 +69,6 @@ def txt2obj(txt: str, name: bool = False) -> tuple[int, str, str, str]: ... def nid2obj(__nid: int) -> tuple[int, str, str, str]: ... class _SSLContext: - _host_flags: int - _msg_callback: Callable[..., Incomplete] check_hostname: bool if sys.version_info >= (3, 8): keylog_filename: str | None @@ -88,26 +85,6 @@ class _SSLContext: verify_flags: int verify_mode: int def __new__(cls, __protocol: int) -> Self: ... - def _set_alpn_protocols(self, __protos: bytearray) -> None: ... - def _wrap_bio( - self, - incoming: MemoryBIO, - outgoing: MemoryBIO, - server_side: bool, - server_hostname: str | bytes | None = None, - *, - owner: object | None = None, - session: SSLSession | None = None, - ) -> Self: ... - def _wrap_socket( - self, - sock: SSLSocket, - server_side: bool, - server_hostname: str | None = None, - *, - owner: SSLSocket | SSLObject | None = None, - session: SSLSession | None = None, - ) -> _SSLSocket: ... def cert_store_stats(self) -> dict[str, int]: ... @overload def get_ca_certs(self, binary_form: Literal[False] = False) -> list[_PeerCertRetDictType]: ... diff --git a/stdlib/ssl.pyi b/stdlib/ssl.pyi index 5bfa93baf745..913f561861d9 100644 --- a/stdlib/ssl.pyi +++ b/stdlib/ssl.pyi @@ -29,7 +29,6 @@ from _ssl import ( SSLSession as SSLSession, _PasswordType as _PasswordType, # typeshed only, but re-export for other type stubs to use _SSLContext, - _SSLSocket, ) if sys.version_info < (3, 12): @@ -321,7 +320,6 @@ class SSLSocket(socket.socket): server_side: bool server_hostname: str | None session: SSLSession | None - _sslobj: _SSLSocket | None @property def session_reused(self) -> bool | None: ... def __init__(self, *args: Any, **kwargs: Any) -> None: ... @@ -365,17 +363,6 @@ class SSLSocket(socket.socket): def recvmsg(self, *args: Never, **kwargs: Never) -> Never: ... # type: ignore[override] def recvmsg_into(self, *args: Never, **kwargs: Never) -> Never: ... # type: ignore[override] def sendmsg(self, *args: Never, **kwargs: Never) -> Never: ... # type: ignore[override] - @classmethod - def _create( - cls, - sock: socket.socket, - server_side: bool = False, - do_handshake_on_connect: bool = True, - suppress_ragged_eofs: bool = True, - server_hostname: str | bytes | None = None, - context: SSLContext | None = None, - session: SSLSession | None = None, - ) -> SSLSocket: ... class TLSVersion(enum.IntEnum): MINIMUM_SUPPORTED: int From 59c132da85cd3933d3f742603e13de001d634086 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 12 Dec 2023 16:45:01 -0800 Subject: [PATCH 09/22] remove _ssl._SSLSocket but add a comment about where _ssl.Certificate objects come from, because that's just weird otherwise --- stdlib/_ssl.pyi | 44 ++++++++++---------------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 6f49946d105d..9f3cd99e3a10 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -7,7 +7,6 @@ from ssl import ( SSLEOFError as SSLEOFError, SSLError as SSLError, SSLObject, - SSLSocket, SSLSyscallError as SSLSyscallError, SSLWantReadError as SSLWantReadError, SSLWantWriteError as SSLWantWriteError, @@ -46,8 +45,6 @@ class _CertInfo(TypedDict): caIssuers: NotRequired[tuple[str, ...] | None] crlDistributionPoints: NotRequired[tuple[str, ...] | None] -class _EmptyCertInfo(TypedDict): ... - def RAND_add(__string: str | ReadableBuffer, __entropy: float) -> None: ... def RAND_bytes(__n: int) -> bytes: ... @@ -108,37 +105,6 @@ class _SSLContext: def set_default_verify_paths(self) -> None: ... def set_ecdh_curve(self, __name: str) -> None: ... -@final -class _SSLSocket: - context: SSLContext - owner: SSLSocket | SSLObject | None - server_hostname: str | None - server_side: bool - session: SSLSession | None - session_reused: bool - def cipher(self) -> tuple[str, str, int] | None: ... - def compression(self) -> str | None: ... - def do_handshake(self) -> None: ... - def get_channel_binding(self, cb_type: str = "tls-unique") -> bytes | None: ... - if sys.version_info >= (3, 10): - def get_unverified_chain(self) -> list[Certificate] | None: ... - def get_verified_chain(self) -> list[Certificate] | None: ... - - @overload - def getpeercert(self, __der: Literal[False] = False) -> _CertInfo | _EmptyCertInfo | None: ... - @overload - def getpeercert(self, __der: Literal[True]) -> bytes | None: ... - @overload - def getpeercert(self, __der: bool = False) -> _CertInfo | _EmptyCertInfo | bytes | None: ... - def pending(self) -> int: ... - def read(self, __len: int) -> bytes: ... - def selected_alpn_protocol(self) -> str | None: ... - def shared_ciphers(self) -> tuple[str, str, int] | None: ... - def shutdown(self) -> _SSLSocket | None: ... - def verify_client_post_handshake(self) -> None: ... - def version(self) -> str: ... - def write(self, __b: ReadableBuffer) -> int: ... - @final class MemoryBIO: eof: bool @@ -164,6 +130,16 @@ class SSLSession: def __lt__(self, other: object) -> bool: ... def __ne__(self, other: object) -> bool: ... +# _ssl.Certificate is weird: it can't be instantiated or subclassed. +# Instances can only be created via methods of the private _ssl._SSLSocket class, +# for which the relevant method signatures are: +# +# class _SSLSocket: +# def get_unverified_chain(self) -> list[Certificate] | None: ... +# def get_verified_chain(self) -> list[Certificate] | None: ... +# +# You can find a _ssl._SSLSocket object as the _sslobj attribute of a ssl.SSLSocket object + if sys.version_info >= (3, 10): @final class Certificate: From a7bcc50746d6bb56be16a83c5386223f2e1c2da1 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 12 Dec 2023 19:33:16 -0800 Subject: [PATCH 10/22] realized that I didn't need the dunder methods because they're inherited from object --- stdlib/_ssl.pyi | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 9f3cd99e3a10..46b39eddc1fc 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -123,12 +123,6 @@ class SSLSession: ticket_lifetime_hint: int time: int timeout: int - def __eq__(self, other: object) -> bool: ... - def __ge__(self, other: object) -> bool: ... - def __gt__(self, other: object) -> bool: ... - def __le__(self, other: object) -> bool: ... - def __lt__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... # _ssl.Certificate is weird: it can't be instantiated or subclassed. # Instances can only be created via methods of the private _ssl._SSLSocket class, @@ -152,13 +146,6 @@ if sys.version_info >= (3, 10): def public_bytes(self, __format: Literal[2]) -> bytes: ... # ENCODING_DER @overload def public_bytes(self, __format: int = 1) -> str | bytes: ... - def __eq__(self, other: object) -> bool: ... - def __ge__(self, other: object) -> bool: ... - def __gt__(self, other: object) -> bool: ... - def __hash__(self) -> int: ... - def __le__(self, other: object) -> bool: ... - def __lt__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... if sys.version_info < (3, 12): err_codes_to_names: dict[tuple[int, int], str] From 46dbd59fdf71fba5dbc3f5d4eeba07a6f88f7560 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Wed, 13 Dec 2023 11:00:57 -0800 Subject: [PATCH 11/22] add _ssl to ruff's isort configuration --- pyproject.toml | 1 + stdlib/ssl.pyi | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c32392828a41..04fc38d0e5e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,6 +80,7 @@ extra-standard-library = [ "_random", "_sitebuiltins", "_socket", + "_ssl", "_stat", "_thread", "_threading_local", diff --git a/stdlib/ssl.pyi b/stdlib/ssl.pyi index 913f561861d9..b9d4e1b02655 100644 --- a/stdlib/ssl.pyi +++ b/stdlib/ssl.pyi @@ -1,11 +1,6 @@ import enum import socket import sys -from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer -from collections.abc import Callable, Iterable -from typing import Any, NamedTuple, overload -from typing_extensions import Literal, Never, Self, TypeAlias - from _ssl import ( _DEFAULT_CIPHERS as _DEFAULT_CIPHERS, _OPENSSL_API_VERSION as _OPENSSL_API_VERSION, @@ -30,6 +25,10 @@ from _ssl import ( _PasswordType as _PasswordType, # typeshed only, but re-export for other type stubs to use _SSLContext, ) +from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer +from collections.abc import Callable, Iterable +from typing import Any, NamedTuple, overload +from typing_extensions import Literal, Never, Self, TypeAlias if sys.version_info < (3, 12): from _ssl import RAND_pseudo_bytes as RAND_pseudo_bytes From 37c1b40b66e4e2cc235a1509e403cc3f9bf4cbd8 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 16 Feb 2024 06:44:37 -0800 Subject: [PATCH 12/22] Update stdlib/ssl.pyi --- stdlib/ssl.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/ssl.pyi b/stdlib/ssl.pyi index 81789a596165..79bd12e794e9 100644 --- a/stdlib/ssl.pyi +++ b/stdlib/ssl.pyi @@ -27,8 +27,8 @@ from _ssl import ( ) from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer from collections.abc import Callable, Iterable -from typing import Any, NamedTuple, TypedDict, final, overload -from typing_extensions import Literal, Never, Self, TypeAlias +from typing import Any, Literal, NamedTuple, TypedDict, final, overload +from typing_extensions import Never, Self, TypeAlias if sys.version_info < (3, 12): from _ssl import RAND_pseudo_bytes as RAND_pseudo_bytes From 97174959ec05dc68bbe67b24b961a03775960c05 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 14:47:29 +0000 Subject: [PATCH 13/22] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/ssl.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/ssl.pyi b/stdlib/ssl.pyi index 79bd12e794e9..a2c0c483432e 100644 --- a/stdlib/ssl.pyi +++ b/stdlib/ssl.pyi @@ -27,7 +27,7 @@ from _ssl import ( ) from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer from collections.abc import Callable, Iterable -from typing import Any, Literal, NamedTuple, TypedDict, final, overload +from typing import Any, Literal, NamedTuple, overload from typing_extensions import Never, Self, TypeAlias if sys.version_info < (3, 12): From c5353011c79ab13eb6333c1d35fbb54105006d93 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 16 Feb 2024 07:00:33 -0800 Subject: [PATCH 14/22] typing imports --- stdlib/_ssl.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 46b39eddc1fc..7c3d7be1b6c3 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -12,8 +12,8 @@ from ssl import ( SSLWantWriteError as SSLWantWriteError, SSLZeroReturnError as SSLZeroReturnError, ) -from typing import Any, overload -from typing_extensions import Literal, NotRequired, Self, TypeAlias, TypedDict, final +from typing import Any, Literal, TypedDict, final overload +from typing_extensions import NotRequired, Self, TypeAlias _PasswordType: TypeAlias = Callable[[], str | bytes | bytearray] | str | bytes | bytearray _PCTRTT: TypeAlias = tuple[tuple[str, str], ...] From 4cc8b029b64b5a2b8ae7e3981c5a266f29e5459b Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 1 Oct 2024 18:13:11 -0700 Subject: [PATCH 15/22] fix syntax --- stdlib/_ssl.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 7c3d7be1b6c3..8e38e420e2bd 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -12,7 +12,7 @@ from ssl import ( SSLWantWriteError as SSLWantWriteError, SSLZeroReturnError as SSLZeroReturnError, ) -from typing import Any, Literal, TypedDict, final overload +from typing import Any, Literal, TypedDict, final, overload from typing_extensions import NotRequired, Self, TypeAlias _PasswordType: TypeAlias = Callable[[], str | bytes | bytearray] | str | bytes | bytearray From e44acfb473b5cd5427cb8519b3534af9b077a261 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 01:21:21 +0000 Subject: [PATCH 16/22] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/_ssl.pyi | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 021d44467795..cd0ee0a18efd 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -67,14 +67,12 @@ def nid2obj(__nid: int) -> tuple[int, str, str, str]: ... class _SSLContext: check_hostname: bool - if sys.version_info >= (3, 8): - keylog_filename: str | None + keylog_filename: str | None maximum_version: int minimum_version: int num_tickets: int options: int - if sys.version_info >= (3, 8): - post_handshake_auth: bool + post_handshake_auth: bool protocol: int if sys.version_info >= (3, 10): security_level: int From 8f0a4f0755af908776ee7387668f55e41b9dc197 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 1 Oct 2024 18:43:15 -0700 Subject: [PATCH 17/22] 3.13 updates --- stdlib/_ssl.pyi | 2 ++ stdlib/ssl.pyi | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index cd0ee0a18efd..96455a6fb74f 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -272,6 +272,8 @@ HAS_SNI: bool HAS_TLS_UNIQUE: bool HAS_ECDH: bool HAS_NPN: bool +if sys.version_info >= (3, 13): + HAS_PSK: bool HAS_ALPN: bool HAS_SSLv2: bool HAS_SSLv3: bool diff --git a/stdlib/ssl.pyi b/stdlib/ssl.pyi index d8a6532a741f..73cf0805c6ad 100644 --- a/stdlib/ssl.pyi +++ b/stdlib/ssl.pyi @@ -30,6 +30,9 @@ from collections.abc import Callable, Iterable from typing import Any, Literal, NamedTuple, overload from typing_extensions import Never, Self, TypeAlias, TypedDict +if sys.version_info >= (3, 13): + from _ssl import HAS_PSK as HAS_PSK + if sys.version_info < (3, 12): from _ssl import RAND_pseudo_bytes as RAND_pseudo_bytes @@ -446,6 +449,13 @@ class SSLContext(_SSLContext): server_hostname: str | bytes | None = None, session: SSLSession | None = None, ) -> SSLObject: ... + if sys.version_info >= (3, 13): + def set_psk_client_callback( + self, psk_client_callback: Callable[[str | None], tuple[str | None, bytes]] | None + ) -> None: ... + def set_psk_server_callback( + self, psk_server_callback: Callable[[str | None], tuple[str | None, bytes]] | None, identity_hint: str | None = None + ) -> None: ... class SSLObject: context: SSLContext From e4843e61189b5d692df4556c9290d75fbff001e6 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 1 Oct 2024 18:51:09 -0700 Subject: [PATCH 18/22] wrong class --- stdlib/_ssl.pyi | 7 +++++++ stdlib/ssl.pyi | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 96455a6fb74f..9dc90b30479c 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -102,6 +102,13 @@ class _SSLContext: def set_ciphers(self, __cipherlist: str) -> None: ... def set_default_verify_paths(self) -> None: ... def set_ecdh_curve(self, __name: str) -> None: ... + if sys.version_info >= (3, 13): + def set_psk_client_callback( + self, callback: Callable[[str | None], tuple[str | None, bytes]] | None + ) -> None: ... + def set_psk_server_callback( + self, callback: Callable[[str | None], tuple[str | None, bytes]] | None, identity_hint: str | None = None + ) -> None: ... @final class MemoryBIO: diff --git a/stdlib/ssl.pyi b/stdlib/ssl.pyi index 73cf0805c6ad..3bf51c7dd534 100644 --- a/stdlib/ssl.pyi +++ b/stdlib/ssl.pyi @@ -449,13 +449,6 @@ class SSLContext(_SSLContext): server_hostname: str | bytes | None = None, session: SSLSession | None = None, ) -> SSLObject: ... - if sys.version_info >= (3, 13): - def set_psk_client_callback( - self, psk_client_callback: Callable[[str | None], tuple[str | None, bytes]] | None - ) -> None: ... - def set_psk_server_callback( - self, psk_server_callback: Callable[[str | None], tuple[str | None, bytes]] | None, identity_hint: str | None = None - ) -> None: ... class SSLObject: context: SSLContext From 9e486f3cd975989db2f51c3a2502492fee436cb9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 01:55:21 +0000 Subject: [PATCH 19/22] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/_ssl.pyi | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 9dc90b30479c..6bb8805f41ca 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -103,9 +103,7 @@ class _SSLContext: def set_default_verify_paths(self) -> None: ... def set_ecdh_curve(self, __name: str) -> None: ... if sys.version_info >= (3, 13): - def set_psk_client_callback( - self, callback: Callable[[str | None], tuple[str | None, bytes]] | None - ) -> None: ... + def set_psk_client_callback(self, callback: Callable[[str | None], tuple[str | None, bytes]] | None) -> None: ... def set_psk_server_callback( self, callback: Callable[[str | None], tuple[str | None, bytes]] | None, identity_hint: str | None = None ) -> None: ... From 521fab2428e845e8207526941f450eda6e9cd640 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 1 Oct 2024 19:53:39 -0700 Subject: [PATCH 20/22] upgrade syntax --- stdlib/_ssl.pyi | 26 +++++++++++++------------- stdlib/ssl.pyi | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 6bb8805f41ca..1b552dfdbf7d 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -45,11 +45,11 @@ class _CertInfo(TypedDict): caIssuers: NotRequired[tuple[str, ...] | None] crlDistributionPoints: NotRequired[tuple[str, ...] | None] -def RAND_add(__string: str | ReadableBuffer, __entropy: float) -> None: ... -def RAND_bytes(__n: int) -> bytes: ... +def RAND_add(string: str | ReadableBuffer, entropy: float, /) -> None: ... +def RAND_bytes(n: int, /) -> bytes: ... if sys.version_info < (3, 12): - def RAND_pseudo_bytes(__n: int) -> tuple[bytes, bool]: ... + def RAND_pseudo_bytes(n: int, /) -> tuple[bytes, bool]: ... if sys.version_info < (3, 10): def RAND_egd(path: str) -> None: ... @@ -63,7 +63,7 @@ if sys.platform == "win32": def enum_crls(store_name: str) -> _EnumRetType: ... def txt2obj(txt: str, name: bool = False) -> tuple[int, str, str, str]: ... -def nid2obj(__nid: int) -> tuple[int, str, str, str]: ... +def nid2obj(nid: int, /) -> tuple[int, str, str, str]: ... class _SSLContext: check_hostname: bool @@ -79,7 +79,7 @@ class _SSLContext: sni_callback: Callable[[SSLObject, str, SSLContext], None | int] | None verify_flags: int verify_mode: int - def __new__(cls, __protocol: int) -> Self: ... + def __new__(cls, protocol: int, /) -> Self: ... def cert_store_stats(self) -> dict[str, int]: ... @overload def get_ca_certs(self, binary_form: Literal[False] = False) -> list[_PeerCertRetDictType]: ... @@ -91,7 +91,7 @@ class _SSLContext: def load_cert_chain( self, certfile: StrOrBytesPath, keyfile: StrOrBytesPath | None = None, password: _PasswordType | None = None ) -> None: ... - def load_dh_params(self, __path: str) -> None: ... + def load_dh_params(self, path: str, /) -> None: ... def load_verify_locations( self, cafile: StrOrBytesPath | None = None, @@ -99,9 +99,9 @@ class _SSLContext: cadata: str | ReadableBuffer | None = None, ) -> None: ... def session_stats(self) -> dict[str, int]: ... - def set_ciphers(self, __cipherlist: str) -> None: ... + def set_ciphers(self, cipherlist: str, /) -> None: ... def set_default_verify_paths(self) -> None: ... - def set_ecdh_curve(self, __name: str) -> None: ... + def set_ecdh_curve(self, name: str, /) -> None: ... if sys.version_info >= (3, 13): def set_psk_client_callback(self, callback: Callable[[str | None], tuple[str | None, bytes]] | None) -> None: ... def set_psk_server_callback( @@ -115,8 +115,8 @@ class MemoryBIO: # stubtest thinks this is (self, *args, *kwargs) # and doesn't respect the alowlist entry for some reason # def __init__(self) -> None: ... - def read(self, __size: int = -1) -> bytes: ... - def write(self, __b: ReadableBuffer) -> int: ... + def read(self, size: int = -1, /) -> bytes: ... + def write(self, b: ReadableBuffer, /) -> int: ... def write_eof(self) -> None: ... @final @@ -149,11 +149,11 @@ if sys.version_info >= (3, 10): @overload def public_bytes(self) -> str: ... @overload - def public_bytes(self, __format: Literal[1]) -> str: ... # ENCODING_PEM + def public_bytes(self, format: Literal[1], /) -> str: ... # ENCODING_PEM @overload - def public_bytes(self, __format: Literal[2]) -> bytes: ... # ENCODING_DER + def public_bytes(self, format: Literal[2], /) -> bytes: ... # ENCODING_DER @overload - def public_bytes(self, __format: int = 1) -> str | bytes: ... + def public_bytes(self, format: int = 1, /) -> str | bytes: ... if sys.version_info < (3, 12): err_codes_to_names: dict[tuple[int, int], str] diff --git a/stdlib/ssl.pyi b/stdlib/ssl.pyi index 3bf51c7dd534..1d97c02acc5e 100644 --- a/stdlib/ssl.pyi +++ b/stdlib/ssl.pyi @@ -27,8 +27,8 @@ from _ssl import ( ) from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer from collections.abc import Callable, Iterable -from typing import Any, Literal, NamedTuple, overload -from typing_extensions import Never, Self, TypeAlias, TypedDict +from typing import Any, Literal, NamedTuple, TypedDict, overload +from typing_extensions import Never, Self, TypeAlias if sys.version_info >= (3, 13): from _ssl import HAS_PSK as HAS_PSK From f54d04b3ae917913f5190ec097c639f5e6a2be7f Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 1 Oct 2024 19:58:37 -0700 Subject: [PATCH 21/22] fix default --- stdlib/_ssl.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 1b552dfdbf7d..41f10f656009 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -149,11 +149,11 @@ if sys.version_info >= (3, 10): @overload def public_bytes(self) -> str: ... @overload - def public_bytes(self, format: Literal[1], /) -> str: ... # ENCODING_PEM + def public_bytes(self, format: Literal[1] = 1, /) -> str: ... # ENCODING_PEM @overload def public_bytes(self, format: Literal[2], /) -> bytes: ... # ENCODING_DER @overload - def public_bytes(self, format: int = 1, /) -> str | bytes: ... + def public_bytes(self, format: int, /) -> str | bytes: ... if sys.version_info < (3, 12): err_codes_to_names: dict[tuple[int, int], str] From 91172654b1993eb4736dbf7af6958ac979ac6b7d Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 1 Oct 2024 20:00:35 -0700 Subject: [PATCH 22/22] Try this way --- stdlib/_ssl.pyi | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 41f10f656009..3e88874143df 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -112,9 +112,7 @@ class _SSLContext: class MemoryBIO: eof: bool pending: int - # stubtest thinks this is (self, *args, *kwargs) - # and doesn't respect the alowlist entry for some reason - # def __init__(self) -> None: ... + def __new__(self) -> Self: ... def read(self, size: int = -1, /) -> bytes: ... def write(self, b: ReadableBuffer, /) -> int: ... def write_eof(self) -> None: ...