安全启动 ============ 本章节主要介绍基于 WQ SDK 的安全启动流程,安全固件的构建方式和烧录方式。 概述 ^^^^^^^^^^^^ 芯片安全启动(Secure Boot)是一种确保设备仅运行经过授权和可信代码的安全机制,其主要目标是防止未经授权的软件加载,保护设备免受潜在的安全威胁。 本文档的目标是帮助开发人员理解和实现芯片的安全启动功能。通过介绍相关概念、技术细节和实现步骤,开发人员可以正确配置和使用安全启动功能,确保设备的启动过程安全可靠。 本文档的结构如下: - 背景与需求:解释安全启动的目标和实现意义。 - 技术概览:描述安全启动的关键概念和常见实现方案。 - 安全启动流程描述:详细描述硬件初始化、引导加载程序阶段和操作系统加载等关键步骤。 - 流程实现细节:提供实现安全启动功能所需的硬件和软件支持。 背景与需求 ^^^^^^^^^^^^ - 安全启动的目标 - 确保设备仅运行经过认证和可信任的软件。 - 防止恶意代码或未经授权的软件加载。 - 提供设备启动过程的完整性和保密性验证。 - 建立可信的设备运行环境,增强系统安全性。 技术概览 ^^^^^^^^^^^^ - 摘要算法:用于生成数据的唯一指纹,确保数据的完整性。当前使用的是 SHA-256 算法,其具有较高的安全性和广泛的应用。 SHA-256 的哈希碰撞概率极低,输出为 256 位的固定长度散列值,其碰撞概率在理想条件下为 ,这意味着尝试产生两个相同散列值的成功率几乎为零。这种高安全性使 SHA-256 在关键安全应用中广泛采用,确保数据在传输和存储过程中的完整性和防篡改能力。 - RSA: 一种广泛应用的非对称加密算法,使用公钥和私钥对进行数据加密和解密。其主要应用包括数字签名、密钥交换和数据加密。数字签名用于验证数据的来源和完整性,而密钥交换则用于在不安全的网络环境中安全地传输加密密钥。RSA-2048 和 RSA-3072 是常用的密钥长度,提供较高的安全性,适用于嵌入式设备和安全启动过程中的关键数据保护。 - OTP(一次性可编程存储器):OTP存储器的一个重要特点是数据一旦写入后无法再更改。与可擦写存储器(如 EEPROM 或 Flash)不同, OTP 存储器不支持擦除或修改操作,在嵌入式系统中, OTP 可以用于存储加密密钥或其他身份验证信息。由于它只能编程一次,这样的数据无法被修改或篡改,从而增加了安全性。 安全启动流程 ^^^^^^^^^^^^ 1. 一级引导 (由ROM引导至SBL) a. 验证公钥,读取 OTP 中存储的公钥的 hash 值,与需要被引导的固件所携带的公钥计算出的hash值进行比较,如果相同,则认为公钥合法。 b. 验证固件,使用公钥解密公钥的签名,与固件的hash值进行对比,如果相同则认为固件合法,加载并运行固件。 2. 二级引导 (由SBL启动APP) a. 验证公钥,与一级验证相同的方式验证app携带的公钥的合法性。 b. 验证app,与一级引导相同的方式验证app固件的合法性,若验证通过则加载并启动。 3. 链式启动 (由app加载其他固件) a. 链式启动中app再次加载其他固件时,可由app自行添加相应的验证方式,或直接使用与一级/二级引导相同的验证方式。 b. 链式启动中的每一级启动都应验证固件的合法性。 .. mermaid:: :align: center :caption: 安全启动流程图 graph TB subgraph 安全启动流程 direction TB subgraph 存储区域 subgraph OTP/EFUSE style OTP/EFUSE fill:#f99 pubhash[公钥 hash值] end subgraph Flash subgraph SBL style SBL fill:#88F sblbin[SBL固件] pubkey[公钥] sblsign[签名] end end end subgraph 签名服务器 style 签名服务器 fill:#cce prikey[私钥] sign[[对固件进行签名]] pubkey <--公私钥对--> prikey prikey --> sign sblbin --> sign sign --> sblsign end A[开始] --> B[计算公钥HASH值] pubkey --> B pubhash --> C B --> C{与OTP公钥哈希值比对} C -->|不相等| G[公钥非法,中止流程] style G fill:#C22 C -->|相等| D[计算固件哈希值A] style D fill:#282 sblbin --> D D --> E[解密签名得到哈希值B] pubkey --> E sblsign --> E E --> F{哈希值A和B比对} F -->|相同| H[验签成功,正常启动] style H fill:#282 F -->|不同| I[验签失败] style I fill:#C22 end 安全固件的配置和构建 ^^^^^^^^^^^^^^^^^^^^ 1. 配置 - 在项目目录使用 :code:`scons --menuconfig` 打开配置 - 开启 **enable build secure package** 选项 - 在 **Select signature type** 中选择要使用的签名算法 - 按需开启各个固件的签名 **Enable ?CORE image secure** - 在 **Command to sign the image** 中配置在编译机器中可以运行的用来对固件进行签名的命令 [#]_ 2. 构建 - 执行常规编译命令 :code:`scons` 3. 安全固件构建流程 .. mermaid:: :align: center :caption: 安全启动流程图 flowchart TD subgraph 编译服务器 style 编译服务器 fill:#FFFACD build[编译] pack[打包] burn[烧录] firmware([固件.wpk]) build --> binfile1([固件1.bin]) build --> binfile2([固件2.bin]) build --> binfile3([固件3.bin]) binfile1 --> pack binfile2 --> pack binfile3 --> pack subgraph 签名脚本 style 签名脚本 fill:#87cefA upload[上传] download[下载] upload --> sign signfile --> download subgraph 签名服务器 style 签名服务器 fill:#FF69B4 sign[签名] prikey[私钥] prikey --> sign sign --> signfile([签名文件]) end end binfile1 --> upload binfile2 --> upload binfile3 --> upload download --> signfilea1([签名1.sign]) download --> signfilea2([签名2.sign]) download --> signfilea3([签名3.sign]) download --> pubkey[公钥] signfilea1 --> pack signfilea2 --> pack signfilea3 --> pack pubkey --> pack pack --> firmware --> burn end .. [#] 可以是在linux/windows下命令行执行的任意命令、shell/bat脚本、python脚本等, 脚本可以在本地进行签名, 但是更常见的方式是联系云端将固件文件上传并获取云端签名后的文件保存至指定位置。命令应该接受三个参数: 1. 需要签名的固件的bin文件 2. 生成的签名文件保存的路径 3. 对应公钥的保存路径 安全固件的下载和安全启动的开启 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1. 初次烧录 - 确保使用工具加载了安全固件包 - 勾选 **开启安全启动** 选项 [#]_ - 勾选 **开启安全下载** 选项 [#]_ - 点击开始烧录 2. 已开启了安全启动的芯片,后续下载 - 使用工具加载正确的固件包 [#]_ - 取消勾选 **开启安全启动** 选项 - 取消勾选 **开启安全下载** 选项 - 点击开始烧录 3. 使用安全固件包,但不使用开启和使用安全启动 [#]_ - 使用工具加载固件包 - 点击开始烧录 .. [#] 此选项会向OTP中写入公钥的摘要信息,后续仅授权固件可以在此芯片运行 .. [#] 此选项会向OTP中写入公钥的摘要信息,后续仅授权的固件可以进行烧录 .. [#] 确保此固件包与芯片内部保存的加密信息相符 .. [#] 仅支持在未开启安全启动的芯片上使用此方式