0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

深入解析U-Boot FIT镜像签名验证:image-sig.c核心实现

jf_44130326 来源:Linux1024 作者:Linux1024 2026-02-25 11:06 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

嵌入式系统安全启动体系中,U-Boot的FIT(Flattened Image Tree)镜像签名验证是一道关键防线——它能确保启动镜像未被篡改、来源可信,而image-sig.c正是实现这一核心能力的核心文件。本文将从数据结构、函数逻辑、数据流程三个维度,拆解image-sig.c的实现细节,带你吃透U-Boot镜像验签的底层逻辑。

一、背景:为什么需要FIT镜像签名验证?

传统的U-Boot镜像格式(如uImage)功能单一,难以满足复杂场景下的安全需求。FIT镜像以设备树(DTB)为载体,支持多镜像打包、版本管理、签名验证等能力,而签名验证则是安全启动的核心:

•防止镜像被恶意篡改,保障启动流程可信;

•支持多种哈希/加密算法,适配不同安全等级需求;

•区分“必需”和“可选”签名,灵活适配不同场景。

image-sig.c的核心职责就是:管理验签所需的算法、解析FIT镜像的签名节点、完成哈希校验与签名验证,是FIT镜像安全的守护者。

二、核心数据结构:算法与验签信息的载体

在分析函数前,先理解几个核心结构体——它们是整个验签逻辑的“数据骨架”。

1.哈希算法结构体checksum_algo

