blob: 8037bb43eaf9a13bb190a68ae397b2b720a85e15 [file] [log] [blame]
/*
* Copyright (c) 2022-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stddef.h>
#include <stdint.h>
#include "delegated_attest.h"
#include "psa/client.h"
#include "psa/crypto.h"
#include "psa/error.h"
#include "psa/initial_attestation.h"
#include "psa/service.h"
#include "psa_manifest/tfm_delegated_attestation.h"
#include "tfm_delegated_attest_defs.h"
#define DELEGATED_ATTEST_KEY_MAX_SIZE PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(521)
/* Buffer to store the derived delegated attestation key. */
static uint8_t dak_buf[DELEGATED_ATTEST_KEY_MAX_SIZE];
/* Buffer to store the created platform attestation token. */
static uint8_t token_buf[PSA_INITIAL_ATTEST_MAX_TOKEN_SIZE];
static psa_status_t get_delegated_attestation_key(const psa_msg_t *msg)
{
psa_ecc_family_t ecc_curve;
psa_algorithm_t hash_algo;
psa_status_t status;
uint32_t key_bits;
size_t key_buf_size;
size_t key_len;
size_t bytes_read;
/* Check input parameters */
if (msg->in_size[0] != sizeof(ecc_curve) ||
msg->in_size[1] != sizeof(key_bits) ||
msg->in_size[2] != sizeof(hash_algo)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
bytes_read = psa_read(msg->handle, 0, &ecc_curve, sizeof(ecc_curve));
if (bytes_read != sizeof(ecc_curve)) {
return PSA_ERROR_GENERIC_ERROR;
}
bytes_read = psa_read(msg->handle, 1, &key_bits, sizeof(key_bits));
if (bytes_read != sizeof(key_bits)) {
return PSA_ERROR_GENERIC_ERROR;
}
bytes_read = psa_read(msg->handle, 2, &hash_algo, sizeof(hash_algo));
if (bytes_read != sizeof(hash_algo)) {
return PSA_ERROR_GENERIC_ERROR;
}
/* COSE standard defines ECDSA to work only with these curves:
* P-256, P-384, and P-521.
* https://datatracker.ietf.org/doc/html/rfc8152#section-8.1
*/
if (ecc_curve != PSA_ECC_FAMILY_SECP_R1) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (key_bits != 256 && key_bits != 384 && key_bits != 521) {
return PSA_ERROR_INVALID_ARGUMENT;
}
/* Check output parameters */
if (msg->out_size[0] < PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(key_bits)) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
key_buf_size = msg->out_size[0] < sizeof(dak_buf) ?
msg->out_size[0] : sizeof(dak_buf);
status = delegated_attest_get_delegated_key(ecc_curve, key_bits,
dak_buf, key_buf_size,
&key_len, hash_algo);
if (status == PSA_SUCCESS) {
psa_write(msg->handle, 0, dak_buf, key_len);
}
return status;
}
static psa_status_t get_platform_attestation_token(const psa_msg_t *msg)
{
psa_status_t status;
uint8_t dak_pub_hash[PSA_HASH_LENGTH(PSA_ALG_SHA_512)];
size_t dak_pub_hash_size;
size_t token_buf_size;
size_t token_size;
size_t bytes_read;
dak_pub_hash_size = msg->in_size[0];
if (dak_pub_hash_size > sizeof(dak_pub_hash)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
bytes_read = psa_read(msg->handle, 0, dak_pub_hash, dak_pub_hash_size);
if (bytes_read != dak_pub_hash_size) {
return PSA_ERROR_GENERIC_ERROR;
}
token_buf_size = msg->out_size[0] < sizeof(token_buf) ?
msg->out_size[0] : sizeof(token_buf);
/* Check input parameters
* Allowed nonce value lengths in attestation token: 32, 48, 64 bytes.
*/
if (dak_pub_hash_size != PSA_HASH_LENGTH(PSA_ALG_SHA_256) &&
dak_pub_hash_size != PSA_HASH_LENGTH(PSA_ALG_SHA_384) &&
dak_pub_hash_size != PSA_HASH_LENGTH(PSA_ALG_SHA_512)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
status = delegated_attest_get_platform_token(dak_pub_hash,
dak_pub_hash_size,
token_buf,
token_buf_size,
&token_size);
if (status == PSA_SUCCESS) {
psa_write(msg->handle, 0, token_buf, token_size);
}
return status;
}
static void delegated_attestation_signal_handle(psa_signal_t signal)
{
psa_status_t status;
psa_msg_t msg;
/* Retrieve the message corresponding to the
* Delegated Attestation service signal.
*/
status = psa_get(signal, &msg);
if (status != PSA_SUCCESS) {
return;
}
switch (msg.type) {
case DELEGATED_ATTEST_GET_DELEGATED_KEY:
status = get_delegated_attestation_key(&msg);
/* Reply with the message result status to unblock the client */
psa_reply(msg.handle, status);
break;
case DELEGATED_ATTEST_GET_PLATFORM_TOKEN:
status = get_platform_attestation_token(&msg);
/* Reply with the message result status to unblock the client */
psa_reply(msg.handle, status);
break;
default:
/* Invalid message type */
psa_panic();
}
}
void delegated_attest_partition_main(void)
{
psa_signal_t signals = 0;
/* Delegated Attestation partition initialization.
* - Nothing to do -
*/
while (1) {
signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
if (signals & TFM_DELEGATED_ATTESTATION_SIGNAL) {
delegated_attestation_signal_handle(TFM_DELEGATED_ATTESTATION_SIGNAL);
} else {
/* Should not come here */
psa_panic();
}
}
}