欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

44. TA镜像加载时的验证

程序员文章站 2022-07-13 16:11:59
...

  历经一年多时间的系统整理合补充,《手机安全和可信应用开发指南:TrustZone与OP-TEE技术详解 》一书得以出版,书中详细介绍了TEE以及系统安全中的所有内容,全书按照从硬件到软件,从用户空间到内核空间的顺序对TEE技术详细阐述,读者可从用户空间到TEE内核一步一步了解系统安全的所有内容,同时书中也提供了相关的示例代码,读者可根据自身实际需求开发TA。目前该书已在天猫、京东、当当同步上线,链接如下(麻烦书友购书时能给予评论,多谢多谢)

京东购买地址

当当购买地址

天猫购买地址

非常感谢在此期间大家的支持以及各位友人的支持和帮助!!!。若觉得书中内容有错误的地方,欢迎大家指出,私信或者在博文中留言联系方式亦可发邮件至:aaa@qq.com,多谢各位了!!!!我会第一时间处理

当TA镜像文件已经被加载到共享内存之后,OP-TEE会对该份数据进行合法性检查。对TA镜像文件合法性的检查是通过调用检查镜像文件中的hash值,magic值,flag等值是否合法并对镜像文件中的signature部分做Verify操作是否成功来判定读取到共享内存中的TA镜像文件内容是否合法。整个验证过程如下:

44. TA镜像加载时的验证

1. 验证使用的RSApublic key的产生和获取

  编译整个工程的时候会产生一个ta_pub_key.c文件,该文件中存放的就是在验证TA镜像文件合法性的时候使用到的RSA public key的内容,该文件是在编译gensrcs-y目标中的ta_pub_key成员来产生的,该部分的内容定义在optee_os/core/sub.mk文件中,其内容如下:

 

subdirs-y += kernel
subdirs-y += tee
subdirs-y += drivers
ifeq ($(CFG_WITH_USER_TA)-$(CFG_REE_FS_TA),y-y)
gensrcs-y += ta_pub_key
produce-ta_pub_key = ta_pub_key.c
depends-ta_pub_key = $(TA_SIGN_KEY)
recipe-ta_pub_key = scripts/pem_to_pub_c.py --prefix ta_pub_key \
	--key $(TA_SIGN_KEY) --out $(sub-dir-out)/ta_pub_key.c
cleanfiles += $(sub-dir-out)/ta_pub_key.c
endif

  编译是在处理ta_pub_key目标时调用recipe-ta_pub_key来产生ta_pub_key.c文件,该文件将会被保存在optee_os/out/arm/core/目录中。在recipe-ta_pub_key中通过调用pem_to_pub_c.py脚本解析存放在optee_os/keys目录中的rsa key获取public key的相关内容并保存到ta_pub_key.c文件中,pem_to_pub_c.py脚本的内容如下:

 

 

#输入参数解析函数
def get_args():
	import argparse
	parser = argparse.ArgumentParser()
	parser.add_argument('--prefix', required=True, \
		help='Prefix for the public key exponent and modulus in c file')
	parser.add_argument('--out', required=True, \
		help='Name of c file for the public key')
	parser.add_argument('--key', required=True, help='Name of key file')
	return parser.parse_args()
#生成ta_pub_key.c文件的主要函数
def main():
	import array
	from Crypto.PublicKey import RSA
	from Crypto.Util.number import long_to_bytes
	#解析输入参数
	args = get_args();
	#打开输入的pem格式的RSA key并读取内容
	f = open(args.key, 'r')
	key = RSA.importKey(f.read())
	f.close
	#创建ta_pub_key.c文件
	f = open(args.out, 'w')
	#将include语句的内容写入到ta_pub_key.c文件中
	f.write("#include <stdint.h>\n");
	f.write("#include <stddef.h>\n\n");
	#写入ta_pub_key_exponent变量的内容和值
	f.write("const uint32_t " + args.prefix + "_exponent = " +
		str(key.publickey().e) + ";\n\n")
	#写入ta_pub_key_modulus变量的内容和值
	f.write("const uint8_t " + args.prefix + "_modulus[] = {\n")
	i = 0;
	for x in array.array("B", long_to_bytes(key.publickey().n)):
		f.write("0x" + '{0:02x}'.format(x) + ",")
		i = i + 1;
		if i % 8 == 0:
			f.write("\n");
		else:
			f.write(" ");
	f.write("};\n");
	#写入ta_pub_key_modulus_size变量的值
	f.write("const size_t " + args.prefix + "_modulus_size = sizeof(" + \
		args.prefix + "_modulus);\n")
	f.close()