structchecksum_algo { constchar*name;     // 算法名(sha1/sha256) intchecksum_len;     // 哈希值长度 intder_len;       // DER前缀长度 constuint8_t *der_prefix;// DER编码前缀(适配ASN.1规范)  EVP_MD *(*calculate_sign)();// 签名用哈希计算函数 int(*calculate)();    // 通用哈希计算函数};

作用:封装SHA1/SHA256两种哈希算法的核心属性,关联哈希计算的具体实现,是后续生成/验证哈希值的基础。

2.加密算法结构体crypto_algo

structcrypto_algo { constchar*name;     // 算法名(rsa2048/rsa4096) intkey_len;       // 密钥长度(字节) int(*sign)();      // 签名函数 int(*add_verify_data)(); // 添加验证数据 int(*verify)();     // 验签函数};

作用:封装RSA2048/RSA4096两种非对称加密算法,关联签名/验签的核心逻辑,是验签的核心执行者。

3.填充算法结构体padding_algo

structpadding_algo { constchar*name;     // 填充方式(pkcs-1.5/pss) int(*verify)();     // 填充验证函数};

作用:适配不同的RSA填充规范(PKCS1.5是默认,PSS更安全),通过配置开关CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT控制是否启用PSS。

4.验签上下文image_sign_info

这个结构体未在代码中显式定义,但从函数参数能看出其核心作用:承载一次验签的所有上下文信息,包括:

•算法指针(哈希/加密/填充);

•FIT镜像指针、节点偏移量;

•密钥名、验证所需的FDT blob;

•必需的密钥节点索引

三、核心函数解析:从算法查找到验签落地

image-sig.c的函数可分为三大类:算法查找、辅助工具、验签核心,我们逐一拆解。

1.算法查找函数:匹配字符串与算法实现

验签的第一步是“识别算法”——从FIT镜像节点的属性字符串(如sha256,rsa2048)中,匹配到对应的算法结构体。

(1)image_get_checksum_algo:查找哈希算法

structchecksum_algo *image_get_checksum_algo(constchar*full_name);

•输入:完整算法名(如sha256,rsa2048);

•逻辑:遍历checksum_algos数组,匹配前缀(如sha256)且后续字符为逗号,返回对应的哈希算法结构体;

•输出:匹配到的checksum_algo指针(NULL表示未匹配)。

(2)image_get_crypto_algo:查找加密算法

structcrypto_algo *image_get_crypto_algo(constchar*full_name);

•输入:完整算法名(如sha256,rsa2048);

•逻辑:先截取逗号后的字符串(如rsa2048),再遍历crypto_algos数组匹配算法名;

•输出:匹配到的crypto_algo指针(NULL表示未匹配)。

(3)image_get_padding_algo:查找填充算法

structpadding_algo *image_get_padding_algo(constchar*name);

•输入:填充算法名(如pkcs-1.5);

•逻辑:遍历padding_algos数组匹配名称;

•输出:匹配到的padding_algo指针(NULL表示未匹配)。

2.辅助工具函数:FDT区域到镜像区域的转换

structimage_region *fit_region_make_list(constvoid*fit, structfdt_region *fdt_regions,intcount, structimage_region *region);

•核心作用:将FDT(设备树)格式的区域信息,转换为U-Boot镜像验签所需的image_region结构体;

•关键细节:

a.非SPL构建:自动调用calloc分配内存(SPL为节省代码量,要求调用者提前分配);

b.填充image_region的data(镜像数据指针)和size(数据长度);

c.输出调试信息(偏移量、大小),方便调试哈希区域。

3.验签核心函数:从初始化到最终验证

验签逻辑是层层封装的,从“单节点验签”到“批量验签”,再到“配置节点验签”,形成完整的验证链路。

(1)fit_image_setup_verify:验签前的初始化

staticintfit_image_setup_verify(structimage_sign_info *info, constvoid*fit,intnoffset,intrequired_keynode, char**err_msgp);

•核心职责:为验签做准备,填充image_sign_info上下文;

•执行流程:

a.从FIT节点获取哈希算法名、填充方式(默认PKCS1.5);

b.初始化info结构体:密钥名、FIT镜像指针、节点偏移量;

c.调用算法查找函数,绑定哈希/加密/填充算法;

d.校验算法是否有效,无效则返回错误信息。

(2)fit_image_check_sig:单个签名节点的验签

intfit_image_check_sig(constvoid*fit,intnoffset,constvoid*data, size_tsize,intrequired_keynode,char**err_msgp);

•核心职责:验证单个签名节点的有效性;

•执行流程:

a.调用fit_image_setup_verify初始化上下文;

b.从FIT节点读取预计算的哈希值(fit_value);

c.构造镜像区域(image_region),包含待验证数据的指针和长度;

d.调用加密算法的verify函数,验证哈希值与签名是否匹配;

e.返回验证结果(0成功,-1失败)。

(3)fit_image_verify_sig:遍历镜像节点的签名子节点

staticintfit_image_verify_sig(constvoid*fit,intimage_noffset, constchar*data,size_tsize,constvoid*sig_blob, intsig_offset);

•核心职责:遍历镜像节点下的所有签名子节点(以sig-开头),批量验签;

•执行流程:

a.遍历FIT镜像节点的所有子节点,筛选出签名节点;

b.对每个签名节点调用fit_image_check_sig验签;

c.只要有一个签名验证通过,标记verified=1并返回成功;

d.若遍历出错(如FDT结构损坏),返回错误信息。

(4)fit_image_verify_required_sigs:验证“必需”的签名

intfit_image_verify_required_sigs(constvoid*fit,intimage_noffset, constchar*data,size_tsize,constvoid*sig_blob, int*no_sigsp);

•核心职责:只验证标记为“required=image”的签名节点(这类签名必须通过,否则启动失败);

•执行流程:

a.查找签名blob中的sig节点;

b.遍历子节点,筛选出required="image"的节点;

c.调用fit_image_verify_sig验证,失败则直接返回错误;

d.统计验证通过的数量,更新no_sigsp(标记是否有签名)。

(5)fit_config_check_sig:配置节点的验签(进阶)

intfit_config_check_sig(constvoid*fit,intnoffset,intrequired_keynode, char**err_msgp);

•核心场景:验证FIT镜像的配置节点(而非镜像数据),防止配置被篡改;

•特殊逻辑:

a.解析hashed-nodes属性:获取需要哈希的子节点列表;

b.校验节点数量(不超过IMAGE_MAX_HASHED_NODES=100),防止栈溢出;

c.调用fdt_find_regions:查找所有需要哈希的FDT区域;

d.处理hashed-strings属性:将字符串区域加入哈希列表;

e.转换为image_region后调用验签函数,完成配置验证;

f.适配硬件加密:如RK的SPL+Secure OTP,验签后烧录密钥哈希。

(6)配置节点验签的封装函数

fit_config_verify_sig/fit_config_verify_required_sigs/fit_config_verify是对fit_config_check_sig的封装,逻辑与镜像节点验签类似:遍历配置节点的签名子节点→验证“required=conf”的签名→返回最终结果。

4.特殊场景:回滚保护

代码末尾的fit_read_otp_rollback_index/fit_rollback_index_verify是“回滚保护”的弱实现:

•读取OTP中的回滚索引,防止攻击者降级到旧版本(有安全漏洞的版本);

•采用__weak修饰,支持厂商自定义实现(如基于硬件OTP的索引校验)。

四、数据处理全流程:从触发验签到验证完成

我们以“镜像节点验签”为例,梳理完整的数据走向,流程图如下:

wKgZO2meaAmAAwoAAARaq-SMhps727.png

流程图核心说明:验签流程层层封装、逐步递进,优先验证“必需签名”,确保启动安全性;单个签名节点验证需完成算法绑定、哈希读取、匹配校验三大核心步骤,任一环节失败则启动终止。

1.启动触发验签 → 传入FIT镜像指针、镜像节点偏移量2.调用fit_image_verify_required_sigs → 筛选required=image的签名节点3.调用fit_image_verify_sig → 遍历镜像节点下的sig-*子节点4. 对每个sig节点调用fit_image_check_sig: a. fit_image_setup_verify → 解析算法名→匹配哈希/加密/填充算法 b. 读取FIT节点中的哈希值(fit_value) c. 构造image_region(待验证数据的指针+长度) d. 调用crypto_algo->verify → 验证哈希值与签名匹配5.验证通过→返回0;验证失败→输出错误信息→返回-16.所有required签名验证通过→启动镜像;否则→启动失败

配置节点验签的流程类似,核心差异是:哈希区域从“镜像数据”变为“配置节点的子节点+字符串区域”。

五、代码设计的亮点与扩展思路

1.设计亮点

•模块化:算法与验签逻辑解耦,新增算法只需修改checksum_algos/crypto_algos数组;

•可配置:通过宏开关(如CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT)控制功能,适配不同场景;

•内存适配:区分SPL/非SPL构建,兼顾代码量和易用性;

•调试友好:输出详细的调试信息(哈希区域、算法名),方便问题定位。

2.扩展思路

•新增哈希算法(如SHA512):在checksum_algos数组中添加新项,实现对应的哈希计算函数;

•支持ECDSA加密:扩展crypto_algos结构体,添加ECDSA的签名/验签函数;

•强化回滚保护:基于硬件OTP实现强校验,替换默认的__weak函数;

•适配TEE:结合OP-TEE(代码中已引入OpteeClientInterface.h),将验签逻辑移到安全世界执行。

六、总结

image-sig.c是U-Boot FIT镜像安全的核心,它以“算法抽象+流程封装”的方式,实现了哈希计算、签名验证、配置校验的完整逻辑。理解这份代码,不仅能掌握U-Boot安全启动的底层原理,也能为嵌入式系统的安全加固提供思路——比如如何设计可扩展的验签框架、如何适配不同的硬件安全特性。

在实际开发中,厂商通常会基于这份代码做定制化:比如适配自研的硬件加密模块、强化回滚保护、新增国密算法(SM2/SM3)等。而掌握核心逻辑后,这些定制化开发都会变得清晰可落地。

最后,安全启动的核心是“全链路可信”,image-sig.c只是其中一环,还需要结合镜像加密、OTP烧录、硬件隔离等技术,才能构建真正的安全启动体系。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式系统
    +关注

    关注

    41

    文章

    3817

    浏览量

    133865
  • u-boot
    +关注

    关注

    0

    文章

    135

    浏览量

    39920
  • Fit
    Fit
    +关注

    关注

    0

    文章

    17

    浏览量

    9584
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    S32G398 u-boot OCOTP 编程保险丝仅在复位后激活是为什么?

    我需要保险丝编程和验证(“保险丝程序”和“保险丝 cmp”)方面的帮助。 S32G3 保险丝通过 u-boot 命令行进行编程。要更新保险丝,我需要在 u-boot 中执行“重置”。\'fuse
    发表于 04-08 06:05

    更新 U-boot 时出现的问题求解

    我在尝试更新 U-boot 时遇到问题。最初我无法启动 Fedora,但后来我读到了这并尝试更新 U-boot。但是,当我按照官方文档我卡在迷你机屏幕上,什么也做不了。我担心董事会来了 DOA......
    发表于 04-01 07:20

    更新固件后 U-boot 不运行怎么解决?

    我刷新了从这里下载的新fw_payload固件(u-boot 和 opensbi):用于 TF 卡兼容性的新 u-boot 二进制文件 -.现在它启动到 OpenSBI,但无法达到 U-boot。我
    发表于 03-25 08:17

    更新 SPL 和 U-Boot的提示和技巧

    U-Boot 和 SPL 文件并将它们加载到 U 盘上 7 连接将 USB 记忆棒连接到 VF2 板并将其安装在文件夹中 8 更新来自终端的固件 9 验证使用命令 cat /proc/mtd 并检查如下
    发表于 03-20 08:15

    深入解析U-Boot image.c:RK平台镜像处理核心逻辑

    在瑞芯微(RK)平台的嵌入式开发中,U-Boot作为核心的启动加载程序,负责完成镜像解析、校验、加载等关键流程。而image.c正是
    的头像 发表于 02-24 16:46 1769次阅读
    <b class='flag-5'>深入</b><b class='flag-5'>解析</b><b class='flag-5'>U-Boot</b> <b class='flag-5'>image.c</b>:RK平台<b class='flag-5'>镜像</b>处理<b class='flag-5'>核心</b>逻辑

    玩转U-Boot bdinfo:嵌入式bsp开发者的定制、扩展与裁剪实战指南

    作为嵌入式开发者,U-Boot 是我们调试、适配板卡的核心工具,而 bdinfo 命令更是板级信息调试的“利器”——它能直观打印内存布局、Flash 信息、网络配置、时钟频率等核心参数。但原厂
    的头像 发表于 02-24 15:26 836次阅读
    玩转<b class='flag-5'>U-Boot</b> bdinfo:嵌入式bsp开发者的定制、扩展与裁剪实战指南

    深入解析RK3588 U-Boot板级文件:evb_rk3588.c核心逻辑拆解

    在嵌入式开发领域,瑞芯微RK3588凭借超强的算力、丰富的接口和广泛的场景适配性,成为高端边缘计算、消费电子项目的热门选择。而U-Boot作为嵌入式系统的“第一道门”,负责硬件初始化、引导内核启动,其板级适配代码直接决定了芯片硬件能力的落地。
    的头像 发表于 02-24 15:24 961次阅读
    <b class='flag-5'>深入</b><b class='flag-5'>解析</b>RK3588 <b class='flag-5'>U-Boot</b>板级文件:evb_rk3588.<b class='flag-5'>c</b><b class='flag-5'>核心</b>逻辑拆解

    U-Boot SPL核心文件spl.c深度解析:从启动流程到调试优化

    解析 U-Boot 中 spl.c 文件的功能与作用,探讨其在系统调试和优化中的价值,并通过流程图和脑图帮助开发者快速掌握核心要点。
    的头像 发表于 02-05 14:08 417次阅读
    <b class='flag-5'>U-Boot</b> SPL<b class='flag-5'>核心</b>文件spl.<b class='flag-5'>c</b>深度<b class='flag-5'>解析</b>:从启动流程到调试优化

    深入解析U-Boot TPL代码:嵌入式启动的“第一棒”背后的秘密

    在嵌入式系统启动过程中,从按下电源键到操作系统开始运行,中间藏着一系列精密的初始化步骤。今天我们就来拆解 Rockchip 平台 U-Boot 中的 TPL(Tiny Program Loader)阶段核心代码tpl.c,看看这
    的头像 发表于 02-05 14:07 1284次阅读
    <b class='flag-5'>深入</b><b class='flag-5'>解析</b><b class='flag-5'>U-Boot</b> TPL代码:嵌入式启动的“第一棒”背后的秘密

    深入解析U-Boot命令处理核心文件:功能、调试与开发价值

    在嵌入式系统开发中,U-Boot 作为主流的引导加载程序,其命令处理、交互逻辑和自动启动流程是核心功能模块。本文将围绕command.c、cli.c和autoboot.
    的头像 发表于 02-03 15:44 982次阅读
    <b class='flag-5'>深入</b><b class='flag-5'>解析</b><b class='flag-5'>U-Boot</b>命令处理<b class='flag-5'>核心</b>文件:功能、调试与开发价值

    深入解析U-Boot核心文件board_f.c:知识点、调试要点与开发价值

    在嵌入式系统开发中,U-Boot 作为应用最广泛的引导程序,其底层初始化逻辑直接决定了硬件启动的稳定性与可靠性。
    的头像 发表于 02-03 15:38 855次阅读
    <b class='flag-5'>深入</b><b class='flag-5'>解析</b><b class='flag-5'>U-Boot</b><b class='flag-5'>核心</b>文件board_f.<b class='flag-5'>c</b>:知识点、调试要点与开发价值

    解析Rockchip平台U-Boot核心文件:boot_rkimg.c到底做了什么?

    在嵌入式开发中,U-Boot 作为引导程序的 “中流砥柱”,负责初始化硬件、加载内核并启动系统。对于 Rockchip 平台的设备(如常见的开发板、智能终端),boot_rkimg.cU-Boot 中专门处理启动流程的
    的头像 发表于 02-03 15:29 929次阅读
    <b class='flag-5'>解析</b>Rockchip平台<b class='flag-5'>U-Boot</b><b class='flag-5'>核心</b>文件:<b class='flag-5'>boot_rkimg.c</b>到底做了什么?

    深入解析rk平台Android Bootloader核心代码:从启动流程到AVB验证

    作为Android设备启动的第一道“闸门”,Bootloader(以U-Boot为主)承担着初始化硬件、加载内核、验证镜像完整性的核心职责。今天我们拆解Rockchip平台
    的头像 发表于 01-22 07:06 467次阅读
    <b class='flag-5'>深入</b><b class='flag-5'>解析</b>rk平台Android Bootloader<b class='flag-5'>核心</b>代码:从启动流程到AVB<b class='flag-5'>验证</b>

    深入解析RK平台Android/Linux Bootloader核心文件:android_bootloader.c

    Bootloader是Android设备启动的第一道“关卡”,负责初始化硬件、加载系统镜像并完成内核启动的前置准备。在基于U-Boot的Android设备中,android_bootloader.c
    的头像 发表于 01-09 10:58 1402次阅读
    <b class='flag-5'>深入</b><b class='flag-5'>解析</b>RK平台Android/Linux Bootloader<b class='flag-5'>核心</b>文件:android_bootloader.<b class='flag-5'>c</b>

    深入理解 RK3506 U-Boot 重定位:从代码到原理

    在嵌入式系统中,U-Boot 作为引导加载程序,其启动流程的核心环节之一就是 重定位(Relocation) 。对于 RK3506 这类基于 ARM Cortex-A 架构的芯片,重定位的本质是将
    的头像 发表于 11-28 07:05 957次阅读
    <b class='flag-5'>深入</b>理解 RK3506 <b class='flag-5'>U-Boot</b> 重定位:从代码到原理