Hoernchen has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/43548?usp=email )
Change subject: osmo-smdpp: fix Twisted ALPN issues with pyOpenSSL ......................................................................
osmo-smdpp: fix Twisted ALPN issues with pyOpenSSL
pyOpenSSL >= 25.0.0 makes a Context immutable once it has been used and raises. Downgrading pyOpenSSL is not a fix either: < 25 does not import against recent cryptography.
This server only speaks HTTP/1.1 anway so ALPN negotiation is unused and this can be hotpatched for affected versions.
Change-Id: I5d53216f24a20625d12f0757015c19fe341303b9 --- M osmo-smdpp.py 1 file changed, 46 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/48/43548/1
diff --git a/osmo-smdpp.py b/osmo-smdpp.py index 2a8e478..8120b0f 100755 --- a/osmo-smdpp.py +++ b/osmo-smdpp.py @@ -136,6 +136,52 @@ import logging # noqa: E402 logger = logging.getLogger(__name__)
+ +def _disable_twisted_alpn_if_incompatible(): + """Twisted <-> pyOpenSSL TLS compatibility guard applied at import. + + Twisted TLSMemoryBIOFactory applies ALPN by setting the 'select' callback + on the SSL Context after it has already created a Connection from that + Context (_createConnection -> _applyProtocolNegotiation). + pyOpenSSL >= 25.0.0 makes a Context immutable once it has been used and + raises, which aborts every inbound TLS handshake, client sees unexpected-EOF + / decode_error that looks like a cert/cipher problem but is not. + pyOpenSSL < 25 does not import against recent cryptography, so downgrading + it is not a fix. + + This server only speaks HTTP/1.1 anyway, so ALPN negotiation is not + needed. + """ + def _major(v): + import re + m = re.match(r'\d+', (v or '').strip()) + return int(m.group()) if m else 0 + + try: + import OpenSSL + except Exception: + return # no pyOpenSSL ??? + pyossl_ver = getattr(OpenSSL, '__version__', '0') + if _major(pyossl_ver) < 25: + return # pre-25 pyOpenSSL allows mutating a used Context + + try: + import twisted + from twisted.protocols import tls + except Exception: + return + factory = getattr(tls, 'TLSMemoryBIOFactory', None) + if factory is None or not hasattr(factory, '_applyProtocolNegotiation'): + return # Twisted already fixed + + factory._applyProtocolNegotiation = lambda self, connection: None + logger.warning("Disabled Twisted ALPN negotiation: Twisted %s + " + "pyOpenSSL %s are incompatible for it", + getattr(twisted, '__version__', '?'), pyossl_ver) + + +_disable_twisted_alpn_if_incompatible() + # HACK: make this configurable DATA_DIR = './smdpp-data' HOSTNAME = 'testsmdpplus1.example.com' # must match certificates!