aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog1
-rw-r--r--lib/Net/IMAP/InterIMAP.pm11
-rw-r--r--tests/list9
-rw-r--r--tests/snippets/dovecot/dhparams.pem8
-rw-r--r--tests/snippets/dovecot/dovecot.key5
-rw-r--r--tests/snippets/dovecot/dovecot.pem11
-rw-r--r--tests/snippets/dovecot/imapd.conf4
-rw-r--r--tests/snippets/dovecot/ssl.conf4
-rw-r--r--tests/starttls-logindisabled/interimap.remote4
-rw-r--r--tests/starttls-logindisabled/remote.conf5
-rw-r--r--tests/starttls-logindisabled/t19
-rw-r--r--tests/starttls/interimap.remote4
-rw-r--r--tests/starttls/remote.conf2
-rw-r--r--tests/starttls/t27
l---------tests/sync-live-tls/interimap.remote1
l---------tests/sync-live-tls/local.conf1
-rw-r--r--tests/sync-live-tls/remote.conf6
l---------tests/sync-live-tls/t1
l---------tests/tls-pin-fingerprint/interimap.remote1
l---------tests/tls-pin-fingerprint/remote.conf1
-rw-r--r--tests/tls-pin-fingerprint/t33
l---------tests/tls-protocols/interimap.remote1
l---------tests/tls-protocols/remote.conf1
-rw-r--r--tests/tls-protocols/t39
-rw-r--r--tests/tls-verify-peer/interimap.remote2
l---------tests/tls-verify-peer/remote.conf1
-rw-r--r--tests/tls-verify-peer/t80
-rw-r--r--tests/tls/interimap.remote3
-rw-r--r--tests/tls/remote.conf2
-rw-r--r--tests/tls/t14
30 files changed, 296 insertions, 5 deletions
diff --git a/Changelog b/Changelog
index 5b43c6f..c08de80 100644
--- a/Changelog
+++ b/Changelog
@@ -85,6 +85,7 @@ interimap (0.5) upstream;
- libinterimap: don't panic() when inflate() reports the end of the
compression stream is reached.
- libinterimap: the 'compress' boolean wasn't honored.
+ - libinterimap: fix STARTTLS directive, broken since 0.2.
-- Guilhem Moulin <guilhem@fripost.org> Fri, 10 May 2019 00:58:14 +0200
diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm
index 77c1b14..b4d8bec 100644
--- a/lib/Net/IMAP/InterIMAP.pm
+++ b/lib/Net/IMAP/InterIMAP.pm
@@ -215,7 +215,7 @@ sub in_set($$) {
return 1 if $x == $1;
}
elsif ($r eq '*' or $r eq '*:*') {
- warn "Assuming $x belongs to set $set! (Dunno what \"*\" means.)";
+ warn "Assuming $x belongs to set $set! (Dunno what \"*\" means.)";
return 1;
}
elsif ($r =~ /\A([0-9]+):\*\z/ or $r =~ /\A\*:([0-9]+)\z/) {
@@ -398,7 +398,8 @@ sub new($%) {
if ($self->{type} eq 'imap' and $self->{STARTTLS}) { # RFC 2595 section 5.1
$self->fail("Server did not advertise STARTTLS capability.")
unless grep {$_ eq 'STARTTLS'} @caps;
- $self->_start_ssl($self->{S}) if $self->{type} eq 'imaps';
+ $self->_send('STARTTLS');
+ $self->_start_ssl($self->{S});
# refresh the previous CAPABILITY list since the previous one could have been spoofed
delete $self->{_CAPABILITIES};
@@ -1610,7 +1611,7 @@ sub _ssl_verify($$$) {
my $pkey = Net::SSLeay::X509_get_X509_PUBKEY($cert);
unless (defined $pkey and Net::SSLeay::EVP_Digest($pkey, $type) eq $digest) {
- $self->warn("Fingerprint doesn't match! MiTM in action?");
+ $self->warn("Fingerprint doesn't match! MiTM in action?");
$ok = 0;
}
}
@@ -2355,7 +2356,7 @@ sub _resp($$;&$$) {
# /!\ No bookkeeping since there is no internal cache mapping sequence numbers to UIDs
if ($self->_enabled('QRESYNC')) {
$self->panic("$1 <= $cache->{EXISTS}") if $1 <= $cache->{EXISTS}; # sanity check
- $self->fail("RFC 7162 violation! Got an EXPUNGE response with QRESYNC enabled.");
+ $self->fail("RFC 7162 violation! Got an EXPUNGE response with QRESYNC enabled.");
}
# the new message was expunged before it was synced
$self->{_NEW} = 0 if $self->{_NEW} == 1 and $cache->{EXISTS} == $1;
@@ -2406,7 +2407,7 @@ sub _resp($$;&$$) {
/\A \((\\?$RE_ATOM_CHAR+ [0-9]+(?: \\?$RE_ATOM_CHAR+ [0-9]+)*)?\)\z/ or $self->panic($_);
my %status = split / /, $1;
$mailbox = 'INBOX' if uc $mailbox eq 'INBOX'; # INBOX is case-insensitive
- $self->panic("RFC 5465 violation! Missing HIGHESTMODSEQ data item in STATUS response")
+ $self->panic("RFC 5465 violation! Missing HIGHESTMODSEQ data item in STATUS response")
if $self->_enabled('QRESYNC') and !defined $status{HIGHESTMODSEQ} and defined $cmd and
($cmd eq 'NOTIFY' or $cmd eq 'slurp');
$self->_update_cache_for($mailbox, %status);
diff --git a/tests/list b/tests/list
index 86034ef..bc8d144 100644
--- a/tests/list
+++ b/tests/list
@@ -38,7 +38,16 @@ repair --repair
auth-logindisabled LOGINDISABLED
auth-noplaintext abort when STARTTLS is not offered
+. SSL/TLS
+ starttls-logindisabled LOGINDISABLED STARTTLS
+ starttls STARTTLS
+ tls SSL/TLS handshake
+ ... tls-verify-peer
+ tls-pin-fingerprint pubkey fingerprint pinning
+ tls-protocols force TLS protocol versions
+
. 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)
diff --git a/tests/snippets/dovecot/dhparams.pem b/tests/snippets/dovecot/dhparams.pem
new file mode 100644
index 0000000..7734d2a
--- /dev/null
+++ b/tests/snippets/dovecot/dhparams.pem
@@ -0,0 +1,8 @@
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEA0J1dU8erRgIk4bMCBMLezjx32pcQpXrdNgl04dxZVxnJ5Ik2gGhA
+uQRbbZhAlHNHtFtp9s4TdQ3Ddrv9SuWXYul8U5BWbcxs4nOtwFU8912SfiuVr/kc
+4ok2zQ1hdMODtaqWS2ZKBmwcuk4QM6e7fMEAkuZX+Dtf2u8bG5G9B7OL5LggYtrP
+cFVNQDtfhs64D+sUKJLWkgeg5NH6nbf+0Gs5a8v3/urHKvoxdVScGmKzF+LsFsBm
+ycQjYeVtA9gLr41mo80rrFysUQqZtNkbdkaXOIA2r9JGTYex1l/XaediR8J94ck9
+dwAe2ubRqWcPjmoLJYQIPKiCbvXuJAd0wwIBAg==
+-----END DH PARAMETERS-----
diff --git a/tests/snippets/dovecot/dovecot.key b/tests/snippets/dovecot/dovecot.key
new file mode 100644
index 0000000..95c9846
--- /dev/null
+++ b/tests/snippets/dovecot/dovecot.key
@@ -0,0 +1,5 @@
+-----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
new file mode 100644
index 0000000..7e53d90
--- /dev/null
+++ b/tests/snippets/dovecot/dovecot.pem
@@ -0,0 +1,11 @@
+-----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/imapd.conf b/tests/snippets/dovecot/imapd.conf
index c9926ce..18c60f8 100644
--- a/tests/snippets/dovecot/imapd.conf
+++ b/tests/snippets/dovecot/imapd.conf
@@ -9,4 +9,8 @@ service imap-login {
inet_listener imap {
port = 10143
}
+ inet_listener imaps {
+ port = 10993
+ ssl = yes
+ }
}
diff --git a/tests/snippets/dovecot/ssl.conf b/tests/snippets/dovecot/ssl.conf
new file mode 100644
index 0000000..240f24b
--- /dev/null
+++ b/tests/snippets/dovecot/ssl.conf
@@ -0,0 +1,4 @@
+ssl = required
+ssl_cert = <dovecot.pem
+ssl_key = <dovecot.key
+ssl_dh = <dhparams.pem
diff --git a/tests/starttls-logindisabled/interimap.remote b/tests/starttls-logindisabled/interimap.remote
new file mode 100644
index 0000000..5d7571d
--- /dev/null
+++ b/tests/starttls-logindisabled/interimap.remote
@@ -0,0 +1,4 @@
+type = imap
+host = 127.0.0.1
+port = 10143
+SSL_verify = no
diff --git a/tests/starttls-logindisabled/remote.conf b/tests/starttls-logindisabled/remote.conf
new file mode 100644
index 0000000..be2d51e
--- /dev/null
+++ b/tests/starttls-logindisabled/remote.conf
@@ -0,0 +1,5 @@
+!include conf.d/imapd.conf
+!include conf.d/ssl.conf
+
+# trick dovecot into treating local connections as insecure
+imap_capability = +LOGINDISABLED
diff --git a/tests/starttls-logindisabled/t b/tests/starttls-logindisabled/t
new file mode 100644
index 0000000..0ac7465
--- /dev/null
+++ b/tests/starttls-logindisabled/t
@@ -0,0 +1,19 @@
+interimap --debug || true
+
+# double check the presence of 'LOGINDISABLED' and 'STARTTLS' in the preauth capability list
+grep -oE -m1 '^remote: S: \* OK \[CAPABILITY IMAP4rev1( [^]]*)? AUTH=[^]]*\]' <"$STDERR" >"$TMPDIR/capability"
+
+sed -ri 's/^remote: S: \* OK \[CAPABILITY (.*)\]$/\1/' "$TMPDIR/capability"
+tr " " "\\n" <"$TMPDIR/capability" >"$TMPDIR/capabilities"
+grep -Fx "IMAP4rev1" <"$TMPDIR/capabilities" || error
+grep -Fx "LOGINDISABLED" <"$TMPDIR/capabilities" || error
+
+# make sure we upgraded the connection and check the capability again
+grep -Fx "STARTTLS" <"$TMPDIR/capabilities" || error
+grep -Fx "remote: C: 000000 STARTTLS" <"$STDERR" || error
+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 :
diff --git a/tests/starttls/interimap.remote b/tests/starttls/interimap.remote
new file mode 100644
index 0000000..5d7571d
--- /dev/null
+++ b/tests/starttls/interimap.remote
@@ -0,0 +1,4 @@
+type = imap
+host = 127.0.0.1
+port = 10143
+SSL_verify = no
diff --git a/tests/starttls/remote.conf b/tests/starttls/remote.conf
new file mode 100644
index 0000000..3d07ea9
--- /dev/null
+++ b/tests/starttls/remote.conf
@@ -0,0 +1,2 @@
+!include conf.d/imapd.conf
+!include conf.d/ssl.conf
diff --git a/tests/starttls/t b/tests/starttls/t
new file mode 100644
index 0000000..99a39c2
--- /dev/null
+++ b/tests/starttls/t
@@ -0,0 +1,27 @@
+for ((i = 0; i < 32; i++)); do
+ u="$(shuf -n1 -e "local" "remote")"
+ sample_message | deliver -u "$u"
+done
+
+interimap --debug || error
+
+# double check the presence of 'STARTTLS' in the preauth capability list
+grep -oE -m1 '^remote: S: \* OK \[CAPABILITY IMAP4rev1( [^]]*)? AUTH=[^]]*\]' <"$STDERR" >"$TMPDIR/capability"
+
+sed -ri 's/^remote: S: \* OK \[CAPABILITY (.*)\]$/\1/' "$TMPDIR/capability"
+tr " " "\\n" <"$TMPDIR/capability" >"$TMPDIR/capabilities"
+grep -Fx "IMAP4rev1" <"$TMPDIR/capabilities" || error
+grep -Fx "STARTTLS" <"$TMPDIR/capabilities" || error
+
+# make sure we upgraded the connection and check the capability again
+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 "^remote: SSL cipher: " <"$STDERR" || error
+
+check_mailbox_status "INBOX"
+
+# vim: set filetype=sh :
diff --git a/tests/sync-live-tls/interimap.remote b/tests/sync-live-tls/interimap.remote
new file mode 120000
index 0000000..daf3741
--- /dev/null
+++ b/tests/sync-live-tls/interimap.remote
@@ -0,0 +1 @@
+../tls/interimap.remote \ No newline at end of file
diff --git a/tests/sync-live-tls/local.conf b/tests/sync-live-tls/local.conf
new file mode 120000
index 0000000..ad27dd1
--- /dev/null
+++ b/tests/sync-live-tls/local.conf
@@ -0,0 +1 @@
+../sync-live/local.conf \ No newline at end of file
diff --git a/tests/sync-live-tls/remote.conf b/tests/sync-live-tls/remote.conf
new file mode 100644
index 0000000..b2af2d2
--- /dev/null
+++ b/tests/sync-live-tls/remote.conf
@@ -0,0 +1,6 @@
+namespace inbox {
+ separator = ^
+}
+
+!include conf.d/imapd.conf
+!include conf.d/ssl.conf
diff --git a/tests/sync-live-tls/t b/tests/sync-live-tls/t
new file mode 120000
index 0000000..189360e
--- /dev/null
+++ b/tests/sync-live-tls/t
@@ -0,0 +1 @@
+../sync-live/t \ No newline at end of file
diff --git a/tests/tls-pin-fingerprint/interimap.remote b/tests/tls-pin-fingerprint/interimap.remote
new file mode 120000
index 0000000..daf3741
--- /dev/null
+++ b/tests/tls-pin-fingerprint/interimap.remote
@@ -0,0 +1 @@
+../tls/interimap.remote \ No newline at end of file
diff --git a/tests/tls-pin-fingerprint/remote.conf b/tests/tls-pin-fingerprint/remote.conf
new file mode 120000
index 0000000..6029749
--- /dev/null
+++ b/tests/tls-pin-fingerprint/remote.conf
@@ -0,0 +1 @@
+../tls/remote.conf \ No newline at end of file
diff --git a/tests/tls-pin-fingerprint/t b/tests/tls-pin-fingerprint/t
new file mode 100644
index 0000000..1b84390
--- /dev/null
+++ b/tests/tls-pin-fingerprint/t
@@ -0,0 +1,33 @@
+# 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"
+}
+
+# pinned valid fingerprint
+with_remote_config <<-EOF
+ SSL_fingerprint = sha256\$e8fc8d03ffe75e03897136a2f1c5647bf8c36be7136a6883a732a8c4961c1614
+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"
+
+
+# and now an invalid one
+with_remote_config <<-EOF
+ SSL_fingerprint = sha256\$deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef
+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
+! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error
+
+# vim: set filetype=sh :
diff --git a/tests/tls-protocols/interimap.remote b/tests/tls-protocols/interimap.remote
new file mode 120000
index 0000000..daf3741
--- /dev/null
+++ b/tests/tls-protocols/interimap.remote
@@ -0,0 +1 @@
+../tls/interimap.remote \ No newline at end of file
diff --git a/tests/tls-protocols/remote.conf b/tests/tls-protocols/remote.conf
new file mode 120000
index 0000000..6029749
--- /dev/null
+++ b/tests/tls-protocols/remote.conf
@@ -0,0 +1 @@
+../tls/remote.conf \ No newline at end of file
diff --git a/tests/tls-protocols/t b/tests/tls-protocols/t
new file mode 100644
index 0000000..f34a95b
--- /dev/null
+++ b/tests/tls-protocols/t
@@ -0,0 +1,39 @@
+# backup config
+install -m0600 "$XDG_CONFIG_HOME/interimap/config" "$XDG_CONFIG_HOME/interimap/config~"
+with_remote_tls_protocols() {
+ install -m0600 "$XDG_CONFIG_HOME/interimap/config~" "$XDG_CONFIG_HOME/interimap/config"
+ 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
+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
+
+# force TLSv1.2
+with_remote_tls_protocols "TLSv1.2"
+interimap --debug || error
+grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1, TLSv1.3" <"$STDERR" || error
+grep -E "^remote: SSL protocol: TLSv1\.2 " <"$STDERR" || error
+
+# force TLSv1 to TLSv1.2
+with_remote_tls_protocols "TLSv1" "TLSv1.1" "TLSv1.2"
+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
+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
+! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error
+
+# vim: set filetype=sh :
diff --git a/tests/tls-verify-peer/interimap.remote b/tests/tls-verify-peer/interimap.remote
new file mode 100644
index 0000000..b02fcd0
--- /dev/null
+++ b/tests/tls-verify-peer/interimap.remote
@@ -0,0 +1,2 @@
+host = ::1
+port = 10993
diff --git a/tests/tls-verify-peer/remote.conf b/tests/tls-verify-peer/remote.conf
new file mode 120000
index 0000000..6029749
--- /dev/null
+++ b/tests/tls-verify-peer/remote.conf
@@ -0,0 +1 @@
+../tls/remote.conf \ No newline at end of file
diff --git a/tests/tls-verify-peer/t b/tests/tls-verify-peer/t
new file mode 100644
index 0000000..d84328a
--- /dev/null
+++ b/tests/tls-verify-peer/t
@@ -0,0 +1,80 @@
+CERT=~/.dovecot/conf.d/dovecot.pem
+
+unverified_peer() {
+ ! interimap --debug || 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
+ ! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error
+}
+verified_peer() {
+ local i u
+ for ((i = 0; i < 32; i++)); do
+ u="$(shuf -n1 -e "local" "remote")"
+ sample_message | deliver -u "$u"
+ done
+ interimap --debug || 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 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"
+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
+EOF
+unverified_peer
+! grep -Fx "remote: WARNING: Fingerprint doesn't match! MiTM in action?" <"$STDERR" || error
+step_done
+
+
+step_start "SSL_CAfile"
+if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then
+ # the self-signed cert should not be in there
+ with_remote_config <<<"SSL_CAfile = /etc/ssl/certs/ca-certificates.crt"
+ unverified_peer
+fi
+with_remote_config <<<"SSL_CAfile = $CERT"
+verified_peer
+step_done
+
+
+step_start "SSL_CApath"
+if [ -d "/etc/ssl/certs" ]; then
+ # the self-signed cert should not be in 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"
+
+with_remote_config <<<"SSL_CApath = $capath"
+verified_peer
+step_done
+
+# vim: set filetype=sh :
diff --git a/tests/tls/interimap.remote b/tests/tls/interimap.remote
new file mode 100644
index 0000000..2c0e37e
--- /dev/null
+++ b/tests/tls/interimap.remote
@@ -0,0 +1,3 @@
+host = ::1
+port = 10993
+SSL_verify = no
diff --git a/tests/tls/remote.conf b/tests/tls/remote.conf
new file mode 100644
index 0000000..3d07ea9
--- /dev/null
+++ b/tests/tls/remote.conf
@@ -0,0 +1,2 @@
+!include conf.d/imapd.conf
+!include conf.d/ssl.conf
diff --git a/tests/tls/t b/tests/tls/t
new file mode 100644
index 0000000..dd6d955
--- /dev/null
+++ b/tests/tls/t
@@ -0,0 +1,14 @@
+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 "^remote: SSL cipher: " <"$STDERR" || error
+
+check_mailbox_status "INBOX"
+
+# vim: set filetype=sh :