if __name__ == "__main__":
	main()

 

生成的ta_pub_key.c文件中将定义三个全局变量并赋值,这三个变量就是RSA public key的内容,作用和内容分别为:

ta_pub_key_exponent    //RSA public key中的E值

ta_pub_key_modulus     //RSA public key中的N值

ta_pub_key_modulus_size     //RSA key的长度,再次该值为256也即表示该RSA key为RSA2048

这三个变量作为全局变量,在对TA镜像文件进行验签的时候用来做RSA2048的verify操作。

2. TA镜像文件的合法性检查的实现

  对TA镜像文件内容合法性的检查是通过调用check_shdr函数来实现的,该函数中除了会对TA镜像文件中的signature内容做verify操作之外,还对校验TA镜像文件中shdr部分中的内容,check_shdr代码内容如下:

 

static TEE_Result check_shdr(struct shdr *shdr)
{
	struct rsa_public_key key;
	TEE_Result res;
	//将全局变量ta_pub_key_exponent转成成RSA public key的E值
	uint32_t e = TEE_U32_TO_BIG_ENDIAN(ta_pub_key_exponent); 
	size_t hash_size;
	/* 校验shdr中的magic值和img_type值 */
	if (shdr->magic != SHDR_MAGIC || shdr->img_type != SHDR_TA)
		return TEE_ERROR_SECURITY;
	/* 检查shdr中的algo成员指定的算法类型是否合法 */
	if (TEE_ALG_GET_MAIN_ALG(shdr->algo) != TEE_MAIN_ALGO_RSA)
		return TEE_ERROR_SECURITY;
	/* 获取verify操作时需要使用的digest的大小 */
	res = tee_hash_get_digest_size(TEE_DIGEST_HASH_TO_ALGO(shdr->algo),
				       &hash_size);
	if (res != TEE_SUCCESS)
		return res;
	/* 检查shdr中的hash_size是否正确 */
	if (hash_size != shdr->hash_size)
		return TEE_ERROR_SECURITY;
	/* 检查OP-TEE中提供的算法接口crypto_ops中的成员是否有效 */
	if (!crypto_ops.acipher.alloc_rsa_public_key ||
	    !crypto_ops.acipher.free_rsa_public_key ||
	    !crypto_ops.acipher.rsassa_verify ||
	    !crypto_ops.bignum.bin2bn)
		return TEE_ERROR_NOT_SUPPORTED;
	/* 分配RSA public key在算法接口中的存储空间 */
	res = crypto_ops.acipher.alloc_rsa_public_key(&key, shdr->sig_size);
	if (res != TEE_SUCCESS)
		return res;
	/* 将RSA public key中的E值转换成bignumber */
	res = crypto_ops.bignum.bin2bn((uint8_t *)&e, sizeof(e), key.e);
	if (res != TEE_SUCCESS)
		goto out;
	/* 将ta_pub_key_modulus变量的值作为RSA public key中的N值并转换成bignumber */
	res = crypto_ops.bignum.bin2bn(ta_pub_key_modulus,
				       ta_pub_key_modulus_size, key.n);
	if (res != TEE_SUCCESS)
		goto out;
	/* 使用TA镜像文件中的digest部分和signature部分做RSA的verify操作 */
	res = crypto_ops.acipher.rsassa_verify(shdr->algo, &key, -1,
				SHDR_GET_HASH(shdr), shdr->hash_size,
				SHDR_GET_SIG(shdr), shdr->sig_size);
out:
	crypto_ops.acipher.free_rsa_public_key(&key);
	if (res != TEE_SUCCESS)
		return TEE_ERROR_SECURITY;
	return TEE_SUCCESS;
}

 

 在进行verify操作时使用的RSA public key的内容就是在编译时生成ta_public_key.c文件中的那两个全局变量ta_pub_key_exponent和ta_pub_key_modulus

 

 

 

 

 

 

 

相关标签: OP-TEE TA验证