You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
226 lines
7.1 KiB
226 lines
7.1 KiB
10 months ago
|
From e0b42b0120b941b5675e4071445424dc8a1230e1 Mon Sep 17 00:00:00 2001
|
||
|
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
|
||
|
Date: Wed, 15 Aug 2018 14:46:52 +0200
|
||
|
Subject: [PATCH] Move SSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITE retry from
|
||
|
read()/write() up
|
||
|
MIME-Version: 1.0
|
||
|
Content-Type: text/plain; charset=UTF-8
|
||
|
Content-Transfer-Encoding: 8bit
|
||
|
|
||
|
Original OpenSSL 1.1.1 fix broke IO-Socket-SSL-2.058's t/core.t test
|
||
|
because it tests non-blocking socket operations and expects to see
|
||
|
SSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITE errors and to handle them
|
||
|
byt itself.
|
||
|
|
||
|
This patch purifies Net::SSLeay::{read,write}() to behave exactly as
|
||
|
underlying OpenSSL functions. The retry is moved to
|
||
|
Net::SSLeay::ssl_read_all. All relevant Net::SSLeay::{read,write}() calls in
|
||
|
tests are changed into Net::SSLea::ssl_{read,write}_all().
|
||
|
|
||
|
All applications should implement the retry themsleves or use
|
||
|
ssl_*_all() instead.
|
||
|
|
||
|
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
||
|
---
|
||
|
SSLeay.xs | 28 +++++++---------------------
|
||
|
lib/Net/SSLeay.pm | 22 +++++++++++++++-------
|
||
|
t/local/07_sslecho.t | 12 ++++++------
|
||
|
t/local/36_verify.t | 9 +++++----
|
||
|
4 files changed, 33 insertions(+), 38 deletions(-)
|
||
|
|
||
|
diff --git a/SSLeay.xs b/SSLeay.xs
|
||
|
index 5aed4d7..7cb6eab 100644
|
||
|
--- a/SSLeay.xs
|
||
|
+++ b/SSLeay.xs
|
||
|
@@ -1997,19 +1997,13 @@ SSL_read(s,max=32768)
|
||
|
PREINIT:
|
||
|
char *buf;
|
||
|
int got;
|
||
|
+ int succeeded = 1;
|
||
|
PPCODE:
|
||
|
New(0, buf, max, char);
|
||
|
|
||
|
- do {
|
||
|
- int err;
|
||
|
-
|
||
|
- got = SSL_read(s, buf, max);
|
||
|
- if (got > 0)
|
||
|
- break;
|
||
|
- err = SSL_get_error(s, got);
|
||
|
- if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE)
|
||
|
- break;
|
||
|
- } while (1);
|
||
|
+ got = SSL_read(s, buf, max);
|
||
|
+ if (got <= 0 && SSL_ERROR_ZERO_RETURN != SSL_get_error(s, got))
|
||
|
+ succeeded = 0;
|
||
|
|
||
|
/* If in list context, return 2-item list:
|
||
|
* first return value: data gotten, or undef on error (got<0)
|
||
|
@@ -2017,13 +2011,13 @@ SSL_read(s,max=32768)
|
||
|
*/
|
||
|
if (GIMME_V==G_ARRAY) {
|
||
|
EXTEND(SP, 2);
|
||
|
- PUSHs(sv_2mortal(got>=0 ? newSVpvn(buf, got) : newSV(0)));
|
||
|
+ PUSHs(sv_2mortal(succeeded ? newSVpvn(buf, got) : newSV(0)));
|
||
|
PUSHs(sv_2mortal(newSViv(got)));
|
||
|
|
||
|
/* If in scalar or void context, return data gotten, or undef on error. */
|
||
|
} else {
|
||
|
EXTEND(SP, 1);
|
||
|
- PUSHs(sv_2mortal(got>=0 ? newSVpvn(buf, got) : newSV(0)));
|
||
|
+ PUSHs(sv_2mortal(succeeded ? newSVpvn(buf, got) : newSV(0)));
|
||
|
}
|
||
|
|
||
|
Safefree(buf);
|
||
|
@@ -2066,15 +2060,7 @@ SSL_write(s,buf)
|
||
|
INPUT:
|
||
|
char * buf = SvPV( ST(1), len);
|
||
|
CODE:
|
||
|
- do {
|
||
|
- ret = SSL_write (s, buf, (int)len);
|
||
|
- if (ret > 0)
|
||
|
- break;
|
||
|
- err = SSL_get_error(s, ret);
|
||
|
- if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE)
|
||
|
- break;
|
||
|
- } while (1);
|
||
|
- RETVAL = ret;
|
||
|
+ RETVAL = SSL_write (s, buf, (int)len);
|
||
|
OUTPUT:
|
||
|
RETVAL
|
||
|
|
||
|
diff --git a/lib/Net/SSLeay.pm b/lib/Net/SSLeay.pm
|
||
|
index 3adf12c..afc6c8f 100644
|
||
|
--- a/lib/Net/SSLeay.pm
|
||
|
+++ b/lib/Net/SSLeay.pm
|
||
|
@@ -579,14 +579,22 @@ sub debug_read {
|
||
|
sub ssl_read_all {
|
||
|
my ($ssl,$how_much) = @_;
|
||
|
$how_much = 2000000000 unless $how_much;
|
||
|
- my ($got, $errs);
|
||
|
+ my ($got, $rv, $errs);
|
||
|
my $reply = '';
|
||
|
|
||
|
while ($how_much > 0) {
|
||
|
- $got = Net::SSLeay::read($ssl,
|
||
|
+ ($got, $rv) = Net::SSLeay::read($ssl,
|
||
|
($how_much > 32768) ? 32768 : $how_much
|
||
|
);
|
||
|
- last if $errs = print_errs('SSL_read');
|
||
|
+ if (! defined $got) {
|
||
|
+ my $err = Net::SSLeay::get_error($ssl, $rv);
|
||
|
+ if ($err != Net::SSLeay::ERROR_WANT_READ() and
|
||
|
+ $err != Net::SSLeay::ERROR_WANT_WRITE()) {
|
||
|
+ $errs = print_errs('SSL_read');
|
||
|
+ last;
|
||
|
+ }
|
||
|
+ next;
|
||
|
+ }
|
||
|
$how_much -= blength($got);
|
||
|
debug_read(\$reply, \$got) if $trace>1;
|
||
|
last if $got eq ''; # EOF
|
||
|
@@ -839,14 +847,14 @@ sub ssl_read_until ($;$$) {
|
||
|
$found = index($match, $delim);
|
||
|
|
||
|
if ($found > -1) {
|
||
|
- #$got = Net::SSLeay::read($ssl, $found+$len_delim);
|
||
|
+ #$got = Net::SSLeay::ssl_read_all($ssl, $found+$len_delim);
|
||
|
#read up to the end of the delimiter
|
||
|
- $got = Net::SSLeay::read($ssl,
|
||
|
+ $got = Net::SSLeay::ssl_read_all($ssl,
|
||
|
$found + $len_delim
|
||
|
- ((blength($match)) - (blength($got))));
|
||
|
$done = 1;
|
||
|
} else {
|
||
|
- $got = Net::SSLeay::read($ssl, $peek_length);
|
||
|
+ $got = Net::SSLeay::ssl_read_all($ssl, $peek_length);
|
||
|
$done = 1 if ($peek_length == $max_length - blength($reply));
|
||
|
}
|
||
|
|
||
|
@@ -857,7 +865,7 @@ sub ssl_read_until ($;$$) {
|
||
|
}
|
||
|
} else {
|
||
|
while (!defined $max_length || length $reply < $max_length) {
|
||
|
- $got = Net::SSLeay::read($ssl,1); # one by one
|
||
|
+ $got = Net::SSLeay::ssl_read_all($ssl,1); # one by one
|
||
|
last if print_errs('SSL_read');
|
||
|
debug_read(\$reply, \$got) if $trace>1;
|
||
|
last if $got eq '';
|
||
|
diff --git a/t/local/07_sslecho.t b/t/local/07_sslecho.t
|
||
|
index 74e317a..7f19027 100644
|
||
|
--- a/t/local/07_sslecho.t
|
||
|
+++ b/t/local/07_sslecho.t
|
||
|
@@ -134,10 +134,10 @@ my @results;
|
||
|
|
||
|
push @results, [ Net::SSLeay::get_cipher($ssl), 'get_cipher' ];
|
||
|
|
||
|
- push @results, [ Net::SSLeay::write($ssl, $msg), 'write' ];
|
||
|
+ push @results, [ Net::SSLeay::ssl_write_all($ssl, $msg), 'write' ];
|
||
|
shutdown($s, 1);
|
||
|
|
||
|
- my ($got) = Net::SSLeay::read($ssl);
|
||
|
+ my $got = Net::SSLeay::ssl_read_all($ssl);
|
||
|
push @results, [ $got eq uc($msg), 'read' ];
|
||
|
|
||
|
Net::SSLeay::free($ssl);
|
||
|
@@ -177,7 +177,7 @@ my @results;
|
||
|
Net::SSLeay::set_fd($ssl, fileno($s));
|
||
|
Net::SSLeay::connect($ssl);
|
||
|
|
||
|
- Net::SSLeay::write($ssl, $msg);
|
||
|
+ Net::SSLeay::ssl_write_all($ssl, $msg);
|
||
|
|
||
|
shutdown $s, 2;
|
||
|
close $s;
|
||
|
@@ -231,15 +231,15 @@ my @results;
|
||
|
Net::SSLeay::set_fd($ssl3, $s3);
|
||
|
|
||
|
Net::SSLeay::connect($ssl1);
|
||
|
- Net::SSLeay::write($ssl1, $msg);
|
||
|
+ Net::SSLeay::ssl_write_all($ssl1, $msg);
|
||
|
shutdown $s1, 2;
|
||
|
|
||
|
Net::SSLeay::connect($ssl2);
|
||
|
- Net::SSLeay::write($ssl2, $msg);
|
||
|
+ Net::SSLeay::ssl_write_all($ssl2, $msg);
|
||
|
shutdown $s2, 2;
|
||
|
|
||
|
Net::SSLeay::connect($ssl3);
|
||
|
- Net::SSLeay::write($ssl3, $msg);
|
||
|
+ Net::SSLeay::ssl_write_all($ssl3, $msg);
|
||
|
shutdown $s3, 2;
|
||
|
|
||
|
close $s1;
|
||
|
diff --git a/t/local/36_verify.t b/t/local/36_verify.t
|
||
|
index 2837288..b04be13 100644
|
||
|
--- a/t/local/36_verify.t
|
||
|
+++ b/t/local/36_verify.t
|
||
|
@@ -252,8 +252,9 @@ sub client {
|
||
|
Net::SSLeay::set_fd($ssl, $cl);
|
||
|
Net::SSLeay::connect($ssl);
|
||
|
my $end = "end";
|
||
|
- Net::SSLeay::write($ssl, $end);
|
||
|
- ok($end eq Net::SSLeay::read($ssl), 'Successful termination');
|
||
|
+ Net::SSLeay::ssl_write_all($ssl, $end);
|
||
|
+ Net::SSLeay::shutdown($ssl);
|
||
|
+ ok($end eq Net::SSLeay::ssl_read_all($ssl), 'Successful termination');
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
@@ -291,10 +292,10 @@ sub run_server
|
||
|
next unless $ret == 1;
|
||
|
|
||
|
# Termination request or other message from client
|
||
|
- my $msg = Net::SSLeay::read($ssl);
|
||
|
+ my $msg = Net::SSLeay::ssl_read_all($ssl);
|
||
|
if (defined $msg and $msg eq 'end')
|
||
|
{
|
||
|
- Net::SSLeay::write($ssl, 'end');
|
||
|
+ Net::SSLeay::ssl_write_all($ssl, 'end');
|
||
|
exit (0);
|
||
|
}
|
||
|
}
|
||
|
--
|
||
|
2.14.4
|
||
|
|