Mbed TLS 完全指南:配置、编译、测试与 PSA 密码学 API(结合 Flipper Zero 固件仓库实例解析)
2026/9/15 2:46:20 网站建设 项目流程

Mbed TLS 完全指南:配置、编译、测试与 PSA 密码学 API(结合 Flipper Zero 固件仓库实例解析)

【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware

导读

本文以 Flipper Zero 固件仓库内 OpenThread 无线协议栈所内置(vendored)的 Mbed TLS 上游 README 为核心,系统讲解 Mbed TLS 这一嵌入式密码学库的配置机制、三大构建系统(GNU Make / CMake / Visual Studio)、测试体系、平台移植要求与 PSA 密码学 API。读完本文,你将掌握如何裁剪 Mbed TLS 特性开关、如何用不同构建模式产出目标库、如何理解并复用其测试框架,并能对照当前仓库中主固件侧(lib/mbedtls)与协处理器侧(STM32WB 无线栈)两套 Mbed TLS 实例的实际裁剪方式。

Mbed TLS 是什么:定位与本仓库中的存在形式

Mbed TLS 是一个用 C 语言实现的密码学库,提供三类核心能力:

  • 密码学原语(cryptographic primitives):AES、DES、RSA、ECC(ECDH/ECDSA)、SHA-1/SHA-256、MD5、RIPEMD-160 等;
  • X.509 证书操作:证书解析、写入与验证;
  • SSL/TLS 与 DTLS 协议:完整的安全传输层协议栈。

其核心卖点是极小的代码占用(small code footprint),使其天然适配嵌入式系统——这正是 Flipper Zero 这类资源受限设备的诉求。此外,Mbed TLS 还内置了PSA Cryptography API的参考实现(在 README 写作时期标注为 "preview for evaluation purposes only",即仅用于评估的预览版本)。

在当前仓库中,该库以两种形态出现:

  1. 主固件侧独立副本:lib/mbedtls(含 include 与 library 目录),供 Flipper 主固件与外部 .fap 应用链接;
  2. STM32WB 无线栈内置副本:lib/stm32wb_copro/wpan/thread/openthread/stack/third_party/mbedtls/repo,即本文关联文档所在目录,服务 OpenThread 协议栈(Thread 网状网络、CoAP-Secure 等场景)。

从目录结构看,vendored 副本保留了include/(含mbedtls/psa/两套头文件)和library/(约 120 个.c实现文件,覆盖 AES、ECP、ECDSA、TLS/DTLS、X.509、PSA 等全部模块),但未包含上游仓库中的programs/(示例程序)、tests/(测试套件)、scripts/(配置脚本)与Makefile/CMakeLists.txt等构建脚本。这一点在阅读下文构建与测试章节时需特别注意:README 中描述的makectestscripts/config.py等流程面向上游完整源码树,而本仓库内的 vendored 副本是经过裁剪的源码快照。

配置机制:从 config.h 到仓库内的两套裁剪实践

上游配置方式(README 原文)

Mbed TLS 在大多数平台上"开箱即用"(build out of the box),但提供了两类配置入口:

  1. 手工编辑:完全文档化的配置文件 include/mbedtls/config.h,这是选择特性的唯一权威位置——每个MBEDTLS_XXX_C宏开关都对应一个模块的编译与否;
  2. 脚本化编辑:使用 Python 3 脚本scripts/config.py(运行--help查看用法),可在命令行上以程序化方式增删配置项,便于 CI 与自动化构建。

此外,上游在configs/目录中提供了若干面向特定用例的非标准配置(例如最小化配置、全功能配置等),详见configs/README.txt

编译器选项则沿用惯例,通过CCCFLAGS等环境变量注入 Make 与 CMake 构建系统。

仓库实践一:主固件侧以独立头文件覆盖默认配置

Flipper 主固件没有直接修改上游config.h,而是通过编译期强制指定自定义配置头文件。在 lib/mbedtls.scons 中:

CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"mbedtls_cfg.h\\"')],

即在编译每个源文件时预定义MBEDTLS_CONFIG_FILE="mbedtls_cfg.h",而 lib/mbedtls_cfg.h 是 Flipper 维护的精简配置清单,其中明确写着设计意图:"A subset of the mbedTLS configuration options that are relevant to the Flipper Zero firmware and apps",并提示如需更多特性,应通过fap_private_libs自带完整 mbedTLS 或提交 issue 补充默认配置。

该文件呈现了非常典型的嵌入式裁剪思路,关键开关包括:

