"""Probe TLS 1.2 full-handshake group negotiation with the firmware root CA.""" import json from pathlib import Path import re import subprocess root = Path(__file__).resolve().parents[1] source = (root / 'ql-application/threadx/interface/custom_app/talkingq_root_ca.c').read_text() pem = ''.join(json.loads('"' + value + '"') for value in re.findall(r'"(.*?)"', source) if 'CERTIFICATE' in value or value.endswith(r'\n')) output = root / 'artifacts/wss/full-handshake' output.mkdir(parents=True, exist_ok=True) ca = output / 'compiled-root.pem' ca.write_text(pem) openssl = Path('C:/Program Files/Git/usr/bin/openssl.exe') groups = { 'sdk_order': 'P-521:brainpoolP512r1:P-384:brainpoolP384r1:P-256:brainpoolP256r1:P-224:secp224k1:P-192:secp192k1:X25519:X448', 'x25519_first': 'X25519:P-256:P-384:P-521', 'p256_first': 'P-256:X25519:P-384:P-521', } firmware = (root / 'ql-application/threadx/interface/custom_app/lib/librws/src/rws_socketpriv.c').read_bytes().decode('latin1') array = re.search(r'rws_tls_preferred_curves\[\]\s*=\s*\{(.*?)\}', firmware, re.S).group(1) names = {'CURVE25519': 'X25519', 'CURVE448': 'X448', 'SECP256R1': 'P-256', 'SECP384R1': 'P-384', 'SECP521R1': 'P-521', 'SECP224R1': 'P-224', 'SECP192R1': 'P-192', 'SECP224K1': 'secp224k1', 'SECP192K1': 'secp192k1', 'BP512R1': 'brainpoolP512r1', 'BP384R1': 'brainpoolP384r1', 'BP256R1': 'brainpoolP256r1'} groups['firmware_policy'] = ':'.join(names[name] for name in re.findall(r'MBEDTLS_ECP_DP_(\w+)', array) if name != 'NONE') report = {} for name, group_list in groups.items(): result = subprocess.run([str(openssl), 's_client', '-connect', 'banban.api.talkingq.com:443', '-servername', 'banban.api.talkingq.com', '-verify_hostname', 'banban.api.talkingq.com', '-verify_return_error', '-CAfile', str(ca), '-no-CApath', '-no-CAstore', '-tls1_2', '-no_ticket', '-groups', group_list, '-brief'], input='', text=True, capture_output=True, timeout=20) text = result.stdout + result.stderr report[name] = {'groups': group_list, 'returncode': result.returncode, 'output': text} print(name + ':\n' + text, flush=True) assert result.returncode == 0 and 'Verification: OK' in text, name (output / 'group-probe.json').write_text(json.dumps(report, indent=2))