ATF加载自定义镜像

实际上包含了两个问题:

  1. 如何把自定义的二进制文件打包到fip.bin中?
  2. 如何在secure boot流程中load和认证自定义的二进制文件?

如何打包

证书创建工具和FIP打包工具是通过命令行传参的方式进行证书创建和打包的,如下:

image

由于我们需要打包自定义得image到fip,但是证书创建工具和FIP打包工具预定义的选项中并没有该选项,所以需要修改cert_createfip_tool工具。

准备自定义的image

我直接在ATF的platform.mk中生成了一个测试用的dtb作为image:

FDT_SOURCES += ${PLAT_QEMU_PATH}/test.dts
HW_CONFIG := ${BUILD_PLAT}/fdts/test.dtb

修改cert_create

  1. include/tools_share/tbbr_oid.h​文件中添加自定义的证书拓展域OID,定义如下(需保证与其他OID不同):

    #define USER_IMAGE_HASH_OID                     "1.3.6.1.4.1.4128.2100.1401"
    
  2. tools/cert_create/include/tbbr/tbb_ext.h​添加一行自定义image的证书拓展域枚举类型:

    /* TBBR extensions */
    enum {
    	TRUSTED_FW_NVCOUNTER_EXT,
    	NON_TRUSTED_FW_NVCOUNTER_EXT,
    	TRUSTED_BOOT_FW_HASH_EXT,
    	TRUSTED_BOOT_FW_CONFIG_HASH_EXT,
    .................
    
    	SCP_FWU_CFG_HASH_EXT,
    	AP_FWU_CFG_HASH_EXT,
    	FWU_HASH_EXT,
    	USER_IMAGE_EXT, /* user-defined image ext */
    };
    
  3. 我们想要使用TRUSTED_BOOT_FW_CERT​去认证这个image,所以在tools/cert_create/src/tbbr/tbb_cert.c​文件中TRUSTED_BOOT_FW_CERT​的拓展域添加USER_IMAGE_EXT​枚举类型。

    /*
     * Certificates used in the chain of trust
     *
     * The order of the certificates must follow the enumeration specified in
     * tbb_cert.h. All certificates are self-signed, so the issuer certificate
     * field points to itself.
     */
    static cert_t tbb_certs[] = {
    	[TRUSTED_BOOT_FW_CERT] = {
    		.id = TRUSTED_BOOT_FW_CERT,
    		.opt = "tb-fw-cert",
    		.help_msg = "Trusted Boot FW Certificate (output file)",
    		.fn = NULL,
    		.cn = "Trusted Boot FW Certificate",
    		.key = ROT_KEY,
    		.issuer = TRUSTED_BOOT_FW_CERT,
    		.ext = {
    			TRUSTED_FW_NVCOUNTER_EXT,
    			TRUSTED_BOOT_FW_HASH_EXT,
    			TRUSTED_BOOT_FW_CONFIG_HASH_EXT,
    			HW_CONFIG_HASH_EXT,
    			FW_CONFIG_HASH_EXT,
    			USER_IMAGE_EXT, /* user-defined image ext */
    		},
    		.num_ext = 6 /*modify the size from five to six */
    	},
    
  4. 接着,在tools/cert_create/src/tbbr/tbb_ext.c​中添加该拓展域的内容:

    static ext_t tbb_ext[] = {
    	[TRUSTED_FW_NVCOUNTER_EXT] = {
    		.oid = TRUSTED_FW_NVCOUNTER_OID,
    		.opt = "tfw-nvctr",
    		.help_msg = "Trusted Firmware Non-Volatile counter value",
    		.sn = "TrustedWorldNVCounter",
    		.ln = "Trusted World Non-Volatile counter",
    		.asn1_type = V_ASN1_INTEGER,
    		.type = EXT_TYPE_NVCOUNTER,
    		.attr.nvctr_type = NVCTR_TYPE_TFW
    	},
    ....................
    
    /* new added */
    	[USER_IMAGE_EXT] = {
    		.oid = USER_IMAGE_HASH_OID, /* 自定义的OID */
    		.opt = "user-img", /*这个会生成cert_create的选项 --user-img */
    		.help_msg = "User-defined Image file",
    		.sn = "UserImgHash",
    		.ln = "User-defined image HASH (SHA256)",
    		.asn1_type = V_ASN1_OCTET_STRING,
    		.type = EXT_TYPE_HASH, /* 使用hash校验该image */
    		.optional = 1
    	}
    };
    
    REGISTER_EXTENSIONS(tbb_ext);
    

自此,cert_create可以使用–user-img命令为自定义的image生成hash并将hash值存储在TRUSTED_BOOT_FW_CERT​证书中。

修改fip_tool

image准备好了,证书生成了,该打包进fip了。

  1. 首先在include/tools_share/firmware_image_package.h​添加一个标识该image的唯一的UUID号,该UUID将会在加载认证阶段用于识别该image:

    #define UUID_USER_DEFINED_IMG \
    	{{0x23, 0x6e, 0xd3, 0x30}, {0x4e, 0xdf}, {0x11, 0xef}, 0x8d, 0xd7, {0x00, 0x15, 0x5d, 0xba, 0x59, 0x68} }
    
  2. tools/fiptool/tbbr_config.c​文件中为fip_tool添加一个命令行选项--user-img​。

    toc_entry_t toc_entries[] = {
    	{
    		.name = "Platform Key Certificate",
    		.uuid = UUID_PLAT_KEY_CERT,
    		.cmdline_name = "plat-key-cert"
    	},
    	.................................
        //添加命令
    	{
    		.name = "User-defined Image",
    		.uuid = UUID_USER_DEFINED_IMG,
    		.cmdline_name = "user-img"
    	},
    	{
    		.name = NULL,
    		.uuid = { {0} },
    		.cmdline_name = NULL,
    	}
    };
    

    这里的命令行选项需要和cert_create的保持一致。

  3. 做完以上操作,在使用fip_tool工具时在–user-img后面跟上自定义的image的路径就可以将image打包到fip_tool。

打包image

最后我们在platform.mk中使用一个宏TOOL_ADD_PAYLOAD即可完成:

  1. 将image的hash记录在TRUSTED_BOOT_FW_CERT​证书中,用于后续的验签
  2. 将image打包到fip.bin。

image

如何加载

可以拆解为以下问题:

  1. 从哪里加载?(需要修改IO storage)
  2. 加载到哪里?(定义加载的位置并进行MMU映射)
  3. 如何加载?怎么验签?(修改信任链)

从哪里加载

  1. 首先我们在include/export/common/tbbr/tbbr_img_def_exp.h​定义一个ID唯一标识该image:

    #define PLAT_USER_IMG_ID		U(38)
    
    /* Max Images */
    #define MAX_IMAGE_IDS			U(39)
    
  2. 在平台路径plat/qemu/common/qemu_io_storage.c​中定义自定义image的描述符:

    static const io_uuid_spec_t user_image_uuid_spec = {
    	.uuid = UUID_USER_DEFINED_IMG,
    };
    
  3. 在平台路径plat/qemu/common/qemu_io_storage.c​中的plat_io_policy数组中添加以下内容,表示该image从fip文件中根据UUID进行解析提取。

    static const struct plat_io_policy policies[] = {
    	[FIP_IMAGE_ID] = {
    		&memmap_dev_handle,
    		(uintptr_t)&fip_block_spec,
    		open_memmap
    	},
    .....................
    	[PLAT_USER_IMG_ID] = {
    		&fip_dev_handle,
    		(uintptr_t)&user_image_uuid_spec,
    		open_fip
    	},
    };
    

加载到哪里

  1. 首先需要在plat/qemu/qemu/include/platform_def.h​中定义自定义镜像加载的基地址和边界,我这里定义的是在RAM的其实地址,最大为一个PAGE_SIZE(4KB),毕竟设备树很小。

    #define USER_IMG_BASE			BL_RAM_BASE
    #define USER_IMG_LIMIT			(USER_IMG_BASE + PAGE_SIZE)
    
  2. 我们计划是在BL2阶段load镜像,所以需要在BL2起来之后进行memory map,不然未经过MMU平坦映射的地址是无法访问的。在plat/qemu/common/qemu_bl2_setup.c​中添加以下映射,内存属性为普通memory、可读写、secure。

    #define MAP_BL2_TOTAL		MAP_REGION_FLAT(			\
    					bl2_tzram_layout.total_base,	\
    					bl2_tzram_layout.total_size,	\
    					MT_MEMORY | MT_RW | MT_SECURE), \
    				/* new added */ \
    				MAP_REGION_FLAT(			\
    					USER_IMG_BASE,			\
    					USER_IMG_LIMIT			\
    						- USER_IMG_BASE,	\
    					MT_MEMORY | MT_RW | MT_SECURE)
    

