https://github.com/python/cpython/commit/af52b41afa4330fb38583db553631baa2f122f90
commit: af52b41afa4330fb38583db553631baa2f122f90
branch: 3.11
author: Gregory P. Smith <[email protected]>
committer: ambv <[email protected]>
date: 2026-10-24T16:10:44-07:00
summary:

[3.11] gh-160040: Distrust compromised eMudhra intermediate CA keys 
(CVE-2026-115557) (GH-160042) (GH-160572)

The ssl module now rejects TLS certificate chains that contain any of a set of
compromised eMudhra intermediate CA keys.  This is an extraordinary measure and
a last line of defense: removing trust is primarily the job of the platform root
store, and the built-in denylist only blocks connections while that update has
not yet reached the OS, a container image, or a bundled trust store in various
Python packages.  Entries are added to the denylist only under a very high
threshold.

The denylist matches on the public key (the SHA-256 digest of the RFC-5280
SubjectPublicKeyInfo), so it also covers the cross-signed certificates that
reuse one of the distrusted keys.

(cherry picked from commit 7dd8b4736a1419750b94a388e6d158be15836fe6)

Co-authored-by: Christian Heimes <[email protected]>
Co-authored-by: Ɓukasz Langa <[email protected]>

files:
A Lib/test/certdata/distrusted.zip
A Misc/NEWS.d/next/Security/2026-10-21-16-55-07.gh-issue-160040.9PjFjC.rst
A Modules/_ssl/distrusted_spki.h
M Lib/test/certdata/make_ssl_certs.py
M Lib/test/test_ssl.py
M Makefile.pre.in
M Modules/_ssl.c
M PCbuild/_ssl.vcxproj
M PCbuild/_ssl.vcxproj.filters

diff --git a/Lib/test/certdata/distrusted.zip b/Lib/test/certdata/distrusted.zip
new file mode 100644
index 000000000000000..83184329a5ab9e0
Binary files /dev/null and b/Lib/test/certdata/distrusted.zip differ
diff --git a/Lib/test/certdata/make_ssl_certs.py 
b/Lib/test/certdata/make_ssl_certs.py
index 94a35a64ab1abe3..9241347e363f387 100644
--- a/Lib/test/certdata/make_ssl_certs.py
+++ b/Lib/test/certdata/make_ssl_certs.py
@@ -5,6 +5,7 @@
 import pprint
 import shutil
 import tempfile
+import zipfile
 from subprocess import *
 
 startdate = "20180829142316Z"
@@ -223,6 +224,107 @@ def print_cert(path):
     pprint.pprint(_ssl._test_decode_cert(path))
 
 
