Skip to content

Commit 79a02e8

Browse files
committed
docs(s7commplus): configure OPENSSL_CONF for TLS on OpenSSL 3.5+
On OpenSSL >= 3.5 the default TLS 1.3 ClientHello advertises the X25519MLKEM768 post-quantum group, whose ~1.2 KB key share the S7-1500 rejects — it drops the handshake, so connect(use_tls=True) fails with a connection reset. The PLC mandates TLS 1.3 (TLS 1.2 is refused outright) and CPython's ssl exposes no API for the TLS 1.3 supported_groups list, so document restricting them to classic ECDHE curves via an OPENSSL_CONF file. Follow-up to #746 (the in-code ctypes group restriction was declined). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 34ef7b6 commit 79a02e8

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

doc/connecting.rst

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,63 @@ with the ``s7commplus`` extra:
152152
``browse()`` and other CommPlus-only operations are not yet
153153
supported on those firmwares — see issue #710.
154154

155+
TLS handshake fails on OpenSSL 3.5+ (post-quantum key share)
156+
-------------------------------------------------------------
157+
158+
On systems with **OpenSSL ≥ 3.5** (e.g. Debian 13 and other recent
159+
distributions) the TLS 1.3 ``ClientHello`` advertises a post-quantum
160+
hybrid key-exchange group, ``X25519MLKEM768``, by default. Its key
161+
share is roughly 1.2 KB, and the S7-1500's TLS stack rejects the
162+
oversized ``ClientHello`` — it drops the connection mid-handshake, so
163+
``connect(use_tls=True)`` fails with a *connection reset by peer*.
164+
165+
The PLC mandates TLS 1.3 (it refuses TLS 1.2 outright), and CPython's
166+
``ssl`` module exposes no API to restrict the TLS 1.3
167+
``supported_groups`` list. The fix is to restrict the offered groups
168+
through OpenSSL's own configuration — via the ``OPENSSL_CONF``
169+
environment variable — to the classic ECDHE curves that every
170+
S7-1200/1500 supports.
171+
172+
1. Create an OpenSSL configuration file, e.g. ``s7-openssl.cnf``:
173+
174+
.. code-block:: ini
175+
176+
# Restrict the TLS key-exchange groups to classic ECDHE curves so the
177+
# ClientHello stays small enough for the S7-1500 to accept.
178+
openssl_conf = openssl_init
179+
180+
[openssl_init]
181+
ssl_conf = ssl_configuration
182+
183+
[ssl_configuration]
184+
system_default = system_default_sect
185+
186+
[system_default_sect]
187+
Groups = x25519:secp256r1:secp384r1
188+
189+
2. Point ``OPENSSL_CONF`` at it **before** the Python process starts.
190+
OpenSSL reads this configuration once, when it initialises, so
191+
setting the variable from inside Python (e.g. via ``os.environ``)
192+
after ``ssl`` is imported is too late — it must be set in the
193+
environment:
194+
195+
.. code-block:: bash
196+
197+
# for a single run
198+
OPENSSL_CONF=/path/to/s7-openssl.cnf python your_script.py
199+
200+
# or for the whole shell session
201+
export OPENSSL_CONF=/path/to/s7-openssl.cnf
202+
203+
With the groups restricted to classic curves, the TLS 1.3 handshake no
204+
longer offers ``X25519MLKEM768`` and the S7-1500 completes it normally.
205+
206+
.. note::
207+
208+
This only affects OpenSSL ≥ 3.5. On older OpenSSL releases the
209+
default key-exchange groups are already classic ECDHE curves, so no
210+
extra configuration is needed.
211+
155212
PLC Password Authentication
156213
----------------------------
157214

0 commit comments

Comments
 (0)