SST: Add rollback protection in SST service

This patch adds rollback protection in SST service, enables it for all
supported platforms and updates the SST service integration guide.

Change-Id: If4697051824766e1ae5774ede0e9960088bdd46a
Signed-off-by: Marc Moreno <marc.morenoberengue@arm.com>
diff --git a/CommonConfig.cmake b/CommonConfig.cmake
index af7af02..77ba88e 100644
--- a/CommonConfig.cmake
+++ b/CommonConfig.cmake
@@ -193,6 +193,10 @@
 		set (SST_ENCRYPTION ON)
 	endif()
 
+	if (NOT DEFINED SST_ROLLBACK_PROTECTION)
+		set (SST_ROLLBACK_PROTECTION OFF)
+	endif()
+
 	if (NOT DEFINED SST_CREATE_FLASH_LAYOUT)
 		set (SST_CREATE_FLASH_LAYOUT OFF)
 	endif()
diff --git a/docs/user_guides/services/tfm_sst_integration_guide.md b/docs/user_guides/services/tfm_sst_integration_guide.md
index 6f7665a..5eab3be 100644
--- a/docs/user_guides/services/tfm_sst_integration_guide.md
+++ b/docs/user_guides/services/tfm_sst_integration_guide.md
@@ -64,12 +64,6 @@
 inherent failures of storage mediums (e.g. bad blocks in a NAND based device)
 is not supported by the current design.
 
-**Rollback Protection** - In the current design, the rollback protection is not
-supported. If the storage medium is not hardware protected against malicious
-writes then it is possible to replace the current contents with older version.
-However, such attack would be limited to a single device since a HUK based
-encryption policy is used.
-
 **Key Diversification** - In a more robust design, each asset would be encrypted
 through a different key.
 
@@ -92,6 +86,7 @@
  - Flash filesystem interfaces
  - Flash interfaces
  - Cryptographic interfaces
+ - Non-volatile (NV) counters interfaces
  - Assets definitions
 
 The PSA interfaces for SST service are located in `interface/include`
@@ -182,6 +177,18 @@
 replace this implementation with calls to another service, crypto library or
 hardware crypto unit.
 
+### Non-volatile (NV) Counters Interface
+
+`nv_counters/sst_nv_counters.h` - Abstracts SST non-volatile counters
+operations. This API detaches the use of NV counters from the TF-M NV counters
+implementation, provided by the platform, and provides a mechanism to compile
+in a different API implementation for test purposes. A SST test suite **may**
+provide its own custom implementation to be able to test different SST service
+use cases.
+
+`nv_counters/sst_nv_counters.c` - Implements the SST NV counters interfaces
+based on TF-M NV counters implementation provided by the platform.
+
 ### Asset Definition
 
 `asset/sst_asset_defs.(c/h)` - Contain a reference implementation of the
@@ -418,6 +425,9 @@
  - `SST_ENABLE_PARTIAL_ASSET_RW`: this flag allows to enable/disable the
    partial asset RW manipulation at compile time. The partial asset
    manipulation is allowed by default.
+ - `SST_ROLLBACK_PROTECTION`: this flag allows to enable/disable rollback
+   protection in secure storage service. This flag takes effect only if the
+   target has non-volatile counters and `SST_ENCRYPTION` flag is on.
 
 --------------
 
diff --git a/platform/ext/Mps2AN519.cmake b/platform/ext/Mps2AN519.cmake
index f1475bf..ca68320 100644
--- a/platform/ext/Mps2AN519.cmake
+++ b/platform/ext/Mps2AN519.cmake
@@ -133,6 +133,9 @@
   #       API ONLY if the target has non-volatile counters.
   list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an519/dummy_nv_counters.c")
   set(TARGET_NV_COUNTERS_ENABLE ON)
+  # Sets SST_ROLLBACK_PROTECTION flag to compile in the SST services
+  # rollback protection code as the target supports nv counters.
+  set (SST_ROLLBACK_PROTECTION ON)
 endif()
 
 if (NOT DEFINED BUILD_CMSIS_DRIVERS)
diff --git a/platform/ext/Mps2AN521.cmake b/platform/ext/Mps2AN521.cmake
index a0c453f..c56faef 100644
--- a/platform/ext/Mps2AN521.cmake
+++ b/platform/ext/Mps2AN521.cmake
@@ -134,6 +134,9 @@
   #       API ONLY if the target has non-volatile counters.
   list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an521/dummy_nv_counters.c")
   set(TARGET_NV_COUNTERS_ENABLE ON)
+  # Sets SST_ROLLBACK_PROTECTION flag to compile in the SST services
+  # rollback protection code as the target supports nv counters.
+  set (SST_ROLLBACK_PROTECTION ON)
 endif()
 
 if (NOT DEFINED BUILD_CMSIS_DRIVERS)
diff --git a/platform/ext/musca_a.cmake b/platform/ext/musca_a.cmake
index e9c06c5..57fad7e 100755
--- a/platform/ext/musca_a.cmake
+++ b/platform/ext/musca_a.cmake
@@ -137,6 +137,9 @@
   #       API ONLY if the target has non-volatile counters.
   list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/musca_a/dummy_nv_counters.c")
   set(TARGET_NV_COUNTERS_ENABLE ON)
