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.
signature.asc
Description: PGP signature