Skip to content

Commit baff99e

Browse files
committed
Merge remote-tracking branch 'origin/master' into edge
2 parents 5e86f9e + e135282 commit baff99e

File tree

5 files changed

+113
-66
lines changed

5 files changed

+113
-66
lines changed

mig/install/openssh-MiG-sftp-subsys-template.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ HostKey __MIG_CERTS__/__SFTP_SUBSYS_ADDRESS__/server.key
3838

3939
# IMPORTANT: these are *generated* hardened values based on generateconf
4040
# invocation. Any permanent changes need to be made there.
41+
HostKeyAlgorithms __OPENSSH_HOSTKEYALGOS__
4142
KexAlgorithms __OPENSSH_KEXALGOS__
4243
Ciphers __OPENSSH_CIPHERS__
4344
MACs __OPENSSH_MACS__

mig/server/grid_sftp.py

Lines changed: 65 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@
8787
from mig.shared.base import invisible_path, force_utf8, force_unicode
8888
from mig.shared.conf import get_configuration_object
8989
from mig.shared.defaults import keyword_auto, STRONG_SSH_KEXALGOS, \
90-
STRONG_SSH_CIPHERS, STRONG_SSH_MACS, STRONG_SSH_LEGACY_KEXALGOS, \
91-
STRONG_SSH_LEGACY_MACS
90+
STRONG_SSH_CIPHERS, STRONG_SSH_MACS, LEGACY_SSH_KEXALGOS, \
91+
LEGACY_SSH_CIPHERS, LEGACY_SSH_MACS, FALLBACK_SSH_KEXALGOS, \
92+
FALLBACK_SSH_CIPHERS, FALLBACK_SSH_MACS
9293
from mig.shared.fileio import check_write_access, user_chroot_exceptions, \
9394
read_file
9495
from mig.shared.gdp.all import project_open, project_close, project_log
@@ -1518,59 +1519,85 @@ def accept_client(client, addr, root_dir, host_rsa_key, conf={}):
15181519
default_max_packet_size=max_packet_size)
15191520
# Restrict transport to strong ciphers+kex+digests used in OpenSSH
15201521
transport_security = transport.get_security_options()
1521-
recommended_ciphers = STRONG_SSH_CIPHERS.split(',')
1522+
strong_ciphers = STRONG_SSH_CIPHERS.split(',')
1523+
legacy_ciphers = LEGACY_SSH_CIPHERS.split(',')
1524+
fallback_ciphers = FALLBACK_SSH_CIPHERS.split(',')
15221525
available_ciphers = transport_security.ciphers
1523-
strong_ciphers = [i for i in recommended_ciphers if i in available_ciphers]
1524-
# logger.debug("TLS ciphers available %s, used %s" % (available_ciphers,
1525-
# strong_ciphers))
1526-
if strong_ciphers:
1527-
transport_security.ciphers = strong_ciphers
1526+
best_ciphers = [i for i in strong_ciphers if i in available_ciphers]
1527+
medium_ciphers = [i for i in legacy_ciphers if i in available_ciphers]
1528+
weak_ciphers = [i for i in fallback_ciphers if i in available_ciphers]
1529+
# logger.debug("TLS ciphers available %s: best %s, medium %s, weak %s" %
1530+
# (available_ciphers, best_ciphers, medium_ciphers, weak_ciphers))
1531+
if best_ciphers:
1532+
# logger.debug("Using only strong ciphers: %s" %
1533+
# ', '.join(best_ciphers))
1534+
transport_security.ciphers = best_ciphers
1535+
elif medium_ciphers:
1536+
logger.info("Rely on best available legacy ciphers: %s" %
1537+
', '.join(medium_ciphers))
1538+
transport_security.ciphers = medium_ciphers
1539+
elif weak_ciphers:
1540+
logger.warning("Force best available weak ciphers: %s" %
1541+
', '.join(weak_ciphers))
1542+
transport_security.ciphers = weak_ciphers
15281543
else:
1529-
logger.warning("No strong TLS ciphers available!")
1530-
logger.info("You need a recent paramiko for best security")
1544+
logger.warning("No safe TLS ciphers available!")
1545+
logger.info("You need a modern paramiko for proper security")
15311546
# NOTE: paramiko doesn't yet implement strong modern kex algos - use legacy
15321547
# A number of paramiko tickets indicate plans and interest for adding the
15331548
# strong curve25519-sha256@libssh.org eventually, but progress looks
15341549
# stalled. Until then our best alternative appears to be the legacy
15351550
# diffie-hellman-group-exchange-sha256 fallback, which should be safe as
15361551
# long as the moduli size tuning of e.g. ssh-audit is applied:
15371552
# http://cert.europa.eu/static/WhitePapers/CERT-EU-SWP_16-002_Weaknesses%20in%20Diffie-Hellman%20Key%20v1_0.pdf
1538-
recommended_kex = STRONG_SSH_KEXALGOS.split(',')
1539-
fallback_kex = STRONG_SSH_LEGACY_KEXALGOS.split(',')
1553+
strong_kex = STRONG_SSH_KEXALGOS.split(',')
1554+
legacy_kex = LEGACY_SSH_KEXALGOS.split(',')
1555+
fallback_kex = FALLBACK_SSH_KEXALGOS.split(',')
15401556
available_kex = transport_security.kex
1541-
strong_kex = [i for i in recommended_kex if i in available_kex]
1542-
medium_kex = [i for i in fallback_kex if i in available_kex]
1543-
# logger.debug("TLS kex available %s, used %s (or fallback to %s)" %
1544-
# (available_kex, strong_kex, medium_kex))
1545-
if strong_kex:
1546-
# logger.debug("Using only strong key exchange algorithms: %s" %
1547-
# ', '.join(strong_kex))
1548-
transport_security.kex = strong_kex
1557+
best_kex = [i for i in strong_kex if i in available_kex]
1558+
medium_kex = [i for i in legacy_kex if i in available_kex]
1559+
weak_kex = [i for i in fallback_kex if i in available_kex]
1560+
# logger.debug("TLS kex available %s: best %s, medium %s, weak %s" %
1561+
# (available_kex, best_kex, medium_kex, weak_kex))
1562+
if best_kex:
1563+
# logger.debug("Using only strong kex algorithms: %s" %
1564+
# ', '.join(best_kex))
1565+
transport_security.kex = best_kex
15491566
elif medium_kex:
1550-
# logger.debug("Using only medium strength key exchange algorithms: %s" %
1551-
# ', '.join(medium_kex))
1567+
logger.info("Rely on best available legacy kex algorithms: %s" %
1568+
', '.join(medium_kex))
15521569
transport_security.kex = medium_kex
1570+
elif weak_kex:
1571+
logger.warning("Force best available weak kex algorithms: %s" %
1572+
', '.join(weak_kex))
1573+
transport_security.kex = weak_kex
15531574
else:
1554-
logger.warning("No strong TLS key exchange algorithm available!")
1555-
logger.info("You need a recent paramiko for best security")
1556-
recommended_digests = STRONG_SSH_MACS.split(',')
1557-
fallback_digests = STRONG_SSH_LEGACY_MACS.split(',')
1575+
logger.warning("No safe TLS key exchange algorithm available!")
1576+
logger.info("You need a modern paramiko for proper security")
1577+
strong_digests = STRONG_SSH_MACS.split(',')
1578+
legacy_digests = LEGACY_SSH_MACS.split(',')
1579+
fallback_digests = FALLBACK_SSH_MACS.split(',')
15581580
available_digests = transport_security.digests
1559-
strong_digests = [i for i in recommended_digests if i in available_digests]
1560-
medium_digests = [i for i in fallback_digests if i in available_digests]
1561-
# logger.debug("TLS digests available %s, used %s (or fallback to %s)" %
1562-
# (available_digests, strong_digests, medium_digests))
1563-
if strong_digests:
1564-
# logger.debug("Using only strong message auth codes: %s" %
1565-
# ', '.join(strong_digests))
1566-
transport_security.digests = strong_digests
1581+
best_digests = [i for i in strong_digests if i in available_digests]
1582+
medium_digests = [i for i in legacy_digests if i in available_digests]
1583+
weak_digests = [i for i in fallback_digests if i in available_digests]
1584+
# logger.debug("TLS digests available %s: best %s, medium %s, weak %s" %
1585+
# (available_digests, best_digests, medium_digests, weak_digests))
1586+
if best_digests:
1587+
# logger.debug("Using only strong digests: %s" %
1588+
# ', '.join(best_digests))
1589+
transport_security.digests = best_digests
15671590
elif medium_digests:
1568-
# logger.debug("Using only medium strength message auth codes: %s" %
1569-
# ', '.join(medium_digests))
1591+
logger.info("Rely on best available legacy digests: %s" %
1592+
', '.join(medium_digests))
15701593
transport_security.digests = medium_digests
1594+
elif weak_digests:
1595+
logger.warning("Force best available weak digests: %s" %
1596+
', '.join(weak_digests))
1597+
transport_security.digests = weak_digests
15711598
else:
1572-
logger.warning("No strong TLS digest algorithm available!")
1573-
logger.info("You need paramiko 1.16 or later for best security")
1599+
logger.warning("No safe TLS digest algorithm available!")
1600+
logger.info("You need a modern paramiko for proper security")
15741601

