178 lines
5.2 KiB
Bash
Executable File
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'
|