+# The distrusted test material (compromised eMudhra CA certs and a leaf signed
+# by them) lives in a password-protected zip so it doesn't trip security
+# scanners that cannot tell internal test fixtures from production secrets and
+# flag any certificate or private key they find.  It is encrypted, not merely
+# zipped, because such scanners read inside plain archives.  The password is
+# fixed, public, and not a secret.
+DISTRUSTED_ZIP = 'distrusted.zip'
+DISTRUSTED_ZIP_DIR = 'distrusted'
+DISTRUSTED_ZIP_CHOSEN_KNIGHT = 'Brave Sir Robin'
+
+# ASN.1 template for the intermediate's compromised key: secp384r1 scalar 4.
+# openssl derives the public key when the SEC1 structure omits it.
+distrusted_key_template = """
+    asn1 = SEQUENCE:eckey
+    [eckey]
+    version = INTEGER:1
+    priv = FORMAT:HEX,OCTETSTRING:{scalar}
+    params = EXPLICIT:0,OID:secp384r1
+    """
+
+
+def make_distrusted_spki_cert():
+    # leaf signed by the distrusted intermediate, chains to the distrusted root
+    print("creating distrusted-SPKI test cert")
+    # The standard library can read but not write encrypted zip files, so we
+    # need the Info-ZIP "zip" command to repackage the archive.
+    if shutil.which('zip') is None:
+        raise SystemExit(
+            f"the 'zip' command is required to write the encrypted 
{DISTRUSTED_ZIP} "
+            "(the zipfile module cannot create encrypted archives); "
+            "please install Info-ZIP's zip utility"
+        )
+
+    # the root and intermediate are real certs we cannot re-mint; carry them
+    # over from the existing archive
+    pw = DISTRUSTED_ZIP_CHOSEN_KNIGHT.encode()
+    with zipfile.ZipFile(DISTRUSTED_ZIP) as z:
+        root = z.read(DISTRUSTED_ZIP_DIR + '/distrusted_root.pem', pw)
+        intermediate = z.read(DISTRUSTED_ZIP_DIR + 
'/distrusted_intermediate.pem', pw)
+
+    with tempfile.TemporaryDirectory() as workdir:
+        stage = os.path.join(workdir, DISTRUSTED_ZIP_DIR)
+        os.mkdir(stage)
+        req_file = os.path.join(workdir, 'req.cnf')
+        key_file = os.path.join(workdir, 'leaf.key')
+        csr_file = os.path.join(workdir, 'leaf.csr')
+        cert_file = os.path.join(workdir, 'leaf.pem')
+        cakey_conf = os.path.join(workdir, 'cakey.cnf')
+        cakey_der = os.path.join(workdir, 'cakey.der')
+        cakey_file = os.path.join(workdir, 'cakey.pem')
+
+        inter_file = os.path.join(stage, 'distrusted_intermediate.pem')
+        with open(os.path.join(stage, 'distrusted_root.pem'), 'wb') as f:
+            f.write(root)
+        with open(inter_file, 'wb') as f:
+            f.write(intermediate)
+
+        # recreate the intermediate's key (secp384r1 scalar 4) on the fly
+        with open(cakey_conf, 'w') as f:
+            f.write(distrusted_key_template.format(scalar='00' * 47 + '04'))
+        check_call(['openssl', 'asn1parse', '-genconf', cakey_conf,
+                    '-out', cakey_der, '-noout'])
+        check_call(['openssl', 'pkey', '-in', cakey_der,
+                    '-inform', 'DER', '-out', cakey_file])
+
+        req = req_template.format(
+            hostname='localhost',
+            extra_san='',
+            startdate=startdate,
+            enddate=enddate
+        )
+        with open(req_file, 'w') as f:
+            f.write(req)
+        # ECC leaf to match the ECC intermediate
+        check_call(['openssl', 'req', '-new', '-nodes', '-days', '7000',
+                    '-newkey', 'param:secp384r1.pem', '-keyout', key_file,
+                    '-config', req_file, '-out', csr_file])
+        # sign with the distrusted intermediate, not the test CA
+        check_call(['openssl', 'ca', '-config', req_file,
+                    '-extensions', 'req_x509_extensions_full',
+                    '-cert', inter_file, '-keyfile', cakey_file,
+                    '-out', cert_file, '-outdir', 'cadir',
+                    '-policy', 'policy_anything', '-batch', '-infiles', 
csr_file])
+        with open(key_file) as f:
+            key = f.read()
+        with open(cert_file) as f:
+            cert = f.read()
+        # server sends leaf + intermediate, client trusts the root
+        with open(os.path.join(stage, 'distrusted_keycert.pem'), 'w') as f:
+            f.write(key)
+            f.write(cert)
+            f.write(intermediate.decode())
+
+        # repackage the encrypted archive (zipfile cannot write encryption)
+        zippath = os.path.join(here, DISTRUSTED_ZIP)
+        if os.path.exists(zippath):
+            os.remove(zippath)
+        check_call(['zip', '-q', '-X', '-P', DISTRUSTED_ZIP_CHOSEN_KNIGHT, 
'-r',
+                    zippath, DISTRUSTED_ZIP_DIR], cwd=workdir)
+
+
 if __name__ == '__main__':
     os.chdir(here)
     cert, key = make_cert_key('localhost', ext='req_x509_extensions_simple')
@@ -306,6 +408,8 @@ def print_cert(path):
         f.write(key)
         f.write(cert)
 
+    make_distrusted_spki_cert()
+
     unmake_ca()
     print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/utils.py")
     print_cert('keycert.pem')
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 6497d3caa023640..bcb82060e9c27b8 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -15,7 +15,9 @@
 import socket
 import select
 import struct
+import tempfile
 import time
+import zipfile
 import enum
 import gc
 import http.client
@@ -132,6 +134,19 @@ def data_file(*name):
 SIGNED_CERTFILE_ECC = data_file("keycertecc.pem")
 SIGNED_CERTFILE_ECC_HOSTNAME = 'localhost-ecc'
 
