44. TA镜像加载时的验证

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

当当购买地址

京东购买地址

天猫购买地址

非常感谢在此期间大家的支持以及各位友人的支持和帮助!!!。
--------------------- 
作者:漂流的猴子 
来源:CSDN 
原文:https://blog.csdn.net/shuaifengyun/article/details/73716352?utm_source=copy 
版权声明:本文为博主原创文章,转载请附上博文链接!

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

扫描二维码关注公众号,回复: 3560761 查看本文章
#输入参数解析函数
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

猜你喜欢

转载自blog.csdn.net/shuaifengyun/article/details/75307326