Define TLS cipher suite on build time
This commit is contained in:
parent
d20afa1807
commit
73123677e8
228
00294-define-TLS-cipher-suite-on-build-time.patch
Normal file
228
00294-define-TLS-cipher-suite-on-build-time.patch
Normal file
@ -0,0 +1,228 @@
|
||||
diff --git a/Lib/ssl.py b/Lib/ssl.py
|
||||
index 1f3a31a..b54a684 100644
|
||||
--- a/Lib/ssl.py
|
||||
+++ b/Lib/ssl.py
|
||||
@@ -116,6 +116,7 @@ except ImportError:
|
||||
|
||||
|
||||
from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN, HAS_TLSv1_3
|
||||
+from _ssl import _DEFAULT_CIPHERS
|
||||
from _ssl import _OPENSSL_API_VERSION
|
||||
|
||||
|
||||
@@ -174,48 +175,7 @@ else:
|
||||
CHANNEL_BINDING_TYPES = []
|
||||
|
||||
|
||||
-# Disable weak or insecure ciphers by default
|
||||
-# (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL')
|
||||
-# Enable a better set of ciphers by default
|
||||
-# This list has been explicitly chosen to:
|
||||
-# * TLS 1.3 ChaCha20 and AES-GCM cipher suites
|
||||
-# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
|
||||
-# * Prefer ECDHE over DHE for better performance
|
||||
-# * Prefer AEAD over CBC for better performance and security
|
||||
-# * Prefer AES-GCM over ChaCha20 because most platforms have AES-NI
|
||||
-# (ChaCha20 needs OpenSSL 1.1.0 or patched 1.0.2)
|
||||
-# * Prefer any AES-GCM and ChaCha20 over any AES-CBC for better
|
||||
-# performance and security
|
||||
-# * Then Use HIGH cipher suites as a fallback
|
||||
-# * Disable NULL authentication, NULL encryption, 3DES and MD5 MACs
|
||||
-# for security reasons
|
||||
-_DEFAULT_CIPHERS = (
|
||||
- 'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:'
|
||||
- 'TLS13-AES-128-GCM-SHA256:'
|
||||
- 'ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:'
|
||||
- 'ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:'
|
||||
- '!aNULL:!eNULL:!MD5:!3DES'
|
||||
- )
|
||||
-
|
||||
-# Restricted and more secure ciphers for the server side
|
||||
-# This list has been explicitly chosen to:
|
||||
-# * TLS 1.3 ChaCha20 and AES-GCM cipher suites
|
||||
-# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
|
||||
-# * Prefer ECDHE over DHE for better performance
|
||||
-# * Prefer AEAD over CBC for better performance and security
|
||||
-# * Prefer AES-GCM over ChaCha20 because most platforms have AES-NI
|
||||
-# * Prefer any AES-GCM and ChaCha20 over any AES-CBC for better
|
||||
-# performance and security
|
||||
-# * Then Use HIGH cipher suites as a fallback
|
||||
-# * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, RC4, and
|
||||
-# 3DES for security reasons
|
||||
-_RESTRICTED_SERVER_CIPHERS = (
|
||||
- 'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:'
|
||||
- 'TLS13-AES-128-GCM-SHA256:'
|
||||
- 'ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:'
|
||||
- 'ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:'
|
||||
- '!aNULL:!eNULL:!MD5:!DSS:!RC4:!3DES'
|
||||
-)
|
||||
+_RESTRICTED_SERVER_CIPHERS = _DEFAULT_CIPHERS
|
||||
|
||||
|
||||
class CertificateError(ValueError):
|
||||
@@ -389,8 +349,6 @@ class SSLContext(_SSLContext):
|
||||
|
||||
def __new__(cls, protocol=PROTOCOL_TLS, *args, **kwargs):
|
||||
self = _SSLContext.__new__(cls, protocol)
|
||||
- if protocol != _SSLv2_IF_EXISTS:
|
||||
- self.set_ciphers(_DEFAULT_CIPHERS)
|
||||
return self
|
||||
|
||||
def __init__(self, protocol=PROTOCOL_TLS):
|
||||
@@ -505,8 +463,6 @@ def create_default_context(purpose=Purpose.SERVER_AUTH, *, cafile=None,
|
||||
# verify certs and host name in client mode
|
||||
context.verify_mode = CERT_REQUIRED
|
||||
context.check_hostname = True
|
||||
- elif purpose == Purpose.CLIENT_AUTH:
|
||||
- context.set_ciphers(_RESTRICTED_SERVER_CIPHERS)
|
||||
|
||||
if cafile or capath or cadata:
|
||||
context.load_verify_locations(cafile, capath, cadata)
|
||||
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
|
||||
index 54644e1..799100c 100644
|
||||
--- a/Lib/test/test_ssl.py
|
||||
+++ b/Lib/test/test_ssl.py
|
||||
@@ -18,6 +18,7 @@ import asyncore
|
||||
import weakref
|
||||
import platform
|
||||
import functools
|
||||
+import sysconfig
|
||||
try:
|
||||
import ctypes
|
||||
except ImportError:
|
||||
@@ -36,7 +37,7 @@ PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
|
||||
HOST = support.HOST
|
||||
IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL')
|
||||
IS_OPENSSL_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0)
|
||||
-
|
||||
+PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS')
|
||||
|
||||
def data_file(*name):
|
||||
return os.path.join(os.path.dirname(__file__), *name)
|
||||
@@ -889,6 +890,19 @@ class ContextTests(unittest.TestCase):
|
||||
with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
|
||||
ctx.set_ciphers("^$:,;?*'dorothyx")
|
||||
|
||||
+ @unittest.skipUnless(PY_SSL_DEFAULT_CIPHERS == 1,
|
||||
+ "Test applies only to Python default ciphers")
|
||||
+ def test_python_ciphers(self):
|
||||
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
+ ciphers = ctx.get_ciphers()
|
||||
+ for suite in ciphers:
|
||||
+ name = suite['name']
|
||||
+ self.assertNotIn("PSK", name)
|
||||
+ self.assertNotIn("SRP", name)
|
||||
+ self.assertNotIn("MD5", name)
|
||||
+ self.assertNotIn("RC4", name)
|
||||
+ self.assertNotIn("3DES", name)
|
||||
+
|
||||
@unittest.skipIf(ssl.OPENSSL_VERSION_INFO < (1, 0, 2, 0, 0), 'OpenSSL too old')
|
||||
def test_get_ciphers(self):
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
|
||||
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
|
||||
index df8c6a7..e23a569 100644
|
||||
--- a/Modules/_ssl.c
|
||||
+++ b/Modules/_ssl.c
|
||||
@@ -206,6 +206,31 @@ SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *s)
|
||||
|
||||
#endif /* OpenSSL < 1.1.0 or LibreSSL */
|
||||
|
||||
+/* Default cipher suites */
|
||||
+#ifndef PY_SSL_DEFAULT_CIPHERS
|
||||
+#define PY_SSL_DEFAULT_CIPHERS 1
|
||||
+#endif
|
||||
+
|
||||
+#if PY_SSL_DEFAULT_CIPHERS == 0
|
||||
+ #ifndef PY_SSL_DEFAULT_CIPHER_STRING
|
||||
+ #error "Py_SSL_DEFAULT_CIPHERS 0 needs Py_SSL_DEFAULT_CIPHER_STRING"
|
||||
+ #endif
|
||||
+#elif PY_SSL_DEFAULT_CIPHERS == 1
|
||||
+/* Python custom selection of sensible ciper suites
|
||||
+ * DEFAULT: OpenSSL's default cipher list. Since 1.0.2 the list is in sensible order.
|
||||
+ * !aNULL:!eNULL: really no NULL ciphers
|
||||
+ * !MD5:!3DES:!DES:!RC4:!IDEA:!SEED: no weak or broken algorithms on old OpenSSL versions.
|
||||
+ * !aDSS: no authentication with discrete logarithm DSA algorithm
|
||||
+ * !SRP:!PSK: no secure remote password or pre-shared key authentication
|
||||
+ */
|
||||
+ #define PY_SSL_DEFAULT_CIPHER_STRING "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK"
|
||||
+#elif PY_SSL_DEFAULT_CIPHERS == 2
|
||||
+/* Ignored in SSLContext constructor, only used to as _ssl.DEFAULT_CIPHER_STRING */
|
||||
+ #define PY_SSL_DEFAULT_CIPHER_STRING SSL_DEFAULT_CIPHER_LIST
|
||||
+#else
|
||||
+ #error "Unsupported PY_SSL_DEFAULT_CIPHERS"
|
||||
+#endif
|
||||
+
|
||||
|
||||
enum py_ssl_error {
|
||||
/* these mirror ssl.h */
|
||||
@@ -2739,7 +2764,12 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
|
||||
/* A bare minimum cipher list without completely broken cipher suites.
|
||||
* It's far from perfect but gives users a better head start. */
|
||||
if (proto_version != PY_SSL_VERSION_SSL2) {
|
||||
- result = SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!eNULL:!MD5");
|
||||
+#if PY_SSL_DEFAULT_CIPHERS == 2
|
||||
+ /* stick to OpenSSL's default settings */
|
||||
+ result = 1;
|
||||
+#else
|
||||
+ result = SSL_CTX_set_cipher_list(ctx, PY_SSL_DEFAULT_CIPHER_STRING);
|
||||
+#endif
|
||||
} else {
|
||||
/* SSLv2 needs MD5 */
|
||||
result = SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!eNULL");
|
||||
@@ -5279,6 +5309,9 @@ PyInit__ssl(void)
|
||||
(PyObject *)&PySSLSession_Type) != 0)
|
||||
return NULL;
|
||||
|
||||
+ PyModule_AddStringConstant(m, "_DEFAULT_CIPHERS",
|
||||
+ PY_SSL_DEFAULT_CIPHER_STRING);
|
||||
+
|
||||
PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN",
|
||||
PY_SSL_ERROR_ZERO_RETURN);
|
||||
PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ",
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 7ea62f8..4b42393 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -5555,6 +5555,42 @@ if test "$have_getrandom" = yes; then
|
||||
[Define to 1 if the getrandom() function is available])
|
||||
fi
|
||||
|
||||
+# ssl module default cipher suite string
|
||||
+AH_TEMPLATE(PY_SSL_DEFAULT_CIPHERS,
|
||||
+ [Default cipher suites list for ssl module.
|
||||
+ 1: Python's preferred selection, 2: leave OpenSSL defaults untouched, 0: custom string])
|
||||
+AH_TEMPLATE(PY_SSL_DEFAULT_CIPHER_STRING,
|
||||
+ [Cipher suite string for PY_SSL_DEFAULT_CIPHERS=0]
|
||||
+)
|
||||
+AC_MSG_CHECKING(for --with-ssl-default-suites)
|
||||
+AC_ARG_WITH(ssl-default-suites,
|
||||
+ AS_HELP_STRING([--with-ssl-default-suites=@<:@python|openssl|STRING@:>@],
|
||||
+ [Override default cipher suites string,
|
||||
+ python: use Python's preferred selection (default),
|
||||
+ openssl: leave OpenSSL's defaults untouched,
|
||||
+ STRING: use a custom string,
|
||||
+ PROTOCOL_SSLv2 ignores the setting]),
|
||||
+[
|
||||
+AC_MSG_RESULT($withval)
|
||||
+case "$withval" in
|
||||
+ python)
|
||||
+ AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 1)
|
||||
+ ;;
|
||||
+ openssl)
|
||||
+ AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 2)
|
||||
+ ;;
|
||||
+ *)
|
||||
+ AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 0)
|
||||
+ AC_DEFINE_UNQUOTED(PY_SSL_DEFAULT_CIPHER_STRING, "$withval")
|
||||
+ ;;
|
||||
+esac
|
||||
+],
|
||||
+[
|
||||
+AC_MSG_RESULT(python)
|
||||
+AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 1)
|
||||
+])
|
||||
+
|
||||
+
|
||||
# generate output files
|
||||
AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc Misc/python-config.sh)
|
||||
AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix])
|
15
python3.spec
15
python3.spec
@ -14,7 +14,7 @@ URL: https://www.python.org/
|
||||
# WARNING When rebasing to a new Python version,
|
||||
# remember to update the python3-docs package as well
|
||||
Version: %{pybasever}.4
|
||||
Release: 6%{?dist}
|
||||
Release: 7%{?dist}
|
||||
License: Python
|
||||
|
||||
|
||||
@ -354,6 +354,14 @@ Patch274: 00274-fix-arch-names.patch
|
||||
# Reported upstream: https://bugs.python.org/issue30697
|
||||
Patch292: 00292-restore-PyExc_RecursionErrorInst-symbol.patch
|
||||
|
||||
# 00294 #
|
||||
# Define TLS cipher suite on build time depending
|
||||
# on the OpenSSL default cipher suite selection.
|
||||
# Fixed upstream on CPython's 3.7 branch:
|
||||
# https://bugs.python.org/issue31429
|
||||
# See also: https://bugzilla.redhat.com/show_bug.cgi?id=1489816
|
||||
Patch294: 00294-define-TLS-cipher-suite-on-build-time.patch
|
||||
|
||||
# (New patches go here ^^^)
|
||||
#
|
||||
# When adding new patches to "python" and "python3" in Fedora, EL, etc.,
|
||||
@ -598,6 +606,7 @@ sed -r -i s/'_PIP_VERSION = "[0-9.]+"'/'_PIP_VERSION = "%{pip_version}"'/ Lib/en
|
||||
%patch273 -p1
|
||||
%patch274 -p1
|
||||
%patch292 -p1
|
||||
%patch294 -p1
|
||||
|
||||
|
||||
# Remove files that should be generated by the build
|
||||
@ -669,6 +678,7 @@ BuildPython() {
|
||||
--enable-loadable-sqlite-extensions \
|
||||
--with-dtrace \
|
||||
--with-lto \
|
||||
--with-ssl-default-suites=openssl \
|
||||
%if %{with valgrind}
|
||||
--with-valgrind \
|
||||
%endif
|
||||
@ -1462,6 +1472,9 @@ fi
|
||||
# ======================================================
|
||||
|
||||
%changelog
|
||||
* Thu Feb 01 2018 Charalampos Stratakis <cstratak@redhat.com> - 3.6.4-7
|
||||
- Define TLS cipher suite on build time.
|
||||
|
||||
* Tue Jan 23 2018 Charalampos Stratakis <cstratak@redhat.com> - 3.6.4-6
|
||||
- Restore the PyExc_RecursionErrorInst public symbol
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user