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: TLS 1.3, client polling returns event without data
Type: behavior Stage:
Components: SSL Versions: Python 3.10, Python 3.9, Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: christian.heimes Nosy List: christian.heimes, gchauvel
Priority: normal Keywords:

Created on 2021-03-25 08:54 by gchauvel, last changed 2022-04-11 14:59 by admin.

Messages (6)
msg389496 - (view) Author: (gchauvel) Date: 2021-03-25 08:54
A simple test in test_ssl.py [1][2] with following context:
- client connects and listens to data without sending any first
- traces to make sure no data is written at test level from server or client
- TLSv1.3 is allowed or not using "context.options |= ssl.OP_NO_TLSv1_3"

produces this result:

TLSv1.2:
- no event on FD, no issue

TLSv1.3:
- event on FD without any write at test level
- recv() blocks, even with setblocking(False)

[1] master: https://github.com/g-chauvel/cpython/commit/8c95c4f67367ea43c508ea62a0cdbe120a3fed9b
[2] 3.6: https://github.com/g-chauvel/cpython/commit/7cd4b4ac22efea7c61a9f8f57b6f2315567f5742
msg389497 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2021-03-25 09:45
Could you please explain why you consider this a bug?

TLS 1.3 works differently than TLS 1.2. You must always assume that an application level read can result in a protocol level write operation and the other way around. This could happen with TLS 1.2, but it was less common to occur. With TLS 1.3 rekeying, client cert authentication with post handshake authentication, and sessions are most common examples.
msg389498 - (view) Author: (gchauvel) Date: 2021-03-25 10:11
that's not the polling in itself,
it's: polling returning event + setblocking(False) + recv() which blocks

note: the behavior is present for python3.6
msg389499 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2021-03-25 10:27
It looks like your code is treating a SSLSocket like an ordinary Kernel socket. SSLSocket are implemented in user space and behave differently. 
https://docs.python.org/3/library/ssl.html#ssl-nonblocking explains some of the aspects of non-blocking I/O for TLS connections. For non-blocking I/O it is generally easier to use sans-I/O approach and make use of MemoryBIO https://docs.python.org/3/library/ssl.html#memory-bio-support instead of SSLSocket.

3.6 and 3.7 only receive security updates and are out of scope anyway.
msg389807 - (view) Author: (gchauvel) Date: 2021-03-30 08:40
Based on your first comment, poll returning an event and recv not able to read data is a behavior to expect with TLSv1.2/TLSv1.3 (or ...)
So in order to use SSLContext in a polling loop with multiple file descriptors, a non-blocking mode (to avoid an fd event and not being able to read data) is mandatory. Do you agree with this statement ?

Furthermore, I looked at [1], the other tests in test_ssl.py and also set a few traces in _ssl.c

- without non blocking mode: even with a fd event, the test blocks on SSL_read
- with non blocking mode: SSL_read returns a negative value, PySSL_SetError throws PySSLWantWriteErrorObject, but:

    nothing is printed on the console, a thread is blocked at PyThread_acquire_lock_timed, so the test hangs forever.

- with non blocking mode + try/except ssl.SSLWantReadError [2], the test is ok

[1] https://docs.python.org/3/library/ssl.html#ssl-nonblocking
[2] https://github.com/g-chauvel/cpython/commit/dc57cbea3558ff7b3c040326709d9b759214584a
msg389812 - (view) Author: (gchauvel) Date: 2021-03-30 09:10
err: second item: copy/paste error, the exception is PySSLWantReadErrorObject
History
Date User Action Args
2022-04-11 14:59:43adminsetgithub: 87788
2021-03-30 09:10:27gchauvelsetmessages: + msg389812
2021-03-30 08:40:23gchauvelsetmessages: + msg389807
2021-03-25 10:27:25christian.heimessetmessages: + msg389499
2021-03-25 10:11:06gchauvelsetmessages: + msg389498
2021-03-25 09:45:14christian.heimessetmessages: + msg389497
versions: - Python 3.6, Python 3.7
2021-03-25 08:54:27gchauvelcreate