Skip to content

chore: Drop support for deprecated TLS versions#2945

Merged
polarathene merged 5 commits intodocker-mailserver:masterfrom
polarathene:chore/drop-support-for-deprecated-tls-versions
Dec 23, 2022
Merged

chore: Drop support for deprecated TLS versions#2945
polarathene merged 5 commits intodocker-mailserver:masterfrom
polarathene:chore/drop-support-for-deprecated-tls-versions

Conversation

@polarathene
Copy link
Copy Markdown
Member

@polarathene polarathene commented Dec 22, 2022

Description

As per the relevant deprecation notice (since July), TLS 1.0 and 1.1 have finally been deprecated by RFC 8896 (Mar 2021).

Support has been dropped from DMS. TLS 1.2 is the new minimum version supported.

Closes #2679


Removes support of the following cipher suites:

Impact:

  • There are no more supported cipher suites from TLS 1.0 or 1.1 after this.
  • Raising the minimum version of TLS supported is now 1.2, we can also remove the workaround to lower the OpenSSL security level (was required for Dovecot with TLS_LEVEL=intermediate).
  • Postfix main.cf adds an additional exclude pattern (SHA1) to prevent these cipher suites from being offered on port 25 (uses Postfix medium cipher list minus excluded cipher suites). This was required as the cipher suites are still part of TLS 1.2, but are no longer being supported due to the MAC being SHA1 (see cipher suite links for more details).
  • These changes should be acceptable. TLS 1.2 has been around since 2008 - and from my own research since contributing to this project in 2020, should be broadly available with mail servers now. Users that require these removed cipher suites should be niche if any, and may add them back via user-patches.sh.

Type of change

  • Improvement (non-breaking change that does improve existing functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected) - Potentially, risk should be low.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • If necessary I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

@polarathene polarathene added service/dovecot service/postfix area/security area/tests kind/improvement Improve an existing feature, configuration file or the documentation labels Dec 22, 2022
@polarathene polarathene added this to the v12.0.0 milestone Dec 22, 2022
@polarathene polarathene self-assigned this Dec 22, 2022
Copy link
Copy Markdown
Member

@georglauterbach georglauterbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍🏼

@casperklein
Copy link
Copy Markdown
Member

casperklein commented Dec 23, 2022

For those who are interested, here is a bash one-liner to check mail.log, if TLSv1 / TLSv1.1 is still used:

