blob: d9f0861bcc431abc2ff1edf300e233caf29551c6 [file] [log] [blame]
// Copyright 2018-2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>
#include <tee-client-api/tee_client_api.h>
//
// `fx shell tee-test`:
//
// Use this command to verify Fuchsia/TEE communications and TA loading on
// real hardware.
//
// Examples:
//
// # Verify basic Fuchsia/TEE communications is working by loading and
// # invoking a simple command of the "Hello World" TA.
// $> fx shell tee-test
//
// # Verify if a specific TA is signed properly (loads successfully).
// # <ta-uuid> is the UUID of the TA in canonical format, e.g.:
// # "abcd1234-abcd-abcd-abcd-abcd1234abcd"
// $> fx shell tee-test <ta-uuid>
//
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define RETURN_STR_IF_MATCH(v, code) \
do { \
if (v == code) \
return #code; \
} while (0)
static const TEEC_UUID ta_helloworld_uuid = {
0x8aaaf200, 0x2450, 0x11e4, {0xab, 0xe2, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
static const char *result_to_str(TEEC_Result result) {
RETURN_STR_IF_MATCH(result, TEEC_SUCCESS);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_GENERIC);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_ACCESS_DENIED);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_CANCEL);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_ACCESS_CONFLICT);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_EXCESS_DATA);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_BAD_FORMAT);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_BAD_PARAMETERS);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_BAD_STATE);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_ITEM_NOT_FOUND);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_NOT_IMPLEMENTED);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_NOT_SUPPORTED);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_NO_DATA);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_OUT_OF_MEMORY);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_BUSY);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_COMMUNICATION);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_SECURITY);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_SHORT_BUFFER);
RETURN_STR_IF_MATCH(result, TEE_ERROR_EXTERNAL_CANCEL);
RETURN_STR_IF_MATCH(result, TEE_ERROR_OVERFLOW);
RETURN_STR_IF_MATCH(result, TEE_ERROR_TARGET_DEAD);
RETURN_STR_IF_MATCH(result, TEEC_ERROR_TARGET_DEAD);
RETURN_STR_IF_MATCH(result, TEE_ERROR_STORAGE_NO_SPACE);
static char buf[12];
sprintf(buf, "0x%08x", result);
return buf;
}
static const char *origin_to_str(uint32_t origin) {
RETURN_STR_IF_MATCH(origin, TEEC_ORIGIN_API);
RETURN_STR_IF_MATCH(origin, TEEC_ORIGIN_COMMS);
RETURN_STR_IF_MATCH(origin, TEEC_ORIGIN_TEE);
RETURN_STR_IF_MATCH(origin, TEEC_ORIGIN_TRUSTED_APP);
static char buf[12];
sprintf(buf, "0x%08x", origin);
return buf;
}
// Parses an UUID in canonical representation, e.g.:
// "abcd1234-abcd-abcd-abcd-abcd1234abcd"
static int uuid_parse(const char *in, TEEC_UUID *out) {
int n_fields;
int n_chars = 0;
n_fields = sscanf(in, "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%n",
&out->timeLow, &out->timeMid, &out->timeHiAndVersion, &out->clockSeqAndNode[0],
&out->clockSeqAndNode[1], &out->clockSeqAndNode[2], &out->clockSeqAndNode[3],
&out->clockSeqAndNode[4], &out->clockSeqAndNode[5], &out->clockSeqAndNode[6],
&out->clockSeqAndNode[7], &n_chars);
if (!(n_fields == 11 && n_chars == 36)) {
printf("UUID (%s) not in expected format (%s).\n", in, "08x-04x-04x-04x-012x");
return -1;
}
return 0;
}
static int uuid_compare(const TEEC_UUID *lh, const TEEC_UUID *rh) {
return memcmp(lh, rh, sizeof(TEEC_UUID));
}
#define TA_HELLO_WORLD_CMD_INC_VALUE 0
static TEEC_Result ta_helloworld_invoke_cmds(TEEC_Session *session) {
TEEC_Result result;
uint32_t origin;
TEEC_Operation op = {0};
op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
op.params[0].value.a = 42;
result = TEEC_InvokeCommand(session, TA_HELLO_WORLD_CMD_INC_VALUE, &op, &origin);
if (result != TEEC_SUCCESS) {
printf("TEEC_InvokeCommand failed. Result=%s, origin=%s.\n", result_to_str(result),
origin_to_str(origin));
return result;
}
if (result == TEEC_SUCCESS && op.params[0].value.a != 43) {
return TEEC_ERROR_GENERIC;
}
return result;
}
static int test_ta(const TEEC_UUID *ta_uuid) {
TEEC_Result result;
TEEC_Context context;
TEEC_Session session;
uint32_t origin;
result = TEEC_InitializeContext(NULL, &context);
if (result != TEEC_SUCCESS) {
printf("Failed to initialize context. Result=%s.\n", result_to_str(result));
return 1;
}
result = TEEC_OpenSession(&context, &session, ta_uuid, TEEC_LOGIN_PUBLIC, NULL, NULL, &origin);
if (result != TEEC_SUCCESS) {
printf("Failed to open session. Result=%s, origin=%s\n", result_to_str(result),
origin_to_str(origin));
TEEC_FinalizeContext(&context);
return 1;
}
if (uuid_compare(ta_uuid, &ta_helloworld_uuid) == 0) {
result = ta_helloworld_invoke_cmds(&session);
}
TEEC_CloseSession(&session);
TEEC_FinalizeContext(&context);
return (result == TEEC_SUCCESS) ? 0 : 1;
}
int main(int argc, char *argv[]) {
TEEC_UUID ta_uuid = ta_helloworld_uuid;
if (argc > 1 && uuid_parse(argv[1], &ta_uuid)) {
printf("Bad UUID: %s\n", argv[1]);
return 1;
}
return test_ta(&ta_uuid);
}