1、问题背景
有客户由于某些原因要求使用命令行来生成DA证书链,而使用STM32TrustedPackageCreator是不行的,它是一个GUI的工具。仔细查看其安装目录下的对应的命令行工具STM32TrustedPackageCreator_CLI,查看其对应帮助文档UM2238的第4.4.5节,提到可使用一个叫PSA_ADAC的工具,生成对应证书。我经过多次摸索,终于在命令行下成功生成证书链,于是总结经验,完成此文档,以供有相应需求的客户参考。
下面是UM2238 rev18文档中第4.4.5节的内容:

2. 生成证书链过程
言归正传,下来我们来看看到底如何在命令行下生成证书链的。
这个PSA_ADAC工具位于STM32CubeProgrammer的安装目录下,具体位于:

我们主要是使用它来生成证书链,接下来我将在windows下的命令行来演示。
第1步:将PSA_ADAC工具所在路径加入到环境路径
打开cmd窗口,并运行:
set PATH=%PATH%;C:\ProgramFiles\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin;C:\ProgramFiles\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\Utilities\Windows
并通过echo%PATH%指令来检查当前路径是否已经成功加入环境路径,然后cd到工作目录:

▲ 图1 准备好工作环境
第2步:准备好密钥对
在命令行下,我是用git bash下的openssl来准备的,当然,也可以用其它方法,比如trusted Package Creator本身就可以生成密钥对。

▲ 图2 生成根密钥对
同理,同时生成Level 1密钥对,intermediate密钥对,和leaf密钥对:

▲ 图3 四组密钥对
在工作目录下我们新建一个test目录,用来保存生成的证书。

▲ 图4 准备好test目录用来存放证书
第3步:准备好yml文件,并生成证书cert文件
要使用PSA_ADAC工具生成证书,得先准备好对应的yml文件。下面是生成根证书的yml文件:
root.yml:
name: C:\Users\arthur bu\work_space\LAT\2025\commandline\test\root issuer-key: C:\Users\arthur bu\work_space\LAT\2025\commandline\root.pem subject-key: C:\Users\arthur bu\work_space\LAT\2025\commandline\root_pub.pem role: 1 usage: 1 lifecycle: 0x0000 oem_constraint: 0 soc_class: 0 soc_id: 0 permissions_mask: 0x00000000_00000000_00000000_00005077
这里解释下各项参数含义。
Name:生成证书文件.cert文件所在路径及文件名,上图将在test目录下生成root.cert证书文件。
Issuer-key:对应签发证书的私钥文件。
Subject-key:对应证书内包含的公钥。
Role:对应角色定义:1:root(生成根证书);2:intermediate(生成中间证书);3:leaf(生成叶子证书)。
Usage设置为1,而lifecycle,soc_class,soc_id全部设置为0。
Permissions_mask:对应此证书的操作许可权限。
将其保存为root.yml文件,然后使用PSA_ADAC生成对应的根证书:

▲ 图5 生成根证书root.cert
然后查看下此证书的内容:

▲ 图6 查看证书内容
与此类似,准备好Level1,intermediate,leaf证书对应的yml文件。
level1.yml:
name: C:\Users\arthur bu\work_space\LAT\2025\commandline\test\level1 issuer-key: C:\Users\arthur bu\work_space\LAT\2025\commandline\root.pem subject-key: C:\Users\arthur bu\work_space\LAT\2025\commandline\level1_pub.pem role: 3 usage: 1lifecycle: 0x0000 oem_constraint: 0 soc_class: 0 soc_id: 0 permissions_mask: 0x00000000_00000000_00000000_00005077
intermediate.yml:
name: C:\Users\arthur bu\work_space\LAT\2025\commandline\test\intermediate issuer-key: C:\Users\arthur bu\work_space\LAT\2025\commandline\root.pem subject-key: C:\Users\arthur bu\work_space\LAT\2025\commandline\intermediate_pub.pem role: 2 usage: 1 lifecycle: 0x0000 oem_constraint: 0 soc_class: 0 soc_id: 0 permissions_mask: 0x00000000_00000000_00000000_00005077
leaf.yml:
name: C:\Users\arthur bu\work_space\LAT\2025\commandline\test\leaf issuer-key: C:\Users\arthur bu\work_space\LAT\2025\commandline\intermediate.pem subject-key: C:\Users\arthur bu\work_space\LAT\2025\commandline\leaf_pub.pem role: 3 usage: 1 lifecycle: 0x0000 oem_constraint: 0 soc_class: 0 soc_id: 0 permissions_mask: 0x00000000_00000000_00000000_00005077
如上所示,intermediate证书属于中间证书,所以role=2,而level1证书和leaf证书都是leaf证书,所以role=3。另外,level1证书和intermediate证书都是使用根密钥来签名的,而leaf证书则是使用intermediate密钥来签名。
然后使用PSA_ADAC sign xxx.yml指令来生成对应的证书cert文件:

