diff --git a/Makefile b/Makefile index 179e07a20..cc9060a05 100644 --- a/Makefile +++ b/Makefile @@ -1177,6 +1177,7 @@ $(eval $(call assert_booleans,\ HW_ASSISTED_COHERENCY \ MEASURED_BOOT \ DICE_PROTECTION_ENVIRONMENT \ + RMMD_ENABLE_EL3_TOKEN_SIGN \ DRTM_SUPPORT \ NS_TIMER_SWITCH \ OVERRIDE_LIBC \ @@ -1331,6 +1332,7 @@ $(eval $(call add_defines,\ ENABLE_PMF \ ENABLE_PSCI_STAT \ ENABLE_RME \ + RMMD_ENABLE_EL3_TOKEN_SIGN \ ENABLE_RUNTIME_INSTRUMENTATION \ ENABLE_SME_FOR_NS \ ENABLE_SME2_FOR_NS \ diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index ae5aa2305..118b537e2 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -15,6 +15,7 @@ #endif #if ENABLE_RME #include +#include #endif #include #if TRNG_SUPPORT @@ -376,6 +377,15 @@ int plat_rmmd_get_cca_attest_token(uintptr_t buf, size_t *len, uint64_t *remaining_len); int plat_rmmd_get_cca_realm_attest_key(uintptr_t buf, size_t *len, unsigned int type); +/* The following 3 functions are to be implement if + * RMMD_ENABLE_EL3_TOKEN_SIGN=1. + * The following three functions are expected to return E_RMM_* error codes. + */ +int plat_rmmd_el3_token_sign_get_rak_pub(uintptr_t buf, size_t *len, + unsigned int type); +int plat_rmmd_el3_token_sign_push_req( + const struct el3_token_sign_request *req); +int plat_rmmd_el3_token_sign_pull_resp(struct el3_token_sign_response *resp); size_t plat_rmmd_get_el3_rmm_shared_mem(uintptr_t *shared); int plat_rmmd_load_manifest(struct rmm_manifest *manifest); #endif diff --git a/include/services/rmm_el3_token_sign.h b/include/services/rmm_el3_token_sign.h new file mode 100644 index 000000000..154940c4a --- /dev/null +++ b/include/services/rmm_el3_token_sign.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RMM_EL3_TOKEN_SIGN_H +#define RMM_EL3_TOKEN_SIGN_H + +#include +#include +#include + +/* + * Defines member of structure and reserves space + * for the next member with specified offset. + */ +/* cppcheck-suppress [misra-c2012-20.7] */ +#define SET_MEMBER(member, start, end) \ + union { \ + member; \ + unsigned char reserved##end[((end) - (start))]; \ + } + +#define EL3_TOKEN_RESPONSE_MAX_SIG_LEN U(512) + +struct el3_token_sign_request { + SET_MEMBER(uint32_t sig_alg_id, 0x0, 0x8); + SET_MEMBER(uint64_t rec_granule, 0x8, 0x10); + SET_MEMBER(uint64_t req_ticket, 0x10, 0x18); + SET_MEMBER(uint32_t hash_alg_id, 0x18, 0x20); + SET_MEMBER(uint8_t hash_buf[SHA512_DIGEST_SIZE], 0x20, 0x60); +}; + +CASSERT(__builtin_offsetof(struct el3_token_sign_request, sig_alg_id) == 0x0U, + assert_el3_token_sign_request_sig_alg_mismatch); +CASSERT(__builtin_offsetof(struct el3_token_sign_request, rec_granule) == 0x8U, + assert_el3_token_sign_request_rec_granule_mismatch); +CASSERT(__builtin_offsetof(struct el3_token_sign_request, req_ticket) == 0x10U, + assert_el3_token_sign_request_req_ticket_mismatch); +CASSERT(__builtin_offsetof(struct el3_token_sign_request, hash_alg_id) == 0x18U, + assert_el3_token_sign_request_hash_alg_id_mismatch); +CASSERT(__builtin_offsetof(struct el3_token_sign_request, hash_buf) == 0x20U, + assert_el3_token_sign_request_hash_buf_mismatch); + + +struct el3_token_sign_response { + SET_MEMBER(uint64_t rec_granule, 0x0, 0x8); + SET_MEMBER(uint64_t req_ticket, 0x8, 0x10); + SET_MEMBER(uint16_t sig_len, 0x10, 0x12); + SET_MEMBER(uint8_t signature_buf[EL3_TOKEN_RESPONSE_MAX_SIG_LEN], 0x12, 0x212); +}; + +CASSERT(__builtin_offsetof(struct el3_token_sign_response, rec_granule) == 0x0U, + assert_el3_token_sign_resp_rec_granule_mismatch); +CASSERT(__builtin_offsetof(struct el3_token_sign_response, req_ticket) == 0x8U, + assert_el3_token_sign_resp_req_ticket_mismatch); +CASSERT(__builtin_offsetof(struct el3_token_sign_response, sig_len) == 0x10U, + assert_el3_token_sign_resp_sig_len_mismatch); +CASSERT(__builtin_offsetof(struct el3_token_sign_response, signature_buf) == 0x12U, + assert_el3_token_sign_resp_sig_buf_mismatch); + +#endif /* RMM_EL3_TOKEN_SIGN_H */ diff --git a/include/services/rmmd_svc.h b/include/services/rmmd_svc.h index 635c28e48..0cc8628a6 100644 --- a/include/services/rmmd_svc.h +++ b/include/services/rmmd_svc.h @@ -129,8 +129,43 @@ /* 0x1B3 */ #define RMM_ATTEST_GET_PLAT_TOKEN SMC64_RMMD_EL3_FID(U(3)) +/* Starting RMM-EL3 interface version 0.4 */ +#define RMM_EL3_FEATURES SMC64_RMMD_EL3_FID(U(4)) +#define RMM_EL3_FEAT_REG_0_IDX U(0) +/* Bit 0 of FEAT_REG_0 */ +/* 1 - the feature is present in EL3 , 0 - the feature is absent */ +#define RMM_EL3_FEAT_REG_0_EL3_TOKEN_SIGN_MASK U(0x1) + +/* + * Function codes to support attestation where EL3 is used to sign + * realm attestation tokens. In this model, the private key is not + * exposed to the RMM. + * The arguments to this SMC are: + * arg0 - Function ID. + * arg1 - Opcode, one of: + * RMM_EL3_TOKEN_SIGN_PUSH_REQ_OP, + * RMM_EL3_TOKEN_SIGN_PULL_RESP_OP, + * RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP + * arg2 - Pointer to buffer with request/response structures, + * which is in the RMM<->EL3 shared buffer. + * arg3 - Buffer size of memory pointed by arg2. + * arg4 - ECC Curve, when opcode is RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP + * The return arguments are: + * ret0 - Status/Error + * ret1 - Size of public key if opcode is RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP + */ +#define RMM_EL3_TOKEN_SIGN SMC64_RMMD_EL3_FID(U(5)) + +/* Opcodes for RMM_EL3_TOKEN_SIGN */ +#define RMM_EL3_TOKEN_SIGN_PUSH_REQ_OP U(1) +#define RMM_EL3_TOKEN_SIGN_PULL_RESP_OP U(2) +#define RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP U(3) + /* ECC Curve types for attest key generation */ -#define ATTEST_KEY_CURVE_ECC_SECP384R1 0 +#define ATTEST_KEY_CURVE_ECC_SECP384R1 U(0) + +/* Identifier for the hash algorithm used for attestation signing */ +#define EL3_TOKEN_SIGN_HASH_ALG_SHA384 U(1) /* * RMM_BOOT_COMPLETE originates on RMM when the boot finishes (either cold @@ -153,7 +188,7 @@ * Increase this when a bug is fixed, or a feature is added without * breaking compatibility. */ -#define RMM_EL3_IFC_VERSION_MINOR (U(3)) +#define RMM_EL3_IFC_VERSION_MINOR (U(4)) #define RMM_EL3_INTERFACE_VERSION \ (((RMM_EL3_IFC_VERSION_MAJOR << 16) & 0x7FFFF) | \ diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 8c884b4de..584542c30 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -409,3 +409,6 @@ EARLY_CONSOLE := 0 # Allow platforms to save/restore DSU PMU registers over a power cycle. # Disabled by default and must be enabled by individual platforms. PRESERVE_DSU_PMU_REGS := 0 + +# Enable RMMD to forward attestation requests from RMM to EL3. +RMMD_ENABLE_EL3_TOKEN_SIGN := 0 diff --git a/plat/arm/board/fvp/fvp_el3_token_sign.c b/plat/arm/board/fvp/fvp_el3_token_sign.c new file mode 100644 index 000000000..282f94afb --- /dev/null +++ b/plat/arm/board/fvp/fvp_el3_token_sign.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include + +static struct el3_token_sign_request el3_req = { 0 }; +static bool el3_req_valid; + +/* + * According to https://www.secg.org/sec1-v2.pdf 2.3.3 + * the size of the ECDSA P384 public key is 97 bytes, + * with the first byte being 0x04. + */ +static uint8_t sample_attest_pub_key[] = { + 0x04, 0x76, 0xf9, 0x88, 0x09, 0x1b, 0xe5, 0x85, 0xed, 0x41, + 0x80, 0x1a, 0xec, 0xfa, 0xb8, 0x58, 0x54, 0x8c, 0x63, 0x05, + 0x7e, 0x16, 0xb0, 0xe6, 0x76, 0x12, 0x0b, 0xbd, 0x0d, 0x2f, + 0x9c, 0x29, 0xe0, 0x56, 0xc5, 0xd4, 0x1a, 0x01, 0x30, 0xeb, + 0x9c, 0x21, 0x51, 0x78, 0x99, 0xdc, 0x23, 0x14, 0x6b, 0x28, + 0xe1, 0xb0, 0x62, 0xbd, 0x3e, 0xa4, 0xb3, 0x15, 0xfd, 0x21, + 0x9f, 0x1c, 0xbb, 0x52, 0x8c, 0xb6, 0xe7, 0x4c, 0xa4, 0x9b, + 0xe1, 0x67, 0x73, 0x73, 0x4f, 0x61, 0xa1, 0xca, 0x61, 0x03, + 0x1b, 0x2b, 0xbf, 0x3d, 0x91, 0x8f, 0x2f, 0x94, 0xff, 0xc4, + 0x22, 0x8e, 0x50, 0x91, 0x95, 0x44, 0xae +}; + +/* + * FVP does not support HES, so provide 0's as keys. + */ +int plat_rmmd_el3_token_sign_get_rak_pub(uintptr_t buf, size_t *len, + unsigned int type) +{ + (void)type; + if (*len < sizeof(sample_attest_pub_key)) { + return E_RMM_INVAL; + } + + if (type != ATTEST_KEY_CURVE_ECC_SECP384R1) { + ERROR("Invalid ECC curve specified\n"); + return E_RMM_INVAL; + } + + *len = sizeof(sample_attest_pub_key); + + (void)memcpy((void *)buf, sample_attest_pub_key, + sizeof(sample_attest_pub_key)); + + return 0; +} + +int plat_rmmd_el3_token_sign_push_req(const struct el3_token_sign_request *req) +{ + /* + * TODO: Today this function is called with a lock held on the + * RMM<->EL3 shared buffer. In the future, we may move to a + * different design that may require handling multi-threaded + * calls to this function, for example, if we have a per CPU + * buffer between RMM and EL3. + */ + if (el3_req_valid) { + return E_RMM_AGAIN; + } + + el3_req = *req; + + if ((el3_req.hash_alg_id != EL3_TOKEN_SIGN_HASH_ALG_SHA384) || + (el3_req.sig_alg_id != ATTEST_KEY_CURVE_ECC_SECP384R1)) { + return E_RMM_INVAL; + } + + el3_req_valid = true; + + return 0; +} + +int plat_rmmd_el3_token_sign_pull_resp(struct el3_token_sign_response *resp) +{ + if (!el3_req_valid) { + return E_RMM_AGAIN; + } + + resp->rec_granule = el3_req.rec_granule; + resp->req_ticket = el3_req.req_ticket; + resp->sig_len = (uint16_t)sizeof(resp->signature_buf); + /* TODO: Provide real signature */ + memset(resp->signature_buf, 0, sizeof(resp->signature_buf)); + + el3_req_valid = false; + + return 0; +} diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index feae8029f..ec2a5e961 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -264,7 +264,8 @@ BL2_SOURCES += plat/arm/board/fvp/aarch64/fvp_helpers.S \ plat/arm/board/fvp/fvp_cpu_pwr.c BL31_SOURCES += plat/arm/board/fvp/fvp_plat_attest_token.c \ - plat/arm/board/fvp/fvp_realm_attest_key.c + plat/arm/board/fvp/fvp_realm_attest_key.c \ + plat/arm/board/fvp/fvp_el3_token_sign.c endif ifeq (${ENABLE_FEAT_RNG_TRAP},1) diff --git a/services/std_svc/rmmd/rmmd_attest.c b/services/std_svc/rmmd/rmmd_attest.c index f73236cb7..7d4ea701c 100644 --- a/services/std_svc/rmmd/rmmd_attest.c +++ b/services/std_svc/rmmd/rmmd_attest.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2022-2024, Arm Limited. All rights reserved. + * Copyright (c) 2024, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -12,7 +13,8 @@ #include #include #include "rmmd_private.h" -#include +#include +#include static spinlock_t lock; @@ -156,10 +158,110 @@ int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_size, (unsigned int)ecc_curve); if (err != 0) { ERROR("Failed to get attestation key: %d.\n", err); - err = E_RMM_UNK; + err = E_RMM_UNK; } spin_unlock(&lock); return err; } + +static int rmmd_el3_token_sign_push_req(uint64_t buf_pa, uint64_t buf_size) +{ + int err; + + err = validate_buffer_params(buf_pa, buf_size); + if (err != 0) { + return err; + } + + if (buf_size < sizeof(struct el3_token_sign_request)) { + return E_RMM_INVAL; + } + + spin_lock(&lock); + + /* Call platform port to handle attestation toekn signing request. */ + err = plat_rmmd_el3_token_sign_push_req((struct el3_token_sign_request *)buf_pa); + + spin_unlock(&lock); + + return err; +} + +static int rmmd_el3_token_sign_pull_resp(uint64_t buf_pa, uint64_t buf_size) +{ + int err; + + err = validate_buffer_params(buf_pa, buf_size); + if (err != 0) { + return err; + } + + + if (buf_size < sizeof(struct el3_token_sign_response)) { + return E_RMM_INVAL; + } + + spin_lock(&lock); + + /* Pull attestation signing response from HES. */ + err = plat_rmmd_el3_token_sign_pull_resp( + (struct el3_token_sign_response *)buf_pa); + + spin_unlock(&lock); + + return err; +} + +static int rmmd_attest_get_attest_pub_key(uint64_t buf_pa, uint64_t *buf_size, + uint64_t ecc_curve) +{ + int err; + + err = validate_buffer_params(buf_pa, *buf_size); + if (err != 0) { + return err; + } + + if (ecc_curve != ATTEST_KEY_CURVE_ECC_SECP384R1) { + ERROR("Invalid ECC curve specified\n"); + return E_RMM_INVAL; + } + + spin_lock(&lock); + + /* Get the Realm attestation public key from platform port. */ + err = plat_rmmd_el3_token_sign_get_rak_pub( + (uintptr_t)buf_pa, buf_size, (unsigned int)ecc_curve); + + spin_unlock(&lock); + if (err != 0) { + ERROR("Failed to get attestation public key from HES: %d.\n", + err); + err = E_RMM_UNK; + } + + + return err; +} + +uint64_t rmmd_el3_token_sign(void *handle, uint64_t opcode, uint64_t x2, + uint64_t x3, uint64_t x4) +{ + int ret; + + switch (opcode) { + case RMM_EL3_TOKEN_SIGN_PUSH_REQ_OP: + ret = rmmd_el3_token_sign_push_req(x2, x3); + SMC_RET1(handle, ret); + case RMM_EL3_TOKEN_SIGN_PULL_RESP_OP: + ret = rmmd_el3_token_sign_pull_resp(x2, x3); + SMC_RET1(handle, ret); + case RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP: + ret = rmmd_attest_get_attest_pub_key(x2, &x3, x4); + SMC_RET2(handle, ret, x3); + default: + SMC_RET1(handle, SMC_UNK); + } +} diff --git a/services/std_svc/rmmd/rmmd_main.c b/services/std_svc/rmmd/rmmd_main.c index 153bb0110..d063ea34d 100644 --- a/services/std_svc/rmmd/rmmd_main.c +++ b/services/std_svc/rmmd/rmmd_main.c @@ -441,6 +441,21 @@ static int gpt_to_gts_error(int error, uint32_t smc_fid, uint64_t address) return ret; } +static int rmm_el3_ifc_get_feat_register(uint64_t feat_reg_idx, + uint64_t *feat_reg) +{ + if (feat_reg_idx != RMM_EL3_FEAT_REG_0_IDX) { + ERROR("RMMD: Failed to get feature register %ld\n", feat_reg_idx); + return E_RMM_INVAL; + } + + *feat_reg = 0UL; +#if RMMD_ENABLE_EL3_TOKEN_SIGN + *feat_reg |= RMM_EL3_FEAT_REG_0_EL3_TOKEN_SIGN_MASK; +#endif + return E_RMM_OK; +} + /******************************************************************************* * This function handles RMM-EL3 interface SMCs ******************************************************************************/ @@ -448,7 +463,7 @@ uint64_t rmmd_rmm_el3_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags) { - uint64_t remaining_len = 0; + uint64_t remaining_len = 0UL; uint32_t src_sec_state; int ret; @@ -479,7 +494,13 @@ uint64_t rmmd_rmm_el3_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, case RMM_ATTEST_GET_REALM_KEY: ret = rmmd_attest_get_signing_key(x1, &x2, x3); SMC_RET2(handle, ret, x2); - + case RMM_EL3_FEATURES: + ret = rmm_el3_ifc_get_feat_register(x1, &x2); + SMC_RET2(handle, ret, x2); +#if RMMD_ENABLE_EL3_TOKEN_SIGN + case RMM_EL3_TOKEN_SIGN: + return rmmd_el3_token_sign(handle, x1, x2, x3, x4); +#endif case RMM_BOOT_COMPLETE: VERBOSE("RMMD: running rmmd_rmm_sync_exit\n"); rmmd_rmm_sync_exit(x1); diff --git a/services/std_svc/rmmd/rmmd_private.h b/services/std_svc/rmmd/rmmd_private.h index 6d3b5ecdc..0ce104d0d 100644 --- a/services/std_svc/rmmd/rmmd_private.h +++ b/services/std_svc/rmmd/rmmd_private.h @@ -51,6 +51,8 @@ int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_size, uint64_t *remaining_len); int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_size, uint64_t ecc_curve); +uint64_t rmmd_el3_token_sign(void *handle, uint64_t x1, uint64_t x2, + uint64_t x3, uint64_t x4); /* Assembly helpers */ uint64_t rmmd_rmm_enter(uint64_t *c_rt_ctx);