blob: 0ad9dd5bcf0d980c6e2e42a83ad1058f762de3d9 [file] [log] [blame]
/*
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
*/
#include <assert.h>
#include <attestation.h>
#include <attestation_priv.h>
#include <debug.h>
#include <errno.h>
#include <fpu_helpers.h>
#include <mbedtls/sha256.h>
#include <measurement.h>
#include <psa/crypto.h>
#include <rmm_el3_ifc.h>
#include <sizes.h>
#define ECC_P384_PUBLIC_KEY_SIZE (97U)
#define SHA256_DIGEST_SIZE (32U)
/*
* The size of X and Y coordinate in 2 parameter style EC public key. Format is
* as defined in [COSE (RFC 8152)] (https://tools.ietf.org/html/rfc8152) and
* [SEC 1: Elliptic Curve Cryptography](http://www.secg.org/sec1-v2.pdf).
*
* This size is well-known and documented in public standards.
*/
#define ECC_P384_COORD_SIZE (48U) /* 384 bits -> 48 bytes */
#define BIT_SIZE_OF_P384 (384U)
/* ECC Curve type define for querying attestation key from monitor */
#define ATTEST_KEY_CURVE_ECC_SECP384R1 0
/*
* The platform token which will be needed during attestation.
*/
static unsigned char rmm_platform_token_buf[SZ_4K];
static struct q_useful_buf rmm_platform_token;
/*
* The public key is kept loaded as it is both not required to be secret (and
* hence can be kept in attestation memory) and immutable.
*/
static uint8_t realm_attest_public_key[ECC_P384_PUBLIC_KEY_SIZE];
static size_t realm_attest_public_key_len;
/*
* The hash of the realm attestation public key is included in the Platform
* attestation token as the challenge claim.
*/
static uint8_t realm_attest_public_key_hash[SHA256_DIGEST_SIZE];
static size_t realm_attest_public_key_hash_len;
/*
* The keypair for the sign operation
*/
static mbedtls_ecp_keypair realm_attest_keypair = {0};
/* Specify the hash algorithm to use for computing the hash of the
* realm public key.
*/
static enum hash_algo public_key_hash_algo_id = HASH_ALGO_SHA256;
/*
* TODO: review panic usage and try to gracefully exit on error. Also
* improve documentation of usage of MbedTLS APIs
*/
int attest_init_realm_attestation_key(void)
{
int ret;
struct q_useful_buf realm_attest_private_key;
uintptr_t buf;
size_t attest_key_size = 0UL;
struct attest_rng_context rng_ctx;
assert(IS_FPU_ALLOWED());
attest_get_cpu_rng_context(&rng_ctx);
/*
* The realm attestation key is requested from the root world in the
* boot phase only once. Then the same key is used in the entire power
* cycle to sign the realm attestation tokens.
*/
if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) != NULL) {
ERROR("Realm attestation key already loaded.\n");
return -EINVAL;
}
/*
* Get the realm attestation key. The key is retrieved in raw format.
*/
buf = rmm_el3_ifc_get_shared_buf_locked();
if (rmm_el3_ifc_get_realm_attest_key(buf,
rmm_el3_ifc_get_shared_buf_size(),
&attest_key_size,
ATTEST_KEY_CURVE_ECC_SECP384R1) != 0) {
rmm_el3_ifc_release_shared_buf();
return -EINVAL;
}
realm_attest_private_key.len = attest_key_size;
realm_attest_private_key.ptr = (void *)buf;
/*
* Setup ECC key.
* The memory for the keypair is allocated from MbedTLS Heap.
*/
mbedtls_ecp_keypair_init(&realm_attest_keypair);
ret = mbedtls_ecp_group_load(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
MBEDTLS_ECP_DP_SECP384R1);
if (ret != 0) {
ERROR("mbedtls_ecp_group_load has failed\n");
rmm_el3_ifc_release_shared_buf();
return -EINVAL;
}
ret = mbedtls_mpi_read_binary(&realm_attest_keypair.MBEDTLS_PRIVATE(d),
realm_attest_private_key.ptr,
realm_attest_private_key.len);
if (ret != 0) {
ERROR("mbedtls_mpi_read_binary has failed\n");
rmm_el3_ifc_release_shared_buf();
return -EINVAL;
}
ret = mbedtls_ecp_check_privkey(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
&realm_attest_keypair.MBEDTLS_PRIVATE(d));
if (ret != 0) {
ERROR("mbedtls_ecp_check_privkey has failed: %d\n", ret);
rmm_el3_ifc_release_shared_buf();
return -EINVAL;
}
ret = mbedtls_ecp_mul(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
&realm_attest_keypair.MBEDTLS_PRIVATE(Q),
&realm_attest_keypair.MBEDTLS_PRIVATE(d),
&realm_attest_keypair.MBEDTLS_PRIVATE(grp).G,
rng_ctx.f_rng,
rng_ctx.p_rng);
if (ret != 0) {
ERROR("mbedtls_ecp_mul priv has failed: %d\n", ret);
rmm_el3_ifc_release_shared_buf();
return -EINVAL;
}
ret = mbedtls_ecp_point_write_binary(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
&realm_attest_keypair.MBEDTLS_PRIVATE(Q),
MBEDTLS_ECP_PF_UNCOMPRESSED,
&realm_attest_public_key_len,
realm_attest_public_key,
sizeof(realm_attest_public_key));
if (ret != 0) {
ERROR("mbedtls_ecp_point_write_binary pub has failed\n");
rmm_el3_ifc_release_shared_buf();
return -EINVAL;
}
/* Compute the hash of the realm attestation public key */
ret = mbedtls_sha256(realm_attest_public_key,
realm_attest_public_key_len,
realm_attest_public_key_hash,
false);
if (ret != 0) {
ERROR("mbedtls_sha256 has failed\n");
rmm_el3_ifc_release_shared_buf();
return -EINVAL;
}
realm_attest_public_key_hash_len = sizeof(realm_attest_public_key_hash);
/* Clear the private key from the buffer */
(void)memset(realm_attest_private_key.ptr, 0,
realm_attest_private_key.len);
rmm_el3_ifc_release_shared_buf();
return 0;
}
int attest_get_realm_signing_key(const void **keypair)
{
if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) == NULL) {
ERROR("Realm attestation key not initialized\n");
return -EINVAL;
}
*keypair = &realm_attest_keypair;
return 0;
}
int attest_get_realm_public_key_hash(struct q_useful_buf_c *public_key_hash)
{
if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) == NULL) {
ERROR("Realm attestation key not initialized\n");
return -EINVAL;
}
public_key_hash->ptr = realm_attest_public_key_hash;
public_key_hash->len = realm_attest_public_key_hash_len;
return 0;
}
int attest_get_realm_public_key(struct q_useful_buf_c *public_key)
{
if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) == NULL) {
ERROR("Realm attestation key not initialized\n");
return -EINVAL;
}
public_key->ptr = realm_attest_public_key;
public_key->len = realm_attest_public_key_len;
return 0;
}
int attest_setup_platform_token(void)
{
int ret;
uintptr_t shared_buf;
size_t platform_token_len = 0;
struct q_useful_buf_c rmm_pub_key_hash;
/*
* Copy the RAK public hash value to the token buffer. This is
* used as the challenge input for the token generation
* thus creating a binding between the two.
*/
ret = attest_get_realm_public_key_hash(&rmm_pub_key_hash);
if (ret != 0) {
ERROR("Realm attestation key not initialized\n");
return ret;
}
shared_buf = rmm_el3_ifc_get_shared_buf_locked();
(void)memcpy((void *)shared_buf, rmm_pub_key_hash.ptr,
rmm_pub_key_hash.len);
ret = rmm_el3_ifc_get_platform_token(shared_buf,
rmm_el3_ifc_get_shared_buf_size(),
&platform_token_len,
SHA256_DIGEST_SIZE);
if (ret != 0) {
rmm_el3_ifc_release_shared_buf();
return -EINVAL;
}
(void)memcpy(rmm_platform_token_buf,
(void *)shared_buf,
platform_token_len);
rmm_el3_ifc_release_shared_buf();
rmm_platform_token.ptr = rmm_platform_token_buf;
rmm_platform_token.len = platform_token_len;
return 0;
}
int attest_get_platform_token(struct q_useful_buf_c **buf)
{
assert(buf != NULL);
if (rmm_platform_token.ptr == NULL) {
return -EINVAL;
}
*buf = (struct q_useful_buf_c *)&rmm_platform_token;
return 0;
}
enum hash_algo attest_get_realm_public_key_hash_algo_id(void)
{
return public_key_hash_algo_id;
}