类别配置宏说明
平台/内存MBEDTLS_HAVE_ASMMBEDTLS_NO_UDBL_DIVISIONMBEDTLS_NO_64BIT_MULTIPLICATION针对 Cortex-M 等无 64 位除法/乘法指令的平台关闭相关代码路径
分组密码模式MBEDTLS_CIPHER_MODE_CBC/CFB/CTR/OFB/XTS使能全部常用分组模式
填充方式MBEDTLS_CIPHER_PADDING_PKCS7ONE_AND_ZEROSZEROS_AND_LENZEROS支持 PKCS7 等主流填充
椭圆曲线MBEDTLS_ECP_DP_SECP256R1_ENABLED(其余曲线全部注释)、MBEDTLS_ECP_NIST_OPTIM只保留 secp256r1,显著缩小 ECP 代码体积
模块开关MBEDTLS_AES_CMBEDTLS_MD5_CMBEDTLS_SHA1_CMBEDTLS_SHA224_CMBEDTLS_SHA256_CMBEDTLS_DES_CMBEDTLS_ECDH_CMBEDTLS_ECDSA_CMBEDTLS_ECP_CMBEDTLS_GCM_CMBEDTLS_CIPHER_CMBEDTLS_BIGNUM_CMBEDTLS_ASN1_PARSE_CMBEDTLS_ASN1_WRITE_CMBEDTLS_BASE64_CMBEDTLS_OID_CMBEDTLS_MD_CMBEDTLS_DHM_CMBEDTLS_GENPRIMEMBEDTLS_ERROR_C按需开启的算法与工具模块
明确关闭MBEDTLS_CHACHA20_CMBEDTLS_CHACHAPOLY_CMBEDTLS_RSA_CMBEDTLS_RIPEMD160_CMBEDTLS_PEM_PARSE_CMBEDTLS_PEM_WRITE_CMBEDTLS_PLATFORM_CMBEDTLS_PLATFORM_MEMORY关闭对固件无用的重模块,换体积

同时 lib/mbedtls.scons 只挑选了 13 个源文件参与编译(aes、bignum、bignum_core、ecdsa、ecp、ecp_curves、md、md5、platform_util、ripemd160、sha1、sha256、des),并注释说明"如果我们构建完整 mbedtls,需要GlobRecursive全部文件;否则只取所需文件"。这是"配置头 + 源文件白名单"双管齐下的体积控制手段。

仓库实践二:OpenThread 侧面向 Thread 场景的极简配置

无线栈副本的配置在 third_party/mbedtls/mbedtls-config.h,它不直接定义MBEDTLS_CONFIG_FILE覆盖文件,而是自身定义了MBEDTLS_CONFIG_H#include "openthread-core-config.h",随后按 OpenThread 的编译选项(OPENTHREAD_CONFIG_*)条件化地开启 Mbed TLS 特性。几个值得注意的细节:

  • 算法面收敛到 Thread 实际所需:默认开启 AES、ASN1、BIGNUM、CCM、CIPHER、CMAC、CTR_DRBG、ECJPAKE、ECP、MD、SHA224/SHA256、TLS/DTLS 客户端等;仅当开启 CoAP-Secure、Border Agent、Commissioner 等选项时才追加MBEDTLS_SSL_SRV_CMBEDTLS_SSL_COOKIE_C、PSK/ECDHE-ECDSA 密钥交换等;
  • 内存与性能参数被显式收紧MBEDTLS_MPI_WINDOW_SIZE=1MBEDTLS_MPI_MAX_SIZE=32MBEDTLS_ECP_MAX_BITS=256MBEDTLS_ECP_WINDOW_SIZE=2MBEDTLS_ECP_FIXED_POINT_OPTIM=0MBEDTLS_ENTROPY_MAX_SOURCES=1,直接限定大数运算与 ECP 的资源上限;
  • TLS 层面做定向压缩:固定唯一密码套件MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8,并依据是否启用 CoAP-Secure 将MBEDTLS_SSL_MAX_CONTENT_LEN设为 900 或 768 字节(进出方向同值);
  • 平台适配:关闭默认熵源(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCESMBEDTLS_NO_PLATFORM_ENTROPY),内存分配走 OpenThread 平台层(MBEDTLS_PLATFORM_STD_CALLOC=otPlatCAllocMBEDTLS_PLATFORM_STD_FREE=otPlatFree),未启用外部堆时则退回MBEDTLS_MEMORY_BUFFER_ALLOC_C静态缓冲分配器。

