diff options
Diffstat (limited to 'tests')
68 files changed, 592 insertions, 141 deletions
diff --git a/tests/auth-login/t b/tests/auth-login/t index 7fd83d5..38e2028 100644 --- a/tests/auth-login/t +++ b/tests/auth-login/t @@ -9,4 +9,4 @@ grep -Fx "remote: C: xxx LOGIN [REDACTED]" <"$STDERR" || error check_mailbox_status "INBOX" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/auth-logindisabled/t b/tests/auth-logindisabled/t index 0bcd0d6..402355f 100644 --- a/tests/auth-logindisabled/t +++ b/tests/auth-logindisabled/t @@ -13,4 +13,4 @@ grep -Fx "LOGINDISABLED" <"$TMPDIR/capabilities" || error grep -Fx "remote: ERROR: Logins are disabled." <"$STDERR" || error ! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/auth-noplaintext/t b/tests/auth-noplaintext/t index 11d7d4d..862bc8d 100644 --- a/tests/auth-noplaintext/t +++ b/tests/auth-noplaintext/t @@ -12,4 +12,4 @@ tr " " "\\n" <"$TMPDIR/capability" >"$TMPDIR/capabilities" grep -Fx "remote: ERROR: Server did not advertise STARTTLS capability." <"$STDERR" || error ! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/auth-sasl-plain-no-ir/t b/tests/auth-sasl-plain-no-ir/t index 17aa9e6..f236ac7 100644 --- a/tests/auth-sasl-plain-no-ir/t +++ b/tests/auth-sasl-plain-no-ir/t @@ -23,4 +23,4 @@ xcgrep "$n" -E "^remote(\(INBOX\))?: C: [0-9]+ APPEND INBOX .* \{[0-9]+\}$" <"$S check_mailbox_status "INBOX" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/auth-sasl-plain/t b/tests/auth-sasl-plain/t index 68f71a9..c5cb024 100644 --- a/tests/auth-sasl-plain/t +++ b/tests/auth-sasl-plain/t @@ -9,4 +9,4 @@ grep -Fx "remote: C: xxx AUTHENTICATE PLAIN [REDACTED]" <"$STDERR" || error check_mailbox_status "INBOX" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/certs/.gitignore b/tests/certs/.gitignore new file mode 100644 index 0000000..8b2d0ad --- /dev/null +++ b/tests/certs/.gitignore @@ -0,0 +1,4 @@ +!/generate +/*.key +/*.crt +/*.pem diff --git a/tests/certs/generate b/tests/certs/generate new file mode 100755 index 0000000..f449764 --- /dev/null +++ b/tests/certs/generate @@ -0,0 +1,57 @@ +#!/bin/sh + +set -ue +PATH="/usr/bin:/bin" +export PATH + +BASEDIR="$(dirname -- "$0")" +OU="InterIMAP test suite" +cd "$BASEDIR" + +OPENSSL_CONF="./openssl.cnf" +export OPENSSL_CONF + +cadir="$(mktemp --tmpdir --directory)" +trap 'rm -rf -- "$cadir"' EXIT INT TERM +genpkey() { + local key="$1" + shift + openssl genpkey -out "$key" "$@" 2>&1 +} + +# generate CA (we intentionally throw away the private key and serial +# file to avoid reuse) +genpkey "$cadir/ca.key" -algorithm RSA +openssl req -new -x509 -rand /dev/urandom \ + -subj "/OU=$OU/CN=Fake Root CA" \ + -addext subjectKeyIdentifier="hash" \ + -addext authorityKeyIdentifier="keyid:always,issuer" \ + -addext basicConstraints="critical,CA:TRUE" \ + -key "$cadir/ca.key" -out ./ca.crt + +SERIAL=1 +new() { + local key="$1" cn="$2" + openssl req -new -rand /dev/urandom -key "$key" \ + -subj "/OU=$OU/CN=$cn" ${3+-addext subjectAltName="$3"} \ + -out "$cadir/new.csr" + cat >"$cadir/new-ext.cnf" <<-EOF + basicConstraints = critical, CA:FALSE + keyUsage = critical, digitalSignature, keyEncipherment + extendedKeyUsage = critical, serverAuth + EOF + if [ -n "${3+x}" ]; then + printf "subjectAltName = %s\\n" "$3" >>"$cadir/new-ext.cnf" + fi + openssl x509 -req -in "$cadir/new.csr" -CA ./ca.crt -CAkey "$cadir/ca.key" \ + -CAserial "$cadir/ca.srl" -CAcreateserial -extfile "$cadir/new-ext.cnf" 2>&1 +} + +genpkey ./dovecot.rsa.key -algorithm RSA +new ./dovecot.rsa.key "localhost" "DNS:localhost,DNS:ip6-localhost,IP:127.0.0.1,IP:::1" >./dovecot.rsa.crt + +genpkey ./dovecot.ecdsa.key -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -pkeyopt ec_param_enc:named_curve +new ./dovecot.ecdsa.key "localhost" >./dovecot.ecdsa.crt + +genpkey ./dovecot.rsa2.key -algorithm RSA +new ./dovecot.rsa2.key "imap.example.net" "DNS:imap.example.net,DNS:localhost" >./dovecot.rsa2.crt diff --git a/tests/certs/openssl.cnf b/tests/certs/openssl.cnf new file mode 100644 index 0000000..b1af7b8 --- /dev/null +++ b/tests/certs/openssl.cnf @@ -0,0 +1,4 @@ +[ req ] +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] diff --git a/tests/compress/t b/tests/compress/t index 5625761..0a04a73 100644 --- a/tests/compress/t +++ b/tests/compress/t @@ -16,4 +16,4 @@ echo "compress = no" >>"$XDG_CONFIG_HOME/interimap/config" interimap --debug || error ! grep -E "^remote: C: [^[:blank:]]+ COMPRESS DEFLATE$" <"$STDERR" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/condstore/t b/tests/condstore/t index 1963b2b..b30ca36 100644 --- a/tests/condstore/t +++ b/tests/condstore/t @@ -47,4 +47,4 @@ for f in "${FLAGS[@]}"; do error "UID list differs for keyword '$f'" done -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/snippets/dovecot/dhparams.pem b/tests/config/dovecot/dhparams.pem index 7734d2a..7734d2a 100644 --- a/tests/snippets/dovecot/dhparams.pem +++ b/tests/config/dovecot/dhparams.pem diff --git a/tests/snippets/dovecot/imapd.conf b/tests/config/dovecot/imapd.conf index 2b26451..2b26451 100644 --- a/tests/snippets/dovecot/imapd.conf +++ b/tests/config/dovecot/imapd.conf diff --git a/tests/snippets/dovecot/interimap-required-capabilities.conf b/tests/config/dovecot/interimap-required-capabilities.conf index 10dd8e1..10dd8e1 100644 --- a/tests/snippets/dovecot/interimap-required-capabilities.conf +++ b/tests/config/dovecot/interimap-required-capabilities.conf diff --git a/tests/snippets/dovecot/lmtpd.conf b/tests/config/dovecot/lmtpd.conf index 6aa8365..6aa8365 100644 --- a/tests/snippets/dovecot/lmtpd.conf +++ b/tests/config/dovecot/lmtpd.conf diff --git a/tests/config/dovecot/ssl.conf b/tests/config/dovecot/ssl.conf new file mode 100644 index 0000000..1f3a698 --- /dev/null +++ b/tests/config/dovecot/ssl.conf @@ -0,0 +1,6 @@ +ssl = required +ssl_cert = <dovecot.rsa.crt +ssl_key = <dovecot.rsa.key +ssl_dh = <dhparams.pem +ssl_min_protocol = TLSv1.2 +ssl_cipher_list = DEFAULT@SECLEVEL=2 diff --git a/tests/db-exclusive-lock/t b/tests/db-exclusive-lock/t index c2df4b5..0d0badb 100644 --- a/tests/db-exclusive-lock/t +++ b/tests/db-exclusive-lock/t @@ -10,7 +10,7 @@ sleep .5 # subsequent runs fail as we can't acquire the exclusive lock ! interimap || error -grep -Fx "DBD::SQLite::db do failed: database is locked at ./interimap line 176." <"$STDERR" \ - || error "Is \$DBH->do(\"PRAGMA locking_mode = EXCLUSIVE\"); at line 176?" +grep -Ex "DBD::SQLite::db do failed: database is locked at (\S+/)?interimap line 181\." <"$STDERR" \ + || error "Is \$DBH->do(\"PRAGMA locking_mode = EXCLUSIVE\"); at line 181?" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/db-migration-0-1-foreign-key-violation/t b/tests/db-migration-0-1-foreign-key-violation/t index 35e5be5..fa4afb4 100644 --- a/tests/db-migration-0-1-foreign-key-violation/t +++ b/tests/db-migration-0-1-foreign-key-violation/t @@ -18,4 +18,4 @@ EOF grep -Fx "Upgrading database version from 0" <"$STDERR" || error "DB upgrade not attempted" grep -Fx "database: ERROR: Broken referential integrity! Refusing to commit changes." <"$STDERR" || error "DB upgrade successful despite broken refint" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/db-no-create--watch/t b/tests/db-no-create--watch/t index a8ea07e..3097558 100644 --- a/tests/db-no-create--watch/t +++ b/tests/db-no-create--watch/t @@ -1,6 +1,6 @@ ! interimap --watch=60 || error -grep -Ex "DBI connect\(.*\) failed: unable to open database file at \./interimap line 172\." <"$STDERR" || error +grep -Ex "DBI connect\(.*\) failed: unable to open database file at (\S+/)?interimap line 177\." <"$STDERR" || error test \! -e "$XDG_DATA_HOME/interimap/remote.db" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/db-upgrade-0-1-delim-mismatch/t b/tests/db-upgrade-0-1-delim-mismatch/t index d133437..c15927c 100644 --- a/tests/db-upgrade-0-1-delim-mismatch/t +++ b/tests/db-upgrade-0-1-delim-mismatch/t @@ -4,4 +4,4 @@ sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <"$TESTDIR/before.sql" || error "Co grep -Fx 'ERROR: Local and remote hierachy delimiters differ (local "\"", remote "^"), refusing to update table `mailboxes`.' <"$STDERR" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/db-upgrade-0-1/t b/tests/db-upgrade-0-1/t index 088008e..2baafe6 100644 --- a/tests/db-upgrade-0-1/t +++ b/tests/db-upgrade-0-1/t @@ -31,4 +31,4 @@ diff -u --label="a/dump.sql" --label="b/dump.sql" \ "$TMPDIR/dump-expected.sql" "$TMPDIR/dump.sql" \ || error "DB dumps differ" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/delete/t b/tests/delete/t index c38d4d3..84fc55f 100644 --- a/tests/delete/t +++ b/tests/delete/t @@ -92,4 +92,4 @@ check_mailbox_list check_mailboxes_status "INBOX" step_done -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/delimiter-change/t b/tests/delimiter-change/t index 3f96953..c49dd66 100644 --- a/tests/delimiter-change/t +++ b/tests/delimiter-change/t @@ -34,4 +34,4 @@ run "." "." n="$(doveadm -u "local" search all | wc -l)" [ "$n" -eq 64 ] || error "$n != 64" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/ignore-mailbox/t b/tests/ignore-mailbox/t index f90227c..0b8d553 100644 --- a/tests/ignore-mailbox/t +++ b/tests/ignore-mailbox/t @@ -59,4 +59,4 @@ EOF check_mailboxes_status "virtual" "virtual.bar" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/list b/tests/interimap.list index db77f50..559daed 100644 --- a/tests/list +++ b/tests/interimap.list @@ -51,13 +51,13 @@ split-set Split large sets to avoid extra-long command lines tls SSL/TLS handshake ... tls-verify-peer tls-pin-fingerprint pubkey fingerprint pinning + tls-rsa+ecdsa pubkey fingerprint pinning for dual-cert RSA+ECDSA + tls-sni TLS servername extension (SNI) tls-protocols force TLS protocol versions + tls-ciphers force TLS cipher list/suites . Live synchronization (60s) sync-live local/remote simulation sync-live-crippled local/remote simulation (crippled remote) sync-live-tls local/remote simulation (TLS remote) sync-live-multi local/remote1+remote2+remote3 simulation (3 local namespaces) - -. pullimap - ... pullimap diff --git a/tests/largeint/t b/tests/largeint/t index b0877d5..c3f349e 100644 --- a/tests/largeint/t +++ b/tests/largeint/t @@ -36,4 +36,4 @@ doveadm -u "remote" mailbox update --min-next-uid 2147483648 --min-highest-modse run -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/list-mailbox/t b/tests/list-mailbox/t index e905537..a1168a6 100644 --- a/tests/list-mailbox/t +++ b/tests/list-mailbox/t @@ -54,4 +54,4 @@ for v in '""' '"f o o""bar"' '"f o o" "bar" "baz\" x'; do grep -xF "Invalid value for list-mailbox: $v" <"$STDERR" done -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/list-reference/t b/tests/list-reference/t index a2cc9c7..12e112b 100644 --- a/tests/list-reference/t +++ b/tests/list-reference/t @@ -44,4 +44,4 @@ verify ! doveadm -u "local" mailbox status uidvalidity "foobaz" || error ! doveadm -u "remote" mailbox status uidvalidity "foobar" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/list-select-opts/t b/tests/list-select-opts/t index 98acb43..30c3fe9 100644 --- a/tests/list-select-opts/t +++ b/tests/list-select-opts/t @@ -53,4 +53,4 @@ grep -Fx "remote: Created mailbox foo" <"$STDERR" || error check_mailbox_list check_mailboxes_status "INBOX" "foo" "foo.bar" "bar" "baz" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/preauth-plaintext/imapd b/tests/preauth-plaintext/imapd index 8f3ac30..bf2ed72 100755 --- a/tests/preauth-plaintext/imapd +++ b/tests/preauth-plaintext/imapd @@ -18,7 +18,7 @@ while (1) { die "accept: $!"; }; - # minimum CAPABILITY list, see tests/snippets/dovecot/interimap-required-capabilities.conf + # minimum CAPABILITY list, see tests/config/dovecot/interimap-required-capabilities.conf $conn->printflush("* PREAUTH [CAPABILITY IMAP4rev1 ENABLE UIDPLUS LIST-EXTENDED QRESYNC LIST-STATUS] IMAP4rev1 Server\r\n"); my $x; @@ -39,6 +39,6 @@ while (1) { END { if (defined $S) { shutdown($S, SHUT_RDWR) or warn "shutdown: $!"; - close($S) or print STDERR "Can't close: $!\n"; + close($S) or print STDERR "close: $!\n"; } } diff --git a/tests/preauth-plaintext/t b/tests/preauth-plaintext/t index 427d57b..2f3071f 100644 --- a/tests/preauth-plaintext/t +++ b/tests/preauth-plaintext/t @@ -10,10 +10,10 @@ grep -Fx 'remote: ERROR: PREAUTH greeting on plaintext connection? MiTM in actio ! grep '^remote: C: ' <"$STDERR" || error "wrote command in MiTM'ed PREAUTH connection!" -# Ignore the warning when STARTTLS is explicitely disabled +# Ignore the warning when STARTTLS is explicitly disabled echo "STARTTLS = NO" >>"$XDG_CONFIG_HOME/interimap/config" interimap --debug || true grep -Fx "remote: S: * STATUS INBOX (UIDNEXT 1 UIDVALIDITY 1 HIGHESTMODSEQ 1)" <"$STDERR" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/pullimap.list b/tests/pullimap.list new file mode 100644 index 0000000..f4304b9 --- /dev/null +++ b/tests/pullimap.list @@ -0,0 +1,2 @@ +. pullimap + ... pullimap diff --git a/tests/pullimap/t b/tests/pullimap/t index 0dfe634..879c5d1 100644 --- a/tests/pullimap/t +++ b/tests/pullimap/t @@ -6,6 +6,13 @@ step_start "\`pullimap --idle\` refuses to create the state file" ! pullimap --idle "remote" || error step_done +step_start "\`pullimap\` creates statefile with mode 0600" +pullimap "remote" || error +if ! st="$(stat -c"%#a" -- "$XDG_DATA_HOME/pullimap/remote")" || [ "$st" != "0600" ]; then + error "$XDG_DATA_HOME/pullimap/remote has mode $st != 0600" +fi +step_done + # compare mailboxes (can't compare the RFC 3501 TEXT as the LMTPd inconditionally # adds a Return-Path: header -- and also Delivered-To: and Received: to by default) list_mails_sha256() { @@ -104,29 +111,31 @@ doveadm -u "remote" search mailbox "$MAILBOX" unseen >"$TMPDIR/unseen" step_done -step_start "--idle (${TIMEOUT}s)" +if [ $TIMEOUT -gt 0 ]; then + step_start "--idle (${TIMEOUT}s)" -pullimap --idle "remote" & PID=$! -trap "ptree_abort $PID" EXIT INT TERM + pullimap --idle "remote" & PID=$! + trap "ptree_abort $PID" EXIT INT TERM -timer=$(( $(date +%s) + TIMEOUT )) -while [ $(date +%s) -le $timer ]; do - n="$(shuf -n1 -i1-5)" - for (( i=0; i < n; i++)); do - sample_message | deliver -u "remote" -- -m "$MAILBOX" - done + timer=$(( $(date +%s) + TIMEOUT )) + while [ $(date +%s) -le $timer ]; do + n="$(shuf -n1 -i1-5)" + for (( i=0; i < n; i++)); do + sample_message | deliver -u "remote" -- -m "$MAILBOX" + done - s=$(shuf -n1 -i1-1500) - [ $s -ge 1000 ] && s="$(printf "1.%03d" $((s-1000)))" || s="$(printf "0.%03d" $s)" - sleep "$s" -done + s=$(shuf -n1 -i1-1500) + [ $s -ge 1000 ] && s="$(printf "1.%03d" $((s-1000)))" || s="$(printf "0.%03d" $s)" + sleep "$s" + done -sleep 5 -ptree_abort $PID -trap - EXIT INT TERM + sleep 5 + ptree_abort $PID + trap - EXIT INT TERM -check -step_done + check + step_done +fi step_start "Purging" @@ -140,4 +149,4 @@ doveadm -u "remote" search mailbox "$MAILBOX" all >"$TMPDIR/messages" [ ! -s "$TMPDIR/messages" ] || error "messages left" step_done -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/rename-exists-db/t b/tests/rename-exists-db/t index cb6cfcd..63d7ba0 100644 --- a/tests/rename-exists-db/t +++ b/tests/rename-exists-db/t @@ -11,4 +11,4 @@ doveadm -u "remote" mailbox delete "t\\o" ! interimap --rename "root.from" "t.o" || error grep -Fx 'database: ERROR: Mailbox t.o exists. Run `interimap --target=database --delete t.o` to delete.' <"$STDERR" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/rename-exists-local/t b/tests/rename-exists-local/t index 190f49a..33c7da7 100644 --- a/tests/rename-exists-local/t +++ b/tests/rename-exists-local/t @@ -10,4 +10,4 @@ doveadm -u "remote" mailbox delete "t\\o" ! interimap --rename "root.from" "t.o" || error grep -Fx 'local: ERROR: Mailbox t.o exists. Run `interimap --target=local --delete t.o` to delete.' <"$STDERR" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/rename-exists-remote/t b/tests/rename-exists-remote/t index be16a12..2e87053 100644 --- a/tests/rename-exists-remote/t +++ b/tests/rename-exists-remote/t @@ -10,4 +10,4 @@ doveadm -u "local" mailbox delete "t.o" ! interimap --rename "root.from" "t.o" || error grep -Fx 'remote: ERROR: Mailbox t\o exists. Run `interimap --target=remote --delete t.o` to delete.' <"$STDERR" || remote -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/rename-inferiors/t b/tests/rename-inferiors/t index 9267e6f..9166230 100644 --- a/tests/rename-inferiors/t +++ b/tests/rename-inferiors/t @@ -97,4 +97,4 @@ check_mailbox_list check_mailboxes_status "from.root" "from.root.child" "from.root.child2" "from.root.child.grandchild" \ "newroot.sibbling" "newroot.sibbling.grandchild" "root2" "INBOX" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/rename-simple/t b/tests/rename-simple/t index 6ebee9a..df9d84c 100644 --- a/tests/rename-simple/t +++ b/tests/rename-simple/t @@ -58,4 +58,4 @@ grep -Fx "database: Created mailbox INBOX" <"$STDERR" check_mailbox_list check_mailboxes_status "INBOX" "bar" "baz" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/repair/t b/tests/repair/t index 6b205ea..10fab0d 100644 --- a/tests/repair/t +++ b/tests/repair/t @@ -104,4 +104,4 @@ check_mailboxes_status "baz" "foo.bar" interimap || error check_mailboxes_status "baz" "foo.bar" "INBOX" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/resume/t b/tests/resume/t index a281ef3..d7b9b53 100644 --- a/tests/resume/t +++ b/tests/resume/t @@ -95,4 +95,4 @@ diff -u --label="a/count" --label="b/count" "$TMPDIR/count" - <<-EOF 9 EOF -# vim: set filetype=sh : +# vim: set filetype=bash : @@ -35,6 +35,15 @@ if [ ! -d "$TESTDIR" ]; then exit 1 fi +# cleanup environment +unset OPENSSL_CONF SSL_CERT_FILE SSL_CERT_DIR + +if [ -z "${INTERIMAP_PATH+x}" ]; then + INTERIMAP_PATH="./" +elif [ -n "$INTERIMAP_PATH" ]; then + INTERIMAP_PATH="${INTERIMAP_PATH%/}/" +fi + ROOTDIR="$(mktemp --tmpdir="${TMPDIR:-/dev/shm}" --directory "$1.XXXXXXXXXX")" declare -a DOVECOT_SERVER=() trap cleanup EXIT INT TERM @@ -93,7 +102,7 @@ prepare() { mail_location = dbox:~/inbox:LAYOUT=index mailbox_list_index = yes ssl = no - listen = 127.0.0.1, ::1 + listen = 127.0.0.1, 127.0.1.1, ::1 namespace inbox { inbox = yes } @@ -101,7 +110,8 @@ prepare() { if [ -f "$TESTDIR/$u.conf" ] || [ -L "$TESTDIR/$u.conf" ]; then cat >>"$home/.dovecot/config" <"$TESTDIR/$u.conf" fi - cp -aT -- "$BASEDIR/snippets/dovecot" "$home/.dovecot/conf.d" + cp -aT -- "$BASEDIR/config/dovecot" "$home/.dovecot/conf.d" + cp -at "$home/.dovecot/conf.d" -- "$BASEDIR/certs/ca.crt" "$BASEDIR/certs"/dovecot.* proto="$(env -i "${ENVIRON[@]}" doveconf -c "$home/.dovecot/config" -h protocols)" if [ -n "$proto" ]; then @@ -202,23 +212,32 @@ prepare interimap() { _interimap_cmd "interimap" "$@"; } pullimap() { _interimap_cmd "pullimap" "$@"; } _interimap_cmd() { - declare -a ENVIRON=() + declare -a ENVIRON=() args=() local script="$1" rv=0 shift environ_set "local" - env -i "${ENVIRON[@]}" perl -I./lib -T "./$script" "$@" 2>"$STDERR" || rv=$? + [ -z "${OPENSSL_CONF+x}" ] || ENVIRON+=( OPENSSL_CONF="$OPENSSL_CONF" ) + [ -z "${SSL_CERT_FILE+x}" ] || ENVIRON+=( SSL_CERT_FILE="$SSL_CERT_FILE" ) + [ -z "${SSL_CERT_DIR+x}" ] || ENVIRON+=( SSL_CERT_DIR="$SSL_CERT_DIR" ) + [ -z "${INTERIMAP_I:+x}" ] || args+=( perl -I"$INTERIMAP_I" -T ) + args+=( "$INTERIMAP_PATH$script" "$@" ) + #printf "I: Running \`%s\`\\n" "${args[*]}" >&3 + env -i "${ENVIRON[@]}" "${args[@]}" 2>"$STDERR" || rv=$? cat <"$STDERR" >&2 return $rv } interimap_init() { local u="${1-remote}" - local db="$XDG_DATA_HOME/interimap/$u.db" + local db="$XDG_DATA_HOME/interimap/$u.db" st local cfg="config${u#remote}" test \! -e "$db" || error "Database already exists" 1 interimap --config "$cfg" || error "Couldn't initialize interimap" 1 test -f "$db" || error "Database is still missing" 1 grep -Fx "Creating new schema in database file $db" <"$STDERR" || error "DB wasn't created" 1 + if ! st="$(stat -c"%#a" -- "$db")" || [ "$st" != "0600" ]; then + error "$db has mode $st != 0600" 1 + fi } doveadm() { if [ $# -le 2 ] || [ "$1" != "-u" ]; then @@ -442,7 +461,7 @@ passed() { # Run test in a sub-shell declare -a ENVIRON=() environ_set "local" -export TMPDIR TESTDIR STDERR "${ENVIRON[@]}" +export TMPDIR TESTDIR INTERIMAP_PATH INTERIMAP_I STDERR "${ENVIRON[@]}" export -f environ_set doveadm interimap interimap_init pullimap _interimap_cmd export -f sqlite3 sample_message deliver ptree_abort step_start step_done passed export -f check_mailbox_status check_mailbox_status_values check_mailbox_status2 diff --git a/tests/run-all b/tests/run-all index d13f689..79e62d1 100755 --- a/tests/run-all +++ b/tests/run-all @@ -24,6 +24,7 @@ export PATH BASEDIR="$(dirname -- "$0")" RUN="$BASEDIR/run" +list="$1" failed=0 @@ -54,7 +55,7 @@ while IFS="" read -r x; do fi INDENT="$indent" "$RUN" "$t" ${desc+"$desc"} || failed=$(( failed+1 )) -done <"$BASEDIR/list" +done <"$BASEDIR/$list" if [ $failed -eq 0 ]; then printf "All tests passed.\\n" diff --git a/tests/snippets/dovecot/dovecot.key b/tests/snippets/dovecot/dovecot.key deleted file mode 100644 index 95c9846..0000000 --- a/tests/snippets/dovecot/dovecot.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIGkqkKq69zVeF17S3y2U2HkQWh8z9M/xeblCztkKIfzJoAoGCCqGSM49 -AwEHoUQDQgAE1LLppulKw8KjINrDhOjEd0NTax5iDCds+vpA2PwsvvtGoprNAjQM -zX+40u30N3CE0r591txqohSBQ/X+nvG2ug== ------END EC PRIVATE KEY----- diff --git a/tests/snippets/dovecot/dovecot.pem b/tests/snippets/dovecot/dovecot.pem deleted file mode 100644 index 7e53d90..0000000 --- a/tests/snippets/dovecot/dovecot.pem +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBkzCCATmgAwIBAgIUQ+3hBMsPJcl59xDDujDDfexurOswCgYIKoZIzj0EAwIw -HzEdMBsGA1UEAwwUSW50ZXJJTUFQIHRlc3Qgc3VpdGUwHhcNMTkxMTEwMTM1NDAw -WhcNMjkxMTA3MTM1NDAwWjAfMR0wGwYDVQQDDBRJbnRlcklNQVAgdGVzdCBzdWl0 -ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNSy6abpSsPCoyDaw4ToxHdDU2se -YgwnbPr6QNj8LL77RqKazQI0DM1/uNLt9DdwhNK+fdbcaqIUgUP1/p7xtrqjUzBR -MB0GA1UdDgQWBBRlh8nSwyX+VlhwuhV7RKYwvKLyDzAfBgNVHSMEGDAWgBRlh8nS -wyX+VlhwuhV7RKYwvKLyDzAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gA -MEUCIQDK8xPPHTbYW5JnZ1Siy8ChZ6GOu2sRwQu7OgtGYGZRSQIgFKn1oAhnq2Oi -aIPqxjvBPMsK/sjrdI/rNsr2XgaulU4= ------END CERTIFICATE----- diff --git a/tests/snippets/dovecot/ssl.conf b/tests/snippets/dovecot/ssl.conf deleted file mode 100644 index 240f24b..0000000 --- a/tests/snippets/dovecot/ssl.conf +++ /dev/null @@ -1,4 +0,0 @@ -ssl = required -ssl_cert = <dovecot.pem -ssl_key = <dovecot.key -ssl_dh = <dhparams.pem diff --git a/tests/split-set/t b/tests/split-set/t index 5e8ea52..d8cf948 100644 --- a/tests/split-set/t +++ b/tests/split-set/t @@ -40,4 +40,4 @@ done interimap || error check_mailbox_status "INBOX" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/starttls-injection/imapd b/tests/starttls-injection/imapd index 9000c8d..52cbe9a 100755 --- a/tests/starttls-injection/imapd +++ b/tests/starttls-injection/imapd @@ -4,7 +4,7 @@ use warnings; use strict; use Errno qw/EINTR/; -use Net::SSLeay qw/die_now die_if_ssl_error/; +use Net::SSLeay qw/die_now/; use Socket qw/INADDR_LOOPBACK AF_INET SOCK_STREAM pack_sockaddr_in SOL_SOCKET SO_REUSEADDR SHUT_RDWR/; @@ -20,16 +20,16 @@ bind($S, pack_sockaddr_in(10143, INADDR_LOOPBACK)) or die "bind: $!\n"; listen($S, 1) or die "listen: $!"; my $CONFDIR = $ENV{HOME} =~ /\A(\p{Print}+)\z/ ? "$1/.dovecot/conf.d" : die; -my $CTX = Net::SSLeay::CTX_new() or die_now("SSL_CTX_new"); +my $CTX = Net::SSLeay::CTX_new() or die_now("SSL_CTX_new()"); Net::SSLeay::CTX_set_mode($CTX, Net::SSLeay::MODE_ENABLE_PARTIAL_WRITE() | Net::SSLeay::MODE_ACCEPT_MOVING_WRITE_BUFFER() | Net::SSLeay::MODE_AUTO_RETRY() | # don't fail SSL_read on renegotiation Net::SSLeay::MODE_RELEASE_BUFFERS() ); -Net::SSLeay::CTX_use_PrivateKey_file($CTX, "$CONFDIR/dovecot.key", &Net::SSLeay::FILETYPE_PEM) - or die_if_ssl_error("Can't load private key: $!"); -Net::SSLeay::CTX_use_certificate_file($CTX, "$CONFDIR/dovecot.pem", &Net::SSLeay::FILETYPE_PEM) - or die_if_ssl_error("Can't load certificate: $!"); +Net::SSLeay::CTX_use_PrivateKey_file($CTX, "$CONFDIR/dovecot.rsa.key", &Net::SSLeay::FILETYPE_PEM) + or die_now("Can't load private key: $!"); +Net::SSLeay::CTX_use_certificate_file($CTX, "$CONFDIR/dovecot.rsa.crt", &Net::SSLeay::FILETYPE_PEM) + or die_now("Can't load certificate: $!"); while (1) { my $sockaddr = accept(my $conn, $S) or do { @@ -52,14 +52,14 @@ while (1) { $conn->printf("%06d OK CAPABILITY injected\r\n", $1+1); $conn->flush(); - my $ssl = Net::SSLeay::new($CTX) or die_if_ssl_error("SSL_new"); - Net::SSLeay::set_fd($ssl, $conn) or die_if_ssl_error("SSL_set_fd"); - Net::SSLeay::accept($ssl) and die_if_ssl_error("SSL_accept"); + my $ssl = Net::SSLeay::new($CTX) or die_now("SSL_new()"); + die_now("SSL_set_fd()") unless Net::SSLeay::set_fd($ssl, $conn) == 1; + die_now("SSL_accept()") unless Net::SSLeay::accept($ssl); - Net::SSLeay::ssl_read_CRLF($ssl) =~ /\A(\S+) CAPABILITY\r\n\z/ or die_now("SSL_read"); + Net::SSLeay::ssl_read_CRLF($ssl) =~ /\A(\S+) CAPABILITY\r\n\z/ or die_now("SSL_read()"); Net::SSLeay::ssl_write_CRLF($ssl, "* CAPABILITY IMAP4rev1 AUTH=LOGIN\r\n$1 OK CAPABILITY completed"); - Net::SSLeay::ssl_read_CRLF($ssl) =~ /\A(\S+) LOGIN .*\r\n\z/ or die_now("SSL_read"); + Net::SSLeay::ssl_read_CRLF($ssl) =~ /\A(\S+) LOGIN .*\r\n\z/ or die_now("SSL_read()"); Net::SSLeay::ssl_write_CRLF($ssl, "$1 OK [CAPABILITY IMAP4rev1] LOGIN completed"); Net::SSLeay::free($ssl); @@ -72,6 +72,6 @@ END { Net::SSLeay::CTX_free($CTX) if defined $CTX; if (defined $S) { shutdown($S, SHUT_RDWR) or warn "shutdown: $!"; - close($S) or print STDERR "Can't close: $!\n"; + close($S) or print STDERR "close: $!\n"; } } diff --git a/tests/starttls-injection/t b/tests/starttls-injection/t index d57aa7a..023baff 100644 --- a/tests/starttls-injection/t +++ b/tests/starttls-injection/t @@ -13,4 +13,4 @@ grep -Fx 'remote: WARNING: Truncating non-empty output buffer (unauthenticated r ! grep -Fx 'remote: ERROR: Logins are disabled.' <"$STDERR" || error "injected capability wasn't ignored" grep -Fx 'remote: ERROR: Server did not advertise ENABLE (RFC 5161) capability.' <"$STDERR" || error "injected capability wasn't ignored" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/starttls-logindisabled/t b/tests/starttls-logindisabled/t index 0ac7465..b2bf87b 100644 --- a/tests/starttls-logindisabled/t +++ b/tests/starttls-logindisabled/t @@ -16,4 +16,4 @@ grep -Fx "remote: C: 000001 CAPABILITY" <"$STDERR" || error # can't go further as the capability string still has the manually # enforced 'LOGINDISABLED' -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/starttls/t b/tests/starttls/t index 99a39c2..7b76469 100644 --- a/tests/starttls/t +++ b/tests/starttls/t @@ -1,3 +1,7 @@ +X509_SHA256="$(doveconf -c "$HOME_remote/.dovecot/config" -hx ssl_cert \ + | openssl x509 -in /dev/stdin -noout -fingerprint -sha256 \ + | sed -rn "/^.*=\\s*/ {s///p;q}" | tr -d : | tr "[A-Z]" "[a-z]")" + for ((i = 0; i < 32; i++)); do u="$(shuf -n1 -e "local" "remote")" sample_message | deliver -u "$u" @@ -17,11 +21,10 @@ grep -Fx "STARTTLS" <"$TMPDIR/capabilities" || error grep -Fx "remote: C: 000000 STARTTLS" <"$STDERR" || error grep -Fx "remote: C: 000001 CAPABILITY" <"$STDERR" || error -grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1" <"$STDERR" || error -grep -Fx "remote: Peer certificate fingerprint: sha256\$35944e3bd3300d3ac310bb497a32cc1eef6931482a587ddbc95343740cdf1323" <"$STDERR" || error -grep "^remote: SSL protocol: TLSv1\.[23] " <"$STDERR" || error +grep -Fx "remote: Peer certificate fingerprint: sha256\$$X509_SHA256" <"$STDERR" || error +grep "^remote: SSL protocol: TLSv" <"$STDERR" || error grep "^remote: SSL cipher: " <"$STDERR" || error check_mailbox_status "INBOX" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/sync-live-multi/t b/tests/sync-live-multi/t index ba7f326..b91cedc 100644 --- a/tests/sync-live-multi/t +++ b/tests/sync-live-multi/t @@ -124,4 +124,4 @@ for m in "${MAILBOXES[@]}"; do check_mailbox_status2 "$blob" "$m" "$u" "$mr" done -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/sync-live/t b/tests/sync-live/t index 5f5b291..1d50b00 100644 --- a/tests/sync-live/t +++ b/tests/sync-live/t @@ -73,4 +73,4 @@ trap - EXIT INT TERM check_mailbox_list check_mailboxes_status "${MAILBOXES[@]}" -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/sync-mailbox-list/t b/tests/sync-mailbox-list/t index ea80fbf..d1567fb 100644 --- a/tests/sync-mailbox-list/t +++ b/tests/sync-mailbox-list/t @@ -90,4 +90,4 @@ EOF [ $(< "$TMPDIR/count") -eq 0 ] || error step_done -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/tls-ciphers/interimap.remote b/tests/tls-ciphers/interimap.remote new file mode 120000 index 0000000..daf3741 --- /dev/null +++ b/tests/tls-ciphers/interimap.remote @@ -0,0 +1 @@ +../tls/interimap.remote
\ No newline at end of file diff --git a/tests/tls-ciphers/remote.conf b/tests/tls-ciphers/remote.conf new file mode 120000 index 0000000..6029749 --- /dev/null +++ b/tests/tls-ciphers/remote.conf @@ -0,0 +1 @@ +../tls/remote.conf
\ No newline at end of file diff --git a/tests/tls-ciphers/t b/tests/tls-ciphers/t new file mode 100644 index 0000000..ca0e610 --- /dev/null +++ b/tests/tls-ciphers/t @@ -0,0 +1,31 @@ +# backup config +install -m0600 "$XDG_CONFIG_HOME/interimap/config" "$XDG_CONFIG_HOME/interimap/config~" +with_remote_config() { + install -m0600 "$XDG_CONFIG_HOME/interimap/config~" "$XDG_CONFIG_HOME/interimap/config" + cat >>"$XDG_CONFIG_HOME/interimap/config" +} + +with_remote_config <<-EOF + SSL_protocol_max = TLSv1.2 + SSL_cipherlist = DHE-RSA-AES128-SHA256:ALL:!COMPLEMENTOFDEFAULT:!eNULL +EOF +interimap --debug || error +grep -Fx "remote: SSL cipher: DHE-RSA-AES128-SHA256 (128 bits)" <"$STDERR" || error + +with_remote_config <<-EOF + SSL_protocol_max = TLSv1.2 + SSL_cipherlist = NONEXISTENT:ECDHE-RSA-AES256-SHA384:ALL:!COMPLEMENTOFDEFAULT:!eNULL + SSL_ciphersuites = TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256 +EOF +interimap --debug || error +grep -Fx "remote: SSL cipher: ECDHE-RSA-AES256-SHA384 (256 bits)" <"$STDERR" || error + +with_remote_config <<-EOF + SSL_protocol_min = TLSv1.3 + SSL_cipherlist = DHE-RSA-AES128-SHA256 + SSL_ciphersuites = TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256 +EOF +interimap --debug || error +grep -Fx "remote: SSL cipher: TLS_CHACHA20_POLY1305_SHA256 (256 bits)" <"$STDERR" || error + +# vim: set filetype=bash : diff --git a/tests/tls-pin-fingerprint/t b/tests/tls-pin-fingerprint/t index 1b84390..6c045a1 100644 --- a/tests/tls-pin-fingerprint/t +++ b/tests/tls-pin-fingerprint/t @@ -1,3 +1,10 @@ +PKEY_SHA256="$(doveconf -c "$HOME_remote/.dovecot/config" -hx ssl_cert \ + | openssl x509 -in /dev/stdin -pubkey \ + | openssl pkey -in /dev/stdin -pubin -outform DER \ + | openssl dgst -sha256 | sed -rn "/^.*=\\s*/ {s///p;q}")" +INVALID_FPR="sha256\$deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" +INVALID_FPR2="sha256\$deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbee2" + # backup config install -m0600 "$XDG_CONFIG_HOME/interimap/config" "$XDG_CONFIG_HOME/interimap/config~" with_remote_config() { @@ -7,7 +14,7 @@ with_remote_config() { # pinned valid fingerprint with_remote_config <<-EOF - SSL_fingerprint = sha256\$e8fc8d03ffe75e03897136a2f1c5647bf8c36be7136a6883a732a8c4961c1614 + SSL_fingerprint = sha256\$$PKEY_SHA256 EOF for ((i = 0; i < 32; i++)); do @@ -18,16 +25,54 @@ interimap_init check_mailbox_status "INBOX" +# with default algorithm (SHA256) +with_remote_config <<-EOF + SSL_fingerprint = $INVALID_FPR $PKEY_SHA256 +EOF +interimap --debug || error +grep -Fx "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_SHA256" <"$STDERR" || error + + # and now an invalid one with_remote_config <<-EOF - SSL_fingerprint = sha256\$deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef + SSL_fingerprint = $INVALID_FPR +EOF +! interimap --debug || error + +grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error +grep -Fx "remote: WARNING: Fingerprint doesn't match! MiTM in action?" <"$STDERR" || error +grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error +# make sure we didn't send any credentials or started speaking IMAP +! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error +grep -Fx "remote: IMAP traffic (bytes): recv 0 sent 0" <"$STDERR" || error + +# two invalid ones +with_remote_config <<-EOF + SSL_fingerprint = $INVALID_FPR $INVALID_FPR2 EOF ! interimap --debug || error grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error grep -Fx "remote: WARNING: Fingerprint doesn't match! MiTM in action?" <"$STDERR" || error grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error -# make sure we didn't send any credentials +# make sure we didn't send any credentials or started speaking IMAP ! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error +grep -Fx "remote: IMAP traffic (bytes): recv 0 sent 0" <"$STDERR" || error + + +# valid + invalid +with_remote_config <<-EOF + SSL_fingerprint = sha256\$$PKEY_SHA256 $INVALID_FPR +EOF +interimap --debug || error +grep -Fx "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_SHA256" <"$STDERR" || error + + +# invalid + valid +with_remote_config <<-EOF + SSL_fingerprint = $INVALID_FPR sha256\$$PKEY_SHA256 +EOF +interimap --debug || error +grep -Fx "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_SHA256" <"$STDERR" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/tls-protocols/openssl.cnf b/tests/tls-protocols/openssl.cnf new file mode 100644 index 0000000..3d9769d --- /dev/null +++ b/tests/tls-protocols/openssl.cnf @@ -0,0 +1,14 @@ +# as we want to test TLSv1 we need to set MinProtocol=None, see +# see /usr/share/doc/libssl1.1/NEWS.Debian.gz + +openssl_conf = default_conf + +[default_conf] +ssl_conf = ssl_sect + +[ssl_sect] +system_default = system_default_sect + +[system_default_sect] +MinProtocol = None +CipherString = DEFAULT@SECLEVEL=0 diff --git a/tests/tls-protocols/remote.conf b/tests/tls-protocols/remote.conf index 6029749..96b3713 120000..100644 --- a/tests/tls-protocols/remote.conf +++ b/tests/tls-protocols/remote.conf @@ -1 +1,4 @@ -../tls/remote.conf
\ No newline at end of file +!include conf.d/imapd.conf +!include conf.d/ssl.conf +ssl_min_protocol = TLSv1 +ssl_cipher_list = DEFAULT@SECLEVEL=0 diff --git a/tests/tls-protocols/t b/tests/tls-protocols/t index f34a95b..b78dd69 100644 --- a/tests/tls-protocols/t +++ b/tests/tls-protocols/t @@ -1,3 +1,13 @@ +# system default +interimap --debug || error +! grep -E "^remote: Disabling SSL protocols: " <"$STDERR" || error # TODO deprecated +! grep -E "^remote: Minimum SSL/TLS protocol version: " <"$STDERR" || error +! grep -E "^remote: Maximum SSL/TLS protocol version: " <"$STDERR" || error +grep -E "^remote: SSL protocol: TLSv" <"$STDERR" || error + +# load custom OpenSSL configuration to allow TLS protocol version <=1.1 +export OPENSSL_CONF="$TESTDIR/openssl.cnf" + # backup config install -m0600 "$XDG_CONFIG_HOME/interimap/config" "$XDG_CONFIG_HOME/interimap/config~" with_remote_tls_protocols() { @@ -5,17 +15,15 @@ with_remote_tls_protocols() { printf "SSL_protocols = %s\\n" "$*" >>"$XDG_CONFIG_HOME/interimap/config" } -# default -interimap --debug || error -grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1" <"$STDERR" || error -grep -E "^remote: SSL protocol: TLSv1\.[23] " <"$STDERR" || error - -# also disable TLSv1.2 +# disable TLSv1.2 and earlier with_remote_tls_protocols "!SSLv2" "!SSLv3" "!TLSv1" "!TLSv1.1" "!TLSv1.2" interimap --debug || error grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1, TLSv1.2" <"$STDERR" || error grep -E "^remote: SSL protocol: TLSv1\.3 " <"$STDERR" || error +interimap || error +grep -E "^remote: WARNING: SSL_protocols is deprecated " <"$STDERR" || error "no deprecation warning" + # force TLSv1.2 with_remote_tls_protocols "TLSv1.2" interimap --debug || error @@ -28,12 +36,64 @@ interimap --debug || error grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1.3" <"$STDERR" || error grep -E "^remote: SSL protocol: TLSv(1\.[12])? " <"$STDERR" || error -# force SSLv2 and SSLv3, fails as it's disabled server side +# force SSLv2 and SSLv3; this fails due to dovecot's ssl_min_protocol=TLSv1 with_remote_tls_protocols "SSLv2" "SSLv3" ! interimap --debug || error grep -Fx "remote: Disabling SSL protocols: TLSv1, TLSv1.1, TLSv1.2, TLSv1.3" <"$STDERR" || error grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error -# make sure we didn't send any credentials +# make sure we didn't send any credentials or started speaking IMAP +! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error +grep -Fx "remote: IMAP traffic (bytes): recv 0 sent 0" <"$STDERR" || error + + +# new interface: SSL_protocol_{min,max} +with_remote_tls_protocol_min_max() { + install -m0600 "$XDG_CONFIG_HOME/interimap/config~" "$XDG_CONFIG_HOME/interimap/config" + if [ -n "${1-}" ]; then + printf "SSL_protocol_min = %s\\n" "$1" >>"$XDG_CONFIG_HOME/interimap/config" + fi + if [ -n "${2-}" ]; then + printf "SSL_protocol_max = %s\\n" "$2" >>"$XDG_CONFIG_HOME/interimap/config" + fi +} + +# disable TLSv1.2 and earlier +# XXX this test assumes that TLSv1.3 is the highest version supported +with_remote_tls_protocol_min_max "TLSv1.3" +interimap --debug || error +grep -Fx "remote: Minimum SSL/TLS protocol version: TLSv1.3" <"$STDERR" || error +! grep -E "^remote: Maximum SSL/TLS protocol version: " <"$STDERR" || error +grep -E "^remote: SSL protocol: TLSv1\.3 " <"$STDERR" || error + +# force TLSv1.2 +with_remote_tls_protocol_min_max "TLSv1.2" "TLSv1.2" +interimap --debug || error +grep -Fx "remote: Minimum SSL/TLS protocol version: TLSv1.2" <"$STDERR" || error +grep -Fx "remote: Maximum SSL/TLS protocol version: TLSv1.2" <"$STDERR" || error +grep -E "^remote: SSL protocol: TLSv1\.2 " <"$STDERR" || error + +# disable TLSv1.2 and later +with_remote_tls_protocol_min_max "" "TLSv1.1" +interimap --debug || error +! grep -E "^remote: Minimum SSL/TLS protocol version: " <"$STDERR" || error +grep -Fx "remote: Maximum SSL/TLS protocol version: TLSv1.1" <"$STDERR" || error +grep -E "^remote: SSL protocol: TLSv1\.1 " <"$STDERR" || error + +# force SSLv3 to to TLSv1.1 +with_remote_tls_protocol_min_max "SSLv3" "TLSv1.1" +interimap --debug || error +grep -Fx "remote: Minimum SSL/TLS protocol version: SSLv3" <"$STDERR" || error +grep -Fx "remote: Maximum SSL/TLS protocol version: TLSv1.1" <"$STDERR" || error +grep -E "^remote: SSL protocol: TLSv1(\.1)? " <"$STDERR" || error + +# force SSLv3; this fails due to dovecot's ssl_min_protocol=TLSv1 +with_remote_tls_protocol_min_max "SSLv3" "SSLv3" +! interimap --debug || error +grep -Fx "remote: Minimum SSL/TLS protocol version: SSLv3" <"$STDERR" || error +grep -Fx "remote: Maximum SSL/TLS protocol version: SSLv3" <"$STDERR" || error +grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error +# make sure we didn't send any credentials or started speaking IMAP ! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error +grep -Fx "remote: IMAP traffic (bytes): recv 0 sent 0" <"$STDERR" || error -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/tls-rsa+ecdsa/interimap.remote b/tests/tls-rsa+ecdsa/interimap.remote new file mode 120000 index 0000000..daf3741 --- /dev/null +++ b/tests/tls-rsa+ecdsa/interimap.remote @@ -0,0 +1 @@ +../tls/interimap.remote
\ No newline at end of file diff --git a/tests/tls-rsa+ecdsa/remote.conf b/tests/tls-rsa+ecdsa/remote.conf new file mode 100644 index 0000000..72ca135 --- /dev/null +++ b/tests/tls-rsa+ecdsa/remote.conf @@ -0,0 +1,5 @@ +!include conf.d/imapd.conf +!include conf.d/ssl.conf + +ssl_alt_cert = <conf.d/dovecot.ecdsa.crt +ssl_alt_key = <conf.d/dovecot.ecdsa.key diff --git a/tests/tls-rsa+ecdsa/t b/tests/tls-rsa+ecdsa/t new file mode 100644 index 0000000..16ec9d9 --- /dev/null +++ b/tests/tls-rsa+ecdsa/t @@ -0,0 +1,57 @@ +doveconf_remote() { + doveconf -c "$HOME_remote/.dovecot/config" -hx "$1" +} +pkey_sha256() { + openssl x509 -in /dev/stdin -pubkey \ + | openssl pkey -in /dev/stdin -pubin -outform DER \ + | openssl dgst -sha256 | sed -rn "/^.*=\\s*/ {s///p;q}" +} +x509_sha256() { + openssl x509 -in /dev/stdin -noout -fingerprint -sha256 \ + | sed -rn "/^.*=\\s*/ {s///p;q}" | tr -d : | tr "[A-Z]" "[a-z]" +} + +PKEY_SHA256="$(doveconf_remote ssl_cert | pkey_sha256)" +X509_SHA256="$(doveconf_remote ssl_cert | x509_sha256)" +PKEY_ALT_SHA256="$(doveconf_remote ssl_alt_cert | pkey_sha256)" +X509_ALT_SHA256="$(doveconf_remote ssl_alt_cert | x509_sha256)" + +# pinned valid fingerprints +cat >>"$XDG_CONFIG_HOME/interimap/config" <<-EOF + SSL_fingerprint = sha256\$$PKEY_SHA256 sha256\$$PKEY_ALT_SHA256 +EOF + +for ((i = 0; i < 32; i++)); do + u="$(shuf -n1 -e "local" "remote")" + sample_message | deliver -u "$u" +done +interimap_init +check_mailbox_status "INBOX" + +interimap --debug || error +# which peer certificate is used is up to libssl +grep -Fx -e "remote: Peer certificate fingerprint: sha256\$$X509_SHA256" \ + -e "remote: Peer certificate fingerprint: sha256\$$X509_ALT_SHA256" \ + <"$STDERR" || error +grep -Fx -e "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_SHA256" \ + -e "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_ALT_SHA256" \ + <"$STDERR" || error + +# force RSA +# XXX we also have to force TLS <=1.2 here as the TLSv1.3 ciphersuites +# don't specify the certificate type (nor key exchange) +cat >>"$XDG_CONFIG_HOME/interimap/config" <<-EOF + SSL_protocol_max = TLSv1.2 + SSL_cipherlist = EECDH+AESGCM+aRSA +EOF +interimap --debug || error +grep -Fx "remote: Peer certificate fingerprint: sha256\$$X509_SHA256" <"$STDERR" || error +grep -Fx "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_SHA256" <"$STDERR" || error + +# force ECDSA +sed -i "s/^SSL_cipherlist\\s*=.*/SSL_cipherlist = EECDH+AESGCM+aECDSA/" -- "$XDG_CONFIG_HOME/interimap/config" +interimap --debug || error +grep -Fx "remote: Peer certificate fingerprint: sha256\$$X509_ALT_SHA256" <"$STDERR" || error +grep -Fx "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_ALT_SHA256" <"$STDERR" || error + +# vim: set filetype=bash : diff --git a/tests/tls-sni/interimap.remote b/tests/tls-sni/interimap.remote new file mode 100644 index 0000000..9f0d521 --- /dev/null +++ b/tests/tls-sni/interimap.remote @@ -0,0 +1,3 @@ +type = imaps +port = 10993 +SSL_verify = no diff --git a/tests/tls-sni/remote.conf b/tests/tls-sni/remote.conf new file mode 100644 index 0000000..4ccfb44 --- /dev/null +++ b/tests/tls-sni/remote.conf @@ -0,0 +1,7 @@ +!include conf.d/imapd.conf +!include conf.d/ssl.conf + +local_name imap.example.net { + ssl_cert = <conf.d/dovecot.rsa2.crt + ssl_key = <conf.d/dovecot.rsa2.key +} diff --git a/tests/tls-sni/t b/tests/tls-sni/t new file mode 100644 index 0000000..0565e49 --- /dev/null +++ b/tests/tls-sni/t @@ -0,0 +1,66 @@ +SERVERNAME="imap.example.net" # cf local_name{} section in the dovecot config +X509_SHA256="$(doveconf -c "$HOME_remote/.dovecot/config" -hx ssl_cert \ + | openssl x509 -in /dev/stdin -noout -fingerprint -sha256 \ + | sed -rn "/^.*=\\s*/ {s///p;q}" | tr -d : | tr "[A-Z]" "[a-z]")" +X509_2_SHA256="$(doveconf -c "$HOME_remote/.dovecot/config" -f lname="$SERVERNAME" -hx ssl_cert \ + | openssl x509 -in /dev/stdin -noout -fingerprint -sha256 \ + | sed -rn "/^.*=\\s*/ {s///p;q}" | tr -d : | tr "[A-Z]" "[a-z]")" + +# check that empty SSL_hostname disables SNI +echo "SSL_hostname =" >>"$XDG_CONFIG_HOME/interimap/config" +interimap --debug || error +! grep "^remote: Using SNI with name " <"$STDERR" || error "Empty SSL_hostname didn't disable SNI" + +# default servername is the host value +sed -i "/^SSL_hostname\\s*=/d" -- "$XDG_CONFIG_HOME/interimap/config" +interimap --debug || error +grep -Fx "remote: Using SNI with name localhost" <"$STDERR" || error "No default SNI" +grep -Fx "remote: Peer certificate fingerprint: sha256\$$X509_SHA256" <"$STDERR" || error + +# verify that SNI is not used when host is an IP +echo "host = __INVALID__" >>"$XDG_CONFIG_HOME/interimap/config" +for ip in "127.0.0.1" "[::1]"; do + sed -i "s/^host\\s*=.*/host = $ip/" -- "$XDG_CONFIG_HOME/interimap/config" + interimap --debug || error + ! grep "^remote: Using SNI with name " <"$STDERR" || error "Using SNI with IP $ip" + grep -Fx "remote: Peer certificate fingerprint: sha256\$$X509_SHA256" <"$STDERR" || error +done + +# verify that SNI actually works (ie we're served the right cert) +sni_ok() { + grep -Fx "remote: Using SNI with name $SERVERNAME" <"$STDERR" || error + grep -Fx "remote: Peer certificate fingerprint: sha256\$$X509_2_SHA256" <"$STDERR" || error +} +echo "SSL_hostname = $SERVERNAME" >>"$XDG_CONFIG_HOME/interimap/config" +interimap --debug || error +sni_ok + + +## make sure SSL_hostname doesn't affect certificate verification ## + +# bad CA, bad host +sed -i "s/^host\\s*=.*/host = 127.0.0.1/" -- "$XDG_CONFIG_HOME/interimap/config" +sed -i "s/^SSL_verify\\s*=.*/SSL_verify = YES/" -- "$XDG_CONFIG_HOME/interimap/config" +! interimap --debug || error +sni_ok +grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error + +# good CA, bad host +echo "SSL_CAfile = $HOME/.dovecot/conf.d/ca.crt" >>"$XDG_CONFIG_HOME/interimap/config" +! interimap --debug || error +sni_ok +grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error + +# bad CA, good host +sed -i "/^SSL_CAfile\\s*=/d" -- "$XDG_CONFIG_HOME/interimap/config" +sed -i "s/^host\\s*=.*/host = localhost/" -- "$XDG_CONFIG_HOME/interimap/config" +! interimap --debug || error +sni_ok +grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error + +# good CA, good host +echo "SSL_CAfile = $HOME/.dovecot/conf.d/ca.crt" >>"$XDG_CONFIG_HOME/interimap/config" +interimap --debug || error +sni_ok + +# vim: set filetype=bash : diff --git a/tests/tls-verify-peer/interimap.remote b/tests/tls-verify-peer/interimap.remote index b02fcd0..263655f 100644 --- a/tests/tls-verify-peer/interimap.remote +++ b/tests/tls-verify-peer/interimap.remote @@ -1,2 +1 @@ -host = ::1 port = 10993 diff --git a/tests/tls-verify-peer/t b/tests/tls-verify-peer/t index d84328a..ee4cd88 100644 --- a/tests/tls-verify-peer/t +++ b/tests/tls-verify-peer/t @@ -1,80 +1,150 @@ -CERT=~/.dovecot/conf.d/dovecot.pem +X509_SHA256="$(doveconf -c "$HOME_remote/.dovecot/config" -hx ssl_cert \ + | openssl x509 -in /dev/stdin -noout -fingerprint -sha256 \ + | sed -rn "/^.*=\\s*/ {s///p;q}" | tr -d : | tr "[A-Z]" "[a-z]")" +PKEY_SHA256="$(doveconf -c "$HOME_remote/.dovecot/config" -hx ssl_cert \ + | openssl x509 -in /dev/stdin -pubkey \ + | openssl pkey -in /dev/stdin -pubin -outform DER \ + | openssl dgst -sha256 | sed -rn "/^.*=\\s*/ {s///p;q}")" unverified_peer() { ! interimap --debug || error + # make sure we aborted the handshake immediately after connecting + grep -Fx "remote: Peer certificate fingerprint: sha256\$$X509_SHA256" <"$STDERR" || error grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error sed -nr "s/remote: \[[0-9]+\] (preverify=[0-9]+)$/\1/p" <"$STDERR" >"$TMPDIR/preverify" [ -s "$TMPDIR/preverify" ] || error ! grep -Fvx "preverify=0" <"$TMPDIR/preverify" || error - # make sure we didn't send any credentials + # make sure we didn't send any credentials or started speaking IMAP ! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error + grep -Fx "remote: IMAP traffic (bytes): recv 0 sent 0" <"$STDERR" || error } verified_peer() { local i u - for ((i = 0; i < 32; i++)); do + for ((i = 0; i < 4; i++)); do u="$(shuf -n1 -e "local" "remote")" sample_message | deliver -u "$u" done interimap --debug || error + grep -Fx "remote: Peer certificate fingerprint: sha256\$$X509_SHA256" <"$STDERR" || error sed -nr "s/remote: \[[0-9]+\] (preverify=[0-9]+)$/\1/p" <"$STDERR" >"$TMPDIR/preverify" [ -s "$TMPDIR/preverify" ] || error ! grep -Fvx "preverify=1" <"$TMPDIR/preverify" || error - grep "^remote: SSL protocol: TLSv1\.[23] " <"$STDERR" || error + grep "^remote: SSL protocol: TLSv" <"$STDERR" || error grep "^remote: SSL cipher: " <"$STDERR" || error check_mailbox_status "INBOX" } # backup config -install -m0600 "$XDG_CONFIG_HOME/interimap/config" "$XDG_CONFIG_HOME/interimap/config~" +install -m0600 -- "$XDG_CONFIG_HOME/interimap/config" "$XDG_CONFIG_HOME/interimap/config~" with_remote_config() { - install -m0600 "$XDG_CONFIG_HOME/interimap/config~" "$XDG_CONFIG_HOME/interimap/config" + install -m0600 -- "$XDG_CONFIG_HOME/interimap/config~" "$XDG_CONFIG_HOME/interimap/config" cat >>"$XDG_CONFIG_HOME/interimap/config" } step_start "peer verification enabled by default" +# assume our fake root CA is not among OpenSSL's default trusted CAs unverified_peer +grep -Fx "remote: Using default locations for trusted CA certificates" <"$STDERR" || error step_done step_start "peer verification result honored when pinned pubkey matches" -pkey_sha256="$(openssl x509 -pubkey <"$CERT" | openssl pkey -pubin -outform DER \ - | openssl dgst -sha256 | sed -rn "/^.*=\\s*/ {s///p;q}")" with_remote_config <<-EOF - SSL_fingerprint = sha256\$$pkey_sha256 + SSL_fingerprint = sha256\$$PKEY_SHA256 EOF unverified_peer -! grep -Fx "remote: WARNING: Fingerprint doesn't match! MiTM in action?" <"$STDERR" || error +grep -Fx "remote: Using default locations for trusted CA certificates" <"$STDERR" || error +grep -Fx "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_SHA256" <"$STDERR" || error step_done -step_start "SSL_CAfile" +capath=$(mktemp --tmpdir="$TMPDIR" --directory capath.XXXXXX) +cp -T -- ~/.dovecot/conf.d/ca.crt "$capath/ca-certificates.crt" + +step_start "SSL_CAfile/\$SSL_CERT_FILE" + +# verify that an error is raised when CAfile can't be loaded +# (it's not the case for $SSL_CERT_FILE, cf. SSL_CTX_load_verify_locations(3ssl)) +with_remote_config <<<"SSL_CAfile = /nonexistent" +! interimap --debug || error +grep -Fx "remote: ERROR: SSL_CTX_load_verify_locations()" <"$STDERR" || error +grep -Fx "remote: IMAP traffic (bytes): recv 0 sent 0" <"$STDERR" || error + if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then - # the self-signed cert should not be in there + # assume our fake root CA is not there with_remote_config <<<"SSL_CAfile = /etc/ssl/certs/ca-certificates.crt" unverified_peer fi -with_remote_config <<<"SSL_CAfile = $CERT" + +# default host (localhost) is the CN (and also subjectAltName) +with_remote_config <<<"SSL_CAfile = $capath/ca-certificates.crt" verified_peer + +with_remote_config </dev/null +SSL_CERT_FILE=~/.dovecot/conf.d/ca.crt verified_peer +grep -Fx "remote: Using default locations for trusted CA certificates" <"$STDERR" || error + +# hostnames and IPs included in the subjectAltName should work as well +for host in "ip6-localhost" "127.0.0.1" "::1"; do + with_remote_config <<-EOF + host = $host + SSL_CAfile = $capath/ca-certificates.crt + EOF + verified_peer +done + +# but not for other hostnames or IPs +for host in "ip6-loopback" "127.0.1.1"; do + with_remote_config <<-EOF + host = $host + SSL_CAfile = $capath/ca-certificates.crt + EOF + unverified_peer +done + step_done -step_start "SSL_CApath" +step_start "SSL_CApath/\$SSL_CERT_DIR" + if [ -d "/etc/ssl/certs" ]; then - # the self-signed cert should not be in there + # assume our fake root CA is not there with_remote_config <<<"SSL_CApath = /etc/ssl/certs" unverified_peer fi -capath=$(mktemp --tmpdir="$TMPDIR" --directory capath.XXXXXX) -cp -t"$capath" "$CERT" c_rehash "$capath" +# default host (localhost) is the CN (and also subjectAltName) with_remote_config <<<"SSL_CApath = $capath" verified_peer + +with_remote_config </dev/null +SSL_CERT_DIR="$capath" verified_peer +grep -Fx "remote: Using default locations for trusted CA certificates" <"$STDERR" || error + +# hostnames and IPs included in the subjectAltName should work as well +for host in "ip6-localhost" "127.0.0.1" "::1"; do + with_remote_config <<-EOF + host = $host + SSL_CApath = $capath + EOF + verified_peer +done + +# but not for other IPs or hostnames +for host in "ip6-loopback" "127.0.1.1"; do + with_remote_config <<-EOF + host = $host + SSL_CApath = $capath + EOF + unverified_peer +done + step_done -# vim: set filetype=sh : +# vim: set filetype=bash : diff --git a/tests/tls/t b/tests/tls/t index dd6d955..aee0678 100644 --- a/tests/tls/t +++ b/tests/tls/t @@ -1,14 +1,17 @@ +X509_SHA256="$(doveconf -c "$HOME_remote/.dovecot/config" -hx ssl_cert \ + | openssl x509 -in /dev/stdin -noout -fingerprint -sha256 \ + | sed -rn "/^.*=\\s*/ {s///p;q}" | tr -d : | tr "[A-Z]" "[a-z]")" + for ((i = 0; i < 32; i++)); do u="$(shuf -n1 -e "local" "remote")" sample_message | deliver -u "$u" done interimap --debug || error -grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1" <"$STDERR" || error -grep -Fx "remote: Peer certificate fingerprint: sha256\$35944e3bd3300d3ac310bb497a32cc1eef6931482a587ddbc95343740cdf1323" <"$STDERR" || error -grep "^remote: SSL protocol: TLSv1\.[23] " <"$STDERR" || error +grep -Fx "remote: Peer certificate fingerprint: sha256\$$X509_SHA256" <"$STDERR" || error +grep "^remote: SSL protocol: TLSv" <"$STDERR" || error grep "^remote: SSL cipher: " <"$STDERR" || error check_mailbox_status "INBOX" -# vim: set filetype=sh : +# vim: set filetype=bash : |