Blame SOURCES/00294-define-TLS-cipher-suite-on-build-time.patch

036b9c
diff --git a/Lib/ssl.py b/Lib/ssl.py
036b9c
index 1f3a31a..b54a684 100644
036b9c
--- a/Lib/ssl.py
036b9c
+++ b/Lib/ssl.py
036b9c
@@ -116,6 +116,7 @@ except ImportError:
036b9c
 
036b9c
 
036b9c
 from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN, HAS_TLSv1_3
036b9c
+from _ssl import _DEFAULT_CIPHERS
036b9c
 from _ssl import _OPENSSL_API_VERSION
036b9c
 
036b9c
 
036b9c
@@ -174,48 +175,7 @@ else:
036b9c
     CHANNEL_BINDING_TYPES = []
036b9c
 
036b9c
 
036b9c
-# Disable weak or insecure ciphers by default
036b9c
-# (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL')
036b9c
-# Enable a better set of ciphers by default
036b9c
-# This list has been explicitly chosen to:
036b9c
-#   * TLS 1.3 ChaCha20 and AES-GCM cipher suites
036b9c
-#   * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
036b9c
-#   * Prefer ECDHE over DHE for better performance
036b9c
-#   * Prefer AEAD over CBC for better performance and security
036b9c
-#   * Prefer AES-GCM over ChaCha20 because most platforms have AES-NI
036b9c
-#     (ChaCha20 needs OpenSSL 1.1.0 or patched 1.0.2)
036b9c
-#   * Prefer any AES-GCM and ChaCha20 over any AES-CBC for better
036b9c
-#     performance and security
036b9c
-#   * Then Use HIGH cipher suites as a fallback
036b9c
-#   * Disable NULL authentication, NULL encryption, 3DES and MD5 MACs
036b9c
-#     for security reasons
036b9c
-_DEFAULT_CIPHERS = (
036b9c
-    'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:'
036b9c
-    'TLS13-AES-128-GCM-SHA256:'
036b9c
-    'ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:'
036b9c
-    'ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:'
036b9c
-    '!aNULL:!eNULL:!MD5:!3DES'
036b9c
-    )
036b9c
-
036b9c
-# Restricted and more secure ciphers for the server side
036b9c
-# This list has been explicitly chosen to:
036b9c
-#   * TLS 1.3 ChaCha20 and AES-GCM cipher suites
036b9c
-#   * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
036b9c
-#   * Prefer ECDHE over DHE for better performance
036b9c
-#   * Prefer AEAD over CBC for better performance and security
036b9c
-#   * Prefer AES-GCM over ChaCha20 because most platforms have AES-NI
036b9c
-#   * Prefer any AES-GCM and ChaCha20 over any AES-CBC for better
036b9c
-#     performance and security
036b9c
-#   * Then Use HIGH cipher suites as a fallback
036b9c
-#   * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, RC4, and
036b9c
-#     3DES for security reasons
036b9c
-_RESTRICTED_SERVER_CIPHERS = (
036b9c
-    'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:'
036b9c
-    'TLS13-AES-128-GCM-SHA256:'
036b9c
-    'ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:'
036b9c
-    'ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:'
036b9c
-    '!aNULL:!eNULL:!MD5:!DSS:!RC4:!3DES'
036b9c
-)
036b9c
+_RESTRICTED_SERVER_CIPHERS = _DEFAULT_CIPHERS
036b9c
 
036b9c
 
036b9c
 class CertificateError(ValueError):
036b9c
@@ -389,8 +349,6 @@ class SSLContext(_SSLContext):
036b9c
 
036b9c
     def __new__(cls, protocol=PROTOCOL_TLS, *args, **kwargs):
036b9c
         self = _SSLContext.__new__(cls, protocol)
036b9c
-        if protocol != _SSLv2_IF_EXISTS:
036b9c
-            self.set_ciphers(_DEFAULT_CIPHERS)
036b9c
         return self
036b9c
 
036b9c
     def __init__(self, protocol=PROTOCOL_TLS):
