Attest: Add initial attestation prototype

Details:
 - implement initial version of API
 - implement veneer function and SVC handler
 - implement wrapper functions around veneers on S and NS side
 - create manifest files and generate new partition defines
 - add attestation service to build system
 - update linker scripts for ARMCLANG and GNUARM

Change-Id: I987509c6cad08fcd082667bca7dbc9a328ea03de
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/secure_fw/CMakeLists.txt b/secure_fw/CMakeLists.txt
index 9008f07..7bd047e 100644
--- a/secure_fw/CMakeLists.txt
+++ b/secure_fw/CMakeLists.txt
@@ -136,6 +136,7 @@
 	add_dependencies(${EXE_NAME} tfm_audit)
 	add_dependencies(${EXE_NAME} tfm_platform)
 	add_dependencies(${EXE_NAME} tfm_secure_tests)
+	add_dependencies(${EXE_NAME} tfm_attest)
 
 	#Set macro definitions for the project.
 	embedded_set_target_compile_defines(TARGET ${PROJECT_OBJ_LIB} LANGUAGE C DEFINES __thumb2__ __ARM_FEATURE_CMSE=3 TFM_LVL=${TFM_LVL} DAUTH_CHIP_DEFAULT APPEND)
@@ -144,14 +145,14 @@
 		#The test service veneers may not be referenced in the secure binary so the
 		#veneer objects are explicitly loaded from the secure tests library.
 		if(${COMPILER} STREQUAL "ARMCLANG")
-			target_link_libraries(${EXE_NAME} tfm_crypto tfm_storage tfm_audit tfm_platform $<TARGET_LINKER_FILE:tfm_secure_tests>\(*veneers.o\) tfm_secure_tests)
+			target_link_libraries(${EXE_NAME} tfm_crypto tfm_storage tfm_audit tfm_platform tfm_attest $<TARGET_LINKER_FILE:tfm_secure_tests>\(*veneers.o\) tfm_secure_tests)
 		elseif(${COMPILER} STREQUAL "GNUARM")
-			target_link_libraries(${EXE_NAME} tfm_secure_tests tfm_crypto tfm_storage tfm_audit tfm_platform)
+			target_link_libraries(${EXE_NAME} tfm_secure_tests tfm_crypto tfm_storage tfm_audit tfm_platform tfm_attest)
 		else()
 			message(FATAL_ERROR "unknown compiler" )
 		endif()
 	else()
-		target_link_libraries(${EXE_NAME} tfm_crypto tfm_storage tfm_audit tfm_platform)
+		target_link_libraries(${EXE_NAME} tfm_crypto tfm_storage tfm_audit tfm_platform tfm_attest)
 	endif()
 
 
@@ -261,6 +262,9 @@
 #Add the platform service library target
 add_subdirectory(${SECURE_FW_DIR}/services/platform)
 
+#Add the initial attestation service library target
+add_subdirectory(${SECURE_FW_DIR}/services/initial_attestation)
+
 if (LINK_TO_BOTH_MEMORY_REGION)
 	#Link to primary memory region
 	set_up_secure_fw_build(S_TARGET      ${PROJECT_NAME}
diff --git a/secure_fw/ns_callable/CMakeLists.inc b/secure_fw/ns_callable/CMakeLists.inc
index afba7d5..8b883db 100644
--- a/secure_fw/ns_callable/CMakeLists.inc
+++ b/secure_fw/ns_callable/CMakeLists.inc
@@ -26,7 +26,8 @@
 set (SS_NS_CALLABLE_C_SRC "${CMAKE_CURRENT_LIST_DIR}/tfm_sst_veneers.c"
                           "${CMAKE_CURRENT_LIST_DIR}/tfm_audit_veneers.c"
                           "${CMAKE_CURRENT_LIST_DIR}/tfm_crypto_veneers.c"
-                          "${CMAKE_CURRENT_LIST_DIR}/tfm_platform_veneers.c")
+                          "${CMAKE_CURRENT_LIST_DIR}/tfm_platform_veneers.c"
+                          "${CMAKE_CURRENT_LIST_DIR}/tfm_initial_attestation_veneers.c")
 
 #Append all our source files to global lists.
 list(APPEND ALL_SRC_C ${SS_NS_CALLABLE_C_SRC})
