You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
SSLObject.version returns incorrect value before handshake. #73967
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=<Date2017-09-06.23:39:28.508>created_at=<Date2017-03-10.10:03:04.146>labels= ['expert-SSL', 'type-bug']
title='SSLObject.version returns incorrect value before handshake.'updated_at=<Date2017-09-06.23:39:28.507>user='https://github.com/Lukasa'
The SSLObject object from the ssl module has a version() method that is undocumented. A reasonable assumption for the behaviour of that method is that it would follow the behaviour of the same method on SSLSocket(), which has the following documentation:
Return the actual SSL protocol version negotiated by the connection as
a string, or None is no secure connection is established. As of this
writing, possible return values include "SSLv2", "SSLv3", "TLSv1",
"TLSv1.1" and "TLSv1.2". Recent OpenSSL versions may define more return
values.
However, SSLObject does not follow that behaviour:
Python 3.6.0 (default, Jan 18 2017, 18:08:34)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>> ctx = ssl.create_default_context()
>>> in_bio = ssl.MemoryBIO()
>>> out_bio = ssl.MemoryBIO()
>>> buffers = ctx.wrap_bio(in_bio, out_bio)
>>> buffers.version()
'TLSv1.2'
That is, a SSLObject that does not have a TLS session established will incorrectly report that it is using a TLS version. This method should return None in this case.
A quick test reveals that Python 3.5 is also affected.
Lukasa commented on Mar 10, 2017
Lukasamannequin
MannequinAuthor
More actions
This actually appears to be an outcome of OpenSSL's logic. I've attached a smallish C file that, when run against OpenSSL 1.0.2 on my machine, prints "TLSv1.2".
This seems like a behaviour we'll have to work around in Python to get the outcome we want here.
Lukasa commented on Mar 10, 2017
Lukasamannequin
MannequinAuthor
More actions
I updated the test script to try with a file-descriptor set and OpenSSL returns TLSv1.2 for that one as well. This strongly suggests that OpenSSL's SSL_get_version documentation is somewhat misleading, and that an SSL object will return a version even when it's not connected.
If Python wants to consider this a bug, it will need to track connections state for the SSLObject like it does for the SSLSocket. Otherwise, Python can redocument version for SSLObject to say that it will always return a value.
It should be possible to solve the issue w/o tracking the connection state manually. It doesn't work correctly with transparent negotiation -- that is implicit handshake with SSL_write().
Activity
Lukasa commentedon Mar 10, 2017
The SSLObject object from the ssl module has a version() method that is undocumented. A reasonable assumption for the behaviour of that method is that it would follow the behaviour of the same method on SSLSocket(), which has the following documentation:
However, SSLObject does not follow that behaviour:
That is, a SSLObject that does not have a TLS session established will incorrectly report that it is using a TLS version. This method should return None in this case.
Lukasa commentedon Mar 10, 2017
A quick test reveals that Python 3.5 is also affected.
Lukasa commentedon Mar 10, 2017
This actually appears to be an outcome of OpenSSL's logic. I've attached a smallish C file that, when run against OpenSSL 1.0.2 on my machine, prints "TLSv1.2".
This seems like a behaviour we'll have to work around in Python to get the outcome we want here.
Lukasa commentedon Mar 10, 2017
I updated the test script to try with a file-descriptor set and OpenSSL returns TLSv1.2 for that one as well. This strongly suggests that OpenSSL's SSL_get_version documentation is somewhat misleading, and that an SSL object will return a version even when it's not connected.
If Python wants to consider this a bug, it will need to track connections state for the SSLObject like it does for the SSLSocket. Otherwise, Python can redocument version for SSLObject to say that it will always return a value.
tiran commentedon Sep 5, 2017
It should be possible to solve the issue w/o tracking the connection state manually. It doesn't work correctly with transparent negotiation -- that is implicit handshake with SSL_write().
SSL_is_init_finished() (https://www.openssl.org/docs/manmaster/man3/SSL_get_state.html) might be the right function.
tiran commentedon Sep 6, 2017
New changeset 6877111 by Christian Heimes in branch 'master':
bpo-29781: Fix SSLObject.version before handshake (bpo-3364)
6877111
tiran commentedon Sep 6, 2017
New changeset 6da379b by Christian Heimes in branch '3.6':
[3.6] bpo-29781: Fix SSLObject.version before handshake (GH-3364) (bpo-3381)
6da379b