+  # Sets SST_ROLLBACK_PROTECTION flag to compile in the SST services
+  # rollback protection code as the target supports nv counters.
+  set (SST_ROLLBACK_PROTECTION ON)
 endif()
 
 if (NOT DEFINED BUILD_CMSIS_DRIVERS)
diff --git a/secure_fw/services/secure_storage/CMakeLists.inc b/secure_fw/services/secure_storage/CMakeLists.inc
index 2231a24..e3d6737 100644
--- a/secure_fw/services/secure_storage/CMakeLists.inc
+++ b/secure_fw/services/secure_storage/CMakeLists.inc
@@ -39,6 +39,10 @@
 		message(FATAL_ERROR "Incomplete build configuration: SST_ENCRYPTION is undefined. ")
 	endif()
 
+	if (NOT DEFINED SST_ROLLBACK_PROTECTION)
+		message(FATAL_ERROR "Incomplete build configuration: SST_ROLLBACK_PROTECTION is undefined.")
+	endif()
+
 	if (NOT DEFINED SST_CREATE_FLASH_LAYOUT)
 		message(FATAL_ERROR "Incomplete build configuration: SST_CREATE_FLASH_LAYOUT is undefined. ")
 	endif()
@@ -70,6 +74,12 @@
 			)
 		set_property(SOURCE ${SECURE_STORAGE_C_SRC} APPEND PROPERTY COMPILE_DEFINITIONS SST_ENCRYPTION)
 		set_property(DIRECTORY ${TEST_DIR} APPEND PROPERTY COMPILE_DEFINITIONS SST_ENCRYPTION)
+
+		if (SST_ROLLBACK_PROTECTION)
+			list (APPEND SECURE_STORAGE_C_SRC
+				"${SECURE_STORAGE_DIR}/nv_counters/sst_nv_counters.c")
+			set_property(SOURCE ${SECURE_STORAGE_C_SRC} APPEND PROPERTY COMPILE_DEFINITIONS SST_ROLLBACK_PROTECTION)
+		endif()
 	endif()
 
 	if (SST_VALIDATE_METADATA_FROM_FLASH)
@@ -91,6 +101,11 @@
 	#Inform the user about SST service features selected based on the SST service cmake flags
 	message("The SST service compile configuration is as follows:")
 	message("- SST_ENCRYPTION: " ${SST_ENCRYPTION})
+	if (SST_ENCRYPTION)
+		message("- SST_ROLLBACK_PROTECTION: " ${SST_ROLLBACK_PROTECTION})
+	else()
+		message("- SST_ROLLBACK_PROTECTION: N/A")
+	endif()
 	message("- SST_VALIDATE_METADATA_FROM_FLASH: " ${SST_VALIDATE_METADATA_FROM_FLASH})
 	message("- SST_CREATE_FLASH_LAYOUT: " ${SST_CREATE_FLASH_LAYOUT})
 	message("- SST_ENABLE_PARTIAL_ASSET_RW: " ${SST_ENABLE_PARTIAL_ASSET_RW})
diff --git a/secure_fw/services/secure_storage/manifest.yaml b/secure_fw/services/secure_storage/manifest.yaml
index 818d62c..3b1708a 100644
--- a/secure_fw/services/secure_storage/manifest.yaml
+++ b/secure_fw/services/secure_storage/manifest.yaml
@@ -85,6 +85,7 @@
     "flash_fs/sst_flash_fs.c",
     "flash_fs/sst_flash_dblock.c",
     "flash_fs/sst_flash_mbock.c",
