ARM64 Linux内核FIT签名镜像全流程实战指南

在嵌入式系统开发中,确保内核镜像的完整性和真实性至关重要。想象一下这样的场景:当你花费数周时间调试的定制开发板终于可以启动时,突然发现系统被恶意代码入侵,所有努力付诸东流。安全启动机制正是为了防止这类噩梦而设计的核心防线。

对于使用U-Boot作为引导加载程序的ARM64平台,FIT(Flattened Image Tree)格式提供了一种灵活且安全的镜像打包方式。本指南将从密码学基础到实际部署,带你完整走过生成密钥对、配置ITS描述文件、编译验签支持的U-Boot,最终生成可验证的FIT镜像全流程。我们特别关注那些开发板上真实遇到的"坑"——比如bootm与booti启动方式的差异、DTS路径配置的玄机、以及签名验证失败的典型表现。

1. 密码学基础与环境准备

在开始生成签名镜像前,我们需要建立基本的密码学工作环境。现代嵌入式系统通常采用非对称加密体系,这意味着需要生成配对的私钥和证书。对于资源受限的ARM64设备,RSA-2048配合SHA-1哈希算法是平衡安全性与性能的常见选择。

开发环境最低要求:

  • 主机系统:Ubuntu 20.04 LTS或更新版本
  • 工具链:aarch64-linux-gnu-gcc 9.x以上
  • 基础软件包:
    sudo apt install build-essential libssl-dev device-tree-compiler flex bison
    

生成开发密钥对的OpenSSL命令如下:

openssl genpkey -algorithm RSA -out dev.key \
  -pkeyopt rsa_keygen_bits:2048 \
  -pkeyopt rsa_keygen_pubexp:65537
openssl req -batch -new -x509 -key dev.key -out dev.crt

注意:实际生产环境应使用HSM或安全元件保护私钥,此处开发用密钥切勿用于正式产品

目录结构建议如下布局,便于后续管理:

~/secure_boot/
├── keys/
│   ├── dev.key  # 私钥
│   └── dev.crt  # 证书
├── linux/
│   ├── Image    # 待签名内核
│   └── fsl-s32g.dtb  # 设备树
└── u-boot/      # U-Boot源码

2. ITS文件深度解析与定制

FIT镜像的核心是ITS(Image Tree Source)描述文件,它采用DTS语法定义了镜像组成、加载方式和签名信息。一个典型的ARM64内核ITS文件包含以下关键部分:

基础结构分析:

/dts-v1/;
/ {
    description = "Secure Kernel Image";
    #address-cells = <1>;

    images {
        kernel@1 {
            data = /incbin/("Image");
            type = "kernel";
            arch = "arm64";
            os = "linux";
            compression = "none";
            load = <0x80080000>;  // 内核加载地址
            entry = <0x80080000>; // 入口地址
            signature {
                algo = "sha1,rsa2048";
                key-name-hint = "dev"; // 对应密钥别名
            };
        };
        // 更多镜像定义...
    };
    configurations {
        default = "conf@1";
        conf@1 {
            kernel = "kernel@1";
            // 其他配置...
        };
    };
};

常见配置陷阱:

  1. 地址对齐问题:ARM64要求内核加载地址必须2MB对齐,否则会触发alignment fault。例如0x80080000是安全的选择。

  2. 哈希算法选择:

    signature {
        algo = "sha256,rsa4096"; // 更高安全级别
        key-name-hint = "prod-key"; // 生产环境密钥
    };
    
  3. 多镜像组合:实际项目常需同时打包内核、设备树和initramfs:

    images {
        kernel { /* ... */ };
        fdt@1 {
            data = /incbin/("board.dtb");
            type = "flat_dt";
            // ...
        };
        ramdisk {
            data = /incbin/("initrd.img");
            type = "ramdisk";
            compression = "gzip";
        };
    }
    

3. U-Boot验签配置实战

要让U-Boot支持FIT验签,需要精确配置编译选项。以U-Boot 2021.04为例,关键配置步骤如下:

菜单配置路径:

make menuconfig

