MAVLink 安全通信系列(6):PX4/QGC 集成与实操
返回系列总目录。
本篇把前文的加密 + 握手转成工程流程:从一次性的 CA 生成、 到给每台设备发证、到编译宏、到把库接进真实飞控 / 地面站,最后给出可跑的 双端示例与一份上线前的安全检查清单。
到这里,你有了一套可在 PC 示例中验证的握手与加密集成原型:在随机源、凭证、 接入闸门及本文列出的协议边界均得到妥善处理时,它可提供有限范围内的 payload 机密性、握手身份认证和会话密钥建立。它尚不能据此称为生产级完整安全方案。
0. 环境准备
- 运行生成工具需要 Python 3 和
cryptography:python -m pip install cryptography。 - PC 测试与 UDP 示例需要支持 C99 的 GCC。Windows 批处理默认使用仓库工具链路径; 若本机路径不同,在同一终端设置
CC后再运行脚本,例如 PowerShell:$env:CC = 'C:\mingw64\bin\gcc.exe'。 - Linux 使用仓库提供的
run_test.sh与build.sh。生成证书时应使用独立工作目录, 不要把 CA 私钥、设备私钥或包含私钥的演示头文件提交到版本库。
1. 总体架构:一张图看全
三块能力如何拼在一起:
flowchart TB
subgraph PKI["① 证书体系(一次性 + 量产)"]
CA["根 CA(gen_pki.py)"] --> LEAF["设备发证(gen_device_cert.py)"]
LEAF --> CRED["每台设备:CA 公钥点 + 本机证书 + 本机私钥"]
end
subgraph HS["② 握手(链路建立时,一次性)"]
X509["X.509 双向认证<br/>(互验证书 + ECDSA 签名自证)"]
ECDHE["P-256 ECDHE 协商共享密钥 Z"]
HKDF["HKDF 派生会话密钥"]
X509 --> ECDHE --> HKDF
end
subgraph ENC["③ 加密通信(会话期间,逐帧)"]
GCM["AES-128-GCM 认证加密<br/>(会话密钥热替换进 aes.key)"]
end
CRED --> X509
HKDF -- "会话密钥热替换" --> GCM
GCS["地面站 QGC(client)"] <== "MAVLink 链路" ==> UAV["飞控 PX4(server)"]
GCM --> GCS
GCM --> UAV运行时流程:链路建立 → 双方验证证书并证明私钥持有 → ECDHE 协商共享秘密 → HKDF 派生会话密钥 → 在 AES-GCM 状态中安装密钥 → 业务帧进入加密路径。 消息是否真正“端到端安全”还取决于发送/接收闸门、header 认证、anti-replay、密钥 方向分离和平台随机源等因素,不能仅凭握手成功日志推断。
2. PKI 凭证流水线(量产)
每台设备上线前要拿到三样东西(tools/ 提供,只用 Python cryptography 库, 不再依赖 openssl CLI):
| 凭证 | 作用 | 敏感性 |
|---|---|---|
| CA 公钥点 | 信任锚(全网一致,钉扎在固件里) | 公开 |
| 本机证书 | X.509 leaf(含公钥,CA 签发) | 公开 |
| 本机私钥 | 与证书公钥配对的身份秘密 | 机密,绝不外泄 |
flowchart LR
A["gen_pki.py<br/>生成根 CA"] --> B["ca.key.pem<br/>CA 私钥(离线保管)"]
A --> C["ca_pub.der<br/>CA 公钥点(烧进设备)"]
C --> D["gen_device_cert.py<br/>给设备发证"]
B --> D
D --> E["np-fcs-h05_credentials.h<br/>ca_pubkey + cert_der + privkey"]两步命令:
# ① 一次性:生成私有 P-256 根 CA(ca.key.pem 必须离线保管)
python tools/gen_pki.py --out-dir certs
# ② 每台设备:发证(密钥对 + CA 签名 + 固件 C 头)
python tools/gen_device_cert.py --ca-dir certs --device NP-FCS-H05 --out-dir fw生成的头文件里是三个符号,与 mavlink_handshake_init() 实参一一对应:
static const uint8_t ca_pubkey[65]; // 钉扎的 CA 公钥点(0x04||X||Y)
static const uint8_t np_fcs_h05_cert_der[]; // 本机 leaf 证书(DER)
static const uint16_t np_fcs_h05_cert_len;
static const uint8_t np_fcs_h05_privkey[32];// 本机 EC 私钥标量(机密)安全红线:证书是公开数据、可随固件分发;私钥标量是身份秘密。PC 演示为 方便把标量明文写在头文件里,真实设备应在安全元件 / TEE 内生成私钥,标量 绝不离开设备。 本项目当前验证器只信任单一钉扎 CA、验证一级证书及可选有效期;没有 CRL/OCSP 撤销检查,也没有将证书 subject 与
sysid绑定。签发独立证书只是建立治理基础, 并不自动具备逐台吊销能力。
3. 编译宏:一切改动的总开关
两把宏控制整套代码,都不定义时编译产物与原生 MAVLink 完全一致:
| 宏 | 作用 |
|---|---|
MAVLINK_USE_AES_ENCRYPTION | 启用 AES-128-GCM 载荷加密 |
MAVLINK_USE_X509_HANDSHAKE | 启用 X.509 握手(隐含启用加密) |
注入方式(PX4 用 CMake,QGC 用 qmake):
# PX4
add_definitions(-DMAVLINK_USE_AES_ENCRYPTION -DMAVLINK_USE_X509_HANDSHAKE)# QGC
DEFINES += MAVLINK_USE_AES_ENCRYPTION MAVLINK_USE_X509_HANDSHAKE只想要加密、不想要握手(用固定 PSK)?只定义 MAVLINK_USE_AES_ENCRYPTION 即可。
4. 集成四步(库 → 你的系统)
无论 PX4 还是 QGC,接入步骤是同一套:
flowchart LR
S1["1. 复制头文件<br/>c_library_v2 → mavlink 头目录"] --> S2["2. 定义编译宏"]
S2 --> S3["3. 初始化 + 注入凭证<br/>init() 绑定通道"]
S3 --> S4["4. 接线三个循环<br/>收 TUNNEL / 泵 TX / 周期 tick"]初始化(不装 PSK,只立旁路标志,mavlink_handshake_init 自动置位):
static mavlink_aes_gcm_state_t aes = {0};
static mavlink_handshake_ctx_t hs;
mavlink_handshake_init(&hs, MAVLINK_HANDSHAKE_ROLE_SERVER, &aes,
ca_pubkey, cert_der, cert_len, privkey, my_hw_random, my_unix_clock);
mavlink_get_channel_status(chan)->aes_gcm = &aes; /* 通道绑定 AES 状态 */
/* GCS 侧再调:mavlink_handshake_start(&hs); */三个接线点(第 5 篇已给代码,这里串成闭环):
sequenceDiagram
participant APP as 应用主循环
participant HS as mavlink_handshake_ctx_t
participant GCM as mavlink_aes_gcm_state_t
participant PHY as 链路
APP->>HS: tick(now)(周期驱动超时重传)
APP->>HS: poll_tx() 取待发记录 → TUNNEL 发出
PHY->>APP: 收到字节 → parse_char → 分发给 handle_tunnel 或业务回调
APP->>GCM: ESTABLISHED 后,业务帧自动 GCM 加解密5. 跑通双端示例(不依赖真实飞控)
仓库提供一套可独立运行的 UDP 双端模拟:example/ 下两个进程 uav_main(server)与 gcs_main(client),经 UDP 回环通信,还支持丢包故障 注入来验证握手的抗丢包能力。运行:
cd example
build.bat # Windows;Linux 用 sh build.sh
# 终端 1:启动无人机(server),参数 20 = 20% 丢包
uav/uav_main.exe 20
# 终端 2:启动地面站(client)
gcs/gcs_main.exe 20两端日志依次出现(截取自真实输出):
[UAV] handshake state: 2 -> 2 # server 在 WAIT_CF 收到 CLIENT_HELLO,发飞行2
[GCS] handshake state: 0 -> 1 # client 进入 WAIT_SH
[GCS] handshake state: 1 -> 3 # 收齐验完飞行2,进入 WAIT_DONE
[UAV] *** HANDSHAKE ESTABLISHED after 703 ms (peak flight retries: 1) ***
[GCS] *** HANDSHAKE ESTABLISHED after 1142 ms (peak flight retries: 3) ***
[GCS] << ATTITUDE roll=+2.3 pitch=-1.4 yaw=+0.0 deg (decrypted)
[GCS] >> COMMAND_LONG arm (confirmation 0)
[UAV] << COMMAND_LONG arm=1 -> ACK
[GCS] << COMMAND_ACK arming ACCEPTED观察点:即便 20% 丢包,握手也会自动整班重传、最终 ESTABLISHED——peak flight retries 就是真实发生的重传次数。随后日志说明演示程序走到了 payload 解密与 业务处理路径;它不验证真实 PX4/QGC 接入,也不构成协议审计、硬件安全或抗重放 证明。
想看算法库本身是否通过标准向量验证,跑自测:
cd test
run_test.bat # Windows;Linux 用 sh run_test.sh
# 期望输出:ALL SUITES PASSED| 测试 | 验证内容 |
|---|---|
test_aes_gcm | AES-GCM 正确性(NIST 标准向量 + 篡改拒绝) |
test_ecc | P-256 点乘 / ECDH / ECDSA 正确性 |
test_x509 | 证书校验:合法通过、篡改/伪造/过期拒绝 |
test_handshake | 完整握手回环:密钥一致、丢包自愈、篡改检测 |
6. 接入真实 PX4 / QGC
库本身是纯 header-only、C99、无堆,可直接进嵌入式。真实接入的关键改动点:
PX4(src/PX4-Autopilot-1.17.0/)
flowchart LR
A["头文件覆盖到<br/>src/modules/mavlink/.../C/include_v2.0/"] --> B["mavlink_main.h/.cpp<br/>新增 aes_gcm 成员 + init_aes_encryption()"]
B --> C["状态绑定到通道 status->aes_gcm"]
C --> D["mavlink_receiver.cpp<br/>处理消息前确保通道已绑 AES 状态"]QGC(src/qgroundcontrol-4.4.5/)
flowchart LR
A["头文件覆盖到<br/>libs/mavlink/include/mavlink/v2.0/"] --> B["MAVLinkProtocol.h/.cc"]
B --> C["按链路惰性初始化 AES 状态 + 配置随机数回调"]
C --> D["断开时释放"]分步说明见仓库内的 src/PX4-Autopilot-1.17.0/README.md 与 src/qgroundcontrol-4.4.5/README.md。
7. 上线前安全检查清单
从"能跑"到"评估是否可上线",至少对照以下项目:
| # | 项 | 红线 |
|---|---|---|
| 1 | 随机源 | 生产必须使用有可靠熵支持的 CSPRNG/DRBG;回调为 NULL 退回 xorshift 仅允许调试 |
| 2 | nonce 唯一 | 同一密钥下 nonce 严禁复用 |
| 3 | 私钥存储 | 在安全元件内生成,标量不落盘、不外传 |
| 4 | CA 私钥 | 离线保管,绝不进设备 |
| 5 | 凭据注入 | 运行时注入,库与示例不硬编码任何凭证 |
| 6 | 时钟 | 提供 now_unix 回调以启用证书有效期校验(否则默认跳过) |
| 7 | 发业务时机 | 必须等 ESTABLISHED 后再发业务帧(握手期间密钥无意义) |
| 8 | 栈 | 握手放独立线程,分配 4~6 KB 栈 |
| 9 | 测试 CA | 仓库公开的测试 CA 私钥严禁用于生产 |
| 10 | 帧长 | 加密帧多 28 字节,MAVLINK_MAX_PACKET_LEN 已调为 308 |
| 11 | AAD 与头部 | 当前 GCM AAD 只覆盖 flags、seq、sysid、compid;未覆盖 len/msgid |
| 12 | 抗重放 | 业务帧没有接收端 nonce/序号重放窗口;不要把随机 nonce 当作 anti-replay |
| 13 | 方向密钥 | 当前一把会话 AES 密钥双向复用;更严格部署应先设计方向分离 traffic keys |
| 14 | 产品评估 | 完成独立协议/实现审查、故障注入与真实目标平台测试后再评估生产适用性 |
8. 适用范围与安全边界
本篇区分了PC 示例验证与平台集成路径:UDP 双端示例和单元测试证明相应 代码路径在测试条件下运行,不代表已在目标机型完成端到端飞行验证。PX4/QGC 的源 码接入说明见本篇第 6 节;部署方仍须在确定的硬件、构建配置和链路环境中完成构建、 互操作及安全验证。
其余安全限制集中记录在第 7 篇:威胁模型与安全评估 和本篇第 7 节清单中,避免在实操篇重复铺陈。至少应注意:当前没有业务帧 anti-replay, AAD 未覆盖全部语义相关头字段,会话 traffic key 双向复用,证书撤销与设备身份绑定 也未实现。这些限制意味着不能仅凭示例通过或握手成功就宣称达到生产级安全。
关于
NextPilot Flight Control 是基于 RT-Thread 与 PX4 的先进 飞控系统,面向教育、研究与工业等领域。本项目(nextpilot-secure-mavlink)以开源 形式提供 MAVLink 链路安全能力,欢迎共建与反馈。