以上两套配置,恰好是 README 所述"在 config.h 中选择特性"这一机制在两个不同工程约束下的真实演绎。

文档体系:在线文档与本地 Doxygen

上游 Mbed TLS 主文档托管在 ReadTheDocs,PSA Cryptography API 规范文档独立成册。README 同时给出了生成本地 HTML 文档的完整步骤:

  1. 安装 Doxygen(README 时代推荐 1.8.11,稍旧或更新的版本亦可);
  2. 在源码树根目录执行make apidoc
  3. 用浏览器打开apidoc/index.htmlapidoc/modules.html

apidoc输出会针对你当前的编译期配置生成,即被config.h裁掉的模块不会出现在文档中。需要注意的是,该流程依赖上游完整的 Makefile 体系;本仓库的 vendored 副本未携带 Makefile,因此这一流程适用于从上游拉取的完整源码树。其他问题渠道可参考同目录下的 SUPPORT.md。

编译:三大构建系统详解

产物划分与链接顺序

Make 与 CMake 构建系统产出三个库

依赖关系
libmbedcrypto基础密码学原语(无依赖)
libmbedx509依赖libmbedcrypto
libmbedtls依赖libmbedx509libmbedcrypto

由于存在链式依赖,部分链接器(如 GNU ld)要求链接旗标按序排列-lmbedtls -lmbedx509 -lmbedcrypto

工具版本要求(README 原文)

  • GNU Make,或 CMake 所支持的构建工具;
  • C99 工具链(编译器、链接器、归档器)——官方测试矩阵为 GCC 5.4、Clang 3.8、IAR8、Visual Studio 2013,更新版本应可工作,略旧版本可能可用;
  • Python 3.6+:用于生成测试代码;
  • Perl:用于运行测试。

GNU Make 构建

仓库(上游)刻意只使用 Makefile 的最小功能子集,以保持与不同工具链的兼容性,便于跨平台迁移;需要更复杂特性的用户被推荐使用 CMake。

make # 构建库与示例程序 make check # 构建并运行测试(需 Python 构建 + Perl 运行) make no_test # 跳过测试构建 programs/test/selftest # 无测试工具时仍可运行的小型自检集

平台相关的关键变量:

  • WINDOWS_BUILD=1:目标为 Windows、但构建环境是 Unix 风格(交叉编译、MSYS shell)时使用;
  • WINDOWS=1:构建环境本身是 Windows shell(如 mingw32-make)时使用(此时部分目标不可用);
  • SHARED=1:在静态库之外额外生成共享库;
  • DEBUG=1:生成调试构建;
  • CFLAGS/LDFLAGS:可在环境或命令行覆盖,注意CFLAGS会覆盖默认的-O2,若只想追加警告选项,可写CFLAGS=-O2 -Werror
  • WARNING_CFLAGS:单独覆盖默认警告选项(默认以-Wall -Wextra开头),当编译器不支持-Wall时可用它清空默认值。

CMake 构建

推荐的独立目录(out-of-tree)构建

mkdir /path/to/build_dir && cd /path/to/build_dir cmake /path/to/mbedtls_source cmake --build . ctest # 运行测试(需 Python 构建 + Perl 执行)

关键开关与模式:

  • cmake -DENABLE_TESTING=Off:无 Python/Perl 环境时禁用测试套件(仍可运行programs/test/selftest);
  • cmake -DUSE_SHARED_MBEDTLS_LIBRARY=On:构建共享库;
  • cmake -D CMAKE_BUILD_TYPE=Debug:切换构建模式;
  • cmake -LH:列出所有可用 CMake 选项。

CMake 提供的构建模式(大部分面向 gcc/clang)如下表:

模式用途
Release默认代码,二进制中不含冗余信息
Debug含调试信息、关闭优化
Coverage在调试信息之外生成代码覆盖率
ASan注入 AddressSanitizer 检测内存错误(新版 gcc/clang 附带 LeakSanitizer;新版 clang 还注入 UndefinedSanitizer)
ASanDbg同 ASan,但更慢,含调试信息与更好栈回溯
MemSan注入 MemorySanitizer 检测未初始化内存读取(实验性,需 Linux/x86_64 上的新版 clang)
MemSanDbg同 MemSan,更慢,含调试信息、栈回溯与来源追踪(origin tracking)
Check激活依赖优化的编译器警告并将全部警告视为错误

