赞
踩
安全启动的目的是保证系统从上电运行开始,到最终的操作系统加载启动完成,所有的固件均经过完整性和真实性验证,保证系统的可信性。
ATF的安全启动按照TBBR规范要求进行实现,为了防止恶意固件在平台上运行,受信任的板级引导 (TBB) 功能要求验证所有固件镜像(包括普通世界的引导加载程序),这通过使用公钥密码标准 (PKCS) 建立信任链来做到这一点。
ATF的认证框架实现如下图所示,包括以下组件。
+---------------+---------------+------------+ | Trusted | Trusted | Trusted | | Firmware | Firmware | Firmware | | Generic | IO Framework | Platform | | Code i.e. | (IO) | Port | | BL1/BL2 (GEN) | | (PP) | +---------------+---------------+------------+ ^ ^ ^ | | | v v v +-----------+ +-----------+ +-----------+ | | | | | Image | | Crypto | | Auth | | Parser | | Module |<->| Module |<->| Module | | (CM) | | (AM) | | (IPM) | | | | | | | +-----------+ +-----------+ +-----------+ ^ ^ | | v v +----------------+ +-----------------+ | Cryptographic | | Image Parser | | Libraries (CL) | | Libraries (IPL) | +----------------+ +-----------------+ | | | | | | v v +-----------------+ | Misc. Libs e.g. | | ASN.1 decoder | | | +-----------------+
信任链CoT是一些列经过认证的镜像,信任从信任根开始往后逐级传递。信任根通常由两个组件构成:信任根公钥和BootROM固件。信任根公钥用于验证可信启动证书和可信密钥证书,而BootROM代码确保镜像验证流程必须执行。
信任链的其他组件还包括符合X.509 v3标准的证书,证书的扩展中存储了建立CoT需要的参数。证书是自签名的,因此不需要CA进行验证,这是因为CoT的建立不需要验证颁发者的有效性,只是请求证书扩展中的内容。换句话说就是证书链的安全性是由硬件保证,需要依赖外部CA:BootROM保证证书链必须经过验证,证书链的源头是由信任根公钥保证。
ATF中BL1阶段主要是验证BL2镜像,信任链实施如下,包括可信启动证书和BL2镜像认证定义,位于tbbr_cot_common.c
和tbbr_cot_bl1.c
文件中,这里暂不关注其他配置镜像。
可信启动证书的认证镜像描述如下:
/* trusted_boot_fw_cert */ 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]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &subject_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .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 } }, } };
而BL2镜像的认证描述如下:
static const auth_img_desc_t bl2_image = {
.img_id = BL2_IMAGE_ID,
.img_type = IMG_RAW,
.parent = &trusted_boot_fw_cert,
.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
[0] = {
.type = AUTH_METHOD_HASH,
.param.hash = {
.data = &raw_data,
.hash = &tb_fw_hash
}
}
}
};
ATF中BL2阶段主要是验证BL3x镜像,信任链实施如下,包括可信密钥证书,BL3x密钥证书和内容证书,位于tbbr_cot_bl2.c
文件中。
可信密钥证书trusted_key_cert定义如下,同BL1可信启动证书一样,认证方法为验签和NV计数器比较,由于没有父镜像,因此该证书验签也由信任根公钥ROTPK进行验证。证书认证通过后,可以从中提取安全和非安全世界公钥trusted_world_pk和non_trusted_world_pk,用于验证后续镜像的密钥证书。
/* * Trusted key certificate */ static const auth_img_desc_t trusted_key_cert = { .img_id = TRUSTED_KEY_CERT_ID, .img_type = IMG_CERT, .parent = NULL, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &subject_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &trusted_world_pk, .data = { .ptr = (void *)trusted_world_pk_buf, .len = (unsigned int)PK_DER_LEN } }, [1] = { .type_desc = &non_trusted_world_pk, .data = { .ptr = (void *)non_trusted_world_pk_buf, .len = (unsigned int)PK_DER_LEN } } } };
BL31的信任链CoT定义如下,包括密钥证书soc_fw_key_cert、内容证书soc_fw_content_cert和镜像bl31_image以及配置soc_fw_config(这里暂不去关注)。
/* * SoC Firmware */ static const auth_img_desc_t soc_fw_key_cert = { .img_id = SOC_FW_KEY_CERT_ID, .img_type = IMG_CERT, .parent = &trusted_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &trusted_world_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &soc_fw_content_pk, .data = { .ptr = (void *)content_pk_buf, .len = (unsigned int)PK_DER_LEN } } } }; static const auth_img_desc_t soc_fw_content_cert = { .img_id = SOC_FW_CONTENT_CERT_ID, .img_type = IMG_CERT, .parent = &soc_fw_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &soc_fw_content_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &soc_fw_hash, .data = { .ptr = (void *)soc_fw_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [1] = { .type_desc = &soc_fw_config_hash, .data = { .ptr = (void *)soc_fw_config_hash_buf, .len = (unsigned int)HASH_DER_LEN } } } }; static const auth_img_desc_t bl31_image = { .img_id = BL31_IMAGE_ID, .img_type = IMG_RAW, .parent = &soc_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &soc_fw_hash } } } };
同理再看一下BL33的信任链定义,类似也包括密钥证书non_trusted_fw_key_cert、内容证书non_trusted_fw_content_cert和镜像bl33_image。
/* * Non-Trusted Firmware */ static const auth_img_desc_t non_trusted_fw_key_cert = { .img_id = NON_TRUSTED_FW_KEY_CERT_ID, .img_type = IMG_CERT, .parent = &trusted_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &non_trusted_world_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &non_trusted_nv_ctr, .plat_nv_ctr = &non_trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &nt_fw_content_pk, .data = { .ptr = (void *)content_pk_buf, .len = (unsigned int)PK_DER_LEN } } } }; static const auth_img_desc_t non_trusted_fw_content_cert = { .img_id = NON_TRUSTED_FW_CONTENT_CERT_ID, .img_type = IMG_CERT, .parent = &non_trusted_fw_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &nt_fw_content_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &non_trusted_nv_ctr, .plat_nv_ctr = &non_trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &nt_world_bl_hash, .data = { .ptr = (void *)nt_world_bl_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [1] = { .type_desc = &nt_fw_config_hash, .data = { .ptr = (void *)nt_fw_config_hash_buf, .len = (unsigned int)HASH_DER_LEN } } } }; static const auth_img_desc_t bl33_image = { .img_id = BL33_IMAGE_ID, .img_type = IMG_RAW, .parent = &non_trusted_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &nt_world_bl_hash } } } };
安全启动的镜像加载认证函数为load_auth_image_recursive
,其会递归认证父镜像,直到信任根。首先通过信任链CoT定义判断该镜像是否有父镜像,如果有则需要先认证父镜像,然后加载镜像,最后调用auth_mod_verify_img函数认证该镜像。
/* * This function uses recursion to authenticate the parent images up to the root * of trust. */ static int load_auth_image_recursive(unsigned int image_id, image_info_t *image_data, int is_parent_image) { int rc; unsigned int parent_id; /* Use recursion to authenticate parent images */ rc = auth_mod_get_parent_id(image_id, &parent_id); if (rc == 0) { rc = load_auth_image_recursive(parent_id, image_data, 1); if (rc != 0) { return rc; } } /* Load the image */ rc = load_image(image_id, image_data); if (rc != 0) { return rc; } /* Authenticate it */ rc = auth_mod_verify_img(image_id, (void *)image_data->image_base, image_data->image_size); if (rc != 0) { /* Authentication error, zero memory and flush it right away. */ zero_normalmem((void *)image_data->image_base, image_data->image_size); flush_dcache_range(image_data->image_base, image_data->image_size); return -EAUTH; } return 0; }
镜像认证最终的函数为auth_mod_verify_img,既可认证证书,也可认证镜像。
/* * Authenticate a certificate/image * * Return: 0 = success, Otherwise = error */ int auth_mod_verify_img(unsigned int img_id, void *img_ptr, unsigned int img_len) { const auth_img_desc_t *img_desc = NULL; const auth_method_desc_t *auth_method = NULL; void *param_ptr; unsigned int param_len; int rc, i; unsigned int cert_nv_ctr = 0; bool need_nv_ctr_upgrade = false; bool sig_auth_done = false; const auth_method_param_nv_ctr_t *nv_ctr_param = NULL; /* Get the image descriptor from the chain of trust */ img_desc = FCONF_GET_PROPERTY(tbbr, cot, img_id); /* Ask the parser to check the image integrity */ rc = img_parser_check_integrity(img_desc->img_type, img_ptr, img_len); return_if_error(rc); /* Authenticate the image using the methods indicated in the image * descriptor. */ if (img_desc->img_auth_methods == NULL) return 1; for (i = 0 ; i < AUTH_METHOD_NUM ; i++) { auth_method = &img_desc->img_auth_methods[i]; switch (auth_method->type) { case AUTH_METHOD_NONE: rc = 0; break; case AUTH_METHOD_HASH: rc = auth_hash(&auth_method->param.hash, img_desc, img_ptr, img_len); break; case AUTH_METHOD_SIG: rc = auth_signature(&auth_method->param.sig, img_desc, img_ptr, img_len); sig_auth_done = true; break; case AUTH_METHOD_NV_CTR: nv_ctr_param = &auth_method->param.nv_ctr; rc = auth_nvctr(nv_ctr_param, img_desc, img_ptr, img_len, &cert_nv_ctr, &need_nv_ctr_upgrade); break; default: /* Unknown authentication method */ rc = 1; break; } return_if_error(rc); } /* * Do platform NV counter upgrade only if the certificate gets * authenticated, and platform NV-counter upgrade is needed. */ if (need_nv_ctr_upgrade && sig_auth_done) { rc = plat_set_nv_ctr2(nv_ctr_param->plat_nv_ctr->cookie, img_desc, cert_nv_ctr); return_if_error(rc); } /* Extract the parameters indicated in the image descriptor to * authenticate the children images. */ if (img_desc->authenticated_data != NULL) { for (i = 0 ; i < COT_MAX_VERIFIED_PARAMS ; i++) { if (img_desc->authenticated_data[i].type_desc == NULL) { continue; } /* Get the parameter from the image parser module */ rc = img_parser_get_auth_param(img_desc->img_type, img_desc->authenticated_data[i].type_desc, img_ptr, img_len, ¶m_ptr, ¶m_len); return_if_error(rc); /* Check parameter size */ if (param_len > img_desc->authenticated_data[i].data.len) { return 1; } /* Copy the parameter for later use */ memcpy((void *)img_desc->authenticated_data[i].data.ptr, (void *)param_ptr, param_len); } } /* Mark image as authenticated */ auth_img_flags[img_desc->img_id] |= IMG_FLAG_AUTHENTICATED; return 0; }
认证哈希是通过比较哈希值是否一致,一个是计算镜像得到的哈希值,一个是从父镜像提取的可信哈希值(包括哈希算法)。
static int auth_hash(const auth_method_param_hash_t *param, const auth_img_desc_t *img_desc, void *img, unsigned int img_len) { void *data_ptr, *hash_der_ptr; unsigned int data_len, hash_der_len; int rc = 0; /* Get the hash from the parent image. This hash will be DER encoded * and contain the hash algorithm */ rc = auth_get_param(param->hash, img_desc->parent, &hash_der_ptr, &hash_der_len); return_if_error(rc); /* Get the data to be hashed from the 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); /* Ask the crypto module to verify this hash */ rc = crypto_mod_verify_hash(data_ptr, data_len, hash_der_ptr, hash_der_len); return rc; }
verify_hash
函数认证签名是公钥验证镜像的签名值,需要以下参数:
如果父镜像只包含公钥的哈希,则需要从待认证的镜像中提取公钥值(即自签名的证书),并计算该公钥的哈希值,与父镜像中获取的哈希值进行比较。如果镜像没有父镜像,则需要用OTP中存储的ROTPK进行验签。
对于使用X509证书方式的镜像解析方式而言,auth_signature函数只会针对于镜像类型为证书IMG_CERT。
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); 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 { /* 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); } } 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; }
crypto_mod_verify_signature
进行验签操作,即调用底层的verify_signature
函数,如果公钥就是实际的值,则直接进行验签操作crypto_mod_verify_hash
,以此来判断公钥是否可信认证NV计数器是系统防回滚设计,这个计数器只能递增并且存储在一次性存储器如OTP中,所有证书中的计数器必须比平台存储的大,即不能升级版本低的固件(防回滚)。
static int auth_nvctr(const auth_method_param_nv_ctr_t *param, const auth_img_desc_t *img_desc, void *img, unsigned int img_len, unsigned int *cert_nv_ctr, bool *need_nv_ctr_upgrade) { unsigned char *p; void *data_ptr = NULL; unsigned int data_len, len, i; unsigned int plat_nv_ctr; int rc = 0; bool is_trial_run = false; /* Get the counter value from current image. The AM expects the IPM * to return the counter value as a DER encoded integer */ rc = img_parser_get_auth_param(img_desc->img_type, param->cert_nv_ctr, img, img_len, &data_ptr, &data_len); return_if_error(rc); /* Parse the DER encoded integer */ assert(data_ptr); p = (unsigned char *)data_ptr; /* * Integers must be at least 3 bytes: 1 for tag, 1 for length, and 1 * for value. The first byte (tag) must be ASN1_INTEGER. */ if ((data_len < 3) || (*p != ASN1_INTEGER)) { /* Invalid ASN.1 integer */ return 1; } p++; /* * NV-counters are unsigned integers up to 31 bits. Trailing * padding is not allowed. */ len = (unsigned int)*p; if ((len > 4) || (data_len - 2 != len)) { return 1; } p++; /* Check the number is not negative */ if (*p & 0x80) { return 1; } /* Convert to unsigned int. This code is for a little-endian CPU */ *cert_nv_ctr = 0; for (i = 0; i < len; i++) { *cert_nv_ctr = (*cert_nv_ctr << 8) | *p++; } /* Get the counter from the platform */ rc = plat_get_nv_ctr(param->plat_nv_ctr->cookie, &plat_nv_ctr); return_if_error(rc); if (*cert_nv_ctr < plat_nv_ctr) { /* Invalid NV-counter */ return 1; } else if (*cert_nv_ctr > plat_nv_ctr) { #if PSA_FWU_SUPPORT && IMAGE_BL2 is_trial_run = fwu_is_trial_run_state(); #endif /* PSA_FWU_SUPPORT && IMAGE_BL2 */ *need_nv_ctr_upgrade = !is_trial_run; } return 0; }
上面认证流程用到的哈希、验签和解密都是基于底层的密码算法库。ATF默认使用的是mbedtls密码算法库。在底层的密码模块中,注册了验签、哈希验证以及认证解密函数。
REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash,
auth_decrypt);
另外对于镜像解析模块,也注册了镜像完整性校验和认证参数解析函数。认证需要的参数如镜像哈希值、公钥等都是存储在X509证书中,在使用这些参数之前,需要从证书中解析出来(ASN.1编码的结构)。
REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \
check_integrity, get_auth_param);
最后以BL31镜像为例总结一下安全启动认证的设计。BL31信任链中包括ROTPK信任根公钥(或者哈希)、Trusted Key Certificate可信密钥证书、Trusted World Public key安全世界公钥、BL31 Key Certificate密钥证书、BL31 Content Certificate PK内容证书公钥、BL31 Content Certificate内容证书和BL31 Image镜像。
+------------------+ +-------------------+ | ROTPK/ROTPK Hash |------>| Trusted Key | +------------------+ | Certificate | | (Auth Image) | /+-------------------+ / | / | / | / | L v +------------------+ +-------------------+ | Trusted World |------>| BL31 Key | | Public Key | | Certificate | +------------------+ | (Auth Image) | +-------------------+ / | / | / | / | / v +------------------+ L +-------------------+ | BL31 Content |------>| BL31 Content | | Certificate PK | | Certificate | +------------------+ | (Auth Image) | +-------------------+ / | / | / | / | / v +------------------+ L +-------------------+ | BL31 Hash |------>| BL31 Image | | | | (Data Image) | +------------------+ | | +-------------------+
因此BL31镜像的认证链如下。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。