+# gh-160040: a leaf signed by a compromised eMudhra intermediate whose public
+# key is on the _ssl distrusted list. The chain to distrusted_root.pem is
+# otherwise valid.
+# The PEMs live in a password-protected zip so the compromised eMudhra certs
+# don't trip security scanners that cannot tell internal test fixtures from
+# production secrets and flag any certificate or private key they find.  It is
+# encrypted, not merely zipped, because such scanners read inside plain 
archives.
+# The password is fixed, public, and not a secret; it only keeps the archive
+# from storing the PEMs in the clear.
+DISTRUSTED_SPKI_ZIP = data_file("distrusted.zip")
+DISTRUSTED_SPKI_CHOSEN_KNIGHT = b"Brave Sir Robin"  # not a secret, see comment
+DISTRUSTED_SPKI_HOSTNAME = "localhost"
+
 # Same certificate as pycacert.pem, but without extra text in file
 SIGNING_CA = data_file("capath", "ceff1710.0")
 # cert with all kinds of subject alt names
@@ -2133,6 +2148,28 @@ def test_unwrap(self):
         c_in.write(s_out.read())
         client.unwrap()
 
+    def test_distrusted_spki(self):
+        # gh-160040: the server chain is otherwise valid, but the eMudhra
+        # intermediate's public key is on the _ssl distrusted list, so
+        # verification rejects it.
+        client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
+        server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+        # the contexts load the PEMs now, so the files are only needed here
+        with tempfile.TemporaryDirectory() as tmpdir:
+            with zipfile.ZipFile(DISTRUSTED_SPKI_ZIP) as z:
+                z.extractall(tmpdir, pwd=DISTRUSTED_SPKI_CHOSEN_KNIGHT)
+            certdir = os.path.join(tmpdir, "distrusted")
+            client_context.load_verify_locations(
+                os.path.join(certdir, "distrusted_root.pem"))
+            server_context.load_cert_chain(
+                os.path.join(certdir, "distrusted_keycert.pem"))
+
+        with self.assertRaises(ssl.SSLCertVerificationError) as cm:
+            connected_bio_pair(client_context, server_context,
+                               DISTRUSTED_SPKI_HOSTNAME)
+        # X509_V_ERR_CERT_REJECTED
+        self.assertEqual(cm.exception.verify_code, 28)
+
     def test_sni_callback_context_released_and_callback_raises(self):
         # Variant of the test below without a HelloRetryRequest: the callback
         # switches the connection to another context, drops the last
diff --git a/Makefile.pre.in b/Makefile.pre.in
index acecc68e7f6e862..c501faadf3585a3 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -2611,7 +2611,7 @@ MODULE__SHA256_DEPS=$(srcdir)/Modules/hashlib.h
 MODULE__SHA3_DEPS=$(srcdir)/Modules/_sha3/sha3.c 
$(srcdir)/Modules/_sha3/sha3.h $(srcdir)/Modules/hashlib.h
 MODULE__SHA512_DEPS=$(srcdir)/Modules/hashlib.h
 MODULE__SOCKET_DEPS=$(srcdir)/Modules/socketmodule.h 
$(srcdir)/Modules/addrinfo.h $(srcdir)/Modules/getaddrinfo.c 
$(srcdir)/Modules/getnameinfo.c
-MODULE__SSL_DEPS=$(srcdir)/Modules/_ssl.h $(srcdir)/Modules/_ssl/cert.c 
$(srcdir)/Modules/_ssl/debughelpers.c $(srcdir)/Modules/_ssl/misc.c 
$(srcdir)/Modules/_ssl_data.h $(srcdir)/Modules/_ssl_data_111.h 
$(srcdir)/Modules/_ssl_data_300.h $(srcdir)/Modules/socketmodule.h
+MODULE__SSL_DEPS=$(srcdir)/Modules/_ssl.h $(srcdir)/Modules/_ssl/cert.c 
$(srcdir)/Modules/_ssl/debughelpers.c $(srcdir)/Modules/_ssl/misc.c 
$(srcdir)/Modules/_ssl/distrusted_spki.h $(srcdir)/Modules/_ssl_data.h 
$(srcdir)/Modules/_ssl_data_111.h $(srcdir)/Modules/_ssl_data_300.h 
$(srcdir)/Modules/socketmodule.h
 MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/testcapi_long.h
 MODULE__SQLITE3_DEPS=$(srcdir)/Modules/_sqlite/connection.h 
