130、配对过程中密钥分发失败的定位方法
前两年做一款无线传感器节点组网的项目现场部署了大概两百多个采集节点网关和节点之间通过低功耗无线做配对绑定。出厂前在实验室里配对测试都挺顺结果到了现场有将近三成的节点反复配对失败。现象很邪门网关端日志显示配对请求收到了也回了配对响应但节点侧就是停在“等待密钥”的状态超时后重试重试几次就彻底放弃。客户那边催得紧现场施工人员拿着手持配置器一个个手动复位两百多个节点折腾了整整两天。更让人难受的是有些节点复位后能配对成功但过几个小时又掉线重新配对又失败。当时第一反应是无线信号干扰换了几个信道问题依旧。后来抓了空口数据才发现问题根本不在信号强度上。这个坑让我重新梳理了一遍配对流程里密钥分发这个环节的定位思路。下面把当时踩过的坑和后来沉淀下来的判断方法写出来。先搞清楚配对和密钥分发是两件事很多刚接触无线组网的人会把“配对成功”和“密钥分发成功”混为一谈。实际上这是两个阶段配对阶段解决的是“我要和你建立关系”双方交换身份标识、能力信息协商出一个会话基础参数。这个阶段通常用明文或者默认密钥保护因为此时双方还没有共享密钥。密钥分发阶段解决的是“我们之间的通信怎么加密”由一方生成或者协商出会话密钥然后安全地传给另一方。这个阶段一旦出问题表现往往就是配对流程卡住、超时、重试但抓包看配对请求和响应都正常。现场排查时第一个要确认的就是故障到底卡在配对阶段还是密钥分发阶段。判断方法很简单在节点侧加一个状态机打点看它停在哪个状态。如果停在“已发送配对请求”之后、“已收到配对响应”之前那是配对阶段的问题如果停在“已收到配对响应”之后、“已安装密钥”之前那就是密钥分发阶段的问题。当时我们的节点固件里没有加这个打点现场只能靠猜这是第一个教训。密钥分发失败的几种典型表现密钥分发失败不是只有“完全收不到”这一种。根据现场观察大概可以分成几类第一类节点侧完全收不到密钥分发消息。现象是节点在等待密钥状态超时网关侧日志显示密钥分发消息已经发出甚至可能显示发送成功。这种最常见的原因是密钥分发消息用的目标地址或者连接句柄不对消息发出去了但节点根本不认。第二类节点侧收到了密钥分发消息但校验失败。现象是节点收到消息后直接丢弃继续等待超时后重试。这种通常是密钥分发消息的完整性保护出了问题比如消息认证码计算不一致、序列号窗口不对、加密模式不匹配。第三类节点侧收到了也校验通过了但安装密钥时失败。现象是节点短暂进入“已安装密钥”状态但很快又回到等待状态。这种往往是密钥存储区域写失败、密钥长度和算法不匹配、或者密钥槽位已经被占用。第四类节点侧安装成功了但网关侧没有收到确认。现象是节点认为配对完成开始用新密钥发数据但网关侧还在用旧密钥或者默认密钥导致数据解密失败。这种最隐蔽因为双方状态不一致但各自都觉得自己是对的。定位时先看空口抓包但别只看空口空口抓包是定位密钥分发问题的第一手资料但很多人抓了包不知道怎么读。当时我们抓包后发现网关确实发出了密钥分发消息节点也回了确认但确认消息里的状态码是“密钥校验失败”。这里有个细节密钥分发消息本身可能是加密的抓包工具不一定能解出来。但消息的头部、长度、序列号、目标地址这些元信息通常是可见的。先看这些元信息对不对再看节点回的确认消息里的状态码。如果空口抓包显示密钥分发消息发出去了节点也回了确认但确认是失败那问题就在节点侧的校验逻辑。这时候要对比网关侧和节点侧的几个参数密钥分发消息的序列号是否在节点接收窗口内、消息认证码的计算输入是否一致、加密算法的初始化向量是否同步。当时我们遇到的一个坑是网关侧在密钥分发时用的序列号是从配对阶段延续下来的但节点侧在配对完成后重置了序列号计数器。结果节点收到密钥分发消息时发现序列号比预期大很多直接判定为重放攻击丢弃了。这个细节在文档里根本没提是抓包对比了两边的计数器才发现的。密钥分发通道本身可能就有问题密钥分发消息通常走的是配对阶段建立的临时通道。这个临时通道可能用的是默认密钥、或者配对阶段协商出来的临时密钥。如果临时通道本身就不安全或者不稳定密钥分发自然容易失败。当时现场有个现象节点离网关近的时候配对成功率高离得远就经常失败。一开始以为是信号强度问题后来发现不是。近距离时临时通道的误码率低密钥分发消息一次就能传完远距离时误码率高密钥分发消息可能需要分片重传而分片重传的逻辑有bug重传时序列号没有正确递增导致节点侧认为收到了重复消息而丢弃。这个问题的定位方法是在密钥分发阶段统计消息重传次数。如果重传次数明显高于配对阶段那就要怀疑分片重传逻辑。当时我们在网关侧加了一个计数器发现失败的那些配对密钥分发消息的平均重传次数是成功配对的五倍以上。节点侧的资源状态也要看密钥分发失败有时候不是协议问题而是节点侧资源不够了。比如密钥存储区域写满、内存不够导致消息队列溢出、或者任务调度优先级太低导致密钥分发消息被其他任务挤掉。当时有一个批次的节点配对失败率特别高。后来发现这些节点在配对前刚执行过一次固件升级升级后没有清理临时存储区导致密钥槽位被旧的临时密钥占满了。新密钥分发过来时找不到空闲槽位直接返回失败。这种问题的定位方法是在节点侧加资源状态打点看密钥分发失败时密钥槽位的使用情况、内存剩余情况、任务队列深度。如果发现资源紧张那就先解决资源问题而不是死磕协议。网关侧的状态机也要对齐密钥分发是双方状态机协同的过程。网关侧的状态机如果和节点侧不一致就会出现一方认为在等待确认、另一方认为已经完成的情况。当时有个隐蔽的bug网关侧在发出密钥分发消息后如果在一定时间内没有收到确认会重发。但重发时没有检查节点侧是否已经切换到了新密钥。结果节点侧已经安装新密钥并开始用新密钥通信网关侧还在用旧密钥重发密钥分发消息节点侧收到后用新密钥解密失败直接丢弃。这种问题的定位方法是在网关侧记录每次密钥分发消息的发送时间、重发次数、以及收到确认的时间。如果发现重发次数大于零且最终失败就要检查重发逻辑是否考虑了节点侧的状态迁移。一个实用的排查顺序综合当时的经验现场排查密钥分发失败可以按这个顺序来第一步确认故障阶段。在节点侧加状态打点看是卡在配对阶段还是密钥分发阶段。第二步看空口抓包。确认密钥分发消息是否发出、节点是否收到、节点回的确认状态码是什么。第三步对比双方参数。重点看序列号、密钥长度、加密算法、消息认证码计算输入。第四步检查通道质量。统计密钥分发阶段的重传次数和配对阶段对比。第五步检查节点资源。看密钥槽位、内存、任务队列。第六步对齐双方状态机。检查网关侧的重发逻辑是否考虑了节点侧的状态迁移。这个顺序不是死的但核心思路是先定位阶段再定位方向最后定位具体参数。最怕的是一上来就怀疑信号强度换信道、加功率折腾半天发现是序列号不匹配。一些取舍密钥分发失败定位最耗时的地方在于复现。现场环境复杂实验室很难完全模拟。当时我们的做法是在实验室里搭了一个可调衰减的射频环境把信号衰减调到临界值人为制造误码和重传这样就能稳定复现现场的问题。另一个取舍是日志粒度。日志打得太细固件体积和运行开销受不了打得太粗现场又定位不了。当时的做法是分级日志默认只打关键状态迁移出问题时可以通过手持配置器打开详细日志复现一次就能抓到足够的信息。还有一个取舍是密钥分发的可靠性机制。加确认重传能提高成功率但会增加配对时间。当时现场有两百多个节点配对时间从平均三秒增加到八秒施工人员等得着急。后来折中方案是只在密钥分发阶段加确认重传配对阶段不加因为配对阶段失败可以快速重试密钥分发阶段失败重试代价更高。这些取舍没有标准答案取决于具体项目的部署规模、施工条件、节点资源。但定位思路是通用的先分阶段再看抓包对比参数检查资源对齐状态机。关键词核心关键词配对、重传、抓包、超时、信道、绑定、低功耗、功耗、固件升级精准长尾关键词配对过程中密钥分发失败的定位方法、密钥分发失败的几种典型表现、定位时先看空口抓包但别只看空口、节点侧的资源状态也要看、网关侧的状态机也要对齐、蓝牙BLE开发实战、BLE协议栈详解、低功耗蓝牙调试、BLE连接参数优化、蓝牙抓包分析、BLE广播数据解析、蓝牙连接稳定性优化