This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: ssl.SSLSocket.send(b"") fails
Type: behavior Stage: resolved
Components: Documentation, SSL Versions: Python 3.10
process
Status: closed Resolution: fixed
Dependencies: Superseder: OpenSSL 1.1.1: use SSL_write_ex() and SSL_read_ex()
View: 42854
Assigned To: docs@python Nosy List: alex, christian.heimes, docs@python, dstufft, janssen, joernheissler, njs, slingamn
Priority: normal Keywords: patch

Created on 2017-10-06 09:43 by joernheissler, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
client.py joernheissler, 2017-10-06 09:42
Pull Requests
URL Status Linked Edit
PR 7559 closed python-dev, 2018-06-09 14:03
PR 17671 closed choyos, 2019-12-23 17:55
Messages (8)
msg303810 - (view) Author: Jörn Heissler (joernheissler) * Date: 2017-10-06 09:42
Traceback (most recent call last):
  File "client.py", line 10, in <module>
    conn.send(b'')
  File "/usr/lib/python3.6/ssl.py", line 941, in send
    return self._sslobj.write(data)
  File "/usr/lib/python3.6/ssl.py", line 642, in write
    return self._sslobj.write(data)
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:2074)

This error is not what I expected. I expected a noop instead.

My guess is, that python calls SSL_write (3.6 branch, _ssl.c:2038) with that empty buffer.
The manpage states: "When calling SSL_write() with num=0 bytes to be sent the behaviour is undefined."

This undefined behaviour should either be documented in python, or defined to either raise an exception (ValueError?) or defined as a noop. I'd prefer the latter.
msg312898 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2018-02-26 09:06
It's a bit too late to change the behavior of send(). Let's document the issue instead.
msg312903 - (view) Author: Nathaniel Smith (njs) * (Python committer) Date: 2018-02-26 09:42
If openssl says the behavior is undefined, then don't we have to first make it defined before we can document it?

And if we're going to detect this case and guarantee some behavior, making it a no-op like it is on regular sockets seems the way to go...
msg312908 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2018-02-26 09:57
The message "EOF occurred in violation of protocol" is set by Python. Python maps SSL_ERROR_SYSCALL with SSL error code == 0 and len == 0 to that error message. 

https://github.com/python/cpython/blob/master/Modules/_ssl.c#L682-L689
https://github.com/python/cpython/blob/master/Modules/_ssl.c#L2263

I don't know why the code was implemented that way.
msg312956 - (view) Author: Nathaniel Smith (njs) * (Python committer) Date: 2018-02-26 20:54
My point is that SSL_write(3ssl) says "WARNING: When calling SSL_write() with num=0 bytes to be sent the behaviour is undefined."

Apparently on the particular openssl you're looking at, it gives SSL_ERROR_SYSCALL with error code == 0 and len == 0, but the openssl devs claim this is some arbitrary thing that shouldn't be depended on.

Just as a general principle it would be nice if performing ordinary operations on an SSLSocket from Python did not invoke undefined behavior :-)
msg346525 - (view) Author: Shivaram Lingamneni (slingamn) * Date: 2019-06-25 13:13
Are there any possible next steps on this?

This issue is very counterintuitive and challenging to debug --- it commonly presents as a nondeterministic edge case, and it appears to be a failed system call but doesn't show up in strace.

Thanks for your time.
msg358830 - (view) Author: Jörn Heissler (joernheissler) * Date: 2019-12-23 18:47
Manpage (openssl 1.1.1d) now states:

You should not call SSL_write() with num=0, it will return an error.  SSL_write_ex() can be called with num=0, but will not send application data to the peer. SSL_write_ex was added in 1.1.1

So it looks like openssl cleaned up another mistake by defining SSL_write_ex's behaviour to be a noop.
msg391357 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2021-04-19 04:01
Thanks to PEP 644 the issue will be fixed in 3.10 by using SSL_read_ex and SSL_write_ex() functions. I couldn't use the functions earlier because Python had to support older OpenSSL versions and LibreSSL. 

See https://github.com/python/cpython/pull/25468 and bpo-42854
History
Date User Action Args
2022-04-11 14:58:53adminsetgithub: 75892
2021-04-19 04:01:15christian.heimessetstatus: open -> closed
versions: + Python 3.10, - Python 2.7, Python 3.6, Python 3.7, Python 3.8
superseder: OpenSSL 1.1.1: use SSL_write_ex() and SSL_read_ex()
messages: + msg391357

resolution: fixed
stage: patch review -> resolved
2019-12-23 18:47:33joernheisslersetmessages: + msg358830
2019-12-23 17:55:43choyossetpull_requests: + pull_request17144
2019-06-25 13:13:22slingamnsetnosy: + slingamn
messages: + msg346525
2018-06-09 14:03:22python-devsetkeywords: + patch
stage: needs patch -> patch review
pull_requests: + pull_request7191
2018-02-26 20:54:16njssetmessages: + msg312956
2018-02-26 09:57:24christian.heimessetmessages: + msg312908
2018-02-26 09:42:33njssetmessages: + msg312903
2018-02-26 09:06:41christian.heimessetassignee: christian.heimes -> docs@python
components: + Documentation
versions: + Python 2.7, Python 3.7, Python 3.8
nosy: + alex, janssen, dstufft, docs@python, njs

messages: + msg312898
stage: needs patch
2017-10-06 09:43:00joernheisslercreate