| From 0df82487a7a253c601ca20ca1bd64fbb9ed64230 Mon Sep 17 00:00:00 2001 |
| From: Vishnu Banavath <vishnu.banavath@arm.com> |
| Date: Fri, 3 Dec 2021 19:19:24 +0000 |
| Subject: [PATCH 06/19] Add secure storage ipc backend |
| |
| Add secure storage ipc ff-m implementation which may use |
| openamp as rpc to communicate with other processor. |
| |
| Upstream-Status: Pending |
| Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com> |
| Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org> |
| --- |
| .../service/common/psa_ipc/service_psa_ipc.c | 143 +++++++++++- |
| .../secure_storage_ipc/component.cmake | 14 ++ |
| .../secure_storage_ipc/secure_storage_ipc.c | 214 ++++++++++++++++++ |
| .../secure_storage_ipc/secure_storage_ipc.h | 52 +++++ |
| deployments/se-proxy/se-proxy.cmake | 1 + |
| 5 files changed, 420 insertions(+), 4 deletions(-) |
| create mode 100644 components/service/secure_storage/backend/secure_storage_ipc/component.cmake |
| create mode 100644 components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c |
| create mode 100644 components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h |
| |
| diff --git a/components/service/common/psa_ipc/service_psa_ipc.c b/components/service/common/psa_ipc/service_psa_ipc.c |
| index e8093c20a523..95a07c135f31 100644 |
| --- a/components/service/common/psa_ipc/service_psa_ipc.c |
| +++ b/components/service/common/psa_ipc/service_psa_ipc.c |
| @@ -16,6 +16,52 @@ |
| #include <psa/client.h> |
| #include "service_psa_ipc_openamp_lib.h" |
| |
| +static struct psa_invec *psa_call_in_vec_param(uint8_t *req) |
| +{ |
| + return (struct psa_invec *)(req + sizeof(struct ns_openamp_msg)); |
| +} |
| + |
| +static struct psa_outvec *psa_call_out_vec_param(uint8_t *req, size_t in_len) |
| +{ |
| + return (struct psa_outvec *)(req + sizeof(struct ns_openamp_msg) + |
| + (in_len * sizeof(struct psa_invec))); |
| +} |
| + |
| +static size_t psa_call_header_len(const struct psa_invec *in_vec, size_t in_len, |
| + struct psa_outvec *out_vec, size_t out_len) |
| +{ |
| + return sizeof(struct ns_openamp_msg) + (in_len * sizeof(*in_vec)) + |
| + (out_len * sizeof(*out_vec)); |
| +} |
| + |
| +static size_t psa_call_in_vec_len(const struct psa_invec *in_vec, size_t in_len) |
| +{ |
| + size_t req_len = 0; |
| + int i; |
| + |
| + if (!in_vec || !in_len) |
| + return 0; |
| + |
| + for (i = 0; i < in_len; i++) |
| + req_len += in_vec[i].len; |
| + |
| + return req_len; |
| +} |
| + |
| +static size_t psa_call_out_vec_len(const struct psa_outvec *out_vec, size_t out_len) |
| +{ |
| + size_t resp_len = 0; |
| + int i; |
| + |
| + if (!out_vec || !out_len) |
| + return 0; |
| + |
| + for (i = 0; i < out_len; i++) |
| + resp_len += out_vec[i].len; |
| + |
| + return resp_len; |
| +} |
| + |
| psa_handle_t psa_connect(struct rpc_caller *caller, uint32_t sid, |
| uint32_t version) |
| { |
| @@ -31,7 +77,7 @@ psa_handle_t psa_connect(struct rpc_caller *caller, uint32_t sid, |
| rpc_handle = rpc_caller_begin(caller, &req, |
| sizeof(struct ns_openamp_msg)); |
| if (!rpc_handle) { |
| - EMSG("psa_connect: could not get handle"); |
| + EMSG("psa_connect: could not get rpc handle"); |
| return PSA_ERROR_GENERIC_ERROR; |
| } |
| |
| @@ -56,14 +102,100 @@ psa_handle_t psa_connect(struct rpc_caller *caller, uint32_t sid, |
| return resp_msg ? (psa_handle_t)resp_msg->reply : PSA_NULL_HANDLE; |
| } |
| |
| -psa_status_t psa_call(struct rpc_caller *caller, psa_handle_t handle, |
| +psa_status_t psa_call(struct rpc_caller *caller, psa_handle_t psa_handle, |
| int32_t type, const struct psa_invec *in_vec, |
| size_t in_len, struct psa_outvec *out_vec, size_t out_len) |
| { |
| + psa_status_t psa_status = PSA_SUCCESS; |
| + struct s_openamp_msg *resp_msg = NULL; |
| + struct psa_outvec *out_vec_param; |
| + struct psa_invec *in_vec_param; |
| + struct ns_openamp_msg *req_msg; |
| + rpc_call_handle rpc_handle; |
| + size_t out_vec_len; |
| + size_t in_vec_len; |
| + size_t header_len; |
| + uint8_t *payload; |
| + size_t resp_len; |
| + uint8_t *resp; |
| + uint8_t *req; |
| + int ret; |
| + int i; |
| + |
| + if ((psa_handle == PSA_NULL_HANDLE) || !caller) |
| + return PSA_ERROR_INVALID_ARGUMENT; |
| + |
| + header_len = psa_call_header_len(in_vec, in_len, out_vec, out_len); |
| + in_vec_len = psa_call_in_vec_len(in_vec, in_len); |
| + out_vec_len = psa_call_out_vec_len(out_vec, out_len); |
| |
| + rpc_handle = rpc_caller_begin(caller, &req, header_len + in_vec_len); |
| + if (!rpc_handle) { |
| + EMSG("psa_call: could not get handle"); |
| + return PSA_ERROR_GENERIC_ERROR; |
| + } |
| + |
| + payload = req + header_len; |
| + |
| + out_vec_param = psa_call_out_vec_param(req, in_len); |
| + in_vec_param = psa_call_in_vec_param(req); |
| + |
| + req_msg = (struct ns_openamp_msg *)req; |
| + |
| + req_msg->call_type = OPENAMP_PSA_CALL; |
| + req_msg->request_id = 1234; |
| + req_msg->params.psa_call_params.handle = psa_handle; |
| + req_msg->params.psa_call_params.type = type; |
| + req_msg->params.psa_call_params.in_len = in_len; |
| + req_msg->params.psa_call_params.in_vec = rpc_caller_virt_to_phys(caller, in_vec_param); |
| + req_msg->params.psa_call_params.out_len = out_len; |
| + req_msg->params.psa_call_params.out_vec = rpc_caller_virt_to_phys(caller, out_vec_param); |
| + |
| + for (i = 0; i < in_len; i++) { |
| + in_vec_param[i].base = rpc_caller_virt_to_phys(caller, payload); |
| + in_vec_param[i].len = in_vec[i].len; |
| + |
| + memcpy(payload, in_vec[i].base, in_vec[i].len); |
| + payload += in_vec[i].len; |
| + } |
| + |
| + for (i = 0; i < out_len; i++) { |
| + out_vec_param[i].base = NULL; |
| + out_vec_param[i].len = out_vec[i].len; |
| + } |
| + |
| + ret = rpc_caller_invoke(caller, rpc_handle, 0, &psa_status, &resp, |
| + &resp_len); |
| + if (ret != TS_RPC_CALL_ACCEPTED) { |
| + EMSG("psa_call: invoke failed: %d", ret); |
| + return PSA_ERROR_GENERIC_ERROR; |
| + } |
| + |
| + if (psa_status != PSA_SUCCESS) { |
| + EMSG("psa_call: psa_status invoke failed: %d", psa_status); |
| + return PSA_ERROR_GENERIC_ERROR; |
| + } |
| + |
| + resp_msg = (struct s_openamp_msg *)resp; |
| + |
| + if (!resp_msg || !out_len || resp_msg->reply != PSA_SUCCESS) |
| + goto caller_end; |
| + |
| + out_vec_param = (struct psa_outvec *)rpc_caller_phys_to_virt(caller, |
| + resp_msg->params.out_vec); |
| + |
| + for (i = 0; i < resp_msg->params.out_len; i++) { |
| + memcpy(out_vec[i].base, rpc_caller_phys_to_virt(caller, out_vec_param[i].base), |
| + out_vec[i].len); |
| + } |
| + |
| +caller_end: |
| + rpc_caller_end(caller, rpc_handle); |
| + |
| + return resp_msg ? resp_msg->reply : PSA_ERROR_COMMUNICATION_FAILURE; |
| } |
| |
| -void psa_close(struct rpc_caller *caller, psa_handle_t handle) |
| +void psa_close(struct rpc_caller *caller, psa_handle_t psa_handle) |
| { |
| psa_status_t psa_status = PSA_SUCCESS; |
| struct s_openamp_msg *resp_msg = NULL; |
| @@ -74,6 +206,9 @@ void psa_close(struct rpc_caller *caller, psa_handle_t handle) |
| uint8_t *req; |
| int ret; |
| |
| + if ((psa_handle == PSA_NULL_HANDLE) || !caller) |
| + return; |
| + |
| rpc_handle = rpc_caller_begin(caller, &req, |
| sizeof(struct ns_openamp_msg)); |
| if (!rpc_handle) { |
| @@ -84,7 +219,7 @@ void psa_close(struct rpc_caller *caller, psa_handle_t handle) |
| req_msg = (struct ns_openamp_msg *)req; |
| |
| req_msg->call_type = OPENAMP_PSA_CLOSE; |
| - req_msg->params.psa_close_params.handle = handle; |
| + req_msg->params.psa_close_params.handle = psa_handle; |
| |
| ret = rpc_caller_invoke(caller, rpc_handle, 0, &psa_status, &resp, |
| &resp_len); |
| diff --git a/components/service/secure_storage/backend/secure_storage_ipc/component.cmake b/components/service/secure_storage/backend/secure_storage_ipc/component.cmake |
| new file mode 100644 |
| index 000000000000..5d8f6714e0bd |
| --- /dev/null |
| +++ b/components/service/secure_storage/backend/secure_storage_ipc/component.cmake |
| @@ -0,0 +1,14 @@ |
| +#------------------------------------------------------------------------------- |
| +# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved. |
| +# |
| +# SPDX-License-Identifier: BSD-3-Clause |
| +# |
| +#------------------------------------------------------------------------------- |
| +if (NOT DEFINED TGT) |
| + message(FATAL_ERROR "mandatory parameter TGT is not defined.") |
| +endif() |
| + |
| +target_sources(${TGT} PRIVATE |
| + "${CMAKE_CURRENT_LIST_DIR}/secure_storage_ipc.c" |
| + ) |
| + |
| diff --git a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c |
| new file mode 100644 |
| index 000000000000..9b55f77dd395 |
| --- /dev/null |
| +++ b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c |
| @@ -0,0 +1,214 @@ |
| +/* |
| + * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved. |
| + * |
| + * SPDX-License-Identifier: BSD-3-Clause |
| + */ |
| + |
| +#include <protocols/rpc/common/packed-c/status.h> |
| +#include "secure_storage_ipc.h" |
| +#include <psa/client.h> |
| +#include <psa/sid.h> |
| +#include <rpc_caller.h> |
| +#include <string.h> |
| +#include <trace.h> |
| + |
| + |
| +static psa_status_t secure_storage_ipc_set(void *context, uint32_t client_id, |
| + psa_storage_uid_t uid, size_t data_length, |
| + const void *p_data, psa_storage_create_flags_t create_flags) |
| +{ |
| + struct secure_storage_ipc *ipc = context; |
| + struct rpc_caller *caller = ipc->client.caller; |
| + psa_handle_t psa_handle; |
| + psa_status_t psa_status; |
| + struct psa_invec in_vec[] = { |
| + { .base = &uid, .len = sizeof(uid) }, |
| + { .base = p_data, .len = data_length }, |
| + { .base = &create_flags, .len = sizeof(create_flags) }, |
| + }; |
| + |
| + (void)client_id; |
| + |
| + ipc->client.rpc_status = TS_RPC_CALL_ACCEPTED; |
| + |
| + /* Validating input parameters */ |
| + if (p_data == NULL) |
| + return PSA_ERROR_INVALID_ARGUMENT; |
| + |
| + psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE, |
| + TFM_PS_SET, in_vec, IOVEC_LEN(in_vec), NULL, 0); |
| + if (psa_status < 0) |
| + EMSG("ipc_set: psa_call failed: %d", psa_status); |
| + |
| + return psa_status; |
| +} |
| + |
| +static psa_status_t secure_storage_ipc_get(void *context, |
| + uint32_t client_id, |
| + psa_storage_uid_t uid, |
| + size_t data_offset, |
| + size_t data_size, |
| + void *p_data, |
| + size_t *p_data_length) |
| +{ |
| + struct secure_storage_ipc *ipc = context; |
| + struct rpc_caller *caller = ipc->client.caller; |
| + psa_handle_t psa_handle; |
| + psa_status_t psa_status; |
| + uint32_t offset = (uint32_t)data_offset; |
| + struct psa_invec in_vec[] = { |
| + { .base = &uid, .len = sizeof(uid) }, |
| + { .base = &offset, .len = sizeof(offset) }, |
| + }; |
| + struct psa_outvec out_vec[] = { |
| + { .base = p_data, .len = data_size }, |
| + }; |
| + |
| + if (!p_data_length) { |
| + EMSG("ipc_get: p_data_length not defined"); |
| + return PSA_ERROR_INVALID_ARGUMENT; |
| + } |
| + |
| + psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE, |
| + TFM_PS_GET, in_vec, IOVEC_LEN(in_vec), |
| + out_vec, IOVEC_LEN(out_vec)); |
| + if (psa_status == PSA_SUCCESS) |
| + *p_data_length = out_vec[0].len; |
| + |
| + return psa_status; |
| +} |
| + |
| +static psa_status_t secure_storage_ipc_get_info(void *context, |
| + uint32_t client_id, |
| + psa_storage_uid_t uid, |
| + struct psa_storage_info_t *p_info) |
| +{ |
| + struct secure_storage_ipc *ipc = context; |
| + struct rpc_caller *caller = ipc->client.caller; |
| + psa_handle_t psa_handle; |
| + psa_status_t psa_status; |
| + struct psa_invec in_vec[] = { |
| + { .base = &uid, .len = sizeof(uid) }, |
| + }; |
| + struct psa_outvec out_vec[] = { |
| + { .base = p_info, .len = sizeof(*p_info) }, |
| + }; |
| + |
| + (void)client_id; |
| + |
| + /* Validating input parameters */ |
| + if (!p_info) |
| + return PSA_ERROR_INVALID_ARGUMENT; |
| + |
| + psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE, |
| + TFM_PS_GET_INFO, in_vec, |
| + IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec)); |
| + if (psa_status != PSA_SUCCESS) |
| + EMSG("ipc_get_info: failed to psa_call: %d", psa_status); |
| + |
| + return psa_status; |
| +} |
| + |
| +static psa_status_t secure_storage_ipc_remove(void *context, |
| + uint32_t client_id, |
| + psa_storage_uid_t uid) |
| +{ |
| + struct secure_storage_ipc *ipc = context; |
| + struct rpc_caller *caller = ipc->client.caller; |
| + psa_handle_t psa_handle; |
| + psa_status_t psa_status; |
| + struct psa_invec in_vec[] = { |
| + { .base = &uid, .len = sizeof(uid) }, |
| + }; |
| + |
| + (void)client_id; |
| + |
| + psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE, |
| + TFM_PS_REMOVE, in_vec, |
| + IOVEC_LEN(in_vec), NULL, 0); |
| + if (psa_status != PSA_SUCCESS) |
| + EMSG("ipc_remove: failed to psa_call: %d", psa_status); |
| + |
| + return psa_status; |
| +} |
| + |
| +static psa_status_t secure_storage_ipc_create(void *context, |
| + uint32_t client_id, |
| + uint64_t uid, |
| + size_t capacity, |
| + uint32_t create_flags) |
| +{ |
| + (void)context; |
| + (void)uid; |
| + (void)client_id; |
| + (void)capacity; |
| + (void)create_flags; |
| + |
| + return PSA_ERROR_NOT_SUPPORTED; |
| +} |
| + |
| +static psa_status_t secure_storage_set_extended(void *context, |
| + uint32_t client_id, |
| + uint64_t uid, |
| + size_t data_offset, |
| + size_t data_length, |
| + const void *p_data) |
| +{ |
| + (void)context; |
| + (void)uid; |
| + (void)client_id; |
| + (void)data_offset; |
| + (void)data_length; |
| + (void)p_data; |
| + |
| + return PSA_ERROR_NOT_SUPPORTED; |
| +} |
| + |
| +static uint32_t secure_storage_get_support(void *context, uint32_t client_id) |
| +{ |
| + struct secure_storage_ipc *ipc = context; |
| + struct rpc_caller *caller = ipc->client.caller; |
| + psa_handle_t psa_handle; |
| + psa_status_t psa_status; |
| + uint32_t support_flags; |
| + struct psa_outvec out_vec[] = { |
| + { .base = &support_flags, .len = sizeof(support_flags) }, |
| + }; |
| + |
| + (void)client_id; |
| + |
| + psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE, |
| + TFM_PS_GET_SUPPORT, NULL, 0, |
| + out_vec, IOVEC_LEN(out_vec)); |
| + if (psa_status != PSA_SUCCESS) |
| + EMSG("ipc_get_support: failed to psa_call: %d", psa_status); |
| + |
| + return psa_status; |
| +} |
| + |
| +struct storage_backend *secure_storage_ipc_init(struct secure_storage_ipc *context, |
| + struct rpc_caller *caller) |
| +{ |
| + service_client_init(&context->client, caller); |
| + |
| + static const struct storage_backend_interface interface = |
| + { |
| + .set = secure_storage_ipc_set, |
| + .get = secure_storage_ipc_get, |
| + .get_info = secure_storage_ipc_get_info, |
| + .remove = secure_storage_ipc_remove, |
| + .create = secure_storage_ipc_create, |
| + .set_extended = secure_storage_set_extended, |
| + .get_support = secure_storage_get_support, |
| + }; |
| + |
| + context->backend.context = context; |
| + context->backend.interface = &interface; |
| + |
| + return &context->backend; |
| +} |
| + |
| +void secure_storage_ipc_deinit(struct secure_storage_ipc *context) |
| +{ |
| + service_client_deinit(&context->client); |
| +} |
| diff --git a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h |
| new file mode 100644 |
| index 000000000000..e8c1e8fd2f92 |
| --- /dev/null |
| +++ b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h |
| @@ -0,0 +1,52 @@ |
| +/* |
| + * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved. |
| + * |
| + * SPDX-License-Identifier: BSD-3-Clause |
| + */ |
| + |
| +#ifndef SECURE_STORAGE_IPC_H |
| +#define SECURE_STORAGE_IPC_H |
| + |
| +#include <service/secure_storage/backend/storage_backend.h> |
| +#include <service/common/client/service_client.h> |
| + |
| +#ifdef __cplusplus |
| +extern "C" { |
| +#endif |
| + |
| +/** |
| + * @brief Secure storage ipc instance |
| + */ |
| +struct secure_storage_ipc |
| +{ |
| + struct storage_backend backend; |
| + struct service_client client; |
| +}; |
| + |
| +/** |
| + * @brief Initialize a secure storage ipc client |
| + * |
| + * A secure storage client is a storage backend that makes RPC calls |
| + * to a remote secure storage provider. |
| + * |
| + * @param[in] context Instance data |
| + * @param[in] rpc_caller RPC caller instance |
| + * |
| + * |
| + * @return Pointer to inialized storage backend or NULL on failure |
| + */ |
| +struct storage_backend *secure_storage_ipc_init(struct secure_storage_ipc *context, |
| + struct rpc_caller *caller); |
| + |
| +/** |
| + * @brief Deinitialize a secure storage ipc client |
| + * |
| + * @param[in] context Instance data |
| + */ |
| +void secure_storage_ipc_deinit(struct secure_storage_ipc *context); |
| + |
| +#ifdef __cplusplus |
| +} |
| +#endif |
| + |
| +#endif /* SECURE_STORAGE_IPC_H */ |
| diff --git a/deployments/se-proxy/se-proxy.cmake b/deployments/se-proxy/se-proxy.cmake |
| index dd0c5d00c21e..cd51460406ca 100644 |
| --- a/deployments/se-proxy/se-proxy.cmake |
| +++ b/deployments/se-proxy/se-proxy.cmake |
| @@ -45,6 +45,7 @@ add_components(TARGET "se-proxy" |
| "components/service/crypto/factory/full" |
| "components/service/secure_storage/include" |
| "components/service/secure_storage/frontend/secure_storage_provider" |
| + "components/service/secure_storage/backend/secure_storage_ipc" |
| "components/service/attestation/include" |
| "components/service/attestation/provider" |
| "components/service/attestation/provider/serializer/packed-c" |
| -- |
| 2.38.0 |
| |