ATF密钥生成和验签
根密钥生成
-
密钥的生成依赖openssl库,需要提前安装:
sudo apt-get install openssl
-
生成.pem格式的RSA4096私钥
openssl genrsa -out pri_key.pem 4096
-
生成对应的DER格式公钥
openssl rsa -in pri_key.pem -pubout -out pub_key.der -outform DER
-
计算公钥hash
openssl dgst -sha256 -binary pub_key.der > pub_key_sha256.bin
这里生成的私钥即可用于image的签名,公钥可用于验签,rotpk(根公钥)的hash通常存储在efuse或者otp中。根据ATF中定义的CoT实例,rotpk用于对trusted_boot_fw_cert和trusted_key_cert进行验签。
为什么不直接在efuse和otp中直接存储公钥?
原因之一为公钥通常比较大,直接放在efuse中会占用较大空间,不划算。而使用sha256算法进行hash计算得到的摘要仅256bit,存储在efuse中不会占太大空间。
验签
由于efuse中存储的值是rotpk的hash,这样就导致一个问题,在信任链建立的初始阶段,无法从efuse中直接得到公钥对image进行验签, 该如何解决?
因为trusted_boot_fw_cert和trusted_key_cert是使用根密钥进行签名的,对应的公钥会被存储在x509证书内部。
x509证书结构
重要的组成部分为与签名该证书的私钥对应的公钥,尾部的证书自身的签名。
那么在验签的时候就需要:
-
从证书中取出公钥对证书本身进行验签。这样保证了证书内容没被修改,但是不能保证公钥是否被修改。验签详细步骤为:
- 从证书中提取数字签名。
- 使用相同的哈希函数对证书内容(除了数字签名)进行哈希计算,得到一个新的哈希值。
- 使用公钥对数字签名进行解密,解密后应该得到与新哈希值相同的原始哈希值。
- 如果解密后的哈希值与新计算的哈希值相同,那么数字签名验证成功,这表明证书未被篡改。
-
然后需要对从证书中取出的公钥计算hash,并与efuse中存储的hash值做比较。如果相同则验签通过,否则验签失败。
对应的code位于drivers/auth/auth_mod.c
:
/*
* Authenticate by digital signature
*
* This function implements 'AUTH_METHOD_SIG'. To authenticate an image using
* this method, the image must contain:
*
* - Data to be signed
* - Signature
* - Signature algorithm
*
* We rely on the image parser module to extract this data from the image.
* The parent image must contain:
*
* - Public key (or a hash of it)
*
* If the parent image contains only a hash of the key, we will try to obtain
* the public key from the image itself (i.e. self-signed certificates). In that
* case, the signature verification is considered just an integrity check and
* the authentication is established by calculating the hash of the key and
* comparing it with the hash obtained from the parent.
*
* If the image has no parent (NULL), it means it has to be authenticated using
* the ROTPK stored in the platform. Again, this ROTPK could be the key itself
* or a hash of it.
*
* Return: 0 = success, Otherwise = error
*/
static int auth_signature(const auth_method_param_sig_t *param,
const auth_img_desc_t *img_desc,
void *img, unsigned int img_len)
{
void *data_ptr, *pk_ptr, *pk_hash_ptr, *sig_ptr, *sig_alg_ptr;
unsigned int data_len, pk_len, pk_hash_len, sig_len, sig_alg_len;
unsigned int flags = 0;
int rc = 0;
/* Get the data to be signed from current image */
rc = img_parser_get_auth_param(img_desc->img_type, param->data,
img, img_len, &data_ptr, &data_len);
return_if_error(rc);
/* Get the signature from current image */
rc = img_parser_get_auth_param(img_desc->img_type, param->sig,
img, img_len, &sig_ptr, &sig_len);
return_if_error(rc);
/* Get the signature algorithm from current image */
rc = img_parser_get_auth_param(img_desc->img_type, param->alg,
img, img_len, &sig_alg_ptr, &sig_alg_len);
return_if_error(rc);
/* Get the public key from the parent. If there is no parent (NULL),
* the certificate has been signed with the ROTPK, so we have to get
* the PK from the platform */
if (img_desc->parent) {
rc = auth_get_param(param->pk, img_desc->parent,
&pk_ptr, &pk_len);
} else {
rc = plat_get_rotpk_info(param->pk->cookie, &pk_ptr, &pk_len,
&flags);
}
return_if_error(rc);
//如果ROTPK是hash,就需要从证书中获取公钥,使用这个公钥验签
if (flags & (ROTPK_IS_HASH | ROTPK_NOT_DEPLOYED)) {
/* If the PK is a hash of the key or if the ROTPK is not
deployed on the platform, retrieve the key from the image */
pk_hash_ptr = pk_ptr;
pk_hash_len = pk_len;
rc = img_parser_get_auth_param(img_desc->img_type,
param->pk, img, img_len,
&pk_ptr, &pk_len);
return_if_error(rc);
/* Ask the crypto module to verify the signature */
rc = crypto_mod_verify_signature(data_ptr, data_len,
sig_ptr, sig_len,
sig_alg_ptr, sig_alg_len,
pk_ptr, pk_len);
return_if_error(rc);
if (flags & ROTPK_NOT_DEPLOYED) {
NOTICE("ROTPK is not deployed on platform. "
"Skipping ROTPK verification.\n");
} else {
#if PLAT_VERIFY_ROTPK
//还需要验证证书中公钥是否合法,这是平台定义的,一般是计算公钥hash并与OTP中的hash对比。
rc = plat_verify_rotpk(pk_ptr, pk_len,
pk_hash_ptr, pk_hash_len);
#else
/* platform may store the hash of a prefixed, suffixed or modified pk */
rc = plat_convert_pk(pk_ptr, pk_len, &pk_ptr, &pk_len);
return_if_error(rc);
/* Ask the crypto-module to verify the key hash */
rc = crypto_mod_verify_hash(pk_ptr, pk_len,
pk_hash_ptr, pk_hash_len);
#endif
}
} else {
/* Ask the crypto module to verify the signature */
rc = crypto_mod_verify_signature(data_ptr, data_len,
sig_ptr, sig_len,
sig_alg_ptr, sig_alg_len,
pk_ptr, pk_len);
}
return rc;
}