diff --git a/core/admin/mailu/internal/nginx.py b/core/admin/mailu/internal/nginx.py index 3f5582cc..5e60cd0c 100644 --- a/core/admin/mailu/internal/nginx.py +++ b/core/admin/mailu/internal/nginx.py @@ -81,6 +81,13 @@ def handle_authentication(headers): raw_password = urllib.parse.unquote(headers["Auth-Pass"]) password = raw_password.encode("iso8859-1").decode("utf8") ip = urllib.parse.unquote(headers["Client-Ip"]) + service_port = int(urllib.parse.unquote(headers["Auth-Port"])) + if service_port == 25: + return { + "Auth-Status": "AUTH not supported", + "Auth-Error-Code": "502 5.5.1", + "Auth-Wait": 0 + } user = models.User.query.get(user_email) if check_credentials(user, password, ip, protocol): return { diff --git a/core/nginx/conf/dhparam.pem b/core/nginx/conf/dhparam.pem index 3cf0fcbc..4f25f663 100644 --- a/core/nginx/conf/dhparam.pem +++ b/core/nginx/conf/dhparam.pem @@ -1,13 +1,11 @@ -----BEGIN DH PARAMETERS----- -MIICCAKCAgEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz -+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a -87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 -YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi -7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD -ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3 -7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32 -nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e -8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx -iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K -zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eZV9q//////////8CAQI= +MIIBiAKCAYEAtQlUSOKGjpdXJ154qmMEa1pEs+9CdSxWiZFkiXBJb0lTafOh8cfF +2IkcWSwzxWwjW4Ad26UQQFh1poGf2QBzVk2vuKCekYzPAs/WqH8VwiXBiWR5R9lh +v/+CkEBYuQOzAhXLN6ZGdPPa2sjdI49rlaIqyLJE4D0TI/VHYmC/vEwqkJUgaGrS +19LhHZimnmouvrnyBPyf00czXlMow0RnmYeHVZ7W5hu7t9TH9o3QAN/GKiFfxFj+ +RkdLM7beQdS0He5YeTaElM5l1YT5d5gHFbOzEQyKHd10ux+bgVcgUeVbBnI1SAIC +w53yc1PkDAiRijSP5j5aWq1djtJPheS13o35HyIf0cHzkNYhKfX5JWPj/cbgdM+C +FL1bnRc8sL5oxmkDoGJhiNZIf4n2WtS8Zu28gUgat6S+vCm/4yavIc/T1g6UiNKE +X41HPbsma/QWUwOL6S+b2qr+7rKqjI5TzVek8vBMellEV4mBvfQU3NDSQ4WvxbTq +ZEOgLPA178nrAgEC -----END DH PARAMETERS----- diff --git a/core/nginx/conf/nginx.conf b/core/nginx/conf/nginx.conf index 5158ca5c..9ce12980 100644 --- a/core/nginx/conf/nginx.conf +++ b/core/nginx/conf/nginx.conf @@ -250,6 +250,7 @@ mail { listen 10025; protocol smtp; smtp_auth plain; + auth_http_header Auth-Port 10025; } # Default IMAP server for the webmail (no encryption, but authentication) @@ -257,6 +258,7 @@ mail { listen 10143; protocol imap; smtp_auth plain; + auth_http_header Auth-Port 10043; } # SMTP is always enabled, to avoid losing emails when TLS is failing @@ -271,6 +273,7 @@ mail { {% endif %} protocol smtp; smtp_auth none; + auth_http_header Auth-Port 25; } # All other protocols are disabled if TLS is failing @@ -283,6 +286,7 @@ mail { {% endif %} protocol imap; imap_auth plain; + auth_http_header Auth-Port 143; } server { @@ -293,6 +297,7 @@ mail { {% endif %} protocol pop3; pop3_auth plain; + auth_http_header Auth-Port 110; } server { @@ -303,6 +308,7 @@ mail { {% endif %} protocol smtp; smtp_auth plain login; + auth_http_header Auth-Port 587; } {% if TLS %} @@ -311,6 +317,7 @@ mail { listen [::]:465 ssl; protocol smtp; smtp_auth plain login; + auth_http_header Auth-Port 465; } server { @@ -318,6 +325,7 @@ mail { listen [::]:993 ssl; protocol imap; imap_auth plain; + auth_http_header Auth-Port 993; } server { @@ -325,6 +333,7 @@ mail { listen [::]:995 ssl; protocol pop3; pop3_auth plain; + auth_http_header Auth-Port 995; } {% endif %} {% endif %} diff --git a/core/nginx/conf/tls.conf b/core/nginx/conf/tls.conf index 5d7ec031..f663bfd2 100644 --- a/core/nginx/conf/tls.conf +++ b/core/nginx/conf/tls.conf @@ -1,5 +1,10 @@ ssl_certificate {{ TLS[0] }}; ssl_certificate_key {{ TLS[1] }}; +{% if TLS_FLAVOR in ['letsencrypt','mail-letsencrypt'] %} +ssl_certificate {{ TLS[2] }}; +ssl_certificate_key {{ TLS[3] }}; +ssl_trusted_certificate /etc/ssl/certs/ca-cert-DST_Root_CA_X3.pem; +{% endif %} ssl_session_timeout 1d; ssl_session_tickets off; ssl_dhparam /conf/dhparam.pem; diff --git a/core/nginx/config.py b/core/nginx/config.py index 6fc9c082..9fa75877 100755 --- a/core/nginx/config.py +++ b/core/nginx/config.py @@ -26,11 +26,11 @@ cert_name = os.getenv("TLS_CERT_FILENAME", default="cert.pem") keypair_name = os.getenv("TLS_KEYPAIR_FILENAME", default="key.pem") args["TLS"] = { "cert": ("/certs/%s" % cert_name, "/certs/%s" % keypair_name), - "letsencrypt": ("/certs/letsencrypt/live/mailu/fullchain.pem", - "/certs/letsencrypt/live/mailu/privkey.pem"), + "letsencrypt": ("/certs/letsencrypt/live/mailu/nginx-chain.pem", + "/certs/letsencrypt/live/mailu/privkey.pem", "/certs/letsencrypt/live/mailu-ecdsa/nginx-chain.pem", "/certs/letsencrypt/live/mailu-ecdsa/privkey.pem"), "mail": ("/certs/%s" % cert_name, "/certs/%s" % keypair_name), - "mail-letsencrypt": ("/certs/letsencrypt/live/mailu/fullchain.pem", - "/certs/letsencrypt/live/mailu/privkey.pem"), + "mail-letsencrypt": ("/certs/letsencrypt/live/mailu/nginx-chain.pem", + "/certs/letsencrypt/live/mailu/privkey.pem", "/certs/letsencrypt/live/mailu-ecdsa/nginx-chain.pem", "/certs/letsencrypt/live/mailu-ecdsa/privkey.pem"), "notls": None }[args["TLS_FLAVOR"]] diff --git a/core/nginx/letsencrypt.py b/core/nginx/letsencrypt.py index b8a0ed2e..1dd2cba4 100755 --- a/core/nginx/letsencrypt.py +++ b/core/nginx/letsencrypt.py @@ -4,7 +4,6 @@ import os import time import subprocess - command = [ "certbot", "-n", "--agree-tos", # non-interactive @@ -14,10 +13,37 @@ command = [ "--cert-name", "mailu", "--preferred-challenges", "http", "--http-01-port", "8008", "--keep-until-expiring", - "--rsa-key-size", "4096", "--config-dir", "/certs/letsencrypt", "--post-hook", "/config.py" ] +command2 = [ + "certbot", + "-n", "--agree-tos", # non-interactive + "-d", os.environ["HOSTNAMES"], + "-m", "{}@{}".format(os.environ["POSTMASTER"], os.environ["DOMAIN"]), + "certonly", "--standalone", + "--cert-name", "mailu-ecdsa", + "--preferred-challenges", "http", "--http-01-port", "8008", + "--keep-until-expiring", + "--key-type", "ecdsa", + "--config-dir", "/certs/letsencrypt", + "--post-hook", "/config.py" +] + +def format_for_nginx(fullchain, output): + """ We may want to strip ISRG Root X1 out + """ + certs = [] + with open(fullchain, 'r') as pem: + cert = '' + for line in pem: + cert += line + if '-----END CERTIFICATE-----' in line: + certs += [cert] + cert = '' + with open(output, 'w') as pem: + for cert in certs[:-1] if len(certs)>2 and os.getenv('LETSENCRYPT_SHORTCHAIN', default="False") else certs: + pem.write(cert) # Wait for nginx to start time.sleep(5) @@ -25,5 +51,7 @@ time.sleep(5) # Run certbot every day while True: subprocess.call(command) + format_for_nginx('/certs/letsencrypt/live/mailu/fullchain.pem', '/certs/letsencrypt/live/mailu/nginx-chain.pem') + subprocess.call(command2) + format_for_nginx('/certs/letsencrypt/live/mailu-ecdsa/fullchain.pem', '/certs/letsencrypt/live/mailu-ecdsa/nginx-chain.pem') time.sleep(86400) - diff --git a/core/postfix/conf/main.cf b/core/postfix/conf/main.cf index 9cd4010e..a35ca16c 100644 --- a/core/postfix/conf/main.cf +++ b/core/postfix/conf/main.cf @@ -33,7 +33,8 @@ relayhost = {{ RELAYHOST }} {% if RELAYUSER %} smtp_sasl_auth_enable = yes smtp_sasl_password_maps = lmdb:/etc/postfix/sasl_passwd -smtp_sasl_security_options = noanonymous +smtp_sasl_security_options = noanonymous, noplaintext +smtp_sasl_tls_security_options = noanonymous {% endif %} # Recipient delimiter for extended addresses @@ -50,7 +51,7 @@ smtpd_authorized_xclient_hosts={{ POD_ADDRESS_RANGE or SUBNET }} # General TLS configuration tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA tls_preempt_cipherlist = yes -tls_ssl_options = NO_COMPRESSION +tls_ssl_options = NO_COMPRESSION, NO_TICKET # By default, outgoing TLS is more flexible because # 1. not all receiving servers will support TLS, @@ -58,7 +59,8 @@ tls_ssl_options = NO_COMPRESSION smtp_tls_security_level = {{ OUTBOUND_TLS_LEVEL|default('may') }} smtp_tls_mandatory_protocols = !SSLv2, !SSLv3 smtp_tls_protocols =!SSLv2,!SSLv3 -smtp_tls_session_cache_database = lmdb:${data_directory}/smtp_scache +smtp_tls_session_cache_database = lmdb:/dev/shm/postfix/smtp_scache +smtpd_tls_session_cache_database = lmdb:/dev/shm/postfix/smtpd_scache ############### # Virtual diff --git a/core/postfix/start.py b/core/postfix/start.py index e0c781b7..df290a3a 100755 --- a/core/postfix/start.py +++ b/core/postfix/start.py @@ -15,6 +15,7 @@ log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING")) def start_podop(): os.setuid(getpwnam('postfix').pw_uid) + os.mkdir('/dev/shm/postfix',mode=0o700) url = "http://" + os.environ["ADMIN_ADDRESS"] + "/internal/postfix/" # TODO: Remove verbosity setting from Podop? run_server(0, "postfix", "/tmp/podop.socket", [ diff --git a/docs/configuration.rst b/docs/configuration.rst index 21effc52..83bc9d90 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -163,6 +163,11 @@ See the `python docs`_ for more information. .. _`python docs`: https://docs.python.org/3.6/library/logging.html#logging-levels +The ``LETSENCRYPT_SHORTCHAIN`` (default: False) setting controls whether we send the ISRG Root X1 certificate in TLS handshakes. This is required for `android handsets older than 7.1.1` but slows down the performance of modern devices. + +.. _`android handsets older than 7.1.1`: https://community.letsencrypt.org/t/production-chain-changes/150739 + + Antivirus settings ------------------ diff --git a/towncrier/newsfragments/1922.enhancement b/towncrier/newsfragments/1922.enhancement new file mode 100644 index 00000000..4b01fa88 --- /dev/null +++ b/towncrier/newsfragments/1922.enhancement @@ -0,0 +1,5 @@ +Add support for ECDSA certificates when letsencrypt is used. This means dropping compatibility for android < 4.1.1 +Add LETSENCRYPT_SHORTCHAIN to your configuration to avoid sending ISRG Root X1 (this will break compatibility with android < 7.1.1) +Disable AUTH command on port 25 +Disable TLS tickets, reconfigure the cache to improve Forward Secrecy +Prevent clear-text credentials from being sent to relays