blob: 3a69d21386f91cdb697807d515b98679194c0e75 [file] [log] [blame]
/*
* Copyright (c) 2022-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <string.h>
#include "measured_boot.h"
#include "measured_boot_defs.h"
#include "tfm_sp_log.h"
#include "psa/service.h"
#include "psa_manifest/pid.h"
#include "psa/crypto.h"
#include "psa_manifest/tfm_measured_boot.h"
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
/* TODO: This info will be used later on as input to decide access control */
static int32_t g_measured_boot_caller_id;
static psa_status_t read_measurements(const psa_msg_t *msg)
{
struct measured_boot_read_iovec_in_t read_iov_in;
struct measured_boot_read_iovec_out_t read_iov_out;
size_t signer_id_len, measurement_value_len;
size_t num;
size_t signer_id_size, measurement_value_size;
uint8_t signer_id[SIGNER_ID_MAX_SIZE] = {0};
uint8_t measurement_value[MEASUREMENT_VALUE_SIZE] = {0};
psa_status_t status;
/* store the client ID here for later use in service */
g_measured_boot_caller_id = msg->client_id;
/* Limit requested sizes to the size of the local buffers */
signer_id_size = MIN(msg->out_size[1], sizeof(signer_id));
measurement_value_size = MIN(msg->out_size[2], sizeof(measurement_value));
/* Check input parameter */
if ((msg->in_size[0] != sizeof(struct measured_boot_read_iovec_in_t)) ||
(msg->out_size[0] != sizeof(struct measured_boot_read_iovec_out_t))) {
return PSA_ERROR_PROGRAMMER_ERROR;
}
num = psa_read(msg->handle, 0, &read_iov_in, sizeof(read_iov_in));
if (num != sizeof(read_iov_in)) {
return PSA_ERROR_PROGRAMMER_ERROR;
}
/* Validate requested slot number */
if (read_iov_in.index >= NUM_OF_MEASUREMENT_SLOTS) {
return PSA_ERROR_INVALID_ARGUMENT;
}
memset(&read_iov_out, 0, sizeof(read_iov_out));
status = measured_boot_read_measurement(read_iov_in.index,
&signer_id[0],
signer_id_size,
&signer_id_len,
&read_iov_out.version[0],
read_iov_in.version_size,
&read_iov_out.version_len,
&read_iov_out.measurement_algo,
&read_iov_out.sw_type[0],
read_iov_in.sw_type_size,
&read_iov_out.sw_type_len,
&measurement_value[0],
measurement_value_size,
&measurement_value_len,
&read_iov_out.is_locked);
if (status == PSA_SUCCESS) {
psa_write(msg->handle, 0, &read_iov_out, sizeof(read_iov_out));
psa_write(msg->handle, 1, &signer_id[0], signer_id_len);
psa_write(msg->handle, 2, &measurement_value[0], measurement_value_len);
}
return status;
}
static psa_status_t extend_measurement(const psa_msg_t *msg)
{
struct measured_boot_extend_iovec_t extend_iov;
size_t num;
size_t signer_id_size;
size_t version_size;
size_t measurement_value_size;
uint8_t signer_id[SIGNER_ID_MAX_SIZE] = {0};
uint8_t version[VERSION_MAX_SIZE] = {0};
uint8_t measurement_value[MEASUREMENT_VALUE_MAX_SIZE] = {0};
/* store the client ID here for later use in service */
g_measured_boot_caller_id = msg->client_id;
/* Check input parameter */
if (msg->in_size[0] != sizeof(struct measured_boot_extend_iovec_t)) {
return PSA_ERROR_PROGRAMMER_ERROR;
}
signer_id_size = msg->in_size[1];
version_size = msg->in_size[2];
measurement_value_size = msg->in_size[3];
memset(&extend_iov, 0, sizeof(extend_iov));
num = psa_read(msg->handle, 0, &extend_iov,
sizeof(struct measured_boot_extend_iovec_t));
if (num != sizeof(struct measured_boot_extend_iovec_t)) {
return PSA_ERROR_PROGRAMMER_ERROR;
}
/* Validate size limits of input parameters */
if ((signer_id_size < SIGNER_ID_MIN_SIZE) ||
(signer_id_size > SIGNER_ID_MAX_SIZE) ||
(version_size > VERSION_MAX_SIZE) ||
(measurement_value_size < MEASUREMENT_VALUE_MIN_SIZE) ||
(measurement_value_size > MEASUREMENT_VALUE_MAX_SIZE) ||
(extend_iov.sw_type_size > SW_TYPE_MAX_SIZE)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
/* Validate requested slot number */
if (extend_iov.index >= NUM_OF_MEASUREMENT_SLOTS) {
return PSA_ERROR_INVALID_ARGUMENT;
}
num = psa_read(msg->handle, 1, signer_id, signer_id_size);
if (num != signer_id_size) {
return PSA_ERROR_PROGRAMMER_ERROR;
}
num = psa_read(msg->handle, 2, version, version_size);
if (num != version_size) {
return PSA_ERROR_PROGRAMMER_ERROR;
}
num = psa_read(msg->handle, 3, &measurement_value[0],
measurement_value_size);
if (num != measurement_value_size) {
return PSA_ERROR_PROGRAMMER_ERROR;
}
return measured_boot_extend_measurement(extend_iov.index,
signer_id,
signer_id_size,
version,
version_size,
extend_iov.measurement_algo,
&extend_iov.sw_type[0],
extend_iov.sw_type_size,
measurement_value,
measurement_value_size,
extend_iov.lock_measurement);
}
/**
* \brief The measured_boot partition's entry function.
*/
psa_status_t tfm_measured_boot_init(void)
{
psa_status_t status = PSA_SUCCESS;
/* Initialise all measurements & related metadata */
initialise_all_measurements();
LOG_DBGFMT("Measured Boot : selected algorithm: %x\r\n",
TFM_MEASURED_BOOT_HASH_ALG);
#ifdef CONFIG_TFM_BOOT_STORE_MEASUREMENTS
status = collect_shared_measurements();
#endif
return status;
}
psa_status_t tfm_measured_boot_sfn(const psa_msg_t *msg)
{
switch (msg->type) {
case TFM_MEASURED_BOOT_READ:
return read_measurements(msg);
case TFM_MEASURED_BOOT_EXTEND:
return extend_measurement(msg);
default:
/* Invalid message type */
return PSA_ERROR_NOT_SUPPORTED;
}
}