Files
bongo/contrib/testing/test-config-tls-material.sh
T
2026-07-22 16:23:26 +02:00

178 lines
5.2 KiB
Bash
Executable File

#!/bin/sh
# This program is free software, licensed under the terms of the GNU GPL.
# See the Bongo COPYING file for full details.
# Copyright (c) 2026 Bongo Project contributors
set -eu
export LC_ALL=C
if [ "$#" -ne 2 ]; then
echo "Usage: $0 BONGO_CONFIG TEMPORARY_SSL_DIRECTORY" >&2
exit 64
fi
binary=$1
directory=$2
case "$directory" in
/tmp/*) ;;
*)
echo "Refusing a TLS test directory outside /tmp: $directory" >&2
exit 64
;;
esac
if [ ! -x "$binary" ]; then
echo "Not an executable bongo-config test binary: $binary" >&2
exit 64
fi
certificate="$directory/server.crt"
key="$directory/server.key"
good_certificate="$directory/server.crt.test-good"
good_key="$directory/server.key.test-good"
wrong_key="$directory/server.key.test-wrong"
for path in "$certificate" "$key" "$good_certificate" "$good_key" "$wrong_key"; do
if [ -e "$path" ] || [ -L "$path" ]; then
echo "Refusing to replace pre-existing test input: $path" >&2
exit 64
fi
done
mkdir -p "$directory"
cleanup()
{
rm -f "$certificate" "$key" "$good_certificate" "$good_key" "$wrong_key"
}
trap cleanup EXIT HUP INT TERM
run_crypto()
{
unshare --user --map-root-user "$binary" \
--hostname mail.bongo.test \
--tls-name mail.bongo.test \
--tls-name smtp.bongo.test crypto
}
restore_pair()
{
rm -f "$certificate" "$key"
cp "$good_certificate" "$certificate"
cp "$good_key" "$key"
chmod 0644 "$certificate"
chmod 0640 "$key"
}
expect_failure()
{
label=$1
expected=$2
before=$(sha256sum "$certificate" 2>/dev/null || true)
before="$before|$(sha256sum "$key" 2>/dev/null || true)"
set +e
output=$(run_crypto 2>&1)
status=$?
set -e
after=$(sha256sum "$certificate" 2>/dev/null || true)
after="$after|$(sha256sum "$key" 2>/dev/null || true)"
if [ "$status" -ne 6 ] ||
! printf '%s' "$output" | grep -F "$expected" >/dev/null ||
[ "$before" != "$after" ]; then
printf 'FAIL %s: status=%s output=%s\n' "$label" "$status" "$output" >&2
exit 1
fi
printf 'PASS %s: rejected without changing input files\n' "$label"
}
run_crypto | grep -F 'Crypto data generated.' >/dev/null
permissions=$(unshare --user --map-root-user stat -c '%a %u:%g' \
"$directory" "$certificate" "$key")
expected_permissions='750 0:0
644 0:0
640 0:0'
if [ "$permissions" != "$expected_permissions" ]; then
printf 'FAIL TLS permissions:\n%s\n' "$permissions" >&2
exit 1
fi
information=$(certtool --certificate-info --infile "$certificate" 2>&1)
for expected in \
'Version: 3' \
'Algorithm Security Level: High (3072 bits)' \
'DNSname: mail.bongo.test' \
'DNSname: smtp.bongo.test' \
'Certificate Authority (CA): FALSE' \
'Digital signature.' \
'Key encipherment.' \
'TLS WWW Server.' \
'Signature Algorithm: RSA-SHA256'; do
if ! printf '%s' "$information" | grep -F "$expected" >/dev/null; then
printf 'FAIL generated certificate lacks: %s\n' "$expected" >&2
exit 1
fi
done
certificate_id=$(certtool --pubkey-info --load-certificate "$certificate" 2>&1 |
sed -n 's/^[[:space:]]*sha256://p' | head -n 1)
key_id=$(certtool --pubkey-info --load-privkey "$key" 2>&1 |
sed -n 's/^[[:space:]]*sha256://p' | head -n 1)
if [ -z "$certificate_id" ] || [ "$certificate_id" != "$key_id" ]; then
echo 'FAIL generated certificate and private key do not match' >&2
exit 1
fi
first_hashes=$(sha256sum "$certificate" "$key")
run_crypto | grep -F 'Reusing existing TLS certificate and key' >/dev/null
second_hashes=$(sha256sum "$certificate" "$key")
if [ "$first_hashes" != "$second_hashes" ]; then
echo 'FAIL a valid existing TLS pair was replaced' >&2
exit 1
fi
printf 'PASS generated TLS material and byte-identical reuse\n'
cp "$certificate" "$good_certificate"
cp "$key" "$good_key"
certtool --generate-privkey --key-type rsa --bits 3072 \
--outfile "$wrong_key" >/dev/null 2>&1
chmod 0640 "$wrong_key"
cp "$wrong_key" "$key"
expect_failure 'mismatched private key' 'do not form a valid pair'
restore_pair
rm -f "$key"
expect_failure 'incomplete pair' 'Unsafe or incomplete TLS key pair'
restore_pair
chmod 0666 "$key"
expect_failure 'unsafe private-key mode' 'Unsafe or incomplete TLS key pair'
restore_pair
rm -f "$key"
ln -s "$good_key" "$key"
expect_failure 'private-key symlink' 'Unsafe or incomplete TLS key pair'
restore_pair
rm -f "$certificate"
ln -s "$good_certificate" "$certificate"
expect_failure 'certificate symlink' 'Unsafe or incomplete TLS key pair'
restore_pair
printf '%s\n' 'not a certificate' >"$certificate"
expect_failure 'malformed certificate' 'do not form a valid pair'
restore_pair
before=$(sha256sum "$certificate" "$key")
set +e
output=$(unshare --user --map-root-user "$binary" \
--hostname mail.bongo.test --tls-name pop.bongo.test crypto 2>&1)
status=$?
set -e
after=$(sha256sum "$certificate" "$key")
if [ "$status" -ne 6 ] ||
! printf '%s' "$output" |
grep -F 'does not cover DNS name pop.bongo.test' >/dev/null ||
[ "$before" != "$after" ]; then
printf 'FAIL missing SAN: status=%s output=%s\n' "$status" "$output" >&2
exit 1
fi
printf 'PASS missing SAN: rejected without changing input files\n'