Add attestation service provider and client

Adds the attestation service provider with a packed-c serializer.  A
client that implements the PSA Attestation C API is also added.  To
allow for service level testing in a PC environment, a standalone
service context has beed added for the attestation service.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I468e8be122472b5cfff4b9a56569a08b193a14e9
diff --git a/components/service/attestation/client/psa/component.cmake b/components/service/attestation/client/psa/component.cmake
new file mode 100644
index 0000000..046c0a5
--- /dev/null
+++ b/components/service/attestation/client/psa/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}/iat_client.c"
+	)
diff --git a/components/service/attestation/client/psa/iat_client.c b/components/service/attestation/client/psa/iat_client.c
new file mode 100644
index 0000000..5c88018
--- /dev/null
+++ b/components/service/attestation/client/psa/iat_client.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include "iat_client.h"
+#include <common/tlv/tlv.h>
+#include <psa/initial_attestation.h>
+#include <protocols/service/attestation/packed-c/get_token.h>
+#include <protocols/service/attestation/packed-c/get_token_size.h>
+#include <protocols/service/attestation/packed-c/opcodes.h>
+#include <protocols/rpc/common/packed-c/status.h>
+
+/**
+ * @brief      The singleton psa_iat_client instance
+ *
+ * The psa attestation C API assumes a single backend service provider.  This
+ * structure defines the state used by the psa_iat_client that communicates
+ * with a remote provider using the provided rpc caller.
+ */
+static struct psa_iat_client
+{
+    struct rpc_caller *caller;
+    int rpc_status;
+} instance;
+
+
+psa_status_t psa_iat_client_init(struct rpc_caller *caller)
+{
+	instance.caller = caller;
+	instance.rpc_status = TS_RPC_CALL_ACCEPTED;
+
+	return PSA_SUCCESS;
+}
+
+void psa_iat_client_deinit(void)
+{
+	instance.caller = NULL;
+}
+
+int psa_iat_client_rpc_status(void)
+{
+	return instance.rpc_status;
+}
+
+psa_status_t psa_initial_attest_get_token(
+	const uint8_t *auth_challenge, size_t challenge_size,
+    uint8_t *token_buf, size_t token_buf_size, size_t *token_size)
+{
+    psa_status_t psa_status = PSA_ERROR_INVALID_ARGUMENT;
+    size_t req_len = tlv_required_space(challenge_size);
+
+    struct tlv_record challenge_record;
+    challenge_record.tag = TS_ATTESTATION_GET_TOKEN_IN_TAG_AUTH_CHALLENGE;
+    challenge_record.length = challenge_size;
+    challenge_record.value = auth_challenge;
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+	*token_size = 0;
+
+    call_handle = rpc_caller_begin(instance.caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+        struct tlv_iterator req_iter;
+
+        tlv_iterator_begin(&req_iter, req_buf, req_len);
+        tlv_encode(&req_iter, &challenge_record);
+
+        instance.rpc_status = rpc_caller_invoke(instance.caller, call_handle,
+            TS_ATTESTATION_OPCODE_GET_TOKEN, &opstatus, &resp_buf, &resp_len);
+
+        if (instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+            psa_status = opstatus;
+
+            if (psa_status == PSA_SUCCESS) {
+
+                struct tlv_const_iterator resp_iter;
+                struct tlv_record decoded_record;
+                tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
+
+                if (tlv_find_decode(&resp_iter,
+						TS_ATTESTATION_GET_TOKEN_OUT_TAG_TOKEN, &decoded_record)) {
+
+                    if (decoded_record.length <= token_buf_size) {
+
+                        memcpy(token_buf, decoded_record.value, decoded_record.length);
+                        *token_size = decoded_record.length;
+                    }
+                    else {
+                        /* Provided buffer is too small */
+                        psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                    }
+                }
+                else {
+                    /* Mandatory response parameter missing */
+                    psa_status = PSA_ERROR_GENERIC_ERROR;
+                }
+			}
+        }
+
+        rpc_caller_end(instance.caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+psa_status_t psa_initial_attest_get_token_size(
+	size_t challenge_size, size_t *token_size)
+{
+    psa_status_t psa_status = PSA_ERROR_INVALID_ARGUMENT;
+    struct ts_attestation_get_token_size_in req_msg;
+    size_t req_len = sizeof(struct ts_attestation_get_token_size_in);
+
+    *token_size = 0;  /* For failure case */
+
+    req_msg.challenge_size = challenge_size;
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(instance.caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+        struct tlv_iterator req_iter;
+
+        memcpy(req_buf, &req_msg, req_len);
+
+        instance.rpc_status = rpc_caller_invoke(instance.caller, call_handle,
+                    TS_ATTESTATION_OPCODE_GET_TOKEN_SIZE, &opstatus, &resp_buf, &resp_len);
+
+        if (instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+            psa_status = opstatus;
+
+            if (psa_status == PSA_SUCCESS) {
+
+				if (resp_len >= sizeof(struct ts_attestation_get_token_size_out)) {
+
+					struct ts_attestation_get_token_size_out resp_msg;
+					memcpy(&resp_msg, resp_buf, sizeof(struct ts_attestation_get_token_size_out));
+					*token_size = resp_msg.token_size;
+				}
+				else {
+					/* Failed to decode response message */
+					psa_status = PSA_ERROR_GENERIC_ERROR;
+				}
+            }
+        }
+
+        rpc_caller_end(instance.caller, call_handle);
+    }
+
+    return psa_status;
+}
diff --git a/components/service/attestation/client/psa/iat_client.h b/components/service/attestation/client/psa/iat_client.h
new file mode 100644
index 0000000..7daeacf
--- /dev/null
+++ b/components/service/attestation/client/psa/iat_client.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IAT_CLIENT_H
+#define PSA_IAT_CLIENT_H
+
+#include <psa/error.h>
+#include <rpc_caller.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief      Initialises the singleton IAT client
+ *
+ * The IAT client provides an implementation of the PSA Attestation API.
+ * This API may be used by client applications to request attestion
+ * tokens.
+ *
+ * @param[in]  rpc_caller RPC caller instance
+ *
+ * @return     A status indicating the success/failure of the operation
+ */
+psa_status_t psa_iat_client_init(struct rpc_caller *caller);
+
+/**
+ * @brief      De-initialises the singleton IAT client
+ *
+ */
+void psa_iat_client_deinit(void);
+
+/**
+ * @brief      Return the most recent RPC status
+ *
+ * May be used to obtain information about an RPC error that resulted
+ * in an API operation failure
+ *
+ * @return     Most recent RPC operation status
+ */
+int psa_iat_client_rpc_status(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IAT_CLIENT_H */
diff --git a/components/service/attestation/include/component.cmake b/components/service/attestation/include/component.cmake
new file mode 100644
index 0000000..00c61bd
--- /dev/null
+++ b/components/service/attestation/include/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# 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_include_directories(${TGT}
+	 PRIVATE
+		"${CMAKE_CURRENT_LIST_DIR}"
+	)
diff --git a/components/service/attestation/include/psa/initial_attestation.h b/components/service/attestation/include/psa/initial_attestation.h
index bc630ee..35a18d0 100644
--- a/components/service/attestation/include/psa/initial_attestation.h
+++ b/components/service/attestation/include/psa/initial_attestation.h
@@ -18,7 +18,6 @@
 #include <limits.h>
 #include <stdint.h>
 #include <stddef.h>
-#include "psa/crypto.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -46,7 +45,7 @@
  * attestation service. Used to configure buffers for services that verify the
  * produced tokens.
  */
-#define PSA_INITIAL_ATTEST_MAX_TOKEN_SIZE (0x400)
+#define PSA_INITIAL_ATTEST_MAX_TOKEN_SIZE   (4096)
 
 /**
  * The list of fixed claims in the initial attestation token is still evolving,
@@ -201,26 +200,6 @@
 psa_initial_attest_get_token_size(size_t  challenge_size,
                                   size_t *token_size);
 
-/**
- * \brief Get the initial attestation public key.
- *
- * \param[out]  public_key        Pointer to the buffer where the public key
- *                                will be stored.
- * \param[in]   key_buf_size      Size of allocated buffer for key, in bytes.
- * \param[out]  public_key_len    Size of public key in bytes.
- * \param[out]  public_key_curve  Type of the elliptic curve which the key
- *                                belongs to.
- *
- * \note Currently only the ECDSA P-256 over SHA-256 algorithm is supported.
- *
- * \return Returns error code as specified in \ref psa_status_t
- */
-psa_status_t
-tfm_initial_attest_get_public_key(uint8_t          *public_key,
-                                  size_t            public_key_buf_size,
-                                  size_t           *public_key_len,
-                                  psa_ecc_family_t *elliptic_curve_type);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/components/service/attestation/key_mngr/attest_key_mngr.c b/components/service/attestation/key_mngr/attest_key_mngr.c
index c871c82..a4d8ec0 100644
--- a/components/service/attestation/key_mngr/attest_key_mngr.c
+++ b/components/service/attestation/key_mngr/attest_key_mngr.c
@@ -8,9 +8,6 @@
 #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.
  */
@@ -55,16 +52,20 @@
     return status;
 }
 
-void attest_key_mngr_init(void)
+void attest_key_mngr_init(psa_key_id_t iak_id)
 {
     instance.is_iak_open = false;
-    instance.iak_id = IAK_KEY_ID;
+    instance.iak_id = iak_id;
     instance.iak_handle = -1;
 }
 
 void attest_key_mngr_deinit(void)
 {
+    if (instance.is_iak_open && !instance.iak_id) {
 
+        psa_destroy_key(instance.iak_handle);
+        instance.is_iak_open = false;
+    }
 }
 
 psa_status_t attest_key_mngr_get_iak_handle(psa_key_handle_t *iak_handle)
@@ -73,20 +74,25 @@
 
     if (!instance.is_iak_open) {
 
-        status = psa_open_key(instance.iak_id, &instance.iak_handle);
+        if (instance.iak_id) {
 
-        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.
+            /* A valid key id has been specified so treat as a persistent key
+             * that will normally already exist.
              */
-            instance.iak_id = 0;
+            status = psa_open_key(instance.iak_id, &instance.iak_handle);
+
+            if (status != PSA_SUCCESS) {
+
+                /* First run and no key has been provisioned */
+                status = generate_iak(instance.iak_id, &instance.iak_handle);
+            }
         }
+        else {
 
-        if (status != PSA_SUCCESS) {
-
-            /* First run and no key has been provisioned */
+            /* An invalid key id has been specified which indicates that a
+             * volatile key should be generated.  This is option is intended
+             * for test purposes only.
+             */
             status = generate_iak(instance.iak_id, &instance.iak_handle);
         }
 
diff --git a/components/service/attestation/key_mngr/attest_key_mngr.h b/components/service/attestation/key_mngr/attest_key_mngr.h
index 982c841..eaf46fc 100644
--- a/components/service/attestation/key_mngr/attest_key_mngr.h
+++ b/components/service/attestation/key_mngr/attest_key_mngr.h
@@ -9,6 +9,9 @@
 
 #include <psa/crypto.h>
 
+/* Key ID for a volatile IAK (for test) */
+#define ATTEST_KEY_MNGR_VOLATILE_IAK            (0)
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -25,8 +28,15 @@
 
 /**
  * \brief Initialize the attest_key_mngr
+ *
+ * Initializes the attest_key_mngr.  The provided key id should
+ * be used as the identifier for the IAK.  If a key ID of zero
+ * is passed, a volatile IAK will be generated.  This is useful
+ * for test purposes.
+ *
+ * \param[in] iak_id    The key id for the IAK
  */
-void attest_key_mngr_init(void);
+void attest_key_mngr_init(psa_key_id_t iak_id);
 
 /**
  * \brief De-initialize the attest_key_mngr
diff --git a/components/service/attestation/provider/attest_provider.c b/components/service/attestation/provider/attest_provider.c
new file mode 100644
index 0000000..1e12717
--- /dev/null
+++ b/components/service/attestation/provider/attest_provider.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <protocols/service/attestation/packed-c/opcodes.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <service/attestation/key_mngr/attest_key_mngr.h>
+#include <service/attestation/reporter/attest_report.h>
+#include <psa/initial_attestation.h>
+#include "attest_provider.h"
+
+/* Service request handlers */
+static rpc_status_t get_token_handler(void *context, struct call_req* req);
+static rpc_status_t get_token_size_handler(void *context, struct call_req* req);
+
+/* Handler mapping table for service */
+static const struct service_handler handler_table[] = {
+    {TS_ATTESTATION_OPCODE_GET_TOKEN,          get_token_handler},
+    {TS_ATTESTATION_OPCODE_GET_TOKEN_SIZE,     get_token_size_handler}
+};
+
+struct rpc_interface *attest_provider_init(struct attest_provider *context, psa_key_id_t iak_id)
+{
+    struct rpc_interface *rpc_interface = NULL;
+
+    if (context) {
+
+        for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
+            context->serializers[encoding] = NULL;
+
+        service_provider_init(&context->base_provider, context,
+                    handler_table, sizeof(handler_table)/sizeof(struct service_handler));
+
+        attest_key_mngr_init(iak_id);
+
+        rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
+    }
+
+    return rpc_interface;
+}
+
+void attest_provider_deinit(struct attest_provider *context)
+{
+    (void)context;
+    attest_key_mngr_deinit();
+}
+
+void attest_provider_register_serializer(struct attest_provider *context,
+                unsigned int encoding, const struct attest_provider_serializer *serializer)
+{
+    if (encoding < TS_RPC_ENCODING_LIMIT)
+        context->serializers[encoding] = serializer;
+}
+
+static const struct attest_provider_serializer *get_attest_serializer(
+                struct attest_provider *context, const struct call_req *req)
+{
+    const struct attest_provider_serializer *serializer = NULL;
+    unsigned int encoding = call_req_get_encoding(req);
+
+    if (encoding < TS_RPC_ENCODING_LIMIT) serializer = context->serializers[encoding];
+
+    return serializer;
+}
+
+static rpc_status_t get_token_handler(void *context, struct call_req* req)
+{
+    struct attest_provider *this_instance = (struct attest_provider*)context;
+    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+
+    uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64];
+    size_t challenge_len = sizeof(challenge);
+
+    struct call_param_buf *req_buf = call_req_get_req_buf(req);
+    const struct attest_provider_serializer *serializer = get_attest_serializer(this_instance, req);
+
+    if (serializer)
+        rpc_status = serializer->deserialize_get_token_req(req_buf, challenge, &challenge_len);
+
+    if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+        psa_key_handle_t iak_handle;
+        int opstatus = attest_key_mngr_get_iak_handle(&iak_handle);
+
+        if (opstatus == PSA_SUCCESS) {
+
+            const uint8_t *token = NULL;
+            size_t token_size = 0;
+
+            opstatus = attest_report_create(iak_handle,
+                (int32_t)call_req_get_caller_id(req),
+                challenge, challenge_len,
+                &token, &token_size);
+
+            if (opstatus == PSA_SUCCESS) {
+
+                struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+                rpc_status = serializer->serialize_get_token_resp(resp_buf, token, token_size);
+            }
+
+            attest_report_destroy(token);
+        }
+
+        call_req_set_opstatus(req, opstatus);
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t get_token_size_handler(void *context, struct call_req* req)
+{
+    struct attest_provider *this_instance = (struct attest_provider*)context;
+    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+
+    uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64];
+    size_t challenge_len = sizeof(challenge);
+
+    struct call_param_buf *req_buf = call_req_get_req_buf(req);
+    const struct attest_provider_serializer *serializer = get_attest_serializer(this_instance, req);
+
+    memset(challenge, 0, sizeof(challenge));
+
+    if (serializer)
+        rpc_status = serializer->deserialize_get_token_size_req(req_buf, &challenge_len);
+
+    if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+        psa_key_handle_t iak_handle;
+        int opstatus = attest_key_mngr_get_iak_handle(&iak_handle);
+
+        if (opstatus == PSA_SUCCESS) {
+
+            const uint8_t *token = NULL;
+            size_t token_size = 0;
+
+            opstatus = attest_report_create(iak_handle,
+                (int32_t)call_req_get_caller_id(req),
+                challenge, challenge_len,
+                &token, &token_size);
+
+            if (opstatus == PSA_SUCCESS) {
+
+                struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+                rpc_status = serializer->serialize_get_token_size_resp(resp_buf, token_size);
+            }
+
+            attest_report_destroy(token);
+        }
+
+        call_req_set_opstatus(req, opstatus);
+    }
+
+    return rpc_status;
+}
diff --git a/components/service/attestation/provider/attest_provider.h b/components/service/attestation/provider/attest_provider.h
new file mode 100644
index 0000000..ed3b59a
--- /dev/null
+++ b/components/service/attestation/provider/attest_provider.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ATTEST_PROVIDER_H
+#define ATTEST_PROVIDER_H
+
+#include <rpc/common/endpoint/rpc_interface.h>
+#include <rpc_caller.h>
+#include <service/common/provider/service_provider.h>
+#include <service/attestation/provider/serializer/attest_provider_serializer.h>
+#include <service/attestation/key_mngr/attest_key_mngr.h>
+#include <protocols/rpc/common/packed-c/encoding.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The attest_provider is a service provider that implements an RPC interface
+ * for an instance of the attestation service.
+ */
+struct attest_provider
+{
+    struct service_provider base_provider;
+    const struct attest_provider_serializer *serializers[TS_RPC_ENCODING_LIMIT];
+};
+
+/**
+ * \brief Initialize an instance of the service provider
+ *
+ * Initializes a an attestation service provider.  Returns an rpc_interface
+ * that should be associated with a suitable rpc endpoint.
+ *
+ * \param[in] context   The instance to initialize
+ * \param[in] iak_id    The key ID for the IAK
+ *
+ * \return An rpc_interface or NULL on failure
+ */
+struct rpc_interface *attest_provider_init(struct attest_provider *context,
+    psa_key_id_t iak_id);
+
+/**
+ * \brief Cleans up when the instance is no longer needed
+ *
+ * \param[in] context   The instance to de-initialize
+ */
+void attest_provider_deinit(struct attest_provider *context);
+
+/**
+ * \brief Register a protocol serializer
+ *
+ * \param[in] context     The instance
+ * \param[in] encoding    Serialization encoding e.g. packed-c
+ * \param[in] serializer  A concrete serializer
+ */
+void attest_provider_register_serializer(struct attest_provider *context,
+    unsigned int encoding, const struct attest_provider_serializer *serializer);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ATTEST_PROVIDER_H */
diff --git a/components/service/attestation/provider/component.cmake b/components/service/attestation/provider/component.cmake
new file mode 100644
index 0000000..cd30f53
--- /dev/null
+++ b/components/service/attestation/provider/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_provider.c"
+	)
diff --git a/components/service/attestation/provider/serializer/attest_provider_serializer.h b/components/service/attestation/provider/serializer/attest_provider_serializer.h
new file mode 100644
index 0000000..5334cba
--- /dev/null
+++ b/components/service/attestation/provider/serializer/attest_provider_serializer.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ATTEST_PROVIDER_SERIALIZER_H
+#define ATTEST_PROVIDER_SERIALIZER_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <rpc/common/endpoint/rpc_interface.h>
+
+/* Provides a common interface for parameter serialization operations
+ * for the attestation service provider.  Allows alternative serialization
+ * protocols to be used without hard-wiring a particular protocol
+ * into the service provider code.  A concrete serializer must
+ * implement this interface.
+ */
+struct attest_provider_serializer {
+
+    /* Operation: get_token */
+    rpc_status_t (*deserialize_get_token_req)(const struct call_param_buf *req_buf,
+        uint8_t *auth_challenge, size_t *auth_challenge_len);
+
+    rpc_status_t (*serialize_get_token_resp)(struct call_param_buf *resp_buf,
+        const uint8_t *token,
+        size_t token_size);
+
+    /* Operation: get_token_size */
+    rpc_status_t (*deserialize_get_token_size_req)(const struct call_param_buf *req_buf,
+        size_t *auth_challenge_len);
+
+    rpc_status_t (*serialize_get_token_size_resp)(struct call_param_buf *resp_buf,
+        size_t token_size);
+};
+
+#endif /* ATTEST_PROVIDER_SERIALIZER_H */
diff --git a/components/service/attestation/provider/serializer/packed-c/component.cmake b/components/service/attestation/provider/serializer/packed-c/component.cmake
new file mode 100644
index 0000000..7231a18
--- /dev/null
+++ b/components/service/attestation/provider/serializer/packed-c/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}/packedc_attest_provider_serializer.c"
+	)
diff --git a/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.c b/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.c
new file mode 100644
index 0000000..c2e5d56
--- /dev/null
+++ b/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <string.h>
+#include <common/tlv/tlv.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/attestation/packed-c/get_token.h>
+#include <protocols/service/attestation/packed-c/get_token_size.h>
+#include "packedc_attest_provider_serializer.h"
+
+
+/* Operation: get_token */
+static rpc_status_t deserialize_get_token_req(const struct call_param_buf *req_buf,
+    uint8_t *auth_challenge, size_t *auth_challenge_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct tlv_const_iterator req_iter;
+    struct tlv_record decoded_record;
+
+    tlv_const_iterator_begin(&req_iter, (uint8_t*)req_buf->data, req_buf->data_len);
+
+    if (tlv_find_decode(&req_iter,
+        TS_ATTESTATION_GET_TOKEN_IN_TAG_AUTH_CHALLENGE, &decoded_record)) {
+
+        if (decoded_record.length <= *auth_challenge_len) {
+
+            memcpy(auth_challenge, decoded_record.value, decoded_record.length);
+            *auth_challenge_len = decoded_record.length;
+            rpc_status = TS_RPC_CALL_ACCEPTED;
+        }
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_get_token_resp(struct call_param_buf *resp_buf,
+    const uint8_t *token, size_t token_size)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct tlv_iterator resp_iter;
+
+    struct tlv_record token_record;
+    token_record.tag = TS_ATTESTATION_GET_TOKEN_OUT_TAG_TOKEN;
+    token_record.length = token_size;
+    token_record.value = token;
+
+    tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+
+    if (tlv_encode(&resp_iter, &token_record)) {
+
+        resp_buf->data_len = tlv_required_space(token_size);
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Operation: get_token_size */
+static rpc_status_t deserialize_get_token_size_req(const struct call_param_buf *req_buf,
+    size_t *auth_challenge_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_attestation_get_token_size_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_attestation_get_token_size_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+        *auth_challenge_len = recv_msg.challenge_size;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_get_token_size_resp(struct call_param_buf *resp_buf,
+    size_t token_size)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct ts_attestation_get_token_size_out resp_msg;
+    size_t fixed_len = sizeof(struct ts_attestation_get_token_size_out);
+
+    resp_msg.token_size = token_size;
+
+    if (fixed_len <= resp_buf->size) {
+
+        memcpy(resp_buf->data, &resp_msg, fixed_len);
+        resp_buf->data_len = fixed_len;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Singleton method to provide access to the serializer instance */
+const struct attest_provider_serializer *packedc_attest_provider_serializer_instance(void)
+{
+    static const struct attest_provider_serializer instance = {
+        deserialize_get_token_req,
+        serialize_get_token_resp,
+        deserialize_get_token_size_req,
+        serialize_get_token_size_resp
+    };
+
+    return &instance;
+}
diff --git a/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h b/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h
new file mode 100644
index 0000000..b73adf8
--- /dev/null
+++ b/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_ATTEST_PROVIDER_SERIALIZER_H
+#define PACKEDC_ATTEST_PROVIDER_SERIALIZER_H
+
+#include <service/attestation/provider/serializer/attest_provider_serializer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Singleton method to provide access to the packed-c serializer
+ * for the attestation service provider.
+ */
+const struct attest_provider_serializer *packedc_attest_provider_serializer_instance(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PACKEDC_ATTEST_PROVIDER_SERIALIZER_H */
diff --git a/components/service/attestation/reporter/psa/psa_attest_report.c b/components/service/attestation/reporter/psa/psa_attest_report.c
index 3228f1c..1f4ed0e 100644
--- a/components/service/attestation/reporter/psa/psa_attest_report.c
+++ b/components/service/attestation/reporter/psa/psa_attest_report.c
@@ -12,7 +12,9 @@
  */
 
 #include <stdlib.h>
+#include <stdbool.h>
 #include <psa/error.h>
+#include <psa/initial_attestation.h>
 #include <service/attestation/reporter/attest_report.h>
 #include <service/attestation/claims/claims_register.h>
 #include "eat_serializer.h"
@@ -22,6 +24,7 @@
 #define MAX_DEVICE_CLAIMS       (50)
 #define MAX_SW_CLAIMS           (50)
 
+static bool validate_challenge(size_t len);
 static void add_auth_challenge_claim(struct claim_vector *v, const uint8_t *data, size_t len);
 static void add_client_id_claim(struct claim_vector *v, int32_t client_id);
 static void add_no_sw_claim(struct claim_vector *v);
@@ -38,6 +41,8 @@
     *report = NULL;
     *report_len = 0;
 
+    if (!validate_challenge(auth_challenge_len)) return PSA_ERROR_INVALID_ARGUMENT;
+
     claim_vector_init(&device_claims, MAX_DEVICE_CLAIMS);
     claim_vector_init(&sw_claims, MAX_SW_CLAIMS);
 
@@ -78,6 +83,15 @@
     free((void*)report);
 }
 
+static bool validate_challenge(size_t len)
+{
+    /* Only allow specific challenge lengths */
+    return
+        (len == PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32) ||
+        (len == PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48) ||
+        (len == PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64);
+}
+
 static void add_auth_challenge_claim(struct claim_vector *v, const uint8_t *data, size_t len)
 {
     struct claim claim;
diff --git a/components/service/attestation/test/common/component.cmake b/components/service/attestation/test/common/component.cmake
new file mode 100644
index 0000000..5985c76
--- /dev/null
+++ b/components/service/attestation/test/common/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}/report_dump.cpp"
+	)
diff --git a/components/service/attestation/test/component/report_dump.cpp b/components/service/attestation/test/common/report_dump.cpp
similarity index 100%
rename from components/service/attestation/test/component/report_dump.cpp
rename to components/service/attestation/test/common/report_dump.cpp
diff --git a/components/service/attestation/test/component/report_dump.h b/components/service/attestation/test/common/report_dump.h
similarity index 100%
rename from components/service/attestation/test/component/report_dump.h
rename to components/service/attestation/test/common/report_dump.h
diff --git a/components/service/attestation/test/component/attestation_reporter_tests.cpp b/components/service/attestation/test/component/attestation_reporter_tests.cpp
index 02b91ac..c83dc3c 100644
--- a/components/service/attestation/test/component/attestation_reporter_tests.cpp
+++ b/components/service/attestation/test/component/attestation_reporter_tests.cpp
@@ -13,10 +13,10 @@
 #include <service/attestation/claims/sources/preloaded/preloaded_claim_source.h>
 #include <service/attestation/reporter/attest_report.h>
 #include <service/attestation/key_mngr/attest_key_mngr.h>
+#include <service/attestation/test/common/report_dump.h>
 #include <protocols/service/attestation/packed-c/eat.h>
 #include <CppUTest/TestHarness.h>
 #include <psa/crypto.h>
-#include "report_dump.h"
 
 TEST_GROUP(AttestationReporterTests)
 {
@@ -28,7 +28,7 @@
         report_len;
 
         psa_crypto_init();
-        attest_key_mngr_init();
+        attest_key_mngr_init(ATTEST_KEY_MNGR_VOLATILE_IAK);
 
         /* The set of registered claim_sources determines the content
          * of a generated attestation source.  The set and type of
diff --git a/components/service/attestation/test/component/component.cmake b/components/service/attestation/test/component/component.cmake
index 9db9a97..3bd7e56 100644
--- a/components/service/attestation/test/component/component.cmake
+++ b/components/service/attestation/test/component/component.cmake
@@ -10,5 +10,4 @@
 
 target_sources(${TGT} PRIVATE
 	"${CMAKE_CURRENT_LIST_DIR}/attestation_reporter_tests.cpp"
-	"${CMAKE_CURRENT_LIST_DIR}/report_dump.cpp"
 	)
diff --git a/components/service/attestation/test/service/attestation_service_tests.cpp b/components/service/attestation/test/service/attestation_service_tests.cpp
new file mode 100644
index 0000000..9fe1f4d
--- /dev/null
+++ b/components/service/attestation/test/service/attestation_service_tests.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <limits.h>
+#include <string.h>
+#include <service/attestation/client/psa/iat_client.h>
+#include <protocols/rpc/common/packed-c/encoding.h>
+#include <service_locator.h>
+#include <psa/initial_attestation.h>
+#include <CppUTest/TestHarness.h>
+
+/*
+ * Service-level tests for the attestation service.
+ */
+TEST_GROUP(AttestationServiceTests)
+{
+    void setup()
+    {
+        struct rpc_caller *caller;
+        int status;
+
+        m_rpc_session_handle = NULL;
+        m_attest_service_context = NULL;
+
+        service_locator_init();
+
+        m_attest_service_context =
+            service_locator_query("sn:trustedfirmware.org:attestation:0", &status);
+        CHECK_TRUE(m_attest_service_context);
+
+        m_rpc_session_handle =
+            service_context_open(m_attest_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
+        CHECK_TRUE(m_rpc_session_handle);
+
+        psa_iat_client_init(caller);
+    }
+
+    void teardown()
+    {
+        psa_iat_client_deinit();
+
+        service_context_close(m_attest_service_context, m_rpc_session_handle);
+        m_rpc_session_handle = NULL;
+
+        service_context_relinquish(m_attest_service_context);
+        m_attest_service_context = NULL;
+    }
+
+    rpc_session_handle m_rpc_session_handle;
+    struct service_context *m_attest_service_context;
+};
+
+TEST(AttestationServiceTests, checkTokenSize)
+{
+    uint8_t token_buf[PSA_INITIAL_ATTEST_MAX_TOKEN_SIZE];
+    uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64];
+
+    memset(challenge, 0x87, sizeof(challenge));
+
+    /* Check that the get_token_size operation returns the same size
+     * as theh get_token operation.
+     */
+    psa_status_t status;
+    size_t reported_token_size = 0;
+    size_t actual_token_size = 0;
+
+    status = psa_initial_attest_get_token_size(
+        sizeof(challenge),
+        &reported_token_size);
+
+    LONGS_EQUAL(PSA_SUCCESS, status);
+    CHECK_TRUE(reported_token_size);
+
+    status = psa_initial_attest_get_token(
+        challenge, sizeof(challenge),
+        token_buf, sizeof(token_buf),
+        &actual_token_size);
+
+    LONGS_EQUAL(PSA_SUCCESS, status);
+    UNSIGNED_LONGS_EQUAL(reported_token_size, actual_token_size);
+}
+
+TEST(AttestationServiceTests, invalidChallengeLen)
+{
+    uint8_t token_buf[PSA_INITIAL_ATTEST_MAX_TOKEN_SIZE];
+    uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64];
+
+    memset(challenge, 0x87, sizeof(challenge));
+
+    /* Check that invalid challenge lengths are rejected cleanly */
+    psa_status_t status;
+    size_t challenge_len;
+    size_t token_size = 0;
+
+    /* Zero length challenge */
+    challenge_len = 0;
+    status = psa_initial_attest_get_token_size(
+        challenge_len,
+        &token_size);
+    LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
+
+    status = psa_initial_attest_get_token(
+        challenge, challenge_len,
+        token_buf, sizeof(token_buf),
+        &token_size);
+    LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
+
+    /* Extra large challenge */
+    challenge_len = UINT32_MAX;
+    status = psa_initial_attest_get_token_size(
+        challenge_len,
+        &token_size);
+    LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
+
+    status = psa_initial_attest_get_token(
+        challenge, challenge_len,
+        token_buf, sizeof(token_buf),
+        &token_size);
+    LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
+
+    /* Slightly large challenge */
+    challenge_len = PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64 + 1;
+    status = psa_initial_attest_get_token_size(
+        challenge_len,
+        &token_size);
+    LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
+
+    status = psa_initial_attest_get_token(
+        challenge, challenge_len,
+        token_buf, sizeof(token_buf),
+        &token_size);
+    LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
+}
+
+TEST(AttestationServiceTests, repeatedOperation)
+{
+    uint8_t token_buf[PSA_INITIAL_ATTEST_MAX_TOKEN_SIZE];
+    uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48];
+
+    memset(challenge, 0x61, sizeof(challenge));
+
+    /* Check reports can be requested repeatedly without
+     * resource exhausation due to a memory leak.
+     */
+    for (int i = 0; i < 100; ++i) {
+
+        psa_status_t status;
+        size_t reported_token_size = 0;
+        size_t actual_token_size = 0;
+
+        status = psa_initial_attest_get_token_size(
+            sizeof(challenge),
+            &reported_token_size);
+
+        LONGS_EQUAL(PSA_SUCCESS, status);
+        CHECK_TRUE(reported_token_size);
+
+        status = psa_initial_attest_get_token(
+            challenge, sizeof(challenge),
+            token_buf, sizeof(token_buf),
+            &actual_token_size);
+
+        LONGS_EQUAL(PSA_SUCCESS, status);
+        UNSIGNED_LONGS_EQUAL(reported_token_size, actual_token_size);
+    }
+}
diff --git a/components/service/attestation/test/service/component.cmake b/components/service/attestation/test/service/component.cmake
new file mode 100644
index 0000000..a07e402
--- /dev/null
+++ b/components/service/attestation/test/service/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}/attestation_service_tests.cpp"
+	)
diff --git a/components/service/locator/standalone/services/attestation/attestation_service_context.cpp b/components/service/locator/standalone/services/attestation/attestation_service_context.cpp
new file mode 100644
index 0000000..302a536
--- /dev/null
+++ b/components/service/locator/standalone/services/attestation/attestation_service_context.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "attestation_service_context.h"
+#include <service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.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>
+
+attestation_service_context::attestation_service_context(const char *sn) :
+    standalone_service_context(sn),
+    m_attest_provider(),
+    m_event_log_claim_source()
+{
+
+}
+
+attestation_service_context::~attestation_service_context()
+{
+
+}
+
+void attestation_service_context::do_init()
+{
+    struct claim_source *claim_source;
+
+    /**
+     * Initialize and register claims sources to define the view of
+     * the device reflected by the attestation service.  On a real
+     * device, the set of claim sources will be deployment specific
+     * to accommodate specific device architecture and product
+     * variations.
+     */
+    claims_register_init();
+
+    /* Boot measurement source - uses mock event log */
+    claim_source = event_log_claim_source_init(&m_event_log_claim_source,
+        mock_event_log_start(), mock_event_log_size());
+    claims_register_add_claim_source(CLAIM_CATEGORY_BOOT_MEASUREMENT, claim_source);
+
+    /* Initialize the attestation service provider */
+    struct rpc_interface *attest_ep =
+        attest_provider_init(&m_attest_provider, ATTEST_KEY_MNGR_VOLATILE_IAK);
+
+    attest_provider_register_serializer(&m_attest_provider,
+        TS_RPC_ENCODING_PACKED_C, packedc_attest_provider_serializer_instance());
+
+    standalone_service_context::set_rpc_interface(attest_ep);
+}
+
+void attestation_service_context::do_deinit()
+{
+    attest_provider_deinit(&m_attest_provider);
+    claims_register_deinit();
+}
diff --git a/components/service/locator/standalone/services/attestation/attestation_service_context.h b/components/service/locator/standalone/services/attestation/attestation_service_context.h
new file mode 100644
index 0000000..ad8d0ee
--- /dev/null
+++ b/components/service/locator/standalone/services/attestation/attestation_service_context.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STANDALONE_ATTESTATION_SERVICE_CONTEXT_H
+#define STANDALONE_ATTESTATION_SERVICE_CONTEXT_H
+
+#include <service/locator/standalone/standalone_service_context.h>
+#include <rpc/direct/direct_caller.h>
+#include <service/attestation/provider/attest_provider.h>
+#include <service/attestation/claims/sources/event_log/event_log_claim_source.h>
+
+
+class attestation_service_context : public standalone_service_context
+{
+public:
+    attestation_service_context(const char *sn);
+    virtual ~attestation_service_context();
+
+private:
+
+    void do_init();
+    void do_deinit();
+
+    struct attest_provider m_attest_provider;
+    struct event_log_claim_source m_event_log_claim_source;
+};
+
+#endif /* STANDALONE_ATTESTATION_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/standalone/services/attestation/component.cmake b/components/service/locator/standalone/services/attestation/component.cmake
new file mode 100644
index 0000000..41fc031
--- /dev/null
+++ b/components/service/locator/standalone/services/attestation/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}/attestation_service_context.cpp"
+	)
diff --git a/components/service/locator/standalone/standalone_env.cpp b/components/service/locator/standalone/standalone_env.cpp
index 132b6d5..ab1a1be 100644
--- a/components/service/locator/standalone/standalone_env.cpp
+++ b/components/service/locator/standalone/standalone_env.cpp
@@ -9,6 +9,7 @@
 #include <service/locator/standalone/services/internal-trusted-storage/its_service_context.h>
 #include <service/locator/standalone/services/protected-storage/ps_service_context.h>
 #include <service/locator/standalone/services/test-runner/test_runner_service_context.h>
+#include <service/locator/standalone/services/attestation/attestation_service_context.h>
 #include "standalone_location_strategy.h"
 #include "standalone_service_registry.h"
 
@@ -26,5 +27,8 @@
     static test_runner_service_context test_runner_context("sn:trustedfirmware.org:test-runner:0");
     standalone_service_registry::instance()->regsiter_service_instance(&test_runner_context);
 
+    static attestation_service_context attestation_context("sn:trustedfirmware.org:attestation:0");
+    standalone_service_registry::instance()->regsiter_service_instance(&attestation_context);
+
     service_locator_register_strategy(standalone_location_strategy());
 }
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index 075538d..bb52dd5 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -41,6 +41,8 @@
 		"components/service/locator/standalone/services/internal-trusted-storage"
 		"components/service/locator/standalone/services/protected-storage"
 		"components/service/locator/standalone/services/test-runner"
+		"components/service/locator/standalone/services/attestation"
+		"components/service/attestation/include"
 		"components/service/attestation/claims"
 		"components/service/attestation/claims/sources/preloaded"
 		"components/service/attestation/claims/sources/event_log"
@@ -48,7 +50,12 @@
 		"components/service/attestation/claims/sources/event_log/test"
 		"components/service/attestation/reporter/psa"
 		"components/service/attestation/key_mngr"