$(srcdir)/Modules/_sqlite/cursor.h $(srcdir)/Modules/_sqlite/microprotocols.h 
$(srcdir)/Modules/_sqlite/module.h $(srcdir)/Modules/_sqlite/prepare_protocol.h 
$(srcdir)/Modules/_sqlite/row.h $(srcdir)/Modules/_sqlite/util.h
 
diff --git 
a/Misc/NEWS.d/next/Security/2026-10-21-16-55-07.gh-issue-160040.9PjFjC.rst 
b/Misc/NEWS.d/next/Security/2026-10-21-16-55-07.gh-issue-160040.9PjFjC.rst
new file mode 100644
index 000000000000000..7bcec7f5808cac6
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-10-21-16-55-07.gh-issue-160040.9PjFjC.rst
@@ -0,0 +1,12 @@
+.. cve: CVE-2026-115557
+
+:mod:`ssl` now rejects TLS certificate chains that contain any of a set of
+compromised eMudhra intermediate CA keys.  This is an extraordinary measure and
+a last line of defense: removing trust is primarily the job of the platform 
root
+store, and the built-in denylist only blocks connections while that update has
+not yet reached the OS, a container image, or a bundled trust store in various
+Python packages.  Entries are added to the denylist only under a very high
+threshold.
+The denylist matches on the public key (the SHA-256 digest of the :rfc:`5280`
+``SubjectPublicKeyInfo``), so it also covers the cross-signed certificates that
+reuse one of the distrusted keys.
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 8b5cb38865b6f88..9b22cae298f7ed4 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -52,6 +52,7 @@
 /* Include OpenSSL header files */
 #include "openssl/rsa.h"
 #include "openssl/crypto.h"
+#include "openssl/evp.h"
 #include "openssl/x509.h"
 #include "openssl/x509v3.h"
 #include "openssl/pem.h"
@@ -878,6 +879,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject 
*sock,
                 int (*verify_cb)(int, X509_STORE_CTX *) = NULL;
                 verify_cb = SSL_get_verify_callback(self->ssl);
                 mode |= SSL_VERIFY_POST_HANDSHAKE;
