-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
Cannot create ssl.SSLSocket without existing socket #71816
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
Comments
I got this stacktrace: with this minimal code:
import ssl
sock = ssl.SSLSocket(server_hostname="docs.python.org")
sock.connect(("docs.python.org", 443))
sock.sendall(b"GET /3/library/ssl.html HTTP/1.0\r\nHost: docs.python.org\r\n\r\n")
print(sock.recv(4096).decode()) Whereas the None socket is correctly handled a few lines later: https://hg.python.org/cpython/file/tip/Lib/ssl.py#l715 All Python >= 3.3 are affected (since https://hg.python.org/cpython/rev/a00842b783cf) and can be patched with the same file, attached to this issue. |
Thank you for the report and the patch! :) This will need a test in Lib/test/test_ssl.py to check for this particular case. I've removed 3.3 and 3.4 from the Versions field, since these versions no longer get regular bugfixes (only security bugfixes may go in these). As a result, only 3.5 and 3.6 will get the fix. |
The change introducing the != SOCK_STREAM check (change a00842b783cf) was made in 2013. It looks like the case was not tested since at least 3 years...
Yes, this new test is mandatory to make sure that the feature is not broken again (check for regression). The workaround is to pass an existing socket... |
Here is a new patch with tests on constructor. The patch on the feature is quite different: instead of testing for None socket, I choose to delay the != SOCK_STREAM check in the later condition, when we know we treat a socket. Tests include different constructor forms: with a given socket, with a fileno (didn't work either, before this patch) and without socket nor file descriptor (as in my original test). I don't have sufficient background to judge if tests will work on all platform (eg. fileno and windows, ...). Here is the interesting diff of the tests on SSL (before/after applying the patch on the feature): 32c32
< Traceback (most recent call last):
< File "test_ssl.py", line 149, in test_constructor
< ss = ssl.SSLSocket()
< File "/usr/lib/python3.4/ssl.py", line 545, in __init__
< if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM:
< AttributeError: 'NoneType' object has no attribute 'getsockopt'
<
<
```====================================================================== |
The patch is incomplete. Please also check that type == SOCK_STREAM. The code can be simplified with a bitmask test: if sock is not None:
type = sock.type
if type & socket.SOCK_STREAM != socket.SOCK_STREAM:
raise NotImplementedError |
I'm considering to not fix this bug and rather remove the dead code. This feature was never documented and has been broken since 3.3, maybe earlier. It's also hard to use it correctly because you need to pass the correct socket family and type. For 3.6 I'm planning to deprecate SSLSocket.__init__() in favor of SSLContext.wrap_socket() anyway. Please use https://docs.python.org/3/library/socket.html#socket.socket with fileno argument. It auto-detects the correct socket type and family. |
The documentation already recommends to use SSLContext.wrap_socket(), but it didn't cover all use cases. Eg. I use multiple inheritance to handle both socket and SSLSocket inside a factory pattern, in order to override some methods defined in both classes. If I use SSLContext.wrap_socket(), it erases my overrides. As the patch add some tests on this feature, this is no more dead code; however I let you decide the future of this issue: I've updated my patch with your remarks if you want to include it (it applies from Python 3.3 to current Python 3.6). |
How about I make the actual SSLSocket and SSLObject class customizable so you can override what is returned by wrap_socket() and wrap_bio()? class MySSLSocket(ssl.SSLSocket):
pass
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.sslsocket_class = MySSLSocket
sock = ctx.wrap_socket(socket.socket(), server_side=True)
assert isinstance(sock, MySSLSocket) |
I have created bpo-27629 to allow customization of SSLObject and SSLSocket. I'm closing this as "won't fix" because I rather want people to move away from ssl.wrap_socket() and manual instantiation of SSLSocket. |
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:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: