| // SPDX-License-Identifier: GPL-2.0 |
| /* Copyright (c) 2018, Linaro Limited */ |
| |
| #include "xtest_test.h" |
| #include "xtest_helpers.h" |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ta_crypt.h> |
| #include <tee_api_types.h> |
| #include <adbg.h> |
| |
| #ifdef OPENSSL_FOUND |
| #include <openssl/x509_vfy.h> |
| #include <openssl/pem.h> |
| #include <openssl/err.h> |
| #include <openssl/crypto.h> |
| #endif |
| |
| #include "regression_8100_ca_crt.h" |
| #include "regression_8100_mid_crt.h" |
| #include "regression_8100_my_crt.h" |
| #include "regression_8100_my_csr.h" |
| |
| #ifdef CFG_TA_MBEDTLS |
| |
| static void test_8101(ADBG_Case_t *c __maybe_unused) |
| { |
| #ifdef CFG_TA_MBEDTLS_SELF_TEST |
| TEEC_Session session = { }; |
| uint32_t ret_orig = 0; |
| |
| if (!ADBG_EXPECT_TEEC_SUCCESS(c, xtest_teec_open_session( |
| &session, &crypt_user_ta_uuid, |
| NULL, &ret_orig))) |
| return; |
| ADBG_EXPECT_TEEC_SUCCESS(c, |
| TEEC_InvokeCommand(&session, TA_CRYPT_CMD_MBEDTLS_SELF_TESTS, |
| NULL, &ret_orig)); |
| TEEC_CloseSession(&session); |
| #else |
| Do_ADBG_Log("CFG_TA_MBEDTLS_SELF_TEST not set, test skipped"); |
| #endif |
| } |
| ADBG_CASE_DEFINE(regression, 8101, test_8101, "TA mbedTLS self tests"); |
| |
| static int __printf(2, 3) myasprintf(char **strp, const char *fmt, ...) |
| { |
| char *str = NULL; |
| int rc = 0; |
| va_list ap; |
| |
| va_start(ap, fmt); |
| rc = vsnprintf(str, rc, fmt, ap); |
| va_end(ap); |
| if (rc <= 0) |
| goto out; |
| |
| str = malloc(rc); |
| if (!str) { |
| rc = -1; |
| goto out; |
| } |
| |
| va_start(ap, fmt); |
| rc = vsnprintf(str, rc, fmt, ap); |
| va_end(ap); |
| if (rc <= 0) |
| free(str); |
| else |
| *strp = str; |
| |
| out: |
| return rc; |
| } |
| |
| static void test_8102(ADBG_Case_t *c) |
| { |
| TEEC_Session session = { }; |
| TEEC_Operation op = TEEC_OPERATION_INITIALIZER; |
| uint32_t ret_orig = 0; |
| char *chain = NULL; |
| int clen = 0; |
| char *trust = NULL; |
| int tlen = 0; |
| |
| if (!ADBG_EXPECT_TEEC_SUCCESS(c, xtest_teec_open_session( |
| &session, &crypt_user_ta_uuid, |
| NULL, &ret_orig))) |
| return; |
| |
| clen = myasprintf(&chain, "%*s\n%*s", |
| (int)regression_8100_my_crt_size, |
| regression_8100_my_crt, |
| (int)regression_8100_mid_crt_size, |
| regression_8100_mid_crt); |
| if (!ADBG_EXPECT_COMPARE_SIGNED(c, clen, !=, -1)) |
| goto out; |
| tlen = myasprintf(&trust, "%*s", (int)regression_8100_ca_crt_size, |
| regression_8100_ca_crt); |
| if (!ADBG_EXPECT_COMPARE_SIGNED(c, tlen, !=, -1)) |
| goto out; |
| |
| op.params[0].tmpref.buffer = chain; |
| op.params[0].tmpref.size = clen; |
| op.params[1].tmpref.buffer = trust; |
| op.params[1].tmpref.size = tlen; |
| op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, |
| TEEC_MEMREF_TEMP_INPUT, |
| TEEC_NONE, TEEC_NONE); |
| |
| ADBG_EXPECT_TEEC_SUCCESS(c, |
| TEEC_InvokeCommand(&session, TA_CRYPT_CMD_MBEDTLS_CHECK_CERT, |
| &op, &ret_orig)); |
| out: |
| free(chain); |
| free(trust); |
| TEEC_CloseSession(&session); |
| } |
| ADBG_CASE_DEFINE(regression, 8102, test_8102, "TA mbedTLS test cert chain"); |
| |
| #ifdef OPENSSL_FOUND |
| static void osslerr(void) |
| { |
| while (true) { |
| unsigned long e = 0; |
| char b[256] = { }; |
| const char *f = NULL; |
| int l = 0; |
| |
| e = ERR_get_error_line(&f, &l); |
| if (!e) |
| return; |
| ERR_error_string_n(e, b, sizeof(b)); |
| Do_ADBG_Log("%s:%d \"%s\"", f, l, b); |
| } |
| } |
| |
| static bool get_cert(ADBG_Case_t *c, const char *crt_str, X509 **crt) |
| { |
| bool ret = false; |
| size_t slen = strlen(crt_str) + 1; |
| BIO *buf = BIO_new(BIO_s_mem()); |
| size_t b = 0; |
| |
| if (!ADBG_EXPECT_NOT_NULL(c, buf)) |
| goto out; |
| |
| b = BIO_write(buf, crt_str, slen); |
| if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, b, ==, slen)) |
| goto out; |
| |
| if (!PEM_read_bio_X509(buf, crt, 0, NULL)) |
| goto out; |
| |
| ret = true; |
| out: |
| if (!ret) |
| osslerr(); |
| BIO_free(buf); |
| return ret; |
| } |
| |
| static bool push_cert(ADBG_Case_t *c, const char *crt_str, STACK_OF(X509) *cs) |
| { |
| X509 *crt = NULL; |
| int rc = 0; |
| |
| if (!get_cert(c, crt_str, &crt)) |
| return false; |
| rc = sk_X509_push(cs, crt); |
| if (!ADBG_EXPECT_COMPARE_SIGNED(c, rc, >, 0)) { |
| osslerr(); |
| X509_free(crt); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static bool check(ADBG_Case_t *c, STACK_OF(X509) *trusted, |
| STACK_OF(X509) *untrusted, X509 *crt) |
| { |
| bool ret = false; |
| X509_STORE *store = NULL; |
| X509_STORE_CTX *csc = NULL; |
| X509_VERIFY_PARAM *pm = NULL; |
| int i = 0; |
| time_t vfy_time = 0; |
| |
| pm = X509_VERIFY_PARAM_new(); |
| vfy_time = 1526898005; /* Mon, 21 May 2018 10:20:05 +0000 */ |
| X509_VERIFY_PARAM_set_time(pm, vfy_time); |
| |
| store = X509_STORE_new(); |
| if (!ADBG_EXPECT_NOT_NULL(c, store)) |
| goto out; |
| X509_STORE_set_flags(store, 0); |
| if (!ADBG_EXPECT_TRUE(c, X509_STORE_set1_param(store, pm))) |
| goto out; |
| |
| csc = X509_STORE_CTX_new(); |
| if (!ADBG_EXPECT_NOT_NULL(c, csc)) |
| goto out; |
| |
| if (!ADBG_EXPECT_TRUE(c, X509_STORE_CTX_init(csc, store, crt, |
| untrusted))) |
| goto out; |
| X509_STORE_CTX_trusted_stack(csc, trusted); |
| |
| i = X509_verify_cert(csc); |
| if (!ADBG_EXPECT_COMPARE_SIGNED(c, i, >, 0)) |
| goto out; |
| i = X509_STORE_CTX_get_error(csc); |
| if (!ADBG_EXPECT_COMPARE_SIGNED(c, i, ==, X509_V_OK)) |
| goto out; |
| ret = true; |
| out: |
| if (!ret) |
| osslerr(); |
| X509_VERIFY_PARAM_free(pm); |
| X509_STORE_free(store); |
| X509_STORE_CTX_free(csc); |
| return ret; |
| } |
| |
| static bool verify_cert(ADBG_Case_t *c, const char *ca, const char *mid, |
| const char *cert) |
| { |
| bool ret = false; |
| STACK_OF(X509) *trusted = NULL; |
| STACK_OF(X509) *untrusted = NULL; |
| X509 *crt = NULL; |
| |
| trusted = sk_X509_new_null(); |
| if (!ADBG_EXPECT_NOT_NULL(c, trusted)) |
| goto out; |
| untrusted = sk_X509_new_null(); |
| if (!ADBG_EXPECT_NOT_NULL(c, untrusted)) |
| goto out; |
| |
| if (!ADBG_EXPECT_TRUE(c, get_cert(c, cert, &crt))) |
| goto out; |
| if (!ADBG_EXPECT_TRUE(c, push_cert(c, mid, untrusted))) |
| goto out; |
| if (!ADBG_EXPECT_TRUE(c, push_cert(c, ca, trusted))) |
| goto out; |
| |
| ret = ADBG_EXPECT_TRUE(c, check(c, trusted, untrusted, crt)); |
| out: |
| if (!ret) |
| osslerr(); |
| X509_free(crt); |
| sk_X509_pop_free(untrusted, X509_free); |
| sk_X509_pop_free(trusted, X509_free); |
| return ret; |
| } |
| #else /*!OPENSSL_FOUND*/ |
| static bool verify_cert(ADBG_Case_t *c, const char *ca, |
| const char *mid, const char *cert) |
| { |
| UNUSED(c); |
| UNUSED(ca); |
| UNUSED(mid); |
| UNUSED(cert); |
| Do_ADBG_Log("OpenSSL not available, skipping certificate verification"); |
| return true; |
| } |
| #endif |
| |
| static void test_8103(ADBG_Case_t *c) |
| { |
| TEEC_Result res = TEEC_ERROR_GENERIC; |
| TEEC_Session session = { }; |
| TEEC_Operation op = TEEC_OPERATION_INITIALIZER; |
| uint32_t ret_orig = 0; |
| char *csr = NULL; |
| int clen = 0; |
| char cert[2048]; |
| char chain[4096]; |
| char *ca = NULL; |
| |
| if (!ADBG_EXPECT_TEEC_SUCCESS(c, xtest_teec_open_session( |
| &session, &crypt_user_ta_uuid, |
| NULL, &ret_orig))) |
| return; |
| |
| clen = myasprintf(&csr, "%*s", (int)regression_8100_my_csr_size, |
| regression_8100_my_csr); |
| if (!ADBG_EXPECT_COMPARE_SIGNED(c, clen, >=, 0)) |
| goto out; |
| op.params[0].tmpref.buffer = csr; |
| op.params[0].tmpref.size = clen; |
| op.params[1].tmpref.buffer = cert; |
| op.params[1].tmpref.size = sizeof(cert); |
| op.params[2].tmpref.buffer = chain; |
| op.params[2].tmpref.size = sizeof(chain); |
| op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, |
| TEEC_MEMREF_TEMP_OUTPUT, |
| TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE); |
| res = TEEC_InvokeCommand(&session, TA_CRYPT_CMD_MBEDTLS_SIGN_CERT, &op, |
| &ret_orig); |
| if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) |
| goto out; |
| |
| myasprintf(&ca, "%*s", (int)regression_8100_ca_crt_size, |
| regression_8100_ca_crt); |
| if (!ADBG_EXPECT_NOT_NULL(c, ca)) |
| goto out; |
| verify_cert(c, ca, op.params[2].tmpref.buffer, |
| op.params[1].tmpref.buffer); |
| out: |
| free(ca); |
| free(csr); |
| TEEC_CloseSession(&session); |
| } |
| ADBG_CASE_DEFINE(regression, 8103, test_8103, |
| "TA mbedTLS process certificate request"); |
| #endif /*CFG_TA_MBEDTLS*/ |