15751602
# Default forces re-keying after every 512MB or same number of packets.
15761603
# We bump that to reduce the slowing effect of those: it's a security

mig/shared/defaults.py

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -451,33 +451,41 @@
451451
# TODO: add curve 'X25519' as first choice once we reach openssl-1.1?
452452
STRONG_TLS_CURVES = "prime256v1:secp384r1:secp521r1"
453453

454-
# Strong SSH key-exchange (Kex), cipher and message auth code (MAC) settings to
455-
# allow in OpenSSH and native Paramiko SFTP daemons (on OpenSSH format).
454+
# SSH hostkey, key-exchange (Kex), cipher and message auth code (MAC) settings
455+
# to allow in OpenSSH and native Paramiko SFTP daemons (on OpenSSH format).
456456
# NOTE: harden in line with Mozilla recommendations for modern versions:
457457
# https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Configuration
458458
# Additional hardening based on https://github.com/arthepsy/ssh-audit
459459
# Please note that the DH GroupX KexAlgorithms require OpenSSH 7.3+, but that
460460
# older versions can relatively safely fall back to instead use the
461461
# diffie-hellman-group-exchange-sha256 as long as the moduli tuning from
462462
# https://infosec.mozilla.org/guidelines/openssh is applied.
463-
# Tested to work with popular recent clients on the main platforms:
463+
# NOTE: DH group14 may also have weak modulus so leave it out.
464+
# Tested to work with popular clients on the main platforms:
464465
# OpenSSH-6.6.1+, LFTP-4.4.13+, FileZilla-3.24+, WinSCP-5.13.3+ and PuTTY-0.70+
465-
# NOTE: CentOS-6 still comes with OpenSSH-5.3 without strong Kex+MAC support
466-
# thus it's necessary to fake legacy ssh version to support any such clients.
467-
STRONG_SSH_KEXALGOS = "curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512"
468-
BEST_SSH_LEGACY_KEXALGOS = "curve25519-sha256@libssh.org"
469-
SAFE_SSH_LEGACY_KEXALGOS = "diffie-hellman-group-exchange-sha256"
470-
STRONG_SSH_LEGACY_KEXALGOS = ",".join([BEST_SSH_LEGACY_KEXALGOS,
471-
SAFE_SSH_LEGACY_KEXALGOS])
466+
# NOTE: CentOS 7 comes with OpenSSH-7.4 with medium Kex+MAC support
467+
# but it's necessary to fake legacy ssh version to support older clients.
468+
# NOTE: ssh-rsa is the deprecated SHA1 based RSA host key exchange. Rely on the
469+
# modern rsa-sha2-(512|256) algorithms instead where available. Unfortunately
470+
# ssh-rsa itself cannot be removed on legacy systems without also removing the
471+
# modern SHA256 versions, too. So keep it last and let client pick best there.
472+
STRONG_SSH_HOSTKEYALGOS = "ssh-ed25519,rsa-sha2-512,rsa-sha2-256"
473+
LEGACY_SSH_HOSTKEYALGOS = ",".join([STRONG_SSH_HOSTKEYALGOS, "ssh-rsa"])
474+
FALLBACK_SSH_HOSTKEYALGOS = LEGACY_SSH_HOSTKEYALGOS
475+
STRONG_SSH_KEXALGOS = "curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group16-sha512"
476+
# NOTE: fall back to relatively safe DH group-exchange-sha256 on old paramiko etc.
477+
LEGACY_SSH_KEXALGOS = ",".join([STRONG_SSH_KEXALGOS,
478+
"diffie-hellman-group-exchange-sha256"])
479+
FALLBACK_SSH_KEXALGOS = LEGACY_SSH_KEXALGOS
472480
STRONG_SSH_CIPHERS = "chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr"
473-
# NOTE: strong cipher support go way back - just reuse
474-
STRONG_SSH_LEGACY_CIPHERS = BEST_SSH_LEGACY_CIPHERS = SAFE_SSH_LEGACY_CIPHERS = STRONG_SSH_CIPHERS
481+
# NOTE: avoid chacha20-poly1305@openssh.com to mitigate Terrapin issue on old servers
482+
LEGACY_SSH_CIPHERS = "aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr"
483+
FALLBACK_SSH_CIPHERS = LEGACY_SSH_CIPHERS
475484
STRONG_SSH_MACS = "hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com"
476-
# NOTE: extend strong MACS with the best possible alternatives on old paramiko
485+
LEGACY_SSH_MACS = STRONG_SSH_MACS
486+
# NOTE: fall back to safe MACS with the best possible alternatives on ancient paramiko
477487
# to avoid falling back to really bad ones
478-
BEST_SSH_LEGACY_MACS = STRONG_SSH_MACS
479-
SAFE_SSH_LEGACY_MACS = "hmac-sha2-512,hmac-sha2-256"
480-
STRONG_SSH_LEGACY_MACS = ",".join([BEST_SSH_LEGACY_MACS, SAFE_SSH_LEGACY_MACS])
488+
FALLBACK_SSH_MACS = ",".join([LEGACY_SSH_MACS, "hmac-sha2-512,hmac-sha2-256"])
481489