必须开启的选项:

Boot options  --->
  [*] Enable FIT image support
  [*] Enable signature verification of FIT images
  (sha1,rsa2048) Default hash algorithm  # 与ITS保持一致

Device Tree Control  --->
  [*] Enable OF_CONTROL
  [*] Separate DTB for U-Boot
  (fsl-s32g-verified-boot) Default Device Tree

设备树关键节点:

signature {
    key-dev {
        required = "conf";
        algo = "sha1,rsa2048"; // 与ITS一致
        key-name-hint = "dev";
    };
};

常见编译问题排查:

  1. 设备树未生效:确认CONFIG_DEFAULT_DEVICE_TREE与实际dts文件名匹配(不含扩展名)

  2. 签名算法不匹配:检查U-Boot配置、ITS文件和设备树中的algo参数完全一致

  3. 密钥路径问题:使用绝对路径指定密钥位置,避免相对路径导致的查找失败

4. 镜像生成与验证全流程

完成上述准备后,我们可以进入实际镜像生成阶段。这个流程需要精确执行多个步骤,任何环节出错都会导致验签失败。

完整操作序列:

# 生成FIT镜像
mkimage -f sign-images.its -K fsl-s32g-verified-boot.dtb -k ~/secure_boot/keys -r fit-image

# 验证签名
fit_check_sign -f fit-image -k fsl-s32g-verified-boot.dtb

# 编译带验签支持的U-Boot
make EXT_DTB=fsl-s32g-verified-boot.dtb

# 组合最终镜像
cat u-boot.bin u-boot.dtb > u-boot.img

关键参数说明:

参数作用示例值
-f指定ITS文件路径linux/sign-images.its
-K输出控制dtb路径linux/fsl-s32g.dtb
-k密钥目录路径~/secure_boot/keys
-r输出镜像名称fit-image

验签失败诊断:

  1. 密钥不匹配:检查key-name-hint在ITS、设备树中是否一致
  2. 哈希值无效:确认所有data字段引用的文件未被修改
  3. 时间戳问题:某些版本U-Boot对时间戳校验严格,可尝试禁用:
    signature {
        algo = "sha1,rsa2048";
        timestamp = <0>; // 禁用时间戳验证
    };
    

5. 开发板部署与测试

将生成的镜像烧写到开发板后,通过U-Boot命令行可以验证安全启动是否生效:

基本启动命令:

# 加载FIT镜像
load mmc 0:1 ${loadaddr} fit-image

# 验签并启动
bootm ${loadaddr}

测试用例设计:

  1. 正向测试:使用正确签名的镜像应正常启动
  2. 篡改检测:修改内核后尝试启动,应看到验签失败提示
  3. 密钥替换:使用非配对密钥签名,验证是否拒绝启动

U-Boot输出分析:

Verifying Hash Integrity ... sha1,rsa2048:dev+ OK  # 验签成功
或
Bad hash algo: sha256 (must be sha1)  # 算法不匹配

6. 进阶技巧与性能优化

对于需要更高安全级别或更优性能的场景,可以考虑以下增强措施:

安全增强方案:

  1. 密钥轮换:实现多密钥支持和吊销机制

    signature {
        algo = "sha256,pss,rsa4096";
        key-name-hint = "key-2023";
        signer-version = <2>;
    };
    
  2. 抗重放攻击:在ITS中添加单调计数器

    timestamp = <$(date +%s)>;
    anti-replay = <1>;
    

性能优化技巧:

  1. 压缩内核:减小镜像尺寸加速加载

    compression = "lz4";
    load = <0x80000000>;  // 解压目标地址
    
  2. 哈希缓存:对频繁验证的镜像启用哈希缓存

    setenv verify_hashing cache  # U-Boot环境变量
    

调试技巧:

# 启用详细调试输出
setenv verify_debug 1
saveenv

通过本指南的系统性实践,你应该已经掌握了ARM64平台下FIT签名镜像的完整生命周期管理。在实际项目部署时,记得根据具体硬件和安全需求调整参数配置,并建立完善的密钥管理流程。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