Bug#914034: Bug#911938: libhttp-daemon-ssl-perl FTBFS: tests fail: Connection refused

Guilhem Moulin guilhem at debian.org
Mon May 13 20:50:04 BST 2019


On Mon, 13 May 2019 at 06:31:26 +0200, Steffen Ullrich wrote:
> Additionally switching off SSL_MODE_AUTO_RETRY would actually just add
> a different unexpected behavior: that sysread might return with EAGAIN
> on a blocking socket.

FWIW as shown below that's always been the case, until OpenSSL 1.1.1a
where SSL_MODE_AUTO_RETRY was switched on by default, so I'd say it's
wrong to expect that it won't :-P  Also I'm not arguing that the default
should be toggled back in IO::Socket::SSL, but that it should have a
flag to optionally revert to the old OpenSSL default.

Please consider the following code, which uses blocking I/O and merely
echoes what's being received from the SSL/TLS server.

    perl -I. -MIO::Socket::SSL -e '
        my $sock = IO::Socket::SSL->new(
            PeerAddr => "127.0.0.1:4433",
            SSL_ca_file => "/tmp/cert.pem"
        ) // die;
        while(1) {
            my $buf = "";
            $sock->sysread($buf, 4096) //
                die "errno=\"$!\", SSL_ERROR=\"$SSL_ERROR\"\n";
            print $buf;
        }'

Running in a Stretch chroot (libssl1.1 1.1.0j-1~deb9u1, libnet-ssleay-perl
1.80-1, and IO::Socket::SSL upstream 2.066), it dies with the following
message when the server renegotiates the TLSv1.2 session (“r\n” command
in the `s_server` input):

    errno="Resource temporarily unavailable", SSL_ERROR="SSL wants a read first"

That's expected because SSL_read() fails and SSL_get_error() returns
SSL_ERROR_WANT_READ.  That code is broken as it doesn't inspect
$SSL_ERROR on sysread failure, and treats retryable errors as fatal.
With TLSv1.3 (but ensuring SSL_MODE_AUTO_RETRY is still unset) it's way
worse because it dies immediately after the handshake, not “just” when
the session is renegotiated.  In that light it makes sense that the
OpenSSL developers have switched SSL_MODE_AUTO_RETRY on by default.

Now with an OpenSSL version where SSL_MODE_AUTO_RETRY is set by default,
SSL_read() automatically retries and blocks until application data is
received, so the above program keeps looping as expected.  Automatic
retrying in lower-level functions is a fine default, but unfortunately
breaks applications that *were* relying on SSL_read() *not* blocking
when only non-application data was received.  That's why there needs to
be a way to optionally switch it back off.  Changing these programs to
use non-blocking I/O is clearly much more invasive.

> I've added more information regarding this to the IO::Socket::SSL
> documentation:
> https://github.com/noxxi/p5-io-socket-ssl/commit/ee176e489f02bfaaa479fc8d9312c8458bf55565

| A sysread on the IO::Socket::SSL socket will not return any data
| though since it is an abstraction which only returns application data.
| This causes the sysread to hang in case the socket was blocking

As shown above this is incorrect for OpenSSL <1.1.1a's (or any later
OpenSSL version where SSL_MODE_AUTO_RETRY was switched off).  There
IO::Socket::SSL::sysread() doesn't hang, but instead fails immediately
and sets $SSL_ERROR to SSL_ERROR_WANT_READ (and $! to EAGAIN).  While
setting errno to EAGAIN is specific to IO::Socket::SSL (and AFAICT
undocumented for blocking I/O), the manpage for SSL_read() and its higher
level bindings & wrappers, incl. IO::Socket::SSL, explicitly says that
upon failure one should first check SSL_get_error() for SSL-specific
errors, i.e., not rely on the errno value unless the SSL error code is
SSL_ERROR_SYSCALL.  That also applies to blocking I/O.

-- 
Guilhem.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://alioth-lists.debian.net/pipermail/pkg-perl-maintainers/attachments/20190513/b1eb91b8/attachment.sig>


More information about the pkg-perl-maintainers mailing list