482490
# Detect and ban cracking attempts and unauthorized vulnerability scans
483491
# A pattern to match usernames unambiguously identifying cracking attempts

mig/shared/install.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,12 @@
5252

5353
from mig.shared.defaults import default_http_port, default_https_port, \
5454
auth_openid_mig_db, auth_openid_ext_db, MIG_BASE, STRONG_TLS_CIPHERS, \
55-
STRONG_TLS_CURVES, STRONG_SSH_KEXALGOS, STRONG_SSH_LEGACY_KEXALGOS, \
56-
STRONG_SSH_CIPHERS, STRONG_SSH_LEGACY_CIPHERS, STRONG_SSH_MACS, \
57-
STRONG_SSH_LEGACY_MACS, CRACK_USERNAME_REGEX, CRACK_WEB_REGEX, \
58-
keyword_any, keyword_auto
55+
STRONG_TLS_CURVES, STRONG_SSH_HOSTKEYALGOS, STRONG_SSH_KEXALGOS, \
56+
STRONG_SSH_CIPHERS, STRONG_SSH_MACS, LEGACY_SSH_HOSTKEYALGOS, \
57+
LEGACY_SSH_KEXALGOS, LEGACY_SSH_CIPHERS, LEGACY_SSH_MACS, \
58+
FALLBACK_SSH_HOSTKEYALGOS, FALLBACK_SSH_KEXALGOS, FALLBACK_SSH_CIPHERS, \
59+
FALLBACK_SSH_MACS, CRACK_USERNAME_REGEX, CRACK_WEB_REGEX, keyword_any, \
60+
keyword_auto
5961
from mig.shared.compat import ensure_native_string
6062
from mig.shared.fileio import read_file, read_file_lines, write_file, \
6163
write_file_lines
@@ -1134,16 +1136,24 @@ def _generate_confs_prepare(
11341136
user_dict['__APACHE_CURVES__'] = STRONG_TLS_CURVES
11351137

11361138
# We use raw string comparison here which seems to work alright for X.Y.Z
1137-
if user_dict['__OPENSSH_VERSION__'] >= "7.3":
1138-
# Use current strong Kex/Cipher/MAC settings for openssh >=7.3
1139+
if user_dict['__OPENSSH_VERSION__'] >= "8.0":
1140+
# Use current strong HostKey/Kex/Cipher/MAC settings for openssh >=8.0
1141+
user_dict['__OPENSSH_HOSTKEYALGOS__'] = STRONG_SSH_HOSTKEYALGOS
11391142
user_dict['__OPENSSH_KEXALGOS__'] = STRONG_SSH_KEXALGOS
11401143
user_dict['__OPENSSH_CIPHERS__'] = STRONG_SSH_CIPHERS
11411144
user_dict['__OPENSSH_MACS__'] = STRONG_SSH_MACS
1145+
elif user_dict['__OPENSSH_VERSION__'] >= "7.4":
1146+
# Fall back to best legacy HostKey/Kex/Cipher/MAC for openssh >=7.4
1147+
user_dict['__OPENSSH_HOSTKEYALGOS__'] = LEGACY_SSH_HOSTKEYALGOS
1148+
user_dict['__OPENSSH_KEXALGOS__'] = LEGACY_SSH_KEXALGOS
1149+
user_dict['__OPENSSH_CIPHERS__'] = LEGACY_SSH_CIPHERS
1150+
user_dict['__OPENSSH_MACS__'] = LEGACY_SSH_MACS
11421151
else:
1143-
# Fall back to legacy Kex/Cipher/MAC for openssh <7.3
1144-
user_dict['__OPENSSH_KEXALGOS__'] = STRONG_SSH_LEGACY_KEXALGOS
1145-
user_dict['__OPENSSH_CIPHERS__'] = STRONG_SSH_LEGACY_CIPHERS
1146-
user_dict['__OPENSSH_MACS__'] = STRONG_SSH_LEGACY_MACS
1152+
# Fall back to best available HostKey/Kex/Cipher/MAC for openssh <7.4
1153+
user_dict['__OPENSSH_HOSTKEYALGOS__'] = FALLBACK_SSH_HOSTKEYALGOS
1154+
user_dict['__OPENSSH_KEXALGOS__'] = FALLBACK_SSH_KEXALGOS
1155+
user_dict['__OPENSSH_CIPHERS__'] = FALLBACK_SSH_CIPHERS
1156+
user_dict['__OPENSSH_MACS__'] = FALLBACK_SSH_MACS
11471157

11481158
# We know that login with one of these common usernames is a password
11491159
# cracking attempt since our own username format differs.

tests/fixture/confs-stdlocal/sshd_config-MiG-sftp-subsys

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ HostKey /home/mig/certs//server.key
3838

3939
# IMPORTANT: these are *generated* hardened values based on generateconf
4040
# invocation. Any permanent changes need to be made there.
41-
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512
42-
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
41+
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa
42+
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group16-sha512,diffie-hellman-group-exchange-sha256
43+
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
4344
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
4445

4546
# Logging

0 commit comments

Comments
 (0)