+    "nv_counters/sst_nv_counters.c",
   ],
   "tfm_linker_pattern": {
     "library_list": [
diff --git a/secure_fw/services/secure_storage/nv_counters/sst_nv_counters.c b/secure_fw/services/secure_storage/nv_counters/sst_nv_counters.c
new file mode 100644
index 0000000..aa103e8
--- /dev/null
+++ b/secure_fw/services/secure_storage/nv_counters/sst_nv_counters.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "sst_nv_counters.h"
+
+enum psa_sst_err_t sst_init_nv_counter(void)
+{
+    enum tfm_plat_err_t err;
+
+    err = tfm_plat_init_nv_counter();
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return PSA_SST_ERR_SYSTEM_ERROR;
+    }
+
+    return PSA_SST_ERR_SUCCESS;
+}
+
+enum psa_sst_err_t sst_read_nv_counter(enum tfm_nv_counter_t counter_id,
+                                       uint32_t *val)
+{
+    enum tfm_plat_err_t err;
+
+    err = tfm_plat_read_nv_counter(counter_id, SST_NV_COUNTER_SIZE,
+                                   (uint8_t *)val);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return PSA_SST_ERR_SYSTEM_ERROR;
+    }
+
+    return PSA_SST_ERR_SUCCESS;
+}
+
+enum psa_sst_err_t sst_increment_nv_counter(enum tfm_nv_counter_t counter_id)
+{
+    enum tfm_plat_err_t err;
+
+    /* NOTE: tfm_plat_increment_nv_counter returns TFM_PLAT_ERR_MAX_VALUE when
+     *       the counter reaches its maximum value. The current SST
+     *       implementation treats this condition as an error as, from that
+     *       moment onwards, the rollback protection can not be achieved based
+     *       on the NV counters.
+     */
+    err = tfm_plat_increment_nv_counter(counter_id);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return PSA_SST_ERR_SYSTEM_ERROR;
+    }
+
+    return PSA_SST_ERR_SUCCESS;
+}
+
diff --git a/secure_fw/services/secure_storage/nv_counters/sst_nv_counters.h b/secure_fw/services/secure_storage/nv_counters/sst_nv_counters.h
new file mode 100644
index 0000000..8686d60
--- /dev/null
+++ b/secure_fw/services/secure_storage/nv_counters/sst_nv_counters.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __SST_NV_COUNTERS_H__
+#define __SST_NV_COUNTERS_H__
+
+/* NOTE: This API abstracts SST NV counters operations. This API detaches the
+ *       use of NV counters from the TF-M NV counters implementation, provided
+ *       by the platform, and provides a mechanism to compile in a different
+ *       API implementation for test purposes. A SST test suite may provide
+ *       its own custom implementation to be able to test different SST service
+ *       use cases.
+ */
+
+#include <stdint.h>
+#include "psa_sst_api.h"
+#include "platform/include/tfm_plat_nv_counters.h"
+
+#define SST_NV_COUNTER_SIZE        4 /* In bytes */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Initializes all non-volatile (NV) counters.
+ *
+ * \return  PSA_SST_ERR_SUCCESS if the initialization succeeds, otherwise
+ *          PSA_SST_ERR_SYSTEM_ERROR
+ */
+enum psa_sst_err_t sst_init_nv_counter(void);
+
+/**
+ * \brief Reads the given non-volatile (NV) counter.
+ *
+ * \param[in]  counter_id  NV counter ID.
+ * \param[out] val         Pointer to store the current NV counter value.
+ *
+ * \return  PSA_SST_ERR_SUCCESS if the value is read correctly, otherwise
+ *          PSA_SST_ERR_SYSTEM_ERROR
+ */
+enum psa_sst_err_t sst_read_nv_counter(enum tfm_nv_counter_t counter_id,
+                                       uint32_t *val);
+
+/**
+ * \brief Increments the given non-volatile (NV) counter.
+ *
+ * \param[in] counter_id  NV counter ID.
+ *
+ * \return  If the counter is incremented correctly, it returns
+ *          PSA_SST_ERR_SUCCESS. Otherwise, PSA_SST_ERR_SYSTEM_ERROR.
+ */
+enum psa_sst_err_t sst_increment_nv_counter(enum tfm_nv_counter_t counter_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SST_NV_COUNTERS_H__ */
+
diff --git a/secure_fw/services/secure_storage/sst_object_table.c b/secure_fw/services/secure_storage/sst_object_table.c
index da4669e..f9cb085 100644
--- a/secure_fw/services/secure_storage/sst_object_table.c
+++ b/secure_fw/services/secure_storage/sst_object_table.c
@@ -12,6 +12,7 @@
 #include "crypto/sst_crypto_interface.h"
 #include "flash/sst_flash.h"
 #include "flash_fs/sst_flash_fs.h"
+#include "nv_counters/sst_nv_counters.h"
 #include "sst_utils.h"
 
 /*!
@@ -35,7 +36,6 @@
     uint32_t uuid;                  /*!< Object UUID */
 };
 
-
 /* Specifies number of entries in the table. The number of entries is the
  * number of assets, defined in asset_defs.h, plus one extra entry to store
  * a new object when the code processes a change in a file.
@@ -49,16 +49,23 @@
  */
 struct __attribute__((__packed__)) sst_obj_table_t {
 #ifdef SST_ENCRYPTION
-  union sst_crypto_t crypto;      /*!< Crypto metadata. */
+  union sst_crypto_t crypto;     /*!< Crypto metadata. */
 #endif
-  uint8_t version;                /*!< SST object system version. */
-  uint8_t swap_count;             /*!< Swap counter to distinguish 2 different
-                                   *   object tables.
-                                   */
-  uint8_t reserved[2];            /*!< 32 bits alignment. */
-  struct sst_obj_table_entry_t    obj_db[SST_OBJ_TABLE_ENTRIES]; /*!< Table's
-                                                                  *   entries
-                                                                  */
+
+  uint8_t version;               /*!< SST object system version. */
+
+#ifndef SST_ROLLBACK_PROTECTION
+  uint8_t swap_count;            /*!< Swap counter to distinguish 2 different
+                                  *   object tables.
+                                  */
+  uint8_t reserved[2];           /*!< 32 bits alignment. */
+#else
+  uint8_t reserved[3];           /*!< 32 bits alignment. */
+#endif /* SST_ROLLBACK_PROTECTION */
+
+  struct sst_obj_table_entry_t obj_db[SST_OBJ_TABLE_ENTRIES]; /*!< Table's
+                                                               *   entries
+                                                               */
 };
 
 /* Object table indexes */
@@ -66,7 +73,7 @@
 #define SST_OBJ_TABLE_IDX_1 1
 
 /* Number of object tables (active and scratch) */
