Add attestation key management

Adds component to manage access and creation of the IAK.  Allows
for factory provisioned and generate-on-first-run strategies.
Extended the attestation reporter tests to use the key manager
to allow the signed report to be verified.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I01e126a8a18a7b3d24a0b322885aa9e558070250
diff --git a/components/service/attestation/key_mngr/attest_key_mngr.c b/components/service/attestation/key_mngr/attest_key_mngr.c
new file mode 100644
index 0000000..c871c82
--- /dev/null
+++ b/components/service/attestation/key_mngr/attest_key_mngr.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <psa/crypto.h>
+#include "attest_key_mngr.h"
+
+/* todo - need strategy for assigning key IDs */
+#define IAK_KEY_ID          0x2000
+
+/**
+ * The singleton attest_key_mngr instance.
+ */
+static struct attest_key_mngr
+{
+    bool is_iak_open;
+    psa_key_id_t iak_id;
+    psa_key_handle_t iak_handle;
+} instance;
+
+/**
+ * \brief Generates the IAK
+ *
+ *  If an IAK hasn't been provisioned during manufacture, there is the
+ *  option to generate a persistent IAK on first run.
+ *
+ * \param[in] key_id       The IAK key id or zero for volatile key
+ * \param[out] iak_handle  The returned key handle
+ *
+ * \return Status
+ */
+static psa_status_t generate_iak(psa_key_id_t key_id, psa_key_handle_t *iak_handle)
+{
+    psa_status_t status;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    if (key_id)
+        psa_set_key_id(&attributes, key_id);
+    else
+        psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+
+    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
+
+    psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
+    psa_set_key_bits(&attributes, 256);
+
+    status = psa_generate_key(&attributes, iak_handle);
+
+    psa_reset_key_attributes(&attributes);
+
+    return status;
+}
+
+void attest_key_mngr_init(void)
+{
+    instance.is_iak_open = false;
+    instance.iak_id = IAK_KEY_ID;
+    instance.iak_handle = -1;
+}
+
+void attest_key_mngr_deinit(void)
+{
+
+}
+
+psa_status_t attest_key_mngr_get_iak_handle(psa_key_handle_t *iak_handle)
+{
+    psa_status_t status = PSA_SUCCESS;
+
+    if (!instance.is_iak_open) {
+
+        status = psa_open_key(instance.iak_id, &instance.iak_handle);
+
+        if (status == PSA_ERROR_STORAGE_FAILURE) {
+
+            /* Accommodate deployments with no persistent storage
+             * to support testing.  In this case, a volatile key
+             * is generated, indicated by an invalid key id.
+             */
+            instance.iak_id = 0;
+        }
+
+        if (status != PSA_SUCCESS) {
+
+            /* First run and no key has been provisioned */
+            status = generate_iak(instance.iak_id, &instance.iak_handle);
+        }
+
+        instance.is_iak_open = (status == PSA_SUCCESS);
+    }
+
+    *iak_handle = instance.iak_handle;
+    return status;
+}
+
+psa_status_t attest_key_mngr_export_iak_public_key(uint8_t *data,
+                                size_t data_size, size_t *data_length)
+{
+    psa_key_handle_t handle;
+    psa_status_t status = attest_key_mngr_get_iak_handle(&handle);
+
+    if (status == PSA_SUCCESS) {
+
+        status = psa_export_public_key(handle, data, data_size, data_length);
+    }
+
+    return status;
+}
diff --git a/components/service/attestation/key_mngr/attest_key_mngr.h b/components/service/attestation/key_mngr/attest_key_mngr.h
new file mode 100644
index 0000000..982c841
--- /dev/null
+++ b/components/service/attestation/key_mngr/attest_key_mngr.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ATTEST_KEY_MNGR_H
+#define ATTEST_KEY_MNGR_H
+
+#include <psa/crypto.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The attestation key manager manages creation and access
+ * to the IAK. In real device deployments, the IAK will
+ * either be provisioned during manufacture or generated
+ * on first run.  To accommodate both sceanrios and to support
+ * testing without a persistent key store, the IAK is
+ * genarated automatically if the corresponding persistent
+ * key doesn't exist.
+ */
+
+/**
+ * \brief Initialize the attest_key_mngr
+ */
+void attest_key_mngr_init(void);
+
+/**
+ * \brief De-initialize the attest_key_mngr
+ */
+void attest_key_mngr_deinit(void);
+
+/**
+ * \brief Get the IAK key handle
+ *
+ * \param[out] iak_handle  The returned key handle
+ * \return Status
+ */
+psa_status_t attest_key_mngr_get_iak_handle(psa_key_handle_t *iak_handle);
+
+/**
+ * \brief Export the IAK public key
+ *
+ * \param[out] data  Buffer for key data
+ * \param[in]  data_size Size of buffer
+ * \param[out] data_length  Length in bytes of key
+ *
+ * \return Status
+ */
+psa_status_t attest_key_mngr_export_iak_public_key(uint8_t *data,
+                                size_t data_size, size_t *data_length);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ATTEST_KEY_MNGR_H */
diff --git a/components/service/attestation/key_mngr/component.cmake b/components/service/attestation/key_mngr/component.cmake
new file mode 100644
index 0000000..722d4f5
--- /dev/null
+++ b/components/service/attestation/key_mngr/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 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}/attest_key_mngr.c"
+	)
diff --git a/components/service/attestation/reporter/attestation_report.h b/components/service/attestation/reporter/attest_report.h
similarity index 73%
rename from components/service/attestation/reporter/attestation_report.h
rename to components/service/attestation/reporter/attest_report.h
index 3b51af2..f5c6fb0 100644
--- a/components/service/attestation/reporter/attestation_report.h
+++ b/components/service/attestation/reporter/attest_report.h
@@ -4,12 +4,13 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef ATTESTATION_REPORT_H
-#define ATTESTATION_REPORT_H
+#ifndef ATTEST_REPORT_H
+#define ATTEST_REPORT_H
 
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <psa/crypto.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -20,9 +21,10 @@
  *
  *  Using the view of the security state of the device provided by
  *  the claims_register, a signed attestation report is created.  On
- *  success, a buffer is allocated for the serialized report.  The buffer
- *  must be freed by calling attestation_report_destroy().
+ *  success, a buffer is allocated for the signed report.  The buffer
+ *  must be freed by calling attest_report_destroy().
  *
+ * \param[in] key_handle            Signing key handle
  * \param[in] client_id             The requesting client id
  * \param[in] auth_challenge_data   The auth challenge from the requester
  * \param[in] auth_challenge_len    The auth challenge from the requester
@@ -31,7 +33,7 @@
  *
  * \return Operation status
  */
-int attestation_report_create(int32_t client_id,
+int attest_report_create(psa_key_handle_t key_handle, int32_t client_id,
         const uint8_t *auth_challenge_data, size_t auth_challenge_len,
         const uint8_t **report, size_t *report_len);
 
@@ -42,11 +44,11 @@
  *
  * \param[in] report               The created report
  */
-void attestation_report_destroy(const uint8_t *report);
+void attest_report_destroy(const uint8_t *report);
 
 
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
 
-#endif /* ATTESTATION_REPORT_H */
+#endif /* ATTEST_REPORT_H */
diff --git a/components/service/attestation/reporter/psa/component.cmake b/components/service/attestation/reporter/psa/component.cmake
index 26be202..084c00f 100644
--- a/components/service/attestation/reporter/psa/component.cmake
+++ b/components/service/attestation/reporter/psa/component.cmake
@@ -9,6 +9,7 @@
 endif()
 
 target_sources(${TGT} PRIVATE
-	"${CMAKE_CURRENT_LIST_DIR}/attestation_report.c"
-	"${CMAKE_CURRENT_LIST_DIR}/report_serializer.c"
+	"${CMAKE_CURRENT_LIST_DIR}/psa_attest_report.c"
+	"${CMAKE_CURRENT_LIST_DIR}/eat_serializer.c"
+	"${CMAKE_CURRENT_LIST_DIR}/eat_signer.c"
 	)
diff --git a/components/service/attestation/reporter/psa/report_serializer.c b/components/service/attestation/reporter/psa/eat_serializer.c
similarity index 94%
rename from components/service/attestation/reporter/psa/report_serializer.c
rename to components/service/attestation/reporter/psa/eat_serializer.c
index d66060e..88b595d 100644
--- a/components/service/attestation/reporter/psa/report_serializer.c
+++ b/components/service/attestation/reporter/psa/eat_serializer.c
@@ -11,7 +11,7 @@
 #include <psa/error.h>
 #include <protocols/service/attestation/packed-c/eat.h>
 #include <service/attestation/claims/claim.h>
-#include "report_serializer.h"
+#include "eat_serializer.h"
 
 static bool alloc_encode_buffer(const struct claim_vector *device_claims,
     const struct claim_vector *sw_claims, UsefulBuf *encode_buffer);
@@ -20,9 +20,9 @@
 static int eat_label(enum claim_subject_id subject_id);
 static int qcbor_to_psa_status(QCBORError qcbor_err);
 
-int serialize_report(const struct claim_vector *device_claims,
+int eat_serialize(const struct claim_vector *device_claims,
     const struct claim_vector *sw_claims,
-    const uint8_t **report, size_t *report_len)
+    const uint8_t **token, size_t *token_len)
 {
     UsefulBuf encode_buffer;
 
@@ -54,21 +54,21 @@
 
     QCBOREncode_CloseMap(&encode_ctx);
 
-    /* Finalize the encoding to create the CBOR serialized report */
+    /* Finalize the encoding to create the CBOR serialized token */
     UsefulBufC encoded_cbor;
     QCBORError qcbor_error;
     qcbor_error = QCBOREncode_Finish(&encode_ctx, &encoded_cbor);
 
     if (qcbor_error == QCBOR_SUCCESS) {
 
-        *report = encoded_cbor.ptr;
-        *report_len = encoded_cbor.len;
+        *token = encoded_cbor.ptr;
+        *token_len = encoded_cbor.len;
     }
     else {
 
         free(encode_buffer.ptr);
-        *report = NULL;
-        *report_len = 0;
+        *token = NULL;
+        *token_len = 0;
     }
 
     return qcbor_to_psa_status(qcbor_error);
diff --git a/components/service/attestation/reporter/psa/eat_serializer.h b/components/service/attestation/reporter/psa/eat_serializer.h
new file mode 100644
index 0000000..9744bc6
--- /dev/null
+++ b/components/service/attestation/reporter/psa/eat_serializer.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_EAT_SERIALIZER_H
+#define PSA_EAT_SERIALIZER_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <service/attestation/claims/claim_vector.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Serialize the collated set of claims
+ *
+ *  Serializes the claims into a CBOR document using PSA defined
+ *  EAT custom claims to identify claim objects.  The output
+ *  token is encoded as cbor but is not signed.
+ *
+ * \param[in] device_claims         Collated device claims
+ * \param[in] sw_claims             Collated software claims
+ * \param[out] token                The serialized token
+ * \param[out] token_len            The length of the token
+ *
+ * \return Operation status
+ */
+int eat_serialize(const struct claim_vector *device_claims,
+    const struct claim_vector *sw_claims,
+    const uint8_t **token, size_t *token_len);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PSA_EAT_SERIALIZER_H */
diff --git a/components/service/attestation/reporter/psa/eat_signer.c b/components/service/attestation/reporter/psa/eat_signer.c
new file mode 100644
index 0000000..08756e7
--- /dev/null
+++ b/components/service/attestation/reporter/psa/eat_signer.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <t_cose/t_cose_sign1_sign.h>
+#include <psa/error.h>
+#include "eat_signer.h"
+
+static bool alloc_output_buf(struct q_useful_buf *buf, size_t input_len);
+static int t_cose_to_psa_status(enum t_cose_err_t t_cose_status);
+
+int eat_sign(psa_key_handle_t key_handle,
+    const uint8_t *unsigned_token, size_t unsigned_token_len,
+    const uint8_t **signed_token, size_t *signed_token_len)
+{
+    struct t_cose_key signing_key;
+    struct t_cose_sign1_sign_ctx sign_ctx;
+    enum t_cose_err_t sign_status;
+    struct q_useful_buf_c input_buf;
+    struct q_useful_buf output_buf;
+    struct q_useful_buf_c result_buf;
+
+    /* Prepare input and output buffers for signing operation */
+    input_buf.ptr = unsigned_token;
+    input_buf.len = unsigned_token_len;
+    result_buf.ptr = NULL;
+    result_buf.len = 0;
+    if (!alloc_output_buf(&output_buf, unsigned_token_len))
+        return PSA_ERROR_INSUFFICIENT_MEMORY;
+
+    /* Initialize signing context */
+    signing_key.k.key_handle = key_handle;
+    signing_key.crypto_lib  = T_COSE_CRYPTO_LIB_PSA;
+    t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_ES256);
+    t_cose_sign1_set_signing_key(&sign_ctx, signing_key,  NULL_Q_USEFUL_BUF_C);
+
+    /* Sign */
+    sign_status = t_cose_sign1_sign(&sign_ctx, input_buf, output_buf, &result_buf);
+
+    if (sign_status == T_COSE_SUCCESS) {
+
+        /* Note that result_buf points into output_buf with len
+         * corresponding to the signed token length.
+         */
+        *signed_token = result_buf.ptr;
+        *signed_token_len = result_buf.len;
+    }
+    else {
+
+        free((void*)output_buf.ptr);
+        *signed_token = NULL;
+        *signed_token_len = 0;
+    }
+
+    return t_cose_to_psa_status(sign_status);
+}
+
+static bool alloc_output_buf(struct q_useful_buf *buf, size_t input_len)
+{
+    size_t required_space = input_len + 300;  /* todo figure out correct overhead */
+    uint8_t *space = malloc(required_space);
+
+    if (space) {
+        buf->ptr = space;
+        buf->len = required_space;
+    }
+
+    return space;
+}
+
+static int t_cose_to_psa_status(enum t_cose_err_t t_cose_status)
+{
+    if (t_cose_status == T_COSE_SUCCESS)          return PSA_SUCCESS;
+    if (t_cose_status == T_COSE_ERR_TOO_SMALL)    return PSA_ERROR_BUFFER_TOO_SMALL;
+
+    return PSA_ERROR_PROGRAMMER_ERROR;
+}
diff --git a/components/service/attestation/reporter/psa/eat_signer.h b/components/service/attestation/reporter/psa/eat_signer.h
new file mode 100644
index 0000000..421cbc2
--- /dev/null
+++ b/components/service/attestation/reporter/psa/eat_signer.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_EAT_SIGNER_H
+#define PSA_EAT_SIGNER_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <psa/crypto.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Sign the serialized EAT token
+ *
+ * \param[in] key_handle         Signing key handle
+ * \param[in] unsigned_token     The token to sign
+ * \param[in] unsigned_token_len The token to sign
+ * \param[out] signed_token      The signed token
+ * \param[out] signed_token_len  The length of the signed token
+ *
+ * \return Operation status
+ */
+int eat_sign(psa_key_handle_t key_handle,
+    const uint8_t *unsigned_token, size_t unsigned_token_len,
+    const uint8_t **signed_token, size_t *signed_token_len);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PSA_EAT_SIGNER_H */
diff --git a/components/service/attestation/reporter/psa/attestation_report.c b/components/service/attestation/reporter/psa/psa_attest_report.c
similarity index 79%
rename from components/service/attestation/reporter/psa/attestation_report.c
rename to components/service/attestation/reporter/psa/psa_attest_report.c
index ed34307..3228f1c 100644
--- a/components/service/attestation/reporter/psa/attestation_report.c
+++ b/components/service/attestation/reporter/psa/psa_attest_report.c
@@ -13,9 +13,10 @@
 
 #include <stdlib.h>
 #include <psa/error.h>
-#include <service/attestation/reporter/attestation_report.h>
+#include <service/attestation/reporter/attest_report.h>
 #include <service/attestation/claims/claims_register.h>
-#include "report_serializer.h"
+#include "eat_serializer.h"
+#include "eat_signer.h"
 
 /* Local defines */
 #define MAX_DEVICE_CLAIMS       (50)
@@ -26,7 +27,7 @@
 static void add_no_sw_claim(struct claim_vector *v);
 
 
-int attestation_report_create(int32_t client_id,
+int attest_report_create(psa_key_handle_t key_handle, int32_t client_id,
     const uint8_t *auth_challenge_data, size_t auth_challenge_len,
     const uint8_t **report, size_t *report_len)
 {
@@ -52,16 +53,27 @@
     /* And if there aren't any sw claims, indicate in report */
     if (!sw_claims.size) add_no_sw_claim(&device_claims);
 
-    /* Serialize the collated claims to create the final report */
-    status = serialize_report(&device_claims, &sw_claims, report, report_len);
+    /* Serialize and sign the collated claims to create the final EAT token */
+    const uint8_t *unsigned_token = NULL;
+    size_t unsigned_token_len = 0;
+    status = eat_serialize(&device_claims, &sw_claims,
+                    &unsigned_token, &unsigned_token_len);
 
+    if (status == PSA_SUCCESS) {
+        status = eat_sign(key_handle,
+                    unsigned_token, unsigned_token_len,
+                    report, report_len);
+    }
+
+    /* Free resource used */
+    free((void*)unsigned_token);
     claim_vector_deinit(&device_claims);
     claim_vector_deinit(&sw_claims);
 
     return status;
 }
 
-void attestation_report_destroy(const uint8_t *report)
+void attest_report_destroy(const uint8_t *report)
 {
     free((void*)report);
 }
diff --git a/components/service/attestation/reporter/psa/report_serializer.h b/components/service/attestation/reporter/psa/report_serializer.h
deleted file mode 100644
index 5da5a66..0000000
--- a/components/service/attestation/reporter/psa/report_serializer.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef PSA_REPORT_SERIALIZER_H
-#define PSA_REPORT_SERIALIZER_H
-
-#include <stddef.h>
-#include <stdint.h>
-#include <service/attestation/claims/claim_vector.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \brief Serialize the collated set of claims
- *
- *  Serializes the claims into a CBOR document using PSA defined
- *  EAT custom claims to identify claim objects.
- *
- * \param[in] device_claims         Collated device claims
- * \param[in] sw_claims             Collated software claims
- * \param[out] report               The serialized report
- * \param[out] report_len           The length of the report
- *
- * \return Operation status
- */
-int serialize_report(const struct claim_vector *device_claims,
-    const struct claim_vector *sw_claims,
-    const uint8_t **report, size_t *report_len);
-
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* PSA_REPORT_SERIALIZER_H */
diff --git a/components/service/attestation/test/component/attestation_reporter_tests.cpp b/components/service/attestation/test/component/attestation_reporter_tests.cpp
index 71fc10d..02b91ac 100644
--- a/components/service/attestation/test/component/attestation_reporter_tests.cpp
+++ b/components/service/attestation/test/component/attestation_reporter_tests.cpp
@@ -6,17 +6,18 @@
 
 #include <psa/error.h>
 #include <qcbor/qcbor_spiffy_decode.h>
+#include <t_cose/t_cose_sign1_verify.h>
 #include <service/attestation/claims/claims_register.h>
 #include <service/attestation/claims/sources/event_log/event_log_claim_source.h>
 #include <service/attestation/claims/sources/event_log/mock/mock_event_log.h>
 #include <service/attestation/claims/sources/preloaded/preloaded_claim_source.h>
-#include <service/attestation/reporter/attestation_report.h>
+#include <service/attestation/reporter/attest_report.h>
+#include <service/attestation/key_mngr/attest_key_mngr.h>
 #include <protocols/service/attestation/packed-c/eat.h>
 #include <CppUTest/TestHarness.h>
+#include <psa/crypto.h>
 #include "report_dump.h"
 
-#include <stdio.h>
-
 TEST_GROUP(AttestationReporterTests)
 {
     void setup()
@@ -26,6 +27,9 @@
         report = NULL;
         report_len;
 
+        psa_crypto_init();
+        attest_key_mngr_init();
+
         /* The set of registered claim_sources determines the content
          * of a generated attestation source.  The set and type of
          * claim_sources registered will be deployment specific.
@@ -40,8 +44,9 @@
 
     void teardown()
     {
-        attestation_report_destroy(report);
+        attest_report_destroy(report);
         claims_register_deinit();
+        attest_key_mngr_deinit();
     }
 
     struct event_log_claim_source event_log_claim_source;
@@ -60,26 +65,45 @@
         17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32
     };
 
+    /* Retrieve the IAK handle */
+    psa_key_handle_t iak_handle;
+    status = attest_key_mngr_get_iak_handle(&iak_handle);
+    LONGS_EQUAL(PSA_SUCCESS, status);
+
     /* Create a report */
-    status = attestation_report_create(client_id,
+    status = attest_report_create(iak_handle, client_id,
         auth_challenge, sizeof(auth_challenge),
         &report, &report_len);
 
     /* Expect the operation to succeed and a non-zero length
      * report created.
      */
-    UNSIGNED_LONGS_EQUAL(PSA_SUCCESS, status);
+    LONGS_EQUAL(PSA_SUCCESS, status);
     CHECK_TRUE(report);
     CHECK_TRUE(report_len);
 
+    /* Verify the signature */
+    struct t_cose_sign1_verify_ctx verify_ctx;
+    struct t_cose_key key_pair;
+
+    key_pair.k.key_handle = iak_handle;
+    key_pair.crypto_lib = T_COSE_CRYPTO_LIB_PSA;
+    UsefulBufC signed_cose;
+    UsefulBufC report_body;
+
+    signed_cose.ptr = report;
+    signed_cose.len = report_len;
+
+    t_cose_sign1_verify_init(&verify_ctx, 0);
+    t_cose_sign1_set_verification_key(&verify_ctx, key_pair);
+
+    status = t_cose_sign1_verify(&verify_ctx, signed_cose, &report_body, NULL);
+    LONGS_EQUAL(T_COSE_SUCCESS, status);
+
     /* Check the report contents */
     QCBORDecodeContext decode_ctx;
-    UsefulBufC report_buf;
 
-    report_buf.ptr = report;
-    report_buf.len = report_len;
-
-    QCBORDecode_Init(&decode_ctx, report_buf, QCBOR_DECODE_MODE_NORMAL);
+    QCBORDecode_Init(&decode_ctx, report_body, QCBOR_DECODE_MODE_NORMAL);
     QCBORDecode_EnterMap(&decode_ctx, NULL);
 
     /* Check client id */
@@ -87,8 +111,8 @@
     QCBORDecode_GetInt64InMapN(&decode_ctx,
         EAT_ARM_PSA_CLAIM_ID_CLIENT_ID, &decoded_client_id);
 
-    UNSIGNED_LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
-    UNSIGNED_LONGS_EQUAL(client_id, decoded_client_id);
+    LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
+    LONGS_EQUAL(client_id, decoded_client_id);
 
     /* Check the auth challenge */
     UsefulBufC auth_challenge_buf;
@@ -97,7 +121,7 @@
     QCBORDecode_GetByteStringInMapN(&decode_ctx,
         EAT_ARM_PSA_CLAIM_ID_CHALLENGE, &auth_challenge_buf);
 
-    UNSIGNED_LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
+    LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
     CHECK_TRUE(auth_challenge_buf.ptr);
     UNSIGNED_LONGS_EQUAL(sizeof(auth_challenge), auth_challenge_buf.len);
     MEMCMP_EQUAL(auth_challenge, auth_challenge_buf.ptr, sizeof(auth_challenge));
@@ -105,12 +129,12 @@
     /* Shouldn't expect to see the 'NO_SW_COMPONENTS' claim */
     int64_t no_sw = 0;
     QCBORDecode_GetInt64InMapN(&decode_ctx, EAT_ARM_PSA_CLAIM_ID_NO_SW_COMPONENTS, &no_sw);
-    UNSIGNED_LONGS_EQUAL(QCBOR_ERR_LABEL_NOT_FOUND, QCBORDecode_GetAndResetError(&decode_ctx));
+    LONGS_EQUAL(QCBOR_ERR_LABEL_NOT_FOUND, QCBORDecode_GetAndResetError(&decode_ctx));
     CHECK_FALSE(no_sw);
 
     /* Check the sw components */
     QCBORDecode_EnterArrayFromMapN(&decode_ctx, EAT_ARM_PSA_CLAIM_ID_SW_COMPONENTS);
-    UNSIGNED_LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
+    LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
 
     /* Iterate over all array members */
     size_t sw_component_count = 0;
@@ -129,7 +153,7 @@
             /* Check measurement id */
             QCBORDecode_GetByteStringInMapN(&decode_ctx,
                     EAT_SW_COMPONENT_CLAIM_ID_MEASUREMENT_TYPE, &property);
-            UNSIGNED_LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
+            LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
             CHECK_TRUE(property.ptr);
             CHECK_TRUE(property.len);
             MEMCMP_EQUAL(measurement->id, property.ptr, property.len);
@@ -137,7 +161,7 @@
             /* Check measurement digest */
             QCBORDecode_GetByteStringInMapN(&decode_ctx,
                     EAT_SW_COMPONENT_CLAIM_ID_MEASUREMENT_VALUE, &property);
-            UNSIGNED_LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
+            LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
             CHECK_TRUE(property.ptr);
             CHECK_TRUE(property.len);
             MEMCMP_EQUAL(measurement->digest, property.ptr, property.len);
@@ -153,10 +177,10 @@
     }
 
     QCBORDecode_ExitArray(&decode_ctx);
-    UNSIGNED_LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
+    LONGS_EQUAL(QCBOR_SUCCESS, QCBORDecode_GetError(&decode_ctx));
 
     QCBORError qcbor_error;
     QCBORDecode_ExitMap(&decode_ctx);
     qcbor_error = QCBORDecode_Finish(&decode_ctx);
-    UNSIGNED_LONGS_EQUAL(QCBOR_SUCCESS, qcbor_error);
+    LONGS_EQUAL(QCBOR_SUCCESS, qcbor_error);
 }
diff --git a/components/service/crypto/test/service/crypto_service_scenarios.cpp b/components/service/crypto/test/service/crypto_service_scenarios.cpp
index e20b6be..7056b4a 100644
--- a/components/service/crypto/test/service/crypto_service_scenarios.cpp
+++ b/components/service/crypto/test/service/crypto_service_scenarios.cpp
@@ -215,6 +215,58 @@
     CHECK_EQUAL(PSA_SUCCESS, status);
 }
 
+void crypto_service_scenarios::signAndVerifyEat()
+{
+    /* Sign and verify a hash using EAT key type and algorithm */
+    psa_status_t status;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_id_t key_id;
+
+    psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
+
+    psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
+    psa_set_key_bits(&attributes, 256);
+
+    /* Generate a key */
+    status = m_crypto_client->generate_key(&attributes, &key_id);
+    CHECK_EQUAL(PSA_SUCCESS, status);
+
+    psa_reset_key_attributes(&attributes);
+
+    /* Sign a hash */
+    uint8_t hash[64];
+    uint8_t signature[PSA_SIGNATURE_MAX_SIZE];
+    size_t signature_length;
+
+    memset(hash, 0x71, sizeof(hash));
+
+    status = m_crypto_client->sign_hash(key_id,
+        PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
+        signature, sizeof(signature), &signature_length);
+
+    CHECK_EQUAL(PSA_SUCCESS, status);
+    CHECK(signature_length > 0);
+
+    /* Verify the signature */
+    status = m_crypto_client->verify_hash(key_id,
+        PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
+        signature, signature_length);
+    CHECK_EQUAL(PSA_SUCCESS, status);
+
+    /* Change the hash and expect verify to fail */
+    hash[0] = 0x72;
+    status = m_crypto_client->verify_hash(key_id,
+        PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
+        signature, signature_length);
+    CHECK_EQUAL(PSA_ERROR_INVALID_SIGNATURE, status);
+
+    /* Remove the key */
+    status = m_crypto_client->destroy_key(key_id);
+    CHECK_EQUAL(PSA_SUCCESS, status);
+}
+
 void crypto_service_scenarios::asymEncryptDecrypt()
 {
     psa_status_t status;
diff --git a/components/service/crypto/test/service/crypto_service_scenarios.h b/components/service/crypto/test/service/crypto_service_scenarios.h
index 0e996aa..648baae 100644
--- a/components/service/crypto/test/service/crypto_service_scenarios.h
+++ b/components/service/crypto/test/service/crypto_service_scenarios.h
@@ -21,6 +21,7 @@
     void asymEncryptDecrypt();
     void asymEncryptDecryptWithSalt();
     void signAndVerifyHash();
+    void signAndVerifyEat();
     void exportAndImportKeyPair();
     void exportPublicKey();
     void generatePersistentKeys();
diff --git a/components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp b/components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp
index 5a620b4..9ceb0d5 100644
--- a/components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp
+++ b/components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp
@@ -77,6 +77,11 @@
     m_scenarios->signAndVerifyHash();
 }
 
+TEST(CryptoServicePackedcTests, signAndVerifyEat)
+{
+    m_scenarios->signAndVerifyEat();
+}
+
 TEST(CryptoServicePackedcTests, asymEncryptDecrypt)
 {
     m_scenarios->asymEncryptDecrypt();
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index 8f5610b..075538d 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -47,6 +47,7 @@
 		"components/service/attestation/claims/sources/event_log/mock"
 		"components/service/attestation/claims/sources/event_log/test"
 		"components/service/attestation/reporter/psa"
+		"components/service/attestation/key_mngr"
 		"components/service/attestation/test/component"
 		"components/service/crypto/client/cpp"
 		"components/service/crypto/client/cpp/protobuf"