Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Upgrade vendored truststore to 0.9.0" #12671

Merged
merged 1 commit into from
May 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion news/truststore.vendor.rst

This file was deleted.

2 changes: 1 addition & 1 deletion src/pip/_vendor/truststore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
del _api, _sys # type: ignore[name-defined] # noqa: F821

__all__ = ["SSLContext", "inject_into_ssl", "extract_from_ssl"]
__version__ = "0.9.0"
__version__ = "0.8.0"
39 changes: 16 additions & 23 deletions src/pip/_vendor/truststore/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
import platform
import socket
import ssl
import sys
import typing

import _ssl # type: ignore[import]

from ._ssl_constants import (
_original_SSLContext,
_original_super_SSLContext,
Expand Down Expand Up @@ -48,7 +49,7 @@ def extract_from_ssl() -> None:
try:
import pip._vendor.urllib3.util.ssl_ as urllib3_ssl

urllib3_ssl.SSLContext = _original_SSLContext # type: ignore[assignment]
urllib3_ssl.SSLContext = _original_SSLContext
except ImportError:
pass

Expand Down Expand Up @@ -170,13 +171,16 @@ def cert_store_stats(self) -> dict[str, int]:
@typing.overload
def get_ca_certs(
self, binary_form: typing.Literal[False] = ...
) -> list[typing.Any]: ...
) -> list[typing.Any]:
...

@typing.overload
def get_ca_certs(self, binary_form: typing.Literal[True] = ...) -> list[bytes]: ...
def get_ca_certs(self, binary_form: typing.Literal[True] = ...) -> list[bytes]:
...

@typing.overload
def get_ca_certs(self, binary_form: bool = ...) -> typing.Any: ...
def get_ca_certs(self, binary_form: bool = ...) -> typing.Any:
...

def get_ca_certs(self, binary_form: bool = False) -> list[typing.Any] | list[bytes]:
raise NotImplementedError()
Expand Down Expand Up @@ -272,23 +276,6 @@ def verify_mode(self, value: ssl.VerifyMode) -> None:
)


# Python 3.13+ makes get_unverified_chain() a public API that only returns DER
# encoded certificates. We detect whether we need to call public_bytes() for 3.10->3.12
# Pre-3.13 returned None instead of an empty list from get_unverified_chain()
if sys.version_info >= (3, 13):

def _get_unverified_chain_bytes(sslobj: ssl.SSLObject) -> list[bytes]:
unverified_chain = sslobj.get_unverified_chain() or () # type: ignore[attr-defined]
return [cert for cert in unverified_chain]

else:
import _ssl # type: ignore[import-not-found]

def _get_unverified_chain_bytes(sslobj: ssl.SSLObject) -> list[bytes]:
unverified_chain = sslobj.get_unverified_chain() or () # type: ignore[attr-defined]
return [cert.public_bytes(_ssl.ENCODING_DER) for cert in unverified_chain]