-#define SST_NUM_OBJ_TABLES 2
+#define SST_NUM_OBJ_TABLES  2
 
 /*!
  * \def SST_TABLE_FS_ID
@@ -141,16 +148,27 @@
 #define SST_OBJECT_TABLE_EMPTY_SIZE  0
 #define SST_OBJECT_TABLE_EMPTY       NULL
 
-/* Invalid object table data value */
-#define SST_OBJ_TABLE_INVALID 1
-
 /* The associated data is the header minus the crypto data */
 #define SST_CRYPTO_ASSOCIATED_DATA(crypto) ((uint8_t *)crypto + \
-                                             SST_NON_AUTH_OBJ_TABLE_SIZE)
+                                            SST_NON_AUTH_OBJ_TABLE_SIZE)
+
+#ifdef SST_ROLLBACK_PROTECTION
+#define SST_OBJ_TABLE_AUTH_DATA_SIZE (SST_OBJ_TABLE_SIZE - \
+                                      SST_NON_AUTH_OBJ_TABLE_SIZE)
+
+struct sst_crypto_assoc_data_t {
+    uint8_t  obj_table_data[SST_OBJ_TABLE_AUTH_DATA_SIZE];
+    uint32_t nv_counter;
+};
+
+#define SST_CRYPTO_ASSOCIATED_DATA_LEN  sizeof(struct sst_crypto_assoc_data_t)
+
+#else
 
 /* The associated data is the header, minus the the tag data */
 #define SST_CRYPTO_ASSOCIATED_DATA_LEN (SST_OBJ_TABLE_SIZE - \
                                         SST_NON_AUTH_OBJ_TABLE_SIZE)
+#endif /* SST_ROLLBACK_PROTECTION */
 
 /* The sst_object_table_init function uses the static memory allocated for
  * the object data manipulation, in sst_object_table.c (g_sst_object), to load a
@@ -164,6 +182,16 @@
 SST_UTILS_BOUND_CHECK(OBJ_TABLE_NOT_FIT_IN_STATIC_OBJ_DATA_BUF,
                       SST_OBJ_TABLE_SIZE, SST_MAX_ASSET_SIZE);
 
+enum sst_obj_table_state {
+    SST_OBJ_TABLE_VALID = 0,   /*!< Table content is valid */
+    SST_OBJ_TABLE_INVALID,     /*!< Table content is invalid */
+    SST_OBJ_TABLE_NVC_1_VALID, /*!< Table content valid with NVC 1 value */
+    SST_OBJ_TABLE_NVC_3_VALID, /*!< Table content valid with NVC 3 value */
+};
+
+/* Specifies that SST NV counter value is invalid */
+#define SST_INVALID_NVC_VALUE 0
+
 /*!
  * \struct sst_obj_table_ctx_t
  *
@@ -173,10 +201,16 @@
     struct sst_obj_table_t *p_table[SST_NUM_OBJ_TABLES]; /*!< Pointer to
                                                           *   object tables
                                                           */
-    uint8_t invalid_table[SST_NUM_OBJ_TABLES];  /*!< Array to indicate if the
-                                                 *   object table X has valid
-                                                 *   data
-                                                 */
+    enum sst_obj_table_state table_state[SST_NUM_OBJ_TABLES]; /*!< Array to
+                                                               *   indicate if
+                                                               *   the object
+                                                               *   table X is
+                                                               *   valid
+                                                               */
+#ifdef SST_ROLLBACK_PROTECTION
+    uint32_t nvc_1;        /*!< Non-volatile counter value 1 */
+    uint32_t nvc_3;        /*!< Non-volatile counter value 3 */
+#endif /* SST_ROLLBACK_PROTECTION */
 };
 
 /**
@@ -198,7 +232,7 @@
                              SST_OBJECT_TABLE_OBJECT_OFFSET,
                              (uint8_t *)init_ctx->p_table[SST_OBJ_TABLE_IDX_0]);
     if (err != PSA_SST_ERR_SUCCESS) {
-        init_ctx->invalid_table[SST_OBJ_TABLE_IDX_0] = SST_OBJ_TABLE_INVALID;
+        init_ctx->table_state[SST_OBJ_TABLE_IDX_0] = SST_OBJ_TABLE_INVALID;
     }
 
     /* Read file with the table 1 data */
@@ -207,7 +241,7 @@
                              SST_OBJECT_TABLE_OBJECT_OFFSET,
                              (uint8_t *)init_ctx->p_table[SST_OBJ_TABLE_IDX_1]);
     if (err != PSA_SST_ERR_SUCCESS) {
-        init_ctx->invalid_table[SST_OBJ_TABLE_IDX_1] = SST_OBJ_TABLE_INVALID;
+        init_ctx->table_state[SST_OBJ_TABLE_IDX_1] = SST_OBJ_TABLE_INVALID;
     }
 }
 
@@ -268,6 +302,175 @@
     return err;
 }
 