diff --git a/secure_fw/ns_callable/tfm_initial_attestation_veneers.c b/secure_fw/ns_callable/tfm_initial_attestation_veneers.c
new file mode 100644
index 0000000..df154d4
--- /dev/null
+++ b/secure_fw/ns_callable/tfm_initial_attestation_veneers.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_initial_attestation_veneers.h"
+#include "secure_fw/services/initial_attestation/attestation.h"
+#include "tfm_secure_api.h"
+#include "tfm_api.h"
+#include "spm_partition_defs.h"
+#include "psa_client.h"
+
+__tfm_secure_gateway_attributes__
+enum psa_attest_err_t
+tfm_attest_veneer_get_token(const psa_invec  *in_vec,  uint32_t num_invec,
+                                  psa_outvec *out_vec, uint32_t num_outvec)
+{
+    TFM_CORE_SFN_REQUEST(TFM_SP_INITIAL_ATTESTATION_ID,
+                         initial_attest_get_token,
+                         in_vec,  num_invec,
+                         out_vec, num_outvec);
+}
diff --git a/secure_fw/services/initial_attestation/CMakeLists.inc b/secure_fw/services/initial_attestation/CMakeLists.inc
new file mode 100644
index 0000000..7bc1f2a
--- /dev/null
+++ b/secure_fw/services/initial_attestation/CMakeLists.inc
@@ -0,0 +1,69 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#Definitions to compile the "initial_attestation" module.
+#This file assumes it will be included from a project specific cmakefile, and
+#will not create a library or executable.
+#Inputs:
+#	MBEDTLS_INSTALL_DIR - directory where mbedtls headers and libraries can be found.
+#	TFM_ROOT_DIR        - root directory of the TF-M repository.
+#Outputs:
+#	Will modify include directories to make the source compile.
+#	ALL_SRC_C: C source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command.
+#	ALL_SRC_CXX: C++ source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command.
+#	ALL_SRC_ASM: assembly source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command.
+#	Include directories will be modified by using the include_directories() commands as needed.
+
+#Get the current directory where this file is located.
+set(INITIAL_ATTESTATION_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+#Check input variables
+if (NOT DEFINED ENABLE_INITIAL_ATTESTATION)
+	message(FATAL_ERROR "Incomplete build configuration: ENABLE_INITIAL_ATTESTATION is undefined. ")
+endif()
+
+if (ENABLE_INITIAL_ATTESTATION)
+	if (NOT DEFINED TFM_ROOT_DIR)
+		message(FATAL_ERROR "Please set TFM_ROOT_DIR before including this file.")
+	endif()
+
+	#Append all our source files to global lists.
+	list(APPEND ALL_SRC_C
+		"${INITIAL_ATTESTATION_DIR}/tfm_attestation_secure_api.c"
+		"${INITIAL_ATTESTATION_DIR}/attestation_core.c"
+		)
+
+	#Setting include directories
+	embedded_include_directories(PATH ${TFM_ROOT_DIR} ABSOLUTE)
+	embedded_include_directories(PATH ${TFM_ROOT_DIR}/interface/include ABSOLUTE)
+	embedded_include_directories(PATH ${TFM_ROOT_DIR}/platform/ext/common ABSOLUTE)
+
+	set(BUILD_CMSIS_CORE Off)
+	set(BUILD_RETARGET Off)
+	set(BUILD_NATIVE_DRIVERS Off)
+	set(BUILD_STARTUP Off)
+	set(BUILD_TARGET_CFG Off)
+	set(BUILD_TARGET_HARDWARE_KEYS Off)
+	set(BUILD_TARGET_NV_COUNTERS Off)
+	set(BUILD_CMSIS_DRIVERS Off)
+	set(BUILD_TIME Off)
+	set(BUILD_UART_STDOUT Off)
+	set(BUILD_FLASH Off)
+	set(BUILD_BOOT_SEED On)
+	set(BUILD_DEVICE_ID On)
+	if(NOT DEFINED PLATFORM_CMAKE_FILE)
+		message (FATAL_ERROR "Platform specific CMake is not defined. Please set PLATFORM_CMAKE_FILE.")
+	elseif(NOT EXISTS ${PLATFORM_CMAKE_FILE})
+		message (FATAL_ERROR "Platform specific CMake \"${PLATFORM_CMAKE_FILE}\" file does not exist. Please fix value of PLATFORM_CMAKE_FILE.")
+	else()
+		include(${PLATFORM_CMAKE_FILE})
+	endif()
+
+else()
+	message(FATAL_ERROR "Build system currently doesn't support selectively disabling of a service.")
+endif()
+
diff --git a/secure_fw/services/initial_attestation/CMakeLists.txt b/secure_fw/services/initial_attestation/CMakeLists.txt
new file mode 100644
index 0000000..1a1ea5f
--- /dev/null
+++ b/secure_fw/services/initial_attestation/CMakeLists.txt
@@ -0,0 +1,41 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+cmake_minimum_required(VERSION 3.7)
+
+#Tell cmake where our modules can be found
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../cmake)
+
+#Include common stuff to control cmake.
+include("Common/BuildSys")
+
+#Start an embedded project.
+embedded_project_start(CONFIG "${CMAKE_CURRENT_LIST_DIR}/../../../ConfigDefault.cmake")
+project(tfm_attest LANGUAGES ASM C)
+embedded_project_fixup()
+
+###Some project global settings
+set (INITIAL_ATTESTATION_DIR "${CMAKE_CURRENT_LIST_DIR}")
+get_filename_component(TFM_ROOT_DIR "${INITIAL_ATTESTATION_DIR}/../../.." ABSOLUTE)
+
+###Get the definition of what files we need to build
+set (ENABLE_INITIAL_ATTESTATION ON)
+include(CMakeLists.inc)
+
+if (NOT DEFINED TFM_LVL)
+	message(FATAL_ERROR "Incomplete build configuration: TFM_LVL is undefined.")
+endif()
+
+#Specify what we build (for the initial attestation service, build as a static library)
+add_library(tfm_attest STATIC ${ALL_SRC_ASM} ${ALL_SRC_C})
+embedded_set_target_compile_defines(TARGET tfm_attest LANGUAGE C DEFINES __ARM_FEATURE_CMSE=3 __thumb2__ TFM_LVL=${TFM_LVL})
+
+#Set common compiler and linker flags
+config_setting_shared_compiler_flags(tfm_attest)
+config_setting_shared_linker_flags(tfm_attest)
+
+embedded_project_end(tfm_attest)
diff --git a/secure_fw/services/initial_attestation/attestation.h b/secure_fw/services/initial_attestation/attestation.h
new file mode 100644
index 0000000..2072cb4
--- /dev/null
+++ b/secure_fw/services/initial_attestation/attestation.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __ATTESTATION_H__
+#define __ATTESTATION_H__
+
+#include "psa_initial_attestation_api.h"
+#include "psa_client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Extension of shared data TLVs defined in bl2/include/tfm_boot_status.h */
+#define TLV_MINOR_IAS_BOOT_SEED       0x0f
+#define TLV_MINOR_IAS_DEVICE_ID       0x10
+#define TLV_MINOR_IAS_CHALLENGE       0x11
+#define TLV_MINOR_IAS_CALLER_ID       0x12
+
+/*!
+ * \brief Initialise the initial attestation service during the TF-M boot up
+ *        process.
+ *
+ * \return Returns PSA_ATTEST_ERR_SUCCESS if init has been completed,
+ *         otherwise error as specified in \ref psa_attest_err_t
+ */
+enum psa_attest_err_t attest_init(void);
+
+/*!
+ * \brief Get initial attestation token
+ *
+ * \param[in]     in_vec     Pointer to in_vec array, which contains input data
+ *                           to attestation service
+ * \param[in]     num_invec  Number of elements in in_vec array
+ * \param[in/out] out_vec    Pointer out_vec array, which contains output data
+ *                           to attestation service
+ * \param[in]     num_outvec Number of elements in out_vec array
+ *
+ * \return Returns error code as specified in \ref psa_attest_err_t
+ */
+enum psa_attest_err_t
+initial_attest_get_token(const psa_invec  *in_vec,  uint32_t num_invec,
+                               psa_outvec *out_vec, uint32_t num_outvec);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ATTESTATION_H__ */
diff --git a/secure_fw/services/initial_attestation/attestation_core.c b/secure_fw/services/initial_attestation/attestation_core.c
new file mode 100644
index 0000000..c16d4a3
--- /dev/null
+++ b/secure_fw/services/initial_attestation/attestation_core.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <stddef.h>
+#include "psa_initial_attestation_api.h"
+#include "attestation.h"
+#include "secure_utilities.h"
+#include "tfm_api.h"
+#include "tfm_secure_api.h"
+#include "psa_client.h"
+#include "bl2/include/tfm_boot_status.h"
+#include "platform/include/tfm_plat_device_id.h"
+#include "platform/include/tfm_plat_boot_seed.h"
+
+#define MAX_BOOT_STATUS 512
+
+/*!
+ * \var boot_status
+ *
+ * \brief Array variable to 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.
+ */
+
+/* FixMe: Enforcement of 4 byte alignment can be removed as soon as memory type
+ *        is configured in the MPU to be normal, instead of device, which
+ *        prohibits unaligned access.
+ */
+__attribute__ ((aligned(4)))
+static uint8_t boot_status[MAX_BOOT_STATUS];
+
+enum psa_attest_err_t attest_init(void)
+{
+    enum tfm_status_e res;
+
+    res = tfm_core_get_boot_data(TLV_MAJOR_IAS, boot_status, MAX_BOOT_STATUS);
+    if (res != TFM_SUCCESS) {
+        return PSA_ATTEST_ERR_INIT_FAILED;
+    }
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
+
+/*!
+ * \brief Static function to look up a specific entry in the shared data
+ *        section.
+ *
+ * \param[in]  minor_type The identifier of the shared data entry
+ * \param[out] tlv_len    Length of the shared data entry
+ * \param[out] tlv_ptr    Pointer to the shared data entry
+ *
+ * \return Returns 0 on success. Otherwise, 1.
+ */
+static uint32_t attest_get_tlv(uint8_t    minor_type,
+                               uint16_t  *tlv_len,
+                               uint8_t  **tlv_ptr)
+{
+    struct shared_data_tlv_header *tlv_header;
+    struct shared_data_tlv_entry  *tlv_entry;
+    uintptr_t tlv_end;
+    uintptr_t tlv_curr;
+
+    tlv_header = (struct shared_data_tlv_header *)boot_status;
+    if (tlv_header->tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) {
+        return 1;
+    }
+
+    /* Get the boundaries of TLV section */
+    tlv_end  = (uintptr_t)boot_status + tlv_header->tlv_tot_len;
+    tlv_curr = (uintptr_t)boot_status + SHARED_DATA_HEADER_SIZE;
+
+    /* Iterates over the TLV section and copy TLVs with requested minor
+     * type to the provided buffer.
+     */
+    for(; tlv_curr < tlv_end; tlv_curr += tlv_entry->tlv_len) {
+        tlv_entry = (struct shared_data_tlv_entry *)tlv_curr;
+        if (tlv_entry->tlv_minor_type == minor_type) {
+            *tlv_ptr = (uint8_t *)tlv_entry;
+            *tlv_len = tlv_entry ->tlv_len;
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+/*!
+ * \brief Static function to copy a TLV entry from shared data section to the
+ *        attestation token.
+ *
+ * \param[in]  tlv_len        The length of TLV entry in bytes
+ * \param[in]  tlv_ptr        Pointer from where to copy the TLV entry
+ * \param[in]  token_buf_size Size of token buffer in bytes
+ * \param[out] token_buf      Pointer to buffer which stores the token
+ *
+ * \return Returns 0 on success. Otherwise, 1.
+ */
+static uint32_t attest_copy_tlv(uint16_t       tlv_len,
+                                const uint8_t *tlv_ptr,
+                                uint32_t       token_buf_size,
+                                uint8_t       *token_buf)
+{
+    struct shared_data_tlv_header *tlv_header;
+    uint8_t *next_tlv = token_buf;
+
+    tlv_header = (struct shared_data_tlv_header *)token_buf;
+    if (tlv_header->tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) {
+        return 1;
+    }
+
+    if (tlv_header->tlv_tot_len + tlv_len > token_buf_size) {
+        return 1;
+    }
+
+    next_tlv += tlv_header->tlv_tot_len;
+    tlv_header->tlv_tot_len += tlv_len;
+    tfm_memcpy(next_tlv, tlv_ptr, tlv_len);
+
+    return 0;
+}
+
+/*!
+ * \brief Static function to add a TLV entry to the attestation token.
+ *
+ * \param[in]  minor_type     The identifier of the TLV entry
+ * \param[in]  size           Size of the TLV entry in bytes
+ * \param[in]  data           Pointer to the buffer which stores the TLV entry
+ * \param[in]  token_buf_size Size of token buffer in bytes
+ * \param[out] token_buf      Pointer to buffer which stores the token
+ *
+ * \return Returns 0 on success. Otherwise, 1.
+ */
+static uint32_t attest_add_tlv(uint8_t        minor_type,
+                               uint32_t       size,
+                               const uint8_t *data,
+                               uint32_t       token_buf_size,
+                               uint8_t       *token_buf)
+{
+    struct shared_data_tlv_header *tlv_header;
+    struct shared_data_tlv_entry  *tlv_entry;
+    uint8_t *next_tlv = token_buf;
+
+    tlv_header = (struct shared_data_tlv_header *)token_buf;
+    if (tlv_header->tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) {
+        return 1;
+    }
+
+    if (tlv_header->tlv_tot_len + SHARED_DATA_ENTRY_SIZE(size) >
+        token_buf_size) {
+        return 1;
+    }
+
+    next_tlv += tlv_header->tlv_tot_len;
+    tlv_header->tlv_tot_len += SHARED_DATA_ENTRY_SIZE(size);
+
+    tlv_entry = (struct shared_data_tlv_entry *)next_tlv;
+    tlv_entry->tlv_major_type = TLV_MAJOR_IAS;
+    tlv_entry->tlv_minor_type = minor_type;
+    tlv_entry->tlv_len = SHARED_DATA_ENTRY_SIZE(size);
+
+    next_tlv += SHARED_DATA_ENTRY_HEADER_SIZE;
+    tfm_memcpy(next_tlv, data, size);
+
+    return 0;
+}
+
+/*!
+ * \brief Static function to initalise the token buffer. Add TLV data header to
+ *        it.
+ *
+ * \param[in]  token_buf_size Size of token buffer in bytes
+ * \param[out] token_buf      Pointer to buffer which stores the token
+ *
+ * \return Returns error code as specified in \ref psa_attest_err_t
+ */
+static enum psa_attest_err_t
+attest_init_token(uint32_t token_buf_size, uint8_t *token_buf)
+{
+    struct shared_data_tlv_header *tlv_header;
+
+    if (SHARED_DATA_HEADER_SIZE > token_buf_size) {
+        return PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW;
+    }
+
+    tlv_header = (struct shared_data_tlv_header *)token_buf;
+    tlv_header->tlv_magic = SHARED_DATA_TLV_INFO_MAGIC;
+    tlv_header->tlv_tot_len = SHARED_DATA_HEADER_SIZE;
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
+
+/*!
+ * \brief Static function to add boot status claim to attestation token.
+ *
+ * \param[in]  token_buf_size Size of token buffer in bytes
+ * \param[out] token_buf      Pointer to buffer which stores the token
+ *
+ * \return Returns error code as specified in \ref psa_attest_err_t
+ */
+static enum psa_attest_err_t
+attest_add_s_ns_sha256_claim(uint32_t token_buf_size, uint8_t *token_buf)
+{
+    uint16_t tlv_len;
+    uint8_t *tlv_ptr;
+    uint32_t res;
+
+    res = attest_get_tlv(TLV_MINOR_IAS_S_NS_SHA256, &tlv_len, &tlv_ptr);
+    if (res != 0) {
+        return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
+    }
+
+    res = attest_copy_tlv(tlv_len, tlv_ptr, token_buf_size, token_buf);
+    if (res != 0) {
+        return PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW;
+    }
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
+
+/*!
+ * \brief Static function to add boot seed claim to attestation token.
+ *
+ * \param[in]  token_buf_size Size of token buffer in bytes
+ * \param[out] token_buf      Pointer to buffer which stores the token
+ *
+ * \return Returns error code as specified in \ref psa_attest_err_t
+ */
+static enum psa_attest_err_t
+attest_add_boot_seed_claim(uint32_t token_buf_size, uint8_t *token_buf)
+{
+    /* FixMe: Enforcement of 4 byte alignment can be removed as soon as memory
+     *        type is configured in the MPU to be normal, instead of device,
+     *        which prohibits unaligned access.
+     */
+    __attribute__ ((aligned(4)))
+    uint8_t boot_seed[BOOT_SEED_SIZE];
+    uint32_t res;
+
+    res = tfm_plat_get_boot_seed(sizeof(boot_seed), boot_seed);
+    if (res != 0) {
+        return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
+    }
+
+    res = attest_add_tlv(TLV_MINOR_IAS_BOOT_SEED,
+                         BOOT_SEED_SIZE,
+                         boot_seed,
+                         token_buf_size,
+                         token_buf);
+    if (res != 0) {
+        return PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW;
+    }
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
+
+/*!
+ * \brief Static function to add device id claim to attestation token.
+ *
+ * \param[in]  token_buf_size Size of token buffer in bytes
+ * \param[out] token_buf      Pointer to buffer which stores the token
+ *
+ * \return Returns error code as specified in \ref psa_attest_err_t
+ */
+static enum psa_attest_err_t
+attest_add_device_id_claim(uint32_t token_buf_size, uint8_t *token_buf)
+{
+    /* FixMe: Enforcement of 4 byte alignment can be removed as soon as memory
+     *        type is configured in the MPU to be normal, instead of device,
+     *        which prohibits unaligned access.
+     */
+    __attribute__ ((aligned(4)))
+    uint8_t device_id[DEVICE_ID_MAX_SIZE];
+    uint32_t res;
+    int32_t size;
+
+    size = tfm_plat_get_device_id(sizeof(device_id), device_id);
+    if (size < 0) {
+        return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
+    }
+
+    res = attest_add_tlv(TLV_MINOR_IAS_DEVICE_ID,
+                         size,
+                         device_id,
+                         token_buf_size,
+                         token_buf);
+    if (res != 0) {
+        return PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW;
+    }
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
+
+/*!
+ * \brief Static function to add caller id claim to attestation token.
+ *
+ * \param[in]  token_buf_size Size of token buffer in bytes
+ * \param[out] token_buf      Pointer to buffer which stores the token
+ *
+ * \return Returns error code as specified in \ref psa_attest_err_t
+ */
+static enum psa_attest_err_t
+attest_add_caller_id_claim(uint32_t token_buf_size, uint8_t *token_buf)
+{
+    uint32_t res;
+    int32_t  caller_id;
+
+    res = tfm_core_get_caller_client_id(&caller_id);
+    if (res != 0) {
+        return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
+    }
+
+    res = attest_add_tlv(TLV_MINOR_IAS_CALLER_ID,
+                         sizeof(int32_t),
+                         (uint8_t *)&caller_id,
+                         token_buf_size,
+                         token_buf);
+    if (res != 0) {
+        return PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW;
+    }
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
+
+/*!
+ * \brief Static function to add challenge claim to attestation token.
+ *
+ * \param[in]  challenge_buf_size Size of challenge object in bytes
+ * \param[in]  challenge_buf      Pointer to buffer which stores the challenge
+ *                                object
+ * \param[in]  token_buf_size     Size of token buffer in bytes
+ * \param[out] token_buf          Pointer to buffer which stores the token
+ *
+ * \return Returns error code as specified in \ref psa_attest_err_t
+ */
+static enum psa_attest_err_t
+attest_add_challenge_claim(uint32_t       challenge_buf_size,
+                           const uint8_t *challenge_buf,
+                           uint32_t       token_buf_size,
+                           uint8_t       *token_buf)
+{
+    uint32_t res;
+
+    res = attest_add_tlv(TLV_MINOR_IAS_CHALLENGE,
+                         challenge_buf_size,
+                         challenge_buf,
+                         token_buf_size,
+                         token_buf);
+    if (res != 0) {
+        return PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW;
+    }
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
+
+/*!
+ * \brief Static function to retrieve the constructed attestation token's size.
+ *
+ * \param[in] token_buf Pointer to buffer which stores the token
+ *
+ * \return Returns the size of token in bytes
+ */
+static uint32_t attest_get_token_size(const uint8_t *token_buf)
+{
+    struct shared_data_tlv_header *tlv_header;
+
+    tlv_header = (struct shared_data_tlv_header *)token_buf;
+
+    return tlv_header->tlv_tot_len;
+}
+
+/* Initial implementation of attestation service:
+ *  - data is TLV encoded
+ *  - token is not signed yet
+ *  - only fixed set of claims are supported
+ *  - external claims are not handled, expect challenge object
+ */
+enum psa_attest_err_t
+initial_attest_get_token(const psa_invec  *in_vec,  uint32_t num_invec,
+                               psa_outvec *out_vec, uint32_t num_outvec)
+{
+    enum tfm_status_e tfm_err;
+    enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS;
+
+    const uint8_t *challenge_buf = (uint8_t *)in_vec[0].base;
+    size_t   challenge_buf_size  = in_vec[0].len;
+    uint8_t *token_buf           = (uint8_t *)out_vec[0].base;
+    size_t  *token_buf_size      = &(out_vec[0].len);
+
+    if (challenge_buf_size > PSA_INITIAL_ATTEST_MAX_CHALLENGE_SIZE) {
+        return PSA_ATTEST_ERR_INVALID_INPUT;
+    }
+
+    if (challenge_buf_size > 0) {
+        tfm_err = tfm_core_memory_permission_check((void *)challenge_buf,
+                                                   challenge_buf_size,
+                                                   TFM_MEMORY_ACCESS_RO);
+        if (tfm_err != TFM_SUCCESS) {
+            attest_err =  PSA_ATTEST_ERR_INVALID_INPUT;
+            goto error;
+        }
+    }
+
+    tfm_err = tfm_core_memory_permission_check(token_buf,
+                                               *token_buf_size,
+                                               TFM_MEMORY_ACCESS_RW);
+    if (tfm_err != TFM_SUCCESS) {
+        attest_err =  PSA_ATTEST_ERR_INVALID_INPUT;
+        goto error;
+    }
+
+    attest_err = attest_init_token(*token_buf_size, token_buf);
+    if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
+        goto error;
+    }
+
+    attest_err = attest_add_s_ns_sha256_claim(*token_buf_size, token_buf);
+    if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
+        goto error;
+    }
+
+    attest_err = attest_add_boot_seed_claim(*token_buf_size, token_buf);
+    if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
+        goto error;
+    }
+
+    attest_err = attest_add_device_id_claim(*token_buf_size, token_buf);
+    if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
+        goto error;
+    }
+
+    if (challenge_buf_size > 0) {
+        attest_err = attest_add_challenge_claim(challenge_buf_size,
+                                                challenge_buf,
+                                                *token_buf_size,
+                                                token_buf);
+        if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
+            goto error;
+        }
+    }
+
+    attest_err = attest_add_caller_id_claim(*token_buf_size, token_buf);
+    if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
+        goto error;
+    }
+     /* FixMe: Token should be signed with attestation key */
+
+    *token_buf_size = attest_get_token_size(token_buf);
+
+error:
+    return attest_err;
+}
diff --git a/secure_fw/services/initial_attestation/manifest.yaml b/secure_fw/services/initial_attestation/manifest.yaml
new file mode 100644
index 0000000..319987b
--- /dev/null
+++ b/secure_fw/services/initial_attestation/manifest.yaml
@@ -0,0 +1,37 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "name": "INITIAL_ATTESTATION",
+  "type": "TRUSTED",
+  "tfm_partition_name": "TFM_SP_INITIAL_ATTESTATION",
+  "tfm_trusted": true,
+  "priority": "NORMAL",
+  "id": "0x00000103",
+  "entry_point": "main",
+  "stack_size": "0x0400",
+  "heap_size": "0x0400",
+  "tfm_init_symbol": "attest_init",
+  "secure_functions": [
+    {
+      "sfid": "TFM_ATTEST_GET_TOKEN_SFID",
+      "signal": "TFM_ATTEST_GET_TOKEN",
+      "tfm_symbol": "attest_get_token",
+      "non_secure_clients": true,
+      "minor_version": 1,
+      "minor_policy": "strict"
+    }
+  ],
+  "source_files": [
+    "attestation_core.c"
+  ],
+  "tfm_linker_pattern": [
+    "library_list": [
+      "*tfm_attest*"
+    ]
+  ]
+}
diff --git a/secure_fw/services/initial_attestation/tfm_attestation_secure_api.c b/secure_fw/services/initial_attestation/tfm_attestation_secure_api.c
new file mode 100644
index 0000000..0943de0
--- /dev/null
+++ b/secure_fw/services/initial_attestation/tfm_attestation_secure_api.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "psa_initial_attestation_api.h"
+#include "tfm_initial_attestation_veneers.h"
+#include "secure_utilities.h"
+#include "psa_client.h"
+#include "tfm_secure_api.h"
+#include <string.h>
+
+/* FIXME: If iovec will be supported by SPM then remove the usage of
+ * scratch area.
+ */
+extern uint8_t *tfm_scratch_area;
+
+__attribute__((section("SFN")))
+enum psa_attest_err_t
+psa_initial_attest_get_token(const uint8_t *challenge_obj,
+                             uint32_t       challenge_size,
+                             uint8_t       *token,
+                             uint32_t      *token_size)
+{
+    enum psa_attest_err_t err;
+    psa_invec *in_vec;
+    psa_outvec *out_vec;
+    uint8_t *challenge_buff;
+    uint8_t *token_buff;
+
+    if (tfm_core_set_buffer_area(TFM_BUFFER_SHARE_SCRATCH) != TFM_SUCCESS) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    /*
+     * Scratch area layout
+     * -------------------------------------------------------
+     * |in_vec[0] | out_vec[0] | challenge_buff | token_buff |
+     * -------------------------------------------------------
+     */
+
+    in_vec  = (psa_invec  *)(tfm_scratch_area);
+    out_vec = (psa_outvec *)(in_vec + 1);
+
+    challenge_buff = (uint8_t *)(out_vec + 1);
+    token_buff     = (uint8_t *)(challenge_buff + challenge_size);
+
+    /* Copy challenge object to scratch area */
+    tfm_memcpy(challenge_buff, challenge_obj, challenge_size);
+
+
+    in_vec[0].base = challenge_buff;
+    in_vec[0].len  = challenge_size;
+
+    out_vec[0].base = token_buff;
+    out_vec[0].len  = *token_size;
+
+    err = tfm_attest_veneer_get_token(in_vec, 1, out_vec, 1);
+    if (err != PSA_ATTEST_ERR_SUCCESS) {
+        return err;
+    }
+
+    /* Copy output token to local buffer */
+    tfm_memcpy(token, out_vec[0].base, out_vec[0].len);
+    *token_size = out_vec[0].len;
+
+    return err;
+}
diff --git a/secure_fw/services/tfm_partition_defs.inc b/secure_fw/services/tfm_partition_defs.inc
index 1ef4cf0..a84c54b 100644
--- a/secure_fw/services/tfm_partition_defs.inc
+++ b/secure_fw/services/tfm_partition_defs.inc
@@ -18,22 +18,24 @@
 
 #define TFM_SP_PLATFORM_ID (TFM_SP_BASE + 3)
 
+#define TFM_SP_INITIAL_ATTESTATION_ID (TFM_SP_BASE + 4)
+
 #ifdef TFM_PARTITION_TEST_CORE
-#define TFM_SP_CORE_TEST_ID (TFM_SP_BASE + 4)
+#define TFM_SP_CORE_TEST_ID (TFM_SP_BASE + 5)
 #endif /* TFM_PARTITION_TEST_CORE */
 
 #ifdef TFM_PARTITION_TEST_CORE
-#define TFM_SP_CORE_TEST_2_ID (TFM_SP_BASE + 5)
+#define TFM_SP_CORE_TEST_2_ID (TFM_SP_BASE + 6)
 #endif /* TFM_PARTITION_TEST_CORE */
 
 #ifdef TFM_PARTITION_TEST_SST
-#define TFM_SP_SST_TEST_PARTITION_ID (TFM_SP_BASE + 6)
+#define TFM_SP_SST_TEST_PARTITION_ID (TFM_SP_BASE + 7)
 #endif /* TFM_PARTITION_TEST_SST */
 
 #ifdef TFM_PARTITION_TEST_SECURE_SERVICES
-#define TFM_SP_SECURE_TEST_PARTITION_ID (TFM_SP_BASE + 7)
+#define TFM_SP_SECURE_TEST_PARTITION_ID (TFM_SP_BASE + 8)
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
 
-#define TFM_MAX_USER_PARTITIONS (8)
+#define TFM_MAX_USER_PARTITIONS (9)
 
 #endif /* __TFM_PARTITION_DEFS_INC__ */
diff --git a/secure_fw/services/tfm_partition_list.inc b/secure_fw/services/tfm_partition_list.inc
index 8be6ef9..57dd18f 100644
--- a/secure_fw/services/tfm_partition_list.inc
+++ b/secure_fw/services/tfm_partition_list.inc
@@ -29,6 +29,10 @@
 PARTITION_DECLARE(TFM_SP_PLATFORM, SPM_PART_FLAG_SECURE | SPM_PART_FLAG_TRUSTED);
 PARTITION_ADD_INIT_FUNC(TFM_SP_PLATFORM, platform_sp_init);
 
+/******** TFM_SP_INITIAL_ATTESTATION ********/
+PARTITION_DECLARE(TFM_SP_INITIAL_ATTESTATION, SPM_PART_FLAG_SECURE | SPM_PART_FLAG_TRUSTED);
+PARTITION_ADD_INIT_FUNC(TFM_SP_INITIAL_ATTESTATION, attest_init);
+
 #ifdef TFM_PARTITION_TEST_CORE
 /******** TFM_SP_CORE_TEST ********/
 PARTITION_DECLARE(TFM_SP_CORE_TEST, SPM_PART_FLAG_SECURE);
diff --git a/secure_fw/services/tfm_sfid_list.inc b/secure_fw/services/tfm_sfid_list.inc
index f2656df..e224dce 100644
--- a/secure_fw/services/tfm_sfid_list.inc
+++ b/secure_fw/services/tfm_sfid_list.inc
@@ -49,6 +49,9 @@
     /******** TFM_SP_PLATFORM ********/
     {platform_sp_system_reset, TFM_SP_PLATFORM_SYSTEM_RESET_SFID},
 
+    /******** TFM_SP_INITIAL_ATTESTATION ********/
+    {attest_get_token, TFM_ATTEST_GET_TOKEN_SFID},
+
 #ifdef TFM_PARTITION_TEST_CORE
     /******** TFM_SP_CORE_TEST ********/
     {spm_core_test_sfn, TFM_CORE_TEST_SFN_SFID},