def _verify_peercerts(
sock_or_sslobj: ssl.SSLSocket | ssl.SSLObject, server_hostname: str | None
) -> None:
Expand All @@ -303,7 +290,13 @@ def _verify_peercerts(
except AttributeError:
pass

cert_bytes = _get_unverified_chain_bytes(sslobj)
# SSLObject.get_unverified_chain() returns 'None'
# if the peer sends no certificates. This is common
# for the server-side scenario.
unverified_chain: typing.Sequence[_ssl.Certificate] = (
sslobj.get_unverified_chain() or () # type: ignore[attr-defined]
)
cert_bytes = [cert.public_bytes(_ssl.ENCODING_DER) for cert in unverified_chain]
_verify_peercerts_impl(
sock_or_sslobj.context, cert_bytes, server_hostname=server_hostname
)
14 changes: 8 additions & 6 deletions src/pip/_vendor/truststore/_macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ def _load_cdll(name: str, macos10_16_path: str) -> CDLL:
Security.SecTrustSetAnchorCertificatesOnly.argtypes = [SecTrustRef, Boolean]
Security.SecTrustSetAnchorCertificatesOnly.restype = OSStatus

Security.SecTrustEvaluate.argtypes = [SecTrustRef, POINTER(SecTrustResultType)]
Security.SecTrustEvaluate.restype = OSStatus

Security.SecPolicyCreateRevocation.argtypes = [CFOptionFlags]
Security.SecPolicyCreateRevocation.restype = SecPolicyRef

Expand Down Expand Up @@ -256,7 +259,6 @@ def _handle_osstatus(result: OSStatus, _: typing.Any, args: typing.Any) -> typin

Security.SecTrustCreateWithCertificates.errcheck = _handle_osstatus # type: ignore[assignment]
Security.SecTrustSetAnchorCertificates.errcheck = _handle_osstatus # type: ignore[assignment]
Security.SecTrustSetAnchorCertificatesOnly.errcheck = _handle_osstatus # type: ignore[assignment]
Security.SecTrustGetTrustResult.errcheck = _handle_osstatus # type: ignore[assignment]


Expand Down Expand Up @@ -415,21 +417,21 @@ def _verify_peercerts_impl(
CoreFoundation.CFRelease(certs)

# If there are additional trust anchors to load we need to transform
# the list of DER-encoded certificates into a CFArray.
# the list of DER-encoded certificates into a CFArray. Otherwise
# pass 'None' to signal that we only want system / fetched certificates.
ctx_ca_certs_der: list[bytes] | None = ssl_context.get_ca_certs(
binary_form=True
)
if ctx_ca_certs_der:
ctx_ca_certs = None
try:
ctx_ca_certs = _der_certs_to_cf_cert_array(ctx_ca_certs_der)
ctx_ca_certs = _der_certs_to_cf_cert_array(cert_chain)
Security.SecTrustSetAnchorCertificates(trust, ctx_ca_certs)
finally:
if ctx_ca_certs:
CoreFoundation.CFRelease(ctx_ca_certs)

# We always want system certificates.
Security.SecTrustSetAnchorCertificatesOnly(trust, False)
else:
Security.SecTrustSetAnchorCertificates(trust, None)

cf_error = CoreFoundation.CFErrorRef()
sec_trust_eval_result = Security.SecTrustEvaluateWithError(
Expand Down
30 changes: 10 additions & 20 deletions src/pip/_vendor/truststore/_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,6 @@ def _verify_peercerts_impl(
server_hostname: str | None = None,
) -> None:
"""Verify the cert_chain from the server using Windows APIs."""

# If the peer didn't send any certificates then
# we can't do verification. Raise an error.
if not cert_chain:
raise ssl.SSLCertVerificationError("Peer sent no certificates to verify")

pCertContext = None
hIntermediateCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, None, 0, None)
try:
Expand Down Expand Up @@ -381,7 +375,7 @@ def _verify_peercerts_impl(
server_hostname,
chain_flags=chain_flags,
)
except ssl.SSLCertVerificationError as e:
except ssl.SSLCertVerificationError:
# If that fails but custom CA certs have been added
# to the SSLContext using load_verify_locations,
# try verifying using a custom chain engine
Expand All @@ -390,19 +384,15 @@ def _verify_peercerts_impl(
binary_form=True
)
if custom_ca_certs:
try:
_verify_using_custom_ca_certs(
ssl_context,
custom_ca_certs,
hIntermediateCertStore,
pCertContext,
pChainPara,
server_hostname,
chain_flags=chain_flags,
)
# Raise the original error, not the new error.
except ssl.SSLCertVerificationError:
raise e from None
_verify_using_custom_ca_certs(
ssl_context,
custom_ca_certs,
hIntermediateCertStore,
pCertContext,
pChainPara,
server_hostname,
chain_flags=chain_flags,
)
else:
raise
finally:
Expand Down
2 changes: 1 addition & 1 deletion src/pip/_vendor/vendor.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ setuptools==69.1.1
six==1.16.0
tenacity==8.2.3
tomli==2.0.1
truststore==0.9.0
truststore==0.8.0
webencodings==0.5.1
Loading