+#ifdef SST_ROLLBACK_PROTECTION
+/**
+ * \brief Aligns all SST non-volatile counters.
+ *
+ * \param[in] nvc_1  Value of SST non-volatile counter 1
+ *
+ * \return Returns error code as specified in \ref psa_sst_err_t
+ */
+static enum psa_sst_err_t sst_object_table_align_nv_counters(uint32_t nvc_1)
+{
+    enum psa_sst_err_t err;
+    uint32_t nvc_x_val = 0;
+
+    /* Align SST NVC 2 with NVC 1 */
+    err = sst_read_nv_counter(TFM_SST_NV_COUNTER_2, &nvc_x_val);
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return PSA_SST_ERR_SYSTEM_ERROR;
+    }
+
+    for (; nvc_x_val < nvc_1; nvc_x_val++) {
+        err = sst_increment_nv_counter(TFM_SST_NV_COUNTER_2);
+        if (err != PSA_SST_ERR_SUCCESS) {
+            return err;
+        }
+    }
+
+    /* Align SST NVC 3 with NVC 1 */
+    err = sst_read_nv_counter(TFM_SST_NV_COUNTER_3, &nvc_x_val);
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return PSA_SST_ERR_SYSTEM_ERROR;
+    }
+
+    for (; nvc_x_val < nvc_1; nvc_x_val++) {
+        err = sst_increment_nv_counter(TFM_SST_NV_COUNTER_3);
+        if (err != PSA_SST_ERR_SUCCESS) {
+            return err;
+        }
+    }
+
+    return PSA_SST_ERR_SUCCESS;
+}
+
+/**
+ * \brief Generates table authentication tag.
+ *
+ * \param[in]     nvc_1      Value of SST non-volatile counter 1
+ * \param[in/out] obj_table  Pointer to the object table to generate
+ *                           authentication
+ *
+ * \return Returns error code as specified in \ref psa_sst_err_t
+ */
+__attribute__ ((always_inline))
+__STATIC_INLINE enum psa_sst_err_t sst_object_table_nvc_generate_auth_tag(
+                                              uint32_t nvc_1,
+                                              struct sst_obj_table_t *obj_table)
+{
+    struct sst_crypto_assoc_data_t assoc_data;
+    union sst_crypto_t *crypto = &obj_table->crypto;
+
+    /* Get new IV */
+    sst_crypto_get_iv(crypto);
+
+    assoc_data.nv_counter = nvc_1;
+    sst_utils_memcpy(assoc_data.obj_table_data,
+                     SST_CRYPTO_ASSOCIATED_DATA(crypto),
+                     SST_OBJ_TABLE_AUTH_DATA_SIZE);
+
+    return sst_crypto_generate_auth_tag(crypto, (const uint8_t *)&assoc_data,
+                                        SST_CRYPTO_ASSOCIATED_DATA_LEN);
+}
+
+/**
+ * \brief Authenticates table of objects.
+ *
+ * \param[in]     table_idx  Table index in the init context
+ * \param[in/out] init_ctx   Pointer to the object table to authenticate
+ *
+ */
+static void sst_object_table_authenticate(uint8_t table_idx,
+                                      struct sst_obj_table_init_ctx_t *init_ctx)
+{
+    struct sst_crypto_assoc_data_t assoc_data;
+    union sst_crypto_t *crypto = &init_ctx->p_table[table_idx]->crypto;
+    enum psa_sst_err_t err;
+
+    /* Init associated data with NVC 1 */
+    assoc_data.nv_counter = init_ctx->nvc_1;
+    sst_utils_memcpy(assoc_data.obj_table_data,
+                     SST_CRYPTO_ASSOCIATED_DATA(crypto),
+                     SST_OBJ_TABLE_AUTH_DATA_SIZE);
+
+    err = sst_crypto_authenticate(crypto, (const uint8_t *)&assoc_data,
+                                  SST_CRYPTO_ASSOCIATED_DATA_LEN);
+    if (err == PSA_SST_ERR_SUCCESS) {
+        init_ctx->table_state[table_idx] = SST_OBJ_TABLE_NVC_1_VALID;
+        return;
+    }
+
+    if (init_ctx->nvc_3 == SST_INVALID_NVC_VALUE) {
+        init_ctx->table_state[table_idx] = SST_OBJ_TABLE_INVALID;
+        return;
+    }
+
+    /* Check with NVC 3 */
+    assoc_data.nv_counter = init_ctx->nvc_3;
+
+    err = sst_crypto_authenticate(crypto, (const uint8_t *)&assoc_data,
+                                  SST_CRYPTO_ASSOCIATED_DATA_LEN);
+    if (err != PSA_SST_ERR_SUCCESS) {
+        init_ctx->table_state[table_idx] = SST_OBJ_TABLE_INVALID;
+    } else {
+        init_ctx->table_state[table_idx] = SST_OBJ_TABLE_NVC_3_VALID;
+    }
+}
+
+/**
+ * \brief Authenticates tables of objects.
+ *
+ * \param[in/out] init_ctx  Pointer to the object table to authenticate
+ *
+ * \return Returns error code as specified in \ref psa_sst_err_t
+ */
+__attribute__ ((always_inline))
+__STATIC_INLINE enum psa_sst_err_t sst_object_table_nvc_authenticate(
+                                      struct sst_obj_table_init_ctx_t *init_ctx)
+{
+    enum psa_sst_err_t err;
+    uint32_t nvc_2;
+
+    err = sst_read_nv_counter(TFM_SST_NV_COUNTER_1, &init_ctx->nvc_1);
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
+
+    err = sst_read_nv_counter(TFM_SST_NV_COUNTER_2, &nvc_2);
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
+
+    err = sst_read_nv_counter(TFM_SST_NV_COUNTER_3, &init_ctx->nvc_3);
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
+
+    /* Check if NVC 3 value can be used to validate an object table */
+    if (init_ctx->nvc_3 != nvc_2) {
+        /* If NVC 3 is different from NVC 2, it is possible to load an old SST
+         * area image in the system by manipulating the FS to return a system
+         * error from the file system layer and triggering power fault before
+         * increasing the NVC 3. So, in that case, NVC 3 value cannot be used to
+         * validate an old object table at the init process.
+         */
+        init_ctx->nvc_3 = SST_INVALID_NVC_VALUE;
+    }
+
+    /* Authenticate table 0 if data is valid */
+    if (init_ctx->table_state[SST_OBJ_TABLE_IDX_0] != SST_OBJ_TABLE_INVALID) {
+        sst_object_table_authenticate(SST_OBJ_TABLE_IDX_0, init_ctx);
+    }
+
+    /* Authenticate table 1 if data is valid */
+    if (init_ctx->table_state[SST_OBJ_TABLE_IDX_1] != SST_OBJ_TABLE_INVALID) {
+        sst_object_table_authenticate(SST_OBJ_TABLE_IDX_1, init_ctx);
+    }
+
+    return PSA_SST_ERR_SUCCESS;
+}
+#else /* SST_ROLLBACK_PROTECTION */
+
 /**
  * \brief Generates table authentication
  *
@@ -276,7 +479,8 @@
  *
  * \return Returns error code as specified in \ref psa_sst_err_t
  */
