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. --- lib/Net/IMAP/InterIMAP.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/Net/IMAP') 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 -- 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(-) (limited to 'lib/Net/IMAP') 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(-) (limited to 'lib/Net/IMAP') 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(-) (limited to 'lib/Net/IMAP') 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 feeb91998a29ca040f6e5dd103e09507a6355e32 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin 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(-) (limited to 'lib/Net/IMAP') 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 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(-) (limited to 'lib/Net/IMAP') 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 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(-) (limited to 'lib/Net/IMAP') 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(-) (limited to 'lib/Net/IMAP') 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(-) (limited to 'lib/Net/IMAP') 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 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(-) (limited to 'lib/Net/IMAP') 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(-) (limited to 'lib/Net/IMAP') 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 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(-) (limited to 'lib/Net/IMAP') 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 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 (limited to 'lib/Net/IMAP') 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 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(-) (limited to 'lib/Net/IMAP') 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