aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog8
-rw-r--r--doc/interimap.1.md9
-rw-r--r--doc/pullimap.1.md9
-rw-r--r--lib/Net/IMAP/InterIMAP.pm32
-rw-r--r--tests/tls-protocols/t64
-rw-r--r--tests/tls-rsa+ecdsa/t2
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