From 4b25958cb09c90c874afd3f7022cb72a82afe898 Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Sun, 22 Jul 2012 08:29:33 +0200 Subject: [PATCH] openssl addresses failed with "nonblocking operation did not complete" when the peer performed a renegotiation --- CHANGES | 4 +++ test.sh | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ xio-openssl.c | 7 +++-- 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index b8ad7f6..12a66de 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,10 @@ corrections: device /dev/ptmx instead of the pty (thanks to Matthew Cloke for pointing me to this bug) + socats openssl addresses failed with "nonblocking operation did not + complete" when the peer performed a renegotiation. Thanks to Benjamin + Delpy for reporting this bug. + corrected the "fixed possible SIGSEGV" fix because SIGSEGV still might occur under those conditions. Thanks to Toni Mattila for first reporting this problem. diff --git a/test.sh b/test.sh index a2e1531..2c02b14 100755 --- a/test.sh +++ b/test.sh @@ -10247,6 +10247,88 @@ PORT=$((PORT+1)) N=$((N+1)) +# socat up to 1.7.1.1 (and 2.0.0-b3) terminated with error when an openssl peer +# performed a renegotiation. Test if this is fixed. +NAME=OPENSSLRENEG1 +case "$TESTS" in +*%functions%*|*%bugs%*|*%openssl%*|*%socket%*|*%$NAME%*) +TEST="$NAME: OpenSSL connections survives renogotiation" +# connect with s_client to socat ssl-l; force a renog, then transfer data. When +# data is passed the test succeeded +if ! eval $NUMCOND; then :; else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="test$N $(date) $RANDOM" +CMD0="$SOCAT $opts OPENSSL-LISTEN:$PORT,reuseaddr,cert=testsrv.crt,key=testsrv.key,verify=0 PIPE" +CMD1="openssl s_client -port $PORT -verify 0" +printf "test $F_n $TEST... " $N +$CMD0 >/dev/null 2>"${te}0" & +pid0=$! +waittcp4port $PORT 1 +(echo "R"; sleep 1; echo "$da"; sleep 1) |$CMD1 2>"${te}1" |fgrep "$da" >"${tf}1" +rc1=$? +kill $pid0 2>/dev/null; wait +if echo "$da" |diff - ${tf}1 >"$tdiff"; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + echo "$CMD0 &" + echo "$CMD1" + cat "${te}0" +# cat "${te}1" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +fi +fi # NUMCOND + ;; +esac +N=$((N+1)) + + +# socat up to 1.7.1.1 (and 2.0.0-b3) terminated with error when an openssl peer +# performed a renegotiation. The first temporary fix to this problem might +# leave socat in a blocking ssl-read state. Test if this has been fixed. +NAME=OPENSSLRENEG2 +case "$TESTS" in +*%functions%*|*%bugs%*|*%openssl%*|*%socket%*|*%$NAME%*) +TEST="$NAME: OpenSSL connections do not block after renogotiation" +# connect with s_client to socat ssl-l; force a renog, then transfer data from +# socat to the peer. When data is passed this means that the former ssl read no +# longer blocks and the test succeeds +if ! eval $NUMCOND; then :; else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="test$N $(date) $RANDOM" +CMD0="$SOCAT $opts OPENSSL-LISTEN:$PORT,reuseaddr,cert=testsrv.crt,key=testsrv.key,verify=0 SYSTEM:\"sleep 1; echo \\\\\\\"\\\"$da\\\"\\\\\\\"; sleep 1\"!!STDIO" +CMD1="openssl s_client -port $PORT -verify 0" +printf "test $F_n $TEST... " $N +eval "$CMD0 >/dev/null 2>\"${te}0\" &" +pid0=$! +waittcp4port $PORT 1 +(echo "R"; sleep 2) |$CMD1 2>"${te}1" |fgrep "$da" >"${tf}1" +rc1=$? +kill $pid0 2>/dev/null; wait +if echo "$da" |diff - ${tf}1 >"$tdiff"; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + echo "$CMD0 &" + echo "$CMD1" + cat "${te}0" +# cat "${te}1" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +fi +fi # NUMCOND + ;; +esac +N=$((N+1)) + + while read KEYW PF LO do if [ -z "$KEYW" ] || [[ "$KEYW" == \#* ]]; then continue; fi diff --git a/xio-openssl.c b/xio-openssl.c index 52de1ef..c713de0 100644 --- a/xio-openssl.c +++ b/xio-openssl.c @@ -1,5 +1,5 @@ /* source: xio-openssl.c */ -/* Copyright Gerhard Rieger 2002-2008 */ +/* Copyright Gerhard Rieger 2002-2012 */ /* Published under the GNU General Public License V.2, see file COPYING */ /* this file contains the implementation of the openssl addresses */ @@ -1208,8 +1208,9 @@ ssize_t xioread_openssl(struct single *pipe, void *buff, size_t bufsiz) { case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_X509_LOOKUP: - Error("nonblocking operation did not complete"); - break; /*!*/ + Info("nonblocking operation did not complete"); + errno = EAGAIN; + return -1; case SSL_ERROR_SYSCALL: if (ERR_peek_error() == 0) { if (ret == 0) {