CMake 的两条重要约束(README 反复强调):

  1. 首次调用cmake之后不能再改编译器与旗标CC=your_cc make/make CC=your_cc均无效(CFLAGS同理),必须在首次配置时指定:CC=your_cc cmake /path/to/mbedtls_source
  2. 若已配置过想改这些设置,必须删除构建目录重建;就地构建(in-place)会覆盖提供的 Makefile(可用scripts/tmp_ignore_makefiles.sh防止git status显示它们被修改),改CC/CFLAGS时需清除 CMake 缓存,例如用 GNU find:find . -iname '*cmake*' -not -name CMakeLists.txt -exec rm -rf {} +

此外,命令行设置CFLAGS时其值不会覆盖CMake 按构建模式提供的内容,而是被前置拼接到其后。

作为子项目(subproject)嵌入:Mbed TLS 支持被父 CMake 工程通过add_subdirectory()直接引入编译,这是将 Mbed TLS 嵌入更大工程的推荐方式。

Microsoft Visual Studio

上游为 Visual Studio 2010 生成构建文件,解决方案文件mbedTLS.sln包含构建库与全部示例程序所需的基础工程。由于测试文件需要 Python 与 Perl 环境生成/执行,tests/下的文件不随 VS 工程编译,但programs/test/中的 selftest 程序仍可用。

与本仓库主固件侧构建的对照

