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

Reply via email to