-static enum psa_sst_err_t sst_object_table_generate_auth_tag(
+__attribute__ ((always_inline))
+__STATIC_INLINE enum psa_sst_err_t sst_object_table_generate_auth_tag(
                                               struct sst_obj_table_t *obj_table)
 {
     union sst_crypto_t *crypto = &obj_table->crypto;
@@ -296,7 +500,7 @@
  *
  */
 __attribute__ ((always_inline))
-__STATIC_INLINE void sst_object_tables_authenticate(
+__STATIC_INLINE void sst_object_table_authenticate_ctx_tables(
                                       struct sst_obj_table_init_ctx_t *init_ctx)
 {
     enum psa_sst_err_t err;
@@ -304,30 +508,29 @@
                                 &init_ctx->p_table[SST_OBJ_TABLE_IDX_0]->crypto;
 
     /* Authenticate table 0 if data is valid */
-    if (init_ctx->invalid_table[SST_OBJ_TABLE_IDX_0] != SST_OBJ_TABLE_INVALID) {
+    if (init_ctx->table_state[SST_OBJ_TABLE_IDX_0] != SST_OBJ_TABLE_INVALID) {
         err = sst_crypto_authenticate(crypto,
                                       SST_CRYPTO_ASSOCIATED_DATA(crypto),
                                       SST_CRYPTO_ASSOCIATED_DATA_LEN);
         if (err != PSA_SST_ERR_SUCCESS) {
-            init_ctx->invalid_table[SST_OBJ_TABLE_IDX_0] =
-                                                          SST_OBJ_TABLE_INVALID;
+            init_ctx->table_state[SST_OBJ_TABLE_IDX_0] = SST_OBJ_TABLE_INVALID;
         }
     }
 
     /* Authenticate table 1 if data is valid */
-    if (init_ctx->invalid_table[SST_OBJ_TABLE_IDX_1] != SST_OBJ_TABLE_INVALID) {
+    if (init_ctx->table_state[SST_OBJ_TABLE_IDX_1] != SST_OBJ_TABLE_INVALID) {
         crypto = &init_ctx->p_table[SST_OBJ_TABLE_IDX_1]->crypto;
 
         err = sst_crypto_authenticate(crypto,
                                       SST_CRYPTO_ASSOCIATED_DATA(crypto),
                                       SST_CRYPTO_ASSOCIATED_DATA_LEN);
         if (err != PSA_SST_ERR_SUCCESS) {
-            init_ctx->invalid_table[SST_OBJ_TABLE_IDX_1] =
-                                                          SST_OBJ_TABLE_INVALID;
+            init_ctx->table_state[SST_OBJ_TABLE_IDX_1] = SST_OBJ_TABLE_INVALID;
         }
     }
 }
-#endif
+#endif /* SST_ROLLBACK_PROTECTION */
+#endif /* SST_ENCRYPTION */
 
 /**
  * \brief Saves object table in the persistent memory.
@@ -339,10 +542,21 @@
 static enum psa_sst_err_t sst_object_table_save_table(
                                               struct sst_obj_table_t *obj_table)
 {
-#ifdef SST_ENCRYPTION
     enum psa_sst_err_t err;
-#endif
 
+#ifdef SST_ROLLBACK_PROTECTION
+    uint32_t nvc_1 = 0;
+
+    err = sst_increment_nv_counter(TFM_SST_NV_COUNTER_1);
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
+
+    err = sst_read_nv_counter(TFM_SST_NV_COUNTER_1, &nvc_1);
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
+#else
     obj_table->swap_count++;
 
     if (obj_table->swap_count == SST_FLASH_DEFAULT_VAL) {
@@ -354,19 +568,42 @@
          */
         obj_table->swap_count = 0;
     }
+#endif /* SST_ROLLBACK_PROTECTION */
 
 #ifdef SST_ENCRYPTION
     /* Set object table key */
-    sst_object_table_set_crypto_key();
+    err = sst_object_table_set_crypto_key();
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
 
+#ifdef SST_ROLLBACK_PROTECTION
+    /* Generate authentication tag from the current table content and SST
+     * NV counter 1.
+     */
+    err = sst_object_table_nvc_generate_auth_tag(nvc_1, obj_table);
+#else
     /* Generate authentication tag from the current table content */
     err = sst_object_table_generate_auth_tag(obj_table);
+#endif /* SST_ROLLBACK_PROTECTION */
+
     if (err != PSA_SST_ERR_SUCCESS) {
         return err;
     }
 #endif /* SST_ENCRYPTION */
 
-    return sst_object_table_fs_write_table(obj_table);
+    err = sst_object_table_fs_write_table(obj_table);
+
+#ifdef SST_ROLLBACK_PROTECTION
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
+
+    /* Align SST NV counters to have the same value */
+    err = sst_object_table_align_nv_counters(nvc_1);
+#endif /* SST_ROLLBACK_PROTECTION */
+
+    return err;
 }
 
 /**
@@ -375,7 +612,8 @@
  * \param[in/out] init_ctx  Pointer to the init object table context
  *
  */
-static void sst_object_table_validate_version(
+__attribute__ ((always_inline))
+__STATIC_INLINE void sst_object_table_validate_version(
                                       struct sst_obj_table_init_ctx_t *init_ctx)
 {
     /* Looks for exact version number.
@@ -383,12 +621,12 @@
      */
     if (SST_OBJECT_SYSTEM_VERSION !=
         init_ctx->p_table[SST_OBJ_TABLE_IDX_0]->version) {
-        init_ctx->invalid_table[SST_OBJ_TABLE_IDX_0] = SST_OBJ_TABLE_INVALID;
+        init_ctx->table_state[SST_OBJ_TABLE_IDX_0] = SST_OBJ_TABLE_INVALID;
     }
 
     if (SST_OBJECT_SYSTEM_VERSION !=
         init_ctx->p_table[SST_OBJ_TABLE_IDX_1]->version) {
-        init_ctx->invalid_table[SST_OBJ_TABLE_IDX_1] = SST_OBJ_TABLE_INVALID;
+        init_ctx->table_state[SST_OBJ_TABLE_IDX_1] = SST_OBJ_TABLE_INVALID;
     }
 }
 
@@ -396,40 +634,54 @@
  * \brief Sets the active object table based on the swap count and validity of
  *        the object table data.
  *
- * \param[in] init_ctx Pointer to the init object table context
+ * \param[in] init_ctx  Pointer to the init object table context
  *
  */
 static enum psa_sst_err_t sst_set_active_object_table(
                                 const struct sst_obj_table_init_ctx_t *init_ctx)
 {
-
+#ifndef SST_ROLLBACK_PROTECTION
     uint8_t table0_swap_count =
                              init_ctx->p_table[SST_OBJ_TABLE_IDX_0]->swap_count;
     uint8_t table1_swap_count =
                              init_ctx->p_table[SST_OBJ_TABLE_IDX_1]->swap_count;
+#endif
 
     /* Check if there is an invalid object table */
-
-    if ((init_ctx->invalid_table[SST_OBJ_TABLE_IDX_0] == SST_OBJ_TABLE_INVALID)
-         && (init_ctx->invalid_table[SST_OBJ_TABLE_IDX_1] ==
+    if ((init_ctx->table_state[SST_OBJ_TABLE_IDX_0] == SST_OBJ_TABLE_INVALID)
+         && (init_ctx->table_state[SST_OBJ_TABLE_IDX_1] ==
                                                        SST_OBJ_TABLE_INVALID)) {
         /* Both tables are invalid */
         return PSA_SST_ERR_SYSTEM_ERROR;
-    } else if (init_ctx->invalid_table[SST_OBJ_TABLE_IDX_0] ==
+    } else if (init_ctx->table_state[SST_OBJ_TABLE_IDX_0] ==
                                                         SST_OBJ_TABLE_INVALID) {
-          /* Table 0 is invalid, the the active one is table 1 */
+          /* Table 0 is invalid, the active one is table 1 */
           sst_obj_table_ctx.active_table  = SST_OBJ_TABLE_IDX_1;
           sst_obj_table_ctx.scratch_table = SST_OBJ_TABLE_IDX_0;
 
           return PSA_SST_ERR_SUCCESS;
     } else {
-        /* Table 1 is invalid, the the active one is table 0 */
+        /* Table 1 is invalid, the active one is table 0 */
         sst_obj_table_ctx.active_table  = SST_OBJ_TABLE_IDX_0;
         sst_obj_table_ctx.scratch_table = SST_OBJ_TABLE_IDX_1;
 
         return PSA_SST_ERR_SUCCESS;
     }
 
+#ifdef SST_ROLLBACK_PROTECTION
+    if (init_ctx->table_state[SST_OBJ_TABLE_IDX_1] ==
+                                                    SST_OBJ_TABLE_NVC_1_VALID) {
+        /* Table 0 is invalid, the active one is table 1 */
+        sst_obj_table_ctx.active_table  = SST_OBJ_TABLE_IDX_1;
+        sst_obj_table_ctx.scratch_table = SST_OBJ_TABLE_IDX_0;
+    } else {
+        /* In case both tables are valid or table 0 is valid, table 0 is the
+         * valid on as it is already in the SST object table context.
+         */
+        sst_obj_table_ctx.active_table  = SST_OBJ_TABLE_IDX_0;
+        sst_obj_table_ctx.scratch_table = SST_OBJ_TABLE_IDX_1;
+    }
+#else
     /* Logic: if the swap count is 0, then it has rolled over. The object table
      * with a swap count of 0 is the latest one, unless the other block has a
      * swap count of 1, in which case the roll over occurred in the previous
@@ -464,7 +716,7 @@
         sst_obj_table_ctx.active_table  = SST_OBJ_TABLE_IDX_0;
         sst_obj_table_ctx.scratch_table = SST_OBJ_TABLE_IDX_1;
     }
-
+#endif /* SST_ROLLBACK_PROTECTION */
 
     /* If active object table is table 1, then copy the content into the
      * SST object table context.
@@ -510,7 +762,8 @@
  *
  * \return Returns free index in the table
  */
-static uint32_t sst_table_free_idx(void)
+__attribute__ ((always_inline))
+__STATIC_INLINE uint32_t sst_table_free_idx(void)
 {
     uint32_t idx;
     struct sst_obj_table_t *p_table = &sst_obj_table_ctx.obj_table;
@@ -548,6 +801,16 @@
 {
     struct sst_obj_table_t *p_table = &sst_obj_table_ctx.obj_table;
 
+#ifdef SST_ROLLBACK_PROTECTION
+    enum psa_sst_err_t err;
+
+    /* Initialize SST NV counters */
+    err = sst_init_nv_counter();
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
+#endif
+
     /* Initialize object structure */
     sst_utils_memset(&sst_obj_table_ctx, SST_DEFAULT_EMPTY_BUFF_VAL,
                      sizeof(struct sst_obj_table_ctx_t));
@@ -555,7 +818,7 @@
     /* Invert the other in the context as sst_object_table_save_table will
      * use the scratch index to create and store the current table.
      */
-    sst_obj_table_ctx.active_table = SST_OBJ_TABLE_IDX_1;
+    sst_obj_table_ctx.active_table  = SST_OBJ_TABLE_IDX_1;
     sst_obj_table_ctx.scratch_table = SST_OBJ_TABLE_IDX_0;
 
     p_table->version = SST_OBJECT_SYSTEM_VERSION;
@@ -569,7 +832,7 @@
     enum psa_sst_err_t err;
     struct sst_obj_table_init_ctx_t init_ctx = {
         .p_table = {&sst_obj_table_ctx.obj_table, 0},
-        .invalid_table = {0, 0}
+        .table_state = {0, 0}
     };
 
     init_ctx.p_table[SST_OBJ_TABLE_IDX_1] = (struct sst_obj_table_t *)obj_data;
@@ -579,10 +842,27 @@
 
 #ifdef SST_ENCRYPTION
     /* Set object table key */
-    sst_object_table_set_crypto_key();
+    err = sst_object_table_set_crypto_key();
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
+
+#ifdef SST_ROLLBACK_PROTECTION
+    /* Initialize SST NV counters */
+    err = sst_init_nv_counter();
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
 
     /* Authenticate table */
-    sst_object_tables_authenticate(&init_ctx);
+    err = sst_object_table_nvc_authenticate(&init_ctx);
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
+#else
+    sst_object_table_authenticate_ctx_tables(&init_ctx);
+#endif /* SST_ROLLBACK_PROTECTION */
+
 #endif /* SST_ENCRYPTION */
 
     /* Check tables version */
@@ -601,6 +881,18 @@
         return err;
     }
 
+#ifdef SST_ROLLBACK_PROTECTION
+    /* Align SST NV counters */
+    err = sst_object_table_align_nv_counters(init_ctx.nvc_1);
+    if (err != PSA_SST_ERR_SUCCESS) {
+        return err;
+    }
+#endif /* SST_ROLLBACK_PROTECTION */
+
+#ifdef SST_ENCRYPTION
+    sst_crypto_set_iv(&sst_obj_table_ctx.obj_table.crypto);
+#endif
+
 #ifdef SST_ENCRYPTION
     sst_crypto_set_iv(&sst_obj_table_ctx.obj_table.crypto);
 #endif
diff --git a/secure_fw/services/secure_storage/sst_object_table.h b/secure_fw/services/secure_storage/sst_object_table.h
index 9c55158..78c48c9 100644
--- a/secure_fw/services/secure_storage/sst_object_table.h
+++ b/secure_fw/services/secure_storage/sst_object_table.h
@@ -70,7 +70,7 @@
 
 /**
  * \brief Sets object's internal information in the object table and
- *        stores it persitently.
+ *        stores it persistently.
  *
  * \param[in] uuid          Object UUID
  * \param[in] obj_tbl_info  Pointer to the location to store object table