▲ 图7 生成level1,intermediate,leaf证书cert文件
第4步:将证书从cert格式转化为.b64格式
使用PSA_ADAC chain -o xxx.b64 xxx.cert命令可将cert文件转化为.b64文件:

▲ 图8 将cert文件转化为.b64文件
其中root.b64文件就是最终的根证书,可直接用于DA操作中。而其它的.b64文件由于均是证书链上的一环,必须将根证书包含进去才可用。
第5步:准备好合并脚本,并生成最终的Level1证书和leaf证书
先来说level 1证书:

如上图所示,一级证书是由ROOT根证书颁发,它必须包含根证书才是完整的。它可直接用于DA操作中,本质上是叶子证书。通过第4步骤操作生成的level1.b64它是没有包含根证书的,因此,这里需要手动来将两个证书合并下,这里使用python脚本来写一个合并脚本:
Level1.py:
import base64
def concatenate_b64_files(input_file1, input_file2, output_file):
# Read Base64 content from each input file
with open(input_file1, 'r') as f1, open(input_file2, 'r') as f2:
b64_file1 = f1.read().strip()
b64_file2 = f2.read().strip()
# Decode each Base64 string to binary
binary1 = base64.b64decode(b64_file1)
binary2 = base64.b64decode(b64_file2)
# Concatenate the binary data
concatenated_binary = binary1 + binary2
# Encode the concatenated binary back to Base64
concatenated_b64 = base64.b64encode(concatenated_binary).decode('utf-8')
# Write the result to the output file
with open(output_file, 'w') as out_f:
out_f.write(concatenated_b64)
print(f"Concatenated Base64 data written to {output_file}")
# Example usage:
if __name__ == "__main__":
input_file1 = "root.b64"
input_file2 = "level1.b64"
output_file = "concatenated_level1.b64"
concatenate_b64_files(input_file1, input_file2, output_file)将其保存为 level1.py 文件,并放置在 test 目录下。然后在 cmd 下运行此脚本:

▲ 图10 生成concatenated_level1.b64文件
这个生成的concatenated_level1.b64就是最终的level1证书了,它可直接用于DA相关操作。
这里再说一下,生成这个concatenated_level1.b64的过程其实就是将root.b64文件和level1.b64分别从base64格式转化成binary然后合并,再转化回base64格式。说到底,是root.b64和level1.b64两个文件的合并。
接下来我们再来看leaf证书的合并。Leaf证书是从intermediate证书而来,因此,leaf证书内必须包含intermediate证书内容,而intermediate证书又是从root证书而来,因此,leaf证书总共应该包含root,intermediate,leaf证书三个证书合并:

