Skip Menu |

This queue is for tickets about the POE-Component-SSLify CPAN distribution.

Report information
The Basics
Id: 126976
Status: open
Priority: 0/
Queue: POE-Component-SSLify

People
Owner: Nobody in particular
Requestors: ppisar [...] redhat.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 1.012
Fixed in: (no value)



Subject: t/connect_hook_nodata.t fails with OpenSSL 1.1.1
OpenSSL released 1.1.1 prerelease that implements TLSv1.3 and enables it by default. TLSv1.3 differs from TLSv1.2 and patched Net-SSLeay (CPAN RT#125218) is needed. With these a POE-Component-SSLify-1.012 test still fails: $ perl -Ilib t/connect_hook_nodata.t ok 1 - SERVER: SSLify_Options ok 2 - SERVER: Server_SSLify ok 3 - SERVER: SSLify_GetStatus is pending ok 4 - SERVER: accepted ok 5 - CLIENT: Client_SSLify ok 6 - CLIENT: SSLify_GetStatus is pending ok 7 - CLIENT: connected ok 8 - CLIENT: Got callback hook ok 9 - CLIENT: Status received from callback is OK ok 10 - CLIENT: SSLify_GetCipher: TLS_AES_256_GCM_SHA384 ok 11 - CLIENT: SSLify_GetStatus is done ok 12 - SERVER: Got callback hook not ok 13 - SERVER: Status received from callback is OK # Failed test 'SERVER: Status received from callback is OK' # at t/connect_hook_nodata.t line 57. # got: '0' # expected: '1' ok 14 - SERVER: SSLify_GetCipher: TLS_AES_256_GCM_SHA384 not ok 15 - SERVER: SSLify_GetStatus is done # Failed test 'SERVER: SSLify_GetStatus is done' # at t/connect_hook_nodata.t line 62. ok 16 - SERVER: client disconnected 1..16 # Looks like you failed 2 tests of 16. There are other differences in TLS resulting in SIGPIPE OpenSSL issue <https://github.com/openssl/openssl/issues/6904#issuecomment-411811600> being more prominent. (In short, if a client closes TCP connection to fast, TLS server will fail in SSL_accept() on EPIPE error from writing to the server socket descriptor). And this cannot be masked by Net-SSLeay because Net-SSLeay is a low-level wrapper exposing bare OpenSSL API. After adding some debugging to ServerHandle::_check_status() one can see it's because the of the same SIGIPE issue: $ perl -Ilib t/connect_hook_nodata.t ok 1 - SERVER: SSLify_Options ok 2 - SERVER: Server_SSLify ok 3 - SERVER: SSLify_GetStatus is pending ok 4 - SERVER: accepted ok 5 - CLIENT: Client_SSLify ok 6 - CLIENT: SSLify_GetStatus is pending ok 7 - CLIENT: connected not ok 8 - Test::FailWarnings should catch no warnings # Failed test 'Test::FailWarnings should catch no warnings' # at lib/POE/Component/SSLify/ServerHandle.pm line 74. # Warning was '_check_status(): status=-1, errval=2, errno=Resource temporarily unavailable at lib/POE/Component/SSLify/ServerHandle.pm line 74.' ok 9 - CLIENT: Got callback hook ok 10 - CLIENT: Status received from callback is OK ok 11 - CLIENT: SSLify_GetCipher: TLS_AES_256_GCM_SHA384 ok 12 - CLIENT: SSLify_GetStatus is done not ok 13 - Test::FailWarnings should catch no warnings # Failed test 'Test::FailWarnings should catch no warnings' # at lib/POE/Component/SSLify/ServerHandle.pm line 74. # Warning was '_check_status(): status=-1, errval=5, errno=Broken pipe at lib/POE/Component/SSLify/ServerHandle.pm line 74.' ok 14 - SERVER: Got callback hook not ok 15 - SERVER: Status received from callback is OK # Failed test 'SERVER: Status received from callback is OK' # at t/connect_hook_nodata.t line 57. # got: '0' # expected: '1' ok 16 - SERVER: SSLify_GetCipher: TLS_AES_256_GCM_SHA384 not ok 17 - SERVER: SSLify_GetStatus is done # Failed test 'SERVER: SSLify_GetStatus is done' # at t/connect_hook_nodata.t line 62. ok 18 - SERVER: client disconnected 1..18 # Looks like you failed 4 tests of 18. As POE-Component-SSLify is a high-level abstraction, I believe this is the right place for handling the SIGPIPE issue. I believe it can be fixed by properly shutting down the TLS connection. Although this will not help if a foreign TLS client does not perform proper TLS shutdown. But there is not much to do except from pressing OpenSSL developers to resolve the SIGPIPE issue internally.
Dne Út 28.srp.2018 08:56:22, ppisar napsal(a): Show quoted text
> OpenSSL released 1.1.1 prerelease that implements TLSv1.3 and enables > it by default. TLSv1.3 differs from TLSv1.2 and patched Net-SSLeay > (CPAN RT#125218) is needed. With these a POE-Component-SSLify-1.012 > test still fails: > > $ perl -Ilib t/connect_hook_nodata.t > ok 1 - SERVER: SSLify_Options > ok 2 - SERVER: Server_SSLify > ok 3 - SERVER: SSLify_GetStatus is pending > ok 4 - SERVER: accepted > ok 5 - CLIENT: Client_SSLify > ok 6 - CLIENT: SSLify_GetStatus is pending > ok 7 - CLIENT: connected > ok 8 - CLIENT: Got callback hook > ok 9 - CLIENT: Status received from callback is OK > ok 10 - CLIENT: SSLify_GetCipher: TLS_AES_256_GCM_SHA384 > ok 11 - CLIENT: SSLify_GetStatus is done > ok 12 - SERVER: Got callback hook > not ok 13 - SERVER: Status received from callback is OK > # Failed test 'SERVER: Status received from callback is OK' > # at t/connect_hook_nodata.t line 57. > # got: '0' > # expected: '1' > ok 14 - SERVER: SSLify_GetCipher: TLS_AES_256_GCM_SHA384 > not ok 15 - SERVER: SSLify_GetStatus is done > # Failed test 'SERVER: SSLify_GetStatus is done' > # at t/connect_hook_nodata.t line 62. > ok 16 - SERVER: client disconnected > 1..16 > # Looks like you failed 2 tests of 16. > > There are other differences in TLS resulting in SIGPIPE OpenSSL issue > <https://github.com/openssl/openssl/issues/6904#issuecomment-
> 411811600> being more prominent. (In short, if a client closes TCP
> connection to fast, TLS server will fail in SSL_accept() on EPIPE > error from writing to the server socket descriptor). And this cannot > be masked by Net-SSLeay because Net-SSLeay is a low-level wrapper > exposing bare OpenSSL API. > > After adding some debugging to ServerHandle::_check_status() one can > see it's because the of the same SIGIPE issue: > > $ perl -Ilib t/connect_hook_nodata.t > ok 1 - SERVER: SSLify_Options > ok 2 - SERVER: Server_SSLify > ok 3 - SERVER: SSLify_GetStatus is pending > ok 4 - SERVER: accepted > ok 5 - CLIENT: Client_SSLify > ok 6 - CLIENT: SSLify_GetStatus is pending > ok 7 - CLIENT: connected > not ok 8 - Test::FailWarnings should catch no warnings > # Failed test 'Test::FailWarnings should catch no warnings' > # at lib/POE/Component/SSLify/ServerHandle.pm line 74. > # Warning was '_check_status(): status=-1, errval=2, errno=Resource > temporarily unavailable at lib/POE/Component/SSLify/ServerHandle.pm > line 74.' > ok 9 - CLIENT: Got callback hook > ok 10 - CLIENT: Status received from callback is OK > ok 11 - CLIENT: SSLify_GetCipher: TLS_AES_256_GCM_SHA384 > ok 12 - CLIENT: SSLify_GetStatus is done > not ok 13 - Test::FailWarnings should catch no warnings > # Failed test 'Test::FailWarnings should catch no warnings' > # at lib/POE/Component/SSLify/ServerHandle.pm line 74. > # Warning was '_check_status(): status=-1, errval=5, errno=Broken pipe > at lib/POE/Component/SSLify/ServerHandle.pm line 74.' > ok 14 - SERVER: Got callback hook > not ok 15 - SERVER: Status received from callback is OK > # Failed test 'SERVER: Status received from callback is OK' > # at t/connect_hook_nodata.t line 57. > # got: '0' > # expected: '1' > ok 16 - SERVER: SSLify_GetCipher: TLS_AES_256_GCM_SHA384 > not ok 17 - SERVER: SSLify_GetStatus is done > # Failed test 'SERVER: SSLify_GetStatus is done' > # at t/connect_hook_nodata.t line 62. > ok 18 - SERVER: client disconnected > 1..18 > # Looks like you failed 4 tests of 18. > > As POE-Component-SSLify is a high-level abstraction, I believe this is > the right place for handling the SIGPIPE issue. I believe it can be > fixed by properly shutting down the TLS connection. Although this will > not help if a foreign TLS client does not perform proper TLS shutdown. > But there is not much to do except from pressing OpenSSL developers to > resolve the SIGPIPE issue internally.
However, I don't know how to perform nonblocking CLOSE. The fix should start SSL_shutdown in client's and server's CLOSE(). And if Net::SSLeay indicates ERROR_WANT_READ or ERROR_WANT_WRITE the CLOSE() should yield to POE so that the other party can perform the complement operation, and they the CLOSE() should be resumed. I have no experience with POE. Any help is welcomed.
Dne Út 28.srp.2018 08:56:22, ppisar napsal(a): Show quoted text
> There are other differences in TLS resulting in SIGPIPE OpenSSL issue > <https://github.com/openssl/openssl/issues/6904#issuecomment-
> 411811600> being more prominent. (In short, if a client closes TCP
> connection to fast, TLS server will fail in SSL_accept() on EPIPE > error from writing to the server socket descriptor). And this cannot > be masked by Net-SSLeay because Net-SSLeay is a low-level wrapper > exposing bare OpenSSL API. >
Attached patch work arounds this issue and the test failure by disabling session tickets if OpenSSL 1.1.1 is in use. That has a drawback the clients won't be able to quickly resume a TLS session. A proper fix should have done something like this but in a non-blocking way: --- a/lib/POE/Component/SSLify/ServerHandle.pm +++ b/lib/POE/Component/SSLify/ServerHandle.pm @@ -219,6 +219,44 @@ sub BINMODE { sub CLOSE { my $self = shift; if ( defined $self->{'socket'} ) { + if ( $self->{'ssl_started'} ) { + local $SIG{PIPE} = 'IGNORE'; + my $retval; + SHUTDOWN: { + do { + $retval = Net::SSLeay::shutdown( $self->{'ssl'} ); + if ($retval < 0) { + my $errval = Net::SSLeay::get_error( $self->{'ssl'}, + $retval ); + if ( $errval == ERROR_WANT_READ or + $errval == ERROR_WANT_WRITE ) { + # FIXME: We should retry CLOSE by returning to POE, + # but I don't know POE. This code simply blocks. + my $rin = my $win = my $ein = ''; + vec($rin, $self->{'fileno'}, 1) = 1; + vec($win, $self->{'fileno'}, 1) = 1; + $ein = $rin | $win; + print STDERR "WAIT "; + my $nfound = select(my $rout = $rin, + my $wout = $win, my $eout = $ein, undef); + print STDERR "$nfound\n"; + if ($nfound <= 0 || vec($eout, $self->{'fileno'}, 1)) { + last; + } + # Retry + $retval = 0; + } elsif ($retval == 0) { + # SSL_shutdown() require SSL_read() all data between + # first and second SSL_shutdown() + while (defined Net::SSLeay::read( $self->{'ssl'}, 1)) {} + } else { + # Some error, shutdown failed + last; + } + } + } while ($retval == 0); + } + } Net::SSLeay::free( $self->{'ssl'} );
Subject: 0001-Disable-sessions-tickets-with-OpenSSL-1.1.1.patch
From e8356bd6528c1fc66cfa83c70f4907f3d3640697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com> Date: Tue, 28 Aug 2018 16:43:24 +0200 Subject: [PATCH] Disable sessions tickets with OpenSSL 1.1.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This works around an OpenSSL SIGIPE issue causing server crash or SSL_accept() failure. CPAN RT#126976 Signed-off-by: Petr Písař <ppisar@redhat.com> --- lib/POE/Component/SSLify.pm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/POE/Component/SSLify.pm b/lib/POE/Component/SSLify.pm index a12e7a9..d41bc8e 100644 --- a/lib/POE/Component/SSLify.pm +++ b/lib/POE/Component/SSLify.pm @@ -396,6 +396,17 @@ sub _createSSLcontext { die_if_ssl_error( 'certificate' ) if ! $IGNORE_SSL_ERRORS; } + # TLS 1.3 server sends session tickets after a handshake as part of + # the SSL_accept(). If a client finishes all its job including closing + # TCP connectino before a server sends the tickets, SSL_accept() fails + # with SSL_ERROR_SYSCALL and EPIPE errno and the server receives + # SIGPIPE signal. <https://github.com/openssl/openssl/issues/6904>, + # CPAN RT#126976. + if ( &Net::SSLeay::OPENSSL_VERSION_NUMBER >= 0x1010100f ) { + Net::SSLeay::CTX_set_num_tickets( $context, 0 ); + die_if_ssl_error( 'disabling session tickets' ) if $IGNORE_SSL_ERRORS; + } + # All done! return $context; } -- 2.14.4
On Tue Aug 28 10:59:03 2018, ppisar wrote: Show quoted text
> Dne Út 28.srp.2018 08:56:22, ppisar napsal(a):
> > There are other differences in TLS resulting in SIGPIPE OpenSSL issue > > <https://github.com/openssl/openssl/issues/6904#issuecomment-
> > 411811600> being more prominent. (In short, if a client closes TCP
> > connection to fast, TLS server will fail in SSL_accept() on EPIPE > > error from writing to the server socket descriptor). And this cannot > > be masked by Net-SSLeay because Net-SSLeay is a low-level wrapper > > exposing bare OpenSSL API. > >
> Attached patch work arounds this issue and the test failure by > disabling session tickets if OpenSSL 1.1.1 is in use. That has a > drawback the clients won't be able to quickly resume a TLS session. > > A proper fix should have done something like this but in a non- > blocking way: > > --- a/lib/POE/Component/SSLify/ServerHandle.pm > +++ b/lib/POE/Component/SSLify/ServerHandle.pm > @@ -219,6 +219,44 @@ sub BINMODE { > sub CLOSE { > my $self = shift; > if ( defined $self->{'socket'} ) { > + if ( $self->{'ssl_started'} ) { > + local $SIG{PIPE} = 'IGNORE'; > + my $retval; > + SHUTDOWN: { > + do { > + $retval = Net::SSLeay::shutdown( $self->{'ssl'} > ); > + if ($retval < 0) { > + my $errval = Net::SSLeay::get_error( $self-
> >{'ssl'},
> + $retval ); > + if ( $errval == ERROR_WANT_READ or > + $errval == ERROR_WANT_WRITE ) { > + # FIXME: We should retry CLOSE by > returning to POE, > + # but I don't know POE. This code simply > blocks. > + my $rin = my $win = my $ein = ''; > + vec($rin, $self->{'fileno'}, 1) = 1; > + vec($win, $self->{'fileno'}, 1) = 1; > + $ein = $rin | $win; > + print STDERR "WAIT "; > + my $nfound = select(my $rout = $rin, > + my $wout = $win, my $eout = $ein, > undef); > + print STDERR "$nfound\n"; > + if ($nfound <= 0 || vec($eout, $self-
> >{'fileno'}, 1)) {
> + last; > + } > + # Retry > + $retval = 0; > + } elsif ($retval == 0) { > + # SSL_shutdown() require SSL_read() all > data between > + # first and second SSL_shutdown() > + while (defined Net::SSLeay::read( $self-
> >{'ssl'}, 1)) {}
> + } else { > + # Some error, shutdown failed > + last; > + } > + } > + } while ($retval == 0); > + } > + } > Net::SSLeay::free( $self->{'ssl'} );
I also experienced failures in this file when attempting to install this distro today as part of CPAN-river-3000 testing on FreeBSD-12 using perl-5.31.0. ##### "t/00-report-prereqs.t ......... ok", "# ", "# Net::SSLeay::ver_number is 0x1010101f", "# \tOpenSSL 1.1.1a-freebsd 20 Nov 2018", "# \tbuilt on: reproducible build, date unspecified", "# \tplatform: FreeBSD-amd64", "# \tOPENSSLDIR: \"/etc/ssl\"", "# \tpogomips: 31751508", "t/00-ssleay-info.t ............ ok", "t/99_mire_test.t .............. skipped: AUTHOR TEST", "t/apocalypse.t ................ skipped: Test::Apocalypse required for validating the distribution", "t/connect_hook.t .............. ok", "", "# Failed test 'Got SERVER read error 54: Connection reset by peer'", "# at t/connect_hook_nodata.t line 84.", "# Looks like you failed 1 test of 17.", "t/connect_hook_nodata.t ....... ", "Dubious, test returned 1 (wstat 256, 0x100)", "Failed 1/17 subtests ", "t/connfail_client.t ........... ok", ##### Can you investigate? Thank you very much. Jim Keenan