diff --git a/Android.mk b/Android.mk index 0ceb594c9..dc25f7904 100644 --- a/Android.mk +++ b/Android.mk @@ -43,6 +43,7 @@ srcs += adbg/src/adbg_case.c \ adbg/src/adbg_run.c \ adbg/src/security_utils_hex.c \ aes_perf.c \ + asym_cipher_perf.c \ benchmark_1000.c \ benchmark_2000.c \ clear_storage.c \ diff --git a/host/xtest/CMakeLists.txt b/host/xtest/CMakeLists.txt index 42ebd0c5d..c53b09ebf 100644 --- a/host/xtest/CMakeLists.txt +++ b/host/xtest/CMakeLists.txt @@ -57,6 +57,7 @@ set (SRC regression_8000.c regression_8100.c hash_perf.c + asym_cipher_perf.c stats.c xtest_helpers.c xtest_main.c diff --git a/host/xtest/Makefile b/host/xtest/Makefile index afa2a87ba..a255ba86b 100644 --- a/host/xtest/Makefile +++ b/host/xtest/Makefile @@ -68,6 +68,7 @@ srcs += adbg/src/adbg_case.c \ regression_8000.c \ regression_8100.c \ hash_perf.c \ + asym_cipher_perf.c \ stats.c \ xtest_helpers.c \ xtest_main.c \ diff --git a/host/xtest/asym_cipher_perf.c b/host/xtest/asym_cipher_perf.c new file mode 100644 index 000000000..6f46cf8d9 --- /dev/null +++ b/host/xtest/asym_cipher_perf.c @@ -0,0 +1,849 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2023, Huawei Technologies Co., Ltd + * All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crypto_common.h" +#include "xtest_helpers.h" + +static TEEC_Context ctx; +static TEEC_Session sess; + +static TEEC_SharedMemory in_shm = { + .flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT +}; +static TEEC_SharedMemory out_shm = { + .flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT +}; +static TEEC_SharedMemory hash_shm = { + .flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT +}; + +static void errx(const char *msg, TEEC_Result res, uint32_t *orig) +{ + fprintf(stderr, "%s: 0x%08x", msg, res); + if (orig) + fprintf(stderr, " (orig=%d)", (int)*orig); + fprintf(stderr, "\n"); + exit (1); +} + +static void check_res(TEEC_Result res, const char *errmsg, uint32_t *orig) +{ + if (res != TEEC_SUCCESS) + errx(errmsg, res, orig); +} + +#define CHECK(res, name, action) do { \ + if ((res) != TEE_SUCCESS) { \ + printf(name ": 0x%08x", (res)); \ + action \ + } \ + } while(0) + +static void open_ta(void) +{ + TEEC_UUID uuid = TA_CRYPTO_PERF_UUID; + TEEC_Result res = TEEC_ERROR_GENERIC; + uint32_t err_origin = 0; + + res = TEEC_InitializeContext(NULL, &ctx); + check_res(res, "TEEC_InitializeContext", NULL); + + res = TEEC_OpenSession(&ctx, &sess, &uuid, TEEC_LOGIN_PUBLIC, NULL, + NULL, &err_origin); + check_res(res, "TEEC_OpenSession", &err_origin); +} + +static void close_ta(void) +{ + TEEC_CloseSession(&sess); + TEEC_FinalizeContext(&ctx); +} + +/* + * Statistics + * + * We want to compute min, max, mean and standard deviation of processing time + */ + +struct statistics { + int n; + double m; + double m2; + double min; + double max; + int initialized; +}; + +/* Take new sample into account (Knuth/Welford algorithm) */ +static void update_stats(struct statistics *s, uint64_t t) +{ + double x = (double)t; + double delta = x - s->m; + + s->n++; + s->m += delta / s->n; + s->m2 += delta * (x - s->m); + if (!s->initialized) { + s->min = x; + s->max = x; + s->initialized = 1; + } else { + if (s->min > x) + s->min = x; + if (s->max < x) + s->max = x; + } +} + +static double stddev(struct statistics *s) +{ + if (s->n < 2) + return NAN; + + return sqrt(s->m2 / s->n); +} + +static void usage(const char *progname, uint32_t width_bits, uint32_t main_algo, + uint32_t mode, uint32_t salt_len, uint32_t size, + uint32_t rsa_algo, int warmup, uint32_t l, uint32_t n) +{ + fprintf(stderr, "Usage: %s [-h]\n", progname); + fprintf(stderr, "Usage: %s [-t] [-m] [-k SIZE]", progname); + fprintf(stderr, " [-t main_algo] [-m mode] [-n LOOP] [-r|--no-inited] [-d WIDTH_BITS]"); + fprintf(stderr, " [-k SIZE] [-a rsa_algo] [-s salt_len] [-v [-v]] [-w SEC]"); + fprintf(stderr, "\n"); + fprintf(stderr, "Asymmetric performance testing tool for OP-TEE\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -h|--help Print this help and exit\n"); + fprintf(stderr, " -t TYPE Test type for asymmetric algo [%u]\n", main_algo); + fprintf(stderr, " DH, RSA, ECDSA, ECDH, X25519\n"); + fprintf(stderr, " -m MODE Test asymmetric mode [%u]\n", mode); + fprintf(stderr, " ENC, DEC, SIGN, VERIFY, GENKEYPAIR\n"); + fprintf(stderr, " -l LOOP Inner loop iterations [%u]\n", l); + fprintf(stderr, " -n LOOP Outer test loop iterations [%u]\n", n); + fprintf(stderr, " -r|--random Get input data from /dev/urandom (default: all zeros)\n"); + fprintf(stderr, " -k SIZE Plaintext Length [%u]\n", size); + fprintf(stderr, " -d WIDTH_BITS ECC:the width_bits only support 192/224/256/384/521 [%u]\n", width_bits); + fprintf(stderr, " DH: width_bits <= 2048, RSA: width_bits <= 4096 [%u]\n", width_bits); + fprintf(stderr, " -a ALGO Crypto algorithm tested when TYPE is 2(RSA)\n"); + fprintf(stderr, " RSA_NOPAD, RSAES_PKCS1_V1_5, RSAES_PKCS1_OAEP_SHA1\n"); + fprintf(stderr, " RSAES_PKCS1_OAEP_SHA224, RSAES_PKCS1_OAEP_SHA256\n"); + fprintf(stderr, " RSAES_PKCS1_OAEP_SHA384, RSAES_PKCS1_OAEP_SHA512\n"); + fprintf(stderr, " RSASSA_PKCS1_V1_5_SHA1, RSASSA_PKCS1_V1_5_SHA224\n"); + fprintf(stderr, " RSASSA_PKCS1_V1_5_SHA256, RSASSA_PKCS1_V1_5_SHA384\n"); + fprintf(stderr, " RSASSA_PKCS1_V1_5_SHA512, RSASSA_PKCS1_PSS_MGF1_SHA1\n"); + fprintf(stderr, " RSASSA_PKCS1_PSS_MGF1_SHA224, RSASSA_PKCS1_PSS_MGF1_SHA256\n"); + fprintf(stderr, " RSASSA_PKCS1_PSS_MGF1_SHA384, RSASSA_PKCS1_PSS_MGF1_SHA512\n"); + fprintf(stderr, " -s SALT_LEN only RSA SSA_PKCS1_PSS support! [%u]\n", salt_len); + fprintf(stderr, " -w|--warmup SEC Warm-up time in seconds: execute a busy loop before [%d]\n", warmup); + fprintf(stderr, " -v Be verbose (use twice for greater effect)\n"); +} + +static void allocate_shm(TEEC_SharedMemory *shm, size_t sz) +{ + TEEC_Result res = TEEC_ERROR_GENERIC; + + shm->buffer = NULL; + shm->size = sz; + res = TEEC_AllocateSharedMemory(&ctx, shm); + check_res(res, "TEEC_AllocateSharedMemory", NULL); +} + +/* initial test buffer allocation (eventual registering to TEEC) */ +static void alloc_buffers(size_t sz, int verbosity) +{ + (void)verbosity; + + allocate_shm(&in_shm, sz); + allocate_shm(&out_shm, TEE_MAX_OUT_SIZE); + allocate_shm(&hash_shm, TEE_MAX_HASH_SIZE); +} + +static void free_shm(void) +{ + TEEC_ReleaseSharedMemory(&in_shm); + TEEC_ReleaseSharedMemory(&out_shm); + TEEC_ReleaseSharedMemory(&hash_shm); +} + +static ssize_t read_random(void *in, size_t rsize) +{ + static int rnd; + ssize_t s = 0; + + if (!rnd) { + rnd = open("/dev/urandom", O_RDONLY); + if (rnd < 0) { + perror("open"); + return 1; + } + } + + s = read(rnd, in, rsize); + if (s < 0) { + perror("read"); + return 1; + } + if ((size_t)s != rsize) + printf("read: requested %zu bytes, got %zd\n", rsize, s); + + return TEE_SUCCESS; +} + +static void get_current_time(struct timespec *ts) +{ + if (clock_gettime(CLOCK_MONOTONIC, ts) < 0) { + perror("clock_gettime"); + exit(1); + } +} + +static uint64_t timespec_to_ns(struct timespec *ts) +{ + return ((uint64_t)ts->tv_sec * 1000000000) + ts->tv_nsec; +} + +static uint64_t timespec_diff_ns(struct timespec *start, struct timespec *end) +{ + return timespec_to_ns(end) - timespec_to_ns(start); +} + +static void prepare_obj(int width_bits, uint32_t main_algo) +{ + uint32_t cmd = TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_OBJ; + TEEC_Operation op = TEEC_OPERATION_INITIALIZER; + TEEC_Result res = TEEC_ERROR_GENERIC; + uint32_t ret_origin = 0; + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, + TEEC_NONE); + op.params[0].value.a = main_algo; + op.params[0].value.b = width_bits; + + res = TEEC_InvokeCommand(&sess, cmd, &op, &ret_origin); + check_res(res, "TEEC_InvokeCommand", &ret_origin); +} + +static void prepare_hash(int size, uint32_t main_algo) +{ + uint32_t cmd = TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_HASH; + TEEC_Operation op = TEEC_OPERATION_INITIALIZER; + TEEC_Result res = TEEC_ERROR_GENERIC; + uint32_t ret_origin = 0; + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, + TEEC_MEMREF_PARTIAL_INPUT, + TEEC_MEMREF_PARTIAL_INOUT, TEEC_NONE); + op.params[0].value.a = main_algo; + op.params[1].memref.parent = &in_shm; + op.params[1].memref.size = size; + op.params[2].memref.parent = &hash_shm; + op.params[2].memref.size = hash_shm.size; + + res = TEEC_InvokeCommand(&sess, cmd, &op, &ret_origin); + check_res(res, "TEEC_InvokeCommand", &ret_origin); + hash_shm.size = op.params[2].memref.size; +} + +static void prepare_keypair(int width_bits, uint8_t *buf, size_t blen, + uint32_t mode, uint32_t algo, uint32_t main_algo) +{ + uint32_t cmd = TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_KEYPAIR; + TEEC_Operation op = TEEC_OPERATION_INITIALIZER; + TEEC_Result res = TEEC_ERROR_GENERIC; + uint32_t ret_origin = 0; + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_VALUE_INPUT, + TEEC_MEMREF_TEMP_INPUT, TEEC_NONE); + op.params[0].value.a = width_bits; + op.params[0].value.b = mode; + op.params[1].value.a = main_algo; + op.params[1].value.b = algo; + op.params[2].tmpref.buffer = buf; + op.params[2].tmpref.size = blen; + + res = TEEC_InvokeCommand(&sess, cmd, &op, &ret_origin); + check_res(res, "TEEC_InvokeCommand", &ret_origin); +} + +static void prepare_enc_sign(uint32_t size, uint32_t mode, uint32_t is_random, + uint8_t *buf, uint32_t blen) +{ + uint32_t cmd = TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_ENC_SIGN; + TEEC_Operation op = TEEC_OPERATION_INITIALIZER; + TEEC_Result res = TEEC_ERROR_GENERIC; + uint32_t ret_origin = 0; + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INPUT, + TEEC_MEMREF_PARTIAL_OUTPUT, + TEEC_VALUE_INPUT, + TEEC_MEMREF_TEMP_INPUT); + op.params[0].memref.parent = (mode == MODE_DECRYPT) ? + &in_shm : &hash_shm; + op.params[0].memref.size = (mode == MODE_DECRYPT) ? + size : hash_shm.size; + op.params[1].memref.parent = &out_shm; + op.params[1].memref.size = out_shm.size; + op.params[2].value.a = mode; + op.params[3].tmpref.buffer = buf; + op.params[3].tmpref.size = blen; + + res = TEEC_InvokeCommand(&sess, cmd, &op, &ret_origin); + + check_res(res, "TEEC_InvokeCommand", &ret_origin); + + out_shm.size = op.params[1].memref.size; + + return; +} + +static void do_warmup(int warmup) +{ + struct timespec t0 = { }; + struct timespec t = { }; + int i = 0; + + get_current_time(&t0); + do { + for (i = 0; i < 100000; i++) + ; + get_current_time(&t); + } while (timespec_diff_ns(&t0, &t) < (uint64_t)warmup * 1000000000); +} + +static const char *yesno(int v) +{ + return (v ? "yes" : "no"); +} + +static double mb_per_sec(size_t size, double usec) +{ + return (1000000000 / usec) * ((double)size / (1024 * 1024)); +} + +static uint32_t get_curve_id(uint32_t width_bits) +{ + uint32_t curve_id = TEE_CRYPTO_ELEMENT_NONE; + + switch (width_bits) { + case ECC_CURVE_192: + curve_id = TEE_ECC_CURVE_NIST_P192; + break; + case ECC_CURVE_224: + curve_id = TEE_ECC_CURVE_NIST_P224; + break; + case ECC_CURVE_256: + curve_id = TEE_ECC_CURVE_NIST_P256; + break; + case ECC_CURVE_384: + curve_id = TEE_ECC_CURVE_NIST_P384; + break; + case ECC_CURVE_521: + curve_id = TEE_ECC_CURVE_NIST_P521; + break; + default: + printf("ECC curve is not supported!\n"); + break; + } + + return curve_id; +} + +static int asym_cipher_perf_run_test(int mode, size_t size, uint32_t n, + uint32_t l, int is_random, uint32_t warmup, + uint32_t verbosity, uint32_t width_bits, + uint32_t main_algo, uint32_t salt_len, + uint32_t algo) +{ + TEEC_Operation op = TEEC_OPERATION_INITIALIZER; + uint32_t cmd = TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PROCESS; + TEEC_Result res = TEEC_ERROR_GENERIC; + uint8_t keygen_dh_p[DH_MAX_SIZE] = { }; + uint8_t keygen_dh_g[DH_G_SIZE] = { }; + TEE_Attribute params[4] = { }; + size_t param_count = 0; + uint32_t curve_id = 0; + struct statistics stats = { }; + struct timespec ts = { }; + struct timespec t0 = { }; + struct timespec t1 = { }; + uint32_t ret_origin = 0; + uint8_t *buf = NULL; + size_t blen = 0; + double sd = 0; + int n0 = n; + + if (clock_getres(CLOCK_MONOTONIC, &ts) < 0) { + perror("clock_getres"); + return -1; + } + + verbose("random=%s, ", yesno(is_random == CRYPTO_USE_RANDOM)); + verbose("inner loops=%u, loops=%u, warm-up=%u s\n", l, n, warmup); + vverbose("Clock resolution is %jd ns\n", (intmax_t)ts.tv_sec * + 1000000000 + ts.tv_nsec); + + if (main_algo == ECDSA || main_algo == ECDH) { + curve_id = get_curve_id(width_bits); + if (curve_id == TEE_ERROR_BAD_PARAMETERS) + return -1; + } + + open_ta(); + + alloc_buffers(size, verbosity); + if (is_random == CRYPTO_USE_ZEROS) + memset((uint8_t *)in_shm.buffer, 0, size); + else + read_random(in_shm.buffer, size); + if (mode == MODE_DECRYPT && main_algo == RSA) + ((unsigned char *)(in_shm.buffer))[0] = 0x00; + + if (main_algo == X25519) + width_bits = WIDTH_BITS_25519; + + prepare_obj(width_bits, main_algo); + + if (main_algo == DH) { + read_random(keygen_dh_p, BITS_TO_BYTES(width_bits)); + read_random(keygen_dh_g, DH_G_SIZE); + keygen_dh_p[0] |= 0x2; /* make sure the p is full width */ + /* make sure keygen_dh_p is odd */ + keygen_dh_p[BITS_TO_BYTES(width_bits) - 1] |= 0x1; + + xtest_add_attr(¶m_count, params, TEE_ATTR_DH_PRIME, + keygen_dh_p, BITS_TO_BYTES(width_bits)); + xtest_add_attr(¶m_count, params, TEE_ATTR_DH_BASE, + keygen_dh_g, DH_G_SIZE); + } else if (main_algo == ECDSA || main_algo == ECDH) { + xtest_add_attr_value(¶m_count, params, TEE_ATTR_ECC_CURVE, + curve_id, 0); + } + + res = pack_attrs(params, param_count, &buf, &blen); + CHECK(res, "pack_attrs", return -1;); + + if (mode != MODE_GENKEYPAIR) + prepare_keypair(width_bits, buf, blen, mode, algo, main_algo); + + if (mode == MODE_SIGN || mode == MODE_VERIFY) + prepare_hash(size, main_algo); + + if (main_algo == RSA && salt_len > 0) { + params[0].attributeID = TEE_ATTR_RSA_PSS_SALT_LENGTH; + params[0].content.value.a = salt_len; + params[0].content.value.b = 0; + param_count = 1; + res = pack_attrs(params, param_count, &buf, &blen); + CHECK(res, "pack_attrs", return -1;); + } + + if (mode == MODE_GENKEYPAIR) { + cmd = TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PROCESS_GEN_KEYPAIR; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, + TEEC_MEMREF_TEMP_INOUT, + TEEC_NONE, TEEC_NONE); + op.params[0].value.a = width_bits; + op.params[0].value.b = l; + op.params[1].tmpref.buffer = buf; + op.params[1].tmpref.size = blen; + } else { + cmd = TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PROCESS; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, + TEEC_VALUE_INPUT, + TEEC_MEMREF_PARTIAL_INPUT, + TEEC_MEMREF_PARTIAL_OUTPUT); + + op.params[0].tmpref.buffer = buf; + op.params[0].tmpref.size = blen; + op.params[1].value.a = l; + op.params[1].value.b = mode; + + switch (mode) { + case MODE_ENCRYPT: + op.params[2].memref.parent = &in_shm; + op.params[2].memref.size = size; + op.params[3].memref.parent = &out_shm; + op.params[3].memref.size = out_shm.size; + break; + case MODE_SIGN: + op.params[2].memref.parent = &hash_shm; + op.params[2].memref.size = hash_shm.size; + op.params[3].memref.parent = &out_shm; + op.params[3].memref.size = out_shm.size; + break; + case MODE_DECRYPT: + prepare_enc_sign(size, mode, is_random, buf, blen); + op.params[2].memref.parent = &out_shm; + op.params[2].memref.size = out_shm.size; + op.params[3].memref.parent = &in_shm; + op.params[3].memref.size = size; + break; + case MODE_VERIFY: + prepare_enc_sign(size, mode, is_random, buf, blen); + op.params[2].memref.parent = &hash_shm; + op.params[2].memref.size = hash_shm.size; + op.params[3].memref.parent = &out_shm; + op.params[3].memref.size = out_shm.size; + break; + default: + fprintf(stderr, "Unexpected mode value\n"); + exit(1); + } + } + + if (warmup) + do_warmup(warmup); + + while (n-- > 0) { + if (mode == MODE_ENCRYPT && main_algo == RSA) { + /* Make sure the N > M */ + ((unsigned char *)(in_shm.buffer))[0] = 0x00; + /* Avoid the problem that the last encryption result is + less than the plaintext. */ + op.params[3].memref.size = out_shm.size; + } + + get_current_time(&t0); + + res = TEEC_InvokeCommand(&sess, cmd, &op, &ret_origin); + + check_res(res, "TEEC_InvokeCommand", &ret_origin); + + get_current_time(&t1); + + update_stats(&stats, timespec_diff_ns(&t0, &t1)); + if (n % (n0 / 10) == 0) + vverbose("#"); + } + + vverbose("\n"); + sd = stddev(&stats); + printf("min=%gus max=%gus mean=%gus stddev=%gus (cv %g%%) (%gMiB/s)\n", + stats.min / 1000, stats.max / 1000, stats.m / 1000, + sd / 1000, 100 * sd / stats.m, mb_per_sec(size, stats.m)); + verbose("2-sigma interval: %g..%gus (%g..%gMiB/s)\n", + (stats.m - 2 * sd) / 1000, (stats.m + 2 * sd) / 1000, + mb_per_sec(size, stats.m + 2 * sd), + mb_per_sec(size, stats.m - 2 * sd)); + + free_shm(); + free(buf); + close_ta(); + return 0; +} + +#define NEXT_ARG(i) \ + do { \ + if (++i == argc) { \ + fprintf(stderr, "%s: %s: missing argument\n", \ + argv[0], argv[i - 1]); \ + return 1; \ + } \ + } while (0); + +#define USAGE() usage(argv[0], width_bits, main_algo, mode, \ + salt_len, size, rsa_algo, warmup, l, n) + +static int get_hash_len(uint32_t algo) +{ + switch (algo) { + case RSAES_PKCS1_OAEP_SHA1: + return SHA1_LEN; + case RSAES_PKCS1_OAEP_SHA224: + return SHA224_LEN; + case RSAES_PKCS1_OAEP_SHA256: + return SHA256_LEN; + case RSAES_PKCS1_OAEP_SHA384: + return SHA384_LEN; + case RSAES_PKCS1_OAEP_SHA512: + return SHA512_LEN; + default: + fprintf(stderr, "The algo[%u] is not valid!\n", algo); + } + + return -1; +} + +static int get_hash_sign_len(uint32_t algo) +{ + switch (algo) { + case RSASSA_PKCS1_V1_5_SHA1: + case RSASSA_PKCS1_PSS_MGF1_SHA1: + return SHA1_LEN; + case RSASSA_PKCS1_V1_5_SHA224: + case RSASSA_PKCS1_PSS_MGF1_SHA224: + return SHA224_LEN; + case RSASSA_PKCS1_V1_5_SHA256: + case RSASSA_PKCS1_PSS_MGF1_SHA256: + return SHA256_LEN; + case RSASSA_PKCS1_V1_5_SHA384: + case RSASSA_PKCS1_PSS_MGF1_SHA384: + return SHA384_LEN; + case RSASSA_PKCS1_V1_5_SHA512: + case RSASSA_PKCS1_PSS_MGF1_SHA512: + return SHA512_LEN; + default: + fprintf(stderr, "The algo[%u] is not valid!\n", algo); + } + + return -1; +} + +static int check_rsa_cipher_params(uint32_t rsa_algo, int width_bits, int size) +{ + int width_bytes = BITS_TO_BYTES(width_bits); + int hash_len = 0; + + if (rsa_algo == 0) { + if (size > width_bytes) { + fprintf(stderr, "The size or algo is not valid!\n"); + return -1; + } + } else if (rsa_algo == RSAES_PKCS1_V1_5) { + if ((size + PKCS_V1_5_MIN) > width_bytes) { + fprintf(stderr, "The size or algo is not valid!\n"); + return -1; + } + } else if (rsa_algo > RSAES_PKCS1_V1_5) { + hash_len = get_hash_len(rsa_algo); + if (hash_len == -1) + return -1; + + if (OAEP_HASH_LEN(hash_len) >= (width_bytes - OAEP_OTHER_LEN)) { + fprintf(stderr, "The width_bits or algo is not valid!\n"); + return -1; + } else if (size > (width_bytes - OAEP_HASH_LEN(hash_len) - + OAEP_OTHER_LEN)) { + fprintf(stderr, "The size or algo is not valid!\n"); + return -1; + } + } + + return TEE_SUCCESS; +} + +static int check_rsa_hash_params(uint32_t rsa_algo, int width_bits, int size, + int salt_len) +{ + int width_bytes = BITS_TO_BYTES(width_bits); + int salt_temp = 0; + int hash_len = get_hash_sign_len(rsa_algo); + + if (hash_len == -1) + return -1; + + if (rsa_algo == RSASSA_PKCS1_V1_5_SHA1 && + width_bytes < hash_len + DERCODE_SHA1_LEN + PKCS_V1_5_MIN) { + fprintf(stderr, "The size or algo is not valid!\n"); + return -1; + } else if (rsa_algo != RSASSA_PKCS1_V1_5_SHA1 && + rsa_algo <= RSASSA_PKCS1_V1_5_SHA512 && + width_bytes < hash_len + DERCODE_SHA_LEN + PKCS_V1_5_MIN) { + fprintf(stderr, "The size or algo is not valid!\n"); + return -1; + } else if (rsa_algo >= RSASSA_PKCS1_PSS_MGF1_SHA1 && + rsa_algo <= RSASSA_PKCS1_PSS_MGF1_SHA512) { + salt_temp = (salt_len == 0 ? hash_len : salt_len); + + if (salt_temp > width_bytes || + width_bytes < hash_len + salt_temp + PSS_OTHER_LEN) { + fprintf(stderr, "The size or algo is not valid!\n"); + return -1; + } + } + + return TEE_SUCCESS; +} + +static int get_rsa_cipher_mode(char *argv) +{ + uint32_t rsa_cipher_mode = RSA_NOPAD; + + if (!strcasecmp(argv, "RSAES_PKCS1_V1_5")) + rsa_cipher_mode = RSAES_PKCS1_V1_5; + else if (!strcasecmp(argv, "RSAES_PKCS1_OAEP_SHA1")) + rsa_cipher_mode = RSAES_PKCS1_OAEP_SHA1; + else if (!strcasecmp(argv, "RSAES_PKCS1_OAEP_SHA224")) + rsa_cipher_mode = RSAES_PKCS1_OAEP_SHA224; + else if (!strcasecmp(argv, "RSAES_PKCS1_OAEP_SHA256")) + rsa_cipher_mode = RSAES_PKCS1_OAEP_SHA256; + else if (!strcasecmp(argv, "RSAES_PKCS1_OAEP_SHA384")) + rsa_cipher_mode = RSAES_PKCS1_OAEP_SHA384; + else if (!strcasecmp(argv, "RSAES_PKCS1_OAEP_SHA512")) + rsa_cipher_mode = RSAES_PKCS1_OAEP_SHA512; + else { + fprintf(stderr, "%s, invalid rsa cipher mode\n", argv); + return 1; + } + + return rsa_cipher_mode; +} + +static uint32_t get_rsa_sign_mode(char *argv) +{ + uint32_t rsa_sign_mode = RSASSA_PKCS1_V1_5_SHA1; + + if (!strcasecmp(argv, "RSASSA_PKCS1_V1_5_SHA1")) + rsa_sign_mode = RSASSA_PKCS1_V1_5_SHA1; + else if (!strcasecmp(argv, "RSASSA_PKCS1_V1_5_SHA224")) + rsa_sign_mode = RSASSA_PKCS1_V1_5_SHA224; + else if (!strcasecmp(argv, "RSASSA_PKCS1_V1_5_SHA256")) + rsa_sign_mode = RSASSA_PKCS1_V1_5_SHA256; + else if (!strcasecmp(argv, "RSASSA_PKCS1_V1_5_SHA384")) + rsa_sign_mode = RSASSA_PKCS1_V1_5_SHA384; + else if (!strcasecmp(argv, "RSASSA_PKCS1_V1_5_SHA512")) + rsa_sign_mode = RSASSA_PKCS1_V1_5_SHA512; + else if (!strcasecmp(argv, "RSASSA_PKCS1_PSS_MGF1_SHA1")) + rsa_sign_mode = RSASSA_PKCS1_PSS_MGF1_SHA1; + else if (!strcasecmp(argv, "RSASSA_PKCS1_PSS_MGF1_SHA224")) + rsa_sign_mode = RSASSA_PKCS1_PSS_MGF1_SHA224; + else if (!strcasecmp(argv, "RSASSA_PKCS1_PSS_MGF1_SHA256")) + rsa_sign_mode = RSASSA_PKCS1_PSS_MGF1_SHA256; + else if (!strcasecmp(argv, "RSASSA_PKCS1_PSS_MGF1_SHA384")) + rsa_sign_mode = RSASSA_PKCS1_PSS_MGF1_SHA384; + else if (!strcasecmp(argv, "RSASSA_PKCS1_PSS_MGF1_SHA512")) + rsa_sign_mode = RSASSA_PKCS1_PSS_MGF1_SHA512; + else { + fprintf(stderr, "%s, invalid rsa sign mode\n", argv); + return 1; + } + + return rsa_sign_mode; +} + +int asym_cipher_perf_runner_cmd_parser(int argc, char *argv[]) +{ + int verbosity = CRYPTO_DEF_VERBOSITY; + int is_random = CRYPTO_USE_ZEROS; + unsigned int n = CRYPTO_DEF_COUNT; + unsigned int l = CRYPTO_DEF_LOOPS; + int warmup = CRYPTO_DEF_WARMUP; + int mode = MODE_GENKEYPAIR; + int width_bits = 1024; + uint32_t main_algo = RSA; + uint32_t rsa_algo = 0; + int size = 1024; + int salt_len = 0; + int i = 0; + + /* Parse command line */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { + USAGE(); + return TEE_SUCCESS; + } + } + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-t")) { + NEXT_ARG(i); + if (!strcasecmp(argv[i], "DH")) + main_algo = DH; + else if (!strcasecmp(argv[i], "RSA")) + main_algo = RSA; + else if (!strcasecmp(argv[i], "ECDSA")) + main_algo = ECDSA; + else if (!strcasecmp(argv[i], "X25519")) + main_algo = X25519; + else { + fprintf(stderr, "%s, invalid main_algo\n", + argv[0]); + USAGE(); + return 1; + } + } else if (!strcmp(argv[i], "-m")) { + NEXT_ARG(i); + if (!strcasecmp(argv[i], "ENC")) + mode = MODE_ENCRYPT; + else if (!strcasecmp(argv[i], "DEC")) + mode = MODE_DECRYPT; + else if (!strcasecmp(argv[i], "SIGN")) + mode = MODE_SIGN; + else if (!strcasecmp(argv[i], "VERIFY")) + mode = MODE_VERIFY; + else if (!strcasecmp(argv[i], "KYEPAIR")) + mode = MODE_GENKEYPAIR; + else { + fprintf(stderr, "%s, invalid mode\n", + argv[0]); + USAGE(); + return 1; + } + } else if (!strcmp(argv[i], "-l")) { + NEXT_ARG(i); + l = atoi(argv[i]); + } else if (!strcmp(argv[i], "-n")) { + NEXT_ARG(i); + n = atoi(argv[i]); + } else if (!strcmp(argv[i], "--random") || + !strcmp(argv[i], "-r")) { + is_random = CRYPTO_USE_RANDOM; + } else if (!strcmp(argv[i], "-k")) { + NEXT_ARG(i); + size = atoi(argv[i]); + } else if (!strcmp(argv[i], "-d")) { + NEXT_ARG(i); + width_bits = atoi(argv[i]); + } else if (!strcmp(argv[i], "-a")) { + NEXT_ARG(i); + if (mode == MODE_ENCRYPT || mode == MODE_DECRYPT) + rsa_algo = get_rsa_cipher_mode(argv[i]); + else if (mode == MODE_SIGN || mode == MODE_VERIFY) + rsa_algo = get_rsa_sign_mode(argv[i]); + } else if (!strcmp(argv[i], "-s")) { + NEXT_ARG(i); + salt_len = atoi(argv[i]); + } else if (!strcmp(argv[i], "-v")) { + verbosity++; + } else if (!strcmp(argv[i], "--warmup") || + !strcmp(argv[i], "-w")) { + NEXT_ARG(i); + warmup = atoi(argv[i]); + } else { + fprintf(stderr, "%s: invalid argument: %s\n", + argv[0], argv[i]); + USAGE(); + return 1; + } + } + + if (main_algo == RSA) { + if (mode == MODE_ENCRYPT || mode == MODE_DECRYPT) { + if (check_rsa_cipher_params(rsa_algo, width_bits, size)) + return -1; + } else if (mode == MODE_SIGN || mode == MODE_VERIFY) { + if (check_rsa_hash_params(rsa_algo, width_bits, size, + salt_len)) + return -1; + } + } + + if (mode == MODE_GENKEYPAIR) + size = BITS_TO_BYTES(width_bits); + + return asym_cipher_perf_run_test(mode, size, n, l, is_random, warmup, + verbosity, width_bits, main_algo, + salt_len, rsa_algo); +} diff --git a/host/xtest/crypto_common.h b/host/xtest/crypto_common.h index 2b3915e09..7c42e0ef4 100644 --- a/host/xtest/crypto_common.h +++ b/host/xtest/crypto_common.h @@ -44,6 +44,7 @@ int hash_perf_runner_cmd_parser(int argc, char *argv[]); void hash_perf_run_test(int algo, size_t size, unsigned int n, unsigned int l, int random_in, int offset, int warmup, int verbosity); +int asym_cipher_perf_runner_cmd_parser(int argc, char *argv[]); #ifdef CFG_SECURE_DATA_PATH int sdp_basic_runner_cmd_parser(int argc, char *argv[]); diff --git a/host/xtest/xtest_main.c b/host/xtest/xtest_main.c index 5e907e263..8e3ec5fba 100644 --- a/host/xtest/xtest_main.c +++ b/host/xtest/xtest_main.c @@ -103,6 +103,7 @@ void usage(char *program) printf("\t--sha-perf [opts] Deprecated, same as --hash-perf\n"); printf("\t--hash-perf [opts] Hash performance testing tool (-h for usage)\n"); printf("\t--aes-perf [opts] AES performance testing tool (-h for usage)\n"); + printf("\t--asym-cipher-perf [opts] Aysmmetric cipher performance testing tool (-h for usage)\n"); #ifdef CFG_SECSTOR_TA_MGMT_PTA printf("\t--install-ta [directory or list of TAs]\n"); printf("\t Install TAs\n"); @@ -169,6 +170,8 @@ int main(int argc, char *argv[]) return hash_perf_runner_cmd_parser(argc-1, &argv[1]); else if (argc > 1 && !strcmp(argv[1], "--aes-perf")) return aes_perf_runner_cmd_parser(argc-1, &argv[1]); + else if (argc > 1 && !strcmp(argv[1], "--asym-cipher-perf")) + return asym_cipher_perf_runner_cmd_parser(argc-1, &argv[1]); #ifdef CFG_SECSTOR_TA_MGMT_PTA else if (argc > 1 && !strcmp(argv[1], "--install-ta")) return install_ta_runner_cmd_parser(argc - 1, argv + 1); diff --git a/ta/crypto_perf/include/ta_crypto_perf.h b/ta/crypto_perf/include/ta_crypto_perf.h index ba47efa5c..39c686ae1 100644 --- a/ta/crypto_perf/include/ta_crypto_perf.h +++ b/ta/crypto_perf/include/ta_crypto_perf.h @@ -18,6 +18,12 @@ #define TA_CRYPTO_PERF_CMD_CIPHER_PROCESS_SDP 2 #define TA_CRYPTO_PERF_CMD_HASH_PREPARE_OP 3 #define TA_CRYPTO_PERF_CMD_HASH_PROCESS 4 +#define TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_OBJ 5 +#define TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_HASH 6 +#define TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_KEYPAIR 7 +#define TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_ENC_SIGN 8 +#define TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PROCESS_GEN_KEYPAIR 9 +#define TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PROCESS 10 /* * Supported AES modes of operation @@ -53,4 +59,71 @@ #define TA_HMAC_SHA512 10 #define TA_HMAC_SM3 11 +/* + * Asymmetric cryptographic algorithms + */ +#define PKCS_V1_5_MIN 11 +#define BITS_TO_BYTES(len) (((len) + 7) / 8) +#define OAEP_HASH_LEN(hsz) ((hsz) * 2) +#define OAEP_OTHER_LEN 2 +#define PSS_OTHER_LEN 2 + +#define DERCODE_SHA1_LEN 15 +#define DERCODE_SHA_LEN 19 +#define SHA1_LEN 20 +#define SHA224_LEN 28 +#define SHA256_LEN 32 +#define SHA384_LEN 48 +#define SHA512_LEN 64 + +#define WIDTH_BITS_25519 256 + +#define DH 1 +#define RSA 2 +#define ECDSA 3 +#define ECDH 4 +#define X25519 5 + +#define ECC_CURVE_192 192 +#define ECC_CURVE_224 224 +#define ECC_CURVE_256 256 +#define ECC_CURVE_384 384 +#define ECC_CURVE_521 521 + +#define TEE_MAX_OUT_SIZE 4096 + +#define DH_MAX_SIZE 4096 +#define DH_G_SIZE 1 + +enum asym_cipher_mode { + MODE_ENCRYPT = 0, + MODE_DECRYPT = 1, + MODE_SIGN = 2, + MODE_VERIFY = 3, + MODE_GENKEYPAIR = 4, +}; + +enum rsa_cipher_mode { + RSA_NOPAD = 0, + RSAES_PKCS1_V1_5 = 1, + RSAES_PKCS1_OAEP_SHA1 = 2, + RSAES_PKCS1_OAEP_SHA224 = 3, + RSAES_PKCS1_OAEP_SHA256 = 4, + RSAES_PKCS1_OAEP_SHA384 = 5, + RSAES_PKCS1_OAEP_SHA512 = 6, +}; + +enum rsa_sign_mode { + RSASSA_PKCS1_V1_5_SHA1 = 0, + RSASSA_PKCS1_V1_5_SHA224 = 1, + RSASSA_PKCS1_V1_5_SHA256 = 2, + RSASSA_PKCS1_V1_5_SHA384 = 3, + RSASSA_PKCS1_V1_5_SHA512 = 4, + RSASSA_PKCS1_PSS_MGF1_SHA1 = 5, + RSASSA_PKCS1_PSS_MGF1_SHA224 = 6, + RSASSA_PKCS1_PSS_MGF1_SHA256 = 7, + RSASSA_PKCS1_PSS_MGF1_SHA384 = 8, + RSASSA_PKCS1_PSS_MGF1_SHA512 = 9, +}; + #endif /* TA_CRYPTO_PERF_H */ diff --git a/ta/crypto_perf/include/ta_crypto_perf_priv.h b/ta/crypto_perf/include/ta_crypto_perf_priv.h index 7b594f964..592701e3d 100644 --- a/ta/crypto_perf/include/ta_crypto_perf_priv.h +++ b/ta/crypto_perf/include/ta_crypto_perf_priv.h @@ -13,6 +13,13 @@ TEE_Result cmd_cipher_process(uint32_t param_types, TEE_Param params[4], bool sdp); TEE_Result cmd_hash_prepare_op(uint32_t param_types, TEE_Param params[4]); TEE_Result cmd_hash_process(uint32_t param_types, TEE_Param params[4]); +TEE_Result cmd_asym_process_keypair(uint32_t param_types, TEE_Param params[4]); +TEE_Result cmd_asym_process_rsa_ecc(uint32_t param_types, TEE_Param params[4]); +TEE_Result cmd_asym_prepare_obj(uint32_t param_types, TEE_Param params[4]); +TEE_Result cmd_asym_prepare_keypair(uint32_t param_types, TEE_Param params[4]); +TEE_Result cmd_asym_prepare_hash(uint32_t param_types, TEE_Param params[4]); +TEE_Result cmd_asym_prepare_enc_sign(uint32_t param_types, TEE_Param params[4]); +void cmd_clean_obj(void); void cmd_clean_res(void); #endif /* TA_CRYPTO_PERF_PRIV_H */ diff --git a/ta/crypto_perf/ta_crypto_perf.c b/ta/crypto_perf/ta_crypto_perf.c index 6f60eb93b..a28ccd42a 100644 --- a/ta/crypto_perf/ta_crypto_perf.c +++ b/ta/crypto_perf/ta_crypto_perf.c @@ -29,6 +29,8 @@ static int use_iv; static TEE_OperationHandle crypto_op; static uint32_t algo; +static TEE_OperationHandle crypto_op_enc_sign; +static TEE_ObjectHandle crypto_obj; static bool is_inbuf_a_secure_memref(TEE_Param *param) { @@ -465,8 +467,479 @@ TEE_Result cmd_hash_prepare_op(uint32_t param_types, TEE_Param params[4]) return TEE_SUCCESS; } +struct attr_packed { + uint32_t id; + uint32_t a; + uint32_t b; +}; + +static TEE_Result unpack_attrs(const uint8_t *buf, size_t blen, + TEE_Attribute **attrs, uint32_t *attr_count) +{ + TEE_Result res = TEE_SUCCESS; + TEE_Attribute *a = NULL; + const struct attr_packed *ap = NULL; + size_t num_attrs = 0; + const size_t num_attrs_size = sizeof(uint32_t); + + if (blen == 0) + goto out; + + if (IS_ALIGNED_WITH_TYPE(buf, uint32_t) || blen < num_attrs_size) + return TEE_ERROR_BAD_PARAMETERS; + num_attrs = *(uint32_t *)(void *)buf; + if ((blen - num_attrs_size) < (num_attrs * sizeof(*ap))) + return TEE_ERROR_BAD_PARAMETERS; + ap = (const struct attr_packed *)(const void *)(buf + num_attrs_size); + + if (num_attrs > 0) { + size_t n = 0; + + a = TEE_Malloc(num_attrs * sizeof(TEE_Attribute), 0); + if (!a) + return TEE_ERROR_OUT_OF_MEMORY; + for (n = 0; n < num_attrs; n++) { + uintptr_t p = 0; + + a[n].attributeID = ap[n].id; + if (ap[n].id & TEE_ATTR_FLAG_VALUE) { + a[n].content.value.a = ap[n].a; + a[n].content.value.b = ap[n].b; + continue; + } + + a[n].content.ref.length = ap[n].b; + p = (uintptr_t)ap[n].a; + if (p) { + if ((p + a[n].content.ref.length) > blen) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + p += (uintptr_t)buf; + } + a[n].content.ref.buffer = (void *)p; + } + } + + res = TEE_SUCCESS; +out: + if (res == TEE_SUCCESS) { + *attrs = a; + *attr_count = num_attrs; + } else { + TEE_Free(a); + } + return res; +} + +static TEE_Result get_rsa_cipher_algo(uint32_t algo_type) +{ + switch (algo_type) { + case RSA_NOPAD: + algo = TEE_ALG_RSA_NOPAD; + break; + case RSAES_PKCS1_V1_5: + algo = TEE_ALG_RSAES_PKCS1_V1_5; + break; + case RSAES_PKCS1_OAEP_SHA1: + algo = TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1; + break; + case RSAES_PKCS1_OAEP_SHA224: + algo = TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224; + break; + case RSAES_PKCS1_OAEP_SHA256: + algo = TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256; + break; + case RSAES_PKCS1_OAEP_SHA384: + algo = TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384; + break; + case RSAES_PKCS1_OAEP_SHA512: + algo = TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512; + break; + default: + EMSG("RSA enc or dec error algo_type"); + return TEE_ERROR_BAD_PARAMETERS; + } + + return TEE_SUCCESS; +} + +static TEE_Result get_rsa_hash_algo(uint32_t algo_type) +{ + switch (algo_type) { + case RSASSA_PKCS1_V1_5_SHA1: + algo = TEE_ALG_RSASSA_PKCS1_V1_5_SHA1; + break; + case RSASSA_PKCS1_V1_5_SHA224: + algo = TEE_ALG_RSASSA_PKCS1_V1_5_SHA224; + break; + case RSASSA_PKCS1_V1_5_SHA256: + algo = TEE_ALG_RSASSA_PKCS1_V1_5_SHA256; + break; + case RSASSA_PKCS1_V1_5_SHA384: + algo = TEE_ALG_RSASSA_PKCS1_V1_5_SHA384; + break; + case RSASSA_PKCS1_V1_5_SHA512: + algo = TEE_ALG_RSASSA_PKCS1_V1_5_SHA512; + break; + case RSASSA_PKCS1_PSS_MGF1_SHA1: + algo = TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1; + break; + case RSASSA_PKCS1_PSS_MGF1_SHA224: + algo = TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224; + break; + case RSASSA_PKCS1_PSS_MGF1_SHA256: + algo = TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256; + break; + case RSASSA_PKCS1_PSS_MGF1_SHA384: + algo = TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384; + break; + case RSASSA_PKCS1_PSS_MGF1_SHA512: + algo = TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512; + break; + default: + EMSG("RSA sign or verify error algo_type"); + return TEE_ERROR_BAD_PARAMETERS; + } + + return TEE_SUCCESS; +} + +static TEE_Result get_ecdsa_hash_algo(uint32_t width_bits) +{ + switch (width_bits) { + case ECC_CURVE_192: + algo = __OPTEE_ALG_ECDSA_P192; + break; + case ECC_CURVE_224: + algo = __OPTEE_ALG_ECDSA_P224; + break; + case ECC_CURVE_256: + algo = __OPTEE_ALG_ECDSA_P256; + break; + case ECC_CURVE_384: + algo = __OPTEE_ALG_ECDSA_P384; + break; + case ECC_CURVE_521: + algo = __OPTEE_ALG_ECDSA_P521; + break; + default: + EMSG("ECDSA sign or verify error width_bits"); + return TEE_ERROR_BAD_PARAMETERS; + } + + return TEE_SUCCESS; +} + +static TEE_Result get_algo(uint32_t tee_type, uint32_t mode, + uint32_t width_bits, uint32_t algo_type) +{ + TEE_Result res = TEE_SUCCESS; + + if (tee_type == RSA) { + if (mode == MODE_ENCRYPT || mode == MODE_DECRYPT) { + res = get_rsa_cipher_algo(algo_type); + } else if (mode == MODE_SIGN || mode == MODE_VERIFY) { + res = get_rsa_hash_algo(algo_type); + } else { + EMSG("RSA error mode"); + res = TEE_ERROR_BAD_PARAMETERS; + } + } else if (tee_type == ECDSA) { + if (mode == MODE_SIGN || mode == MODE_VERIFY) { + res = get_ecdsa_hash_algo(width_bits); + } else { + EMSG("ECDSA error mode"); + res = TEE_ERROR_BAD_PARAMETERS; + } + } + + return res; +} + +static uint32_t get_keypair_type(uint32_t value) +{ + switch (value) { + case DH: + return TEE_TYPE_DH_KEYPAIR; + case RSA: + return TEE_TYPE_RSA_KEYPAIR; + case ECDSA: + return TEE_TYPE_ECDSA_KEYPAIR; + case ECDH: + return TEE_TYPE_ECDH_KEYPAIR; + case X25519: + return TEE_TYPE_X25519_KEYPAIR; + default: + EMSG("The algo[%u] is not valid", algo); + } + + return TEE_TYPE_ILLEGAL_VALUE; +} + +TEE_Result cmd_asym_process_keypair(uint32_t param_types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + TEE_Result res = TEE_ERROR_GENERIC; + TEE_Attribute *attrs = NULL; + uint32_t attr_count = 0; + int width_bits = 0; + int n = 0; + uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + res = unpack_attrs(params[1].memref.buffer, params[1].memref.size, + &attrs, &attr_count); + if (res != TEE_SUCCESS) + return res; + + width_bits = params[0].value.a; + n = params[0].value.b; + + while (n--) { + res = TEE_GenerateKey(crypto_obj, width_bits, attrs, attr_count); + CHECK(res, "TEE_GenerateKey", goto out;); + TEE_ResetTransientObject(crypto_obj); + } + +out: + TEE_Free(attrs); + return res; +} + +TEE_Result cmd_asym_process_rsa_ecc(uint32_t param_types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + TEE_Result res = TEE_ERROR_GENERIC; + int n = 0; + uint32_t mode = 0; + uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_OUTPUT); + TEE_Attribute *attrs = NULL; + uint32_t attr_count = 0; + TEE_Result (*do_asym)(TEE_OperationHandle, const TEE_Attribute *, + uint32_t, const void *, uint32_t, void *, + uint32_t *) = NULL; + + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + res = unpack_attrs(params[0].memref.buffer, params[0].memref.size, + &attrs, &attr_count); + if (res != TEE_SUCCESS) + return res; + + n = params[1].value.a; + mode = params[1].value.b; + + if (mode == MODE_ENCRYPT) + do_asym = TEE_AsymmetricEncrypt; + else if (mode == MODE_DECRYPT) + do_asym = TEE_AsymmetricDecrypt; + else if (mode == MODE_SIGN) + do_asym = TEE_AsymmetricSignDigest; + + if (mode == MODE_VERIFY) { + while (n--) { + res = TEE_AsymmetricVerifyDigest(crypto_op, attrs, + attr_count, params[2].memref.buffer, + params[2].memref.size, params[3].memref.buffer, + params[3].memref.size); + CHECK(res, "TEE_AsymmetricVerifyDigest", goto out;); + } + } else { + while (n--) { + res = do_asym(crypto_op, attrs, attr_count, + params[2].memref.buffer, params[2].memref.size, + params[3].memref.buffer, ¶ms[3].memref.size); + + CHECK(res, "TEE_AsymmetricEncrypt", goto out;); + } + } + +out: + TEE_Free(attrs); + return res; +} + +TEE_Result cmd_asym_prepare_obj(uint32_t param_types, TEE_Param params[4]) +{ + TEE_Result res = TEE_ERROR_GENERIC; + uint32_t tee_type = TEE_TYPE_ILLEGAL_VALUE; + uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + tee_type = get_keypair_type(params[0].value.a); + if (tee_type == TEE_ERROR_BAD_PARAMETERS) + return TEE_ERROR_BAD_PARAMETERS; + + cmd_clean_obj(); + res = TEE_AllocateTransientObject(tee_type, params[0].value.b, + &crypto_obj); + CHECK(res, "TEE_AllocateTransientObject", return res;); + + return TEE_SUCCESS; +} + +TEE_Result cmd_asym_prepare_keypair(uint32_t param_types, TEE_Param params[4]) +{ + TEE_Result res = TEE_ERROR_GENERIC; + TEE_Attribute *attrs = NULL; + uint32_t attr_count = 0; + uint32_t width_bits = 0; + uint32_t algo_type = 0; + uint32_t tee_type = 0; + uint32_t mode = 0; + uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_NONE); + + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + mode = params[0].value.b; + width_bits = params[0].value.a; + tee_type = params[1].value.a; + algo_type = params[1].value.b; + + if (get_algo(tee_type, mode, width_bits, algo_type)) + return TEE_ERROR_BAD_PARAMETERS; + + res = unpack_attrs(params[2].memref.buffer, params[2].memref.size, + &attrs, &attr_count); + if (res != TEE_SUCCESS) + return res; + + res = TEE_GenerateKey(crypto_obj, width_bits, attrs, attr_count); + CHECK(res, "TEE_GenerateKey", goto out;); + + cmd_clean_res(); + res = TEE_AllocateOperation(&crypto_op, algo, mode, width_bits); + CHECK(res, "TEE_AllocateOperation", goto out;); + + res = TEE_SetOperationKey(crypto_op, crypto_obj); + CHECK(res, "TEE_SetOperationKey", goto out;); + + if (mode == MODE_DECRYPT) { + res = TEE_AllocateOperation(&crypto_op_enc_sign, algo, + MODE_ENCRYPT, width_bits); + CHECK(res, "TEE_AllocateOperation", goto out;); + + res = TEE_SetOperationKey(crypto_op_enc_sign, crypto_obj); + CHECK(res, "TEE_SetOperationKey", goto out;); + } else if (mode == MODE_VERIFY) { + res = TEE_AllocateOperation(&crypto_op_enc_sign, algo, + MODE_SIGN, width_bits); + CHECK(res, "TEE_AllocateOperation", goto out;); + + res = TEE_SetOperationKey(crypto_op_enc_sign, crypto_obj); + CHECK(res, "TEE_SetOperationKey", goto out;); + } + +out: + TEE_Free(attrs); + + return res; +} + +TEE_Result cmd_asym_prepare_hash(uint32_t param_types, TEE_Param params[4]) +{ + TEE_Result res = TEE_ERROR_GENERIC; + TEE_OperationHandle hash_op = NULL; + uint32_t hash_algo = 0; + uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE); + + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + if (params[0].value.a == ECDSA) + hash_algo = TEE_ALG_SHA1; + else + hash_algo = TEE_ALG_HASH_ALGO(TEE_ALG_GET_DIGEST_HASH(algo)); + + res = TEE_AllocateOperation(&hash_op, hash_algo, TEE_MODE_DIGEST, 0); + CHECK(res, "TEE_AllocateOperation", return res;); + + res = TEE_DigestDoFinal(hash_op, params[1].memref.buffer, + params[1].memref.size, params[2].memref.buffer, + ¶ms[2].memref.size); + TEE_FreeOperation(hash_op); + CHECK(res, "TEE_DigestDoFinal", return res;); + + return TEE_SUCCESS; +} + +TEE_Result cmd_asym_prepare_enc_sign(uint32_t param_types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + TEE_Result res = TEE_ERROR_GENERIC; + TEE_Attribute *attrs = NULL; + uint32_t attr_count = 0; + uint32_t mode = 0; + uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT); + + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + mode = params[2].value.a; + res = unpack_attrs(params[3].memref.buffer, params[3].memref.size, + &attrs, &attr_count); + if (res != TEE_SUCCESS) + return res; + + if (mode == MODE_DECRYPT) + res = TEE_AsymmetricEncrypt(crypto_op_enc_sign, NULL, 0, + params[0].memref.buffer, params[0].memref.size, + params[1].memref.buffer, ¶ms[1].memref.size); + else + res = TEE_AsymmetricSignDigest(crypto_op_enc_sign, attrs, + attr_count, + params[0].memref.buffer, + params[0].memref.size, + params[1].memref.buffer, + ¶ms[1].memref.size); + + TEE_Free(attrs); + if (mode == MODE_DECRYPT) + CHECK(res, "TEE_AsymmetricEncrypt", return res;); + else + CHECK(res, "TEE_AsymmetricSignDigest", return res;); + + return TEE_SUCCESS; +} + +void cmd_clean_obj(void) +{ + if (crypto_obj) + TEE_FreeTransientObject(crypto_obj); + crypto_obj = TEE_HANDLE_NULL; +} + void cmd_clean_res(void) { if (crypto_op) TEE_FreeOperation(crypto_op); + if (crypto_op_enc_sign) { + TEE_FreeOperation(crypto_op_enc_sign); + crypto_op_enc_sign = NULL; + } } diff --git a/ta/crypto_perf/ta_entry.c b/ta/crypto_perf/ta_entry.c index 0f94ffc75..929eaaab4 100644 --- a/ta/crypto_perf/ta_entry.c +++ b/ta/crypto_perf/ta_entry.c @@ -69,6 +69,18 @@ TEE_Result TA_InvokeCommandEntryPoint(void *pSessionContext, return cmd_hash_prepare_op(nParamTypes, pParams); case TA_CRYPTO_PERF_CMD_HASH_PROCESS: return cmd_hash_process(nParamTypes, pParams); + case TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PROCESS_GEN_KEYPAIR: + return cmd_asym_process_keypair(nParamTypes, pParams); + case TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PROCESS: + return cmd_asym_process_rsa_ecc(nParamTypes, pParams); + case TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_KEYPAIR: + return cmd_asym_prepare_keypair(nParamTypes, pParams); + case TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_HASH: + return cmd_asym_prepare_hash(nParamTypes, pParams); + case TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_OBJ: + return cmd_asym_prepare_obj(nParamTypes, pParams); + case TA_CRYPTO_PERF_CMD_ASYM_CIPHER_PREPARE_ENC_SIGN: + return cmd_asym_prepare_enc_sign(nParamTypes, pParams); default: return TEE_ERROR_BAD_PARAMETERS;