036b9c
@@ -505,8 +463,6 @@ def create_default_context(purpose=Purpose.SERVER_AUTH, *, cafile=None,
036b9c
         # verify certs and host name in client mode
036b9c
         context.verify_mode = CERT_REQUIRED
036b9c
         context.check_hostname = True
036b9c
-    elif purpose == Purpose.CLIENT_AUTH:
036b9c
-        context.set_ciphers(_RESTRICTED_SERVER_CIPHERS)
036b9c
 
036b9c
     if cafile or capath or cadata:
036b9c
         context.load_verify_locations(cafile, capath, cadata)
036b9c
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
036b9c
index 9785a59..34a7ec2 100644
036b9c
--- a/Lib/test/test_ssl.py
036b9c
+++ b/Lib/test/test_ssl.py
036b9c
@@ -18,6 +18,7 @@ import asyncore
036b9c
 import weakref
036b9c
 import platform
036b9c
 import functools
036b9c
+import sysconfig
036b9c
 try:
036b9c
     import ctypes
036b9c
 except ImportError:
036b9c
@@ -36,7 +37,7 @@ PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
036b9c
 HOST = support.HOST
036b9c
 IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL')
036b9c
 IS_OPENSSL_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0)
036b9c
-
036b9c
+PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS')
036b9c
 
036b9c
 def data_file(*name):
036b9c
     return os.path.join(os.path.dirname(__file__), *name)
036b9c
@@ -889,6 +890,19 @@ class ContextTests(unittest.TestCase):
036b9c
         with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
036b9c
             ctx.set_ciphers("^$:,;?*'dorothyx")
036b9c
 
036b9c
+    @unittest.skipUnless(PY_SSL_DEFAULT_CIPHERS == 1,
036b9c
+                         "Test applies only to Python default ciphers")
036b9c
+    def test_python_ciphers(self):
036b9c
+        ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
036b9c
+        ciphers = ctx.get_ciphers()
036b9c
+        for suite in ciphers:
036b9c
+            name = suite['name']
036b9c
+            self.assertNotIn("PSK", name)
036b9c
+            self.assertNotIn("SRP", name)
036b9c
+            self.assertNotIn("MD5", name)
036b9c
+            self.assertNotIn("RC4", name)
036b9c
+            self.assertNotIn("3DES", name)
036b9c
+
036b9c
     @unittest.skipIf(ssl.OPENSSL_VERSION_INFO < (1, 0, 2, 0, 0), 'OpenSSL too old')
036b9c
     def test_get_ciphers(self):
036b9c
         ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
036b9c
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
036b9c
index 5e007da..130f006 100644
036b9c
--- a/Modules/_ssl.c
036b9c
+++ b/Modules/_ssl.c
036b9c
@@ -237,6 +237,31 @@ SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *s)
036b9c
 
036b9c
 #endif /* OpenSSL < 1.1.0 or LibreSSL < 2.7.0 */
036b9c
 
036b9c
+/* Default cipher suites */
036b9c
+#ifndef PY_SSL_DEFAULT_CIPHERS
036b9c
+#define PY_SSL_DEFAULT_CIPHERS 1
036b9c
+#endif
036b9c
+
036b9c
+#if PY_SSL_DEFAULT_CIPHERS == 0
036b9c
+  #ifndef PY_SSL_DEFAULT_CIPHER_STRING
036b9c
+     #error "Py_SSL_DEFAULT_CIPHERS 0 needs Py_SSL_DEFAULT_CIPHER_STRING"
036b9c
+  #endif
036b9c
+#elif PY_SSL_DEFAULT_CIPHERS == 1
036b9c
+/* Python custom selection of sensible ciper suites
036b9c
+ * DEFAULT: OpenSSL's default cipher list. Since 1.0.2 the list is in sensible order.
036b9c
+ * !aNULL:!eNULL: really no NULL ciphers
036b9c
+ * !MD5:!3DES:!DES:!RC4:!IDEA:!SEED: no weak or broken algorithms on old OpenSSL versions.
036b9c
+ * !aDSS: no authentication with discrete logarithm DSA algorithm
036b9c
+ * !SRP:!PSK: no secure remote password or pre-shared key authentication
036b9c
+ */
036b9c
+  #define PY_SSL_DEFAULT_CIPHER_STRING "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK"
036b9c
+#elif PY_SSL_DEFAULT_CIPHERS == 2
036b9c
+/* Ignored in SSLContext constructor, only used to as _ssl.DEFAULT_CIPHER_STRING */
036b9c
+  #define PY_SSL_DEFAULT_CIPHER_STRING SSL_DEFAULT_CIPHER_LIST
036b9c
+#else
036b9c
+  #error "Unsupported PY_SSL_DEFAULT_CIPHERS"
036b9c
+#endif
036b9c
+
036b9c
 
