Antoine Pitrou wrote:
What I'm specifically interested in is SSL_ERROR_SYSCALL with errno==0.
I have investigated this issue of -1/SSL_ERROR_SYSCALL with errno==0.
From the SSL_get_error(3) man page:
SSL_ERROR_SYSCALL
Some I/O error occurred. The OpenSSL error queue may contain more
information on the error. If the error queue is empty (i.e.
ERR_get_error() returns 0), ret can be used to find out more about the
error: If ret == 0, an EOF was observed that violates the protocol. If
ret == -1, the underlying BIO reported an I/O error (for socket I/O on
Unix systems, consult errno for details).
Note the use of "may contain more information" there is no guarantee.
Note the confirmation that ret==0 for the specific condition of EOF (on
the BIO, i.e. on the socket, it violates the protocol because the
protocol expects to receive a shutdown notify packet, which would have
been caused by the far end calling SSL_shutdown() at least once). You
have used the term "errno" where really OpenSSL talks in terms of the
error codes off the error stack.
I also note the man page doesn't include SSL_shutdown() in the very
specific list of calls that SSL_get_error() is used in sympathy with.
However it was my intention to bring SSL_shutdown() into line so that
man page should also be updated to include SSL_shutdown().
My claim is that the other end did a close() on the socket, while you
were trying/sending/waiting-for the two-way SSL shutdown process to
complete.
This would be observed as an end-of-file condition, i.e. read() returns 0.
This is considered a "SSL3/TLS1 protocol violation" because the protocol
expects all users to always make use of the cryptographically secure
two-stream shutdown all the time.
I have then taken a look at Python from CVS and see that:
./Modules/_ssl.c function PySSL_SetError() does attempt to handle
SSL_ERROR_SYSCALL as per the documentation. Whoever wrote that did read
the man page.
While I agree with the sentiment that having the exact errno saved and
available for inspection/recall by the application using OpenSSL would
be very useful. I don't agree that SSL_shutdown() is acting against the
existing documentation.
Unfortunately I am not sure myself how errno values from read/write or
recv/send calls get onto the OpenSSL error stack. Auditing the source
reveals very few places where get_last_socket_error() is called in
relation to normal recv/send IO operations. So I'm almost able to say
it is not possible to retrieve errno values for anything other than the
connect setup phase (where a variety of kinds of error can occur,
ECONNREFUSED, ETIMEDOUT, ENETUNREACH, ... check out the connect(2) man
page). This is also the stage most people have problems and therefore
historically have required the most detail about the problem to resolve it.
There is however one mystery of how EPIPE from a write() is getting
propagated back in Python, I can only think that Python's custom BIO is
providing this information. As I can't see how OpenSSL's own socket BIO
implementation does that. The strangeness of printing errno==0 out as a
reason for an error is actually leaning towards a facet of Python's BIO
layer and BIO error handling.
Darryl
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List openssl-users@openssl.org
Automated List Manager majord...@openssl.org