如何加载?怎么验签?

  1. 然后需要告诉BL2阶段需要加载这个自定义的image,在plat/qemu/common/qemu_bl2_mem_params_desc.c​的bl2_mem_params_descs​数组中添加如下内容。如此,BL2在load_image时就会解析该数组,根据镜像UUID在fip中查找到该镜像,并将镜像load到指定的镜像基地址进行验证。

    static bl_mem_params_node_t bl2_mem_params_descs[] = {
    	/* Fill BL32 related information */
    	{ .image_id = BL32_IMAGE_ID,
    	  SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
    				entry_point_info_t, BL32_EP_ATTRIBS),
    	  .ep_info.pc = BL32_BASE,
    	  SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2,
    				image_info_t, BL32_IMG_ATTRIBS),
    	  .image_info.image_base = BL32_BASE,
    	  .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
    
    	  .next_handoff_image_id = BL33_IMAGE_ID,
    	},
    ...................................
    	/* new added */
    	{ .image_id = PLAT_USER_IMG_ID, /* 镜像ID */
    	   SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2,
    				 entry_point_info_t, SECURE | NON_EXECUTABLE),
    	   SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2,
    				 image_info_t, 0),
    	   .image_info.image_base = USER_IMG_BASE, /* 加载的基地址 */
    	   .image_info.image_max_size = USER_IMG_LIMIT - USER_IMG_BASE, /*镜像最大size*/
    	   .next_handoff_image_id = INVALID_IMAGE_ID,
    	},
    };
    
  2. 然后还需要修改COT(chain of trust),否则BL2不知道如何验证该镜像的完整性。在drivers/auth/tbbr/tbbr_cot_common.c​中添加如下内容,表明TRUSTED_BOOT_FW_CERT_ID​证书的拓展域存储了自定义image的hash值。

    line 32: static unsigned char user_img_hash_buf[HASH_DER_LEN];
    line 56: auth_param_type_desc_t user_img_hash = AUTH_PARAM_TYPE_DESC(
    	AUTH_PARAM_HASH, USER_IMAGE_HASH_OID);
    
    * trusted_boot_fw_cert */
    line 63: const auth_img_desc_t trusted_boot_fw_cert = {
    	.img_id = TRUSTED_BOOT_FW_CERT_ID,
    	.img_type = IMG_CERT,
    	.parent = NULL,
    	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
    	 .................
    	},
    	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
    		[0] = {
    			.type_desc = &tb_fw_hash,
    			.data = {
    				.ptr = (void *)tb_fw_hash_buf,
    				.len = (unsigned int)HASH_DER_LEN
    			}
    		},
    		................................
    		/* new added */
    		[4] = {
    			.type_desc = &user_img_hash, /* hash 校验 */
    			.data = {
    				.ptr = (void *)user_img_hash_buf, /* 证书拓展域的hash buffer */
    				.len = (unsigned int)HASH_DER_LEN
    			}
    		},
    	}
    };
    
  3. 还需要在drivers/auth/tbbr/tbbr_cot_common.c​文件中增加一个需要认证的节点的描述结构:

    const auth_img_desc_t user_img = {
    	.img_id = PLAT_USER_IMG_ID,
    	.img_type = IMG_RAW,
    	.parent = &trusted_boot_fw_cert, /* 指定它需要由trusted_boot_fw_cert认证*/
    	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
    		[0] = {
    			.type = AUTH_METHOD_HASH, /* 认证方法为hash */
    			.param.hash = {
    				.data = &raw_data,
    				.hash = &user_img_hash
    			}
    		}
    	}
    };
    
  4. 最后将该结构加入到COT当中。在文件drivers/auth/tbbr/tbbr_cot_bl2.c​增加。这样,在验证该image时,BL2就可以根据COT找到认证该image所需的父节点和方法。

    static const auth_img_desc_t * const cot_desc[] = {
    	[TRUSTED_BOOT_FW_CERT_ID]		=	&trusted_boot_fw_cert,
    	[HW_CONFIG_ID]				=	&hw_config,
    	[TRUSTED_KEY_CERT_ID]			=	&trusted_key_cert,
    	[SCP_FW_KEY_CERT_ID]			=	&scp_fw_key_cert,
    	[SCP_FW_CONTENT_CERT_ID]		=	&scp_fw_content_cert,
    
    	.................................
    	[PLAT_USER_IMG_ID]			=	&user_img, //new added
    };
    

Demo

从启动过程中log可以看出:BL2在加载ID为38的镜像(即我们添加的自定义镜像PLAT_USER_IMG_ID​)时,去加载了ID=6的TRUSTED_BOOT_FW_CERT​证书对齐进行认证,认证成功后才开始去解析该image。

image

文档提供完整patch资源,在ATF2.9.0的qemu平台的代码上实现了将一个自定义的dtb打包到fip中,并且在BL2阶段对该dtb进行加载和验证。

  • 28
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liangtao`

请作者喝杯咖啡吧~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值