036b9c
 enum py_ssl_error {
036b9c
     /* these mirror ssl.h */
036b9c
@@ -2803,7 +2828,12 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
036b9c
     /* A bare minimum cipher list without completely broken cipher suites.
036b9c
      * It's far from perfect but gives users a better head start. */
036b9c
     if (proto_version != PY_SSL_VERSION_SSL2) {
036b9c
-        result = SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!eNULL:!MD5");
036b9c
+#if PY_SSL_DEFAULT_CIPHERS == 2
036b9c
+        /* stick to OpenSSL's default settings */
036b9c
+        result = 1;
036b9c
+#else
036b9c
+        result = SSL_CTX_set_cipher_list(ctx, PY_SSL_DEFAULT_CIPHER_STRING);
036b9c
+#endif
036b9c
     } else {
036b9c
         /* SSLv2 needs MD5 */
036b9c
         result = SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!eNULL");
036b9c
@@ -5343,6 +5373,9 @@ PyInit__ssl(void)
036b9c
                              (PyObject *)&PySSLSession_Type) != 0)
036b9c
         return NULL;
036b9c
 
036b9c
+    PyModule_AddStringConstant(m, "_DEFAULT_CIPHERS",
036b9c
+                               PY_SSL_DEFAULT_CIPHER_STRING);
036b9c
+
036b9c
     PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN",
036b9c
                             PY_SSL_ERROR_ZERO_RETURN);
036b9c
     PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ",
036b9c
diff --git a/configure.ac b/configure.ac
036b9c
index 3703701..2eff514 100644
036b9c
--- a/configure.ac
036b9c
+++ b/configure.ac
036b9c
@@ -5598,6 +5598,42 @@ if test "$have_getrandom" = yes; then
036b9c
               [Define to 1 if the getrandom() function is available])
036b9c
 fi
036b9c
 
036b9c
+# ssl module default cipher suite string
036b9c
+AH_TEMPLATE(PY_SSL_DEFAULT_CIPHERS,
036b9c
+  [Default cipher suites list for ssl module.
036b9c
+   1: Python's preferred selection, 2: leave OpenSSL defaults untouched, 0: custom string])
036b9c
+AH_TEMPLATE(PY_SSL_DEFAULT_CIPHER_STRING,
036b9c
+  [Cipher suite string for PY_SSL_DEFAULT_CIPHERS=0]
036b9c
+)
036b9c
+AC_MSG_CHECKING(for --with-ssl-default-suites)
036b9c
+AC_ARG_WITH(ssl-default-suites,
036b9c
+            AS_HELP_STRING([--with-ssl-default-suites=@<:@python|openssl|STRING@:>@],
036b9c
+                           [Override default cipher suites string,
036b9c
+                            python: use Python's preferred selection (default),
036b9c
+                            openssl: leave OpenSSL's defaults untouched,
036b9c
+                            STRING: use a custom string,
036b9c
+                            PROTOCOL_SSLv2 ignores the setting]),
036b9c
+[
036b9c
+AC_MSG_RESULT($withval)
036b9c
+case "$withval" in
036b9c
+    python)
036b9c
+        AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 1)
036b9c
+        ;;
036b9c
+    openssl)
036b9c
+        AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 2)
036b9c
+        ;;
036b9c
+    *)
036b9c
+        AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 0)
036b9c
+        AC_DEFINE_UNQUOTED(PY_SSL_DEFAULT_CIPHER_STRING, "$withval")
036b9c
+        ;;
036b9c
+esac
036b9c
+],
036b9c
+[
036b9c
+AC_MSG_RESULT(python)
036b9c
+AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 1)
036b9c
+])
036b9c
+
036b9c
+
036b9c
 # generate output files
036b9c
 AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc Misc/python-config.sh)
036b9c
 AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix])