Fix #125660: Extensions fail to sync HTTPS repositories on WIN32

Workaround: `[ASN1] nested asn1 error` error when making HTTPS
connections on systems with certificates that OpenSSL cannot parse
are installed.

This is a general issue with Python, resolve by applying a proposed
fix [0] to the extensions Python process at run-time.
(this doesn't impact Blender's Python run-time).

The down side is HTTPS connections will only work for extensions
on systems with this problem so this needs to be resolved by Python
long term.

While any changes to Python's SSL checks is worth avoiding,
this simply skips SSL certificates in the windows store that OpenSSL
can't parse instead of failing all SSL connections.

See related issues:

- https://github.com/python/cpython/issues/79846
- https://github.com/openssl/openssl/issues/25023

[0]: https://github.com/python/cpython/pull/91740

Ref !124943.
This commit is contained in:
Campbell Barton
2024-07-30 22:49:21 +10:00
parent 95d8b9096a
commit 3a88af5402

View File

@@ -142,6 +142,45 @@ ${body}
'''
# -----------------------------------------------------------------------------
# Workarounds
def _worlaround_win32_ssl_cert_failure() -> None:
# Applies workaround by `pukkandan` on GITHUB at run-time:
# See: https://github.com/python/cpython/pull/91740
import ssl
class SSLContext_DUMMY(ssl.SSLContext):
def _load_windows_store_certs(self, storename: str, purpose: ssl.Purpose) -> bytearray:
# WIN32 only.
enum_certificates = getattr(ssl, "enum_certificates", None)
assert callable(enum_certificates)
certs = bytearray()
try:
for cert, encoding, trust in enum_certificates(storename):
try:
self.load_verify_locations(cadata=cert)
except ssl.SSLError:
# warnings.warn("Bad certificate in Windows certificate store")
pass
else:
# CA certs are never PKCS#7 encoded
if encoding == "x509_asn":
if trust is True or purpose.oid in trust:
certs.extend(cert)
except PermissionError:
# warnings.warn("unable to enumerate Windows certificate store")
pass
# NOTE(@ideasman42): Python never uses this return value internally.
# Keep it for consistency.
return certs
ssl.SSLContext._load_windows_store_certs = SSLContext_DUMMY._load_windows_store_certs # type: ignore
# -----------------------------------------------------------------------------
# Argument Overrides
class _ArgsDefaultOverride:
__slots__ = (
"build_valid_tags",
@@ -155,6 +194,7 @@ class _ArgsDefaultOverride:
ARG_DEFAULTS_OVERRIDE = _ArgsDefaultOverride()
del _ArgsDefaultOverride
# Standard out may be communicating with a parent process,
# arbitrary prints are NOT acceptable.
@@ -4978,6 +5018,9 @@ def msglog_from_args(args: argparse.Namespace) -> MessageLogger:
raise Exception("Unknown output!")
# -----------------------------------------------------------------------------
# Main Function
def main(
argv: Optional[List[str]] = None,
args_internal: bool = True,
@@ -4999,6 +5042,9 @@ def main(
sys.stdout.write("{:s}\n".format(VERSION))
return 0
if sys.platform == "win32":
_worlaround_win32_ssl_cert_failure()
parser = argparse_create(
args_internal=args_internal,
args_extra_subcommands_fn=args_extra_subcommands_fn,