Files
banban/docs/talkingq_wss.md
T
chenjintao 5c3e7eee6d Fix legacy WSS certificate support and receive retries
Share the APP/kernel TLS profile, enable ECDSA and AES-GCM, and use RTC time for certificate validation. Fix WANT_READ/WANT_WRITE handling during WebSocket upgrade and add ABI, certificate, and receive regression checks.
2026-09-16 14:19:55 +08:00

9.2 KiB
Raw Blame History

旧板 WSS 适配与联调

本次修改位于 legacy-board-wss(基于 legacy-board),默认地址为 wss://banban.api.talkingq.com:443/ws。沿用无 GNSS、默认音量 100 的旧板配置。上板暴露内核缺少 ECDSA 后,已补齐内核 TLS 能力并统一 APP/内核配置;本次必须更新内核和 APP。

后台实测(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 的域名配置中参考以下转发(由后台按真实部署调整):

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 下载及其他业务连接。

根证书来源与验证

固件内置的是公共根 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 实测。

构建与验证

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/recv-fix/EG800AKCN_11LG-legacy-wss-recv.zip,标准输出为 target/EG800AKCN_11LG/EG800AKCN_11LG.zip,两者字节一致。这是完整多分区烧录包,内核与 ECC/RTC 修复包一致,APP 增加接收重试修复。在保留已构建的 ECC/RTC 内核的当前工作区,本次仅需 build.bat app 和 build.bat firmware;全新工作区仍需先构建内核。校验命令为 ql-cross-tool\win32\owtoolchain\Python\python.exe tools\verify_wss_package.py artifacts/wss/recv-fix/EG800AKCN_11LG-legacy-wss-recv.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 修复已在板端通过 TLS 验证,接收修复包仍需上板检查:

  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. 服务器确认原设备鉴权成功,再测试收发音频、断网重连和休眠唤醒。

TLS 成功、WebSocket 成功、设备鉴权成功是三个不同阶段,不能只看其中一条日志就认定业务已跑通。