From fce1c73c8c942e6a87b8000f80da7dc735635296 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Dec 2020 12:31:08 +0100 Subject: Update copyright years. --- README | 2 +- interimap | 2 +- lib/Net/IMAP/InterIMAP.pm | 2 +- pullimap | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index fbc4ed7..d969da0 100644 --- a/README +++ b/README @@ -80,6 +80,6 @@ usage with regular INET sockets (type=imaps or type=imap). _______________________________________________________________________ -InterIMAP is Copyright© 2015-2018 Guilhem Moulin ⟨guilhem@fripost.org⟩, +InterIMAP is Copyright© 2015-2020 Guilhem Moulin ⟨guilhem@fripost.org⟩, and licensed for use under the GNU General Public License version 3 or later. See ‘COPYING’ for specific terms and distribution information. diff --git a/interimap b/interimap index f8aa768..68cb60b 100755 --- a/interimap +++ b/interimap @@ -2,7 +2,7 @@ #---------------------------------------------------------------------- # Fast bidirectional synchronization for QRESYNC-capable IMAP servers -# Copyright © 2015-2019 Guilhem Moulin +# Copyright © 2015-2020 Guilhem Moulin # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index fff1570..8b59ed2 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -1,6 +1,6 @@ #---------------------------------------------------------------------- # A minimal IMAP4 client for QRESYNC-capable servers -# Copyright © 2015-2019 Guilhem Moulin +# Copyright © 2015-2020 Guilhem Moulin # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/pullimap b/pullimap index 86d80e0..b691272 100755 --- a/pullimap +++ b/pullimap @@ -2,7 +2,7 @@ #---------------------------------------------------------------------- # Pull mails from an IMAP mailbox and deliver them to an SMTP session -# Copyright © 2016-2019 Guilhem Moulin +# Copyright © 2016-2020 Guilhem Moulin # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -- cgit v1.2.3 From e6bc060ec4c2577eed285215537f85047a5d3c10 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Dec 2020 12:38:19 +0100 Subject: typofix --- Changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 28a1ef4..d41906b 100644 --- a/Changelog +++ b/Changelog @@ -4,7 +4,7 @@ interimap (0.5.4) upstream; Subject Alternative Name (SAN) or Subject CommonName (CN) matches the hostname or IP literal specified by the 'host' option. Previously it was only checking the chain of trust. This bumps the minimum - Net::SSLeay version to 1.83 and OpenSSL version 1.0.2. + Net::SSLeay version to 1.83 and OpenSSL version to 1.0.2. * libinterimap: add support for the TLS SNI (Server Name Indication) extension, controlled by the new 'SSL_hostname' option. The default value of that option is the value of the 'host' option when it is -- cgit v1.2.3 From f247a5ed7f92b46341ce51bfe6ee4893d23715be Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Dec 2020 12:38:37 +0100 Subject: manpages: improve wording. --- doc/interimap.1.md | 2 +- doc/pullimap.1.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/interimap.1.md b/doc/interimap.1.md index 2d2a637..5f19d66 100644 --- a/doc/interimap.1.md +++ b/doc/interimap.1.md @@ -420,7 +420,7 @@ Valid options are: *SSL_verify* -: Whether to verify the server certificate chain, and match its +: Whether to 1/ verify the server certificate chain, and 2/ match its Subject Alternative Name (SAN) or Subject CommonName (CN) against the value of the *host* option. (Default: `YES`.) diff --git a/doc/pullimap.1.md b/doc/pullimap.1.md index c9500e0..ea93ed3 100644 --- a/doc/pullimap.1.md +++ b/doc/pullimap.1.md @@ -239,7 +239,7 @@ Valid options are: *SSL_verify* -: Whether to verify the server certificate chain, and match its +: Whether to 1/ verify the server certificate chain, and 2/ match its Subject Alternative Name (SAN) or Subject CommonName (CN) against the value of the *host* option. (Default: `YES`.) -- cgit v1.2.3 From 79463a5972229686a10c6fb39eaf3c27b85b165c Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Dec 2020 14:54:00 +0100 Subject: Remove incorrect affirmation from 0.5.4 changelog. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test suite already required OpenSSL ≥1.1.1 as some tests are using TLSv1.3. --- Changelog | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Changelog b/Changelog index d41906b..42cac7a 100644 --- a/Changelog +++ b/Changelog @@ -11,8 +11,7 @@ interimap (0.5.4) upstream; hostname, and the empty string (which disables SNI) when it is an IP literal. + libinterimap: show the matching pinned SPKI in --debug mode. - + test suite: always generate new certificates on `make test`. Hence - running `make test` now requires OpenSSL 1.1.1 or later. + + test suite: always generate new certificates on `make test`. + test suite: sign all test certificates with the same root CA. + libinterimap: factor out hostname/IP parsing. + document that enclosing 'host' value in square brackets forces its -- cgit v1.2.3 From e3b95b0da424e55682c8c7b025d9d272a4a35ffe Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Dec 2020 15:09:15 +0100 Subject: libinterimap: remove default SSL_protocols value. Namely, use the system default instead of "!SSLv2 !SSLv3 !TLSv1 !TLSv1.1". As of Debian Buster (OpenSSL 1.1.1) this does not make a difference, however using the system default provides better compatibility with future libssl versions. --- Changelog | 10 ++++++++++ doc/interimap.1.md | 11 +++++------ doc/pullimap.1.md | 11 +++++------ lib/Net/IMAP/InterIMAP.pm | 38 ++++++++++++++++++++------------------ tests/starttls/t | 1 - tests/tls-protocols/t | 7 +------ tests/tls/t | 1 - 7 files changed, 41 insertions(+), 38 deletions(-) diff --git a/Changelog b/Changelog index 42cac7a..b809cd3 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,13 @@ +interimap (0.5.5) upstream; + + * libinterimap: remove default SSL_protocols value "!SSLv2 !SSLv3 + !TLSv1 !TLSv1.1" and use the system default instead. As of Debian + Buster (OpenSSL 1.1.1) this does not make a difference, however using + the system default provides better compatibility with future libssl + versions. + + -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 + interimap (0.5.4) upstream; * libinterimap: make SSL_verify also checks that the certificate diff --git a/doc/interimap.1.md b/doc/interimap.1.md index 5f19d66..9cfec7a 100644 --- a/doc/interimap.1.md +++ b/doc/interimap.1.md @@ -383,12 +383,11 @@ Valid options are: *SSL_protocols* -: A space-separated list of SSL protocols to enable or disable (if - prefixed with an exclamation mark `!`. Known protocols are `SSLv2`, - `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`. Enabling a - protocol is a short-hand for disabling all other protocols. - (Default: `!SSLv2 !SSLv3 !TLSv1 !TLSv1.1`, i.e., only enable TLSv1.2 - and above.) +: A space-separated list of SSL protocols to explicitly enable or + disable (if prefixed with an exclamation mark `!`. Known protocols + are `SSLv2`, `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`. + Enabling a protocol is a short-hand for disabling all other + protocols. *SSL_cipher_list* diff --git a/doc/pullimap.1.md b/doc/pullimap.1.md index ea93ed3..84cae46 100644 --- a/doc/pullimap.1.md +++ b/doc/pullimap.1.md @@ -202,12 +202,11 @@ Valid options are: *SSL_protocols* -: A space-separated list of SSL protocols to enable or disable (if - prefixed with an exclamation mark `!`. Known protocols are `SSLv2`, - `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`. Enabling a - protocol is a short-hand for disabling all other protocols. - (Default: `!SSLv2 !SSLv3 !TLSv1 !TLSv1.1`, i.e., only enable TLSv1.2 - and above.) +: A space-separated list of SSL protocols to explicitly enable or + disable (if prefixed with an exclamation mark `!`. Known protocols + are `SSLv2`, `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`. + Enabling a protocol is a short-hand for disabling all other + protocols. *SSL_cipher_list* diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 8b59ed2..221b016 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -1694,32 +1694,34 @@ sub _start_ssl($$) { my ($self, $socket) = @_; my $openssl_version = Net::SSLeay::OPENSSL_VERSION_NUMBER(); my $ctx = Net::SSLeay::CTX_new() or $self->panic("Failed to create SSL_CTX $!"); - my $ssl_options = Net::SSLeay::OP_SINGLE_DH_USE() | Net::SSLeay::OP_SINGLE_ECDH_USE(); if (defined $self->{_OUTBUF} and $self->{_OUTBUF} ne '') { $self->warn("Truncating non-empty output buffer (unauthenticated response injection?)"); undef $self->{_OUTBUF}; } - $self->{SSL_protocols} //= q{!SSLv2 !SSLv3 !TLSv1 !TLSv1.1}; - my ($proto_include, $proto_exclude) = (0, 0); - foreach (split /\s+/, $self->{SSL_protocols}) { - my $neg = s/^!// ? 1 : 0; - s/\.0$//; - ($neg ? $proto_exclude : $proto_include) |= $SSL_proto{$_} // $self->panic("Unknown SSL protocol: $_"); - } - if ($proto_include != 0) { - # exclude all protocols except those explictly included - my $x = 0; - $x |= $_ foreach values %SSL_proto; - $x &= ~ $proto_include; - $proto_exclude |= $x; - } - my @proto_exclude = grep { ($proto_exclude & $SSL_proto{$_}) != 0 } keys %SSL_proto; - $self->log("Disabling SSL protocols: ".join(', ', sort @proto_exclude)) if $self->{debug}; - $ssl_options |= $SSL_proto{$_} foreach @proto_exclude; + my $ssl_options = Net::SSLeay::OP_SINGLE_DH_USE() | Net::SSLeay::OP_SINGLE_ECDH_USE(); $ssl_options |= Net::SSLeay::OP_NO_COMPRESSION(); + if (defined (my $protos = $self->{SSL_protocols})) { + my ($proto_include, $proto_exclude) = (0, 0); + foreach (split /\s+/, $protos) { + my $neg = s/^!// ? 1 : 0; + s/\.0$//; + ($neg ? $proto_exclude : $proto_include) |= $SSL_proto{$_} // $self->panic("Unknown SSL protocol: $_"); + } + if ($proto_include != 0) { + # exclude all protocols except those explictly included + my $x = 0; + $x |= $_ foreach values %SSL_proto; + $x &= ~ $proto_include; + $proto_exclude |= $x; + } + my @proto_exclude = grep { ($proto_exclude & $SSL_proto{$_}) != 0 } keys %SSL_proto; + $self->log("Disabling SSL protocols: ".join(', ', sort @proto_exclude)) if $self->{debug}; + $ssl_options |= $SSL_proto{$_} foreach @proto_exclude; + } + # https://www.openssl.org/docs/manmaster/ssl/SSL_CTX_set_options.html Net::SSLeay::CTX_set_options($ctx, $ssl_options); diff --git a/tests/starttls/t b/tests/starttls/t index 5f9bd4f..55caf99 100644 --- a/tests/starttls/t +++ b/tests/starttls/t @@ -21,7 +21,6 @@ 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\$$X509_SHA256" <"$STDERR" || error grep "^remote: SSL protocol: TLSv1\.[23] " <"$STDERR" || error grep "^remote: SSL cipher: " <"$STDERR" || error diff --git a/tests/tls-protocols/t b/tests/tls-protocols/t index f34a95b..5444658 100644 --- a/tests/tls-protocols/t +++ b/tests/tls-protocols/t @@ -5,12 +5,7 @@ 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 versions 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 diff --git a/tests/tls/t b/tests/tls/t index 9fdd399..76f7c14 100644 --- a/tests/tls/t +++ b/tests/tls/t @@ -8,7 +8,6 @@ for ((i = 0; i < 32; i++)); do done interimap --debug || error -grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1" <"$STDERR" || error grep -Fx "remote: Peer certificate fingerprint: sha256\$$X509_SHA256" <"$STDERR" || error grep "^remote: SSL protocol: TLSv1\.[23] " <"$STDERR" || error grep "^remote: SSL cipher: " <"$STDERR" || error -- cgit v1.2.3 From 7d7a28bc77908d05983a3c3fcfed79616a1614ce Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Dec 2020 15:47:08 +0100 Subject: libinterimap: make $OPENSSL_VERSION global. --- Changelog | 1 + lib/Net/IMAP/InterIMAP.pm | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Changelog b/Changelog index b809cd3..d880a0f 100644 --- a/Changelog +++ b/Changelog @@ -5,6 +5,7 @@ interimap (0.5.5) upstream; Buster (OpenSSL 1.1.1) this does not make a difference, however using the system default provides better compatibility with future libssl versions. + - libinterimap: make $OPENSSL_VERSION global. -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 221b016..5843b27 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -48,6 +48,7 @@ my $RE_LIST_CHAR = qr/[\x21\x23-\x27\x2A\x2B-\x5B\x5D-\x7A\x7C-\x7E]/; my $RE_TEXT_CHAR = qr/[\x01-\x09\x0B\x0C\x0E-\x7F]/; my $RE_SSL_PROTO = qr/(?:SSLv[23]|TLSv1|TLSv1\.[0-3])/; +my $OPENSSL_VERSION = Net::SSLeay::OPENSSL_VERSION_NUMBER(); # Map each option to a regexp validating its values. my %OPTIONS = ( @@ -1692,7 +1693,6 @@ BEGIN { # Upgrade the $socket to SSL/TLS. sub _start_ssl($$) { my ($self, $socket) = @_; - my $openssl_version = Net::SSLeay::OPENSSL_VERSION_NUMBER(); my $ctx = Net::SSLeay::CTX_new() or $self->panic("Failed to create SSL_CTX $!"); if (defined $self->{_OUTBUF} and $self->{_OUTBUF} ne '') { @@ -1746,7 +1746,7 @@ sub _start_ssl($$) { my ($hostip, $hostipfam) = _parse_hostip($host); if ($self->{SSL_verify} // 1) { # for X509_VERIFY_PARAM_set1_{ip,host}() - $self->panic("Failed requirement libssl >=1.0.2") if $openssl_version < 0x1000200f; + $self->panic("Failed requirement libssl >=1.0.2") if $OPENSSL_VERSION < 0x1000200f; # verify certificate chain my ($file, $path) = ($self->{SSL_CAfile} // '', $self->{SSL_CApath} // ''); @@ -1777,7 +1777,7 @@ sub _start_ssl($$) { # always use 'SSL_hostname' when set, otherwise use 'host' (unless it's an IP) on OpenSSL >=0.9.8f my $servername = $self->{SSL_hostname} // (defined $hostipfam ? "" : $host); if ($servername ne "") { - $self->panic("Failed requirement libssl >=0.9.8f") if $openssl_version < 0x00908070; + $self->panic("Failed requirement libssl >=0.9.8f") if $OPENSSL_VERSION < 0x00908070; $self->_ssl_error("Can't set TLS servername extension (value $servername)") unless Net::SSLeay::set_tlsext_host_name($ssl, $servername) == 1; $self->log("Using SNI with name $servername") if $self->{debug}; -- cgit v1.2.3 From 35f4ecefa9c9ff55acfdb337b215e3d13345c86d Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Dec 2020 16:23:12 +0100 Subject: libinterimap: use Net::SSLeay::get_version() to get the protocol version string. This avoids maintaing our own map. --- Changelog | 2 ++ lib/Net/IMAP/InterIMAP.pm | 12 +++--------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Changelog b/Changelog index d880a0f..83dea70 100644 --- a/Changelog +++ b/Changelog @@ -6,6 +6,8 @@ interimap (0.5.5) upstream; the system default provides better compatibility with future libssl versions. - libinterimap: make $OPENSSL_VERSION global. + - libinterimap: use Net::SSLeay::get_version() to get the protocol + version string. -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 5843b27..e2b89ec 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -1789,15 +1789,9 @@ sub _start_ssl($$) { Net::SSLeay::X509_VERIFY_PARAM_free($vpm); if ($self->{debug}) { - my $v = Net::SSLeay::version($ssl); - $self->log(sprintf('SSL protocol: %s (0x%x)', ($v == 0x0002 ? 'SSLv2' : - $v == 0x0300 ? 'SSLv3' : - $v == 0x0301 ? 'TLSv1' : - $v == 0x0302 ? 'TLSv1.1' : - $v == 0x0303 ? 'TLSv1.2' : - $v == 0x0304 ? 'TLSv1.3' : - '??'), - $v)); + $self->log(sprintf('SSL protocol: %s (0x%x)', + , Net::SSLeay::get_version($ssl) + , Net::SSLeay::version($ssl))); $self->log(sprintf('SSL cipher: %s (%d bits)' , Net::SSLeay::get_cipher($ssl) , Net::SSLeay::get_cipher_bits($ssl))); -- cgit v1.2.3 From b99cd2fd12bc3a2c6b858e65182a47a4ef27dba2 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Dec 2020 17:57:22 +0100 Subject: test suite: `mv tests/snippets tests/config` --- Changelog | 1 + tests/config/dovecot/dhparams.pem | 8 ++++++++ tests/config/dovecot/imapd.conf | 19 +++++++++++++++++++ .../dovecot/interimap-required-capabilities.conf | 3 +++ tests/config/dovecot/lmtpd.conf | 7 +++++++ tests/config/dovecot/ssl.conf | 4 ++++ tests/preauth-plaintext/imapd | 2 +- tests/run | 2 +- tests/snippets/dovecot/dhparams.pem | 8 -------- tests/snippets/dovecot/imapd.conf | 19 ------------------- .../dovecot/interimap-required-capabilities.conf | 3 --- tests/snippets/dovecot/lmtpd.conf | 7 ------- tests/snippets/dovecot/ssl.conf | 4 ---- 13 files changed, 44 insertions(+), 43 deletions(-) create mode 100644 tests/config/dovecot/dhparams.pem create mode 100644 tests/config/dovecot/imapd.conf create mode 100644 tests/config/dovecot/interimap-required-capabilities.conf create mode 100644 tests/config/dovecot/lmtpd.conf create mode 100644 tests/config/dovecot/ssl.conf delete mode 100644 tests/snippets/dovecot/dhparams.pem delete mode 100644 tests/snippets/dovecot/imapd.conf delete mode 100644 tests/snippets/dovecot/interimap-required-capabilities.conf delete mode 100644 tests/snippets/dovecot/lmtpd.conf delete mode 100644 tests/snippets/dovecot/ssl.conf diff --git a/Changelog b/Changelog index 83dea70..e21ccf7 100644 --- a/Changelog +++ b/Changelog @@ -8,6 +8,7 @@ interimap (0.5.5) upstream; - libinterimap: make $OPENSSL_VERSION global. - libinterimap: use Net::SSLeay::get_version() to get the protocol version string. + - test suite: `mv tests/snippets tests/config` -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 diff --git a/tests/config/dovecot/dhparams.pem b/tests/config/dovecot/dhparams.pem new file mode 100644 index 0000000..7734d2a --- /dev/null +++ b/tests/config/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/config/dovecot/imapd.conf b/tests/config/dovecot/imapd.conf new file mode 100644 index 0000000..2b26451 --- /dev/null +++ b/tests/config/dovecot/imapd.conf @@ -0,0 +1,19 @@ +protocols = $protocols imap + +mail_plugins = $mail_plugins zlib +protocol imap { + mail_plugins = $mail_plugins imap_zlib +} + +service imap-login { + inet_listener imap { + port = 10143 + } + inet_listener imaps { + port = 10993 + ssl = yes + } +} + +# we should avoid sending command lines that are too long +imap_max_line_length = 8192 diff --git a/tests/config/dovecot/interimap-required-capabilities.conf b/tests/config/dovecot/interimap-required-capabilities.conf new file mode 100644 index 0000000..10dd8e1 --- /dev/null +++ b/tests/config/dovecot/interimap-required-capabilities.conf @@ -0,0 +1,3 @@ +# strict minimum of IMAP capabilities required for interimap to work +# (in particular, no LITERAL+, MULTIAPPEND, COMPRESS=DEFLATE, SASL-IR) +imap_capability = IMAP4rev1 ENABLE UIDPLUS LIST-EXTENDED QRESYNC LIST-STATUS diff --git a/tests/config/dovecot/lmtpd.conf b/tests/config/dovecot/lmtpd.conf new file mode 100644 index 0000000..6aa8365 --- /dev/null +++ b/tests/config/dovecot/lmtpd.conf @@ -0,0 +1,7 @@ +protocols = $protocols lmtp + +service lmtp { + inet_listener lmtp { + port = 10024 + } +} diff --git a/tests/config/dovecot/ssl.conf b/tests/config/dovecot/ssl.conf new file mode 100644 index 0000000..2d68c80 --- /dev/null +++ b/tests/config/dovecot/ssl.conf @@ -0,0 +1,4 @@ +ssl = required +ssl_cert = printflush("* PREAUTH [CAPABILITY IMAP4rev1 ENABLE UIDPLUS LIST-EXTENDED QRESYNC LIST-STATUS] IMAP4rev1 Server\r\n"); my $x; diff --git a/tests/run b/tests/run index d216591..994c257 100755 --- a/tests/run +++ b/tests/run @@ -101,7 +101,7 @@ 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)" diff --git a/tests/snippets/dovecot/dhparams.pem b/tests/snippets/dovecot/dhparams.pem deleted file mode 100644 index 7734d2a..0000000 --- a/tests/snippets/dovecot/dhparams.pem +++ /dev/null @@ -1,8 +0,0 @@ ------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/imapd.conf b/tests/snippets/dovecot/imapd.conf deleted file mode 100644 index 2b26451..0000000 --- a/tests/snippets/dovecot/imapd.conf +++ /dev/null @@ -1,19 +0,0 @@ -protocols = $protocols imap - -mail_plugins = $mail_plugins zlib -protocol imap { - mail_plugins = $mail_plugins imap_zlib -} - -service imap-login { - inet_listener imap { - port = 10143 - } - inet_listener imaps { - port = 10993 - ssl = yes - } -} - -# we should avoid sending command lines that are too long -imap_max_line_length = 8192 diff --git a/tests/snippets/dovecot/interimap-required-capabilities.conf b/tests/snippets/dovecot/interimap-required-capabilities.conf deleted file mode 100644 index 10dd8e1..0000000 --- a/tests/snippets/dovecot/interimap-required-capabilities.conf +++ /dev/null @@ -1,3 +0,0 @@ -# strict minimum of IMAP capabilities required for interimap to work -# (in particular, no LITERAL+, MULTIAPPEND, COMPRESS=DEFLATE, SASL-IR) -imap_capability = IMAP4rev1 ENABLE UIDPLUS LIST-EXTENDED QRESYNC LIST-STATUS diff --git a/tests/snippets/dovecot/lmtpd.conf b/tests/snippets/dovecot/lmtpd.conf deleted file mode 100644 index 6aa8365..0000000 --- a/tests/snippets/dovecot/lmtpd.conf +++ /dev/null @@ -1,7 +0,0 @@ -protocols = $protocols lmtp - -service lmtp { - inet_listener lmtp { - port = 10024 - } -} diff --git a/tests/snippets/dovecot/ssl.conf b/tests/snippets/dovecot/ssl.conf deleted file mode 100644 index 2d68c80..0000000 --- a/tests/snippets/dovecot/ssl.conf +++ /dev/null @@ -1,4 +0,0 @@ -ssl = required -ssl_cert = Date: Fri, 11 Dec 2020 18:28:32 +0100 Subject: test suite: supply our own OpenSSL configuration file with MinProtocol=None. So we can test TLSv1 as well, not just TLSv1.2 and later. Also, explicitly set ssl_min_protocol=TLSv1 in the Dovecot configuration file (the default as of 2.3.11.3), hence running TLS tests now require Dovecot 2.3 or later. --- Changelog | 6 ++++++ tests/config/dovecot/ssl.conf | 1 + tests/config/openssl.cnf | 14 ++++++++++++++ tests/run | 4 +++- tests/starttls/t | 2 +- tests/tls-verify-peer/t | 2 +- tests/tls/t | 2 +- 7 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 tests/config/openssl.cnf diff --git a/Changelog b/Changelog index e21ccf7..01e272c 100644 --- a/Changelog +++ b/Changelog @@ -9,6 +9,12 @@ interimap (0.5.5) upstream; - libinterimap: use Net::SSLeay::get_version() to get the protocol version string. - test suite: `mv tests/snippets tests/config` + - test suite: supply our own OpenSSL configuration file with + MinProtocol=None so we can test TLSv1 as well, not just TLSv1.2 and + later. + - test suite: explicitly set ssl_min_protocol=TLSv1 in the Dovecot + configuration file (the default as of 2.3.11.3), hence running TLS + tests now require Dovecot 2.3 or later. -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 diff --git a/tests/config/dovecot/ssl.conf b/tests/config/dovecot/ssl.conf index 2d68c80..3fd99d5 100644 --- a/tests/config/dovecot/ssl.conf +++ b/tests/config/dovecot/ssl.conf @@ -2,3 +2,4 @@ ssl = required ssl_cert = Date: Fri, 11 Dec 2020 18:39:46 +0100 Subject: libinterimap: deprecate SSL_protocols and introduce SSL_protocol_{min,max}. Using the libssl interface simplifies our protocol black/whitelist greatly; this only allows simple min/max bounds, but holes are arguably not very useful here. Using the new settings bumps the required libssl version to 1.1.0. --- Changelog | 8 +++++- doc/interimap.1.md | 9 +++++++ doc/pullimap.1.md | 9 +++++++ lib/Net/IMAP/InterIMAP.pm | 32 +++++++++++++++++++++--- tests/tls-protocols/t | 64 +++++++++++++++++++++++++++++++++++++++++++++-- tests/tls-rsa+ecdsa/t | 2 +- 6 files changed, 117 insertions(+), 7 deletions(-) diff --git a/Changelog b/Changelog index 01e272c..c2f60dc 100644 --- a/Changelog +++ b/Changelog @@ -5,6 +5,11 @@ interimap (0.5.5) upstream; Buster (OpenSSL 1.1.1) this does not make a difference, however using the system default provides better compatibility with future libssl versions. + * libinterimap: deprecate SSL_protocols, obsoleted by new settings + SSL_protocol_{min,max}. Using the libssl interface simplifies our + protocol black/whilelist greatly; this only allows simple min/max + bounds, but holes are arguably not very useful here. Using the new + settings bumps the required libssl version to 1.1.0. - libinterimap: make $OPENSSL_VERSION global. - libinterimap: use Net::SSLeay::get_version() to get the protocol version string. @@ -24,7 +29,8 @@ interimap (0.5.4) upstream; Subject Alternative Name (SAN) or Subject CommonName (CN) matches the hostname or IP literal specified by the 'host' option. Previously it was only checking the chain of trust. This bumps the minimum - Net::SSLeay version to 1.83 and OpenSSL version to 1.0.2. + Net::SSLeay version to 1.83 and OpenSSL version to 1.0.2 (when + SSL_verify is used). * libinterimap: add support for the TLS SNI (Server Name Indication) extension, controlled by the new 'SSL_hostname' option. The default value of that option is the value of the 'host' option when it is diff --git a/doc/interimap.1.md b/doc/interimap.1.md index 9cfec7a..9b14a49 100644 --- a/doc/interimap.1.md +++ b/doc/interimap.1.md @@ -389,6 +389,15 @@ Valid options are: Enabling a protocol is a short-hand for disabling all other protocols. + *Deprecacted*: Use *SSL_protocol_min* and/or *SSL_protocol_max* + instead. + +*SSL_protocol_min*, *SSL_protocol_max* + +: Set minimum resp. maximum SSL/TLS protocol version to use for the + connection. Accepted values are `SSLv3`, `TLSv1`, `TLSv1.1`, + `TLSv1.2`, and `TLSv1.3`. + *SSL_cipher_list* : The cipher list to send to the server. Although the server diff --git a/doc/pullimap.1.md b/doc/pullimap.1.md index 84cae46..028cbaa 100644 --- a/doc/pullimap.1.md +++ b/doc/pullimap.1.md @@ -208,6 +208,15 @@ Valid options are: Enabling a protocol is a short-hand for disabling all other protocols. + *Deprecacted*: Use *SSL_protocol_min* and/or *SSL_protocol_max* + instead. + +*SSL_protocol_min*, *SSL_protocol_max* + +: Set minimum resp. maximum SSL/TLS protocol version to use for the + connection. Accepted values are `SSLv3`, `TLSv1`, `TLSv1.1`, + `TLSv1.2`, and `TLSv1.3`. + *SSL_cipher_list* : The cipher list to send to the server. Although the server diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index e2b89ec..49ea343 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -63,7 +63,9 @@ my %OPTIONS = ( command => qr/\A(\P{Control}+)\z/, 'null-stderr' => qr/\A(YES|NO)\z/i, compress => qr/\A(YES|NO)\z/i, - SSL_protocols => qr/\A(!?$RE_SSL_PROTO(?: !?$RE_SSL_PROTO)*)\z/, + SSL_protocols => qr/\A(!?$RE_SSL_PROTO(?: !?$RE_SSL_PROTO)*)\z/, # TODO deprecated, remove in 0.6 + SSL_protocol_min => qr/\A(\P{Control}+)\z/, + SSL_protocol_max => qr/\A(\P{Control}+)\z/, SSL_fingerprint => qr/\A((?:[A-Za-z0-9]+\$)?\p{AHex}+(?: (?:[A-Za-z0-9]+\$)?\p{AHex}+)*)\z/, SSL_cipherlist => qr/\A(\P{Control}+)\z/, SSL_hostname => qr/\A(\P{Control}*)\z/, @@ -1676,7 +1678,7 @@ sub _ssl_verify($$$) { } my %SSL_proto; -BEGIN { +BEGIN { # TODO deprecated, remove in 0.6 sub _append_ssl_proto($$) { my ($k, $v) = @_; $SSL_proto{$k} = $v if defined $v; @@ -1689,6 +1691,15 @@ BEGIN { _append_ssl_proto( "TLSv1.3", eval { Net::SSLeay::OP_NO_TLSv1_3() } ); } +# see ssl/ssl_conf.c:protocol_from_string() in the OpenSSL source tree +my %SSL_protocol_versions = ( + "SSLv3" => eval { Net::SSLeay::SSL3_VERSION() } + , "TLSv1" => eval { Net::SSLeay::TLS1_VERSION() } + , "TLSv1.1" => eval { Net::SSLeay::TLS1_1_VERSION() } + , "TLSv1.2" => eval { Net::SSLeay::TLS1_2_VERSION() } + , "TLSv1.3" => eval { Net::SSLeay::TLS1_3_VERSION() } +); + # $self->_start_ssl($socket) # Upgrade the $socket to SSL/TLS. sub _start_ssl($$) { @@ -1703,7 +1714,22 @@ sub _start_ssl($$) { my $ssl_options = Net::SSLeay::OP_SINGLE_DH_USE() | Net::SSLeay::OP_SINGLE_ECDH_USE(); $ssl_options |= Net::SSLeay::OP_NO_COMPRESSION(); - if (defined (my $protos = $self->{SSL_protocols})) { + if (defined $self->{SSL_protocol_min} or defined $self->{SSL_protocol_max}) { + $self->panic("Failed requirement libssl >=1.1.0") if $OPENSSL_VERSION < 0x1010000f; + my ($min, $max) = @$self{qw/SSL_protocol_min SSL_protocol_max/}; + if (defined $min) { + my $v = $SSL_protocol_versions{$min} // $self->panic("Unknown protocol version: $min"); + $self->_ssl_error("CTX_set_min_proto_version()") unless Net::SSLeay::CTX_set_min_proto_version($ctx, $v) == 1; + $self->log("Minimum SSL/TLS protocol version: ", $min) if $self->{debug}; + } + if (defined $max) { + my $v = $SSL_protocol_versions{$max} // $self->panic("Unknown protocol version: $max"); + $self->_ssl_error("CTX_set_max_proto_version()") unless Net::SSLeay::CTX_set_max_proto_version($ctx, $v) == 1; + $self->log("Maximum SSL/TLS protocol version: ", $max) if $self->{debug}; + } + } elsif (defined (my $protos = $self->{SSL_protocols})) { # TODO deprecated, remove in 0.6 + $self->warn("SSL_protocols is deprecated and will be removed in a future release! ", + "Use SSL_protocol_{min,max} instead."); my ($proto_include, $proto_exclude) = (0, 0); foreach (split /\s+/, $protos) { my $neg = s/^!// ? 1 : 0; diff --git a/tests/tls-protocols/t b/tests/tls-protocols/t index 5444658..b65d93c 100644 --- a/tests/tls-protocols/t +++ b/tests/tls-protocols/t @@ -1,3 +1,10 @@ +# 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 + # backup config install -m0600 "$XDG_CONFIG_HOME/interimap/config" "$XDG_CONFIG_HOME/interimap/config~" with_remote_tls_protocols() { @@ -5,12 +12,15 @@ with_remote_tls_protocols() { printf "SSL_protocols = %s\\n" "$*" >>"$XDG_CONFIG_HOME/interimap/config" } -# disable TLSv1.2 and earlier versions +# 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: SSL_protocols is deprecated " <"$STDERR" || error "no deprecation message" + # force TLSv1.2 with_remote_tls_protocols "TLSv1.2" interimap --debug || error @@ -23,7 +33,7 @@ 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 @@ -31,4 +41,54 @@ 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 + +# 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 +! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error + # vim: set filetype=sh : diff --git a/tests/tls-rsa+ecdsa/t b/tests/tls-rsa+ecdsa/t index 2adf930..8b811fd 100644 --- a/tests/tls-rsa+ecdsa/t +++ b/tests/tls-rsa+ecdsa/t @@ -38,7 +38,7 @@ grep -Fx -e "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_S # force RSA (XXX do we really have to force TLSv1.2 here?) cat >>"$XDG_CONFIG_HOME/interimap/config" <<-EOF - SSL_protocols = TLSv1.2 + SSL_protocol_max = TLSv1.2 SSL_cipherlist = EECDH+AESGCM+aRSA EOF interimap --debug || error -- cgit v1.2.3 From 9c192cc8946800535be678644314ec38f6e48ec7 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Dec 2020 19:06:29 +0100 Subject: documentation: simplify SSL options in the sample configuration files. --- Changelog | 1 + interimap.sample | 5 ++--- pullimap.sample | 5 ++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Changelog b/Changelog index c2f60dc..37029cd 100644 --- a/Changelog +++ b/Changelog @@ -20,6 +20,7 @@ interimap (0.5.5) upstream; - test suite: explicitly set ssl_min_protocol=TLSv1 in the Dovecot configuration file (the default as of 2.3.11.3), hence running TLS tests now require Dovecot 2.3 or later. + - documentation: simplify SSL options in the sample configuration files. -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 diff --git a/interimap.sample b/interimap.sample index b4d131c..17c8f7e 100644 --- a/interimap.sample +++ b/interimap.sample @@ -23,10 +23,9 @@ password = xxxxxxxxxxxxxxxx #compress = YES # SSL options -SSL_CApath = /etc/ssl/certs +#SSL_CApath = /etc/ssl/certs #SSL_verify = YES -#SSL_protocols = !SSLv2 !SSLv3 !TLSv1 !TLSv1.1 -#SSL_cipherlist = EECDH+AESGCM:!MEDIUM:!LOW:!EXP:!aNULL:!eNULL +#SSL_protocol_min = !TLSv1.3 #SSL_fingerprint = sha256$29111aea5d5be7e448bdc5c6e8a9d03bc9221c53c09b1cfbe6f953221e24dda0 # vim:ft=dosini diff --git a/pullimap.sample b/pullimap.sample index 136d3d4..d92e645 100644 --- a/pullimap.sample +++ b/pullimap.sample @@ -4,10 +4,9 @@ deliver-method = smtp:[127.0.0.1]:25 purge-after = 90 # SSL options -SSL_CApath = /etc/ssl/certs +#SSL_CApath = /etc/ssl/certs #SSL_verify = YES -#SSL_protocols = !SSLv2 !SSLv3 !TLSv1 !TLSv1.1 -#SSL_cipherlist = EECDH+AESGCM:!MEDIUM:!LOW:!EXP:!aNULL:!eNULL +#SSL_protocol_min = !TLSv1.3 [private] #type = imaps -- cgit v1.2.3 From 765a8c2f7cac073b3b70277160639f8df3acb8ef Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Dec 2020 20:34:07 +0100 Subject: `make release`: also bump libinterimap version and pin it in 'use' declarations. Also, make use the tag doesn't exist, and fail early if we can't detect the version. --- Changelog | 2 ++ Makefile | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Changelog b/Changelog index 37029cd..b9c7df2 100644 --- a/Changelog +++ b/Changelog @@ -10,6 +10,8 @@ interimap (0.5.5) upstream; protocol black/whilelist greatly; this only allows simple min/max bounds, but holes are arguably not very useful here. Using the new settings bumps the required libssl version to 1.1.0. + + `make release`: also bump libinterimap version and pin it in 'use' + declarations. - libinterimap: make $OPENSSL_VERSION global. - libinterimap: use Net::SSLeay::get_version() to get the protocol version string. diff --git a/Makefile b/Makefile index ff62bf1..9f4702d 100644 --- a/Makefile +++ b/Makefile @@ -20,16 +20,21 @@ test: ./tests/run-all release: - @if ! git diff HEAD --quiet -- ./interimap ./pullimap ./Changelog; then \ + @if ! git diff HEAD --quiet -- ./Changelog ./interimap ./pullimap ./lib/Net/IMAP/InterIMAP.pm; then \ echo "Dirty state, refusing to release!" >&2; \ exit 1; \ fi - sed -ri "0,/^( -- .*) .*/ s//\1 $(shell date -R)/" ./Changelog VERS=$$(dpkg-parsechangelog -l Changelog -SVersion 2>/dev/null) && \ - sed -ri "0,/^(our \\\$$VERSION\\s*=\s*)'[0-9.]+'\\s*;/ s//\1'$$VERS';/" \ + if git rev-parse -q --verify "refs/tags/v$$VERS" >/dev/null; then echo "tag exists" 2>/dev/null; exit 1; fi && \ + sed -ri "0,/^( -- .*) .*/ s//\\1 $(shell date -R)/" ./Changelog && \ + sed -ri "0,/^(our\\s+\\\$$VERSION\\s*=\\s*)'[0-9.]+'\\s*;/ s//\\1'$$VERS';/" \ + -- ./interimap ./pullimap && \ + sed -ri "0,/^(package\\s+Net::IMAP::InterIMAP\\s+)v[0-9.]+\\s*;/ s//\\1v$$VERS;/" \ + -- ./lib/Net/IMAP/InterIMAP.pm && \ + sed -ri "0,/^(use\\s+Net::IMAP::InterIMAP\\s+)[0-9.]+(\\s|\\$$)/ s//\\1$$VERS\\2/" \ -- ./interimap ./pullimap && \ git commit -m "Prepare new release v$$VERS." \ - -- ./interimap ./pullimap ./Changelog && \ + -- ./Changelog ./interimap ./pullimap ./lib/Net/IMAP/InterIMAP.pm && \ git tag -sm "Release version $$VERS" "v$$VERS" ## make html CSS="https://guilhem.org/static/css/bootstrap.min.css" BUILD_DOCDIR="$XDG_RUNTIME_DIR/Downloads" -- cgit v1.2.3 From ea120902dfe146cd7f04a289da9fa05a9e06e44c Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Dec 2020 21:24:32 +0100 Subject: typofix, spelling --- Changelog | 14 +++++++------- doc/getting-started.md | 2 +- doc/interimap.1.md | 17 +++++++++-------- doc/pullimap.1.md | 23 ++++++++++++----------- interimap | 2 +- lib/Net/IMAP/InterIMAP.pm | 2 +- tests/preauth-plaintext/t | 2 +- 7 files changed, 32 insertions(+), 30 deletions(-) diff --git a/Changelog b/Changelog index b9c7df2..43fbf8f 100644 --- a/Changelog +++ b/Changelog @@ -7,7 +7,7 @@ interimap (0.5.5) upstream; versions. * libinterimap: deprecate SSL_protocols, obsoleted by new settings SSL_protocol_{min,max}. Using the libssl interface simplifies our - protocol black/whilelist greatly; this only allows simple min/max + protocol black/whitelist greatly; this only allows simple min/max bounds, but holes are arguably not very useful here. Using the new settings bumps the required libssl version to 1.1.0. + `make release`: also bump libinterimap version and pin it in 'use' @@ -54,7 +54,7 @@ interimap (0.5.4) upstream; interimap (0.5.3) upstream; - * libinterimap: SSL_fingerprint now supports a space-separate list of + * libinterimap: SSL_fingerprint now supports a space-separated list of digests to pin, and succeeds if, and only if, the peer certificate SPKI matches one of the pinned digest values. Specifying multiple digest values can key useful in key rollover scenarios and/or when @@ -103,7 +103,7 @@ interimap (0.5) upstream; (regardless of the hierarchy delimiter in use). Other changes: - * interimap: the space-speparated list of names and/or patterns in + * interimap: the space-separated list of names and/or patterns in 'list-mailbox' can now contain C-style escape sequences (backslash and hexadecimal escape). * interimap: fail when two non-INBOX LIST replies return different @@ -111,7 +111,7 @@ interimap (0.5) upstream; happen if mailboxes from different namespaces are being listed. The workaround here is to run a new interimap instance for each namespace. - * libinterimap: in tunnel mode, use a socketpair rather than two pipes + * libinterimap: in tunnel mode, use a socket pair rather than two pipes for IPC between the interimap and the IMAP server. Also, use SOCK_CLOEXEC to save an fcntl() call when setting the close-on-exec flag on the socket. @@ -174,7 +174,7 @@ interimap (0.5) upstream; - libinterimap: use directories relative to $HOME for the XDG environment variables default values. Previously getpwuid() was called to determine the user's home directory, while the XDG - specification explicitely mentions $HOME. Conveniently our docs + specification explicitly mentions $HOME. Conveniently our docs always mentioned ~/, which on POSIX-compliant systems expands to the value of the variable HOME. (Cf. Shell and Utilities volume of POSIX.1-2017, sec. 2.6.1.) @@ -188,7 +188,7 @@ interimap (0.5) upstream; - libinterimap: push_flag_updates(): ignore UIDs for which no untagged FETCH response was received. - libinterimap: push_flag_updates(): don't ignores received updates (by - another client) to a superset of the desigred flag list. + another client) to a superset of the desired flag list. - libinterimap: avoid sending large UID EXPUNGE|FETCH|STORE commands as they might exceed the server's max acceptable command size; these commands are now split into multiple (sequential) commands when their @@ -198,7 +198,7 @@ interimap (0.5) upstream; This is a also a workaround for a bug in Dovecot 2.3.4: https://dovecot.org/pipermail/dovecot/2019-November/117522.html - interimap: for the reason explained above, limit number of messages - to 128 per APPEND command (only on servers advertizing MULTIAPPEND, + to 128 per APPEND command (only on servers advertising MULTIAPPEND, for other servers the number remains 1). - interimap: gracefully ignore messages with a NIL RFC822 attribute. - pullimap: treat messages with a NIL RFC822 attribute as empty. diff --git a/doc/getting-started.md b/doc/getting-started.md index 83d3ba9..74fc8da 100644 --- a/doc/getting-started.md +++ b/doc/getting-started.md @@ -20,7 +20,7 @@ format][mbox]). Local mail clients usually access it directly. They also often maintain their own cache in order to speed up message header listing and searches. -While most bidirectional synchronisation software (such as [OfflineIMAP]) +While most bidirectional synchronization software (such as [OfflineIMAP]) are able to handle a mail storage in Maildir format, *InterIMAP is not*. Instead, InterIMAP needs an [IMAP4rev1] server on *both* peers to synchronize. This may sound like a severe limitation at first, but by diff --git a/doc/interimap.1.md b/doc/interimap.1.md index 9b14a49..2310cb3 100644 --- a/doc/interimap.1.md +++ b/doc/interimap.1.md @@ -249,7 +249,7 @@ Valid options are: Two wildcards are available, and passed verbatim to the IMAP server: a ‘\*’ character matches zero or more characters, while a ‘%’ character matches zero or more characters up to the hierarchy - delimiter. Hardcoding the hierarchy delimiter in this setting is + delimiter. Hard-coding the hierarchy delimiter in this setting is not advised because the server might silently change it at some point. A null character should be used instead. For instance, if *list-mailbox* is set `"foo\x00bar"` then, assuming the hierarchy @@ -309,7 +309,7 @@ Valid options are: `type=imap` and `type=imaps` are respectively used for IMAP and IMAP over SSL/TLS connections over an INET socket. `type=tunnel` causes `interimap` to create an unnamed pair of - connected sockets for interprocess communication with a *command* + connected sockets for inter-process communication with a *command* instead of opening a network socket. Note that specifying `type=tunnel` in the `[remote]` section makes the default *database* to be `localhost.db`. @@ -383,13 +383,14 @@ Valid options are: *SSL_protocols* -: A space-separated list of SSL protocols to explicitly enable or - disable (if prefixed with an exclamation mark `!`. Known protocols - are `SSLv2`, `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`. +: Space-separated list of SSL/TLS protocol versions to explicitly + enable (or disable if prefixed with an exclamation mark `!`). Known + protocols are `SSLv2`, `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and + `TLSv1.3`. Enabling a protocol is a short-hand for disabling all other protocols. - *Deprecacted*: Use *SSL_protocol_min* and/or *SSL_protocol_max* + *DEPRECATED*: Use *SSL_protocol_min* and/or *SSL_protocol_max* instead. *SSL_protocol_min*, *SSL_protocol_max* @@ -398,7 +399,7 @@ Valid options are: connection. Accepted values are `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`. -*SSL_cipher_list* +*SSL_cipherlist* : The cipher list to send to the server. Although the server determines which cipher suite is used, it should take the first @@ -428,7 +429,7 @@ Valid options are: *SSL_verify* -: Whether to 1/ verify the server certificate chain, and 2/ match its +: Whether to 1/ verify the server certificate chain; and 2/ match its Subject Alternative Name (SAN) or Subject CommonName (CN) against the value of the *host* option. (Default: `YES`.) diff --git a/doc/pullimap.1.md b/doc/pullimap.1.md index 028cbaa..cf6ec52 100644 --- a/doc/pullimap.1.md +++ b/doc/pullimap.1.md @@ -106,14 +106,14 @@ Valid options are: *deliver-ehlo* -: Hostname to use in `EHLO` or `LHLO` commands. +: Name to use in `EHLO` or `LHLO` commands. (Default: `localhost.localdomain`.) *deliver-rcpt* : Message recipient. Note that the local part needs to quoted if it contains special characters; see [RFC 5321] for details. - (Default: the username associated with the effective uid of the + (Default: the username associated with the effective user ID of the `pullimap` process.) *purge-after* @@ -123,7 +123,7 @@ Valid options are: `SEARCH` criterion ignoring time and timezone.) If *purge-after* is set to `0` then messages are deleted immediately after delivery. Otherwise `pullimap` issues an IMAP `SEARCH` (or - extended `SEARCH` on servers advertizing the [`ESEARCH`][RFC 4731] + extended `SEARCH` on servers advertising the [`ESEARCH`][RFC 4731] capability) command to list old messages; if `--idle` is set then the `SEARCH` command is issued again every 12 hours. @@ -133,7 +133,7 @@ Valid options are: `type=imap` and `type=imaps` are respectively used for IMAP and IMAP over SSL/TLS connections over an INET socket. `type=tunnel` causes `pullimap` to create an unnamed pair of - connected sockets for interprocess communication with a *command* + connected sockets for inter-process communication with a *command* instead of opening a network socket. (Default: `imaps`.) @@ -202,13 +202,14 @@ Valid options are: *SSL_protocols* -: A space-separated list of SSL protocols to explicitly enable or - disable (if prefixed with an exclamation mark `!`. Known protocols - are `SSLv2`, `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`. +: Space-separated list of SSL/TLS protocol versions to explicitly + enable (or disable if prefixed with an exclamation mark `!`). Known + protocols are `SSLv2`, `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and + `TLSv1.3`. Enabling a protocol is a short-hand for disabling all other protocols. - *Deprecacted*: Use *SSL_protocol_min* and/or *SSL_protocol_max* + *DEPRECATED*: Use *SSL_protocol_min* and/or *SSL_protocol_max* instead. *SSL_protocol_min*, *SSL_protocol_max* @@ -217,7 +218,7 @@ Valid options are: connection. Accepted values are `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`. -*SSL_cipher_list* +*SSL_cipherlist* : The cipher list to send to the server. Although the server determines which cipher suite is used, it should take the first @@ -247,7 +248,7 @@ Valid options are: *SSL_verify* -: Whether to 1/ verify the server certificate chain, and 2/ match its +: Whether to 1/ verify the server certificate chain; and 2/ match its Subject Alternative Name (SAN) or Subject CommonName (CN) against the value of the *host* option. (Default: `YES`.) @@ -330,7 +331,7 @@ In more details, `pullimap` works as follows: to terminate it gracefully. 3. Issue a `UID STORE` command to mark all retrieved messages (and - stalled UIDs found in the *statefile* after the eigth byte) as + stalled UIDs found in the *statefile* after the eighth byte) as `\Seen`. 4. Update the *statefile* with the new UIDNEXT value (bytes 5-8). diff --git a/interimap b/interimap index 68cb60b..67651d4 100755 --- a/interimap +++ b/interimap @@ -286,7 +286,7 @@ sub list_mailboxes($) { my ($m) = sort keys %$delims; $imap->{delimiter} = delete $delims->{$m}; } else { - # didn't get a non-INBOX LIST reply so we need to explicitely query + # didn't get a non-INBOX LIST reply so we need to explicitly query # the hierarchy delimiter get_delimiter($name, $imap, $ref); } diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 49ea343..2e36d6e 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -1371,7 +1371,7 @@ sub push_flag_updates($$@) { $modified->{$uid} //= [ 0, undef ]; } elsif (defined (my $m = $modified->{$uid})) { # received an untagged FETCH response, remove from the list of pending changes - # if the flag list was up to date (either implicitely or explicitely) + # if the flag list was up to date (either implicitely or explicitly) if (!defined $m->[1] or $m->[1] eq $flags) { delete $modified->{$uid}; push @ok, $uid; diff --git a/tests/preauth-plaintext/t b/tests/preauth-plaintext/t index 427d57b..bc287dd 100644 --- a/tests/preauth-plaintext/t +++ b/tests/preauth-plaintext/t @@ -10,7 +10,7 @@ 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 -- cgit v1.2.3 From 4d2ad4a3c2b6bcdb97934264bc3d37a8c63239d4 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 12 Dec 2020 10:57:12 +0100 Subject: gitignore: Exclude aspell(1)'s backup copies. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9dae7e6..2267ea4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *~ +*.bak /doc/*.1 /doc/*.html !/doc/template.html -- cgit v1.2.3 From 22ef303cdc7b6d5f7de35d3189fbf157093c258e Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 12 Dec 2020 11:29:02 +0100 Subject: README: use 'restrict' option in authorized_keys(5) snippet. This is shorter and more future-proof. Quoting the manual: restrict Enable all restrictions, i.e. disable port, agent and X11 forwarding, as well as disabling PTY allocation and execution of ~/.ssh/rc. If any future restriction capabilities are added to authorized_keys files they will be included in this set. Note that this won't work with Jessie's OpenSSH server. --- Changelog | 2 ++ README | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 43fbf8f..196c01d 100644 --- a/Changelog +++ b/Changelog @@ -23,6 +23,8 @@ interimap (0.5.5) upstream; configuration file (the default as of 2.3.11.3), hence running TLS tests now require Dovecot 2.3 or later. - documentation: simplify SSL options in the sample configuration files. + - README: suggest 'restrict,command="/usr/bin/doveadm exec imap"' as + authorized_keys(5) options. -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 diff --git a/README b/README index d969da0..cee8443 100644 --- a/README +++ b/README @@ -69,7 +69,7 @@ type=imaps. Compression yes remote: ~user/.ssh/authorized_keys: - command="/usr/lib/dovecot/imap",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-... id-interimap + restrict,command="/usr/bin/doveadm exec imap" ssh-[…] id-interimap However for long-lived connections (using the --watch command-line option), the TLS overhead becomes negligible hence the advantage offered -- cgit v1.2.3 From d961f6e9069308927f4882978d95706f408ef944 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 12 Dec 2020 12:12:50 +0100 Subject: README: suggest ControlPath=$XDG_RUNTIME_DIR/ssh-imap-%C for the SSH transport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not a good idea to use a world-writable directory, see ssh_config(5)… Note that variable expansion is only available in OpenSSH 8.4 and later, cf. https://bugzilla.mindrot.org/show_bug.cgi?id=3140 . --- Changelog | 3 +++ README | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 196c01d..4bc426b 100644 --- a/Changelog +++ b/Changelog @@ -25,6 +25,9 @@ interimap (0.5.5) upstream; - documentation: simplify SSL options in the sample configuration files. - README: suggest 'restrict,command="/usr/bin/doveadm exec imap"' as authorized_keys(5) options. + - README: suggest ControlPath=$XDG_RUNTIME_DIR/ssh-imap-%C for the SSH + transport (note that variable expansion is only available in OpenSSH + 8.4 and later). -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 diff --git a/README b/README index cee8443..d2b8942 100644 --- a/README +++ b/README @@ -59,7 +59,7 @@ type=imaps. Host imap.example.net IdentityFile ~/.ssh/id-interimap IdentitiesOnly yes - ControlPath /run/shm/%u@%n + ControlPath ${XDG_RUNTIME_DIR}/ssh-imap-%C ControlMaster auto ControlPersist 10m StrictHostKeyChecking yes -- cgit v1.2.3 From 2dc741fe5a127b4d10bef0e001d10459b2c5e9ef Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 12 Dec 2020 16:35:25 +0100 Subject: README: Reflow with tw=78. --- README | 89 ++++++++++++++++++++++++++++++++---------------------------------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/README b/README index d2b8942..c241486 100644 --- a/README +++ b/README @@ -1,54 +1,51 @@ InterIMAP is a fast bidirectional synchronization program for QRESYNC-capable IMAP4rev1 servers. PullIMAP retrieves messages a remote IMAP mailbox and -deliver them to an SMTP session. Visit https://guilhem.org/interimap -for more information. +deliver them to an SMTP session. Visit https://guilhem.org/interimap for more +information. -_______________________________________________________________________ +______________________________________________________________________________ -Compared to IMAP-to-Maildir synchronization solutions like OfflineIMAP, -adding an IMAP server between the Maildir storage and the MUA saves -loads of readdir(2) system calls and other File System quirks; moreover -the abstraction layer offered by the IMAP server makes the MUA and -synchronization program agnostic to the storage backend (Maildir, mbox, -dbox,...) in use. +Compared to IMAP-to-Maildir synchronization solutions like OfflineIMAP, adding +an IMAP server between the Maildir storage and the MUA saves loads of +readdir(2) system calls and other File System quirks; moreover the abstraction +layer offered by the IMAP server makes the MUA and synchronization program +agnostic to the storage backend (Maildir, mbox, dbox,...) in use. IMAP synchronization of a mailbox is usually two-folds: 1/ detect and -propagate changes (flag updates and message deletions) to existing -messages, then 2/ copy the new messages. The naive way to perform the -first step is to issue a FETCH command to list all messages in the -mailbox along with their flags and UIDs, causing heavy network usage. -Instead, InterIMAP takes advantage of the QRESYNC extension from -[RFC7162] to perform stateful synchronization: querying changes since -the last synchronization only gives a phenomenal performance boost and -drastically reduces the network traffic. +propagate changes (flag updates and message deletions) to existing messages, +then 2/ copy the new messages. The naive way to perform the first step is to +issue a FETCH command to list all messages in the mailbox along with their +flags and UIDs, causing heavy network usage. Instead, InterIMAP takes +advantage of the QRESYNC extension from [RFC7162] to perform stateful +synchronization: querying changes since the last synchronization only gives a +phenomenal performance boost and drastically reduces the network traffic. -For convenience reasons servers must also support LIST-EXTENDED -[RFC5258], LIST-STATUS [RFC5819] and UIDPLUS [RFC4315]. Other supported -extensions are: - * LITERAL+ [RFC2088] non-synchronizing literals (recommended), - * MULTIAPPEND [RFC3502] (recommended), - * COMPRESS=DEFLATE [RFC4978] (recommended), - * SASL-IR [RFC4959] SASL Initial Client Response, and +For convenience reasons servers must also support LIST-EXTENDED [RFC5258], +LIST-STATUS [RFC5819] and UIDPLUS [RFC4315]. Other supported extensions are: + + * LITERAL+ [RFC2088] non-synchronizing literals (recommended); + * MULTIAPPEND [RFC3502] (recommended); + * COMPRESS=DEFLATE [RFC4978] (recommended); + * SASL-IR [RFC4959] SASL Initial Client Response; and * UNSELECT [RFC3691]. -_______________________________________________________________________ +______________________________________________________________________________ -IMAP traffic is mostly text (beside message bodies perhaps) hence -compresses pretty well: enabling compression can save a great amount of -network resources. +IMAP traffic is mostly text (beside message bodies perhaps) hence compresses +pretty well: enabling compression can save a great amount of network +resources. However establishing an SSL/TLS connection (type=imaps, or type=imap and STARTTLS=YES) yields a small overhead due to the SSL/TLS handshake. On the other hand if SSH access is allowed on the remote server, one can -tunnel the IMAP traffic through SSH and use OpenSSH's ControlPersist -feature to save most of the cryptographic overhead (at the expense of a -local 'ssh' process and a remote 'imap' process). Moreover if the IMAP -user is a valid UNIX user it is possible to use pre-authentication on -the remote server as well, which saves the extra round trip caused by -the AUTHENTICATE command. For instance the following configuration -snippet saves bandwidth and brings a significant speed gain compared to -type=imaps. +tunnel the IMAP traffic through SSH and use OpenSSH's ControlPersist feature +to save most of the cryptographic overhead (at the expense of a local 'ssh' +process and a remote 'imap' process). Moreover if the IMAP user is a valid +UNIX user it is possible to use pre-authentication on the remote server as +well, which saves the extra round trip caused by the AUTHENTICATE command. +For instance the following configuration snippet saves bandwidth and brings a +significant speed gain compared to type=imaps. local: $XDG_CONFIG_HOME/interimap/config: [remote] @@ -71,15 +68,15 @@ type=imaps. remote: ~user/.ssh/authorized_keys: restrict,command="/usr/bin/doveadm exec imap" ssh-[…] id-interimap -However for long-lived connections (using the --watch command-line -option), the TLS overhead becomes negligible hence the advantage offered -by the OpenSSH ControlPersist feature is not obvious. Furthermore if -the remote server supports the IMAP COMPRESS extension [RFC4978], adding -compress=DEFLATE to the configuration can also greatly reduce bandwidth -usage with regular INET sockets (type=imaps or type=imap). +However for long-lived connections (using the --watch command-line option), +the TLS overhead becomes negligible hence the advantage offered by the OpenSSH +ControlPersist feature is not obvious. Furthermore if the remote server +supports the IMAP COMPRESS extension [RFC4978], adding compress=DEFLATE to the +configuration can also greatly reduce bandwidth usage with regular INET +sockets (type=imaps or type=imap). -_______________________________________________________________________ +______________________________________________________________________________ -InterIMAP is Copyright© 2015-2020 Guilhem Moulin ⟨guilhem@fripost.org⟩, -and licensed for use under the GNU General Public License version 3 or -later. See ‘COPYING’ for specific terms and distribution information. +InterIMAP is Copyright© 2015-2020 Guilhem Moulin ⟨guilhem@fripost.org⟩, and +licensed for use under the GNU General Public License version 3 or later. See +‘COPYING’ for specific terms and distribution information. -- cgit v1.2.3 From 2d301be3df763be39d12d214779cf2320b426696 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 13 Dec 2020 12:31:32 +0100 Subject: Fix broken URLs. --- lib/Net/IMAP/InterIMAP.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 2e36d6e..6afca07 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -1627,7 +1627,7 @@ sub _proxify($$$$) { # $self->_ssl_verify($self, $preverify_ok, $x509_ctx) # SSL verify callback function, see -# https://www.openssl.org/docs/manmaster/ssl/SSL_CTX_set_verify.html +# https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_verify.html sub _ssl_verify($$$) { my ($self, $ok, $x509_ctx) = @_; return 0 unless $x509_ctx; # reject @@ -1748,10 +1748,10 @@ sub _start_ssl($$) { $ssl_options |= $SSL_proto{$_} foreach @proto_exclude; } - # https://www.openssl.org/docs/manmaster/ssl/SSL_CTX_set_options.html + # https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html Net::SSLeay::CTX_set_options($ctx, $ssl_options); - # https://www.openssl.org/docs/manmaster/ssl/SSL_CTX_set_mode.html + # https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_mode.html Net::SSLeay::CTX_set_mode($ctx, Net::SSLeay::MODE_ENABLE_PARTIAL_WRITE() | Net::SSLeay::MODE_ACCEPT_MOVING_WRITE_BUFFER() | -- cgit v1.2.3 From b70d9b261a6d2849efeb670b53e0ab726a58fb59 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 13 Dec 2020 15:07:30 +0100 Subject: Make error messages more uniform and consistent. --- Changelog | 1 + lib/Net/IMAP/InterIMAP.pm | 52 +++++++++++++++++++++--------------------- pullimap | 8 +++---- tests/preauth-plaintext/imapd | 2 +- tests/starttls-injection/imapd | 20 ++++++++-------- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/Changelog b/Changelog index 4bc426b..931e526 100644 --- a/Changelog +++ b/Changelog @@ -12,6 +12,7 @@ interimap (0.5.5) upstream; settings bumps the required libssl version to 1.1.0. + `make release`: also bump libinterimap version and pin it in 'use' declarations. + + Make error messages more uniform and consistent. - libinterimap: make $OPENSSL_VERSION global. - libinterimap: use Net::SSLeay::get_version() to get the protocol version string. diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 6afca07..3745aad 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -328,19 +328,19 @@ sub new($%) { my $pid = fork // $self->panic("fork: $!"); unless ($pid) { # children - close($self->{S}) or $self->panic("Can't close: $!"); - open STDIN, '<&', $s or $self->panic("Can't dup: $!"); - open STDOUT, '>&', $s or $self->panic("Can't dup: $!"); + close($self->{S}) or $self->panic("close: $!"); + open STDIN, '<&', $s or $self->panic("dup: $!"); + open STDOUT, '>&', $s or $self->panic("dup: $!"); my $stderr2; if (($self->{'null-stderr'} // 0) and !($self->{debug} // 0)) { open $stderr2, '>&', *STDERR; - open STDERR, '>', '/dev/null' or $self->panic("Can't open /dev/null: $!"); + open STDERR, '>', '/dev/null' or $self->panic("open(/dev/null): $!"); } my $sigset = POSIX::SigSet::->new(SIGINT); my $oldsigset = POSIX::SigSet::->new(); - sigprocmask(SIG_BLOCK, $sigset, $oldsigset) // $self->panic("Can't block SIGINT: $!"); + sigprocmask(SIG_BLOCK, $sigset, $oldsigset) // $self->panic("sigprocmask: $!"); unless (exec $command) { my $err = $!; @@ -348,12 +348,12 @@ sub new($%) { close STDERR; open STDERR, '>&', $stderr2; } - $self->panic("Can't exec: $err"); + $self->panic("exec: $err"); } } # parent - close($s) or $self->panic("Can't close: $!"); + close($s) or $self->panic("close: $!"); } else { foreach (qw/host port/) { @@ -363,9 +363,9 @@ sub new($%) { : $self->_tcp_connect(@$self{qw/host port/}); if (defined $self->{keepalive}) { setsockopt($self->{S}, Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1) - or $self->fail("Can't setsockopt SO_KEEPALIVE: $!"); + or $self->fail("setsockopt SO_KEEPALIVE: $!"); setsockopt($self->{S}, Socket::IPPROTO_TCP, Socket::TCP_KEEPIDLE, 60) - or $self->fail("Can't setsockopt TCP_KEEPIDLE: $!"); + or $self->fail("setsockopt TCP_KEEPIDLE: $!"); } } @@ -1493,9 +1493,9 @@ sub _tcp_connect($$$) { # https://stackoverflow.com/questions/8284243/how-do-i-set-so-rcvtimeo-on-a-socket-in-perl my $timeout = pack('l!l!', 30, 0); setsockopt($s, Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, $timeout) - or $self->fail("Can't setsockopt SO_RCVTIMEO: $!"); + or $self->fail("setsockopt SO_RCVTIMEO: $!"); setsockopt($s, Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, $timeout) - or $self->fail("Can't setsockopt SO_RCVTIMEO: $!"); + or $self->fail("setsockopt SO_RCVTIMEO: $!"); until (connect($s, $ai->{addr})) { next if $! == EINTR; # try again if connect(2) was interrupted by a signal @@ -1512,7 +1512,7 @@ sub _xwrite($$$) { while ($length > 0) { my $n = syswrite($_[0], $_[1], $length, $offset); - $self->fail("Can't write: $!") unless defined $n and $n > 0; + $self->fail("write: $!") unless defined $n and $n > 0; $offset += $n; $length -= $n; } @@ -1524,7 +1524,7 @@ sub _xread($$$) { my $offset = 0; my $buf; while ($length > 0) { - my $n = sysread($fh, $buf, $length, $offset) // $self->fail("Can't read: $!"); + my $n = sysread($fh, $buf, $length, $offset) // $self->fail("read: $!"); $self->fail("0 bytes read (got EOF)") unless $n > 0; # EOF $offset += $n; $length -= $n; @@ -1582,7 +1582,7 @@ sub _proxify($$$$) { my ($err, $ipaddr) = getnameinfo($_->{addr}, NI_NUMERICHOST, NIx_NOSERV); $err eq '' ? [$ipaddr,$_->{family}] : undef } @res; - $self->fail("Can't getnameinfo") unless defined $addr; + $self->fail("getnameinfo") unless defined $addr; ($hostip, $fam) = @$addr; } @@ -1704,7 +1704,7 @@ my %SSL_protocol_versions = ( # Upgrade the $socket to SSL/TLS. sub _start_ssl($$) { my ($self, $socket) = @_; - my $ctx = Net::SSLeay::CTX_new() or $self->panic("Failed to create SSL_CTX $!"); + my $ctx = Net::SSLeay::CTX_new() or $self->panic("SSL_CTX_new(): $!"); if (defined $self->{_OUTBUF} and $self->{_OUTBUF} ne '') { $self->warn("Truncating non-empty output buffer (unauthenticated response injection?)"); @@ -1749,6 +1749,7 @@ sub _start_ssl($$) { } # https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html + # TODO 0.6: move SSL_CTX_set_options() and SSL_CTX_set_mode() before SSL_CTX_set_{min,max}_proto_version() Net::SSLeay::CTX_set_options($ctx, $ssl_options); # https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_mode.html @@ -1758,9 +1759,8 @@ sub _start_ssl($$) { Net::SSLeay::MODE_AUTO_RETRY() | # don't fail SSL_read on renegotiation Net::SSLeay::MODE_RELEASE_BUFFERS() ); - if (defined (my $ciphers = $self->{SSL_cipherlist})) { - Net::SSLeay::CTX_set_cipher_list($ctx, $ciphers) - or $self->_ssl_error("Can't set cipher list"); + if (defined (my $str = $self->{SSL_cipherlist})) { + $self->_ssl_error("SSL_CTX_set_cipher_list()") unless Net::SSLeay::CTX_set_cipher_list($ctx, $str) == 1; } my $vpm = Net::SSLeay::X509_VERIFY_PARAM_new() or $self->_ssl_error("X509_VERIFY_PARAM_new()"); @@ -1777,8 +1777,8 @@ sub _start_ssl($$) { # verify certificate chain my ($file, $path) = ($self->{SSL_CAfile} // '', $self->{SSL_CApath} // ''); if ($file ne '' or $path ne '') { - Net::SSLeay::CTX_load_verify_locations($ctx, $file, $path) - or $self->_ssl_error("Can't load verify locations"); + $self->_ssl_error("SSL_CTX_load_verify_locations()") + unless Net::SSLeay::CTX_load_verify_locations($ctx, $file, $path) == 1; } # verify DNS hostname or IP literal @@ -1797,14 +1797,14 @@ sub _start_ssl($$) { Net::SSLeay::CTX_set_verify($ctx, Net::SSLeay::VERIFY_PEER(), sub($$) {$self->_ssl_verify(@_)}); $self->_ssl_error("CTX_SSL_set1_param()") unless Net::SSLeay::CTX_set1_param($ctx, $vpm) == 1; - my $ssl = Net::SSLeay::new($ctx) or $self->fail("Can't create new SSL structure"); - Net::SSLeay::set_fd($ssl, fileno $socket) or $self->fail("SSL filehandle association failed"); + my $ssl = Net::SSLeay::new($ctx) or $self->fail("SSL_new()"); + $self->fail("SSL_set_fd()") unless Net::SSLeay::set_fd($ssl, fileno($socket)) == 1; - # always use 'SSL_hostname' when set, otherwise use 'host' (unless it's an IP) on OpenSSL >=0.9.8f + # always use 'SSL_hostname' when set, otherwise use 'host' (unless it's an IP) my $servername = $self->{SSL_hostname} // (defined $hostipfam ? "" : $host); if ($servername ne "") { $self->panic("Failed requirement libssl >=0.9.8f") if $OPENSSL_VERSION < 0x00908070; - $self->_ssl_error("Can't set TLS servername extension (value $servername)") + $self->_ssl_error("SSL_set_tlsext_host_name($servername)") unless Net::SSLeay::set_tlsext_host_name($ssl, $servername) == 1; $self->log("Using SNI with name $servername") if $self->{debug}; } @@ -1852,7 +1852,7 @@ sub _getline($;$) { $n = sysread($stdout, $buf, $BUFSIZE, 0); } - $self->_ssl_error("Can't read: $!") unless defined $n; + $self->_ssl_error("read: $!") unless defined $n; $self->_ssl_error("0 bytes read (got EOF)") unless $n > 0; # EOF $self->{_OUTRAWCOUNT} += $n; @@ -2065,7 +2065,7 @@ sub _cmd_flush($;$$) { my $written = defined $ssl ? Net::SSLeay::write_partial($ssl, $offset, $length, $self->{_INBUF}) : syswrite($stdin, $self->{_INBUF}, $length, $offset); - $self->_ssl_error("Can't write: $!") unless defined $written and $written > 0; + $self->_ssl_error("write: $!") unless defined $written and $written > 0; $offset += $written; $length -= $written; diff --git a/pullimap b/pullimap index b691272..8142be8 100755 --- a/pullimap +++ b/pullimap @@ -104,7 +104,7 @@ do { # Read a UID (32-bits integer) from the statefile, or undef if we're at # the end of the statefile sub readUID() { - my $n = sysread($STATE, my $buf, 4) // die "Can't sysread: $!"; + my $n = sysread($STATE, my $buf, 4) // die "read: $!"; return if $n == 0; # EOF # file length is a multiple of 4 bytes, and we always read 4 bytes at a time die "Corrupted state file!" if $n != 4; @@ -117,7 +117,7 @@ sub writeUID($) { my $offset = 0; for ( my $offset = 0 ; $offset < 4 - ; $offset += syswrite($STATE, $uid, 4-$offset, $offset) // die "Can't syswrite: $!" + ; $offset += syswrite($STATE, $uid, 4-$offset, $offset) // die "write: $!" ) {} # no need to sync (or flush) since $STATE is opened with O_DSYNC } @@ -333,11 +333,11 @@ sub pull(;$) { undef $SMTP; # update the statefile - my $p = sysseek($STATE, 4, SEEK_SET) // die "Can't seek: $!"; + my $p = sysseek($STATE, 4, SEEK_SET) // die "seek: $!"; die "Couldn't seek to 4" unless $p == 4; # safety check my ($uidnext) = $IMAP->get_cache('UIDNEXT'); writeUID($uidnext); - truncate($STATE, 8) // die "Can't truncate"; + truncate($STATE, 8) // die "truncate: $!"; } do { diff --git a/tests/preauth-plaintext/imapd b/tests/preauth-plaintext/imapd index 6196f73..bf2ed72 100755 --- a/tests/preauth-plaintext/imapd +++ b/tests/preauth-plaintext/imapd @@ -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/starttls-injection/imapd b/tests/starttls-injection/imapd index 15c53c7..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.rsa.key", &Net::SSLeay::FILETYPE_PEM) - or die_if_ssl_error("Can't load private key: $!"); + 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_if_ssl_error("Can't load certificate: $!"); + 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"; } } -- cgit v1.2.3 From f3f064a4e0e74088daea091bc62a8141f0e6c0bb Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 13 Dec 2020 16:00:53 +0100 Subject: Explicitly set SSL_verify=1 (default) only once. --- lib/Net/IMAP/InterIMAP.pm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 3745aad..5bdd954 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -1641,7 +1641,7 @@ sub _ssl_verify($$$) { $self->log(' Subject Name: ', Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_subject_name($cert))); } - $ok = 1 unless $self->{SSL_verify} // 1; + $ok = 1 unless $self->{SSL_verify} // die; # safety check, always set if ($depth == 0 and !exists $self->{_SSL_PEER_VERIFIED}) { if ($self->{debug}) { my $algo = 'sha256'; @@ -1705,6 +1705,7 @@ my %SSL_protocol_versions = ( sub _start_ssl($$) { my ($self, $socket) = @_; my $ctx = Net::SSLeay::CTX_new() or $self->panic("SSL_CTX_new(): $!"); + $self->{SSL_verify} //= 1; # default is to perform certificate verification if (defined $self->{_OUTBUF} and $self->{_OUTBUF} ne '') { $self->warn("Truncating non-empty output buffer (unauthenticated response injection?)"); @@ -1770,7 +1771,7 @@ sub _start_ssl($$) { my $host = $self->{host} // $self->panic(); my ($hostip, $hostipfam) = _parse_hostip($host); - if ($self->{SSL_verify} // 1) { + if ($self->{SSL_verify}) { # for X509_VERIFY_PARAM_set1_{ip,host}() $self->panic("Failed requirement libssl >=1.0.2") if $OPENSSL_VERSION < 0x1000200f; @@ -1811,7 +1812,7 @@ sub _start_ssl($$) { $self->_ssl_error("Can't initiate TLS/SSL handshake") unless Net::SSLeay::connect($ssl) == 1; $self->panic() unless $self->{_SSL_PEER_VERIFIED}; # sanity check - $self->panic() if ($self->{SSL_verify} // 1) and Net::SSLeay::get_verify_result($ssl) != Net::SSLeay::X509_V_OK(); + $self->panic() if $self->{SSL_verify} and Net::SSLeay::get_verify_result($ssl) != Net::SSLeay::X509_V_OK(); Net::SSLeay::X509_VERIFY_PARAM_free($vpm); if ($self->{debug}) { -- cgit v1.2.3 From 6dcf633e6dde4c2af549f374de885038f90b7258 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 13 Dec 2020 16:47:41 +0100 Subject: typofix --- interimap.sample | 2 +- pullimap.sample | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interimap.sample b/interimap.sample index 17c8f7e..e54c8a0 100644 --- a/interimap.sample +++ b/interimap.sample @@ -25,7 +25,7 @@ password = xxxxxxxxxxxxxxxx # SSL options #SSL_CApath = /etc/ssl/certs #SSL_verify = YES -#SSL_protocol_min = !TLSv1.3 +#SSL_protocol_min = TLSv1.2 #SSL_fingerprint = sha256$29111aea5d5be7e448bdc5c6e8a9d03bc9221c53c09b1cfbe6f953221e24dda0 # vim:ft=dosini diff --git a/pullimap.sample b/pullimap.sample index d92e645..d911851 100644 --- a/pullimap.sample +++ b/pullimap.sample @@ -6,7 +6,7 @@ purge-after = 90 # SSL options #SSL_CApath = /etc/ssl/certs #SSL_verify = YES -#SSL_protocol_min = !TLSv1.3 +#SSL_protocol_min = TLSv1.2 [private] #type = imaps -- cgit v1.2.3 From ba9d8af01141a6d5d5b98a0e249c311814b844a6 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 13 Dec 2020 17:37:32 +0100 Subject: test suite: ensure we haven't started speaking IMAP when the SSL/TLS handshake is aborted. (Unless STARTTLS is used to upgrade the connection.) --- Changelog | 3 +++ tests/tls-pin-fingerprint/t | 6 ++++-- tests/tls-protocols/t | 6 ++++-- tests/tls-verify-peer/t | 3 ++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Changelog b/Changelog index 931e526..9a36e8a 100644 --- a/Changelog +++ b/Changelog @@ -29,6 +29,9 @@ interimap (0.5.5) upstream; - README: suggest ControlPath=$XDG_RUNTIME_DIR/ssh-imap-%C for the SSH transport (note that variable expansion is only available in OpenSSH 8.4 and later). + - test suite: ensure we haven't started speaking IMAP when the SSL/TLS + handshake is aborted (unless STARTTLS is used to upgrade to + connection). -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 diff --git a/tests/tls-pin-fingerprint/t b/tests/tls-pin-fingerprint/t index 6716833..883a887 100644 --- a/tests/tls-pin-fingerprint/t +++ b/tests/tls-pin-fingerprint/t @@ -41,8 +41,9 @@ EOF 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 # two invalid ones with_remote_config <<-EOF @@ -53,8 +54,9 @@ EOF 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 diff --git a/tests/tls-protocols/t b/tests/tls-protocols/t index b65d93c..ecf7e49 100644 --- a/tests/tls-protocols/t +++ b/tests/tls-protocols/t @@ -38,8 +38,9 @@ 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} @@ -88,7 +89,8 @@ with_remote_tls_protocol_min_max "SSLv3" "SSLv3" 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 +# 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 : diff --git a/tests/tls-verify-peer/t b/tests/tls-verify-peer/t index 17018a6..8cc098a 100644 --- a/tests/tls-verify-peer/t +++ b/tests/tls-verify-peer/t @@ -15,8 +15,9 @@ unverified_peer() { [ -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 -- cgit v1.2.3 From 8c43ed9baa905d907a6aad77de2282a852ba69a9 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 13 Dec 2020 17:43:52 +0100 Subject: libinterimap: use default locations for trusted CA certificates when neither CAfile nor CApath are set. In particular, OpenSSL's default locations can be overridden by the SSL_CERT_FILE resp. SSL_CERT_DIR environment variables, see SSL_CTX_load_verify_locations(3ssl). This bumps the minimum OpenSSL version to 1.1.0 (when SSL_verify is used). --- Changelog | 6 ++++++ doc/interimap.1.md | 14 ++++++++++---- doc/pullimap.1.md | 14 ++++++++++---- interimap.sample | 1 - lib/Net/IMAP/InterIMAP.pm | 10 +++++++--- pullimap.sample | 1 - tests/run | 3 +++ tests/tls-verify-peer/t | 27 ++++++++++++++++++++++++--- 8 files changed, 60 insertions(+), 16 deletions(-) diff --git a/Changelog b/Changelog index 9a36e8a..2fbdf36 100644 --- a/Changelog +++ b/Changelog @@ -10,6 +10,12 @@ interimap (0.5.5) upstream; protocol black/whitelist greatly; this only allows simple min/max bounds, but holes are arguably not very useful here. Using the new settings bumps the required libssl version to 1.1.0. + * libinterimap: use default locations for trusted CA certificates when + neither CAfile nor CApath are set. In particular, OpenSSL's default + locations can be overridden by the SSL_CERT_FILE resp. SSL_CERT_DIR + environment variables, see SSL_CTX_load_verify_locations(3ssl). + This bumps the minimum OpenSSL version to 1.1.0 (when SSL_verify is + used). + `make release`: also bump libinterimap version and pin it in 'use' declarations. + Make error messages more uniform and consistent. diff --git a/doc/interimap.1.md b/doc/interimap.1.md index 2310cb3..63d5ab0 100644 --- a/doc/interimap.1.md +++ b/doc/interimap.1.md @@ -439,6 +439,14 @@ Valid options are: measure as it pins directly its key material and ignore its chain of trust. +*SSL_CAfile* + +: File containing trusted certificates to use during server + certificate verification when `SSL_verify=YES`. + + Trusted CA certificates are loaded from the default system locations + unless one (or both) of *SSL_CAfile* or *SSL_CApath* is set. + *SSL_CApath* : Directory to use for server certificate verification when @@ -446,10 +454,8 @@ Valid options are: This directory must be in “hash format”, see [`verify`(1ssl)] for more information. -*SSL_CAfile* - -: File containing trusted certificates to use during server - certificate verification when `SSL_verify=YES`. + Trusted CA certificates are loaded from the default system locations + unless one (or both) of *SSL_CAfile* or *SSL_CApath* is set. *SSL_hostname* diff --git a/doc/pullimap.1.md b/doc/pullimap.1.md index cf6ec52..05cbcaf 100644 --- a/doc/pullimap.1.md +++ b/doc/pullimap.1.md @@ -258,6 +258,14 @@ Valid options are: measure as it pins directly its key material and ignore its chain of trust. +*SSL_CAfile* + +: File containing trusted certificates to use during server + certificate verification when `SSL_verify=YES`. + + Trusted CA certificates are loaded from the default system locations + unless one (or both) of *SSL_CAfile* or *SSL_CApath* is set. + *SSL_CApath* : Directory to use for server certificate verification when @@ -265,10 +273,8 @@ Valid options are: This directory must be in “hash format”, see [`verify`(1ssl)] for more information. -*SSL_CAfile* - -: File containing trusted certificates to use during server - certificate verification when `SSL_verify=YES`. + Trusted CA certificates are loaded from the default system locations + unless one (or both) of *SSL_CAfile* or *SSL_CApath* is set. *SSL_hostname* diff --git a/interimap.sample b/interimap.sample index e54c8a0..36eeb2a 100644 --- a/interimap.sample +++ b/interimap.sample @@ -23,7 +23,6 @@ password = xxxxxxxxxxxxxxxx #compress = YES # SSL options -#SSL_CApath = /etc/ssl/certs #SSL_verify = YES #SSL_protocol_min = TLSv1.2 #SSL_fingerprint = sha256$29111aea5d5be7e448bdc5c6e8a9d03bc9221c53c09b1cfbe6f953221e24dda0 diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 5bdd954..89e5cba 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -1776,10 +1776,14 @@ sub _start_ssl($$) { $self->panic("Failed requirement libssl >=1.0.2") if $OPENSSL_VERSION < 0x1000200f; # verify certificate chain - my ($file, $path) = ($self->{SSL_CAfile} // '', $self->{SSL_CApath} // ''); - if ($file ne '' or $path ne '') { + if (defined $self->{SSL_CAfile} or defined $self->{SSL_CApath}) { $self->_ssl_error("SSL_CTX_load_verify_locations()") - unless Net::SSLeay::CTX_load_verify_locations($ctx, $file, $path) == 1; + unless Net::SSLeay::CTX_load_verify_locations($ctx, + $self->{SSL_CAfile} // '', $self->{SSL_CApath} // '') == 1; + } else { + $self->log("Using default locations for trusted CA certificates") if $self->{debug}; + $self->_ssl_error("SSL_CTX_set_default_verify_paths()") + unless Net::SSLeay::CTX_set_default_verify_paths($ctx) == 1; } # verify DNS hostname or IP literal diff --git a/pullimap.sample b/pullimap.sample index d911851..f1a66f9 100644 --- a/pullimap.sample +++ b/pullimap.sample @@ -4,7 +4,6 @@ deliver-method = smtp:[127.0.0.1]:25 purge-after = 90 # SSL options -#SSL_CApath = /etc/ssl/certs #SSL_verify = YES #SSL_protocol_min = TLSv1.2 diff --git a/tests/run b/tests/run index 29384ec..329f3e3 100755 --- a/tests/run +++ b/tests/run @@ -209,6 +209,8 @@ _interimap_cmd() { local script="$1" rv=0 shift environ_set "local" + [ -z "${SSL_CERT_FILE+x}" ] || ENVIRON+=( SSL_CERT_FILE="$SSL_CERT_FILE" ) + [ -z "${SSL_CERT_DIR+x}" ] || ENVIRON+=( SSL_CERT_DIR="$SSL_CERT_DIR" ) env -i "${ENVIRON[@]}" perl -I./lib -T "./$script" "$@" 2>"$STDERR" || rv=$? cat <"$STDERR" >&2 return $rv @@ -445,6 +447,7 @@ passed() { # Run test in a sub-shell declare -a ENVIRON=() environ_set "local" +unset SSL_CERT_FILE SSL_CERT_DIR export TMPDIR TESTDIR STDERR "${ENVIRON[@]}" OPENSSL_CONF export -f environ_set doveadm interimap interimap_init pullimap _interimap_cmd export -f sqlite3 sample_message deliver ptree_abort step_start step_done passed diff --git a/tests/tls-verify-peer/t b/tests/tls-verify-peer/t index 8cc098a..8326521 100644 --- a/tests/tls-verify-peer/t +++ b/tests/tls-verify-peer/t @@ -46,7 +46,9 @@ with_remote_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" @@ -54,13 +56,23 @@ 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" +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" @@ -71,6 +83,10 @@ fi with_remote_config <<<"SSL_CAfile = $capath/ca-certificates.crt" verified_peer +with_remote_config Date: Sun, 13 Dec 2020 18:15:39 +0100 Subject: libinterimap: _start_ssl() now fails immediately with OpenSSL <1.1.0. It could in principle still work with earlier versions if the new settings SSL_protocol_{min,max} are not used, however it's cumbersome to do individual checks for specific settings, let alone maintain test coverage with multiple OpenSSL versions. --- Changelog | 10 ++++++---- lib/Net/IMAP/InterIMAP.pm | 11 +++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Changelog b/Changelog index 2fbdf36..773065d 100644 --- a/Changelog +++ b/Changelog @@ -8,14 +8,16 @@ interimap (0.5.5) upstream; * libinterimap: deprecate SSL_protocols, obsoleted by new settings SSL_protocol_{min,max}. Using the libssl interface simplifies our protocol black/whitelist greatly; this only allows simple min/max - bounds, but holes are arguably not very useful here. Using the new - settings bumps the required libssl version to 1.1.0. + bounds, but holes are arguably not very useful here. * libinterimap: use default locations for trusted CA certificates when neither CAfile nor CApath are set. In particular, OpenSSL's default locations can be overridden by the SSL_CERT_FILE resp. SSL_CERT_DIR environment variables, see SSL_CTX_load_verify_locations(3ssl). - This bumps the minimum OpenSSL version to 1.1.0 (when SSL_verify is - used). + * libinterimap: _start_ssl() now fails immediately with OpenSSL <1.1.0. + It could in principle still work with earlier versions if the new + settings SSL_protocol_{min,max} are not used, however it's cumbersome + to do individual checks for specific settings, let alone maintain + test coverage with multiple OpenSSL versions. + `make release`: also bump libinterimap version and pin it in 'use' declarations. + Make error messages more uniform and consistent. diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 89e5cba..99d3a0e 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -48,7 +48,6 @@ my $RE_LIST_CHAR = qr/[\x21\x23-\x27\x2A\x2B-\x5B\x5D-\x7A\x7C-\x7E]/; my $RE_TEXT_CHAR = qr/[\x01-\x09\x0B\x0C\x0E-\x7F]/; my $RE_SSL_PROTO = qr/(?:SSLv[23]|TLSv1|TLSv1\.[0-3])/; -my $OPENSSL_VERSION = Net::SSLeay::OPENSSL_VERSION_NUMBER(); # Map each option to a regexp validating its values. my %OPTIONS = ( @@ -1704,6 +1703,11 @@ my %SSL_protocol_versions = ( # Upgrade the $socket to SSL/TLS. sub _start_ssl($$) { my ($self, $socket) = @_; + # need OpenSSL 1.1.0 or later for SSL_CTX_set_min_proto_version(3ssl), see + # https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_set_min_proto_version.html + $self->panic("SSL/TLS functions require OpenSSL 1.1.0 or later") + if Net::SSLeay::OPENSSL_VERSION_NUMBER() < 0x1010000f; + my $ctx = Net::SSLeay::CTX_new() or $self->panic("SSL_CTX_new(): $!"); $self->{SSL_verify} //= 1; # default is to perform certificate verification @@ -1716,7 +1720,6 @@ sub _start_ssl($$) { $ssl_options |= Net::SSLeay::OP_NO_COMPRESSION(); if (defined $self->{SSL_protocol_min} or defined $self->{SSL_protocol_max}) { - $self->panic("Failed requirement libssl >=1.1.0") if $OPENSSL_VERSION < 0x1010000f; my ($min, $max) = @$self{qw/SSL_protocol_min SSL_protocol_max/}; if (defined $min) { my $v = $SSL_protocol_versions{$min} // $self->panic("Unknown protocol version: $min"); @@ -1772,9 +1775,6 @@ sub _start_ssl($$) { my $host = $self->{host} // $self->panic(); my ($hostip, $hostipfam) = _parse_hostip($host); if ($self->{SSL_verify}) { - # for X509_VERIFY_PARAM_set1_{ip,host}() - $self->panic("Failed requirement libssl >=1.0.2") if $OPENSSL_VERSION < 0x1000200f; - # verify certificate chain if (defined $self->{SSL_CAfile} or defined $self->{SSL_CApath}) { $self->_ssl_error("SSL_CTX_load_verify_locations()") @@ -1808,7 +1808,6 @@ sub _start_ssl($$) { # always use 'SSL_hostname' when set, otherwise use 'host' (unless it's an IP) my $servername = $self->{SSL_hostname} // (defined $hostipfam ? "" : $host); if ($servername ne "") { - $self->panic("Failed requirement libssl >=0.9.8f") if $OPENSSL_VERSION < 0x00908070; $self->_ssl_error("SSL_set_tlsext_host_name($servername)") unless Net::SSLeay::set_tlsext_host_name($ssl, $servername) == 1; $self->log("Using SNI with name $servername") if $self->{debug}; -- cgit v1.2.3 From ae2e4297e0a298444e94e89264e5d814a34ec61d Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 13 Dec 2020 18:47:51 +0100 Subject: manual: improve wording. --- doc/interimap.1.md | 4 ++-- doc/pullimap.1.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/interimap.1.md b/doc/interimap.1.md index 63d5ab0..bcd27f9 100644 --- a/doc/interimap.1.md +++ b/doc/interimap.1.md @@ -424,8 +424,8 @@ Valid options are: Specifying multiple digest values can be useful in key rollover scenarios and/or when the server supports certificates of different - types (for instance RSA+ECDSA). In that case the connection is - aborted when none of the specified digests matches. + types (for instance a dual-cert RSA/ECDSA setup). In that case the + connection is aborted when none of the specified digests matches. *SSL_verify* diff --git a/doc/pullimap.1.md b/doc/pullimap.1.md index 05cbcaf..94fa831 100644 --- a/doc/pullimap.1.md +++ b/doc/pullimap.1.md @@ -243,8 +243,8 @@ Valid options are: Specifying multiple digest values can be useful in key rollover scenarios and/or when the server supports certificates of different - types (for instance RSA+ECDSA). In that case the connection is - aborted when none of the specified digests matches. + types (for instance a dual-cert RSA/ECDSA setup). In that case the + connection is aborted when none of the specified digests matches. *SSL_verify* -- cgit v1.2.3 From 9c8b3460c4ae5026066aff9ea1b7d38716c893a8 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 13 Dec 2020 23:02:22 +0100 Subject: Remove obsolete Changelog entry. --- Changelog | 1 - 1 file changed, 1 deletion(-) diff --git a/Changelog b/Changelog index 773065d..000e3a1 100644 --- a/Changelog +++ b/Changelog @@ -21,7 +21,6 @@ interimap (0.5.5) upstream; + `make release`: also bump libinterimap version and pin it in 'use' declarations. + Make error messages more uniform and consistent. - - libinterimap: make $OPENSSL_VERSION global. - libinterimap: use Net::SSLeay::get_version() to get the protocol version string. - test suite: `mv tests/snippets tests/config` -- cgit v1.2.3 From 43516b78b6b626bb6df522e4f1c5166989d79eb5 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 13 Dec 2020 23:47:15 +0100 Subject: typofix --- lib/Net/IMAP/InterIMAP.pm | 2 +- tests/tls-protocols/t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 99d3a0e..856c5c8 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -1732,7 +1732,7 @@ sub _start_ssl($$) { $self->log("Maximum SSL/TLS protocol version: ", $max) if $self->{debug}; } } elsif (defined (my $protos = $self->{SSL_protocols})) { # TODO deprecated, remove in 0.6 - $self->warn("SSL_protocols is deprecated and will be removed in a future release! ", + $self->warn("SSL_protocols is deprecated and will be removed in a future release! " . "Use SSL_protocol_{min,max} instead."); my ($proto_include, $proto_exclude) = (0, 0); foreach (split /\s+/, $protos) { diff --git a/tests/tls-protocols/t b/tests/tls-protocols/t index ecf7e49..c302731 100644 --- a/tests/tls-protocols/t +++ b/tests/tls-protocols/t @@ -19,7 +19,7 @@ grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1, TLSv1.2" <"$ST grep -E "^remote: SSL protocol: TLSv1\.3 " <"$STDERR" || error interimap || error -grep -E "^remote: SSL_protocols is deprecated " <"$STDERR" || error "no deprecation message" +grep -E "^remote: WARNING: SSL_protocols is deprecated " <"$STDERR" || error "no deprecation warning" # force TLSv1.2 with_remote_tls_protocols "TLSv1.2" -- cgit v1.2.3 From 30c2bc3c362a4eb6b35560cff0bd95404360fe22 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 17 Dec 2020 13:47:09 +0100 Subject: test suite: use stock OpenSSL config except for tests/tls-protocols. It's best to use a stock (clean) environment when possible. We only need to test TLS protocol version <1.2 for tests/tls-protocols. --- Changelog | 2 +- tests/config/openssl.cnf | 14 -------------- tests/run | 9 +++++---- tests/tls-protocols/openssl.cnf | 14 ++++++++++++++ tests/tls-protocols/t | 3 +++ 5 files changed, 23 insertions(+), 19 deletions(-) delete mode 100644 tests/config/openssl.cnf create mode 100644 tests/tls-protocols/openssl.cnf diff --git a/Changelog b/Changelog index 000e3a1..c401c2d 100644 --- a/Changelog +++ b/Changelog @@ -24,7 +24,7 @@ interimap (0.5.5) upstream; - libinterimap: use Net::SSLeay::get_version() to get the protocol version string. - test suite: `mv tests/snippets tests/config` - - test suite: supply our own OpenSSL configuration file with + - tests/tls-protocols: use custom OpenSSL configuration file with MinProtocol=None so we can test TLSv1 as well, not just TLSv1.2 and later. - test suite: explicitly set ssl_min_protocol=TLSv1 in the Dovecot diff --git a/tests/config/openssl.cnf b/tests/config/openssl.cnf deleted file mode 100644 index 980097d..0000000 --- a/tests/config/openssl.cnf +++ /dev/null @@ -1,14 +0,0 @@ -# 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 diff --git a/tests/run b/tests/run index 329f3e3..1eaad54 100755 --- a/tests/run +++ b/tests/run @@ -35,6 +35,9 @@ if [ ! -d "$TESTDIR" ]; then exit 1 fi +# cleanup environment +unset OPENSSL_CONF SSL_CERT_FILE SSL_CERT_DIR + ROOTDIR="$(mktemp --tmpdir="${TMPDIR:-/dev/shm}" --directory "$1.XXXXXXXXXX")" declare -a DOVECOT_SERVER=() trap cleanup EXIT INT TERM @@ -57,13 +60,11 @@ mkdir -- "$TMPDIR" "$ROOTDIR/home" declare -a REMOTES=() # Set environment for the given user -OPENSSL_CONF="$BASEDIR/config/openssl.cnf" environ_set() { local user="$1" home eval home="\$HOME_$user" ENVIRON=( PATH="$PATH" - OPENSSL_CONF="$OPENSSL_CONF" USER="$user" HOME="$home" XDG_CONFIG_HOME="$home/.config" @@ -209,6 +210,7 @@ _interimap_cmd() { local script="$1" rv=0 shift environ_set "local" + [ -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" ) env -i "${ENVIRON[@]}" perl -I./lib -T "./$script" "$@" 2>"$STDERR" || rv=$? @@ -447,8 +449,7 @@ passed() { # Run test in a sub-shell declare -a ENVIRON=() environ_set "local" -unset SSL_CERT_FILE SSL_CERT_DIR -export TMPDIR TESTDIR STDERR "${ENVIRON[@]}" OPENSSL_CONF +export TMPDIR TESTDIR 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/tls-protocols/openssl.cnf b/tests/tls-protocols/openssl.cnf new file mode 100644 index 0000000..980097d --- /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 diff --git a/tests/tls-protocols/t b/tests/tls-protocols/t index c302731..72f7db2 100644 --- a/tests/tls-protocols/t +++ b/tests/tls-protocols/t @@ -5,6 +5,9 @@ interimap --debug || 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() { -- cgit v1.2.3 From 1a19feb7a4b3d70f44e4e1fb0f9920b063842422 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 17 Dec 2020 14:54:34 +0100 Subject: manuals: Clarify that known TLS protocol versions depend on the OpenSSL version used. --- Changelog | 2 ++ doc/interimap.1.md | 12 +++++++----- doc/pullimap.1.md | 12 +++++++----- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Changelog b/Changelog index c401c2d..afee1ca 100644 --- a/Changelog +++ b/Changelog @@ -39,6 +39,8 @@ interimap (0.5.5) upstream; - test suite: ensure we haven't started speaking IMAP when the SSL/TLS handshake is aborted (unless STARTTLS is used to upgrade to connection). + - documentation: Clarify that known TLS protocol versions depend on the + OpenSSL version used. -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 diff --git a/doc/interimap.1.md b/doc/interimap.1.md index bcd27f9..ae6224b 100644 --- a/doc/interimap.1.md +++ b/doc/interimap.1.md @@ -384,9 +384,10 @@ Valid options are: *SSL_protocols* : Space-separated list of SSL/TLS protocol versions to explicitly - enable (or disable if prefixed with an exclamation mark `!`). Known - protocols are `SSLv2`, `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and - `TLSv1.3`. + enable (or disable if prefixed with an exclamation mark `!`). + Potentially known protocols are `SSLv2`, `SSLv3`, `TLSv1`, + `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`, depending on the OpenSSL + version used. Enabling a protocol is a short-hand for disabling all other protocols. @@ -396,8 +397,9 @@ Valid options are: *SSL_protocol_min*, *SSL_protocol_max* : Set minimum resp. maximum SSL/TLS protocol version to use for the - connection. Accepted values are `SSLv3`, `TLSv1`, `TLSv1.1`, - `TLSv1.2`, and `TLSv1.3`. + connection. Potentially recognized values are `SSLv3`, `TLSv1`, + `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`, depending on the OpenSSL + version used. *SSL_cipherlist* diff --git a/doc/pullimap.1.md b/doc/pullimap.1.md index 94fa831..b0bc2fd 100644 --- a/doc/pullimap.1.md +++ b/doc/pullimap.1.md @@ -203,9 +203,10 @@ Valid options are: *SSL_protocols* : Space-separated list of SSL/TLS protocol versions to explicitly - enable (or disable if prefixed with an exclamation mark `!`). Known - protocols are `SSLv2`, `SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, and - `TLSv1.3`. + enable (or disable if prefixed with an exclamation mark `!`). + Potentially known protocols are `SSLv2`, `SSLv3`, `TLSv1`, + `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`, depending on the OpenSSL + version used. Enabling a protocol is a short-hand for disabling all other protocols. @@ -215,8 +216,9 @@ Valid options are: *SSL_protocol_min*, *SSL_protocol_max* : Set minimum resp. maximum SSL/TLS protocol version to use for the - connection. Accepted values are `SSLv3`, `TLSv1`, `TLSv1.1`, - `TLSv1.2`, and `TLSv1.3`. + connection. Potentially recognized values are `SSLv3`, `TLSv1`, + `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`, depending on the OpenSSL + version used. *SSL_cipherlist* -- cgit v1.2.3 From 57988c83bb4b3f1780f045880ac4a8f36a51c55c Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 17 Dec 2020 17:38:17 +0100 Subject: libinterimap: new option SSL_ciphersuites to set the TLSv1.3 ciphersuites. Also, clarify that SSL_cipherlist only applies to TLSv1.2 and below. See SSL_CTX_set_cipher_list(3ssl). --- Changelog | 3 +++ doc/interimap.1.md | 12 +++++++----- doc/pullimap.1.md | 12 +++++++----- lib/Net/IMAP/InterIMAP.pm | 4 ++++ tests/list | 1 + tests/tls-ciphers/interimap.remote | 1 + tests/tls-ciphers/remote.conf | 1 + tests/tls-ciphers/t | 31 +++++++++++++++++++++++++++++++ tests/tls-rsa+ecdsa/t | 4 +++- 9 files changed, 58 insertions(+), 11 deletions(-) create mode 120000 tests/tls-ciphers/interimap.remote create mode 120000 tests/tls-ciphers/remote.conf create mode 100644 tests/tls-ciphers/t diff --git a/Changelog b/Changelog index afee1ca..29ca360 100644 --- a/Changelog +++ b/Changelog @@ -18,6 +18,9 @@ interimap (0.5.5) upstream; settings SSL_protocol_{min,max} are not used, however it's cumbersome to do individual checks for specific settings, let alone maintain test coverage with multiple OpenSSL versions. + * libinterimap: new option SSL_ciphersuites to set the TLSv1.3 + ciphersuites; also, clarify that SSL_cipherlist only applies to + TLSv1.2 and below, see SSL_CTX_set_cipher_list(3ssl). + `make release`: also bump libinterimap version and pin it in 'use' declarations. + Make error messages more uniform and consistent. diff --git a/doc/interimap.1.md b/doc/interimap.1.md index ae6224b..2d588ae 100644 --- a/doc/interimap.1.md +++ b/doc/interimap.1.md @@ -401,12 +401,14 @@ Valid options are: `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`, depending on the OpenSSL version used. -*SSL_cipherlist* +*SSL_cipherlist*, *SSL_ciphersuites* -: The cipher list to send to the server. Although the server - determines which cipher suite is used, it should take the first - supported cipher in the list sent by the client. See - [`ciphers`(1ssl)] for more information. +: Sets the TLSv1.2 and below cipher list resp. TLSv1.3 cipher suites. + The combination of these lists is sent to the server, which then + determines which cipher to use (normally the first supported one + from the list sent by the client). The default suites depend on the + OpenSSL version and its configuration, see [`ciphers`(1ssl)] for + more information. *SSL_fingerprint* diff --git a/doc/pullimap.1.md b/doc/pullimap.1.md index b0bc2fd..89969b2 100644 --- a/doc/pullimap.1.md +++ b/doc/pullimap.1.md @@ -220,12 +220,14 @@ Valid options are: `TLSv1.1`, `TLSv1.2`, and `TLSv1.3`, depending on the OpenSSL version used. -*SSL_cipherlist* +*SSL_cipherlist*, *SSL_ciphersuites* -: The cipher list to send to the server. Although the server - determines which cipher suite is used, it should take the first - supported cipher in the list sent by the client. See - [`ciphers`(1ssl)] for more information. +: Sets the TLSv1.2 and below cipher list resp. TLSv1.3 cipher suites. + The combination of these lists is sent to the server, which then + determines which cipher to use (normally the first supported one + from the list sent by the client). The default suites depend on the + OpenSSL version and its configuration, see [`ciphers`(1ssl)] for + more information. *SSL_fingerprint* diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 856c5c8..09f510f 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -67,6 +67,7 @@ my %OPTIONS = ( SSL_protocol_max => qr/\A(\P{Control}+)\z/, SSL_fingerprint => qr/\A((?:[A-Za-z0-9]+\$)?\p{AHex}+(?: (?:[A-Za-z0-9]+\$)?\p{AHex}+)*)\z/, SSL_cipherlist => qr/\A(\P{Control}+)\z/, + SSL_ciphersuites => qr/\A(\P{Control}*)\z/, # "an empty list is permissible" SSL_hostname => qr/\A(\P{Control}*)\z/, SSL_verify => qr/\A(YES|NO)\z/i, SSL_CApath => qr/\A(\P{Control}+)\z/, @@ -1766,6 +1767,9 @@ sub _start_ssl($$) { if (defined (my $str = $self->{SSL_cipherlist})) { $self->_ssl_error("SSL_CTX_set_cipher_list()") unless Net::SSLeay::CTX_set_cipher_list($ctx, $str) == 1; } + if (defined (my $str = $self->{SSL_ciphersuites})) { + $self->_ssl_error("SSL_CTX_set_ciphersuites()") unless Net::SSLeay::CTX_set_ciphersuites($ctx, $str) == 1; + } my $vpm = Net::SSLeay::X509_VERIFY_PARAM_new() or $self->_ssl_error("X509_VERIFY_PARAM_new()"); my $purpose = Net::SSLeay::X509_PURPOSE_SSL_SERVER(); diff --git a/tests/list b/tests/list index cb31a73..d1058ba 100644 --- a/tests/list +++ b/tests/list @@ -54,6 +54,7 @@ split-set Split large sets to avoid extra-long command lines 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 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..0dfc771 --- /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=sh : diff --git a/tests/tls-rsa+ecdsa/t b/tests/tls-rsa+ecdsa/t index 8b811fd..c9f5b96 100644 --- a/tests/tls-rsa+ecdsa/t +++ b/tests/tls-rsa+ecdsa/t @@ -36,7 +36,9 @@ grep -Fx -e "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_S -e "remote: Peer certificate matches pinned SPKI digest sha256\$$PKEY_ALT_SHA256" \ <"$STDERR" || error -# force RSA (XXX do we really have to force TLSv1.2 here?) +# 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 -- cgit v1.2.3 From 28949bd234e3d977bc2dfc10df3a76a921cc2c07 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 17 Dec 2020 19:08:48 +0100 Subject: typofix --- Changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 29ca360..6e9cf1c 100644 --- a/Changelog +++ b/Changelog @@ -42,7 +42,7 @@ interimap (0.5.5) upstream; - test suite: ensure we haven't started speaking IMAP when the SSL/TLS handshake is aborted (unless STARTTLS is used to upgrade to connection). - - documentation: Clarify that known TLS protocol versions depend on the + - documentation: clarify that known TLS protocol versions depend on the OpenSSL version used. -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 -- cgit v1.2.3 From 9cbaed6527c3030819976dbe41bfb4392d6a6fa2 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 26 Dec 2020 23:11:11 +0100 Subject: Prepare new release v0.5.5. --- Changelog | 2 +- interimap | 4 ++-- lib/Net/IMAP/InterIMAP.pm | 2 +- pullimap | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Changelog b/Changelog index 6e9cf1c..cba8719 100644 --- a/Changelog +++ b/Changelog @@ -45,7 +45,7 @@ interimap (0.5.5) upstream; - documentation: clarify that known TLS protocol versions depend on the OpenSSL version used. - -- Guilhem Moulin Fri, 11 Dec 2020 14:55:53 +0100 + -- Guilhem Moulin Sat, 26 Dec 2020 23:11:10 +0100 interimap (0.5.4) upstream; diff --git a/interimap b/interimap index 67651d4..7bb86f6 100755 --- a/interimap +++ b/interimap @@ -22,7 +22,7 @@ use v5.14.2; use strict; use warnings; -our $VERSION = '0.5.4'; +our $VERSION = '0.5.5'; my $NAME = 'interimap'; my $DATABASE_VERSION = 1; use Getopt::Long qw/:config posix_default no_ignore_case gnu_compat @@ -32,7 +32,7 @@ use DBD::SQLite::Constants ':file_open'; use Fcntl qw/F_GETFD F_SETFD FD_CLOEXEC/; use List::Util 'first'; -use Net::IMAP::InterIMAP 0.0.5 qw/xdg_basedir read_config compact_set/; +use Net::IMAP::InterIMAP 0.5.5 qw/xdg_basedir read_config compact_set/; # Clean up PATH $ENV{PATH} = join ':', qw{/usr/bin /bin}; diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 09f510f..0c4fc89 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -16,7 +16,7 @@ # along with this program. If not, see . #---------------------------------------------------------------------- -package Net::IMAP::InterIMAP v0.0.5; +package Net::IMAP::InterIMAP v0.5.5; use v5.20.0; use warnings; use strict; diff --git a/pullimap b/pullimap index 8142be8..9edbcf7 100755 --- a/pullimap +++ b/pullimap @@ -22,7 +22,7 @@ use v5.20.2; use strict; use warnings; -our $VERSION = '0.5.4'; +our $VERSION = '0.5.5'; my $NAME = 'pullimap'; use Errno 'EINTR'; @@ -31,7 +31,7 @@ use Getopt::Long qw/:config posix_default no_ignore_case gnu_getopt auto_version use List::Util 'first'; use Socket qw/PF_INET PF_INET6 SOCK_STREAM IPPROTO_TCP/; -use Net::IMAP::InterIMAP 0.0.5 qw/xdg_basedir read_config compact_set/; +use Net::IMAP::InterIMAP 0.5.5 qw/xdg_basedir read_config compact_set/; # Clean up PATH $ENV{PATH} = join ':', qw{/usr/bin /bin}; -- cgit v1.2.3