2021-02-18 09:24:34 +00:00
|
|
|
#!/usr/bin/env bats
|
2022-11-25 22:37:58 +00:00
|
|
|
load "${REPOSITORY_ROOT}/test/test_helper/common"
|
2021-02-18 09:24:34 +00:00
|
|
|
# Globals ${BATS_TMPDIR} and ${NAME}
|
|
|
|
# `${NAME}` defaults to `mailserver-testing:ci`
|
|
|
|
|
|
|
|
function teardown() {
|
2022-05-30 00:53:30 +00:00
|
|
|
docker rm -f tls_test_cipherlists
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function setup_file() {
|
2022-05-30 00:53:30 +00:00
|
|
|
export DOMAIN="example.test"
|
|
|
|
export NETWORK="test-network"
|
|
|
|
|
|
|
|
# Shared config for TLS testing (read-only)
|
|
|
|
export TLS_CONFIG_VOLUME
|
|
|
|
TLS_CONFIG_VOLUME="$(pwd)/test/test-files/ssl/${DOMAIN}/:/config/ssl/:ro"
|
|
|
|
# `${BATS_TMPDIR}` maps to `/tmp`
|
|
|
|
export TLS_RESULTS_DIR="${BATS_TMPDIR}/results"
|
|
|
|
|
|
|
|
# NOTE: If the network already exists, test will fail to start.
|
|
|
|
docker network create "${NETWORK}"
|
|
|
|
|
|
|
|
# Copies all of `./test/config/` to specific directory for testing
|
|
|
|
# `${PRIVATE_CONFIG}` becomes `$(pwd)/test/duplicate_configs/<bats test filename>`
|
|
|
|
export PRIVATE_CONFIG
|
|
|
|
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
|
|
|
|
|
|
|
# Pull `testssl.sh` image in advance to avoid it interfering with the `run` captured output.
|
|
|
|
# Only interferes (potential test failure) with `assert_output` not `assert_success`?
|
|
|
|
docker pull drwetter/testssl.sh:3.1dev
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function teardown_file() {
|
2022-05-30 00:53:30 +00:00
|
|
|
docker network rm "${NETWORK}"
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@test "checking tls: cipher list - rsa intermediate" {
|
2022-05-30 00:53:30 +00:00
|
|
|
check_ports 'rsa' 'intermediate'
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@test "checking tls: cipher list - rsa modern" {
|
2022-05-30 00:53:30 +00:00
|
|
|
check_ports 'rsa' 'modern'
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@test "checking tls: cipher list - ecdsa intermediate" {
|
2022-05-30 00:53:30 +00:00
|
|
|
check_ports 'ecdsa' 'intermediate'
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@test "checking tls: cipher list - ecdsa modern" {
|
2022-05-30 00:53:30 +00:00
|
|
|
check_ports 'ecdsa' 'modern'
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
Dual certificate support (eg ECDSA with RSA fallback) (#1801)
* feat: Change Postfix smtpd_tls key and cert files to chain_files
Since Postfix 3.4, `smtpd_tls_cert_file` and `smtpd_tls_key_file` have been deprecated in favor of `smtpd_tls_chain_files` which supports a list of values where a single or sequence of file paths provide a private key followed by it's certificate chain.
* feat: Dual certificate support
`smtpd_tls_chain_files` allows for multiple key+cert bundles so that you can provide different key types, such as ECDSA and RSA.
To maintain compatibility with the current CERT/KEY ENV vars only a 2nd certificate is supported.
Since Dovecot 2.2.31 a related feature is also available, but it is limited to only providing one alternative certificate via separate cert and key settings.
---
This feature enables support for multiple certificates, eg for serving modern ECDSA certs with RSA as fallback.
* chore: Refactor variable names to meet style guide
Improved some comments too.
* chore: Have function definitions respect style guide
* chore: Minor edits to comments
* chore: Expand on comments for maintenance, alert of insecure config
When `SSL_TYPE` isn't properly setup, we're still offering SSL connections but not warning in logs about the insecurity of such, or why a misconfiguration may have occurred.
This commit more clearly communicates to the user that they should look into the issue before considering deploying to production.
The `TODO` comments communicate to any future maintainer to consider treating these improper configs as disabling TLS instead.
* fix: Use `snakeoil` cert
I mistakenly thought this was placeholder text, which broke some tests. This adds the two files in the correct order (private key followed by cert/chain), to fix that issue.
* fix: Disable alt cert for Dovecot if necessary
Certain scenarios may persist state of previously configured alt cert via ENV vars that are removed from a future run. If the config is not reset to original immutable state, this will correctly disable the config from using alt cert unintentionally.
* fix: Satisfy ShellCheck lint
By switching from string var to array / list expansion, this better stores the extracted result and applies it in a manner that ShellCheck linting approves, removing the need to disable the rule.
* feat: Support dual cert test
Few tweaks to the test script allows re-purposing it for covering dual cert support as well.
* chore: Rearranged cert and key lines
A little reorganization, mostly placing private key ahead of related cert lines.
* chore: Refactor `_set_certificate`
This should make the parameters a little less confusing.
Previously was 3 parameters, but the Postfix parameter (1st) may look like two variables if you don't pay attention to the surrounding quotes; while the Dovecot parameters (2nd + 3rd) would have an opposing order. There was also a variant where the `FULLKEYCHAIN` var was passed in three times.
Now it's two params, with the 2nd param as an optional one. If the 2nd param is provided, then the two params are in the order of private key then certificate, otherwise if only a single parameter it's a single PEM file with the full cert chain and private key bundled.
This avoids implying that Postfix and Dovecot might use different files.
* chore: Document current state of `SSL_TYPE` logic better
Inlined for the benefit of anyone else maintaining this section if I'm unable to address the concerns within my own time.
* docs: ENV vars
`TLS_LEVEL=old` isn't in the codebase anymore, not likely to be relevant to retain.
No point in documenting what is considered invalid / unsupported config value in the first place for `SSL_TYPE`.
`SSL_TYPE=manual` was missing documentation for both related file path ENV vars, they've been added along with their alt fallback variants.
* chore: Update Dovecot LMTP SSL test config
Not sure how relevant this is, the file isn't complete sync with the main dovecot `10-ssl.conf` config, adding the support just in case.
* chore: Rename `FULLKEYCHAIN` to avoid confusion
There doesn't appear to be a standardized name for this type of file bundle, and `keychain` may be misleading (fullkeychain often provides macOS keychain results on search engines).
Opting for a more explicit `KEY_WITH_FULLCHAIN` name instead.
* fix: Invalid var name
`_set_certificate` refactor commit accidentally changed a var name and committed that breaking the dual cert support (thanks tests!).
* test: Refactor `mail_ssl_manual.bats`
Proper test return values instead of `wc -l` based checking.
Tests with dual cert support active, tests that feature (to better detect failure case.
Third test case was unable to verify new self-signed certificate, added new certs signed with self-signed root CA.
Adjusted openssl `CApath` parameter to use `CAfile` instead as `letsencrypt` cert was replaced thus CA cert is missing from the system trust store.
* test: Properly check for files in `mail_ssl_manual.bats`
Fixes lint error.
Also realized I was accidentally asserting a file exists in the test environment, not within the container.
Resolved that and also added an additional test case to ensure the ENV var files are valid when passed in, in the event a change misconfigures them and that the issue is identified earlier.
* chore: Apply PR review feedback
Better format some strings that had mixed quotes when they weren't necessary.
Additionally DRYed up the config path for Postfix and Dovecot within the `_setup_ssl` method.
Co-authored-by: Georg Lauterbach <infrastructure@itbsd.com>
2021-02-21 22:43:41 +00:00
|
|
|
|
|
|
|
# Only ECDSA with RSA fallback is tested.
|
|
|
|
# There isn't a situation where RSA with ECDSA fallback would make sense.
|
|
|
|
@test "checking tls: cipher list - ecdsa intermediate, with rsa fallback" {
|
2022-05-30 00:53:30 +00:00
|
|
|
check_ports 'ecdsa' 'intermediate' 'rsa'
|
Dual certificate support (eg ECDSA with RSA fallback) (#1801)
* feat: Change Postfix smtpd_tls key and cert files to chain_files
Since Postfix 3.4, `smtpd_tls_cert_file` and `smtpd_tls_key_file` have been deprecated in favor of `smtpd_tls_chain_files` which supports a list of values where a single or sequence of file paths provide a private key followed by it's certificate chain.
* feat: Dual certificate support
`smtpd_tls_chain_files` allows for multiple key+cert bundles so that you can provide different key types, such as ECDSA and RSA.
To maintain compatibility with the current CERT/KEY ENV vars only a 2nd certificate is supported.
Since Dovecot 2.2.31 a related feature is also available, but it is limited to only providing one alternative certificate via separate cert and key settings.
---
This feature enables support for multiple certificates, eg for serving modern ECDSA certs with RSA as fallback.
* chore: Refactor variable names to meet style guide
Improved some comments too.
* chore: Have function definitions respect style guide
* chore: Minor edits to comments
* chore: Expand on comments for maintenance, alert of insecure config
When `SSL_TYPE` isn't properly setup, we're still offering SSL connections but not warning in logs about the insecurity of such, or why a misconfiguration may have occurred.
This commit more clearly communicates to the user that they should look into the issue before considering deploying to production.
The `TODO` comments communicate to any future maintainer to consider treating these improper configs as disabling TLS instead.
* fix: Use `snakeoil` cert
I mistakenly thought this was placeholder text, which broke some tests. This adds the two files in the correct order (private key followed by cert/chain), to fix that issue.
* fix: Disable alt cert for Dovecot if necessary
Certain scenarios may persist state of previously configured alt cert via ENV vars that are removed from a future run. If the config is not reset to original immutable state, this will correctly disable the config from using alt cert unintentionally.
* fix: Satisfy ShellCheck lint
By switching from string var to array / list expansion, this better stores the extracted result and applies it in a manner that ShellCheck linting approves, removing the need to disable the rule.
* feat: Support dual cert test
Few tweaks to the test script allows re-purposing it for covering dual cert support as well.
* chore: Rearranged cert and key lines
A little reorganization, mostly placing private key ahead of related cert lines.
* chore: Refactor `_set_certificate`
This should make the parameters a little less confusing.
Previously was 3 parameters, but the Postfix parameter (1st) may look like two variables if you don't pay attention to the surrounding quotes; while the Dovecot parameters (2nd + 3rd) would have an opposing order. There was also a variant where the `FULLKEYCHAIN` var was passed in three times.
Now it's two params, with the 2nd param as an optional one. If the 2nd param is provided, then the two params are in the order of private key then certificate, otherwise if only a single parameter it's a single PEM file with the full cert chain and private key bundled.
This avoids implying that Postfix and Dovecot might use different files.
* chore: Document current state of `SSL_TYPE` logic better
Inlined for the benefit of anyone else maintaining this section if I'm unable to address the concerns within my own time.
* docs: ENV vars
`TLS_LEVEL=old` isn't in the codebase anymore, not likely to be relevant to retain.
No point in documenting what is considered invalid / unsupported config value in the first place for `SSL_TYPE`.
`SSL_TYPE=manual` was missing documentation for both related file path ENV vars, they've been added along with their alt fallback variants.
* chore: Update Dovecot LMTP SSL test config
Not sure how relevant this is, the file isn't complete sync with the main dovecot `10-ssl.conf` config, adding the support just in case.
* chore: Rename `FULLKEYCHAIN` to avoid confusion
There doesn't appear to be a standardized name for this type of file bundle, and `keychain` may be misleading (fullkeychain often provides macOS keychain results on search engines).
Opting for a more explicit `KEY_WITH_FULLCHAIN` name instead.
* fix: Invalid var name
`_set_certificate` refactor commit accidentally changed a var name and committed that breaking the dual cert support (thanks tests!).
* test: Refactor `mail_ssl_manual.bats`
Proper test return values instead of `wc -l` based checking.
Tests with dual cert support active, tests that feature (to better detect failure case.
Third test case was unable to verify new self-signed certificate, added new certs signed with self-signed root CA.
Adjusted openssl `CApath` parameter to use `CAfile` instead as `letsencrypt` cert was replaced thus CA cert is missing from the system trust store.
* test: Properly check for files in `mail_ssl_manual.bats`
Fixes lint error.
Also realized I was accidentally asserting a file exists in the test environment, not within the container.
Resolved that and also added an additional test case to ensure the ENV var files are valid when passed in, in the event a change misconfigures them and that the issue is identified earlier.
* chore: Apply PR review feedback
Better format some strings that had mixed quotes when they weren't necessary.
Additionally DRYed up the config path for Postfix and Dovecot within the `_setup_ssl` method.
Co-authored-by: Georg Lauterbach <infrastructure@itbsd.com>
2021-02-21 22:43:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@test "checking tls: cipher list - ecdsa modern, with rsa fallback" {
|
2022-05-30 00:53:30 +00:00
|
|
|
check_ports 'ecdsa' 'modern' 'rsa'
|
Dual certificate support (eg ECDSA with RSA fallback) (#1801)
* feat: Change Postfix smtpd_tls key and cert files to chain_files
Since Postfix 3.4, `smtpd_tls_cert_file` and `smtpd_tls_key_file` have been deprecated in favor of `smtpd_tls_chain_files` which supports a list of values where a single or sequence of file paths provide a private key followed by it's certificate chain.
* feat: Dual certificate support
`smtpd_tls_chain_files` allows for multiple key+cert bundles so that you can provide different key types, such as ECDSA and RSA.
To maintain compatibility with the current CERT/KEY ENV vars only a 2nd certificate is supported.
Since Dovecot 2.2.31 a related feature is also available, but it is limited to only providing one alternative certificate via separate cert and key settings.
---
This feature enables support for multiple certificates, eg for serving modern ECDSA certs with RSA as fallback.
* chore: Refactor variable names to meet style guide
Improved some comments too.
* chore: Have function definitions respect style guide
* chore: Minor edits to comments
* chore: Expand on comments for maintenance, alert of insecure config
When `SSL_TYPE` isn't properly setup, we're still offering SSL connections but not warning in logs about the insecurity of such, or why a misconfiguration may have occurred.
This commit more clearly communicates to the user that they should look into the issue before considering deploying to production.
The `TODO` comments communicate to any future maintainer to consider treating these improper configs as disabling TLS instead.
* fix: Use `snakeoil` cert
I mistakenly thought this was placeholder text, which broke some tests. This adds the two files in the correct order (private key followed by cert/chain), to fix that issue.
* fix: Disable alt cert for Dovecot if necessary
Certain scenarios may persist state of previously configured alt cert via ENV vars that are removed from a future run. If the config is not reset to original immutable state, this will correctly disable the config from using alt cert unintentionally.
* fix: Satisfy ShellCheck lint
By switching from string var to array / list expansion, this better stores the extracted result and applies it in a manner that ShellCheck linting approves, removing the need to disable the rule.
* feat: Support dual cert test
Few tweaks to the test script allows re-purposing it for covering dual cert support as well.
* chore: Rearranged cert and key lines
A little reorganization, mostly placing private key ahead of related cert lines.
* chore: Refactor `_set_certificate`
This should make the parameters a little less confusing.
Previously was 3 parameters, but the Postfix parameter (1st) may look like two variables if you don't pay attention to the surrounding quotes; while the Dovecot parameters (2nd + 3rd) would have an opposing order. There was also a variant where the `FULLKEYCHAIN` var was passed in three times.
Now it's two params, with the 2nd param as an optional one. If the 2nd param is provided, then the two params are in the order of private key then certificate, otherwise if only a single parameter it's a single PEM file with the full cert chain and private key bundled.
This avoids implying that Postfix and Dovecot might use different files.
* chore: Document current state of `SSL_TYPE` logic better
Inlined for the benefit of anyone else maintaining this section if I'm unable to address the concerns within my own time.
* docs: ENV vars
`TLS_LEVEL=old` isn't in the codebase anymore, not likely to be relevant to retain.
No point in documenting what is considered invalid / unsupported config value in the first place for `SSL_TYPE`.
`SSL_TYPE=manual` was missing documentation for both related file path ENV vars, they've been added along with their alt fallback variants.
* chore: Update Dovecot LMTP SSL test config
Not sure how relevant this is, the file isn't complete sync with the main dovecot `10-ssl.conf` config, adding the support just in case.
* chore: Rename `FULLKEYCHAIN` to avoid confusion
There doesn't appear to be a standardized name for this type of file bundle, and `keychain` may be misleading (fullkeychain often provides macOS keychain results on search engines).
Opting for a more explicit `KEY_WITH_FULLCHAIN` name instead.
* fix: Invalid var name
`_set_certificate` refactor commit accidentally changed a var name and committed that breaking the dual cert support (thanks tests!).
* test: Refactor `mail_ssl_manual.bats`
Proper test return values instead of `wc -l` based checking.
Tests with dual cert support active, tests that feature (to better detect failure case.
Third test case was unable to verify new self-signed certificate, added new certs signed with self-signed root CA.
Adjusted openssl `CApath` parameter to use `CAfile` instead as `letsencrypt` cert was replaced thus CA cert is missing from the system trust store.
* test: Properly check for files in `mail_ssl_manual.bats`
Fixes lint error.
Also realized I was accidentally asserting a file exists in the test environment, not within the container.
Resolved that and also added an additional test case to ensure the ENV var files are valid when passed in, in the event a change misconfigures them and that the issue is identified earlier.
* chore: Apply PR review feedback
Better format some strings that had mixed quotes when they weren't necessary.
Additionally DRYed up the config path for Postfix and Dovecot within the `_setup_ssl` method.
Co-authored-by: Georg Lauterbach <infrastructure@itbsd.com>
2021-02-21 22:43:41 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 09:24:34 +00:00
|
|
|
function check_ports() {
|
2022-05-30 00:53:30 +00:00
|
|
|
local KEY_TYPE=$1
|
|
|
|
local TLS_LEVEL=$2
|
|
|
|
local ALT_KEY_TYPE=$3 # Optional parameter
|
|
|
|
|
|
|
|
local KEY_TYPE_LABEL="${KEY_TYPE}"
|
|
|
|
# This is just to add a `_` delimiter between the two key types for readability
|
|
|
|
if [[ -n ${ALT_KEY_TYPE} ]]
|
|
|
|
then
|
|
|
|
KEY_TYPE_LABEL="${KEY_TYPE}_${ALT_KEY_TYPE}"
|
|
|
|
fi
|
|
|
|
local RESULTS_PATH="${KEY_TYPE_LABEL}/${TLS_LEVEL}"
|
|
|
|
|
|
|
|
collect_cipherlist_data
|
|
|
|
|
|
|
|
# SMTP: Opportunistic STARTTLS Explicit(25)
|
|
|
|
# Needs to test against cipher lists specific to Port 25 ('_p25' parameter)
|
|
|
|
check_cipherlists "${RESULTS_PATH}/port_25.json" '_p25'
|
|
|
|
|
|
|
|
# SMTP Submission: Mandatory STARTTLS Explicit(587) and Implicit(465) TLS
|
|
|
|
check_cipherlists "${RESULTS_PATH}/port_587.json"
|
|
|
|
check_cipherlists "${RESULTS_PATH}/port_465.json"
|
|
|
|
|
|
|
|
# IMAP: Mandatory STARTTLS Explicit(143) and Implicit(993) TLS
|
|
|
|
check_cipherlists "${RESULTS_PATH}/port_143.json"
|
|
|
|
check_cipherlists "${RESULTS_PATH}/port_993.json"
|
|
|
|
|
|
|
|
# POP3: Mandatory STARTTLS Explicit(110) and Implicit(995)
|
|
|
|
check_cipherlists "${RESULTS_PATH}/port_110.json"
|
|
|
|
check_cipherlists "${RESULTS_PATH}/port_995.json"
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function collect_cipherlist_data() {
|
2022-05-30 00:53:30 +00:00
|
|
|
local ALT_CERT=()
|
|
|
|
local ALT_KEY=()
|
|
|
|
|
|
|
|
if [[ -n ${ALT_KEY_TYPE} ]]
|
|
|
|
then
|
|
|
|
ALT_CERT=(--env SSL_ALT_CERT_PATH="/config/ssl/cert.${ALT_KEY_TYPE}.pem")
|
|
|
|
ALT_KEY=(--env SSL_ALT_KEY_PATH="/config/ssl/key.${ALT_KEY_TYPE}.pem")
|
|
|
|
fi
|
|
|
|
|
|
|
|
run docker run -d --name tls_test_cipherlists \
|
|
|
|
--volume "${PRIVATE_CONFIG}/:/tmp/docker-mailserver/" \
|
|
|
|
--volume "${TLS_CONFIG_VOLUME}" \
|
|
|
|
--env ENABLE_POP3=1 \
|
|
|
|
--env SSL_TYPE="manual" \
|
|
|
|
--env SSL_CERT_PATH="/config/ssl/cert.${KEY_TYPE}.pem" \
|
|
|
|
--env SSL_KEY_PATH="/config/ssl/key.${KEY_TYPE}.pem" \
|
|
|
|
"${ALT_CERT[@]}" \
|
|
|
|
"${ALT_KEY[@]}" \
|
|
|
|
--env TLS_LEVEL="${TLS_LEVEL}" \
|
|
|
|
--network "${NETWORK}" \
|
|
|
|
--network-alias "${DOMAIN}" \
|
|
|
|
--hostname "mail.${DOMAIN}" \
|
|
|
|
--tty \
|
|
|
|
"${NAME}" # Image name
|
|
|
|
|
|
|
|
assert_success
|
|
|
|
|
|
|
|
wait_for_tcp_port_in_container 25 tls_test_cipherlists
|
|
|
|
# NOTE: An rDNS query for the container IP will resolve to `<container name>.<network name>.`
|
|
|
|
|
|
|
|
# Make directory with test user ownership. Avoids Docker creating with root ownership.
|
|
|
|
# TODO: Can switch to filename prefix for JSON output when this is resolved: https://github.com/drwetter/testssl.sh/issues/1845
|
|
|
|
mkdir -p "${TLS_RESULTS_DIR}/${RESULTS_PATH}"
|
|
|
|
|
|
|
|
# For non-CI test runs, instead of removing prior test files after this test suite completes,
|
|
|
|
# they're retained and overwritten by future test runs instead. Useful for inspection.
|
|
|
|
# `--preference` reduces the test scope to the cipher suites reported as supported by the server. Completes in ~35% of the time.
|
|
|
|
local TESTSSL_CMD=(--quiet --file "/config/ssl/testssl.txt" --mode parallel --overwrite --preference)
|
|
|
|
# NOTE: Batch testing ports via `--file` doesn't properly bubble up failure.
|
|
|
|
# If the failure for a test is misleading consider testing a single port with:
|
|
|
|
# local TESTSSL_CMD=(--quiet --jsonfile-pretty "${RESULTS_PATH}/port_${PORT}.json" --starttls smtp "${DOMAIN}:${PORT}")
|
|
|
|
# TODO: Can use `jq` to check for failure when this is resolved: https://github.com/drwetter/testssl.sh/issues/1844
|
|
|
|
|
|
|
|
# `--user "<uid>:<gid>"` is a workaround: Avoids `permission denied` write errors for json output, uses `id` to match user uid & gid.
|
|
|
|
run docker run --rm \
|
|
|
|
--user "$(id -u):$(id -g)" \
|
|
|
|
--network "${NETWORK}" \
|
|
|
|
--volume "${TLS_CONFIG_VOLUME}" \
|
|
|
|
--volume "${TLS_RESULTS_DIR}/${RESULTS_PATH}/:/output" \
|
|
|
|
--workdir "/output" \
|
|
|
|
drwetter/testssl.sh:3.1dev "${TESTSSL_CMD[@]}"
|
|
|
|
|
|
|
|
assert_success
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Use `jq` to extract a specific cipher list from the target`testssl.sh` results json output file
|
|
|
|
function compare_cipherlist() {
|
2022-05-30 00:53:30 +00:00
|
|
|
local TARGET_CIPHERLIST=$1
|
|
|
|
local RESULTS_FILE=$2
|
|
|
|
local EXPECTED_CIPHERLIST=$3
|
2021-02-18 09:24:34 +00:00
|
|
|
|
2022-05-30 00:53:30 +00:00
|
|
|
run jq '.scanResult[0].serverPreferences[] | select(.id=="'"${TARGET_CIPHERLIST}"'") | .finding' "${TLS_RESULTS_DIR}/${RESULTS_FILE}"
|
|
|
|
assert_success
|
|
|
|
assert_output "${EXPECTED_CIPHERLIST}"
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Compares the expected cipher lists against logged test results from `testssl.sh`
|
|
|
|
function check_cipherlists() {
|
2022-05-30 00:53:30 +00:00
|
|
|
local RESULTS_FILE=$1
|
|
|
|
local p25=$2 # optional suffix
|
|
|
|
|
|
|
|
# TLS_LEVEL `modern` doesn't have TLS v1.0 or v1.1 cipher suites. Sets TLS v1.2 as minimum.
|
|
|
|
if [[ ${TLS_LEVEL} == "intermediate" ]]
|
|
|
|
then
|
|
|
|
compare_cipherlist "cipherorder_TLSv1" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1${p25}")"
|
|
|
|
compare_cipherlist "cipherorder_TLSv1_1" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1_1${p25}")"
|
|
|
|
fi
|
|
|
|
|
|
|
|
compare_cipherlist "cipherorder_TLSv1_2" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1_2${p25}")"
|
|
|
|
compare_cipherlist "cipherorder_TLSv1_3" "${RESULTS_FILE}" "$(get_cipherlist 'TLSv1_3')"
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Expected cipher lists. Should match `TLS_LEVEL` cipher lists set in `start-mailserver.sh`.
|
|
|
|
# Excluding Port 25 which uses defaults from Postfix after applying `smtpd_tls_exclude_ciphers` rules.
|
Dual certificate support (eg ECDSA with RSA fallback) (#1801)
* feat: Change Postfix smtpd_tls key and cert files to chain_files
Since Postfix 3.4, `smtpd_tls_cert_file` and `smtpd_tls_key_file` have been deprecated in favor of `smtpd_tls_chain_files` which supports a list of values where a single or sequence of file paths provide a private key followed by it's certificate chain.
* feat: Dual certificate support
`smtpd_tls_chain_files` allows for multiple key+cert bundles so that you can provide different key types, such as ECDSA and RSA.
To maintain compatibility with the current CERT/KEY ENV vars only a 2nd certificate is supported.
Since Dovecot 2.2.31 a related feature is also available, but it is limited to only providing one alternative certificate via separate cert and key settings.
---
This feature enables support for multiple certificates, eg for serving modern ECDSA certs with RSA as fallback.
* chore: Refactor variable names to meet style guide
Improved some comments too.
* chore: Have function definitions respect style guide
* chore: Minor edits to comments
* chore: Expand on comments for maintenance, alert of insecure config
When `SSL_TYPE` isn't properly setup, we're still offering SSL connections but not warning in logs about the insecurity of such, or why a misconfiguration may have occurred.
This commit more clearly communicates to the user that they should look into the issue before considering deploying to production.
The `TODO` comments communicate to any future maintainer to consider treating these improper configs as disabling TLS instead.
* fix: Use `snakeoil` cert
I mistakenly thought this was placeholder text, which broke some tests. This adds the two files in the correct order (private key followed by cert/chain), to fix that issue.
* fix: Disable alt cert for Dovecot if necessary
Certain scenarios may persist state of previously configured alt cert via ENV vars that are removed from a future run. If the config is not reset to original immutable state, this will correctly disable the config from using alt cert unintentionally.
* fix: Satisfy ShellCheck lint
By switching from string var to array / list expansion, this better stores the extracted result and applies it in a manner that ShellCheck linting approves, removing the need to disable the rule.
* feat: Support dual cert test
Few tweaks to the test script allows re-purposing it for covering dual cert support as well.
* chore: Rearranged cert and key lines
A little reorganization, mostly placing private key ahead of related cert lines.
* chore: Refactor `_set_certificate`
This should make the parameters a little less confusing.
Previously was 3 parameters, but the Postfix parameter (1st) may look like two variables if you don't pay attention to the surrounding quotes; while the Dovecot parameters (2nd + 3rd) would have an opposing order. There was also a variant where the `FULLKEYCHAIN` var was passed in three times.
Now it's two params, with the 2nd param as an optional one. If the 2nd param is provided, then the two params are in the order of private key then certificate, otherwise if only a single parameter it's a single PEM file with the full cert chain and private key bundled.
This avoids implying that Postfix and Dovecot might use different files.
* chore: Document current state of `SSL_TYPE` logic better
Inlined for the benefit of anyone else maintaining this section if I'm unable to address the concerns within my own time.
* docs: ENV vars
`TLS_LEVEL=old` isn't in the codebase anymore, not likely to be relevant to retain.
No point in documenting what is considered invalid / unsupported config value in the first place for `SSL_TYPE`.
`SSL_TYPE=manual` was missing documentation for both related file path ENV vars, they've been added along with their alt fallback variants.
* chore: Update Dovecot LMTP SSL test config
Not sure how relevant this is, the file isn't complete sync with the main dovecot `10-ssl.conf` config, adding the support just in case.
* chore: Rename `FULLKEYCHAIN` to avoid confusion
There doesn't appear to be a standardized name for this type of file bundle, and `keychain` may be misleading (fullkeychain often provides macOS keychain results on search engines).
Opting for a more explicit `KEY_WITH_FULLCHAIN` name instead.
* fix: Invalid var name
`_set_certificate` refactor commit accidentally changed a var name and committed that breaking the dual cert support (thanks tests!).
* test: Refactor `mail_ssl_manual.bats`
Proper test return values instead of `wc -l` based checking.
Tests with dual cert support active, tests that feature (to better detect failure case.
Third test case was unable to verify new self-signed certificate, added new certs signed with self-signed root CA.
Adjusted openssl `CApath` parameter to use `CAfile` instead as `letsencrypt` cert was replaced thus CA cert is missing from the system trust store.
* test: Properly check for files in `mail_ssl_manual.bats`
Fixes lint error.
Also realized I was accidentally asserting a file exists in the test environment, not within the container.
Resolved that and also added an additional test case to ensure the ENV var files are valid when passed in, in the event a change misconfigures them and that the issue is identified earlier.
* chore: Apply PR review feedback
Better format some strings that had mixed quotes when they weren't necessary.
Additionally DRYed up the config path for Postfix and Dovecot within the `_setup_ssl` method.
Co-authored-by: Georg Lauterbach <infrastructure@itbsd.com>
2021-02-21 22:43:41 +00:00
|
|
|
# NOTE: If a test fails, look at the `check_ports` params, then update the corresponding associative key's value
|
|
|
|
# with the `actual` error value (assuming an update needs to be made, and not a valid security issue to look into).
|
2021-02-18 09:24:34 +00:00
|
|
|
function get_cipherlist() {
|
2022-05-30 00:53:30 +00:00
|
|
|
local TLS_VERSION=$1
|
|
|
|
|
|
|
|
if [[ ${TLS_VERSION} == "TLSv1_3" ]]
|
|
|
|
then
|
|
|
|
# TLS v1.3 cipher suites are not user defineable and not unique to the available certificate(s).
|
|
|
|
# They do not support server enforced order either.
|
|
|
|
echo '"TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256"'
|
|
|
|
else
|
|
|
|
# Associative array for easy querying of required cipher list
|
|
|
|
declare -A CIPHER_LIST
|
|
|
|
|
|
|
|
# `intermediate` cipher lists TLS v1.0 and v1.1 cipher suites should be the same:
|
|
|
|
CIPHER_LIST["rsa_intermediate_TLSv1"]='"ECDHE-RSA-AES128-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA"'
|
|
|
|
CIPHER_LIST["rsa_intermediate_TLSv1_1"]=${CIPHER_LIST["rsa_intermediate_TLSv1"]}
|
|
|
|
CIPHER_LIST["rsa_intermediate_TLSv1_2"]='"ECDHE-RSA-CHACHA20-POLY1305 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES128-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA"'
|
|
|
|
# `modern` cipher lists shouldn't have TLS v1.0 or v1.1 cipher suites:
|
|
|
|
CIPHER_LIST["rsa_modern_TLSv1_2"]='"ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384"'
|
|
|
|
|
|
|
|
# ECDSA:
|
|
|
|
CIPHER_LIST["ecdsa_intermediate_TLSv1"]='"ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA"'
|
|
|
|
CIPHER_LIST["ecdsa_intermediate_TLSv1_1"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1"]}
|
|
|
|
CIPHER_LIST["ecdsa_intermediate_TLSv1_2"]='"ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA"'
|
|
|
|
CIPHER_LIST["ecdsa_modern_TLSv1_2"]='"ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305"'
|
|
|
|
|
|
|
|
# ECDSA + RSA fallback, dual cert support:
|
|
|
|
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1"]='"ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA"'
|
|
|
|
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_1"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1"]}
|
|
|
|
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2"]='"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"'
|
|
|
|
CIPHER_LIST["ecdsa_rsa_modern_TLSv1_2"]='"ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384"'
|
|
|
|
|
|
|
|
|
|
|
|
# Port 25
|
|
|
|
# TLSv1 and TLSv1_1 share the same cipher suites as other ports have. But the server order differs:
|
|
|
|
CIPHER_LIST["rsa_intermediate_TLSv1_p25"]='"ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA"'
|
|
|
|
CIPHER_LIST["rsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["rsa_intermediate_TLSv1_p25"]}
|
|
|
|
# TLSv1_2 has different server order and also includes ARIA, CCM, DHE+CHACHA20-POLY1305 cipher suites:
|
|
|
|
CIPHER_LIST["rsa_intermediate_TLSv1_2_p25"]='"ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES256-CCM8 DHE-RSA-AES256-CCM ECDHE-ARIA256-GCM-SHA384 DHE-RSA-ARIA256-GCM-SHA384 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES256-SHA256 ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ARIA256-GCM-SHA384 ECDHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-CCM8 DHE-RSA-AES128-CCM ECDHE-ARIA128-GCM-SHA256 DHE-RSA-ARIA128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA ARIA128-GCM-SHA256"'
|
|
|
|
# Port 25 is unaffected by `TLS_LEVEL` profiles (other than min TLS version), it has the same TLS v1.2 cipher list under both:
|
|
|
|
CIPHER_LIST["rsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["rsa_intermediate_TLSv1_2_p25"]}
|
|
|
|
|
|
|
|
# ECDSA (Port 25):
|
|
|
|
CIPHER_LIST["ecdsa_intermediate_TLSv1_p25"]='"ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA"'
|
|
|
|
CIPHER_LIST["ecdsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1_p25"]}
|
|
|
|
|
|
|
|
CIPHER_LIST["ecdsa_intermediate_TLSv1_2_p25"]='"ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-CCM8 ECDHE-ECDSA-AES256-CCM ECDHE-ECDSA-ARIA256-GCM-SHA384 ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES128-CCM8 ECDHE-ECDSA-AES128-CCM ECDHE-ECDSA-ARIA128-GCM-SHA256 ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA"'
|
|
|
|
CIPHER_LIST["ecdsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1_2_p25"]}
|
|
|
|
|
|
|
|
|
|
|
|
# ECDSA + RSA fallback, dual cert support (Port 25):
|
|
|
|
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_p25"]='"ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA"'
|
|
|
|
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_p25"]}
|
|
|
|
|
|
|
|
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2_p25"]='"ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-CCM8 ECDHE-ECDSA-AES256-CCM DHE-RSA-AES256-CCM8 DHE-RSA-AES256-CCM ECDHE-ECDSA-ARIA256-GCM-SHA384 ECDHE-ARIA256-GCM-SHA384 DHE-RSA-ARIA256-GCM-SHA384 ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES256-SHA256 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ARIA256-GCM-SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES128-CCM8 ECDHE-ECDSA-AES128-CCM DHE-RSA-AES128-CCM8 DHE-RSA-AES128-CCM ECDHE-ECDSA-ARIA128-GCM-SHA256 ECDHE-ARIA128-GCM-SHA256 DHE-RSA-ARIA128-GCM-SHA256 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA ARIA128-GCM-SHA256"'
|
|
|
|
CIPHER_LIST["ecdsa_rsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2_p25"]}
|
|
|
|
|
|
|
|
|
|
|
|
local TARGET_QUERY="${KEY_TYPE_LABEL}_${TLS_LEVEL}_${TLS_VERSION}"
|
|
|
|
echo "${CIPHER_LIST[${TARGET_QUERY}]}"
|
|
|
|
fi
|
2021-02-18 09:24:34 +00:00
|
|
|
}
|