/* * (C) Copyright 2017 Rockchip Electronics Co., Ltd * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* rk used */ int rk_avb_get_pub_key(struct rk_pub_key *pub_key) { struct tag *t = NULL; t = atags_get_tag(ATAG_PUB_KEY); if (!t) return -1; memcpy(pub_key, t->u.pub_key.data, sizeof(struct rk_pub_key)); return 0; } int rk_avb_get_perm_attr_cer(uint8_t *cer, uint32_t size) { #ifdef CONFIG_OPTEE_CLIENT if (trusty_read_permanent_attributes_cer((uint8_t *)cer, size)) { printf("AVB: perm attr cer is not exist.\n"); return -EIO; } return 0; #else return -1; #endif } int rk_avb_set_perm_attr_cer(uint8_t *cer, uint32_t size) { #ifdef CONFIG_OPTEE_CLIENT if (trusty_write_permanent_attributes_cer((uint8_t *)cer, size)) return -EIO; return 0; #else return -1; #endif } int rk_avb_read_permanent_attributes(uint8_t *attributes, uint32_t size) { #ifdef CONFIG_OPTEE_CLIENT if(trusty_read_permanent_attributes(attributes, size) != 0) { printf("trusty_read_permanent_attributes failed!\n"); return -1; } return 0; #else return -1; #endif } int rk_avb_write_permanent_attributes(uint8_t *attributes, uint32_t size) { #ifdef CONFIG_OPTEE_CLIENT if(trusty_write_permanent_attributes(attributes, size) != 0) { printf("trusty_write_permanent_attributes failed!\n"); return -1; } return 0; #else return -1; #endif } int rk_avb_read_flash_lock_state(uint8_t *flash_lock_state) { #ifdef CONFIG_OPTEE_CLIENT int ret; ret = trusty_read_flash_lock_state(flash_lock_state); switch (ret) { case TEE_SUCCESS: break; case TEE_ERROR_GENERIC: case TEE_ERROR_NO_DATA: case TEE_ERROR_ITEM_NOT_FOUND: *flash_lock_state = 1; if (trusty_write_flash_lock_state(*flash_lock_state)) { printf("trusty_write_flash_lock_state error!"); ret = -1; } else { ret = trusty_read_flash_lock_state(flash_lock_state); } break; default: printf("%s: trusty_read_flash_lock_state failed\n", __FILE__); } return ret; #else *flash_lock_state = 1; return 0; #endif } int rk_avb_write_flash_lock_state(uint8_t flash_lock_state) { #ifdef CONFIG_OPTEE_CLIENT if (trusty_write_flash_lock_state(flash_lock_state)) { printf("trusty_write_flash_lock_state error!\n"); return -1; } return 0; #else return -1; #endif } int rk_avb_write_lock_state(uint8_t lock_state) { #ifdef CONFIG_OPTEE_CLIENT if (trusty_write_lock_state(lock_state)) { printf("trusty_write_lock_state error!\n"); return -1; } return 0; #else return -1; #endif } int rk_avb_read_lock_state(uint8_t *lock_state) { #ifdef CONFIG_OPTEE_CLIENT uint8_t vboot_flag = 0; int ret; ret = trusty_read_lock_state(lock_state); switch (ret) { case TEE_SUCCESS: break; case TEE_ERROR_GENERIC: case TEE_ERROR_NO_DATA: case TEE_ERROR_ITEM_NOT_FOUND: if (trusty_read_vbootkey_enable_flag(&vboot_flag)) { printf("Can't read vboot flag\n"); return -1; } if (vboot_flag) *lock_state = 0; else *lock_state = 1; if (rk_avb_write_lock_state(*lock_state)) { printf("avb_write_lock_state error!"); ret = -1; } else { ret = trusty_read_lock_state(lock_state); } break; default: printf("%s: trusty_read_lock_state failed\n", __FILE__); } return ret; #else return -1; #endif } int rk_avb_write_perm_attr_flag(uint8_t flag) { #ifdef CONFIG_OPTEE_CLIENT if (trusty_write_permanent_attributes_flag(flag)) { printf("trusty_write_permanent_attributes_flag error!\n"); return -1; } return 0; #else return -1; #endif } int rk_avb_read_perm_attr_flag(uint8_t *flag) { #ifdef CONFIG_OPTEE_CLIENT int ret; ret = trusty_read_permanent_attributes_flag(flag); switch (ret) { case TEE_SUCCESS: break; case TEE_ERROR_GENERIC: case TEE_ERROR_NO_DATA: case TEE_ERROR_ITEM_NOT_FOUND: *flag = 0; if (rk_avb_write_perm_attr_flag(*flag)) { printf("avb_write_perm_attr_flag error!"); ret = -1; } else { ret = trusty_read_permanent_attributes_flag(flag); } break; default: printf("%s: trusty_read_permanent_attributes_flag failed", __FILE__); } return ret; #else return -1; #endif } int rk_avb_read_vbootkey_hash(uint8_t *buf, uint8_t length) { #ifdef CONFIG_OPTEE_CLIENT if (trusty_read_vbootkey_hash((uint32_t *)buf, (uint32_t)length / sizeof(uint32_t))) { printf("trusty_read_vbootkey_hash error!\n"); return -1; } return 0; #else return -1; #endif } int rk_avb_write_vbootkey_hash(uint8_t *buf, uint8_t length) { #ifdef CONFIG_OPTEE_CLIENT if (trusty_write_vbootkey_hash((uint32_t *)buf, (uint32_t)length / sizeof(uint32_t))) { printf("trusty_write_vbootkey_hash error!\n"); return -1; } return 0; #else return -1; #endif } int rk_avb_close_optee_client(void) { #ifdef CONFIG_OPTEE_CLIENT if(trusty_notify_optee_uboot_end()) { printf("trusty_notify_optee_uboot_end error!\n"); return -1; } return 0; #else return -1; #endif } int rk_avb_read_attribute_hash(uint8_t *buf, uint8_t length) { #ifdef CONFIG_OPTEE_CLIENT if (trusty_read_attribute_hash((uint32_t *)buf, (uint32_t)(length/sizeof(uint32_t)))) { printf("trusty_read_attribute_hash error!\n"); return -1; } return 0; #else return -1; #endif } int rk_avb_write_attribute_hash(uint8_t *buf, uint8_t length) { #ifdef CONFIG_OPTEE_CLIENT if (trusty_write_attribute_hash((uint32_t *)buf, (uint32_t)(length/sizeof(uint32_t)))) { printf("trusty_write_attribute_hash error!\n"); return -1; } return 0; #else return -1; #endif } int rk_avb_read_all_rollback_index(char *buffer) { AvbOps* ops; uint64_t stored_rollback_index = 0; AvbIOResult io_ret; char temp[ROLLBACK_MAX_SIZE] = {0}; ops = avb_ops_user_new(); if (ops == NULL) { printf("avb_ops_user_new() failed!\n"); return -1; } /* Actually the rollback_index_location 0 is used. */ io_ret = ops->read_rollback_index(ops, 0, &stored_rollback_index); if (io_ret != AVB_IO_RESULT_OK) goto out; snprintf(temp, sizeof(int) + 1, "%d", 0); strncat(buffer, temp, ROLLBACK_MAX_SIZE); strncat(buffer, ":", 1); snprintf(temp, sizeof(uint64_t) + 1, "%lld", stored_rollback_index); strncat(buffer, temp, ROLLBACK_MAX_SIZE); strncat(buffer, ",", 1); io_ret = ops->read_rollback_index(ops, AVB_ATX_PIK_VERSION_LOCATION, &stored_rollback_index); if (io_ret != AVB_IO_RESULT_OK) { printf("Failed to read PIK minimum version.\n"); goto out; } /* PIK rollback index */ snprintf(temp, sizeof(int) + 1, "%d", AVB_ATX_PIK_VERSION_LOCATION); strncat(buffer, temp, ROLLBACK_MAX_SIZE); strncat(buffer, ":", 1); snprintf(temp, sizeof(uint64_t) + 1, "%lld", stored_rollback_index); strncat(buffer, temp, ROLLBACK_MAX_SIZE); strncat(buffer, ",", 1); io_ret = ops->read_rollback_index(ops, AVB_ATX_PSK_VERSION_LOCATION, &stored_rollback_index); if (io_ret != AVB_IO_RESULT_OK) { printf("Failed to read PSK minimum version.\n"); goto out; } /* PSK rollback index */ snprintf(temp, sizeof(int) + 1, "%d", AVB_ATX_PSK_VERSION_LOCATION); strncat(buffer, temp, ROLLBACK_MAX_SIZE); strncat(buffer, ":", 1); snprintf(temp, sizeof(uint64_t) + 1, "%lld", stored_rollback_index); strncat(buffer, temp, ROLLBACK_MAX_SIZE); debug("%s\n", buffer); avb_ops_user_free(ops); return 0; out: avb_ops_user_free(ops); return -1; } int rk_avb_read_bootloader_locked_flag(uint8_t *flag) { #ifdef CONFIG_OPTEE_CLIENT if (trusty_read_vbootkey_enable_flag(flag)) return -1; #endif return 0; } #ifdef CONFIG_SUPPORT_EMMC_RPMB static int curr_device = -1; int rk_bootloader_rollback_index_read(uint32_t offset, uint32_t bytes, void *rb_index) { struct mmc *mmc; uint8_t rpmb_buf[256] = {0}; uint32_t n; char original_part; if ((offset + bytes) > 256) return -1; if (curr_device < 0) { if (get_mmc_num() > 0) curr_device = 0; else { printf("No MMC device available"); return -1; } } mmc = find_mmc_device(curr_device); /* Switch to the RPMB partition */ #ifndef CONFIG_BLK original_part = mmc->block_dev.hwpart; #else original_part = mmc_get_blk_desc(mmc)->hwpart; #endif if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, MMC_PART_RPMB) != 0) return -1; n = mmc_rpmb_read(mmc, rpmb_buf, RPMB_BASE_ADDR, 1, NULL); if (n != 1) return -1; /* Return to original partition */ if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, original_part) != 0) return -1; memcpy(rb_index, (void*)&rpmb_buf[offset], bytes); return 0; } int rk_avb_get_bootloader_min_version(char *buffer) { uint32_t rb_index; char temp[ROLLBACK_MAX_SIZE] = {0}; if (rk_bootloader_rollback_index_read(UBOOT_RB_INDEX_OFFSET, sizeof(uint32_t), &rb_index)) { printf("Can not read uboot rollback index"); return -1; } snprintf(temp, sizeof(int) + 1, "%d", 0); strncat(buffer, temp, ROLLBACK_MAX_SIZE); strncat(buffer, ":", 1); snprintf(temp, sizeof(uint32_t) + 1, "%d", rb_index); strncat(buffer, temp, ROLLBACK_MAX_SIZE); strncat(buffer, ",", 1); if (rk_bootloader_rollback_index_read(TRUST_RB_INDEX_OFFSET, sizeof(uint32_t), &rb_index)) { printf("Can not read trust rollback index"); return -1; } snprintf(temp, sizeof(int) + 1, "%d", 1); strncat(buffer, temp, ROLLBACK_MAX_SIZE); strncat(buffer, ":", 1); snprintf(temp, sizeof(uint32_t) + 1, "%d", rb_index); strncat(buffer, temp, ROLLBACK_MAX_SIZE); return 0; } #endif void rk_avb_get_at_vboot_state(char *buf) { char temp_flag = 0; char *lock_val = NULL; char *unlock_dis_val = NULL; char *perm_attr_flag = NULL; char *bootloader_locked_flag = NULL; char *rollback_indices; char min_versions[ROLLBACK_MAX_SIZE + 1] = {0}; int n; if (rk_avb_read_perm_attr_flag((uint8_t *)&temp_flag)) { printf("Can not read perm_attr_flag!"); perm_attr_flag = ""; } else { perm_attr_flag = temp_flag ? "1" : "0"; } temp_flag = 0; if (rk_avb_read_lock_state((uint8_t *)&temp_flag)) { printf("Can not read lock state!"); lock_val = ""; unlock_dis_val = ""; } else { lock_val = (temp_flag & LOCK_MASK) ? "0" : "1"; unlock_dis_val = (temp_flag & UNLOCK_DISABLE_MASK) ? "1" : "0"; } temp_flag = 0; if (rk_avb_read_bootloader_locked_flag((uint8_t *)&temp_flag)) { printf("Can not read bootloader locked flag!"); bootloader_locked_flag = ""; } else { bootloader_locked_flag = temp_flag ? "1" : "0"; } rollback_indices = malloc(VBOOT_STATE_SIZE); if (!rollback_indices) { printf("No buff to malloc!"); return; } memset(rollback_indices, 0, VBOOT_STATE_SIZE); if (rk_avb_read_all_rollback_index(rollback_indices)) printf("Can not read avb_min_ver!"); #ifdef CONFIG_SUPPORT_EMMC_RPMB /* bootloader-min-versions */ if (rk_avb_get_bootloader_min_version(min_versions)) printf("Call rk_avb_get_bootloader_min_version error!"); #endif n = snprintf(buf, VBOOT_STATE_SIZE - 1, "avb-perm-attr-set=%s\n" "avb-locked=%s\n" "avb-unlock-disabled=%s\n" "bootloader-locked=%s\n" "avb-min-versions=%s\n" "bootloader-min-versions=%s\n", perm_attr_flag, lock_val, unlock_dis_val, bootloader_locked_flag, rollback_indices, min_versions); if (n >= VBOOT_STATE_SIZE) { printf("The VBOOT_STATE buf is truncated\n"); buf[VBOOT_STATE_SIZE - 1] = 0; } debug("The vboot state buf is %s\n", buf); free(rollback_indices); } int rk_avb_get_ab_info(AvbABData* ab_data) { AvbOps* ops; AvbIOResult io_ret = AVB_IO_RESULT_OK; int ret = 0; ops = avb_ops_user_new(); if (ops == NULL) { printf("%s: avb_ops_user_new() failed!\n", __FILE__); return -1; } io_ret = ops->ab_ops->read_ab_metadata(ops->ab_ops, ab_data); if (io_ret != AVB_IO_RESULT_OK) { printf("I/O error while loading A/B metadata.\n"); ret = -1; } avb_ops_user_free(ops); return ret; } int rk_avb_get_part_has_slot_info(const char *base_name) { char *part_name; int part_num; size_t part_name_len; disk_partition_t part_info; struct blk_desc *dev_desc; const char *slot_suffix = "_a"; dev_desc = rockchip_get_bootdev(); if (!dev_desc) { printf("%s: Could not find device!\n", __func__); return -1; } if (base_name == NULL) { printf("The base_name is NULL!\n"); return -1; } part_name_len = strlen(base_name) + 1; part_name_len += strlen(slot_suffix); part_name = malloc(part_name_len); if (!part_name) { printf("%s can not malloc a buffer!\n", __FILE__); return -1; } memset(part_name, 0, part_name_len); snprintf(part_name, part_name_len, "%s%s", base_name, slot_suffix); part_num = part_get_info_by_name(dev_desc, part_name, &part_info); if (part_num < 0) { printf("Could not find partition \"%s\"\n", part_name); part_num = -1; } free(part_name); return part_num; } int rk_auth_unlock(void *buffer, char *out_is_trusted) { AvbOps* ops; ops = avb_ops_user_new(); if (ops == NULL) { printf("avb_ops_user_new() failed!"); return -1; } if (avb_atx_validate_unlock_credential(ops->atx_ops, (AvbAtxUnlockCredential*)buffer, (bool*)out_is_trusted)) { avb_ops_user_free(ops); return -1; } avb_ops_user_free(ops); if (*out_is_trusted == true) return 0; else return -1; } int rk_generate_unlock_challenge(void *buffer, uint32_t *challenge_len) { AvbOps* ops; AvbIOResult result = AVB_IO_RESULT_OK; ops = avb_ops_user_new(); if (ops == NULL) { printf("avb_ops_user_new() failed!"); return -1; } result = avb_atx_generate_unlock_challenge(ops->atx_ops, (AvbAtxUnlockChallenge *)buffer); avb_ops_user_free(ops); *challenge_len = sizeof(AvbAtxUnlockChallenge); if (result == AVB_IO_RESULT_OK) return 0; else return -1; } int rk_avb_init_ab_metadata(void) { AvbOps *ops; AvbABData ab_data; memset(&ab_data, 0, sizeof(AvbABData)); debug("sizeof(AvbABData) = %d\n", (int)(size_t)sizeof(AvbABData)); ops = avb_ops_user_new(); if (ops == NULL) { printf("avb_ops_user_new() failed!\n"); return -1; } avb_ab_data_init(&ab_data); if (ops->ab_ops->write_ab_metadata(ops->ab_ops, &ab_data) != 0) { printf("do_avb_init_ab_metadata error!\n"); avb_ops_user_free(ops); return -1; } printf("Initialize ab data to misc partition success.\n"); avb_ops_user_free(ops); return 0; } #define AT_PERM_ATTR_FUSE 1 #define AT_PERM_ATTR_CER_FUSE 2 #define AT_LOCK_VBOOT 3 int rk_avb_write_perm_attr(u16 id, void *pbuf, u16 size) { uint8_t lock_state; #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY sha256_context ctx; uint8_t digest[SHA256_SUM_LEN] = {0}; uint8_t digest_temp[SHA256_SUM_LEN] = {0}; uint8_t perm_attr_temp[PERM_ATTR_TOTAL_SIZE] = {0}; uint8_t flag = 0; #endif switch (id) { case AT_PERM_ATTR_FUSE: if (size != PERM_ATTR_TOTAL_SIZE) { debug("%s Permanent attribute size is not equal!\n", __func__); return -EINVAL; } #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY if (rk_avb_read_perm_attr_flag(&flag)) { debug("%s rk_avb_read_perm_attr_flag error!\n", __func__); return -EIO; } if (flag == PERM_ATTR_SUCCESS_FLAG) { if (rk_avb_read_attribute_hash(digest_temp, SHA256_SUM_LEN)) { debug("%s The efuse IO can not be used!\n", __func__); return -EIO; } if (memcmp(digest, digest_temp, SHA256_SUM_LEN) != 0) { if (rk_avb_read_permanent_attributes(perm_attr_temp, PERM_ATTR_TOTAL_SIZE)) { debug("%s rk_avb_write_permanent_attributes error!\n", __func__); return -EIO; } sha256_starts(&ctx); sha256_update(&ctx, (const uint8_t *)perm_attr_temp, PERM_ATTR_TOTAL_SIZE); sha256_finish(&ctx, digest); if (memcmp(digest, digest_temp, SHA256_SUM_LEN) == 0) { debug("%s The hash has been written!\n", __func__); return 0; } } if (rk_avb_write_perm_attr_flag(0)) { debug("%s Perm attr flag write failure\n", __func__); return -EIO; } } #endif if (rk_avb_write_permanent_attributes((uint8_t *) pbuf, size)) { if (rk_avb_write_perm_attr_flag(0)) { debug("%s Perm attr flag write failure\n", __func__); return -EIO; } debug("%s Perm attr write failed\n", __func__); return -EIO; } #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY memset(digest, 0, SHA256_SUM_LEN); sha256_starts(&ctx); sha256_update(&ctx, (const uint8_t *)pbuf, PERM_ATTR_TOTAL_SIZE); sha256_finish(&ctx, digest); if (rk_avb_write_attribute_hash((uint8_t *)digest, SHA256_SUM_LEN)) { if (rk_avb_read_attribute_hash(digest_temp, SHA256_SUM_LEN)) { debug("%s The efuse IO can not be used!\n", __func__); return -EIO; } if (memcmp(digest, digest_temp, SHA256_SUM_LEN) != 0) { if (rk_avb_write_perm_attr_flag(0)) { debug("%s Perm attr flag write failure\n", __func__); return -EIO; } debug("%s The hash has been written, but is different!\n", __func__); return -EIO; } } #endif if (rk_avb_write_perm_attr_flag(PERM_ATTR_SUCCESS_FLAG)) { debug("%s, Perm attr flag write failure\n", __func__); return -EIO; } break; case AT_PERM_ATTR_CER_FUSE: if (size != 256) { debug("%s Permanent attribute rsahash size is not equal!\n", __func__); return -EINVAL; } if (rk_avb_set_perm_attr_cer((uint8_t *)pbuf, size)) { debug("%s FAILSet perm attr cer fail!\n", __func__); return -EIO; } break; case AT_LOCK_VBOOT: lock_state = 0; if (rk_avb_write_lock_state(lock_state)) { debug("%s FAILwrite lock state failed\n", __func__); return -EIO; } else { debug("%s OKAY\n", __func__); } break; } return 0; } int rk_avb_read_perm_attr(u16 id, void *pbuf, u16 size) { int ret = 0; debug("%s %d\n", __func__, size); switch (id) { case AT_PERM_ATTR_FUSE: size = PERM_ATTR_TOTAL_SIZE; ret = rk_avb_read_permanent_attributes((uint8_t *)pbuf, PERM_ATTR_TOTAL_SIZE); break; case AT_PERM_ATTR_CER_FUSE: size = PERM_ATTR_TOTAL_SIZE; ret = rk_avb_get_perm_attr_cer((uint8_t *)pbuf, 256); break; case AT_LOCK_VBOOT: break; } return ret; } int rk_avb_update_stored_rollback_indexes_for_slot(AvbOps* ops, AvbSlotVerifyData* slot_data) { uint64_t rollback_index = slot_data->rollback_indexes[0]; uint64_t current_stored_rollback_index; AvbIOResult io_ret; if (rollback_index > 0) { io_ret = ops->read_rollback_index(ops, 0, ¤t_stored_rollback_index); if (io_ret != AVB_IO_RESULT_OK) return -1; if (rollback_index > current_stored_rollback_index) { io_ret = ops->write_rollback_index(ops, 0, rollback_index); if (io_ret != AVB_IO_RESULT_OK) return -1; } } return 0; }