RA8P1安全启动与密钥管理:从硬件信任根到安全固件部署
1. 项目概述:为什么RA8P1的安全启动值得深挖
在嵌入式开发领域,尤其是涉及物联网网关、工业控制器或支付终端这类对安全性有严苛要求的场景,固件被篡改或密钥泄露往往是灾难性的。很多开发者初期会依赖软件层面的加密库,但这就像把家门钥匙藏在脚垫下面——攻击者一旦获得物理访问或调试接口,防线便形同虚设。瑞萨电子的RA8P1 MCU提供了一套从硬件底层构建的、立体的安全启动与密钥管理框架,它不仅仅是“有”这个功能,而是将安全理念贯穿于芯片从出厂、开发、量产到失效分析的整个生命周期。
这套机制的核心,在于将密码学信任链与芯片的物理状态深度绑定。它不像一些简单的“使能安全启动位”那样粗暴,而是通过设备生命周期状态、保护等级和认证级别这三个维度的状态机,精细地控制每个阶段能执行什么操作、能访问什么资源。比如,在开发早期,你需要高权限来调试和注入密钥;到了量产阶段,你则要“锁死”芯片,只允许运行经过签名的合法固件。RA8P1通过硬件强制实现了这一流程,任何越权操作都会导致芯片“罢工”。
我最初接触这套机制时,也被其复杂性“劝退”过。但真正理解后才发现,它的设计逻辑非常清晰:一切为了在保证灵活性的前提下,实现最高级别的防物理攻击和防逻辑攻击能力。本次分享,我将结合手册中的核心流程与我在实际项目中的踩坑经验,为你拆解RA8P1安全启动与密钥注入的每一个关键环节,让你不仅能看懂手册,更能知道如何在实际项目中安全、高效地应用它。
2. 安全架构基石:理解设备生命周期、保护等级与认证级别
在动手配置任何安全功能之前,必须透彻理解RA8P1安全体系的三个核心状态:设备生命周期状态、保护等级和认证级别。它们是所有安全策略得以执行的前提和边界。
2.1 设备生命周期状态:芯片的“人生阶段”
你可以把设备生命周期状态想象成芯片从“出生”到“退休”的不可逆历程。它决定了芯片最根本的能力和去向。
- OEM状态:这是芯片的“青春期”,也是我们开发者主要活动的阶段。在此状态下,我们可以进行安全密钥注入、固件编程、调试等所有开发活动。芯片功能完整,但处于“可塑”期。
- LCK_BOOT状态:可以理解为“锁定引导”状态。这是一种特殊的锁定状态,通常用于产线编程后。在此状态下,芯片只能从特定区域启动经过安全验证的固件,其他许多功能(如调试接口、密钥注入)会被禁用,以防止后续篡改。
- RMA_REQ状态:当产品在客户现场出现故障,需要返回原厂进行失效分析时,就需要将芯片置为此状态。这个状态是单向的,一旦进入,芯片就无法再回到正常工作状态,这是为了防止分析过程中的敏感信息泄露。
- RMA_RET状态:这是由瑞萨原厂在完成失效分析后设置的状态。芯片在此状态下可供客户验证分析结果,但通常已不具备再次商用的条件。
关键点:从OEM状态向LCK_BOOT或RMA_REQ状态的转换,通常需要特定的密钥(如RMA_KEY)或认证流程,且不可逆。这意味着,一旦你将产品发货,芯片状态被锁定,即使攻击者获得物理设备,也无法将其回退到可调试、可分析的OEM状态,从而保护了你的核心知识产权和密钥。
2.2 保护等级:控制访问权限的“大门”
保护等级定义了当前环境下,通过串行编程接口(如SWD/JTAG)可以对芯片内存进行何种操作。PL等级从低到高(PL0最高),限制逐渐增强。
- PL2:最低保护等级。在此等级下,串行编程器拥有最大的访问权限,可以读写包括代码MRAM和SiP Flash在内的几乎所有内存区域。这是开发阶段的标准配置,方便我们进行固件下载和调试。
- PL1:中等保护等级。此等级会限制串行编程器对某些安全敏感内存区域的访问。通常用于将芯片交付给第三方进行非核心应用开发时,既能保证其开发功能,又能保护你的核心安全资产(如已注入的密钥、安全启动代码)不被读取或篡改。
- PL0:最高保护等级。在此等级下,串行编程器的访问能力被严格限制,通常只能进行有限的、预先授权的操作。这是产品最终部署时的状态,能有效抵御通过调试接口发起的物理攻击。
一个至关重要的细节:手册中提到,从高PL等级切换到低PL等级(例如从PL1回到PL2)不需要认证。但从低等级切换到高等级(例如从PL2升到PL1)必须使用相应的AL密钥(AL2_KEY或AL1_KEY)进行认证。这个设计非常巧妙:它允许你在需要时“降级”以进行维护或深度调试(当然,这可能需要物理上的触发条件),但绝对禁止任何人未经授权就“升级”保护等级来锁定你的芯片。
2.3 认证级别:执行敏感操作的“钥匙”
认证级别与保护等级协同工作,它定义了执行特定敏感操作(如初始化命令、切换PL等级)所需的密钥凭证。RA8P1主要涉及两个AL密钥:
- AL2_KEY:一个128位的AES密钥。用于在AL2级别进行认证。它通常由安全开发者(掌握核心安全策略的一方)持有和使用。
- AL1_KEY:同样是一个128位的AES密钥。用于在AL1级别进行认证。它可能被分配给非安全开发者或产线工具使用。
认证过程采用挑战-响应机制:
- 芯片生成一个128位的随机数(挑战值)。
- 主机(如编程器)使用AL2_KEY或AL1_KEY,通过AES-128 CMAC算法计算这个挑战值的消息认证码(MAC),作为响应值发回。
- 芯片使用内部存储的对应密钥进行相同的计算,并比对结果。匹配则认证通过。
核心价值:这种机制确保了即使通信信道被监听,攻击者也无法从挑战-响应对中推导出密钥本身,实现了安全的身份认证。
实操心得:务必在项目规划初期就确定好AL2_KEY和AL1_KEY的保管与使用策略。谁持有AL2_KEY?是留在公司安全团队,还是烧录到专用的产线编程工具中?AL1_KEY又分发给谁?一旦密钥被注入并启用,相关的操作权限就交给了密钥持有者。手册特别指出,AL2_KEY可以在AL2级别被永久禁用,AL1_KEY可以在AL2或AL1级别被永久禁用。这是一个重要的安全收尾动作,如果你的生产流程不需要某个密钥,就禁用它,遵循“最小权限原则”。
3. 安全密钥注入详解:从理论到实践
安全启动的信任根,最终要落脚到“密钥”上。如何将你的应用密钥、根证书公钥等安全资产安全地注入到芯片中,是构建整个信任链的第一步。RA8P1的密钥注入机制设计精良,确保了密钥在传输和注入过程中全程保密。
3.1 密钥注入的核心流程与原理
整个过程的核心思想是“密钥从不以明文形式出现在不安全的环境中”。它依赖于一个由瑞萨提供的用户工厂编程密钥(UFPK)作为中介。流程如下图所示,我们可以将其分为准备阶段和注入阶段:
[用户端安全环境] [瑞萨密钥封装服务] [生产车间/用户端] UFPK (明文) ---------> 密钥封装服务 ---------> W-UFPK (密文) | | | | v v 用户密钥 (明文) --(用UFPK加密)--> 被包裹的用户密钥 (密文) ----> [通过Boot命令发送至MCU] | v MCU内部:用HUK解包并存储步骤拆解:
创建UFPK:你在一个安全的环境中(如公司的加密机或离线安全工作站)随机生成一个256位的AES密钥,这就是UFPK。它是整个密钥注入流程的“主密钥”,必须绝对保密。
获取W-UFPK:将UFPK提交给瑞萨提供的“密钥封装服务”。该服务会使用一个只有瑞萨和你的芯片知道的、基于芯片唯一ID的密钥,对你的UFPK进行加密,生成“被包裹的UFPK”(W-UFPK)。这个过程通常通过瑞萨的安全密钥管理工具(Security Key Management Tool)在线完成。W-UFPK可以公开分发,因为它只能被对应的目标芯片解密。
包裹用户密钥:在安全环境中,使用你持有的UFPK,通过AES等算法加密你的实际应用密钥(如RSA私钥、AES密钥、OEM_ROOT_PK等),生成“被包裹的用户密钥”。
注入密钥:在产线或开发环境中,将W-UFPK和被包裹的用户密钥通过Boot Firmware命令发送给RA8P1 MCU。芯片内部会进行如下操作: a. 使用其硬件唯一密钥(HUK)解密W-UFPK,恢复出UFPK。 b. 使用恢复出的UFPK解密被包裹的用户密钥,得到明文用户密钥。 c. 立即用芯片自身的另一个安全密钥(或HUK派生密钥)重新加密该用户密钥,并将其存储到指定的非易失性存储器中(DLM密钥存于未映射的Flash,应用密钥存于指定地址)。
这样设计的好处:
- 端到端安全:你的明文UFPK和用户密钥从未离开过你的安全环境。
- 产线安全:在产线上传输和处理的只有密文(W-UFPK和被包裹的用户密钥),即使产线环境不安全,也不会泄露密钥。
- 芯片唯一性:W-UFPK与具体芯片绑定,即使被截获,也无法用于其他芯片。
3.2 可注入的密钥类型与选择
RA8P1支持注入的密钥类型非常丰富,覆盖了各种安全应用场景:
| 密钥类别 | 具体算法与密钥类型 | 主要用途 |
|---|---|---|
| DLM/AL过渡 | RMA_KEY, AL2_KEY, AL1_KEY | 控制设备生命周期状态切换、保护等级切换的认证。 |
| 对称加密 | AES-128/192/256, AES-XTS-128/256 | 用于固件加密、数据存储加密、安全通信。 |
| 流加密 | ChaCha20-Poly1305 | 高效的高速通信加密与认证。 |
| 非对称加密 | RSA-1024/2048/3072/4096 (公私钥对), RSA-2048 (TLS公钥) | 数字签名、密钥交换。TLS公钥用于预置证书。 |
| 椭圆曲线 | ECC P-192/224/256/384/521, P256r1/P384r1/P512r1/secp256k1 (公私钥对) | ECDSA签名、ECDH密钥协商,比RSA效率更高。 |
| 消息认证 | HMAC-SHA224/256/384/512等 | 生成消息认证码,验证数据完整性。 |
| 爱德华兹曲线 | Ed25519 (公私钥对) | 一种高性能的数字签名算法。 |
| 安全启动 | 最多4个OEM_ROOT_PK (公钥) | 作为安全启动信任根,验证OEM_BL签名。 |
| 其他 | Key-Update Key | 用于后续密钥更新。 |
选型建议:
- 安全启动根密钥:推荐使用ECC P-256 (secp256r1)。它在安全强度和计算效率上取得了很好的平衡,是当前行业的主流选择。
- 应用数据加密:根据性能需求选择AES-128或AES-256。对于Flash加密,XTS模式是标准选择。
- 固件签名:如果OEM_BL由你签名,则需要注入对应的OEM_BL_PK(公钥)。其对应的私钥(OEM_BL_SK)必须在你手中安全保管,用于签名。
- 调试认证:AL2_KEY和AL1_KEY通常使用AES-128,兼顾安全性和Boot Firmware命令的响应速度。
注意事项:密钥注入是一次性的,或者需要专门的密钥更新流程。在注入前,务必在安全环境中备份好所有密钥材料,特别是UFPK和各类私钥。一旦丢失,可能导致对应的安全功能无法使用或设备变砖。
4. 安全启动机制深度解析:构建不可篡改的引导链
安全启动的目标是确保MCU每次上电后执行的第一个代码(OEM_BL)是真实且未被篡改的。RA8P1通过“两级证书验证”和“芯片唯一度量值”来实现这个目标,构建了一个从硬件信任根到应用代码的完整信任链。
4.1 验证流程与证书结构
整个验证过程涉及两种证书:密钥证书和代码证书。它们的关系和验证流程,是理解安全启动的关键。
1. 信任根注入: 首先,你需要将最多4个OEM_ROOT_PK(公钥)通过安全密钥注入流程,写入芯片的受保护存储区。这些公钥的SHA-256哈希值被芯片保存,作为信任的起点。对应的私钥OEM_ROOT_SK由你绝对安全地保管。
2. 创建与签名OEM_BL: 你开发OEM引导加载程序(OEM_BL),并为其生成一对ECC密钥(OEM_BL_SK/OEM_BL_PK)。然后,你需要创建两个证书:
- 密钥证书:内容包含OEM_BL_PK本身,以及使用OEM_ROOT_SK对该证书内容(含OEM_BL_PK)的ECDSA签名。这个证书证明了“这个OEM_BL_PK是经过我(信任根持有者)认证的”。
- 代码证书:内容包含OEM_BL的CRC32校验值、OEM_BL_PK的哈希值(Signer ID),以及使用OEM_BL_SK对整个代码证书和OEM_BL二进制数据联合计算的ECDSA签名。这个证书证明了“这段OEM_BL代码是由OEM_BL_SK的持有者发布的,且内容完整”。
3. 编程时的验证(图52.11流程): 当你通过串行编程模式将OEM_BL、代码证书和密钥证书写入芯片时,Boot Firmware会执行以下验证:
- 验证密钥证书:使用芯片内预置的OEM_ROOT_PK(从存储的哈希值匹配)验证密钥证书的签名。通过,则证明OEM_BL_PK可信。
- 验证代码证书:使用刚刚验证通过的OEM_BL_PK验证代码证书的签名。通过,则证明OEM_BL来自合法的发布者。
- 验证代码完整性:计算OEM_BL的CRC32,与代码证书中的
EXPECTED_CRC字段比对。通过,则证明OEM_BL数据在传输和存储过程中未被破坏。 - 生成并存储OEM_BL_digest:以上所有验证通过后,Boot Firmware会使用一个从芯片HUK派生的密钥,计算OEM_BL和代码证书的HMAC-SHA256值,即
OEM_BL_digest,并将其存储到MRAM中。这个值是芯片唯一的,即使相同的OEM_BL和证书写入另一个芯片,生成的digest也不同。
4. 运行时验证(图52.12流程): 芯片上电后,固化的第一级引导加载程序(FSBL)会:
- 根据配置,读取存储的
OEM_BL_digest。 - 实时计算当前OEM_BL和代码证书的HMAC值。
- 将计算结果与存储的
OEM_BL_digest进行比较。 - 如果匹配,则跳转到OEM_BL执行;如果不匹配,则触发安全错误(如拉高某个GPIO并进入CPU睡眠模式)。
这种设计的精妙之处:
- 双重验证:既验证了发布者身份(通过证书签名),又验证了代码完整性(通过CRC和运行时HMAC)。
- 信任链传递:信任从OEM_ROOT_PK传递到OEM_BL_PK,再传递到OEM_BL代码本身。
- 防克隆:
OEM_BL_digest与芯片唯一绑定,即使攻击者复制了完整的Flash镜像到另一颗芯片,也会因为HUK不同而导致HMAC校验失败。 - 防回滚:代码证书中包含镜像版本号。FSBL或OEM_BL可以检查此版本号,防止被替换成旧版本的有漏洞固件。
4.2 证书格式与寄存器配置实操
要让这套机制跑起来,你必须严格按照手册中的格式准备证书数据。这里以代码证书为例,说明关键字段:
// 代码证书头部示例 (参考Table 52.10) typedef struct { uint32_t magic; // 必须为 0x636F6463 ('codc'的十六进制) uint32_t manifest_version; // 必须为 0x00010000 uint32_t flags; // 必须为 0x00000000 uint32_t load_addr; // 必须为 0x00000000 uint32_t dest_addr; // 必须为 0x00000000 uint32_t image_size; // OEM_BL的大小(字节),必须是16的倍数,最小64字节 uint32_t image_version; // OEM_BL的版本号 (1-64) uint32_t build_number; // 必须为 0x00000000 uint32_t tlv_length; // 后续TLV字段的总长度 // 后面跟着 TLV_ECCPUBKEY, TLV_EXPECTED_CRC, TLV_SIGNER_ID, TLV_EXPECTED_SIG 等TLV结构 } code_certificate_header_t;关键配置步骤:
- 生成密钥对和证书:使用OpenSSL或类似的密码学库,在安全环境中生成ECC P-256密钥对,并按照上述格式生成密钥证书和代码证书,并计算签名。
- 编程证书和OEM_BL:通过瑞萨的编程工具(如Renesas Flash Programmer)或自定义的Boot Firmware命令,将密钥证书、代码证书和OEM_BL二进制文件写入芯片的指定MRAM区域。
- 配置证书地址寄存器:这是最容易出错的一步。证书在MRAM中的起始地址必须写入
SACC0n或SACC1n寄存器(OTP类型)。BTFLG位决定从哪个启动区域启动,从而决定FSBL读取SACC0n还是SACC1n。- 这些寄存器有多个(n=0~3),FSBL会从n值最大的寄存器开始读,直到找到一个非全1的值作为证书地址。
- 最佳实践:从n最小的寄存器开始使用。例如,第一次编程时使用
SACC00。如果需要更新证书,则编程到新的MRAM地址,然后将新地址写入SACC01。这样,FSBL会先读SACC03(全1),再读SACC02(全1),最后读到SACC01中的新地址,实现了证书的更新,同时保留了回退到SACC00旧地址的可能性(如果需要)。
- 配置FSBL控制寄存器:通过
FSBLCTRL1寄存器选择安全启动模式(HMAC验证)或CRC启动模式。通常选择安全启动模式以获得更强的安全性。还可以配置测量报告功能,将启动度量值存入指定SRAM地址,供后续可信应用验证。
踩坑记录:
- 镜像大小对齐:
image_size字段必须是16的倍数。如果你的OEM_BL编译后是12345字节,你需要将其填充到12352字节(12345向上对齐到16的倍数),并填写填充后的大小。 - OTP寄存器一次性写入:
SACC0n/SACC1n是OTP(一次可编程)寄存器。一旦将某个地址写入,就无法再修改该寄存器位。规划证书存储地址和更新策略时务必谨慎。 - 测量报告与ECC:如果使能了测量报告功能,在读取SRAM中的报告前,必须通过设置
SRAMCRn.ECCMOD[1:0] = 00b来禁用该SRAM块的ECC功能,否则读出的数据会是错误的。
5. 安全工厂编程:在不安全产线部署安全固件
对于大批量生产,将包含核心算法的明文固件交给代工厂或产线是一个巨大的风险。RA8P1的安全工厂编程功能就是为了解决这个问题而生。它允许你将固件加密后,在完全不接触解密密钥的普通产线环境进行烧录。
5.1 安全工厂编程流程
该流程是密钥注入流程的扩展应用,核心思想是对固件镜像本身进行加密。
准备阶段(客户安全区): a. 生成一个256位的镜像加密密钥(Image Encryption Key)。 b. 使用该密钥和AES-128-CCM算法,加密你的完整固件镜像,生成加密镜像。 c. 使用你的UFPK,通过安全密钥管理工具加密(包裹)这个镜像加密密钥。 d. 通过瑞萨服务获取你的UFPK对应的W-UFPK。
编程阶段(工厂产线): a. 将加密的固件镜像、被包裹的镜像加密密钥、W-UFPK三个文件提供给产线编程设备。 b. 产线设备通过串行编程接口,向RA8P1芯片发送一个特殊的Boot Firmware命令,并将上述三个数据块传输给芯片。 c. 芯片内部: - 使用其HUK解密W-UFPK,得到UFPK。 - 使用UFPK解密被包裹的镜像加密密钥,得到明文镜像加密密钥。 - 使用镜像加密密钥解密固件镜像。 - 将解密后的明文固件编程到Flash/MRAM中。 d.整个过程在芯片内部完成,镜像加密密钥和明文固件从未在芯片外部出现。
5.2 命令使用要点与限制
这个强大的Boot Firmware命令有一些严格的先决条件和限制,必须遵守:
- 芯片状态:只能在设备生命周期为OEM状态下执行。
- 保护等级变化:命令执行会改变PL。初始PL必须是PL2,最终PL必须变为PL0。这意味着该命令通常是你对芯片进行的最后一次编程操作,之后芯片将进入最高保护等级。
- 密钥注入:如果DLM状态保持在OEM,则必须注入AL2_KEY。AL1_KEY可选注入。如果要将MCU转换到LCK_BOOT状态,则不能注入AL密钥。
- 密钥一致性:AL密钥(如果注入)和镜像加密密钥必须使用同一个UFPK进行包裹。
- 内存擦除:该命令在执行加密固件编程前,会擦除所有代码MRAM区域(除选项设置存储器外)。如果存在任何被永久锁定的存储块,此命令无法执行。
- 启动区域选择:执行此命令时,相关启动区域选择寄存器的设置必须正确,例如
SAS.BTFLG = 1。 - 选项设置内存:加密固件镜像中必须包含所有选项设置内存的值,即使某些值与默认值相同。但如果某些区域被写保护,则镜像中不应包含对这些区域的写数据,否则命令会报错终止。
实操建议:
- 流程整合:将安全工厂编程作为产品量产烧录的最终步骤。在此步骤之前,可以预先注入AL2_KEY等密钥。
- 镜像制作:开发一个可靠的脚本或工具,用于自动完成固件加密、密钥包裹和生成最终烧录包的工作,避免人工操作错误。
- 全面测试:务必在试产阶段,完整测试从加密镜像生成到烧录、上电启动的全流程。验证芯片在PL0状态下能否正常启动并运行加密烧录的固件。
6. OEM_BL更新与故障恢复机制
产品发布后,难免需要固件升级。RA8P1的安全启动机制也考虑了OEM_BL本身的安全更新需求。
6.1 安全更新流程
OEM_BL的更新不是简单地覆盖旧镜像,而是一个精心设计的、具备原子性和回滚能力的流程(见图52.15)。其核心是利用芯片的双启动区域和状态标志位。
- 编程新OEM_BL:将新的、已签名的OEM_BL及其代码证书编程到非当前启动区域(如果当前从Area 0启动,则编程到Area 1)。
- 清除状态标志:在MRAM中清除“更新完成标志”(UCF)和“增量完成标志”(ICF)。
- 验证新OEM_BL:在芯片内,运行与初始验证(图52.11)相同的流程,验证新OEM_BL的完整性和真实性。验证通过后,生成新的
OEM_BL_digest。 - 编程新证书和Digest:将新的代码证书和生成的
OEM_BL_digest编程到新启动区域的对应位置。 - 设置UCF标志:将UCF置1,表示新OEM_BL及其证书已成功编程并验证。
- 更新反回滚计数器:更新
ARC_OEMBL寄存器(如果使用),防止降级到旧的有漏洞版本。 - 设置ICF标志:将ICF置1,表示反回滚计数器已更新。
- 切换启动地址:将
SACC0n或SACC1n寄存器设置为新代码证书的地址。 - 切换启动区域:设置
BTFLG位,指向新的启动区域。 - 复位MCU:复位后,FSBL将从新区域启动,验证并运行新的OEM_BL。
6.2 防掉电故障与恢复策略
更新过程中若发生意外断电,系统可能处于不一致状态。RA8P1建议在代码MRAM中实现UCF和ICF标志位来应对此问题。
恢复逻辑如下:
- 上电后,FSBL执行,跳转到OEM_BL(可能是旧的,也可能是新的,取决于
BTFLG和SACC0n/1n)。 - OEM_BL首先检查UCF和ICF。
- 场景1:UCF != 1:说明新OEM_BL编程未完成。恢复程序应擦除未完成的新镜像区域,然后从流程第1步重新开始。
- 场景2:UCF == 1 但 ICF != 1:说明新OEM_BL已就绪,但反回滚计数器未更新。恢复程序应检查
ARC_OEMBL是否等于新版本号。如果不是,则从流程第6步(更新ARC_OEMBL)开始恢复;如果是,则直接设置ICF=1,然后从流程第8步开始恢复。 - 场景3:UCF == 1 且 ICF == 1:检查
ARC_OEMBL版本和当前启动区域。如果版本匹配且启动区域已切换,则更新成功。如果版本匹配但启动区域未切换,则从流程第8步开始恢复。
关键点:旧的OEM_BL和新的OEM_BL都必须包含这套更新错误判定与恢复的程序。这样,无论更新过程在哪个阶段中断,下次启动时总有一个可用的OEM_BL能执行恢复逻辑,避免设备“变砖”。
7. 外设安全属性配置:构建安全域隔离
安全启动保证了代码的完整性,但一个安全的系统还需要在运行时限制非安全代码对敏感资源的访问。RA8P1通过外设安全属性寄存器(PSARx)来实现外设级别的硬件隔离。
7.1 寄存器功能详解
PSARB、PSARC、PSARD、PSARE等寄存器,每一位控制着一个特定外设或模块的安全属性。将其设为0,表示该外设只能被处于安全状态下的CPU(即运行在TrustZone安全世界状态的代码)访问;设为1,则表示该外设也可以被非安全状态的代码访问。
例如(来自手册):
PSARB9:控制I2C0总线接口。如果您的安全固件需要使用I2C0与一个安全元件通信,则应将其设为0(Secure)。这样,运行在非安全世界的应用程序就无法直接操控该I2C外设,防止其窃取或篡改通信数据。PSARE2:控制独立看门狗定时器(IWDT)。通常,系统看门狗应由安全世界代码管理,以确保即使非安全应用崩溃,安全核心也能复位系统。因此,IWDT应配置为Secure。
MSSAR寄存器则专门控制内存模块(如SRAM0-3, NPU)的时钟停止功能的安全属性。这可以防止非安全代码通过停止安全代码所用内存的时钟来发起拒绝服务攻击。
7.2 配置策略与实践
- 最小权限原则:默认将所有外设配置为
Secure。仅当非安全世界的应用程序确有必要时,才将其需要的外设改为Non-secure。 - 早期配置:这些寄存器通常在上电初始化阶段,由最早运行的安全代码(如OEM_BL或安全区的初始化代码)进行配置。一旦配置,在后续运行中不应随意更改。
- 结合TrustZone:RA8P1支持Arm TrustZone技术。PSAR寄存器的配置与TrustZone的SAU/IDAU配置协同工作,共同定义系统的安全内存和外设地图。非安全代码尝试访问Secure外设,不仅会被PSAR寄存器阻挡,还会触发TrustZone的安全异常。
- 审计与验证:在系统设计文档中,明确记录每个外设的安全属性配置及其理由。在代码中,可以将这些配置集中在一个头文件或初始化函数中,便于审查和维护。
通过合理配置PSAR寄存器,你可以在硬件层面将系统划分为安全域和非安全域,有效隔离关键外设,即使非安全应用被攻破,攻击者也难以危及到系统的核心安全功能,从而实现了深度的防御。
