From df4eeb0de5a901a0fb2e0d10fb0f8a5832b44154 Mon Sep 17 00:00:00 2001 From: Marc Billow Date: Mon, 29 Jun 2026 21:10:46 -0500 Subject: [PATCH] fix: handle X509_V_ERR_CA_MD_TOO_WEAK in DTLS verify callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @SECLEVEL=1 in the cipher string does not reliably lower the security level for DTLS_METHOD contexts across all pyOpenSSL/OpenSSL builds. Instead, explicitly allow error 66 (X509_V_ERR_CA_MD_TOO_WEAK) in the verify callback. This is the error OpenSSL emits when a CA certificate uses SHA-1 — which Samsung's OCF Root CA does. All other verification errors (chain trust, expiry, key usage, revocation) are still enforced. --- custom_components/localthings/ocf/coap_dtls.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/custom_components/localthings/ocf/coap_dtls.py b/custom_components/localthings/ocf/coap_dtls.py index 8bd16dd..afd53fc 100644 --- a/custom_components/localthings/ocf/coap_dtls.py +++ b/custom_components/localthings/ocf/coap_dtls.py @@ -228,12 +228,19 @@ class DtlsCoapSession: def connect(self): """DTLS handshake. Blocks up to HANDSHAKE_TIMEOUT_S. Raises ConnectionError / TimeoutError on failure.""" + # X509_V_ERR_CA_MD_TOO_WEAK (66): OpenSSL 3.x SECLEVEL=2 rejects + # SHA-1 signed CA certs. Samsung's OCF Root CA is SHA-1 signed. + # We explicitly allow this one error while still enforcing everything + # else (chain trust, expiry, key usage). @SECLEVEL=1 in the cipher + # string is also set but DTLS_METHOD may not honour it in all builds. + _CA_MD_TOO_WEAK = 66 + + def _verify(conn, cert, errnum, depth, ok): + return True if errnum == _CA_MD_TOO_WEAK else ok + ctx = SSL.Context(SSL.DTLS_METHOD) ctx.load_verify_locations(_OCF_ROOT_CA) - ctx.set_verify(SSL.VERIFY_PEER, lambda conn, cert, err, depth, ok: ok) - # SECLEVEL=1 (80-bit) allows the Samsung OCF Root CA which is SHA-1 - # signed. SECLEVEL=2 (the OpenSSL 3.x default) rejects SHA-1 in the - # cert chain entirely, which kills CA verification on connect. + ctx.set_verify(SSL.VERIFY_PEER, _verify) ctx.set_cipher_list(b'ECDHE-ECDSA-AES128-GCM-SHA256@SECLEVEL=1') ctx.use_certificate_chain_file(self.cert_path) ctx.use_privatekey_file(self.key_path)