Flipper 主固件使用 SCons(见根目录 SConstruct 与 firmware.scons)而非 Make/CMake,但其思路与 README 高度一致:在 lib/mbedtls.scons 中为 mbedtls 库附加-mword-relocations-mlong-calls(注释注明"Required for lib to be linkable with .faps",即让库能被外部应用 ELF 链接),并忽略-Wno-redundant-decls这类噪音警告。若你希望在 SCons 工程中以同样的方式复用完整 Mbed TLS,GlobRecursive全部library/*.c即为等价于"完整构建"的做法。

示例程序:programs/ 目录的定位

上游在programs/目录下为大量特性与用例提供了示例程序(其说明见上游programs/README.md)。README 特别提醒:这些示例旨在演示库的特定特性,代码需要改造后才能用于真实应用——切勿直接拷贝进产品代码。本仓库的 vendored 副本未包含programs/目录(仅保留include/library/),如需示例需取自上游完整源码。

测试体系:生成式测试与集成测试矩阵

Mbed TLS 的测试套件采用**"代码生成 + 数据驱动"**模式(README 原文):

  • 测试文件(如test_suite_mpi.c)最初需要 Python 生成;
  • 生成的依据是两类源文件:function file(如suites/test_suite_mpi.function,存放测试函数)与data file(如suites/test_suite_mpi.data,存放测试用例——即传给测试函数的参数)。

在具备 Unix shell 与 OpenSSL(可选 GnuTLS)的机器上,还有一组高层脚本:

脚本作用
tests/ssl-opt.sh各种 TLS 选项(重协商、会话恢复等)的集成测试,并测试与其他实现的互操作性
tests/compat.sh每个密码套件与其他实现(OpenSSL/GnuTLS)的互操作测试
tests/scripts/test-ref-configs.pl在多种精简配置下做构建测试
tests/scripts/depends.py分别只开启单一曲线、密钥交换、哈希、密码或 pkalg 进行构建测试(验证依赖完整性)
tests/scripts/all.sh组合上述测试并附加更多变体(ASan、全量config.h等)

若不想手工安装全部测试工具,可复用 CI 所用的 Docker 镜像(详见上游测试基础设施仓库说明)。同样地,这些脚本在本仓库的 vendored 副本中未包含,属于上游工程化资产。

移植 Mbed TLS:平台前提条件

README 明确指出 Mbed TLS 大部分代码是可移植的 C99,但存在少量超出 C 标准、而现代主流架构普遍满足的平台要求:

  1. 字节必须为8 位
  2. 全零位(all-bits-zero)必须是空指针的合法表示
  3. 有符号整数必须采用二进制补码表示;
  4. intsize_t至少32 位宽
  5. 必须提供uint8_tuint16_tuint32_t及其有符号对应类型。

结合本仓库,Flipper Zero 的两套移植都额外做了平台定制:主固件侧通过 lib/mbedtls_cfg.h 的MBEDTLS_NO_UDBL_DIVISIONMBEDTLS_NO_64BIT_MULTIPLICATION适配 Cortex-M 内核缺少 64 位除法/乘法指令的问题(改为软件模拟路径);OpenThread 侧则在 mbedtls-config.h 中通过MBEDTLS_PLATFORM_MEMORY+otPlatCAlloc/otPlatFree(或MBEDTLS_MEMORY_BUFFER_ALLOC_C)把内存分配接回 Thread 平台层,并关闭默认熵源由平台自备随机数,这正对应 README 知识库中"移植到新环境/OS""外部依赖有哪些""如何配置"三类经典问题。

PSA Cryptography API:设计与参考实现

PSA 是什么

Arm 的Platform Security Architecture(PSA)是一套涵盖威胁模型、安全分析、硬件与固件架构规范、以及开源固件参考实现的整体安全方案,主张基于行业最佳实践,把安全"在硬件和固件两个层面一致地设计进去"。

PSA Cryptography API则提供对一组密码学原语的统一访问接口,具备双重用途:

  1. 在 PSA 合规平台上构建安全服务(安全启动 secure boot、安全存储 secure storage、安全通信 secure communication);
  2. 脱离其他 PSA 组件,在任意平台上独立使用。

API 设计目标(README 原文)

  • 调用者内存与内部内存分离:库可在隔离空间实现,无需隔离时可退化为直接函数调用,需要隔离时可实现为远程过程调用(RPC);
  • 内部数据结构对应用隐藏:允许在编译期或运行期替换替代实现(如接入硬件加速器);
  • 密钥全部通过 key identifier 访问:透明支持外部密码协处理器;
  • 算法接口泛化:优先算法敏捷性(algorithm agility);
  • 易用且难以误用:接口设计以安全易用为第一目标。

本仓库中的 PSA 实现

Mbed TLS 内置 PSA Cryptography API 的参考实现,README 明确声明其成熟度低于库的其他部分——部分代码未经同样深入的评审,部分实现尚未针对代码体积充分优化。X.509 与 TLS 代码可以通过在config.h中开启MBEDTLS_USE_PSA_CRYPTO来对有限的操作子集使用 PSA 密码学路径。当前仍存在若干与最新规范的偏差,合规问题清单以 GitHub 上游 issue 为准。

在本仓库的 vendored 副本中可看到 PSA 模块的实体存在:include/psa 头文件目录,以及 library 下的psa_crypto.cpsa_crypto_aead.cpsa_crypto_cipher.cpsa_crypto_ecp.cpsa_crypto_hash.cpsa_crypto_mac.cpsa_crypto_rsa.cpsa_crypto_slot_management.cpsa_crypto_storage.cpsa_crypto_driver_wrappers.c等系列实现文件(同时存在include/mbedtls/config_psa.hinclude/mbedtls/psa_util.h),印证了 README 对 PSA 实现模块的描述。

展望中的特性(README 原文)

上游计划中的后续能力包括:驱动编程接口(为选定算法接入硬件加速器代替软件实现)、外部密钥支持(密钥只存储与操作于独立密码协处理器)、按需编译的配置机制(只编译应用所需算法)、以及更广的算法集合

License 与贡献方式

除非文件内另有明确说明,Mbed TLS 文件采用Apache-2.0 OR GPL-2.0-or-later双许可证(SPDX 表达),完整文本见 LICENSE,贡献规范中"License and Copyright"一节见 CONTRIBUTING.md。

联系方式(上游渠道,供参考):

  • 报告安全漏洞:发送邮件至 mbed-tls-security 列表,流程详见 SECURITY.md;
  • 报告 Bug 或请求特性:在上游 GitHub 仓库提交 issue;
  • 其他讨论与支持渠道:SUPPORT.md。

总结:在 Flipper Zero 固件中实际运用本文知识

将 README 的通用知识与本仓库落地结合,可以形成三条可直接执行的行动路线:

  1. 裁剪验证:对照 lib/mbedtls_cfg.h 理解每个MBEDTLS_*宏对固件体积/功能的影响,新增功能时按"曲线→模块→填充/模式"逐级放开,并用MBEDTLS_ERROR_C辅助运行时诊断;
  2. 跨副本比对:主固件侧副本(lib/mbedtls)与 OpenThread 侧副本(repo)功能面完全不同——前者偏重 AES/DES/哈希与 ECDSA 的本地应用场景,后者收敛到 Thread 的 ECJPAKE + AES-128-CCM-8 DTLS 场景,可据此判断新增密码学需求应接入哪一侧;
  3. 复用测试思想:虽然 vendored 副本不含上游tests/,但其"function 文件 + data 文件生成测试"与"单一特性构建验证(depends.py 思路)"的方法论,同样适用于为 Flipper 固件的密码学模块编写数据驱动的单元测试。

【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询