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
TLS connections should not "succeed" when certificate verification fails #12075
Comments
I think I agree with something like this issue but I'm not sure exactly what. Recall that Backwards compatibility is great and remains one of Twisted's strengths but it is also true that this is an unfortunate stumbling block for using TLS in Twisted (something that is otherwise more pleasant than is the case when using many other libraries). The introduction of
|
I have never used the Maybe have an API like The signature can be Later we can remove the deprecationg warning and have the signature as I am happy to have a better Below is my boilerplate code that I use for any TLS connection. But, it's important to forward the TLS error to the connectionLost() API. from typing import Any
from twisted.internet import defer
from twisted.internet.endpoints import HostnameEndpoint, wrapClientTLS
from twisted.internet.interfaces import ISSLTransport, IHandshakeListener
from twisted.internet.protocol import Factory, Protocol
from twisted.internet.ssl import optionsForClientTLS
from twisted.internet.task import react
from zope.interface.declarations import implementer
@implementer(IHandshakeListener)
class ClientProtocol(Protocol):
def __init__(self):
self._tls_handshake_completed = defer.Deferred()
def handshakeCompleted(self):
self._tls_handshake_completed.callback(None)
def connectionLost(self, reason):
self._tlsConnectionLost(reason)
def waitHandshakeCompleted(self):
return self._tls_handshake_completed
def _tlsConnectionLost(self, failure):
if not self._tls_handshake_completed:
return
if self._tls_handshake_completed.called:
return
# Once the connection is lost, there shouldn't be any other
# process waiting for the deferred, so it's safe to ignore the error,
# that we are triggering here.
# We push the error here to trigger emitting the events.
self._tls_handshake_completed.addErrback(lambda f: None)
self._tls_handshake_completed.errback(failure)
@react
async def main(reactor: Any) -> None:
print("connecting")
proto = await wrapClientTLS(
optionsForClientTLS("expired.badssl.com"),
HostnameEndpoint(reactor, "expired.badssl.com", 443),
).connect(Factory.forProtocol(ClientProtocol))
print("connected", proto)
await proto.waitHandshakeCompleted() |
Possibly the right signature here would be simply Basically, put these lines into their own public function, rather than hiding them behind twisted/src/twisted/internet/endpoints.py Lines 2294 to 2304 in 88151eb
|
The formal compatibility policy that Twisted attempts to guarantee is not "all behavior is the same", but "we aren't going to make public names start raising exceptions (particularly Any code making a TLS connection with an endpoint already has to handle failures from This covers the developer-facing part of the process, but there is also an operational concern. We do have other facilities we can play with in order to allow users to roll back the behavior if it causes issues for them, e.g. an environment variable. That said, I do think that we are missing something like It does seem like adding a new |
Consider this example:
On current Twisted, this happily gives you a "connected" protocol, despite the fact that the certificate has not been verified yet.
This is not correct. It should fail with a service identity verification error.
cc @exarkun @adiroiban re: #12074
The text was updated successfully, but these errors were encountered: