aboutsummaryrefslogtreecommitdiff
path: root/secure_fw/partitions/initial_attestation/attest_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'secure_fw/partitions/initial_attestation/attest_core.c')
-rw-r--r--secure_fw/partitions/initial_attestation/attest_core.c854
1 files changed, 333 insertions, 521 deletions
diff --git a/secure_fw/partitions/initial_attestation/attest_core.c b/secure_fw/partitions/initial_attestation/attest_core.c
index 7a43b00670..f58715ac74 100644
--- a/secure_fw/partitions/initial_attestation/attest_core.c
+++ b/secure_fw/partitions/initial_attestation/attest_core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -10,56 +10,20 @@
#include <stddef.h>
#include "psa/client.h"
#include "attest.h"
+#include "attest_boot_data.h"
#include "attest_key.h"
-#include "tfm_boot_status.h"
+#include "attest_token.h"
+#include "config_tfm.h"
#include "tfm_plat_defs.h"
#include "tfm_plat_device_id.h"
#include "tfm_plat_boot_seed.h"
#include "tfm_attest_hal.h"
-#include "attest_token.h"
-#include "attest_eat_defines.h"
+#include "tfm_attest_iat_defs.h"
#include "t_cose_common.h"
-#include "tfm_memory_utils.h"
-#include "tfm_plat_crypto_keys.h"
-
-#define MAX_BOOT_STATUS 512
-
-/* Indicates how to encode SW components' measurements in the CBOR map */
-#define EAT_SW_COMPONENT_NESTED 1 /* Nested map */
-#define EAT_SW_COMPONENT_NOT_NESTED 0 /* Flat structure */
-
-/* The algorithm used in COSE */
-#ifdef SYMMETRIC_INITIAL_ATTESTATION
-#define T_COSE_ALGORITHM T_COSE_ALGORITHM_HMAC256
-#else
-#define T_COSE_ALGORITHM T_COSE_ALGORITHM_ES256
-#endif
-
-/*!
- * \struct attest_boot_data
- *
- * \brief Contains the received boot status information from bootloader
- *
- * \details This is a redefinition of \ref tfm_boot_data to allocate the
- * appropriate, service dependent size of \ref boot_data.
- */
-struct attest_boot_data {
- struct shared_data_tlv_header header;
- uint8_t data[MAX_BOOT_STATUS];
-};
+#include "tfm_crypto_defs.h"
+#include "tfm_sp_log.h"
-/*!
- * \var boot_data
- *
- * \brief Store the boot status in service's memory.
- *
- * \details Boot status comes from the secure bootloader and primarily stored
- * on a memory area which is shared between bootloader and SPM.
- * SPM provides the \ref tfm_core_get_boot_data() API to retrieve
- * the service related data from shared area.
- */
-__attribute__ ((aligned(4)))
-static struct attest_boot_data boot_data;
+#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(*(array)))
/*!
* \brief Static function to map return values between \ref psa_attest_err_t
@@ -100,9 +64,7 @@ psa_status_t attest_init(void)
{
enum psa_attest_err_t res;
- res = attest_get_boot_data(TLV_MAJOR_IAS,
- (struct tfm_boot_data *)&boot_data,
- MAX_BOOT_STATUS);
+ res = attest_boot_data_init();
return error_mapping_to_psa_status_t(res);
}
@@ -131,151 +93,6 @@ error_mapping_to_psa_attest_err_t(enum attest_token_err_t token_err)
}
/*!
- * \brief Static function to convert a pointer and size info to unsigned
- * integer number. Max 32bits unsigned integers are supported.
- *
- * This implementation assumes that the endianness of the sender and receiver
- * of the data is the same because they are actually running on the same CPU
- * instance. If this assumption is not true than this function must be
- * refactored accordingly.
- *
- * \param[in] int_ptr Pointer to the unsigned integer
- * \param[in] len Size of the unsigned integers in bytes
- * \param[in] value Pointer where to store the converted value
- *
- * \return Returns 0 on success and -1 on error.
- */
-static inline int32_t get_uint(const void *int_ptr,
- size_t len,
- uint32_t *value)
-{
- uint16_t uint16;
-
- switch (len) {
- case 1:
- *value = (uint32_t)(*(uint8_t *)(int_ptr));
- break;
- case 2:
- /* Avoid unaligned access */
- (void)tfm_memcpy(&uint16, int_ptr, sizeof(uint16));
- *value = (uint32_t)uint16;
- break;
- case 4:
- /* Avoid unaligned access */
- (void)tfm_memcpy(value, int_ptr, sizeof(uint32_t));
- break;
- default:
- return -1;
- }
-
- return 0;
-}
-/*!
- * \brief Static function to look up all entires in the shared data area
- * (boot status) which belong to a specific module.
- *
- * \param[in] module The identifier of SW module to look up based on this
- * \param[out] claim The type of SW module's attribute
- * \param[out] tlv_len Length of the shared data entry
- * \param[in/out] tlv_ptr Pointer to the shared data entry. If its value NULL as
- * input then it will starts the look up from the
- * beginning of the shared data section. If not NULL then
- * it continue look up from the next entry. It returns
- * the address of next found entry which belongs to
- * module.
- *
- * \retval -1 Error, boot status is malformed
- * \retval 0 Entry not found
- * \retval 1 Entry found
- */
-static int32_t attest_get_tlv_by_module(uint8_t module,
- uint8_t *claim,
- uint16_t *tlv_len,
- uint8_t **tlv_ptr)
-{
- struct shared_data_tlv_entry tlv_entry;
- uint8_t *tlv_end;
- uint8_t *tlv_curr;
-
- if (boot_data.header.tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) {
- return -1;
- }
-
- /* Get the boundaries of TLV section where to lookup*/
- tlv_end = (uint8_t *)&boot_data + boot_data.header.tlv_tot_len;
- if (*tlv_ptr == NULL) {
- /* At first call set to the beginning of the TLV section */
- tlv_curr = boot_data.data;
- } else {
- /* Any subsequent call set to the next TLV entry */
- (void)tfm_memcpy(&tlv_entry, *tlv_ptr, SHARED_DATA_ENTRY_HEADER_SIZE);
-
- tlv_curr = (*tlv_ptr) + SHARED_DATA_ENTRY_HEADER_SIZE
- + tlv_entry.tlv_len;
- }
-
- /* Iterates over the TLV section and returns the address and size of TLVs
- * with requested module identifier
- */
- while (tlv_curr < tlv_end) {
- /* Create local copy to avoid unaligned access */
- (void)tfm_memcpy(&tlv_entry, tlv_curr, SHARED_DATA_ENTRY_HEADER_SIZE);
- if (GET_IAS_MODULE(tlv_entry.tlv_type) == module) {
- *claim = GET_IAS_CLAIM(tlv_entry.tlv_type);
- *tlv_ptr = tlv_curr;
- *tlv_len = tlv_entry.tlv_len;
- return 1;
- }
-
- tlv_curr += (SHARED_DATA_ENTRY_HEADER_SIZE + tlv_entry.tlv_len);
- }
-
- return 0;
-}
-
-/*!
- * \brief Static function to look up specific claim belongs to SW_GENERAL module
- *
- * \param[in] claim The claim ID to look for
- * \param[out] tlv_len Length of the shared data entry
- * \param[out] tlv_ptr Pointer to a shared data entry which belongs to the
- * SW_GENERAL module.
- *
- * \retval -1 Error, boot status is malformed
- * \retval 0 Entry not found
- * \retval 1 Entry found
- */
-static int32_t attest_get_tlv_by_id(uint8_t claim,
- uint16_t *tlv_len,
- uint8_t **tlv_ptr)
-{
- uint8_t tlv_id;
- uint8_t module = SW_GENERAL;
- int32_t found;
-
- /* Ensure that look up starting from the beginning of the boot status */
- *tlv_ptr = NULL;
-
- /* Look up specific TLV entry which belongs to SW_GENERAL module */
- do {
- /* Look up next entry */
- found = attest_get_tlv_by_module(module, &tlv_id,
- tlv_len, tlv_ptr);
- if (found != 1) {
- break;
- }
- /* At least one entry was found which belongs to SW_GENERAL,
- * check whether this one is looked for
- */
- if (claim == tlv_id) {
- break;
- }
- } while (found == 1);
-
- return found;
-}
-
-/*!
* \brief Static function to add the claims of all SW components to the
* attestation token.
*
@@ -286,95 +103,62 @@ static int32_t attest_get_tlv_by_id(uint8_t claim,
static enum psa_attest_err_t
attest_add_all_sw_components(struct attest_token_encode_ctx *token_ctx)
{
- uint16_t tlv_len;
- uint8_t *tlv_ptr;
- uint8_t tlv_id;
- int32_t found;
- uint32_t cnt = 0;
- uint8_t module = 0;
QCBOREncodeContext *cbor_encode_ctx = NULL;
- UsefulBufC encoded = NULLUsefulBufC;
+ uint32_t component_cnt;
+ int32_t map_label = IAT_SW_COMPONENTS;
+ enum psa_attest_err_t err;
cbor_encode_ctx = attest_token_encode_borrow_cbor_cntxt(token_ctx);
- for (module = 0; module < SW_MAX; ++module) {
- /* Indicates to restart the look up from the beginning of the shared
- * data section
- */
- tlv_ptr = NULL;
-
- /* Look up the first TLV entry which belongs to the SW module */
- found = attest_get_tlv_by_module(module, &tlv_id,
- &tlv_len, &tlv_ptr);
- if (found == -1) {
- return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
- }
-
- if (found == 1) {
- cnt++;
- if (cnt == 1) {
- /* Open array which stores SW components claims */
- QCBOREncode_OpenArrayInMapN(cbor_encode_ctx,
- EAT_CBOR_ARM_LABEL_SW_COMPONENTS);
- }
-
- encoded.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
- encoded.len = tlv_len;
- QCBOREncode_AddEncoded(cbor_encode_ctx, encoded);
- }
+ err = attest_encode_sw_components_array(cbor_encode_ctx,
+ &map_label,
+ &component_cnt);
+ if (err != PSA_ATTEST_ERR_SUCCESS) {
+ return err;
}
- if (cnt != 0) {
- /* Close array which stores SW components claims*/
- QCBOREncode_CloseArray(cbor_encode_ctx);
- } else {
- /* If there is not any SW components' measurement in the boot status
- * then include this claim to indicate that this state is intentional
+ if (component_cnt == 0) {
+#if ATTEST_TOKEN_PROFILE_PSA_IOT_1
+ /* Allowed to not have SW components claim, but it must be indicated
+ * that this state is intentional. In this case, include the
+ * IAT_NO_SW_COMPONENTS claim with a fixed value.
*/
attest_token_encode_add_integer(token_ctx,
- EAT_CBOR_ARM_LABEL_NO_SW_COMPONENTS,
+ IAT_NO_SW_COMPONENTS,
(int64_t)NO_SW_COMPONENT_FIXED_VALUE);
+#else
+ /* Mandatory to have SW components claim in the token */
+ return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
+#endif
}
return PSA_ATTEST_ERR_SUCCESS;
}
/*!
- * \brief Static function to add boot seed claim to attestation token.
+ * \brief Static function to add implementation id claim to attestation token.
*
* \param[in] token_ctx Token encoding context
*
* \return Returns error code as specified in \ref psa_attest_err_t
*/
static enum psa_attest_err_t
-attest_add_boot_seed_claim(struct attest_token_encode_ctx *token_ctx)
+attest_add_implementation_id_claim(struct attest_token_encode_ctx *token_ctx)
{
- uint8_t boot_seed[BOOT_SEED_SIZE];
- enum tfm_plat_err_t res;
- struct q_useful_buf_c claim_value = {0};
- uint16_t tlv_len;
- uint8_t *tlv_ptr = NULL;
- int32_t found = 0;
-
- /* First look up BOOT_SEED in boot status, it might comes from bootloader */
- found = attest_get_tlv_by_id(BOOT_SEED, &tlv_len, &tlv_ptr);
- if (found == 1) {
- claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
- claim_value.len = tlv_len;
- } else {
- /* If not found in boot status then use callback function to get it
- * from runtime SW
- */
- res = tfm_plat_get_boot_seed(sizeof(boot_seed), boot_seed);
- if (res != TFM_PLAT_ERR_SUCCESS) {
- return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
- }
- claim_value.ptr = boot_seed;
- claim_value.len = BOOT_SEED_SIZE;
+ uint8_t implementation_id[IMPLEMENTATION_ID_MAX_SIZE];
+ enum tfm_plat_err_t res_plat;
+ uint32_t size = sizeof(implementation_id);
+ struct q_useful_buf_c claim_value;
+
+ res_plat = tfm_plat_get_implementation_id(&size, implementation_id);
+ if (res_plat != TFM_PLAT_ERR_SUCCESS) {
+ return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
}
+ claim_value.ptr = implementation_id;
+ claim_value.len = size;
attest_token_encode_add_bstr(token_ctx,
- EAT_CBOR_ARM_LABEL_BOOT_SEED,
+ IAT_IMPLEMENTATION_ID,
&claim_value);
return PSA_ATTEST_ERR_SUCCESS;
@@ -403,230 +187,278 @@ attest_add_instance_id_claim(struct attest_token_encode_ctx *token_ctx)
}
attest_token_encode_add_bstr(token_ctx,
- EAT_CBOR_ARM_LABEL_UEID,
+ IAT_INSTANCE_ID,
&claim_value);
return PSA_ATTEST_ERR_SUCCESS;
}
/*!
- * \brief Static function to add implementation id claim to attestation token.
+ * \brief Static function to add security lifecycle claim to attestation token.
*
* \param[in] token_ctx Token encoding context
*
* \return Returns error code as specified in \ref psa_attest_err_t
*/
static enum psa_attest_err_t
-attest_add_implementation_id_claim(struct attest_token_encode_ctx *token_ctx)
+attest_add_security_lifecycle_claim(struct attest_token_encode_ctx *token_ctx)
{
- uint8_t implementation_id[IMPLEMENTATION_ID_MAX_SIZE];
- enum tfm_plat_err_t res_plat;
- uint32_t size = sizeof(implementation_id);
- struct q_useful_buf_c claim_value;
+ enum tfm_security_lifecycle_t security_lifecycle;
- res_plat = tfm_plat_get_implementation_id(&size, implementation_id);
- if (res_plat != TFM_PLAT_ERR_SUCCESS) {
- return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
+ /* Use callback function to get it from runtime SW */
+ security_lifecycle = tfm_attest_hal_get_security_lifecycle();
+
+ /* Sanity check */
+ if (security_lifecycle > TFM_SLC_MAX_VALUE) {
+ return PSA_ATTEST_ERR_GENERAL;
}
- claim_value.ptr = implementation_id;
- claim_value.len = size;
- attest_token_encode_add_bstr(token_ctx,
- EAT_CBOR_ARM_LABEL_IMPLEMENTATION_ID,
- &claim_value);
+ attest_token_encode_add_integer(token_ctx,
+ IAT_SECURITY_LIFECYCLE,
+ (int64_t)security_lifecycle);
return PSA_ATTEST_ERR_SUCCESS;
}
/*!
- * \brief Static function to add caller id claim to attestation token.
+ * \brief Static function to add the name of the profile definition document
+ *
+ * \note This function would be optional for PSA IoT 1/2 profiles but we keep it
+ * as mandatory for both CCA and PSA IoT for simplicity
*
* \param[in] token_ctx Token encoding context
*
* \return Returns error code as specified in \ref psa_attest_err_t
*/
static enum psa_attest_err_t
-attest_add_caller_id_claim(struct attest_token_encode_ctx *token_ctx)
+attest_add_profile_definition(struct attest_token_encode_ctx *token_ctx)
{
- enum psa_attest_err_t res;
- int32_t caller_id;
+ struct q_useful_buf_c profile;
+ uint8_t buf[PROFILE_DEFINITION_MAX_SIZE];
+ uint32_t size = sizeof(buf);
+ enum tfm_plat_err_t err;
- res = attest_get_caller_client_id(&caller_id);
- if (res != PSA_ATTEST_ERR_SUCCESS) {
- return res;
+ err = tfm_attest_hal_get_profile_definition(&size, buf);
+ if (err != TFM_PLAT_ERR_SUCCESS) {
+ return PSA_ATTEST_ERR_GENERAL;
}
- attest_token_encode_add_integer(token_ctx,
- EAT_CBOR_ARM_LABEL_CLIENT_ID,
- (int64_t)caller_id);
+ profile.ptr = &buf;
+ profile.len = size;
+ attest_token_encode_add_tstr(token_ctx,
+ IAT_PROFILE_DEFINITION,
+ &profile);
return PSA_ATTEST_ERR_SUCCESS;
}
+#if ATTEST_INCLUDE_OPTIONAL_CLAIMS
/*!
- * \brief Static function to add security lifecycle claim to attestation token.
+ * \brief Static function to add the verification service indicator claim
+ * to the attestation token.
*
* \param[in] token_ctx Token encoding context
*
* \return Returns error code as specified in \ref psa_attest_err_t
*/
static enum psa_attest_err_t
-attest_add_security_lifecycle_claim(struct attest_token_encode_ctx *token_ctx)
+attest_add_verification_service(struct attest_token_encode_ctx *token_ctx)
{
- enum tfm_security_lifecycle_t security_lifecycle;
- uint32_t slc_value;
- int32_t res;
- struct q_useful_buf_c claim_value = {0};
- uint16_t tlv_len;
- uint8_t *tlv_ptr = NULL;
- int32_t found = 0;
-
- /* First look up lifecycle state in boot status, it might comes
- * from bootloader
- */
- found = attest_get_tlv_by_id(SECURITY_LIFECYCLE, &tlv_len, &tlv_ptr);
- if (found == 1) {
- claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
- claim_value.len = tlv_len;
- res = get_uint(claim_value.ptr, claim_value.len, &slc_value);
- if (res) {
- return PSA_ATTEST_ERR_GENERAL;
- }
- security_lifecycle = (enum tfm_security_lifecycle_t)slc_value;
- } else {
- /* If not found in boot status then use callback function to get it
- * from runtime SW
- */
- security_lifecycle = tfm_attest_hal_get_security_lifecycle();
- }
+ struct q_useful_buf_c service;
+ uint8_t buf[VERIFICATION_URL_MAX_SIZE];
+ uint32_t size = sizeof(buf);
+ enum tfm_plat_err_t err;
- /* Sanity check */
- if (security_lifecycle > TFM_SLC_MAX_VALUE) {
+ err = tfm_attest_hal_get_verification_service(&size, buf);
+ if (err != TFM_PLAT_ERR_SUCCESS) {
return PSA_ATTEST_ERR_GENERAL;
}
- attest_token_encode_add_integer(token_ctx,
- EAT_CBOR_ARM_LABEL_SECURITY_LIFECYCLE,
- (int64_t)security_lifecycle);
+ service.ptr = &buf;
+ service.len = size;
+ attest_token_encode_add_tstr(token_ctx,
+ IAT_VERIFICATION_SERVICE,
+ &service);
return PSA_ATTEST_ERR_SUCCESS;
}
+#endif /* ATTEST_INCLUDE_OPTIONAL_CLAIMS */
+#if ATTEST_TOKEN_PROFILE_PSA_IOT_1 || ATTEST_TOKEN_PROFILE_PSA_2_0_0
/*!
- * \brief Static function to add challenge claim to attestation token.
+ * \brief Static function to add boot seed claim to attestation token.
*
* \param[in] token_ctx Token encoding context
- * \param[in] challenge Pointer to buffer which stores the challenge
*
* \return Returns error code as specified in \ref psa_attest_err_t
*/
static enum psa_attest_err_t
-attest_add_challenge_claim(struct attest_token_encode_ctx *token_ctx,
- const struct q_useful_buf_c *challenge)
+attest_add_boot_seed_claim(struct attest_token_encode_ctx *token_ctx)
{
+ uint8_t boot_seed[BOOT_SEED_SIZE];
+ enum tfm_plat_err_t res;
+ struct q_useful_buf_c claim_value = {0};
+
+ /* Use callback function to get it from runtime SW */
+ res = tfm_plat_get_boot_seed(sizeof(boot_seed), boot_seed);
+ if (res != TFM_PLAT_ERR_SUCCESS) {
+ return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
+ }
+ claim_value.ptr = boot_seed;
+ claim_value.len = BOOT_SEED_SIZE;
+
attest_token_encode_add_bstr(token_ctx,
- EAT_CBOR_ARM_LABEL_CHALLENGE,
- challenge);
+ IAT_BOOT_SEED,
+ &claim_value);
return PSA_ATTEST_ERR_SUCCESS;
}
-#ifdef INCLUDE_OPTIONAL_CLAIMS /* Remove them from release build */
/*!
- * \brief Static function to add the verification service indicator claim
- * to the attestation token.
+ * \brief Static function to add caller id claim to attestation token.
*
* \param[in] token_ctx Token encoding context
*
* \return Returns error code as specified in \ref psa_attest_err_t
*/
static enum psa_attest_err_t
-attest_add_verification_service(struct attest_token_encode_ctx *token_ctx)
+attest_add_caller_id_claim(struct attest_token_encode_ctx *token_ctx)
{
- struct q_useful_buf_c service;
- uint32_t size;
-
- service.ptr = tfm_attest_hal_get_verification_service(&size);
+ enum psa_attest_err_t res;
+ int32_t caller_id;
- if (service.ptr) {
- service.len = size;
- attest_token_encode_add_tstr(token_ctx,
- EAT_CBOR_ARM_LABEL_ORIGINATION,
- &service);
+ res = attest_get_caller_client_id(&caller_id);
+ if (res != PSA_ATTEST_ERR_SUCCESS) {
+ return res;
}
+ attest_token_encode_add_integer(token_ctx,
+ IAT_CLIENT_ID,
+ (int64_t)caller_id);
+
return PSA_ATTEST_ERR_SUCCESS;
}
+#if ATTEST_INCLUDE_OPTIONAL_CLAIMS
/*!
- * \brief Static function to add the name of the profile definition document
+ * \brief Static function to add certification reference claim to attestation
+ * token.
*
* \param[in] token_ctx Token encoding context
*
* \return Returns error code as specified in \ref psa_attest_err_t
*/
static enum psa_attest_err_t
-attest_add_profile_definition(struct attest_token_encode_ctx *token_ctx)
+attest_add_cert_ref_claim(struct attest_token_encode_ctx *token_ctx)
{
- struct q_useful_buf_c profile;
- uint32_t size;
-
- profile.ptr = tfm_attest_hal_get_profile_definition(&size);
+ uint8_t buf[CERTIFICATION_REF_MAX_SIZE];
+ enum tfm_plat_err_t res_plat;
+ uint32_t size = sizeof(buf);
+ struct q_useful_buf_c claim_value = {0};
- if (profile.ptr) {
- profile.len = size;
- attest_token_encode_add_tstr(token_ctx,
- EAT_CBOR_ARM_LABEL_PROFILE_DEFINITION,
- &profile);
+ /* Use callback function to get it from runtime SW */
+ res_plat = tfm_plat_get_cert_ref(&size, buf);
+ if (res_plat != TFM_PLAT_ERR_SUCCESS) {
+ return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
}
+ claim_value.ptr = buf;
+ claim_value.len = size;
+
+ attest_token_encode_add_tstr(token_ctx,
+ IAT_CERTIFICATION_REFERENCE,
+ &claim_value);
return PSA_ATTEST_ERR_SUCCESS;
}
+#endif /* ATTEST_INCLUDE_OPTIONAL_CLAIMS */
+#endif /* ATTEST_TOKEN_PROFILE_PSA_IOT_1 || ATTEST_TOKEN_PROFILE_PSA_2_0_0 */
+#if ATTEST_TOKEN_PROFILE_ARM_CCA
/*!
- * \brief Static function to add hardware version claim to attestation token.
+ * \brief Static function to add the platform hash algorithm identifier
+ * claim to the attestation token. This hash algo is used for extending
+ * the boot measurements.
*
* \param[in] token_ctx Token encoding context
+ * \param[in] challenge Pointer to buffer which stores the hash algo.
*
* \return Returns error code as specified in \ref psa_attest_err_t
*/
static enum psa_attest_err_t
-attest_add_hw_version_claim(struct attest_token_encode_ctx *token_ctx)
+attest_add_hash_algo_claim(struct attest_token_encode_ctx *token_ctx)
{
- uint8_t hw_version[HW_VERSION_MAX_SIZE];
- enum tfm_plat_err_t res_plat;
- uint32_t size = sizeof(hw_version);
- struct q_useful_buf_c claim_value = {0};
- uint16_t tlv_len;
- uint8_t *tlv_ptr = NULL;
- int32_t found = 0;
+ struct q_useful_buf_c hash_algo;
+ uint8_t buf[PLATFORM_HASH_ALGO_ID_MAX_SIZE];
+ uint32_t size = sizeof(buf);
+ enum tfm_plat_err_t err;
- /* First look up HW version in boot status, it might comes
- * from bootloader
- */
- found = attest_get_tlv_by_id(HW_VERSION, &tlv_len, &tlv_ptr);
- if (found == 1) {
- claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
- claim_value.len = tlv_len;
- } else {
- /* If not found in boot status then use callback function to get it
- * from runtime SW
- */
- res_plat = tfm_plat_get_hw_version(&size, hw_version);
- if (res_plat != TFM_PLAT_ERR_SUCCESS) {
- return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
- }
- claim_value.ptr = hw_version;
- claim_value.len = size;
+ err = tfm_attest_hal_get_platform_hash_algo(&size, buf);
+ if (err != TFM_PLAT_ERR_SUCCESS) {
+ return PSA_ATTEST_ERR_GENERAL;
}
+ hash_algo.ptr = &buf;
+ hash_algo.len = size;
attest_token_encode_add_tstr(token_ctx,
- EAT_CBOR_ARM_LABEL_HW_VERSION,
+ IAT_PLATFORM_HASH_ALGO_ID,
+ &hash_algo);
+
+ return PSA_ATTEST_ERR_SUCCESS;
+}
+
+/*!
+ * \brief Static function to add the platform hash algorithm identifier
+ * claim to the attestation token. This hash algo is used for extending
+ * the boot measurements.
+ *
+ * \param[in] token_ctx Token encoding context
+ * \param[in] challenge Pointer to buffer which stores the hash algo.
+ *
+ * \return Returns error code as specified in \ref psa_attest_err_t
+ */
+static enum psa_attest_err_t
+attest_add_platform_config_claim(struct attest_token_encode_ctx *token_ctx)
+{
+
+ uint8_t plat_config[PLATFORM_CONFIG_MAX_SIZE];
+ enum tfm_plat_err_t res;
+ uint32_t size = sizeof(plat_config);
+ struct q_useful_buf_c claim_value;
+
+ res = tfm_attest_hal_get_platform_config(&size, plat_config);
+ if (res != TFM_PLAT_ERR_SUCCESS) {
+ return PSA_ATTEST_ERR_GENERAL;
+ }
+
+ claim_value.ptr = plat_config;
+ claim_value.len = size;
+
+ attest_token_encode_add_bstr(token_ctx,
+ IAT_PLATFORM_CONFIG,
&claim_value);
return PSA_ATTEST_ERR_SUCCESS;
}
-#endif /* INCLUDE_OPTIONAL_CLAIMS */
+#endif /* ATTEST_TOKEN_PROFILE_ARM_CCA */
+
+/*!
+ * \brief Static function to add the nonce claim to attestation token.
+ *
+ * \param[in] token_ctx Token encoding context
+ * \param[in] nonce Pointer to buffer which stores the challenge
+ *
+ * \return Returns error code as specified in \ref psa_attest_err_t
+ */
+static enum psa_attest_err_t
+attest_add_nonce_claim(struct attest_token_encode_ctx *token_ctx,
+ const struct q_useful_buf_c *nonce)
+{
+ attest_token_encode_add_bstr(token_ctx,
+ IAT_NONCE,
+ nonce);
+
+ return PSA_ATTEST_ERR_SUCCESS;
+}
/*!
* \brief Static function to verify the input challenge size
@@ -651,7 +483,7 @@ static enum psa_attest_err_t attest_verify_challenge_size(size_t challenge_size)
return PSA_ATTEST_ERR_INVALID_INPUT;
}
-#ifdef INCLUDE_TEST_CODE /* Remove them from release build */
+#ifdef INCLUDE_TEST_CODE
/*!
* \brief Static function to get the option flags from challenge object
*
@@ -694,7 +526,7 @@ static void attest_get_option_flags(struct q_useful_buf_c *challenge,
}
if (found_option_flags) {
- (void)tfm_memcpy(option_flags, challenge->ptr, option_flags_size);
+ (void)memcpy(option_flags, challenge->ptr, option_flags_size);
/* Lower three bits are the key select */
*key_select = *option_flags & 0x7;
@@ -705,6 +537,93 @@ static void attest_get_option_flags(struct q_useful_buf_c *challenge,
}
#endif /* INCLUDE_TEST_CODE */
+static enum psa_attest_err_t attest_get_t_cose_algorithm(
+ int32_t *cose_algorithm_id)
+{
+ psa_status_t status;
+ psa_key_attributes_t attr;
+ psa_key_handle_t handle = TFM_BUILTIN_KEY_ID_IAK;
+ psa_key_type_t key_type;
+
+ status = psa_get_key_attributes(handle, &attr);
+ if (status != PSA_SUCCESS) {
+ return PSA_ATTEST_ERR_GENERAL;
+ }
+
+ key_type = psa_get_key_type(&attr);
+ if (status != PSA_SUCCESS) {
+ return PSA_ATTEST_ERR_GENERAL;
+ }
+
+ if (PSA_KEY_TYPE_IS_ECC(key_type) &&
+ PSA_KEY_TYPE_ECC_GET_FAMILY(key_type) == PSA_ECC_FAMILY_SECP_R1) {
+ switch (psa_get_key_bits(&attr)) {
+ case 256:
+ *cose_algorithm_id = T_COSE_ALGORITHM_ES256;
+ break;
+ case 384:
+ *cose_algorithm_id = T_COSE_ALGORITHM_ES384;
+ break;
+ case 512:
+ *cose_algorithm_id = T_COSE_ALGORITHM_ES512;
+ break;
+ default:
+ return PSA_ATTEST_ERR_GENERAL;
+ }
+ } else if (key_type == PSA_KEY_TYPE_HMAC) {
+ switch (psa_get_key_bits(&attr)) {
+ case 256:
+ *cose_algorithm_id = T_COSE_ALGORITHM_HMAC256;
+ break;
+ case 384:
+ *cose_algorithm_id = T_COSE_ALGORITHM_HMAC384;
+ break;
+ case 512:
+ *cose_algorithm_id = T_COSE_ALGORITHM_HMAC512;
+ break;
+ default:
+ return PSA_ATTEST_ERR_GENERAL;
+ }
+ } else {
+ LOG_DBGFMT("Attestation: Unexpected key_type for TFM_BUILTIN_KEY_ID_IAK. Key storage may be corrupted!\r\n");
+ return PSA_ATTEST_ERR_GENERAL;
+ }
+
+ return PSA_ATTEST_ERR_SUCCESS;
+}
+
+#if ATTEST_TOKEN_PROFILE_PSA_IOT_1 || ATTEST_TOKEN_PROFILE_PSA_2_0_0
+ static enum psa_attest_err_t
+ (*claim_query_funcs[])(struct attest_token_encode_ctx *) = {
+ &attest_add_boot_seed_claim,
+ &attest_add_instance_id_claim,
+ &attest_add_implementation_id_claim,
+ &attest_add_caller_id_claim,
+ &attest_add_security_lifecycle_claim,
+ &attest_add_all_sw_components,
+ &attest_add_profile_definition,
+#if ATTEST_INCLUDE_OPTIONAL_CLAIMS
+ &attest_add_verification_service,
+ &attest_add_cert_ref_claim
+#endif
+ };
+#elif ATTEST_TOKEN_PROFILE_ARM_CCA
+
+ static enum psa_attest_err_t
+ (*claim_query_funcs[])(struct attest_token_encode_ctx *) = {
+ &attest_add_instance_id_claim,
+ &attest_add_implementation_id_claim,
+ &attest_add_security_lifecycle_claim,
+ &attest_add_all_sw_components,
+ &attest_add_profile_definition,
+ &attest_add_hash_algo_claim,
+ &attest_add_platform_config_claim,
+#if ATTEST_INCLUDE_OPTIONAL_CLAIMS
+ &attest_add_verification_service,
+#endif
+ };
+#endif
+
/*!
* \brief Static function to create the initial attestation token
*
@@ -727,23 +646,37 @@ attest_create_token(struct q_useful_buf_c *challenge,
struct attest_token_encode_ctx attest_token_ctx;
int32_t key_select = 0;
uint32_t option_flags = 0;
+ int i;
+ int32_t cose_algorithm_id;
- attest_err = attest_register_initial_attestation_key();
+ attest_err = attest_get_t_cose_algorithm(&cose_algorithm_id);
if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
- goto error;
+ return attest_err;
}
-#ifdef INCLUDE_TEST_CODE /* Remove them from release build */
+#ifdef INCLUDE_TEST_CODE
attest_get_option_flags(challenge, &option_flags, &key_select);
+ if (option_flags) {
+ /* If any option flags are provided (TOKEN_OPT_OMIT_CLAIMS or
+ * TOKEN_OPT_SHORT_CIRCUIT_SIGN) then force the cose_algorithm_id
+ * to be either:
+ * - T_COSE_ALGORITHM_ES256 or (SYMMETRIC_INITIAL_ATTESTATION=OFF)
+ * - T_COSE_ALGORITHM_HMAC256 (SYMMETRIC_INITIAL_ATTESTATION=ON)
+ * for testing purposes to match with expected minimal token.
+ */
+ /* ESxxx range is smaller than 0; HMACxxx range is greater than 0 */
+ cose_algorithm_id = cose_algorithm_id < 0 ? T_COSE_ALGORITHM_ES256 :
+ T_COSE_ALGORITHM_HMAC256;
+ }
#endif
/* Get started creating the token. This sets up the CBOR and COSE contexts
* which causes the COSE headers to be constructed.
*/
token_err = attest_token_encode_start(&attest_token_ctx,
- option_flags, /* option_flags */
- key_select, /* key_select */
- T_COSE_ALGORITHM, /* alg_select */
+ option_flags, /* option_flags */
+ key_select, /* key_select */
+ cose_algorithm_id, /* alg_select */
token);
if (token_err != ATTEST_TOKEN_ERR_SUCCESS) {
@@ -751,97 +684,46 @@ attest_create_token(struct q_useful_buf_c *challenge,
goto error;
}
- attest_err = attest_add_challenge_claim(&attest_token_ctx,
- challenge);
+ attest_err = attest_add_nonce_claim(&attest_token_ctx,
+ challenge);
if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
goto error;
}
if (!(option_flags & TOKEN_OPT_OMIT_CLAIMS)) {
- /* Mandatory claims in IAT token */
- attest_err = attest_add_boot_seed_claim(&attest_token_ctx);
- if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
- goto error;
- }
-
- attest_err = attest_add_instance_id_claim(&attest_token_ctx);
- if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
- goto error;
- }
-
- attest_err = attest_add_implementation_id_claim(&attest_token_ctx);
- if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
- goto error;
- }
-
- attest_err = attest_add_caller_id_claim(&attest_token_ctx);
- if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
- goto error;
- }
-
- attest_err = attest_add_security_lifecycle_claim(&attest_token_ctx);
- if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
- goto error;
- }
-
- attest_err = attest_add_all_sw_components(&attest_token_ctx);
- if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
- goto error;
- }
-
-#ifdef INCLUDE_OPTIONAL_CLAIMS
- /* Optional claims in IAT token, remove them from release build */
- attest_err = attest_add_verification_service(&attest_token_ctx);
- if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
- goto error;
- }
-
- attest_err = attest_add_profile_definition(&attest_token_ctx);
- if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
- goto error;
- }
-
- attest_err = attest_add_hw_version_claim(&attest_token_ctx);
- if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
- goto error;
+ for (i = 0; i < ARRAY_LENGTH(claim_query_funcs); ++i) {
+ /* Calling the attest_add_XXX_claim functions */
+ attest_err = claim_query_funcs[i](&attest_token_ctx);
+ if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
+ goto error;
+ }
}
-#endif /* INCLUDE_OPTIONAL_CLAIMS */
}
/* Finish up creating the token. This is where the actual signature
* is generated. This finishes up the CBOR encoding too.
*/
token_err = attest_token_encode_finish(&attest_token_ctx, completed_token);
- if (token_err) {
- attest_err = error_mapping_to_psa_attest_err_t(token_err);
- goto error;
- }
+ attest_err = error_mapping_to_psa_attest_err_t(token_err);
error:
- if (attest_err == PSA_ATTEST_ERR_SUCCESS) {
- /* We got here normally and therefore care about error codes. */
- attest_err = attest_unregister_initial_attestation_key();
- }
- else {
- /* Error handler: just remove they key and preserve error. */
- (void)attest_unregister_initial_attestation_key();
- }
return attest_err;
}
psa_status_t
-initial_attest_get_token(const psa_invec *in_vec, uint32_t num_invec,
- psa_outvec *out_vec, uint32_t num_outvec)
+initial_attest_get_token(const void *challenge_buf, size_t challenge_size,
+ void *token_buf, size_t token_buf_size,
+ size_t *token_size)
{
enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS;
struct q_useful_buf_c challenge;
struct q_useful_buf token;
struct q_useful_buf_c completed_token;
- challenge.ptr = in_vec[0].base;
- challenge.len = in_vec[0].len;
- token.ptr = out_vec[0].base;
- token.len = out_vec[0].len;
+ challenge.ptr = challenge_buf;
+ challenge.len = challenge_size;
+ token.ptr = token_buf;
+ token.len = token_buf_size;
attest_err = attest_verify_challenge_size(challenge.len);
if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
@@ -858,20 +740,17 @@ initial_attest_get_token(const psa_invec *in_vec, uint32_t num_invec,
goto error;
}
- out_vec[0].base = (void *)completed_token.ptr;
- out_vec[0].len = completed_token.len;
+ *token_size = completed_token.len;
error:
return error_mapping_to_psa_status_t(attest_err);
}
psa_status_t
-initial_attest_get_token_size(const psa_invec *in_vec, uint32_t num_invec,
- psa_outvec *out_vec, uint32_t num_outvec)
+initial_attest_get_token_size(const size_t challenge_size,
+ size_t *token_size)
{
enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS;
- uint32_t challenge_size = *(uint32_t *)in_vec[0].base;
- uint32_t *token_buf_size = (uint32_t *)out_vec[0].base;
struct q_useful_buf_c challenge;
struct q_useful_buf token;
struct q_useful_buf_c completed_token;
@@ -884,11 +763,6 @@ initial_attest_get_token_size(const psa_invec *in_vec, uint32_t num_invec,
token.ptr = NULL;
token.len = INT32_MAX;
- if (out_vec[0].len < sizeof(uint32_t)) {
- attest_err = PSA_ATTEST_ERR_INVALID_INPUT;
- goto error;
- }
-
attest_err = attest_verify_challenge_size(challenge_size);
if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
goto error;
@@ -899,70 +773,8 @@ initial_attest_get_token_size(const psa_invec *in_vec, uint32_t num_invec,
goto error;
}
- *token_buf_size = completed_token.len;
-
-error:
- return error_mapping_to_psa_status_t(attest_err);
-}
-
-#ifdef SYMMETRIC_INITIAL_ATTESTATION
-psa_status_t
-initial_attest_get_public_key(const psa_invec *in_vec, uint32_t num_invec,
- psa_outvec *out_vec, uint32_t num_outvec)
-{
- (void)in_vec;
- (void)num_invec;
- (void)out_vec;
- (void)num_outvec;
-
- return PSA_ERROR_NOT_SUPPORTED;
-}
-#else /* SYMMETRIC_INITIAL_ATTESTATION */
-psa_status_t
-initial_attest_get_public_key(const psa_invec *in_vec, uint32_t num_invec,
- psa_outvec *out_vec, uint32_t num_outvec)
-{
- enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS;
- struct q_useful_buf key_buffer;
- uint8_t *key_source;
- size_t key_len;
- psa_ecc_family_t curve_type;
-
- (void)in_vec;
-
- if (num_invec != 0 || num_outvec != 3) {
- attest_err = PSA_ATTEST_ERR_INVALID_INPUT;
- goto error;
- }
-
- key_buffer.ptr = out_vec[0].base;
- key_buffer.len = out_vec[0].len;
-
- if (out_vec[1].len != sizeof(curve_type) ||
- out_vec[2].len != sizeof(key_len)) {
- attest_err = PSA_ATTEST_ERR_INVALID_INPUT;
- goto error;
- }
-
- attest_err = attest_get_initial_attestation_public_key(&key_source,
- &key_len,
- &curve_type);
- if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
- goto error;
- }
-
- if (key_buffer.len < key_len) {
- attest_err = PSA_ATTEST_ERR_BUFFER_OVERFLOW;
- goto error;
- }
-
- (void)tfm_memcpy(key_buffer.ptr, key_source, key_len);
-
- *(psa_ecc_family_t *)out_vec[1].base = curve_type;
-
- *(size_t *)out_vec[2].base = key_len;
+ *token_size = completed_token.len;
error:
return error_mapping_to_psa_status_t(attest_err);
}
-#endif /* SYMMETRIC_INITIAL_ATTESTATION */