X509_SHA256="$(doveconf -c "$HOME_remote/.dovecot/config" -hx ssl_cert \ | openssl x509 -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 -pubkey | openssl pkey -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 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 < 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: 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~" with_remote_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" unverified_peer step_done step_start "peer verification result honored when pinned pubkey matches" with_remote_config <<-EOF SSL_fingerprint = sha256\$$PKEY_SHA256 EOF unverified_peer grep -Fx "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_SHA256" <"$STDERR" || error step_done capath=$(mktemp --tmpdir="$TMPDIR" --directory capath.XXXXXX) cp -T -- ~/.dovecot/conf.d/ca.crt "$capath/ca-certificates.crt" step_start "SSL_CAfile" if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then # assume our fake root CA is not there with_remote_config <<<"SSL_CAfile = /etc/ssl/certs/ca-certificates.crt" unverified_peer fi # default host (localhost) is the CN (and also subjectAltName) with_remote_config <<<"SSL_CAfile = $capath/ca-certificates.crt" verified_peer # 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 IPs or hostnames 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" if [ -d "/etc/ssl/certs" ]; then # assume our fake root CA is not there with_remote_config <<<"SSL_CApath = /etc/ssl/certs" unverified_peer fi c_rehash "$capath" # default host (localhost) is the CN (and also subjectAltName) with_remote_config <<<"SSL_CApath = $capath" verified_peer # 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 :