// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd */ #include #include #include #include #include #include #include #include #include #include #define STORAGE_CMD_WRITE 6 #define SIZE_OF_TAG 4 #define BOOT_FROM_EMMC (1 << 1) #define WIDEVINE_TAG "KBOX" #define ATTESTATION_TAG "ATTE" #define ID_ATTESTATION_TAG "IDAT" #define PLAYREADY30_TAG "SL30" TEEC_Result write_to_security_storage(uint8_t is_use_rpmb, uint8_t *filename, uint32_t filename_size, uint8_t *data, uint32_t data_size) { TEEC_Result TeecResult; TEEC_Context TeecContext; TEEC_Session TeecSession; TEEC_SharedMemory SharedMem0 = {0}; TEEC_SharedMemory SharedMem1 = {0}; uint32_t ErrorOrigin; TEEC_UUID tempuuid = { 0x1b484ea5, 0x698b, 0x4142, { 0x82, 0xb8, 0x3a, 0xcf, 0x16, 0xe9, 0x9e, 0x2a } }; TEEC_UUID *TeecUuid = &tempuuid; TEEC_Operation TeecOperation = {0}; TeecResult = OpteeClientApiLibInitialize(); if (TeecResult) { printf("OpteeClientApiLibInitialize fail\n"); return TeecResult; } TeecResult = TEEC_InitializeContext(NULL, &TeecContext); if (TeecResult) { printf("TEEC_InitializeContext fail\n"); return TeecResult; } TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); /*0 nand or emmc "security" partition , 1 rpmb*/ TeecOperation.params[0].value.a = is_use_rpmb; TeecResult = TEEC_OpenSession(&TeecContext, &TeecSession, TeecUuid, TEEC_LOGIN_PUBLIC, NULL, &TeecOperation, &ErrorOrigin); if (TeecResult) { printf("TEEC_OpenSession fail\n"); return TeecResult; } SharedMem0.size = filename_size; SharedMem0.flags = 0; TeecResult = TEEC_AllocateSharedMemory(&TeecContext, &SharedMem0); if (TeecResult) { printf("TEEC_AllocateSharedMemory fail\n"); return TeecResult; } memcpy(SharedMem0.buffer, filename, SharedMem0.size); SharedMem1.size = data_size; SharedMem1.flags = 0; TeecResult = TEEC_AllocateSharedMemory(&TeecContext, &SharedMem1); if (TeecResult) { printf("TEEC_AllocateSharedMemory fail\n"); return TeecResult; } memcpy(SharedMem1.buffer, data, SharedMem1.size); TeecOperation.params[0].tmpref.buffer = SharedMem0.buffer; TeecOperation.params[0].tmpref.size = SharedMem0.size; TeecOperation.params[1].tmpref.buffer = SharedMem1.buffer; TeecOperation.params[1].tmpref.size = SharedMem1.size; TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_INOUT, TEEC_NONE, TEEC_NONE); TeecResult = TEEC_InvokeCommand(&TeecSession, 1, &TeecOperation, &ErrorOrigin); if (TeecResult) { printf("TEEC_InvokeCommand fail\n"); return TeecResult; } TEEC_ReleaseSharedMemory(&SharedMem0); TEEC_ReleaseSharedMemory(&SharedMem1); TEEC_CloseSession(&TeecSession); TEEC_FinalizeContext(&TeecContext); debug("TeecResult %x\n", TeecResult); return TeecResult; } uint32_t rk_send_keybox_to_ta(uint8_t *filename, uint32_t filename_size, TEEC_UUID uuid, uint8_t *key, uint32_t key_size, uint8_t *data, uint32_t data_size) { uint32_t ErrorOrigin; TEEC_Result TeecResult; TEEC_Context TeecContext; TEEC_Session TeecSession; TEEC_UUID *TeecUuid = &uuid; TEEC_Operation TeecOperation = {0}; TEEC_SharedMemory SharedMem0 = {0}; TEEC_SharedMemory SharedMem1 = {0}; TEEC_SharedMemory SharedMem2 = {0}; struct blk_desc *dev_desc; dev_desc = rockchip_get_bootdev(); if (!dev_desc) { printf("%s: dev_desc is NULL!\n", __func__); return -TEEC_ERROR_GENERIC; } TeecResult = OpteeClientApiLibInitialize(); if (TeecResult != TEEC_SUCCESS) return TeecResult; TeecResult = TEEC_InitializeContext(NULL, &TeecContext); if (TeecResult != TEEC_SUCCESS) return TeecResult; TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); /* 0 nand or emmc "security" partition , 1 rpmb */ TeecOperation.params[0].value.a = (dev_desc->if_type == IF_TYPE_MMC) ? 1 : 0; #ifdef CONFIG_OPTEE_ALWAYS_USE_SECURITY_PARTITION TeecOperation.params[0].value.a = 0; #endif TeecResult = TEEC_OpenSession(&TeecContext, &TeecSession, TeecUuid, TEEC_LOGIN_PUBLIC, NULL, &TeecOperation, &ErrorOrigin); if (TeecResult != TEEC_SUCCESS) return TeecResult; SharedMem0.size = filename_size; SharedMem0.flags = 0; TeecResult = TEEC_AllocateSharedMemory(&TeecContext, &SharedMem0); if (TeecResult != TEEC_SUCCESS) return TeecResult; memcpy(SharedMem0.buffer, filename, SharedMem0.size); SharedMem1.size = key_size; SharedMem1.flags = 0; TeecResult = TEEC_AllocateSharedMemory(&TeecContext, &SharedMem1); if (TeecResult != TEEC_SUCCESS) return TeecResult; memcpy(SharedMem1.buffer, key, SharedMem1.size); SharedMem2.size = data_size; SharedMem2.flags = 0; TeecResult = TEEC_AllocateSharedMemory(&TeecContext, &SharedMem2); if (TeecResult != TEEC_SUCCESS) return TeecResult; memcpy(SharedMem2.buffer, data, SharedMem2.size); TeecOperation.params[0].tmpref.buffer = SharedMem0.buffer; TeecOperation.params[0].tmpref.size = SharedMem0.size; TeecOperation.params[1].tmpref.buffer = SharedMem1.buffer; TeecOperation.params[1].tmpref.size = SharedMem1.size; TeecOperation.params[2].tmpref.buffer = SharedMem2.buffer; TeecOperation.params[2].tmpref.size = SharedMem2.size; TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_INOUT, TEEC_NONE); printf("write keybox to secure storage\n"); TeecResult = TEEC_InvokeCommand(&TeecSession, STORAGE_CMD_WRITE, &TeecOperation, &ErrorOrigin); if (TeecResult != TEEC_SUCCESS) printf("send data to TA failed with code 0x%x\n", TeecResult); else printf("send data to TA success with code 0x%x\n", TeecResult); TEEC_ReleaseSharedMemory(&SharedMem0); TEEC_ReleaseSharedMemory(&SharedMem1); TEEC_ReleaseSharedMemory(&SharedMem2); TEEC_CloseSession(&TeecSession); TEEC_FinalizeContext(&TeecContext); return TeecResult; } uint32_t write_keybox_to_secure_storage(uint8_t *received_data, uint32_t len) { uint8_t *widevine_data; uint8_t *attestation_data; uint8_t *id_attestation_data; uint8_t *playready_sl30_data; uint32_t key_size; uint32_t data_size; int rc = 0; TEEC_Result ret; struct blk_desc *dev_desc; uint8_t is_use_rpmb; dev_desc = rockchip_get_bootdev(); if (!dev_desc) { printf("%s: dev_desc is NULL!\n", __func__); return -EIO; } is_use_rpmb = (dev_desc->if_type == IF_TYPE_MMC) ? 1 : 0; #ifdef CONFIG_OPTEE_ALWAYS_USE_SECURITY_PARTITION is_use_rpmb = 0; #endif if (is_use_rpmb) printf("I will write key to rpmb\n"); else printf("I will write key to security partition\n"); rc = write_to_security_storage(0, (uint8_t *)"security_partition", sizeof("security_partition"), &is_use_rpmb, sizeof(is_use_rpmb)); if (rc) return -EIO; widevine_data = (uint8_t *)new_strstr((char *)received_data, WIDEVINE_TAG, len); attestation_data = (uint8_t *)new_strstr((char *)received_data, ATTESTATION_TAG, len); id_attestation_data = (uint8_t *)new_strstr((char *)received_data, ID_ATTESTATION_TAG, len); playready_sl30_data = (uint8_t *)new_strstr((char *)received_data, PLAYREADY30_TAG, len); if (widevine_data) { /* widevine keybox */ TEEC_UUID widevine_uuid = { 0x1b484ea5, 0x698b, 0x4142, { 0x82, 0xb8, 0x3a, 0xcf, 0x16, 0xe9, 0x9e, 0x2a } }; key_size = *(widevine_data + SIZE_OF_TAG); data_size = *(widevine_data + SIZE_OF_TAG + sizeof(key_size)); ret = rk_send_keybox_to_ta((uint8_t *)"widevine_keybox", sizeof("widevine_keybox"), widevine_uuid, widevine_data + SIZE_OF_TAG + sizeof(key_size) + sizeof(data_size), key_size, widevine_data + 12 + key_size, data_size); if (ret == TEEC_SUCCESS) { rc = 0; printf("write widevine keybox to secure storage success\n"); } else { rc = -EIO; printf("write widevine keybox to secure storage fail\n"); } } else if (attestation_data) { /* attestation key */ atap_result ret; ret = write_attestation_key_to_secure_storage(attestation_data, len); if (ret == ATAP_RESULT_OK) { rc = 0; printf("write attestation key to secure storage success\n"); } else { rc = -EIO; printf("write attestation key to secure storage fail\n"); } } else if (id_attestation_data) { /* id attestation */ ret = write_id_attestation_to_secure_storage(id_attestation_data, len); if (ret == ATAP_RESULT_OK) { rc = 0; printf("write id attestation success!\n"); } else { rc = -EIO; printf("write id attestation failed\n"); } } else if (playready_sl30_data) { /* PlayReady SL3000 root key */ uint32_t ret; data_size = *(playready_sl30_data + SIZE_OF_TAG); ret = write_to_security_storage(is_use_rpmb, (uint8_t *)"PlayReady_SL3000", sizeof("PlayReady_SL3000"), playready_sl30_data + SIZE_OF_TAG +sizeof(data_size), data_size); if (ret == TEEC_SUCCESS) { rc = 0; printf("write PlayReady SL3000 root key to secure storage success\n"); } else { rc = -EIO; printf("write PlayReady SL3000 root key to secure storage fail\n"); } } /* write all data to secure storage for readback check */ if (!rc) { uint32_t ret; uint8_t *raw_data = malloc(len + sizeof(uint32_t)); /* add raw_data_len(4 byte) in begin of raw_data */ memcpy(raw_data, &len, sizeof(uint32_t)); memcpy((raw_data + sizeof(uint32_t)), received_data, len); ret = write_to_security_storage(is_use_rpmb, (uint8_t *)"raw_data", sizeof("raw_data"), raw_data, len + sizeof(uint32_t)); if (ret == TEEC_SUCCESS) rc = 0; else rc = -EIO; free(raw_data); } return rc; } uint32_t read_raw_data_from_secure_storage(uint8_t *data, uint32_t data_size) { uint32_t rc; uint32_t key_size; uint8_t *read_data = malloc(1024 * 40); rc = read_from_keymaster((uint8_t *)"raw_data", sizeof("raw_data"), read_data, data_size); if (rc != TEEC_SUCCESS) return 0; memcpy(&key_size, read_data, sizeof(uint32_t)); memcpy(data, read_data + sizeof(uint32_t), key_size); rc = key_size; free(read_data); return rc; } char *new_strstr(const char *s1, const char *s2, uint32_t l1) { uint32_t l2; l2 = strlen(s2); if (!l2) return (char *)s1; while (l1 >= l2) { l1--; if (!memcmp(s1, s2, l2)) return (char *)s1; s1++; } return NULL; }