while read line; do dig -x $line +short; done < <(grep -aP 'TLSv1(\.1)? ' mail.log | grep -Po '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sort | uniq)

or to check all mail logs, including gziped ones:

while read line; do dig -x $line +short; done < <(zgrep -aP 'TLSv1(\.1)? ' mail.log* | grep -Po '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sort | uniq)

This gives an output like this:

internet.nl.
pancake.scanf.shodan.io.
gravy.scanf.shodan.io.
biscuit.scanf.shodan.io.
eggs.scanf.shodan.io.
waffles.scanf.shodan.io.
green.census.shodan.io.
bacon.scanf.shodan.io.

Shodan & Internet.nl are internet scanner and can be ignored.

Removes support of the following cipher suites that are only valid for TLS 1.0 + 1.1:

- `ECDHE-ECDSA-AES128-SHA`
- `ECDHE-RSA-AES128-SHA`
- `ECDHE-ECDSA-AES256-SHA`
- `ECDHE-RSA-AES256-SHA`
- `DHE-RSA-AES128-SHA`
- `DHE-RSA-AES256-SHA`
These are now the same as modern settings.
No longer required now that outdated TLS versions have been dropped.
The removed SHA1 cipher suites are still supported in TLS 1.2, thus they've been excluded for port 25 via the `SHA1` exclusion pattern in `main.cf`.
@polarathene polarathene force-pushed the chore/drop-support-for-deprecated-tls-versions branch from e3a3afe to 1bc5c5f Compare December 23, 2022 12:58
@polarathene polarathene merged commit 4dda5f8 into docker-mailserver:master Dec 23, 2022
miles170 added a commit to miles170/docker-mailserver that referenced this pull request Apr 17, 2023
miles170 added a commit to miles170/docker-mailserver that referenced this pull request May 11, 2023
miles170 added a commit to miles170/docker-mailserver that referenced this pull request Nov 27, 2023
miles170 added a commit to miles170/docker-mailserver that referenced this pull request Nov 30, 2023
miles170 added a commit to miles170/docker-mailserver that referenced this pull request Jan 21, 2024
miles170 added a commit to miles170/docker-mailserver that referenced this pull request Jan 24, 2024
@polarathene
Copy link
Copy Markdown
Member Author

@miles170 I see that you're reverting the changes from this PR while rebasing to new releases with a commit reference adding the noise above.

I'd rather hear about your need for that so we're better aware of it and can support the functionality without you needing to carry the patch.

  • I can see that your last rebase was prior to our Debian 12 upgrade (so rebased to the last published/tagged release of DMS). The next rebase you do will be with OpenSSL 3.0 and I think the config change for security level will differ slightly, probably need to set level 0.
  • Are you still only needing to support TLS 1.2 with the ciphers you're adding back? Is there one you need in particular? These should still be available without enabling TLS 1.0/1.1, just double checking since you did explicitly enable those again.

Our "intermediate" security level I don't think I've altered like the "modern" level when I did an audit due to reviewer concerns at the time. I have considered dropping the "intermediate" level in future but I'm still open towards replacing it with a "legacy" security level for those preferring broader compatibility over what is considered secure (the dropped ciphers from this PR have some security concerns, but mostly regarding CBC prior to TLS 1.2).

@miles170
Copy link
Copy Markdown

miles170 commented Feb 17, 2024

@miles170 I see that you're reverting the changes from this PR while rebasing to new releases with a commit reference adding the noise above.

I'd rather hear about your need for that so we're better aware of it and can support the functionality without you needing to carry the patch.

  • I can see that your last rebase was prior to our Debian 12 upgrade (so rebased to the last published/tagged release of DMS). The next rebase you do will be with OpenSSL 3.0 and I think the config change for security level will differ slightly, probably need to set level 0.
  • Are you still only needing to support TLS 1.2 with the ciphers you're adding back? Is there one you need in particular? These should still be available without enabling TLS 1.0/1.1, just double checking since you did explicitly enable those again.

Our "intermediate" security level I don't think I've altered like the "modern" level when I did an audit due to reviewer concerns at the time. I have considered dropping the "intermediate" level in future but I'm still open towards replacing it with a "legacy" security level for those preferring broader compatibility over what is considered secure (the dropped ciphers from this PR have some security concerns, but mostly regarding CBC prior to TLS 1.2).

Sorry for the noise. I'm currently facing an issue where some of our legacy Windows 7 systems are unable to use TLSv1.2 and can only use TLSv1 (we cannot update the Microsoft-provided packages).

@polarathene
Copy link
Copy Markdown
Member Author

Sorry for the noise.

No worries, was just concerned about the why :)

I'm currently facing an issue where some of our legacy Windows 7 systems are unable to use TLSv1.2 and can only use TLSv1

Good to know thanks 👍

So to confirm this is for internal systems you manage where you're more concerned about connections to DMS on ports that are enforcing a secure connection, not third-party inbound/outbound traffic on port 25?

Just trying to understand the remaining scenarios where reducing the security of TLS is still necessary.

  • If we no longer offer a intermediate catered cipher list and you're still able to establish connections to DMS by a similar legacy opt-in feature, would that be ok?
  • I don't think TLS 1.0/1.1 had much left that was considered secure beyond the semi-ok cipher suites dropped in this PR so I assume that's an acceptable tradeoff for you.

@miles170
Copy link
Copy Markdown

miles170 commented Feb 17, 2024

So to confirm this is for internal systems you manage where you're more concerned about connections to DMS on ports that are enforcing a secure connection, not third-party inbound/outbound traffic on port 25?

Yes, and legacy internal systems need to communicate with ports 587 and 993 via TLSv1.

If we no longer offer a intermediate catered cipher list and you're still able to establish connections to DMS by a similar legacy opt-in feature, would that be ok?

The legacy opt-in feature is okay, thank you.

I don't think TLS 1.0/1.1 had much left that was considered secure beyond the semi-ok cipher suites dropped in this PR so I assume that's an acceptable tradeoff for you.

This tradeoff is very reasonable and acceptable, but it is not clear whether the semi-ok cipher suites can be used on Windows 7.

@polarathene
Copy link
Copy Markdown
Member Author

polarathene commented Feb 17, 2024

UPDATE: If you're here for the workaround to enable TLSv1 / TLSv1.1 in DMS v14 or newer, jump straight down to the last section of this comment and look at the example compose.yaml 👍


Yes, and legacy internal systems need to communicate with ports 587 and 993 via TLSv1.
The legacy opt-in feature is okay, thank you.

Great!

This tradeoff is very reasonable and acceptable, but it is not clear whether the semi-ok cipher suites can be used on Windows 7.

Oh you're fine! 👍

The "semi-ok" cipher suites I was referring to are listed at the top of this PR and part of what you reverted. With our intermediate cipher list and smtpd_tls_exclude_ciphers I think they were the only ones that may have been available for TLS 1.0/1.1 to connect with.

They should still be available if the other maintainers approve of the proposal. If anything, less secure ciphers may become available which would be the tradeoff, but as it's internal traffic only connecting this that shouldn't be an issue.

Alternative workaround - user-patches.sh

EDIT: While the below two examples should work, I realize that due to our change detection service (check-for-changes.sh), any config changes that trigger the TLS settings to be applied again (certificates renewed), or the relay host config if enabled would undo the changes from the below approach 😩 (on the bright-side, it helps towards getting support back into DMS 👍 )

This should be equivalent to the patch you're carrying, but for our user-patches.sh:

#!/bin/bash

function _enable_tls_v1() {
    local POSTFIX_CONFIG_MAIN='/etc/postfix/main.cf'
    local DOVECOT_CONFIG_SSL='/etc/dovecot/conf.d/10-ssl.conf'

    local TLS_CIPHERS_ALLOW='ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA'
    local TLS_PROTOCOL_IGNORE='!SSLv2,!SSLv3'
    local TLS_PROTOCOL_MINIMUM='TLSv1'

    # Postfix configuration
    sed -i -r \
        -e "s|^(smtpd?_tls_mandatory_protocols =).*|\1 ${TLS_PROTOCOL_IGNORE}|" \
        -e "s|^(smtpd?_tls_protocols =).*|\1 ${TLS_PROTOCOL_IGNORE}|" \
        -e "s|^(tls_high_cipherlist =).*|\1 ${TLS_CIPHERS_ALLOW}|" \
        "${POSTFIX_CONFIG_MAIN}"

    # Dovecot configuration
    sed -i -r \
        -e "s|^(ssl_min_protocol =).*|\1 ${TLS_PROTOCOL_MINIMUM}|" \
        -e "s|^(ssl_cipher_list =).*|\1 ${TLS_CIPHERS_ALLOW}|" \
        "${DOVECOT_CONFIG_SSL}"

    # Lowers the minimum acceptable TLS version connection to `TLSv1` (from Debian upstream `TLSv1.2`)
    # Lowers Security Level to `1` (from Debian upstream `2`, openssl release defaults to `1`)
    # https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_security_level.html
    # https://wiki.debian.org/ContinuousIntegration/TriagingTips/openssl-1.1.1
    # https://dovecot.org/pipermail/dovecot/2020-October/120225.html
    # WARNING: This applies to all processes that use openssl and respect these settings.
    sedfile -i -r --follow-symlinks \
        -e 's|^(MinProtocol).*|\1 = TLSv1|' \
        -e 's|^(CipherString).*|\1 = DEFAULT@SECLEVEL=1|' \
        /usr/lib/ssl/openssl.cnf
}

# Run the function above:
_enable_tls_v1

Alternative script

If we ignore the TLS cipher suite:

  • It should be as simple as switching to the default Postfix medium list instead of our custom list for high (that we configured mandatory to use which is for a encrypt security level on ports 587/465 and any configured relay host).
  • Likewise disabling the configured Dovecot customized cipher list to use it's default. Assuming these are still relaxed enough to be compatible with TLS 1.0/1.1.
#!/bin/bash

function _enable_tls_v1() {
    # Postfix configuration (main.cf)
    # - From DMS v14 (Postfix 3.6) you could swap `!SSLv2,!SSLv3` for `>=TLSv1`
    # - `smtp_` for outbound connections (25), `smtpd_` for inbound (25),
    # - `mandatory` applies to authenticated ports (587,465)
    postconf 'smtp_tls_protocols = !SSLv2,!SSLv3'
    postconf 'smtp_tls_mandatory_protocols = !SSLv2,!SSLv3'
    postconf 'smtpd_tls_protocols = !SSLv2,!SSLv3'
    postconf 'smtpd_tls_mandatory_protocols = !SSLv2,!SSLv3'
    # NOTE: DMS does not appear to set the equivalent for `smtp_` if a relay host is configured
    postconf 'smtpd_tls_mandatory_ciphers = medium'

    # Remove all excluded ciphers (doesn't apply to outbound connections, DMS does not configure that):
    # https://github.com/docker-mailserver/docker-mailserver/blob/a815bf5ab44388baecb597a0b83f71872a2d34bc/target/postfix/main.cf#L47
    postconf -X smtpd_tls_exclude_ciphers

    # Dovecot configuration
    # Use default Dovecot setting for ssl_cipher_list by commenting the line out:
    # https://doc.dovecot.org/configuration_manual/dovecot_ssl_configuration/#ssl-security-settings
    sed -i -r \
        -e "s|^(ssl_min_protocol =).*|\1 TLSv1|" \
        -e "s|^(ssl_cipher_list =).*|#\1|" \
        /etc/dovecot/conf.d/10-ssl.conf

    # Lowers the minimum acceptable TLS version connection to `TLSv1` (from Debian upstream `TLSv1.2`)
    # DMS v14 (OpenSSL 3.0) may require `DEFAULT@SECLEVEL=0`
    sed -i -r \
        -e 's|^(MinProtocol).*|\1 = TLSv1|' \
        -e 's|^(CipherString).*|\1 = DEFAULT@SECLEVEL=1|' \
        /etc/ssl/openssl.cnf
}

# Run the function above:
_enable_tls_v1

Instead of the sed call for Postfix, used postconf command, if you still want DMS to keep TLS 1.2+ for outbound connections (if they're not going to those Windows systems) you can remove the smtp_ lines and just keep the smtpd_ ones. Likewise if you want to keep the prior smtpd_tls_exclude_ciphers we had without the added SHA1, just adjust the line to assign the previous value like the earlier postconf lines show.


UPDATE: DMS v12 (April 2023) had OpenSSL 1.1.1n (March 2022) with this content in /etc/ssl/openssl.cnf:

openssl_conf = default_conf

# ...

[default_conf]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
MinProtocol = TLSv1.2
CipherString = DEFAULT@SECLEVEL=2

This content remained up until DMS v13.3.1 (Jan 2024) with OpenSSL 1.1.1w (Sep 2023). Up until this point the sed modification to lower these values was valid.

From DMS v14 (June 2024), the base image moved from Debian 11 Bullseye to Debian 12 Bookworm. This raised the version of OpenSSL to 3.x where this additional config is no longer present.

DMS v14 or newer

Here is a compose.yaml example you can adopt with an updated user-patches.sh from earlier. If you have any issues this compose.yaml should provide a full copy/paste example you use to verify the functionality is working, and then adapt to your real compose.yaml.

compose.yaml:

name: example

services:
  dms:
    image: mailserver/docker-mailserver:15
    hostname: mail.example.test
    environment:
      - SSL_TYPE=manual
      - SSL_KEY_PATH=/tmp/tls/key.pem
      - SSL_CERT_PATH=/tmp/tls/cert.pem
    configs:
      # These two files will patch DMS to allow TLSv1:
      - source: tls-legacy
        target: /tmp/docker-mailserver/user-patches.sh
      - source: openssl-config-insecure
        target: /tmp/openssl.insecure.cnf
      # Extra config bundled into the `compose.yaml` to ease testing:
      - source: dms-accounts
        target: /tmp/docker-mailserver/postfix-accounts.cf
      - source: tls-cert
        target: /tmp/tls/cert.pem
      - source: tls-key
        target: /tmp/tls/key.pem
      # Optional - Allows clients in the container to verify cert trust with the CA that signed it:
      - source: tls-ca-cert
        target: /tmp/tls/ca-cert.pem

  # Optional - Verify DMS now runs with lower TLSv1 ciphers by running:
  # docker compose run --rm -it testssl
  testssl:
    scale: 0 # This avoids running the container during `docker compose up`
    image: ghcr.io/testssl/testssl.sh:3.2
    # Config for TestSSL.sh to trust the locally generated cert:
    environment:
      ADDTL_CA_FILES: "/tmp/tls/ca-cert.pem"
    configs:
      - source: tls-ca-cert
        target: /tmp/tls/ca-cert.pem
      # Simplifies testing multiple ports on DMS:
      - source: testssl-config
        target: /tmp/testssl.txt
    # Set to the UID/GID of the working_dir
    # Optionally mount your own volume if you need to inspect the JSON files stored here:
    user: "0:0"
    working_dir: /output
    # testssl.sh options to run tests with:
    command: >-
      --quiet
      --file '/tmp/testssl.txt'
      --mode parallel
      --preference
      --overwrite

configs:
  tls-legacy:
    content: |
      #!/bin/bash

      function _enable_tls_v1() {
        # Postfix configuration (main.cf)
        # - `smtp_` for outbound connections (25), `smtpd_` for inbound (25),
        # - `mandatory` variant applies to the authenticated ports (587,465)
        postconf 'smtp_tls_protocols = >=TLSv1'
        postconf 'smtp_tls_mandatory_protocols = >=TLSv1'
        postconf 'smtpd_tls_protocols = >=TLSv1'
        postconf 'smtpd_tls_mandatory_protocols = >=TLSv1'
        # NOTE: DMS does not appear to set the equivalent for `smtp_` (if a relay host is configured)
        postconf 'smtpd_tls_mandatory_ciphers = medium'

        # Remove all excluded ciphers (doesn't apply to outbound connections, DMS does not configure that):
        # https://github.com/docker-mailserver/docker-mailserver/blob/a815bf5ab44388baecb597a0b83f71872a2d34bc/target/postfix/main.cf#L47
        postconf -X smtpd_tls_exclude_ciphers

        # Dovecot configuration:
        # - Lower the min protocol to TLS v1.0
        # - Revert to the default value of the Dovecot setting `ssl_cipher_list` by commenting the config line:
        #   https://doc.dovecot.org/configuration_manual/dovecot_ssl_configuration/#ssl-security-settings
        sed -i -r \
          -e "s|^(ssl_min_protocol =).*|\1 TLSv1|" \
          -e "s|^(ssl_cipher_list =).*|#\1|" \
          /etc/dovecot/conf.d/10-ssl.conf

        # Lower the minimum acceptable TLS version connection to `TLSv1` (from upstream default of `TLSv1.2`):
        # NOTE: This only appears relevant to Dovecot, Postfix can lower to TLSv1 only for itself via OpenSSL API?
        # Set `openssl_conf = default_conf` to reference the new sections we append to the config.
        # NOTE: In Debian 11 with OpenSSL 1.1.1, this content was previously appended to the file (but for TLSv1.2 + SECLEVEL=2).
        sed -i -r 's|^(openssl_conf).*|\1 = default_conf|' /etc/ssl/openssl.cnf
        cat /tmp/openssl.insecure.cnf >> /etc/ssl/openssl.cnf
      }

      # Run the function above, but not if it's been patched already:
      if [[ ! $(grep -q 'openssl_conf = default_conf' /etc/ssl/openssl.cnf) ]]; then
        _enable_tls_v1
      fi

  openssl-config-insecure:
   content: |
     [default_conf]
     ssl_conf = ssl_sect

     [ssl_sect]
     system_default = system_default_sect

     [system_default_sect]
     MinProtocol = TLSv1
     # `SECLEVEL=0` is required for Dovecot to accept TLSv1
     CipherString = DEFAULT@SECLEVEL=0

  # Pre-provisioned account for local reproduction use:
  # NOTE: `$` is escaped by repeating it to avoid the Docker Compose ENV interpolation feature
  # Password is `secret`
  dms-accounts:
    content: |
      [email protected]|{SHA512-CRYPT}$$6$$sbgFRCmQ.KWS5ryb$$EsWrlYosiadgdUOxCBHY0DQ3qFbeudDhNMqHs6jZt.8gmxUwiLVy738knqkHD4zj4amkb296HFqQ3yDq4UXt8.

  # Example ECDSA cert files for testing locally:
  tls-ca-cert:
    content: |
      -----BEGIN CERTIFICATE-----
      MIIBfTCCASKgAwIBAgIRAMAZttlRlkcuSun0yV0z4RwwCgYIKoZIzj0EAwIwHDEa
      MBgGA1UEAxMRU21hbGxzdGVwIFJvb3QgQ0EwHhcNMjEwMTAxMDAwMDAwWhcNMzEw
      MTAxMDAwMDAwWjAcMRowGAYDVQQDExFTbWFsbHN0ZXAgUm9vdCBDQTBZMBMGByqG
      SM49AgEGCCqGSM49AwEHA0IABJX2hCtoK3+bM5I3rmyApXLJ1gOcVhtoSSwM8XXR
      SEl25Kkc0n6mINuMK8UrBkiBUgexf6CYayx3xVr9TmMkg4KjRTBDMA4GA1UdDwEB
      /wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBQD8sBrApbyYyqU
      y+/TlwGynx2V5jAKBggqhkjOPQQDAgNJADBGAiEAi8N2eOETI+6hY3+G+kzNMd3K
      Sd3Ke8b++/nlwr5Fb/sCIQDYAjpKp/MpTDWICeHC2tcB5ptxoTdWkTBuG4rKcktA
      0w==
      -----END CERTIFICATE-----

  tls-key:
    content: |
      -----BEGIN EC PRIVATE KEY-----
      MHcCAQEEIOc6wqZmSDmT336K4O26dMk1RCVc0+cmnsO2eK4P5K5yoAoGCCqGSM49
      AwEHoUQDQgAEFOWNgekKKvUZE89vJ7henUYxODYIvCiHitRc2ylwttjqt1KUY1cp
      q3jof2fhURHfBUH3dHPXLHig5V9Jw5gqeg==
      -----END EC PRIVATE KEY-----

  tls-cert:
    content: |
      -----BEGIN CERTIFICATE-----
      MIIB9DCCAZqgAwIBAgIQE53a/y2c//YXRsz2kLm6gDAKBggqhkjOPQQDAjAcMRow
      GAYDVQQDExFTbWFsbHN0ZXAgUm9vdCBDQTAeFw0yMTAxMDEwMDAwMDBaFw0zMTAx
      MDEwMDAwMDBaMBkxFzAVBgNVBAMTDlNtYWxsc3RlcCBMZWFmMFkwEwYHKoZIzj0C
      AQYIKoZIzj0DAQcDQgAEFOWNgekKKvUZE89vJ7henUYxODYIvCiHitRc2ylwttjq
      t1KUY1cpq3jof2fhURHfBUH3dHPXLHig5V9Jw5gqeqOBwDCBvTAOBgNVHQ8BAf8E
      BAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBSz
      w74g+O6dcBbwienD70D8A9ESmDAfBgNVHSMEGDAWgBQD8sBrApbyYyqUy+/TlwGy
      nx2V5jBMBgNVHREERTBDghFtYWlsLmV4YW1wbGUudGVzdIIVbWFpbC5kZXN0aW5h
      dGlvbi50ZXN0ghdzbXRwLnJlbGF5LXNlcnZpY2UudGVzdDAKBggqhkjOPQQDAgNI
      ADBFAiEAoety5oClZtuBMkvlUIWRmWlyg1VIOZ544LSEbplsIhcCIHb6awMwNdXP
      m/xHjFkuwH1+UjDDRW53Ih7KZoLrQ6Cp
      -----END CERTIFICATE-----

  # Provides commands for the `--file` option of `testssl.sh` to run multiple tests with:
  testssl-config:
    content: |
      --jsonfile-pretty port_25.json --starttls smtp mail.example.test:25
      --jsonfile-pretty port_587.json --starttls smtp mail.example.test:587
      --jsonfile-pretty port_465.json mail.example.test:465

      #--jsonfile-pretty port_110.json --starttls pop3 mail.example.test:110
      #--jsonfile-pretty port_995.json mail.example.test:995

      --jsonfile-pretty port_143.json --starttls imap mail.example.test:143
      --jsonfile-pretty port_993.json mail.example.test:993

Manual verification:

# Shell into the DMS container:
docker compose exec -it dms bash

# Run OpenSSL commands to force TLSv1 connections for the different ports:
# `-CAfile` is optional, it verifies the cert against the CA cert that signed it.
# Explicit TLS (STARTTLS):
timeout 1 openssl s_client -tls1 -connect mail.example.test:25  -starttls smtp -CAfile /tmp/tls/ca-cert.pem
timeout 1 openssl s_client -tls1 -connect mail.example.test:587 -starttls smtp -CAfile /tmp/tls/ca-cert.pem
timeout 1 openssl s_client -tls1 -connect mail.example.test:143 -starttls imap -CAfile /tmp/tls/ca-cert.pem

# Implicit TLS:
timeout 1 openssl s_client -tls1 -connect mail.example.test:465 -CAfile /tmp/tls/ca-cert.pem
timeout 1 openssl s_client -tls1 -connect mail.example.test:993 -CAfile /tmp/tls/ca-cert.pem


# Equivalent commands via step CLI (lacks STARTTLS support):
# `--roots` is optional, it verifies the cert against the CA cert that signed it.
# You can also inspect the certificate via similar `step certificate inspect ...` command.
step certificate verify --verbose --roots /tmp/tls/ca-cert.pem tls://mail.example.test:465
step certificate verify --verbose --roots /tmp/tls/ca-cert.pem tls://mail.example.test:993

Automated verification:

As shown in the compose.yaml example there is a testssl.sh service added. Just run docker compose run --rm -it testssl and it'll output results to the terminal.

  • This will automate a security check for TLS, showing the earlier versions are supported and what cipher suites DMS is providing for those.
  • Do keep in mind that this depends on your certificate having RSA or ECDSA provisioned, ensure your certificate has compatible ciphers for your legacy client device connecting to DMS.

A more detailed security report can be given without the --preference option, which will do a more thorough test. You can also provide your own testssl command options such as testing one port specifically:

Collapsed for brevity (Click to view)
# If testing explict TLS, be sure to add the `--starttls smtp` / `--startls imap` option too:
$ docker compose run --rm -it testssl 'mail.example.test:993'

#####################################################################
  testssl.sh version 3.2.0 from https://testssl.sh/

  This program is free software. Distribution and modification under
  GPLv2 permitted. USAGE w/o ANY WARRANTY. USE IT AT YOUR OWN RISK!

  Please file bugs @ https://testssl.sh/bugs/
#####################################################################

  Using OpenSSL 1.0.2-bad (Mar 28 2025)  [~179 ciphers]
  on 8c788669f7b8:/home/testssl/bin/openssl.Linux.x86_64

 Start 2025-05-22 09:28:26        -->> 192.168.0.2:993 (mail.example.test) <<--

 rDNS (192.168.0.2):     example-dms-1.example_default.
 Service detected:       IMAP, thus skipping HTTP specific checks

 Testing protocols via sockets except NPN+ALPN

 SSLv2      not offered (OK)
 SSLv3      not offered (OK)
 TLS 1      offered (deprecated)
 TLS 1.1    offered (deprecated)
 TLS 1.2    offered (OK)
 TLS 1.3    offered (OK): final
 NPN/SPDY   not offered
 ALPN/HTTP2 not offered

 Testing cipher categories

 NULL ciphers (no encryption)                      not offered (OK)
 Anonymous NULL Ciphers (no authentication)        not offered (OK)
 Export ciphers (w/o ADH+NULL)                     not offered (OK)
 LOW: 64 Bit + DES, RC[2,4], MD5 (w/o export)      not offered (OK)
 Triple DES Ciphers / IDEA                         not offered
 Obsoleted CBC ciphers (AES, ARIA etc.)            offered
 Strong encryption (AEAD ciphers) with no FS       not offered
 Forward Secrecy strong encryption (AEAD ciphers)  offered (OK)


 Testing server's cipher preferences

Hexcode  Cipher Suite Name (OpenSSL)       KeyExch.   Encryption  Bits     Cipher Suite Name (IANA/RFC)
-----------------------------------------------------------------------------------------------------------------------------
SSLv2
 -
SSLv3
 -
TLSv1 (server order)
 xc00a   ECDHE-ECDSA-AES256-SHA            ECDH 256   AES         256      TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
 xc009   ECDHE-ECDSA-AES128-SHA            ECDH 256   AES         128      TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLSv1.1 (server order)
 xc00a   ECDHE-ECDSA-AES256-SHA            ECDH 256   AES         256      TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
 xc009   ECDHE-ECDSA-AES128-SHA            ECDH 256   AES         128      TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLSv1.2 (server order)
 xc02c   ECDHE-ECDSA-AES256-GCM-SHA384     ECDH 253   AESGCM      256      TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
 xcca9   ECDHE-ECDSA-CHACHA20-POLY1305     ECDH 253   ChaCha20    256      TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
 xc0af   ECDHE-ECDSA-AES256-CCM8           ECDH 253   AESCCM8     256      TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
 xc0ad   ECDHE-ECDSA-AES256-CCM            ECDH 253   AESCCM      256      TLS_ECDHE_ECDSA_WITH_AES_256_CCM
 xc05d   ECDHE-ECDSA-ARIA256-GCM-SHA384    ECDH 253   ARIAGCM     256      TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384
 xc024   ECDHE-ECDSA-AES256-SHA384         ECDH 253   AES         256      TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
 xc073   ECDHE-ECDSA-CAMELLIA256-SHA384    ECDH 253   Camellia    256      TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
 xc00a   ECDHE-ECDSA-AES256-SHA            ECDH 253   AES         256      TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
 xc02b   ECDHE-ECDSA-AES128-GCM-SHA256     ECDH 253   AESGCM      128      TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
 xc0ae   ECDHE-ECDSA-AES128-CCM8           ECDH 253   AESCCM8     128      TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
 xc0ac   ECDHE-ECDSA-AES128-CCM            ECDH 253   AESCCM      128      TLS_ECDHE_ECDSA_WITH_AES_128_CCM
 xc05c   ECDHE-ECDSA-ARIA128-GCM-SHA256    ECDH 253   ARIAGCM     128      TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256
 xc023   ECDHE-ECDSA-AES128-SHA256         ECDH 253   AES         128      TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
 xc072   ECDHE-ECDSA-CAMELLIA128-SHA256    ECDH 253   Camellia    128      TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
 xc009   ECDHE-ECDSA-AES128-SHA            ECDH 253   AES         128      TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLSv1.3 (server order)
 x1302   TLS_AES_256_GCM_SHA384            ECDH 253   AESGCM      256      TLS_AES_256_GCM_SHA384
 x1303   TLS_CHACHA20_POLY1305_SHA256      ECDH 253   ChaCha20    256      TLS_CHACHA20_POLY1305_SHA256
 x1301   TLS_AES_128_GCM_SHA256            ECDH 253   AESGCM      128      TLS_AES_128_GCM_SHA256

 Has server cipher order?     yes (OK) -- TLS 1.3 and below


 Testing robust forward secrecy (FS) -- omitting Null Authentication/Encryption, 3DES, RC4

 FS is offered (OK)           TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-CCM8 ECDHE-ECDSA-AES256-CCM
                              ECDHE-ECDSA-CAMELLIA256-SHA384 ECDHE-ECDSA-ARIA256-GCM-SHA384 TLS_AES_128_GCM_SHA256 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES128-CCM8 ECDHE-ECDSA-AES128-CCM
                              ECDHE-ECDSA-CAMELLIA128-SHA256 ECDHE-ECDSA-ARIA128-GCM-SHA256
 Elliptic curves offered:     prime256v1 secp384r1 secp521r1 X25519 X448
 Finite field group:          ffdhe2048 ffdhe3072 ffdhe4096 ffdhe6144 ffdhe8192
 TLS 1.2 sig_algs offered:    ECDSA+SHA256 ECDSA+SHA384 ECDSA+SHA512 ECDSA+SHA224 ECDSA+SHA1
 TLS 1.3 sig_algs offered:    ECDSA+SHA256

 Testing server defaults (Server Hello)

 TLS extensions (standard)    "server name/#0" "max fragment length/#1" "supported_groups/#10" "EC point formats/#11" "encrypt-then-mac/#22" "extended master secret/#23" "session ticket/#35" "supported versions/#43" "key share/#51"
                              "renegotiation info/#65281"
 Session Ticket RFC 5077 hint 7200 seconds, session tickets keys seems to be rotated < daily
 SSL Session ID support       yes
 Session Resumption           Tickets no, ID: no
 TLS clock skew               Random values, no fingerprinting possible
 Certificate Compression      none
 Client Authentication        none
 Signature Algorithm          ECDSA with SHA256
 Server key size              EC 256 bits (curve P-256)
 Server key usage             Digital Signature
 Server extended key usage    TLS Web Server Authentication, TLS Web Client Authentication
 Serial                       139DDAFF2D9CFFF61746CCF690B9BA80 (OK: length 16)
 Fingerprints                 SHA1 4B4F2F920C0376A7D5BBE807792B05B2384BCB8F
                              SHA256 A60CD194DF9F78BF07FA60B1DEEBC6BB83FFAAF619A3A86F1F8CB92F13086A8B
 Common Name (CN)             Smallstep Leaf
 subjectAltName (SAN)         mail.example.test mail.destination.test smtp.relay-service.test
 Trust (hostname)             Ok via SAN (same w/o SNI)
 Chain of trust               Ok
 EV cert (experimental)       no
 Certificate Validity (UTC)   2049 >= 60 days (2021-01-01 00:00 --> 2031-01-01 00:00)
                              >= 10 years is way too long
 ETS/"eTLS", visibility info  not present
 Certificate Revocation List  --
 OCSP URI                     --
                              NOT ok -- neither CRL nor OCSP URI provided
 OCSP stapling                not offered
 OCSP must staple extension   --
 DNS CAA RR (experimental)    not offered
 Certificate Transparency     N/A
 Certificates provided        1
 Issuer                       Smallstep Root CA
 Intermediate Bad OCSP (exp.) Ok


 Testing vulnerabilities

 Heartbleed (CVE-2014-0160)                not vulnerable (OK), no heartbeat extension
 CCS (CVE-2014-0224)                       not vulnerable (OK)
 Ticketbleed (CVE-2016-9244), experiment.  (applicable only for HTTPS)
 ROBOT                                     Server does not support any cipher suites that use RSA key transport
 Secure Renegotiation (RFC 5746)           supported (OK)
 Secure Client-Initiated Renegotiation     not vulnerable (OK)
 CRIME, TLS (CVE-2012-4929)                not vulnerable (OK) (not using HTTP anyway)
 POODLE, SSL (CVE-2014-3566)               not vulnerable (OK), no SSLv3 support
 TLS_FALLBACK_SCSV (RFC 7507)              some unexpected "handshake failure" instead of "inappropriate fallback"
 SWEET32 (CVE-2016-2183, CVE-2016-6329)    not vulnerable (OK)
 FREAK (CVE-2015-0204)                     not vulnerable (OK)
 DROWN (CVE-2016-0800, CVE-2016-0703)      not vulnerable on this host and port (OK)
                                           no RSA certificate, thus certificate can't be used with SSLv2 elsewhere
 LOGJAM (CVE-2015-4000), experimental      not vulnerable (OK): no DH EXPORT ciphers, no DH key detected with <= TLS 1.2
 BEAST (CVE-2011-3389)                     TLS1: ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA
                                           VULNERABLE -- but also supports higher protocols  TLSv1.1 TLSv1.2 (likely mitigated)
 LUCKY13 (CVE-2013-0169), experimental     potentially VULNERABLE, uses cipher block chaining (CBC) ciphers with TLS. Check patches
 Winshock (CVE-2014-6321), experimental    not vulnerable (OK)
 RC4 (CVE-2013-2566, CVE-2015-2808)        no RC4 ciphers detected (OK)


 Running client simulations via sockets

 Browser                      Protocol  Cipher Suite Name (OpenSSL)       Forward Secrecy
------------------------------------------------------------------------------------------------
 Android 8.1 (native)         TLSv1.2   ECDHE-ECDSA-AES256-GCM-SHA384     253 bit ECDH (X25519)
 Android 9.0 (native)         TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 Android 10.0 (native)        TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 Android 11/12 (native)       TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 Android 13/14 (native)       TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 Android 15 (native)          TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 Java 7u25                    TLSv1.0   ECDHE-ECDSA-AES128-SHA            256 bit ECDH (P-256)
 Java 8u442 (OpenJDK)         TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 Java 11.0.2 (OpenJDK)        TLSv1.3   TLS_AES_256_GCM_SHA384            256 bit ECDH (P-256)
 Java 17.0.3 (OpenJDK)        TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 Java 21.0.6 (OpenJDK)        TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 go 1.17.8                    TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 LibreSSL 3.3.6 (macOS)       TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 OpenSSL 1.0.2e               TLSv1.2   ECDHE-ECDSA-AES256-GCM-SHA384     256 bit ECDH (P-256)
 OpenSSL 1.1.1d (Debian)      TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 OpenSSL 3.0.15 (Debian)      TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 OpenSSL 3.5.0 (git)          TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)
 Apple Mail (16.0)            TLSv1.2   ECDHE-ECDSA-AES256-GCM-SHA384     256 bit ECDH (P-256)
 Thunderbird (91.9)           TLSv1.3   TLS_AES_256_GCM_SHA384            253 bit ECDH (X25519)


 Rating (experimental)

 Rating specs (not complete)  SSL Labs's 'SSL Server Rating Guide' (version 2009q from 2020-01-30)
 Specification documentation  https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide
 Protocol Support (weighted)  95 (28)
 Key Exchange     (weighted)  100 (30)
 Cipher Strength  (weighted)  90 (36)
 Final Score                  94
 Overall Grade                B
 Grade cap reasons            Grade capped to B. TLS 1.1 offered
                              Grade capped to B. TLS 1.0 offered

 Done 2025-05-22 09:29:29 [  65s] -->> 192.168.0.2:993 (mail.example.test) <<--

@georglauterbach
Copy link
Copy Markdown
Member

Mhh, this is a difficult one. I absolutely understand the issue at hand, but I am also not a fan of bending software to such "edge cases". Whether it actually is "edge" I am not sure. If the implementation is not too big and easily maintainable, then I see no issue; otherwise, I'd prefer user-patches.sh.

@polarathene
Copy link
Copy Markdown
Member Author

If the implementation is not too big and easily maintainable

It mostly would just replace / deprecate TLS_LEVEL=intermediate. With the bonus that we don't carry that cipher list anymore. No rush, I'll give it some thought next month perhaps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/security area/tests kind/improvement Improve an existing feature, configuration file or the documentation service/dovecot service/postfix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deprecation Notice: Dropping TLS_LEVEL=intermediate support for TLS < 1.2

4 participants