2025-05-10 21:49:39 +08:00

442 lines
13 KiB
C

/*
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
*/
#include <string.h>
#include "rkcrypto_core_int.h"
#include "rkcrypto_otp_key.h"
#include "rkcrypto_trace.h"
#include "tee_client_api.h"
#define STORAGE_UUID { 0x2d26d8a8, 0x5134, 0x4dd8, \
{ 0xb3, 0x2f, 0xb3, 0x4b, 0xce, 0xeb, 0xc4, 0x71 } }
#define RK_CRYPTO_SERVICE_UUID { 0x0cacdb5d, 0x4fea, 0x466c, \
{ 0x97, 0x16, 0x3d, 0x54, 0x16, 0x52, 0x83, 0x0f } }
#define STORAGE_CMD_WRITE_OEM_OTP_KEY 14
#define STORAGE_CMD_SET_OEM_HR_OTP_READ_LOCK 15
#define STORAGE_CMD_OEM_OTP_KEY_IS_WRITTEN 16
#define CRYPTO_SERVICE_CMD_OEM_OTP_KEY_CIPHER 0x00000001
#define CRYPTO_SERVICE_CMD_OEM_OTP_KEY_PHYS_CIPHER 0x00000002
static const struct {
const uint32_t tee_code;
const uint32_t rk_crypto_code;
} tee_crypto_code[] = {
{TEEC_SUCCESS, RK_CRYPTO_SUCCESS},
{TEEC_ERROR_GENERIC, RK_CRYPTO_ERR_GENERIC},
{TEEC_ERROR_BAD_PARAMETERS, RK_CRYPTO_ERR_PARAMETER},
{TEEC_ERROR_BAD_STATE, RK_CRYPTO_ERR_STATE},
{TEEC_ERROR_NOT_SUPPORTED, RK_CRYPTO_ERR_NOT_SUPPORTED},
{TEEC_ERROR_OUT_OF_MEMORY, RK_CRYPTO_ERR_OUT_OF_MEMORY},
{TEEC_ERROR_ACCESS_DENIED, RK_CRYPTO_ERR_ACCESS_DENIED},
};
static RK_RES tee_to_crypto_code(uint32_t tee_code)
{
uint32_t i;
uint32_t array_size = sizeof(tee_crypto_code) / sizeof((tee_crypto_code)[0]);
for (i = 0; i < array_size; i++) {
if (tee_code == tee_crypto_code[i].tee_code)
return tee_crypto_code[i].rk_crypto_code;
}
/* Others convert to RK_CRYPTO_ERR_GENERIC. */
return RK_CRYPTO_ERR_GENERIC;
}
static uint32_t cipher_get_blocksize(uint32_t algo)
{
switch (algo) {
case RK_ALGO_DES:
case RK_ALGO_TDES:
return DES_BLOCK_SIZE;
case RK_ALGO_AES:
return AES_BLOCK_SIZE;
case RK_ALGO_SM4:
return SM4_BLOCK_SIZE;
default:
return 1;
}
}
RK_RES rk_write_oem_otp_key(enum RK_OEM_OTP_KEYID key_id, uint8_t *key,
uint32_t key_len)
{
RK_RES res;
TEEC_Context contex;
TEEC_Session session;
TEEC_Operation operation;
TEEC_UUID uuid = STORAGE_UUID;
uint32_t error_origin = 0;
RK_CRYPTO_CHECK_PARAM(key_id != RK_OEM_OTP_KEY0 &&
key_id != RK_OEM_OTP_KEY1 &&
key_id != RK_OEM_OTP_KEY2 &&
key_id != RK_OEM_OTP_KEY3 &&
key_id != RK_OEM_OTP_KEY_FW);
RK_CRYPTO_CHECK_PARAM(!key);
RK_CRYPTO_CHECK_PARAM(key_len != 16 &&
key_len != 24 &&
key_len != 32);
RK_CRYPTO_CHECK_PARAM(key_id == RK_OEM_OTP_KEY_FW &&
key_len != 16);
res = TEEC_InitializeContext(NULL, &contex);
if (res != TEEC_SUCCESS) {
E_TRACE("TEEC_InitializeContext failed with code TEEC res= 0x%x", res);
return tee_to_crypto_code(res);
}
res = TEEC_OpenSession(&contex, &session, &uuid, TEEC_LOGIN_PUBLIC,
NULL, NULL, &error_origin);
if (res != TEEC_SUCCESS) {
E_TRACE("TEEC_Opensession failed with code TEEC res= 0x%x origin 0x%x",
res, error_origin);
goto out;
}
memset(&operation, 0, sizeof(TEEC_Operation));
operation.params[0].value.a = key_id;
operation.params[1].tmpref.buffer = key;
operation.params[1].tmpref.size = key_len;
operation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
TEEC_MEMREF_TEMP_INPUT,
TEEC_NONE,
TEEC_NONE);
res = TEEC_InvokeCommand(&session, STORAGE_CMD_WRITE_OEM_OTP_KEY,
&operation, &error_origin);
if (res != TEEC_SUCCESS) {
E_TRACE("InvokeCommand ERR! TEEC res= 0x%x, error_origin= 0x%x",
res, error_origin);
}
TEEC_CloseSession(&session);
out:
TEEC_FinalizeContext(&contex);
return tee_to_crypto_code(res);
}
RK_RES rk_oem_otp_key_is_written(enum RK_OEM_OTP_KEYID key_id, uint8_t *is_written)
{
RK_RES res;
TEEC_Context contex;
TEEC_Session session;
TEEC_Operation operation;
TEEC_UUID uuid = STORAGE_UUID;
uint32_t error_origin = 0;
RK_CRYPTO_CHECK_PARAM(key_id != RK_OEM_OTP_KEY0 &&
key_id != RK_OEM_OTP_KEY1 &&
key_id != RK_OEM_OTP_KEY2 &&
key_id != RK_OEM_OTP_KEY3 &&
key_id != RK_OEM_OTP_KEY_FW);
RK_CRYPTO_CHECK_PARAM(!is_written);
res = TEEC_InitializeContext(NULL, &contex);
if (res != TEEC_SUCCESS) {
E_TRACE("TEEC_InitializeContext failed with code TEEC res= 0x%x", res);
return tee_to_crypto_code(res);
}
res = TEEC_OpenSession(&contex, &session, &uuid, TEEC_LOGIN_PUBLIC,
NULL, NULL, &error_origin);
if (res != TEEC_SUCCESS) {
E_TRACE("TEEC_Opensession failed with code TEEC res= 0x%x origin 0x%x",
res, error_origin);
goto out;
}
memset(&operation, 0, sizeof(TEEC_Operation));
operation.params[0].value.a = key_id;
operation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT,
TEEC_NONE,
TEEC_NONE,
TEEC_NONE);
res = TEEC_InvokeCommand(&session, STORAGE_CMD_OEM_OTP_KEY_IS_WRITTEN,
&operation, &error_origin);
if (res == TEEC_ERROR_ACCESS_DENIED) {
E_TRACE("Check if it has been set oem_hr_otp_read_lock!");
} else if (res != TEEC_SUCCESS) {
E_TRACE("InvokeCommand ERR! TEEC res= 0x%x, error_origin= 0x%x",
res, error_origin);
} else {
*is_written = operation.params[0].value.b;
}
TEEC_CloseSession(&session);
out:
TEEC_FinalizeContext(&contex);
return tee_to_crypto_code(res);
}
RK_RES rk_set_oem_hr_otp_read_lock(enum RK_OEM_OTP_KEYID key_id)
{
RK_RES res;
TEEC_Context contex;
TEEC_Session session;
TEEC_Operation operation;
TEEC_UUID uuid = STORAGE_UUID;
uint32_t error_origin = 0;
RK_CRYPTO_CHECK_PARAM(key_id != RK_OEM_OTP_KEY0 &&
key_id != RK_OEM_OTP_KEY1 &&
key_id != RK_OEM_OTP_KEY2 &&
key_id != RK_OEM_OTP_KEY3);
res = TEEC_InitializeContext(NULL, &contex);
if (res != TEEC_SUCCESS) {
E_TRACE("TEEC_InitializeContext failed with code TEEC res= 0x%x", res);
return tee_to_crypto_code(res);
}
res = TEEC_OpenSession(&contex, &session, &uuid, TEEC_LOGIN_PUBLIC,
NULL, NULL, &error_origin);
if (res != TEEC_SUCCESS) {
E_TRACE("TEEC_Opensession failed with code TEEC res= 0x%x origin 0x%x",
res, error_origin);
goto out;
}
memset(&operation, 0, sizeof(TEEC_Operation));
operation.params[0].value.a = key_id;
operation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
TEEC_NONE,
TEEC_NONE,
TEEC_NONE);
res = TEEC_InvokeCommand(&session, STORAGE_CMD_SET_OEM_HR_OTP_READ_LOCK,
&operation, &error_origin);
if (res != TEEC_SUCCESS) {
E_TRACE("InvokeCommand ERR! TEEC res= 0x%x, error_origin= 0x%x",
res, error_origin);
}
TEEC_CloseSession(&session);
out:
TEEC_FinalizeContext(&contex);
return tee_to_crypto_code(res);
}
RK_RES rk_oem_otp_key_cipher_virt(enum RK_OEM_OTP_KEYID key_id, rk_cipher_config *config,
uint8_t *src, uint8_t *dst, uint32_t len)
{
RK_RES res;
TEEC_Context contex;
TEEC_Session session;
TEEC_Operation operation;
TEEC_UUID uuid = RK_CRYPTO_SERVICE_UUID;
uint32_t error_origin = 0, len_aligned, len_cipher, block_size;
TEEC_SharedMemory sm;
RK_CRYPTO_CHECK_PARAM(key_id != RK_OEM_OTP_KEY0 &&
key_id != RK_OEM_OTP_KEY1 &&
key_id != RK_OEM_OTP_KEY2 &&
key_id != RK_OEM_OTP_KEY3 &&
key_id != RK_OEM_OTP_KEY_FW);
RK_CRYPTO_CHECK_PARAM(!config || !src || !dst);
RK_CRYPTO_CHECK_PARAM(config->algo != RK_ALGO_AES &&
config->algo != RK_ALGO_SM4);
RK_CRYPTO_CHECK_PARAM(config->mode >= RK_CIPHER_MODE_XTS);
RK_CRYPTO_CHECK_PARAM(config->operation != RK_OP_CIPHER_ENC &&
config->operation != RK_OP_CIPHER_DEC);
RK_CRYPTO_CHECK_PARAM(config->key_len != 16 &&
config->key_len != 24 &&
config->key_len != 32);
RK_CRYPTO_CHECK_PARAM(key_id == RK_OEM_OTP_KEY_FW &&
config->key_len != 16);
RK_CRYPTO_CHECK_PARAM(len > RK_CRYPTO_MAX_DATA_LEN ||
len == 0);
RK_CRYPTO_CHECK_PARAM(config->mode == RK_CIPHER_MODE_CTS &&
len <= 16);
len_cipher = len;
block_size = cipher_get_blocksize(config->algo);
if (config->mode != RK_CIPHER_MODE_CTS && (len % block_size)) {
RK_CRYPTO_CHECK_PARAM(config->mode != RK_CIPHER_MODE_CTR &&
config->mode != RK_CIPHER_MODE_CFB &&
config->mode != RK_CIPHER_MODE_OFB);
len_aligned = ROUNDUP(len, block_size);
len_cipher = len_aligned;
}
res = TEEC_InitializeContext(NULL, &contex);
if (res != TEEC_SUCCESS) {
E_TRACE("TEEC_InitializeContext failed with code TEEC res= 0x%x", res);
return tee_to_crypto_code(res);
}
res = TEEC_OpenSession(&contex, &session, &uuid, TEEC_LOGIN_PUBLIC,
NULL, NULL, &error_origin);
if (res != TEEC_SUCCESS) {
E_TRACE("TEEC_Opensession failed with code TEEC res= 0x%x origin 0x%x",
res, error_origin);
goto out;
}
sm.size = len_cipher;
sm.flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
res = TEEC_AllocateSharedMemory(&contex, &sm);
if (res != TEEC_SUCCESS) {
E_TRACE("AllocateSharedMemory ERR! TEEC res= 0x%x", res);
goto out1;
}
memset(sm.buffer, 0, sm.size);
memcpy(sm.buffer, src, len);
memset(&operation, 0, sizeof(TEEC_Operation));
operation.params[0].value.a = key_id;
operation.params[1].tmpref.buffer = config;
operation.params[1].tmpref.size = sizeof(rk_cipher_config);
operation.params[2].memref.parent = &sm;
operation.params[2].memref.offset = 0;
operation.params[2].memref.size = sm.size;
operation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
TEEC_MEMREF_TEMP_INPUT,
TEEC_MEMREF_PARTIAL_INOUT,
TEEC_NONE);
res = TEEC_InvokeCommand(&session, CRYPTO_SERVICE_CMD_OEM_OTP_KEY_CIPHER,
&operation, &error_origin);
if (res != TEEC_SUCCESS) {
E_TRACE("InvokeCommand ERR! TEEC res= 0x%x, error_origin= 0x%x",
res, error_origin);
} else {
memcpy(dst, sm.buffer, sm.size);
}
TEEC_ReleaseSharedMemory(&sm);
out1:
TEEC_CloseSession(&session);
out:
TEEC_FinalizeContext(&contex);
return tee_to_crypto_code(res);
}
RK_RES rk_oem_otp_key_cipher(enum RK_OEM_OTP_KEYID key_id, rk_cipher_config *config,
int32_t in_fd, int32_t out_fd, uint32_t len)
{
RK_RES res;
TEEC_Context contex;
TEEC_Session session;
TEEC_Operation operation;
TEEC_UUID uuid = RK_CRYPTO_SERVICE_UUID;
uint32_t error_origin = 0, len_aligned, len_cipher, block_size;
struct crypt_fd_map_op src_mop;
struct crypt_fd_map_op dst_mop;
RK_CRYPTO_CHECK_PARAM(in_fd < 0);
RK_CRYPTO_CHECK_PARAM(out_fd < 0);
RK_CRYPTO_CHECK_PARAM(key_id != RK_OEM_OTP_KEY0 &&
key_id != RK_OEM_OTP_KEY1 &&
key_id != RK_OEM_OTP_KEY2 &&
key_id != RK_OEM_OTP_KEY3 &&
key_id != RK_OEM_OTP_KEY_FW);
RK_CRYPTO_CHECK_PARAM(!config);
RK_CRYPTO_CHECK_PARAM(config->algo != RK_ALGO_AES &&
config->algo != RK_ALGO_SM4);
RK_CRYPTO_CHECK_PARAM(config->mode >= RK_CIPHER_MODE_XTS);
RK_CRYPTO_CHECK_PARAM(config->operation != RK_OP_CIPHER_ENC &&
config->operation != RK_OP_CIPHER_DEC);
RK_CRYPTO_CHECK_PARAM(config->key_len != 16 &&
config->key_len != 24 &&
config->key_len != 32);
RK_CRYPTO_CHECK_PARAM(key_id == RK_OEM_OTP_KEY_FW &&
config->key_len != 16);
RK_CRYPTO_CHECK_PARAM(len == 0);
RK_CRYPTO_CHECK_PARAM(config->mode == RK_CIPHER_MODE_CTS &&
len <= 16);
len_cipher = len;
block_size = cipher_get_blocksize(config->algo);
if (config->mode != RK_CIPHER_MODE_CTS && (len % block_size)) {
RK_CRYPTO_CHECK_PARAM(config->mode != RK_CIPHER_MODE_CTR &&
config->mode != RK_CIPHER_MODE_CFB &&
config->mode != RK_CIPHER_MODE_OFB);
len_aligned = ROUNDUP(len, block_size);
len_cipher = len_aligned;
}
memset(&src_mop, 0, sizeof(src_mop));
memset(&dst_mop, 0, sizeof(dst_mop));
src_mop.dma_fd = in_fd;
dst_mop.dma_fd = out_fd;
res = rk_crypto_fd_ioctl(RIOCCRYPT_FD_MAP, &src_mop);
if (res != RK_CRYPTO_SUCCESS) {
E_TRACE("RIOCCRYPT_FD_MAP failed, res= 0x%x", res);
return res;
}
if (out_fd != in_fd) {
res = rk_crypto_fd_ioctl(RIOCCRYPT_FD_MAP, &dst_mop);
if (res != RK_CRYPTO_SUCCESS) {
E_TRACE("RIOCCRYPT_FD_MAP failed, res= 0x%x", res);
goto out;
}
} else {
dst_mop.phys_addr = src_mop.phys_addr;
}
res = TEEC_InitializeContext(NULL, &contex);
if (res != TEEC_SUCCESS) {
E_TRACE("TEEC_InitializeContext failed with code TEEC res= 0x%x", res);
goto out1;
}
res = TEEC_OpenSession(&contex, &session, &uuid, TEEC_LOGIN_PUBLIC,
NULL, NULL, &error_origin);
if (res != TEEC_SUCCESS) {
E_TRACE("TEEC_Opensession failed with code TEEC res= 0x%x origin 0x%x",
res, error_origin);
goto out2;
}
memset(&operation, 0, sizeof(TEEC_Operation));
operation.params[0].value.a = key_id;
operation.params[1].tmpref.buffer = config;
operation.params[1].tmpref.size = sizeof(rk_cipher_config);
operation.params[2].value.a = src_mop.phys_addr;
operation.params[2].value.b = len_cipher;
operation.params[3].value.a = dst_mop.phys_addr;
operation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
TEEC_MEMREF_TEMP_INPUT,
TEEC_VALUE_INPUT,
TEEC_VALUE_INPUT);
res = TEEC_InvokeCommand(&session, CRYPTO_SERVICE_CMD_OEM_OTP_KEY_PHYS_CIPHER,
&operation, &error_origin);
if (res != TEEC_SUCCESS) {
E_TRACE("InvokeCommand ERR! TEEC res= 0x%x, error_origin= 0x%x",
res, error_origin);
}
TEEC_CloseSession(&session);
out2:
TEEC_FinalizeContext(&contex);
out1:
res = tee_to_crypto_code(res);
if (out_fd != in_fd)
rk_crypto_fd_ioctl(RIOCCRYPT_FD_UNMAP, &dst_mop);
out:
rk_crypto_fd_ioctl(RIOCCRYPT_FD_UNMAP, &src_mop);
return res;
}