2025-05-10 21:58:58 +08:00

356 lines
7.9 KiB
C
Executable File

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <tee_client_api.h>
#include <tee_api_defines_extensions.h>
#include "ta_keybox.h"
#define KEY_SIZE 32
#define DEFAULT_STORAGE TEE_STORAGE_PRIVATE_RPMB
static int run_system(const char *command)
{
int status;
status = system(command);
if (status == -1) {
printf("ERROR: system fork failed\n");
return -1;
} else {
if (WIFEXITED(status)) {
if (WEXITSTATUS(status)) {
printf("ERROR: system command failed\n");
return -1;
}
}
}
return 0;
}
static int grep_string(const char *dst, const char *target)
{
int i;
for (i = 0; i < strlen(dst); i++) {
if (!memcmp(&dst[i], target, strlen(target)))
return 0;
}
return -1;
}
static int check_ramdisk_env(const char *file)
{
FILE *fp;
char buf[1000];
fp = fopen(file, "r");
if (!fp) {
printf("ERROR: bad node\n");
return -1;
}
while (!feof(fp)) {
fgets(buf, 1000, fp);
if (!grep_string(buf, "none / rootfs")) {
fclose(fp);
return 0;
}
};
fclose(fp);
return -1;
}
static void dump_hex(char *var_name, const uint8_t *data,
uint32_t len)
{
#ifdef DEBUG_DUMP
uint32_t i;
printf("LINE:%d %s:", __LINE__, var_name);
for (i = 0; i < len; i++) {
if ((i % 16) == 7)
printf(" ");
if ((i % 16) == 0)
printf("\n");
printf("0x%02x", data[i]);
}
printf("\n");
#endif
}
static uint32_t js_hash(uint32_t hash, uint8_t *buf, int len)
{
int i;
for (i = 0; i < len; i++)
hash ^= ((hash << 5) + buf[i] + (hash >> 2));
return hash;
}
static int process_key(int cmd, char *key)
{
TEEC_Result res = TEEC_SUCCESS;
uint32_t error_origin = 0;
TEEC_Context contex;
TEEC_Session session;
TEEC_Operation operation;
TEEC_SharedMemory sm;
const TEEC_UUID uuid = TA_KEYBOX_UUID;
/* [1] Connect to TEE */
res = TEEC_InitializeContext(NULL, &contex);
if (res != TEEC_SUCCESS) {
printf("TEEC_InitializeContext failed with code 0x%x\n", res);
return res;
}
/* [2] Open seesion with TEE application */
res = TEEC_OpenSession(&contex, &session, &uuid,
TEEC_LOGIN_PUBLIC, NULL, NULL, &error_origin);
if (res != TEEC_SUCCESS) {
printf("TEEC_Opensession failed with code 0x%x origin 0x%x\n",
res, error_origin);
goto out;
}
/* [3] Perform operation initialization */
memset(&operation, 0, sizeof(TEEC_Operation));
if (cmd == TA_KEY_READ) {
sm.size = KEY_SIZE;
sm.flags = TEEC_MEM_OUTPUT;
res = TEEC_AllocateSharedMemory(&contex, &sm);
if (res != TEEC_SUCCESS) {
printf("AllocateSharedMemory ERR! res = 0x%x\n", res);
goto out1;
}
operation.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_OUTPUT,
TEEC_NONE,
TEEC_NONE,
TEEC_NONE);
operation.params[0].memref.parent = &sm;
operation.params[0].memref.offset = 0;
operation.params[0].memref.size = sm.size;
res = TEEC_InvokeCommand(&session, TA_KEY_RNG, &operation, &error_origin);
if (res != TEEC_SUCCESS) {
printf("InvokeCommand ERR! res = 0x%x\n", res);
TEEC_ReleaseSharedMemory(&sm);
goto out1;
}
dump_hex("RNG -> ", sm.buffer, KEY_SIZE);
operation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
TEEC_NONE,
TEEC_NONE,
TEEC_NONE);
operation.params[0].value.a = js_hash(0x47c6a7e6, sm.buffer, KEY_SIZE);
res = TEEC_InvokeCommand(&session, TA_KEY_VER, &operation, &error_origin);
if (res != TEEC_SUCCESS) {
printf("InvokeCommand ERR! res = 0x%x\n", res);
TEEC_ReleaseSharedMemory(&sm);
goto out1;
}
//printf("HASH -> %x", operation.params[0].value.a);
operation.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_OUTPUT,
TEEC_VALUE_INPUT,
TEEC_NONE,
TEEC_NONE);
operation.params[0].memref.parent = &sm;
operation.params[0].memref.offset = 0;
operation.params[0].memref.size = sm.size;
operation.params[1].value.a = DEFAULT_STORAGE;
res = TEEC_InvokeCommand(&session, TA_KEY_READ, &operation, &error_origin);
if (res != TEEC_SUCCESS) {
printf("InvokeCommand ERR! res = 0x%x\n", res);
TEEC_ReleaseSharedMemory(&sm);
goto out1;
}
dump_hex("read key -> ", sm.buffer, KEY_SIZE);
operation.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_OUTPUT,
TEEC_VALUE_INPUT,
TEEC_NONE,
TEEC_NONE);
operation.params[0].memref.parent = &sm;
operation.params[0].memref.offset = 0;
operation.params[0].memref.size = sm.size;
operation.params[1].value.a = DEFAULT_STORAGE;
res = TEEC_InvokeCommand(&session, TA_KEY_READ, &operation, &error_origin);
if (res != TEEC_SUCCESS) {
printf("InvokeCommand ERR! res = 0x%x\n", res);
TEEC_ReleaseSharedMemory(&sm);
goto out1;
}
dump_hex("read key -> ", sm.buffer, KEY_SIZE);
memcpy(key, sm.buffer, KEY_SIZE);
TEEC_ReleaseSharedMemory(&sm);
} else {
operation.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
TEEC_VALUE_INPUT,
TEEC_NONE,
TEEC_NONE);
operation.params[0].tmpref.size = KEY_SIZE;
operation.params[0].tmpref.buffer = (void *)key;
operation.params[1].value.a = DEFAULT_STORAGE;
res = TEEC_InvokeCommand(&session, TA_KEY_WRITE, &operation, &error_origin);
if (res != TEEC_SUCCESS) {
printf("InvokeCommand ERR! res = 0x%x\n", res);
}
}
out1:
TEEC_CloseSession(&session);
out:
TEEC_FinalizeContext(&contex);
return (res == TEEC_SUCCESS) ? 0 : -1;
}
/* 1 -> string to ascii */
static char transform_byte(int direction, uint8_t c)
{
if (direction) {
if (c > 'f')
return -1;
else if (c >= 'a')
return c - 'a' + 10;
else if (c > 'F')
return -1;
else if (c >= 'A')
return c - 'A' + 10;
else if (c > '9')
return -1;
else if (c >= '0')
return c - '0';
else
return -1;
} else {
if (c > 9)
return c + 'a' - 10;
else
return c + '0';
}
}
static int transform_key_to_ascii(int direction, uint8_t *in, uint8_t *out, int size)
{
int i;
uint8_t tmp;
for (i = 0; i < size; i++) {
if (direction) {
out[i] = (transform_byte(1, in[i << 1]) << 4) | transform_byte(1, in[(i << 1) + 1]);
} else {
out[i << 1] = transform_byte(0, in[i] >> 4);
out[(i << 1) + 1] = transform_byte(0, in[i] & 0x0f);
}
}
}
static int process_recovery(int argc, char *argv[])
{
int fd, ret;
uint8_t pw[KEY_SIZE];
uint8_t t_pw[KEY_SIZE << 1];
fd = open("/tmp/syspw", O_RDONLY);
if (fd == -1) {
printf("ERROR: failed to open syspw\n");
return -1;
}
ret = read(fd, t_pw, KEY_SIZE << 1);
if (ret != (KEY_SIZE << 1)) {
printf("ERROR: bad pw length\n");
return -1;
}
transform_key_to_ascii(1, t_pw, pw, KEY_SIZE);
dump_hex("pw -> ", pw, KEY_SIZE);
close(fd);
#ifdef CA_DEBUG
return process_key((argc > 1) ? TA_KEY_READ : TA_KEY_WRITE,
pw);
#else
return process_key(TA_KEY_WRITE, pw);
#endif
}
static int process_ramfs(void)
{
int fd, ret;
uint8_t pw[KEY_SIZE];
uint8_t t_pw[KEY_SIZE << 1];
if (process_key(TA_KEY_READ, pw))
return -1;
fd = open("/tmp/syspw", O_WRONLY | O_CREAT);
if (fd == -1) {
printf("ERROR: failed to open syspw\n");
return -1;
}
ftruncate(fd, 0);
lseek(fd, 0, SEEK_SET);
transform_key_to_ascii(0, pw, t_pw, KEY_SIZE);
ret = write(fd, t_pw, KEY_SIZE << 1);
if (ret != (KEY_SIZE << 1)) {
printf("ERROR: failed to write syspw (ret = %d)\n", ret);
return -1;
}
close(fd);
return 0;
}
int main(int argc, char *argv[])
{
#ifdef CA_DEBUG
return (argc > 1) ? process_ramfs() : process_recovery(argc, argv);
#else
int status;
/* check run under pid 1(init) */
if ((getppid() != 1) || (argc > 1)) {
return process_recovery(argc, argv);
}
/* check proc has mounted */
if (run_system("/bin/mount -t proc proc /proc")) {
printf("ERROR: failed to run system command\n");
return -1;
}
/* check run at ramdisk */
if (run_system("cat /proc/mounts > /tmp/proc_test")) {
printf("ERROR: failed to run system command\n");
return -1;
}
status = check_ramdisk_env("/tmp/proc_test");
remove("/tmp/proc_test");
if (status)
return -1;
return process_ramfs();
#endif
}