Adapt WSS to new boards and use MQTT domain for eSIM connectivity

Preserve main GNSS and volume behavior while porting verified TLS, receive fixes and full-handshake optimizations. Add MQTT connection diagnostics and route MQTT through banban.api.talkingq.com:1883.

Include migration documentation and regression tools. Firmware builds and package checks passed; user confirmed new-board connectivity after switching the MQTT host to the domain.
This commit is contained in:
chenjintao
2026-09-16 17:27:21 +08:00
parent 2746cc3d4e
commit 3deb51d838
45 changed files with 3724 additions and 4815 deletions
+128
View File
@@ -0,0 +1,128 @@
# 旧板 WSS 适配与联调
> 新板 main 说明:本文保留旧板历史过程、配置与实测数据。新板已迁入 WSS,保留 GNSS 与原 main 音量行为;新板构建、下载包及验收请见 [新板 WSS 迁移说明](D:/banban/project/nfc_gnss/docs/new_board_wss.md)。旧板实测耗时不代表新板实测。
本次修改位于 `legacy-board-wss`(基于 `legacy-board`),默认地址为 `wss://banban.api.talkingq.com:443/ws`。沿用无 GNSS、默认音量 100 的旧板配置。上板暴露内核缺少 ECDSA 后,已补齐内核 TLS 能力并统一 APP/内核配置;从原明文旧板版本升级时必须更新内核和 APP。已有匹配 NIST 加速内核时,最新 X25519 调整只需更新 APP。
完整的问题根因、算法、提交、性能数据和影响说明见 [WSS 适配与性能优化完整总结](D:/banban/project/nfc_gnss/docs/WSS适配与性能优化完整总结.md)。2026-09-16 15:52 最新板端已确认 X25519 协商、完整 TLS 握手 1455 ms 和 HTTP 101。
## 后台实测(2026-09-16)
| 地址 | 结果 |
| --- | --- |
| `wss://banban.api.talkingq.com:443/ws` | 11:32 复测:TLS 1.2、证书链、域名、WebSocket Accept 校验通过,返回 HTTP 101;此前 404 已解决 |
| `wss://banban.api.talkingq.com:8080/ws` | TLS 握手失败,端口未提供可用的 TLS 服务 |
| `ws://banban.api.talkingq.com:8080/ws` | 明文 Upgrade 返回 HTTP 101,Accept 值正确 |
8080 当前是明文 WebSocket 服务,443 的 WSS 入口已可用。测试没有发送设备身份或业务数据,也没有修改服务器。
若 nginx 与 8080 服务部署在同一主机,可在现有 `listen 443 ssl` 的域名配置中参考以下转发(由后台按真实部署调整):
```nginx
location /ws {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 300s;
}
```
可重新运行 `powershell.exe -NoProfile -ExecutionPolicy Bypass -File tools\probe_talkingq_wss.ps1`。必须得到有效 HTTP 101 和匹配的 `Sec-WebSocket-Accept`;仅 HTTPS 打得开或证书正常不代表 WebSocket 已可用。
## 上板 -9774 的修复
11:42 日志中,联网和 MQTT 正常,WSS 在解析根 CA 时返回 `-9774`(`-0x262E`:未知签名算法)。ISRG Root X2 使用 ECDSA/SHA-384,原内核 mini TLS 配置没有编译 ECDSA。此前主机 OpenSSL 验证通过,仅能证明证书链有效,不能证明内核支持它。
- 新增 `ql-config/config/talkingq_mbedtls_config.h`,由 APP 和内核 mini profile 共用;增加 ECDSA、ECDHE-ECDSA、AES-GCM 和证书日期校验。
- 内核缺失的 `mbedtls/ecdsa.h` 从 APP 中同版本 2.28.9 SDK 头文件补入。
- ARMCC 编译内核头文件、GCC 编译 APP 头文件,对比 10 种 TLS 类型的大小和关键字段偏移,防止调用内核 API 时结构体布局不一致。
- 内核的 `GetCurrentCompTime()` 在此产品上是空 shim。X.509 时间检查改用 `mbedtls_time()` 的真实 RTC 时间和 UTC 转换,保留证书日期验证。
- 日志增加失败阶段及十六进制错误码;CA 解析成功会输出 `WSS root CA parsed successfully`。
不能仅刷 APP 修复本次问题,也不能只用未修改配置的旧内核重新打包。
## 固件行为
2026-09-16 14:06 板端已通过根 CA 解析、TLS 握手、服务器证书和域名校验。后续 `recv data failed` / `HTTP 0` 定位到 APP 接收函数:TLS 返回 WANT_READ/WANT_WRITE 后跳出循环,错误变量仍为初始值 -1,导致误断线。现已在该分支明确清除错误状态,由原握手循环继续等待;真实 EOF、TLS 错误和握手超时仍会结束连接。
- `inc/talkingq_wss.h` 集中定义默认地址。解析独立处理域名、端口、路径,默认端口 443、无路径时默认 `/ws`;拒绝明文 URL、非法端口、过长字段和 CR/LF 注入。现有存储容量为 64 字节;不支持 IPv6 字面量。
- `hal_os_get_talkingq_url()` 在没有保存地址、或保存值与已知旧默认地址完全匹配时,返回新默认 WSS 地址。此迁移在读取时生效,不改写 Flash。自定义地址保留;自定义明文地址会明确失败,不自动降级。
- 启用 librws 的 mbedTLS 实现,统一公共和私有头文件中的宏。TCP 继续使用现有蜂窝 PDP profile 1,避免 SDK 定制 `mbedtls_net_connect` 的 CID/端口 ABI 差异。
- 设置 SNI 和预期服务器域名,使用 `MBEDTLS_SSL_VERIFY_REQUIRED` 和 TLS 1.2 下限。没有客户端证书、客户端私钥或双向 TLS。
- 使用现有 NITZ/RTC 时间检查证书有效期;时间明显未初始化会拒绝连接并打印原因。不会通过关闭校验来绕过时间问题。上板需要确认运营商时间同步有效。
- 修复 TLS 短写、WANT_READ/WANT_WRITE、断线处理与资源清理;TLS 握手最多等待 20 秒,HTTP Upgrade 最多 10 秒,应用连接等待 45 秒。DNS/TCP 调用和任务调度还会消耗时间,45 秒不是所有底层调用的硬性总期限。
- WSS 每次产生随机 WebSocket nonce,校验 HTTP 101、Upgrade、Connection、对应 Accept;支持拆分到多个 TLS 记录的响应头,保留响应头后的 WebSocket 数据。
- 连接失败唤醒等待方;超时停止待连接 socket,回调只处理对应 socket。工作任务栈从 4 KiB 增至 16 KiB,给 TLS 证书和密码运算留出空间;仍需上板观察实际栈和堆余量。
- WebSocket 成功后,仍由原 `sendAuthentication()` 发送 `device_id`、`serial_number`。本次不改变 MQTT、HTTP 下载及其他业务连接。
## TLS 握手耗时优化(2026-09-16)
14:20 板端日志中,TCP 在 14:20:39.114 已连接,TLS 在 14:20:48.752 左右完成,约 9.6 秒;HTTP 101 在 14:20:48.894 完成,约再耗时 0.1 秒。原 `socket break` 仅表示退出 TCP 连接重试循环,现改为 `TCP connected; leaving connect loop`。这不是固定 10 秒延时,也不是 WebSocket HTTP 握手耗时。
共享 TLS 配置启用 `MBEDTLS_ECP_NIST_OPTIM`,使用 SDK 自带的 NIST 曲线快速模约减,减少证书 ECDSA 校验和相应 ECDHE 运算的开销。不改变证书信任、域名和日期校验规则,不调整服务器地址、设备鉴权、曲线列表或连接生命周期。
APP 通过 SDK 导出的 `mbedtls_ssl_handshake_step` 驱动同一 TLS 1.2 握手状态机,保留 WANT 重试和 20 秒超时;仅在 WANT 状态等待,正常状态推进不增加睡眠。每阶段打印 `WSS TLS phase ... elapsed=... ms, calls=... ms, retries=...`,结束打印 `WSS TLS handshake total=... ms`。`elapsed` 是该阶段总时间,`calls` 是 SDK 调用内累计经过时间(含任务调度,并非纯 CPU 时间),`retries` 是等待 I/O 的返回次数;时间分辨率为 SDK 的 5 ms tick。证书和密钥交换阶段仍可能同时包含网络与运算时间,不能单凭阶段名归因。
同一 Windows 主机上用实际 SDK crypto/X.509 源码验证相同证书链,各运行 20 次:关闭 NIST 优化平均 36.8 ms,开启后 10.2 ms,约 3.6 倍。两种配置均通过证书链、错误域名、不可信根、证书日期与 AES-GCM 检查。这是主机算法对比,不是板端总握手时间预测。可运行 `tools/test_mbedtls_cert.py --compare-nist` 复测;`tools/test_wss_handshake.py` 验证计时握手循环的状态推进、WANT、真实错误、超时与 tick 回绕。
第一轮加速包是 `artifacts/wss/tls-speed/EG800AKCN_11LG-legacy-wss-fast.zip`,相对早期版本需更新内核和 APP。14:38 上板已确认 TLS 握手 1820 ms,其中证书校验 965 ms、服务器密钥交换 160 ms、客户端密钥交换 445 ms,HTTP 101 正常。
### 完整握手的曲线协商优化
用户要求每次完整握手且不提前建连。WSS 的 `ssl_conf.curve_list` 改为 X25519、P-256、P-384、P-521 优先,其他原已启用曲线继续作为回退;不启用会话恢复、不改变按键/休眠/提示音逻辑。SDK 没有向 APP 导出 `mbedtls_ssl_conf_curves`,因此采用其实现同样的配置字段赋值。ABI 检查扩展到该字段、握手参数及 ECDH 上下文,验证 ARMCC 内核与 GCC APP 的实际布局一致。协商日志直接读取已匹配的上下文,`WSS TLS negotiated ECDHE group: 9` 表示 X25519(P-256=3、P-384=4、P-521=5)。
`tools/probe_wss_groups.py` 用同一固件根 CA、TLS 1.2 和证书/域名校验进行独立完整握手,读取固件的曲线数组进行验证:实际后台在 SDK 默认顺序下选择 P-521,在新固件顺序下选择 X25519;密码套件均为 ECDHE-ECDSA-AES256-GCM-SHA384。证据见 `artifacts/wss/full-handshake/group-probe.json`。X25519 是标准的约 128 位安全强度密钥交换;P-521 的参数更大,单纯参数更大不等于更适合本设备。当前服务端叶证书是 P-256 ECDSA,证书链、有效期和域名校验保持必需。
主机实际 SDK 新建 ECDH(每组 20 次,重新生成临时密钥并计算共享密钥)平均:X25519 1.55 ms、P-256 1.90 ms、P-384 3.40 ms、P-521 5.15 ms;X25519 测试峰值额外堆 1144 字节,P-521 6376 字节(包含测试对端共享密钥校验的内存)。每次校验双方计算结果相同并检查内存释放。15:52 板端补充日志已确认 group=9,客户端密钥交换 135 ms(上一版 445 ms),TLS 总计 1455 ms(上一版 1820 ms),HTTP 101 正常。两次日志样本中 TLS 再缩短约 20%;不能把主机基准比例套用到整个握手。
另对比 ECP window=4/5/6:证书校验约 10.35/10.20/10.45 ms,峰值分配约 11913/16009/18697 字节,收益不稳定,因此固件保留 window=4。可在 MSVC 开发者终端运行 `tools/test_mbedtls_cert.py --compare-windows` 复测。
最新包 `artifacts/wss/full-handshake/EG800AKCN_11LG-legacy-wss-x25519.zip` 沿用已验证的 NIST 内核,只更新 APP。当前工作区可 `build.bat app`、`build.bat firmware`;全新检出仍需先构建匹配的内核。旧 `tls-speed` 包保留,作为板端 1820 ms 的对照。
## 根证书来源与验证
固件内置的是公共根 CA **ISRG Root X2**,不是短期服务器证书。
- 来源:对目标域名进行 Windows 系统信任和域名校验后导出的证书链根。
- 根证书 DER SHA-256:`69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470`。
- 根证书有效期到 2040-09-17。
- 实测链:`banban.api.talkingq.com → Let's Encrypt YE1 → Root YE(由 X2 交叉签名)→ ISRG Root X2`。
- 当前服务器证书有效期:2026-08-28 至 2026-11-26。后台正常续期且仍能链到内置根时,不需要随服务器证书续期更新固件。
- Python/OpenSSL 仅加载从固件源码提取的这一张根 CA,没有加载系统证书库或自动下载中间证书,TLS 1.2 验证成功;错误域名和空信任库均验证失败。
- 固件进行证书链、有效期和域名验证;未增加 OCSP/CRL 吊销查询。后端更换到其他根 CA 时,需要评估并更新信任根。
可重跑:`ql-cross-tool\win32\owtoolchain\Python\python.exe tools\probe_wss_root.py`。该测试验证服务器链完整性和内置信任根,不能代替板端 mbedTLS 实测。
## 构建与验证
```bat
tools\test_wss.cmd
ql-cross-tool\win32\owtoolchain\Python\python.exe tools\check_mbedtls_abi.py
build.bat kernel
build.bat app
build.bat firmware
```
主机测试使用 MSVC 编译实际 URL 和握手解析源码;另从真实实现提取 TLS 写入和取消连接函数,注入桩测试短写、重试、超时、时钟回绕和资源释放。`tools/test_wss_receive.py` 提取实际接收和握手等待函数,结合实际 HTTP 解析器验证 WANT_READ/WANT_WRITE、分片 101、响应后帧数据保留、超时和时钟回绕、EOF/真实错误、空 TLS 上下文及错误 Accept;修复前可复现误断线,修复后通过。解析测试覆盖合法地址、非法端口、明文拒绝、缓冲区边界、旧地址识别、每个响应头分片边界、非 101、错误/重复 Accept、缺失 Upgrade/Connection 和响应大小上限。
在 Visual Studio 开发者终端运行 `ql-cross-tool\win32\owtoolchain\Python\python.exe tools\test_mbedtls_cert.py`,使用 SDK 实际 crypto/X.509 源码和共享配置验证内置根 CA、当前服务器证书链、错误域名、空信任库、过期/尚未生效日期,以及 AES-GCM 标准测试向量。测试中的分配器、UTC 时钟和日志适配到 Windows,文件读取由测试程序完成;没有替换证书算法实现。默认使用 `artifacts/wss/retest-443/chain-0.pem` 至 `chain-2.pem`,可把探测输出目录作为脚本参数。
导出到下述路径后运行 `ql-cross-tool\win32\owtoolchain\Python\python.exe tools\verify_wss_package.py`,核对 ZIP CRC、APP/内核与当前构建的字节一致性、无 GNSS 入口以及内核 ECDSA/GCM/日期校验符号。SDK 有既有编译警告,不能仅凭外层批处理退出码认定成功。
最新优化包位于 `artifacts/wss/full-handshake/EG800AKCN_11LG-legacy-wss-x25519.zip`,标准输出为 `target/EG800AKCN_11LG/EG800AKCN_11LG.zip`,两者字节一致。这是完整多分区烧录包,内核与上一版 NIST 加速包字节一致。运行 `ql-cross-tool\win32\owtoolchain\Python\python.exe tools\verify_wss_package.py` 校验默认最新包;也可显式传入该 ZIP 路径。
`ecc-fix/EG800AKCN_11LG-legacy-wss-ecc.zip` 保留用于对照接收错误。原 `artifacts/wss/EG800AKCN_11LG-legacy-wss.zip` 存在缺失 ECDSA 的问题,请勿用于验证本次修复。旧板明文 WS 包仍保留在 `artifacts/legacy-no-gnss/`。
## 上板验收
443 `/ws` 已通过主机握手测试;ECC/RTC、接收修复、NIST 加速和 X25519 优先配置均已在板端通过 TLS、HTTP 101。下面作为后续多次重复测试与业务稳定性验收步骤:
1. 无 GNSS 旧板正常启动、蜂窝网络就绪、RTC 时间正确。
2. 先出现 `WSS root CA parsed successfully`,再出现 `WSS TLS handshake and certificate/hostname verification passed`。
3. 出现 `WebSocket upgrade verified: HTTP 101` 和 `ws connect okay`。
4. 服务器确认原设备鉴权成功,再测试收发音频、断网重连和休眠唤醒。
5. 确认 `WSS TLS negotiated ECDHE group: 9`;记录 `WSS TLS phase` 和 `WSS TLS handshake total`,同一网络环境多次对比上一版 1820 ms 的 TLS 握手耗时。
TLS 成功、WebSocket 成功、设备鉴权成功是三个不同阶段,不能只看其中一条日志就认定业务已跑通。