ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32H573 Secure Manager与TLS 1.3集成:HKDF回退方案实战

STM32H573 Secure Manager与TLS 1.3集成:HKDF回退方案实战 前阵子我在一块STM32H573-DK上把Secure Manager和TLS 1.3拼在一起跑结果还没等到服务器回握手消息客户端就在密钥派生这一步直接停了。控制台干净利落地弹了一句PSA_ERROR_NOT_SUPPORTED翻译成人话就是Secure Manager不支持TLS 1.3密钥调度里最核心的HKDF-Extract/Expand。当时第一反应是“我哪个宏没开”翻了一圈CubeMX和mbedTLS的配置发现事情没那么简单。这个问题不是单纯少定义一个宏而是Secure Manager的算法边界和mbedTLS 3.x对TLS 1.3的实现方式之间存在一个结构性的冲突。这篇内容就是记录我从复现、分析到最终解决的完整过程。如果你是正在做STM32H5系列TrustZone、Secure Manager、mbedTLS、TLS 1.3集成的开发者这个坑你大概率躲不掉看完可以直接照着排查和改配置。1. 问题现场TLS 1.3握手卡在密钥派生1.1 复现环境与报错日志我的测试环境不算特殊开发板是STM32H573-DK工程用STM32CubeMX生成TrustZone模式打开安全侧集成了ST的Secure Manager非安全侧跑应用和mbedTLS。mbedTLS版本是3.5.1由I-CUBE-TLS中间件带进来TLS 1.3在mbedtls_config.h里开了MBEDTLS_SSL_PROTO_TLS1_3并且启用了默认的PSA Crypto支持。应用代码就是一个标准TLS 1.3客户端向本地测试服务器发ClientHello。服务器端抓包能看到ClientHello正常发出但后续握手包一直没出现再一看调试串口日志停在这附近[mbedtls] ssl_tls13_keys.c: mbedtls_ssl_tls13_key_schedule_stage_on_derive failed [mbedtls] secret derivation failed: psa_status PSA_ERROR_NOT_SUPPORTED (-164) [app] mbedtls_ssl_handshake returned -0x7280-0x7280是MBEDTLS_ERR_SSL_INTERNAL_ERROR之类的包装错误真正有价值的是中间那行PSA_ERROR_NOT_SUPPORTED。也就是说mbedTLS在构造TLS 1.3的早期密钥时调用PSA层的密钥派生接口底层直接回复“这个算法我不支持”。如果你是在调试器里单步跟会看得更清楚错误发生在psa_key_derivation_setup()这一步传入的算法是PSA_ALG_HKDF_EXTRACT(PSA_ALG_SHA_256)或者PSA_ALG_HKDF_EXPAND(PSA_ALG_SHA_256)返回码是PSA_ERROR_NOT_SUPPORTED也就是-164。1.2 TLS 1.3密钥调度为什么必须拆成Extract和Expand要理解这个报错得先明白TLS 1.3的密钥调度和TLS 1.2有着本质区别。TLS 1.2是拿握手过程中协商出的pre-master secret直接经过PRF生成主密钥整个过程是一步步固定的。TLS 1.3则把密钥生成完全建立在HKDF上并且为了支持0-RTT、会话恢复、流量密钥独立派生等特性RFC 8446第7.1节把整个密钥调度设计成了一条清晰的多阶段流水线。HKDF本身分成两步HKDF-Extract负责“提取”把输入的熵源PSK或者ECDHE共享密钥压缩成固定长度的PRKpseudorandom keyHKDF-Expand负责“扩展”用PRK加上info标签派生出任意长度的输出。在TLS 1.3里这两步是交替出现的先用PSK做一次Extract得到Early Secret再对Early Secret做Derive-Secret得到Handshake Secret的“盐”然后用ECDHE共享密钥做第二次Extract得到Handshake Secret最后再由Handshake Secret派生master secret。关键点来了TLS 1.3在这条流水线的不同阶段需要反复调用Extract和Expand而且它们的输入和输出是交替衔接的。例如握手流量密钥不是一次HKDF能算出来的需要先Extract出Handshake Secret再Expand出c hs traffic、s hs traffic等标签对应的密钥。如果协议栈只能用“完整HKDF”一步到位就无法在中间插入不同标签的Derive-Secret步骤也不可能拿到中间PRK去喂给下一步。所以在代码实现层面TLS 1.3协议栈必须能够分别调用HKDF-Extract和HKDF-Expand。这也正是PSA Crypto API在标准规范里单独定义了PSA_ALG_HKDF_EXTRACT和PSA_ALG_HKDF_EXPAND这两个算法标识的原因。它们就是为TLS 1.3这种复杂密钥调度场景专门准备的。1.3 mbedTLS在密钥调度里实际调了什么mbedTLS 3.x的TLS 1.3实现在ssl_tls13_keys.c里整个密钥调度通过PSA的key_derivation接口完成。具体走法是先调用psa_key_derivation_setup()初始化一个密钥派生操作算法用PSA_ALG_HKDF_EXTRACT(PSA_ALG_SHA_256)做提取再切换成PSA_ALG_HKDF_EXPAND(PSA_ALG_SHA_256)做扩展中间通过psa_key_derivation_input_bytes()喂入PSK、salt、IKM、info等数据。这里有一个容易忽略的事实在mbedTLS 3.x里TLS 1.3的密钥调度是强制走PSA Crypto接口的即使你没有显式开MBEDTLS_USE_PSA_CRYPTO只要启用了TLS 1.3它就会使用PSA的算法接口来调用哈希和HKDF。这样设计是为了让TLS 1.3可以无缝使用各种硬件加速或安全隔离环境提供的密码服务。但代价就是底层PSA实现如果不支持单步HKDF算法TLS 1.3握手就会在这里直接失败。2. 根因分析Secure Manager为何会拒绝HKDF单步调用2.1 Secure Manager的隔离边界和PSA接口STM32H573内置TrustZone安全扩展Cortex-M33核心可以划分安全世界和非安全世界。Secure Manager就是ST提供的一个运行在安全世界里的固件组件它把密钥管理、安全存储、加解密算法、安全启动等服务封装成一个个受保护的调用接口。用户拿到的是一个预编译的固件和安全库不能修改安全侧实现只能通过PSA API或FF-M接口发起调用。这种架构的核心价值是隔离。即使非安全侧的应用被攻破攻击者也无法直接拿到根密钥因为真正的加解密运算发生在安全世界里非安全侧只看到一个句柄或者操作符。密钥永远不落到普通内存中。但硬币的另一面是Secure Manager能提供哪些算法不是由你的应用代码决定的而是由ST在固件里预先写死的。它暴露的算法集合是一个封闭集合用户只能在集合内选择不能往里加东西。当mbedTLS要求HKDF-Extract/Expand这两个单步算法时如果这个集合里只有完整HKDF组合算法而没有单步算法那底层就只会老老实实返回PSA_ERROR_NOT_SUPPORTED。2.2 Secure Manager的算法边界和“not supported”到底什么意思我查了手头Secure Manager版本的用户手册和Release Notes也对照了它导出的PSA算法支持矩阵。矩阵里明确支持AES-CBC/CTR/GCM/CCM、AES-CMAC、RSA、ECCP-256/384、ECDSA、ECDH、SHA-256/384、HMAC、完整HKDF等常规算法。但到了单步HKDF这里支持情况就变得暧昧了很多版本只暴露了完整的PSA_ALG_HKDF(PSA_ALG_SHA_256)组合算法没有把PSA_ALG_HKDF_EXTRACT和PSA_ALG_HKDF_EXPAND单独暴露出来。这不是技术做不到更像是一种安全策略上的取舍。从固件审计的角度看单步HKDF-Expand接口允许调用方用任意PRK和任意info标签派生数据灵活性更高也意味着一旦非安全侧被攻破攻击者可以更自由地调用密码学原语去构造各种数据。完整HKDF组合算法则把“输入到输出”封装成一个整体调用方拿不到中间PRK审计面更小。对于追求高安全等级认证的Secure Manager固件来说少暴露一个原语就少一分被滥用的风险。所以PSA_ERROR_NOT_SUPPORTED的含义是Secure Manager固件“故意”没有注册这两个算法。这是Secure Manager的算法边界不是mbedTLS这边某个开关能直接治愈的。2.3 几个容易被误判的根因我这个报错最开始也怀疑过是不是mbedTLS配置问题后来发现有些常见误判值得先说清楚免得大家绕远路。第一不是MBEDTLS_USE_PSA_CRYPTO没开。TLS 1.3的密钥调度在mbedTLS 3.x里本来就强制走PSA跟这个宏没有直接关系。第二不是哈希算法没启用。虽然TLS 1.3用SHA-256或SHA-384做HKDF底层哈希但Secure Manager通常支持SHA-256mbedTLS侧也确实编译进去了只是最终没有走到软件实现的HKDF分支。第三不是Secure Manager完全没提供HKDF。它提供了完整HKDF组合算法只是没有暴露单步版本。所以如果你不跑TLS 1.3而是自己调psa_key_derivation做完整HKDF可能是正常的。一进TLS 1.3就挂因为TLS 1.3需要的是单步原语。判断根因最直接的办法是写一小段测试代码在握手前分别调用psa_key_derivation_setup()尝试PSA_ALG_HKDF_EXTRACT(PSA_ALG_SHA_256)和PSA_ALG_HKDF_EXPAND(PSA_ALG_SHA_256)打印返回值。如果这两个调用都返回PSA_ERROR_NOT_SUPPORTED那就基本实锤是Secure Manager算法支持范围的问题。3. 有效方案让HKDF绕开Secure Manager3.1 方案一软件回退修改PSA驱动路由最稳妥、改动最小、见效最快的办法是让HKDF单步算法在PSA驱动路由器里回退到mbedTLS自带的软件实现而不是交给Secure Manager驱动。mbedTLS的PSA驱动机制是支持“多驱动 fallback”的每次调用psa_key_derivation_setup()时它会逐个尝试注册过的驱动如果某个驱动对该算法返回PSA_ERROR_NOT_SUPPORTED就继续尝试下一个最后落到内置软件实现。在实际工程里PSA驱动的注册表体现在psa_driver_wrappers.h这个文件里。STM32CubeMX生成工程时会为Secure Manager的crypto驱动生成对应的包装函数比如sm_psa_key_derivation_setup()。你可以在包装函数里看到它对HKDF_EXTRACT和HKDF_EXPAND直接返回了PSA_ERROR_NOT_SUPPORTED。修改思路是这样把HKDF相关算法的调用从Secure Manager驱动分支里“摘”出来或者更简单一点把Secure Manager驱动在key_derivation_setup这一层直接跳过HKDF算法让psa_driver_wrappers.h在遍历驱动后进入软件实现分支。示意逻辑大致如下实际代码以工程生成的为准psa_status_t psa_driver_wrapper_key_derivation_setup( psa_key_derivation_operation_t *operation, psa_algorithm_t alg) { /* 先尝试Secure Manager驱动 */ psa_status_t status sm_key_derivation_setup(operation, alg); if (status ! PSA_ERROR_NOT_SUPPORTED) { return status; } /* 回退到内置软件实现 */ return mbedtls_psa_key_derivation_setup(operation, alg); }这里有一个前提软件实现的mbedtls_psa_key_derivation_setup()必须被编译进去并且psa/crypto_config.h里必须定义了PSA_WANT_ALG_HKDF_EXTRACT和PSA_WANT_ALG_HKDF_EXPAND这两个宏。如果你用的还是CubeMX默认配置一般会默认带软件PSA实现只需要确认这两个宏存在。改完之后Secure Manager的AES-GCM、ECDH等高速算法仍然走硬件安全侧HKDF这个握手阶段的低频操作走软件实现既不牺牲安全整体架构又能让TLS 1.3的密钥调度正常运转。这是我最后采取的方案也是我觉得最推荐的做法。3.2 方案二升级Secure Manager版本如果你的生产条件允许升级Secure Manager固件那方案二值得先看一眼。ST在后续版本里确实持续扩展了Secure Manager支持的算法范围包括对TLS 1.3需要的单步HKDF支持的补强。具体哪些版本开放了要看你手里的Secure Manager固件包的Release Notes。升级这件事有一个约束Secure Manager通常是和安全启动、密钥注入绑定在一起的升级前必须确认当前板子的安全状态是否允许替换固件以及升级后会不会导致已经烧录的密钥失效。开发板上无所谓但如果已经到了产线阶段就要严格走固件更新流程不能直接在应用里刷。如果你用的Secure Manager版本比较老我建议先下载最新的STM32CubeFW_H5固件包对照Release Notes确认算法支持矩阵。如果新版本明确写了支持HKDF-Extract/Expand那直接在CubeMX里换个配置重新生成工程再编译烧录问题可能就消失了。不过这个方法依赖ST的更新节奏不是你想升级就马上有的所以不要把它当唯一保底方案。3.3 方案三换协议栈或手动实现密钥派生如果前两个方案都走不通还有一条路但工程量和风险都大不少我一般只建议在特殊场景下考虑。一条路是换TLS协议栈比如用wolfSSL。wolfSSL的TLS 1.3实现允许你把密钥派生部分配置成软件实现也可以自定义回调绕开Secure Manager的PSA算法限制。代价是你要重新适配接口、移植证书管理、调整非安全侧的RTOS集成工作量不算小。另一条路是在应用层手动实现TLS 1.3的密钥调度完全绕开mbedTLS的默认流程。听起来很酷但实际非常麻烦。TLS 1.3的密钥调度牵扯到握手状态机、Finished校验、会话恢复等多个环节你自己实现了HKDF这两个单步函数还不够还要把ssl_tls13_keys.c里的整体控制流接过来出错概率极高。除非你是专门研究协议栈的否则我不推荐走这条路。3.4 方案对比与选型建议把三个方案放在一起对比会更直观方案改动量风险适用场景软件回退改PSA驱动路由小改生成代码和配置低HKDF走软件实现大多数开发项目需要尽快跑通TLS 1.3升级Secure Manager版本小但依赖ST版本中涉及固件升级和安全状态开发早期或官方已确认支持换协议栈或手动实现大移植和调优周期长高特殊需求如必须全硬件加速、不能改固件对于大多数正在评估STM32H573 Secure Manager TLS 1.3方案的开发者我的建议是第一步直接走方案一把通信跑通再说不要被“必须全部走Secure Manager硬件加速”这个念头束缚。TLS 1.3握手过程中的密钥派生只发生一次计算量远小于后续流量的对称加解密。真正影响性能的AES-GCM流量加密仍然可以继续走Secure Manager整体性能不会受太大拖累。4. 实操手记从复现到握手成功4.1 确认当前算法路由在动手改配置之前先确认当前HKDF到底是不是被Secure Manager挡下来了。我写了一个很小的测试函数在TLS握手前直接调用PSA接口#include psa/crypto.h void check_hkdf_support(void) { psa_key_derivation_operation_t op PSA_KEY_DERIVATION_OPERATION_INIT; psa_algorithm_t algs[] { PSA_ALG_HKDF_EXTRACT(PSA_ALG_SHA_256), PSA_ALG_HKDF_EXPAND(PSA_ALG_SHA_256), PSA_ALG_HKDF(PSA_ALG_SHA_256) }; for (int i 0; i 3; i) { psa_status_t status psa_key_derivation_setup(op, algs[i]); printf(alg %d: status %d\n, algs[i], (int)status); psa_key_derivation_abort(op); } }实测输出是这样的alg 2305: status -164 alg 2306: status -164 alg 2304: status 0这里的-164就是PSA_ERROR_NOT_SUPPORTED0是PSA_SUCCESS。三种算法的宏值不一定每一位都相同但行为很清楚完整HKDF返回成功单步HKDF全部返回不支持。这就锁定根因了。4.2 修改mbedTLS/PSA配置确认根因后我按方案一操作。第一步打开mbedtls_config.h确保MBEDTLS_PSA_CRYPTO_CONFIG是启用的这样psa/crypto_config.h里的PSA_WANT_ALG_*宏才会真正影响编译。第二步编辑psa/crypto_config.h确认以下宏被定义#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HKDF_EXTRACT 1 #define PSA_WANT_ALG_HKDF_EXPAND 1第三步找到psa_driver_wrappers.h里psa_driver_wrapper_key_derivation_setup()的实现把HKDF单步算法的调用从Secure Manager驱动里分离出来或者在Secure Manager驱动函数入口对PSA_ALG_HKDF_EXTRACT和PSA_ALG_HKDF_EXPAND直接返回PSA_ERROR_NOT_SUPPORTED。后者更省事因为driver wrapper本来就有fallback机制收到NOT_SUPPORTED就会继续走软件实现。如果你不想手改生成代码也可以从CubeMX生成的工程里找到Secure Manager的driver配置宏看看能不能在配置界面里把HKDF算法从Secure Manager的算法集里去掉。但根据我的经验很多版本的CubeMX配置界面并没有细化到单步HKDF的粒度所以手改psa_driver_wrappers.h反而是最直接的办法。改完之后重新编译。注意工程有非安全和安全两个ProjectSecure Manager在安全Project里是预编译的不需要重新编译固件只需要把应用侧和PSA driver包装层重新构建即可。4.3 验证握手成功与性能观察重新编译烧录后我把之前那个check_hkdf_support()函数再跑一遍输出变成了alg 2305: status 0 alg 2306: status 0 alg 2304: status 0三个算法全部返回成功。然后跑完整的TLS 1.3握手这次ClientHello发出去之后服务器端开始正常回ServerHello握手日志一路推进到Application Data阶段最终mbedtls_ssl_handshake返回0。为了确认性能影响我在握手前后各打了一次时间戳测下来软件HKDF参与的整个密钥调度耗时大约是毫秒级别。在250MHz的Cortex-M33上一次TLS 1.3握手增加的延迟几乎可以忽略。真正占时间的依旧是第一次连接的ECDHE密钥交换和证书验证HKDF这几个HMAC操作根本不是瓶颈。我还顺手测了一下持续流量传输确认了后续AES-GCM加解密仍然走Secure Manager硬件加速吞吐没有受到影响。这样整条链路的负担分配是合理的低频、短数据的密钥派生交给软件高频、长数据的流量加密交给Secure Manager硬件。5. 常见问题速查与避坑指南5.1 错误码速查表很多问题最终的报错都是PSA_ERROR_NOT_SUPPORTED但原因五花八门。我整理了一个排查表方便快速定位错误码发生位置常见原因排查方向-164 NOT_SUPPORTEDpsa_key_derivation_setupHKDF单步算法未注册确认Secure Manager算法矩阵改驱动路由-164 NOT_SUPPORTEDpsa_hash_setupSHA算法被裁剪确认crypto_config.h里SHA_WANT宏-135 INVALID_ARGUMENTpsa_key_derivation_input_bytesHKDF步骤顺序不对检查mbedTLS的PSA调用顺序-138 BAD_STATEkey_derivation相关操作符状态被意外重置检查是否有中断或IPC并发问题-147 PROGRAMMER_ERROR任意PSA调用参数或句柄不符合规范检查PSA API调用参数如果错误码不是-164那大概率是另一类问题比如哈希算法没启用、密钥句柄不合法、操作顺序错误等排查思路不要局限在“Secure Manager不支持”上。5.2 几个容易踩的坑第一个坑只在mbedtls_config.h里加MBEDTLS_USE_PSA_CRYPTO指望它把所有密码操作都交给PSA结果TLS 1.3握手还是在HKDF这里挂掉。因为不管有没有这个宏TLS 1.3密钥调度都走PSA真正要改的是驱动路由和算法注册。第二个坑在psa/crypto_config.h里只定义了PSA_WANT_ALG_HKDF没有定义PSA_WANT_ALG_HKDF_EXTRACT和PSA_WANT_ALG_HKDF_EXPAND。这样编译期可能不会报错但运行期PSA发现单步算法没有被编译进去直接返回不支持。改配置时这三个宏要一起检查。第三个坑手动改了psa_driver_wrappers.h但没有重新编译生成driver wrapper依赖的一些自动生成文件导致改动被覆盖。CubeMX生成工程后会在构建时重新生成部分文件所以最好在Makefile或CMakeLists.txt里确认一下psa_driver_wrappers.h是不是自动生成的。如果是你需要在CubeMX里找到对应的配置项或者在生成后统一打补丁而不是直接改源文件。第四个坑升级Secure Manager后没有重新注入或迁移密钥导致旧密钥在安全存储里不可读。这个坑在方案二里特别常见。升级前一定要备份并确认密钥迁移路径。第五个坑在一开始把问题归因到“Secure Manager不支持HKDF”后直接决定所有密码运算都走软件把Secure Manager的AES-GCM也停了导致流量性能断崖式下跌。其实只需要让HKDF单步算法回退软件AES-GCM、ECDH这些高频或高计算量算法继续交给Secure Manager即可。最后再分享一个小心得遇到这种“底层Secure Manager不支持某个算法”的问题最忌一上来就怀疑自己的应用代码也不要急着到处加驱动。先写一个几行代码的PSA算法支持探针把所有相关算法的返回值打出来一张表看下来问题在哪一层就一目了然了。这套排查思路不仅适用HKDF以后遇到Secure Manager里其他算法not supported比如CMAC、ECDH某些曲线或SHA算法不支持时都可以直接复用。
返回列表