+                /* Keep ctx verify callback (distrusted SPKI check) */
                 SSL_set_verify(self->ssl, mode, verify_cb);
             }
         } else {
@@ -2990,11 +2992,70 @@ static PyType_Spec PySSLSocket_spec = {
  * _SSLContext objects
  */
 
+#include "_ssl/distrusted_spki.h"
+
+/* Returns 1 if the SHA-256 of the cert's SPKI is on the distrusted list,
+   0 if not (okay), -1 on an internal error. */
+static int
+_cert_has_distrusted_spki(X509 *cert)
+{
+    unsigned char *spki = NULL;
+    int spki_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &spki);
+    if (spki_len <= 0 || spki == NULL) {
+        return -1;
+    }
+
+    unsigned char digest[EVP_MAX_MD_SIZE];
+    unsigned int digest_len = 0;
+    int ok = EVP_Digest(spki, (size_t)spki_len, digest, &digest_len,
+                        EVP_sha256(), NULL);
+    OPENSSL_free(spki);
+    assert(sizeof(_distrusted_spki[0]) == SHA256_DIGEST_LENGTH);
+    if (!ok
+        || digest_len != SHA256_DIGEST_LENGTH
+        || sizeof(_distrusted_spki[0]) != SHA256_DIGEST_LENGTH) {
+        return -1;
+    }
+
+    for (size_t i = 0; i < Py_ARRAY_LENGTH(_distrusted_spki); i++) {
+        if (memcmp(digest, _distrusted_spki[i], SHA256_DIGEST_LENGTH) == 0) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+/* Verify callback, called once per cert. Reject distrusted SPKIs. */
+static int
+_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+    /* Don't override an error OpenSSL already reported for this certificate. 
*/
+    if (!preverify_ok) {
+        return preverify_ok;
+    }
+    X509 *cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+    if (cert == NULL) {
+        return preverify_ok;
+    }
+    switch (_cert_has_distrusted_spki(cert)) {
+    case 0:
+        /* okay: not on the distrusted list */
+        return preverify_ok;
+    case 1:
+        /* rejected: public key is on the distrusted list */
+        X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REJECTED);
+        return 0;
+    default:
+        /* internal error */
+        X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_UNSPECIFIED);
+        return 0;
+    }
+}
+
 static int
 _set_verify_mode(PySSLContext *self, enum py_ssl_cert_requirements n)
 {
     int mode;
-    int (*verify_cb)(int, X509_STORE_CTX *) = NULL;
 
     switch(n) {
     case PY_SSL_CERT_NONE:
@@ -3015,9 +3076,7 @@ _set_verify_mode(PySSLContext *self, enum 
py_ssl_cert_requirements n)
     /* bpo-37428: newPySSLSocket() sets SSL_VERIFY_POST_HANDSHAKE flag for
      * server sockets and SSL_set_post_handshake_auth() for client. */
 
-    /* keep current verify cb */
-    verify_cb = SSL_CTX_get_verify_callback(self->ctx);
-    SSL_CTX_set_verify(self->ctx, mode, verify_cb);
+    SSL_CTX_set_verify(self->ctx, mode, _ssl_verify_callback);
     return 0;
 }
 
diff --git a/Modules/_ssl/distrusted_spki.h b/Modules/_ssl/distrusted_spki.h
new file mode 100644
index 000000000000000..bbdb56dcfe671ed
--- /dev/null
+++ b/Modules/_ssl/distrusted_spki.h
@@ -0,0 +1,75 @@
+/* Denylist of distrusted SubjectPublicKeyInfo (SPKI).
+ *
+ * Verification rejects any chain with a cert whose SPKI SHA-256 digest is in
+ * the _distrusted_spki table.  We match the key, not a cert fingerprint, so
+ * cross-signs that reuse the key are blocked too.
+ *
+ * This is an extraordinary measure and last line of defense.  Removing trust 
is
+ * primarily the job of the platform root store. This list only blocks keys 
while
+ * that update is still propagating to the OS, container images, or root CAs
+ * bundled in Python packages.  The threshold for adding an entry is very high.
+  *
+ * See https://github.com/python/cpython/issues/160040 for the eMudhra 
discussion.
+ *
+ * To block another key, add the SHA-256 digest bytes of its SPKI:
+ *
+ *     $ openssl x509 -in cert.pem -noout -pubkey | openssl pkey -pubin 
-outform DER | openssl dgst -sha256 -binary | xxd -i
+ */
+#ifndef Py_SSL_DISTRUSTED_SPKI_H
+#define Py_SSL_DISTRUSTED_SPKI_H
+
+#include "openssl/sha.h"
+
+static const unsigned char _distrusted_spki[][SHA256_DIGEST_LENGTH] = {
+    /* Compromised eMudhra intermediates, 
https://emudhra.we-have-a-problem.com/ */
+    /* CN=EM OV TLS CA - G3B,O=eMudhra BV,C=NL */
+    {
+        0x43, 0xbf, 0xfa, 0x19, 0xd6, 0xef, 0x65, 0x14, 0x51, 0xf6, 0x84, 0x1e,
+        0x01, 0x99, 0x31, 0xe9, 0x6f, 0x6f, 0x2e, 0xae, 0xff, 0x28, 0xab, 0x4b,
+        0x6f, 0x1c, 0xe4, 0x57, 0x6d, 0xe2, 0x71, 0x7b,
+    },
+    /* CN=EM DV TLS CA - G3C,O=eMudhra Inc,C=US */
+    {
+        0x49, 0xdd, 0x35, 0x3d, 0xc2, 0xb9, 0x19, 0xa3, 0x77, 0x06, 0x45, 0x11,
+        0x7d, 0x0e, 0x60, 0xc1, 0x61, 0x15, 0xe7, 0xd1, 0xbc, 0x25, 0x9e, 0xef,
+        0xe7, 0x34, 0xb0, 0x0e, 0xa4, 0x34, 0xfe, 0x5f,
+    },
+    /* CN=EM EV TLS CA - G3C,O=eMudhra Inc,C=US */
+    {
+        0x5c, 0x06, 0x60, 0xa2, 0xb1, 0x64, 0x91, 0x0d, 0x8f, 0xf5, 0x89, 0xc1,
+        0x8e, 0x14, 0x55, 0x2e, 0x9e, 0x0e, 0xc2, 0x37, 0xdc, 0xef, 0xe2, 0xcb,
+        0x73, 0x6d, 0x41, 0xa4, 0x81, 0x1f, 0x81, 0xa0,
+    },
+    /* CN=EM OV TLS CA - G3C,O=eMudhra Inc,C=US */
+    {
+        0x63, 0xec, 0xef, 0xee, 0x43, 0x1d, 0x49, 0x52, 0x3b, 0xc1, 0x13, 0x6c,
+        0x4e, 0x72, 0xd0, 0x20, 0x6a, 0x47, 0x70, 0x86, 0xca, 0xf6, 0x06, 0xcd,
+        0x5c, 0xf0, 0x25, 0x68, 0x6c, 0x10, 0x9c, 0xf8,
+    },
+    /* CN=EM OV CS CA - G3C,O=eMudhra Inc,C=US */
+    {
+        0x92, 0xc0, 0x63, 0xd6, 0x7e, 0x8f, 0x14, 0xdb, 0x71, 0xd2, 0x88, 0xe1,
+        0x12, 0x66, 0xff, 0xda, 0xf6, 0x9c, 0xbf, 0x11, 0x5f, 0x7b, 0xab, 0x14,
+        0xf3, 0xbc, 0x2f, 0x68, 0xd2, 0x5e, 0x0e, 0x30,
+    },
+    /* CN=EM EV TLS CA - G3B,O=eMudhra BV,C=NL */
+    {
+        0xe0, 0x25, 0x4c, 0x7f, 0xcd, 0xc2, 0x65, 0xe2, 0xf0, 0xf8, 0xa4, 0x28,
+        0xda, 0xbb, 0x75, 0xab, 0x4a, 0xe0, 0x39, 0xb4, 0x87, 0x2d, 0x62, 0xf5,
+        0xee, 0x57, 0xf0, 0x87, 0x7d, 0x5a, 0x8a, 0x41,
+    },
+    /* CN=EM DV TLS CA - G3B,O=eMudhra BV,C=NL */
+    {
+        0xeb, 0xed, 0x64, 0x75, 0xc2, 0xc2, 0xd8, 0x0f, 0xcb, 0x19, 0x9f, 0x3f,
+        0xe8, 0xdd, 0x6e, 0x6b, 0x3c, 0xe6, 0x0b, 0x77, 0xeb, 0x15, 0xd4, 0xe4,
+        0x2c, 0x3d, 0xec, 0x0c, 0x6f, 0x5b, 0x51, 0x05,
+    },
+    /* CN=EM OV CS CA - G3B,O=eMudhra BV,C=NL */
+    {
+        0xec, 0x4f, 0xfa, 0x1a, 0xd0, 0xac, 0x88, 0x08, 0x13, 0x14, 0xb7, 0xaa,
+        0xff, 0xef, 0x6a, 0x91, 0xf9, 0x7c, 0xd5, 0x72, 0x91, 0xbb, 0x5b, 0xa6,
+        0x86, 0xc5, 0x41, 0x5f, 0x5e, 0xb4, 0xf6, 0xb6,
+    },
+};
+
+#endif /* !Py_SSL_DISTRUSTED_SPKI_H */
diff --git a/PCbuild/_ssl.vcxproj b/PCbuild/_ssl.vcxproj
index 4907f49b6628fa6..965cc1f3acb762f 100644
--- a/PCbuild/_ssl.vcxproj
+++ b/PCbuild/_ssl.vcxproj
@@ -97,6 +97,9 @@
       
<AdditionalDependencies>ws2_32.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
   </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="..\Modules\_ssl\distrusted_spki.h" />
+  </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\Modules\_ssl.c" />
     <ClCompile Include="$(opensslIncludeDir)\applink.c">
diff --git a/PCbuild/_ssl.vcxproj.filters b/PCbuild/_ssl.vcxproj.filters
index 716a69a41af3517..3df9d70532edc57 100644
--- a/PCbuild/_ssl.vcxproj.filters
+++ b/PCbuild/_ssl.vcxproj.filters
@@ -4,6 +4,9 @@
     <Filter Include="Source Files">
       
<UniqueIdentifier>{695348f7-e9f6-4fe1-bc03-5f08ffc8095b}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Header Files">
+      
<UniqueIdentifier>{7c1bd5da-8912-4107-b6ac-f3930f2d90c7}</UniqueIdentifier>
+    </Filter>
     <Filter Include="Resource Files">
       
<UniqueIdentifier>{1b18a2e6-040d-46c7-a9ac-ac2ec64fb5d6}</UniqueIdentifier>
     </Filter>
@@ -16,6 +19,11 @@
       <Filter>Source Files</Filter>
     </ClCompile>
   </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\Modules\_ssl\distrusted_spki.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\PC\python_nt.rc">
       <Filter>Resource Files</Filter>

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to