Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client SSLSocket with select.select() always returns readable with OpenSSL 1.1.1 #81716

Closed
scaramallion mannequin opened this issue Jul 10, 2019 · 6 comments
Closed

Client SSLSocket with select.select() always returns readable with OpenSSL 1.1.1 #81716

scaramallion mannequin opened this issue Jul 10, 2019 · 6 comments
Assignees
Labels
3.7 (EOL) end of life 3.8 only security fixes 3.9 only security fixes topic-SSL type-bug An unexpected behavior, bug, or error

Comments

@scaramallion
Copy link
Mannequin

scaramallion mannequin commented Jul 10, 2019

BPO 37535
Nosy @tiran, @scaramallion, @SeaHOH
Files
  • ssl_select.zip
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/tiran'
    closed_at = <Date 2019-12-09.16:26:07.729>
    created_at = <Date 2019-07-10.03:57:44.851>
    labels = ['expert-SSL', '3.8', 'type-bug', '3.7', '3.9']
    title = 'Client SSLSocket with select.select() always returns readable with OpenSSL 1.1.1'
    updated_at = <Date 2019-12-10.08:53:47.370>
    user = 'https://github.com/scaramallion'

    bugs.python.org fields:

    activity = <Date 2019-12-10.08:53:47.370>
    actor = 'seahoh'
    assignee = 'christian.heimes'
    closed = True
    closed_date = <Date 2019-12-09.16:26:07.729>
    closer = 'christian.heimes'
    components = ['SSL']
    creation = <Date 2019-07-10.03:57:44.851>
    creator = 'ddddaaaa'
    dependencies = []
    files = ['48464']
    hgrepos = []
    issue_num = 37535
    keywords = []
    message_count = 6.0
    messages = ['347595', '358111', '358115', '358159', '358164', '358173']
    nosy_count = 3.0
    nosy_names = ['christian.heimes', 'ddddaaaa', 'seahoh']
    pr_nums = []
    priority = 'normal'
    resolution = 'wont fix'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue37535'
    versions = ['Python 2.7', 'Python 3.5', 'Python 3.6', 'Python 3.7', 'Python 3.8', 'Python 3.9']

    @scaramallion
    Copy link
    Mannequin Author

    scaramallion mannequin commented Jul 10, 2019

    Hi, I've come across an issue with OpenSSL 1.1.1, when a client socket wrapped using ssl.wrap_socket() is used in select.select() its always returning ready for reading even though there appears to be nothing to read.

    To reproduce:
    0. Extract files from attached zip

    1. Run server.py
    2. Run client.py

    I expect client.py to print "Nothing to read" and then b'\x00\x01\x02\x03', which it does with Python 2.7.14, 3.6.8 and 3.7.3 and OpenSSL 1.0.1f and 1.1.0g.

    With OpenSSL 1.1.1 it prints 'Pending: 0' and blocks on the sock.recv(1) call.

    Thanks!

    @scaramallion scaramallion mannequin added the 3.7 (EOL) end of life label Jul 10, 2019
    @scaramallion scaramallion mannequin assigned tiran Jul 10, 2019
    @scaramallion scaramallion mannequin added topic-SSL type-bug An unexpected behavior, bug, or error labels Jul 10, 2019
    @SeaHOH
    Copy link
    Mannequin

    SeaHOH mannequin commented Dec 9, 2019

    All new releases which include an OpenSSL version above 1.1.1 has the same issue. Can anybody fix it? Thanks a lot!

    @SeaHOH SeaHOH mannequin added 3.8 only security fixes 3.9 only security fixes labels Dec 9, 2019
    @tiran
    Copy link
    Member

    tiran commented Dec 9, 2019

    The problem is caused by the way how TLS 1.3 works. Select considers a TLS 1.3 socket as readable after the handshake, because there is still data on the line. The server is sending session tickets (usually two) after the handshake has been performed. If you set "context.num_tickets = 0" in server.py or "context.maximum_version = ssl.TLSVersion.TLSv1_2" in either server.py or client.py, your script works. Ticket bpo-37120 has more information on that.

    Session tickets are low-level TLS protocol elements. Methods like SSLSocket.pending() and SSLSocket.recv() only act on high-level application protocol data. That's why pending() returns 0 and recv() is blocking. There is no application data available.

    You have to take another approach and follow the guidelines in
    https://docs.python.org/3/library/ssl.html#notes-on-non-blocking-sockets . You also have to set the SSLSocket into non-blocking mode and handle SSLWantWriteError or SSLWantReadError.

    @tiran tiran closed this as completed Dec 9, 2019
    @SeaHOH
    Copy link
    Mannequin

    SeaHOH mannequin commented Dec 10, 2019

    Thanks for explanation, I understand what the reason is. But why do_handshake() not clear of useless data buffer after it is completed? I think that must be easy to do.

    @tiran
    Copy link
    Member

    tiran commented Dec 10, 2019

    do_handshake() performs just the handshake. TLS protocol can send or receive additional protocol data after the handshake, e.g. alerts, rekeying or renegotiation. The example just happened to not trigger these in TLS 1.2. TLS makes non-blocking IO more complicated.

    @SeaHOH
    Copy link
    Mannequin

    SeaHOH mannequin commented Dec 10, 2019

    So, that means there are some additional optional operations after do_handshake(), the data is needed. Thanks for explanation!

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.7 (EOL) end of life 3.8 only security fixes 3.9 only security fixes topic-SSL type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    1 participant