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" # 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" with_remote_config <<-EOF SSL_fingerprint = sha256\$$PKEY_SHA256 EOF unverified_peer 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 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 # 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 with_remote_config