▲ 图11 leaf证书(最右边)
从上图可知,leaf证书包含intermediate证书,而intermediate证书又包含了root证书。
因此,要生成leaf证书,可以有两种方法:
第一种方法:从root证书生成intermediate证书,再从intermediate证书生成leaf证书对于这种方法,可以模仿level1.py脚本,将root.b64和intermediate.b64合并后生成concatenated_intermediate.b64文件,然后再将concatenated_intermediate.b64文件与leaf.b64文件合并生成concatenated_leaf.b64文件。
另一种方法,就是将root.b64,intermediate.b64.leaf.b64三个文件一起合并,一步到位生成concatenated_leaf.b64文件。
接下来,我们按第二种方法来制作这个python脚本:
Leaf.py:
import base64
def concatenate_b64_files(input_file1, input_file2, input_file3, output_file):
# Read Base64 content from each input file
with open(input_file1, 'r') as f1, open(input_file2, 'r') as f2, open(input_file3, 'r') as f3:
b64_file1 = f1.read().strip()
b64_file2 = f2.read().strip()
b64_file3 = f3.read().strip()
# Decode each Base64 string to binary
binary1 = base64.b64decode(b64_file1)
binary2 = base64.b64decode(b64_file2)
binary3 = base64.b64decode(b64_file3)
# Concatenate the binary data
concatenated_binary = binary1 + binary2 + binary3
# Encode the concatenated binary back to Base64
concatenated_b64 = base64.b64encode(concatenated_binary).decode('utf-8')
# Write the result to the output file
with open(output_file, 'w') as out_f:
out_f.write(concatenated_b64)
print(f"Concatenated Base64 data written to {output_file}")
# Example usage:
if __name__ == "__main__":
input_file1 = "root.b64"
input_file2 = "intermediate.b64"
input_file3 = "leaf.b64"
output_file = "concatenated_leaf.b64"
concatenate_b64_files(input_file1, input_file2, input_file3, output_file)将其保存为leaf.py,然后运行它:

▲ 图12 生成concatenated_leaf.b64文件
这个生成的concatenated_leaf.b64就是生成的最终的leaf证书文件,它可直接用于DA相关操作。
3. 验证生成的证书
由于中间证书是不能直接使用的,因此,我们主要是验证生成的root.b64,concatenated_level1.b64和concatenated_leaf.b64这三个生成的证书文件。由于本文档主要侧重于如何在命令行下生成证书链,因此,验证证书的有效性,我们还是使用STM32CubeProgrammer这个带GUI的工具来验证。
测试硬件平台:NUCLEO-STM32H533RE板
工具:STM32 Trusted Package Creator v2.20,STM32CubeProgrammer v2.20
3.1 生成obk文件
使用TPC生成obk文件:

▲ 图13 使用TPC生成obk文件
3.2 将obk文件写入芯片
使用STM32CubeProgrammer将STM32H533芯片的Trustzone激活:

▲ 图14 激活Trustzone
再切换到Provisioning状态…

▲ 图15 切换到Provisioning状态
当点击Apply时,会弹出来提示是否预配置默认的obk文件,这里我们选择NO,因为我们接下来会写入之前生成的obk文件,而不是这个默认的obk。

▲ 图16 提示是否预配置默认的obk文件
切换到PROV界面,写入之前生成的H533.obk文件:

▲ 图17 写入obk文件然后再断开连接。
3.3验证证书
接下来我们分别使用:
1)根密钥+根证书
2)Level 1密钥+Level 1证书
3.)Leaf密钥+leaf证书
来验证三个证书有有效性。

▲ 图18 选择根密钥+根证书

▲ 图19 根密钥+根证书验证通过
再让芯片重新激活Trustzone,再切换到Provisioning状态,再写入H533.obk文件,然后使用Level1密钥+Level1证书来验证一遍:

▲ 图20 选择Level1密钥+Level1证书

▲ 图21 Level1密钥+Level1证书验证通过
再次让芯片重新激活Trustzone,再切换到Provisioning状态,再写入H533.obk文件,然后使用Leaf密钥+Leaf证书来验证一遍:

▲ 图22 选择leaf密钥+leaf证书

▲ 图23 leaf密钥+leaf证书验证通过
至此,我们完成了根密钥+根证书,level1密钥+Level1证书,以及leaf密钥+leaf证书验证DA回退操作,证实了通过命令行生成的所有证书的有效性。
来源:STM32
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。