+		"components/service/attestation/provider"
+		"components/service/attestation/provider/serializer/packed-c"
+		"components/service/attestation/client/psa"
+		"components/service/attestation/test/common"
 		"components/service/attestation/test/component"
+		"components/service/attestation/test/service"
 		"components/service/crypto/client/cpp"
 		"components/service/crypto/client/cpp/protobuf"
 		"components/service/crypto/client/cpp/packed-c"
diff --git a/deployments/libts/linux-pc/CMakeLists.txt b/deployments/libts/linux-pc/CMakeLists.txt
index f6ac33d..d1a96ae 100644
--- a/deployments/libts/linux-pc/CMakeLists.txt
+++ b/deployments/libts/linux-pc/CMakeLists.txt
@@ -31,6 +31,7 @@
 	COMPONENTS
 		"components/rpc/direct"
 		"components/common/tlv"
+		"components/common/endian"
 		"components/service/common/include"
 		"components/service/common/serializer/protobuf"
 		"components/service/common/provider"
@@ -39,6 +40,16 @@
 		"components/service/locator/standalone/services/internal-trusted-storage"
 		"components/service/locator/standalone/services/protected-storage"
 		"components/service/locator/standalone/services/test-runner"
+		"components/service/locator/standalone/services/attestation"
+		"components/service/attestation/include"
+		"components/service/attestation/claims"
+		"components/service/attestation/claims/sources/preloaded"
+		"components/service/attestation/claims/sources/event_log"
+		"components/service/attestation/claims/sources/event_log/mock"
+		"components/service/attestation/reporter/psa"
+		"components/service/attestation/key_mngr"
+		"components/service/attestation/provider"
+		"components/service/attestation/provider/serializer/packed-c"
 		"components/service/crypto/provider/mbedcrypto"
 		"components/service/crypto/provider/mbedcrypto/trng_adapter/linux"
 		"components/service/crypto/provider/serializer/protobuf"
@@ -80,6 +91,14 @@
 include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
 target_link_libraries(ts PRIVATE mbedcrypto)
 
+# Qcbor
+include(${TS_ROOT}/external/qcbor/qcbor.cmake)
+target_link_libraries(ts PRIVATE qcbor)
+
+# t_cose
+include(${TS_ROOT}/external/t_cose/t_cose.cmake)
+target_link_libraries(ts PRIVATE t_cose)
+
 #-------------------------------------------------------------------------------
 #  Test executable (libts-test) for testing libts static library
 #
diff --git a/deployments/ts-service-test/linux-pc/CMakeLists.txt b/deployments/ts-service-test/linux-pc/CMakeLists.txt
index 4a86c87..ac4c237 100644
--- a/deployments/ts-service-test/linux-pc/CMakeLists.txt
+++ b/deployments/ts-service-test/linux-pc/CMakeLists.txt
@@ -80,6 +80,9 @@
     COMPONENTS
         "components/service/test_runner/client/cpp"
 		"components/service/test_runner/test/service"
+		"components/service/attestation/include"
+		"components/service/attestation/client/psa"
+		"components/service/attestation/test/service"
 )
 
 #-------------------------------------------------------------------------------