Skip to content

Commit

Permalink
ITS: Add support for encrypted ITS
Browse files Browse the repository at this point in the history
-Adds encryption and authentication support for ITS files
-Encryption is optional and is enabled using a CMake variable
-The encryption implementation is platform dependent,
 the signatures of the APIs are provided in this change

Change-Id: Ifd3a67ac2274fa8d7ceec19482f7cec01b2cac54
Signed-off-by: Markus Swarowsky <markus.swarowsky@nordicsemi.no>
  • Loading branch information
mswarowsky authored and David Hu committed Jul 10, 2023
1 parent 9d05a53 commit 7de096f
Show file tree
Hide file tree
Showing 17 changed files with 984 additions and 98 deletions.
1 change: 1 addition & 0 deletions config/config_base.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ set(PS_ENCRYPTION ON CACHE BOOL "Enable encr
set(PS_CRYPTO_AEAD_ALG PSA_ALG_GCM CACHE STRING "The AEAD algorithm to use for authenticated encryption in Protected Storage")

set(TFM_PARTITION_INTERNAL_TRUSTED_STORAGE OFF CACHE BOOL "Enable Internal Trusted Storage partition")
set(ITS_ENCRYPTION OFF CACHE BOOL "Enable authenticated encryption of ITS files using platform specific APIs")

set(TFM_PARTITION_CRYPTO OFF CACHE BOOL "Enable Crypto partition")
set(CRYPTO_TFM_BUILTIN_KEYS_DRIVER ON CACHE BOOL "Whether to allow crypto service to store builtin keys. Without this, ALL builtin keys must be stored in a platform-specific location")
Expand Down
10 changes: 10 additions & 0 deletions config/config_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,16 @@
#define ITS_STACK_SIZE 0x720
#endif

/* The size of the authentication tag used when authentication/encryption of ITS files is enabled */
#ifndef TFM_ITS_AUTH_TAG_LENGTH
#define TFM_ITS_AUTH_TAG_LENGTH 16
#endif

/* The size of the nonce used when ITS file encryption is enabled */
#ifndef TFM_ITS_ENC_NONCE_LENGTH
#define TFM_ITS_ENC_NONCE_LENGTH 12
#endif

/* PS Partition Configs */

/* Create flash FS if it doesn't exist for Protected Storage partition */
Expand Down
4 changes: 4 additions & 0 deletions docs/design_docs/media/tfm_its_encryption.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions docs/design_docs/services/tfm_its_service.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ manifest)
- ``tfm_internal_trusted_storage.h`` - TF-M ITS API (with client_id parameter)
- ``tfm_internal_trusted_storage.c`` - TF-M ITS implementation, using the
flash_fs as a backend
- ``its_crypto_interface.h`` - APIs for encrypting ITS assets used by ITS implementation (optional)
- ``its_crypto_interface.c`` - Implementation for ITS encryption (optional)
- ``platform/ext/target/.../tfm_hal_its_encryption.c`` - Platform implementation for ITS encryption HAL APIs (optional)
- ``flash_fs/`` - Filesystem
- ``flash/`` - Flash interface

Expand Down Expand Up @@ -280,6 +283,60 @@ implemented separately, as would some way of isolating static memory belonging
to each partition but not the code. Because of these complications, this option
has not been considered further at this time.


Encryption in ITS
=================

The ITS can optionally be configured to encrypt the internal trusted storage
data.
To support encryption in ITS the target platform must provide an
implementation of the APIs defined in ``platform/include/tfm_hal_its_encryption.h``::

enum tfm_hal_status_t tfm_hal_its_aead_generate_nonce(uint8_t *nonce,
const size_t nonce_size);

enum tfm_hal_status_t tfm_hal_its_aead_encrypt(
struct tfm_hal_its_auth_crypt_ctx *ctx,
const uint8_t *plaintext,
const size_t plaintext_size,
uint8_t *ciphertext,
const size_t ciphertext_size,
uint8_t *tag,
const size_t tag_size);

enum tfm_hal_status_t tfm_hal_its_aead_decrypt(
struct tfm_hal_its_auth_crypt_ctx *ctx,
const uint8_t *ciphertext,
const size_t ciphertext_size,
uint8_t *tag,
const size_t tag_size,
uint8_t *plaintext,
const size_t plaintext_size);


Then encryption can be enabled by setting the build option ``-DITS_ENCRYPTION=ON``.

The figure :numref:`fig-tfm_eits` describes the encryption and decryption
process happening when calling ``tfm_its_set`` and ``tfm_its_get``.

.. figure:: /design_docs/media/tfm_its_encryption.*
:align: center
:name: fig-tfm_eits
:width: 80%

En/Decryption of ITS

By using an AEAD scheme, it is possible to not only encrypt the file data but
also authenticate the file meta data, which include:

- File id
- File size
- File flags

The key used to perform the AEAD operation must be derived from a long-term
key-derivation key and the file id, which is used as a derivation label.
The long-term key-derivation key must be managed by the target platform.

--------------

*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
1 change: 1 addition & 0 deletions platform/ext/target/nordic_nrf/common/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ target_sources(platform_s
native_drivers/spu.c
$<$<OR:$<BOOL:${TFM_S_REG_TEST}>,$<BOOL:${TFM_NS_REG_TEST}>>:${CMAKE_CURRENT_SOURCE_DIR}/plat_test.c>
$<$<BOOL:${TEST_PSA_API}>:${CMAKE_CURRENT_SOURCE_DIR}/pal_plat_test.c>
$<$<BOOL:${ITS_ENCRYPTION}>:${CMAKE_CURRENT_SOURCE_DIR}/tfm_hal_its_encryption.c>
)

if (NRF_HW_INIT_RESET_ON_BOOT)
Expand Down
264 changes: 264 additions & 0 deletions platform/ext/target/nordic_nrf/common/core/tfm_hal_its_encryption.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <stdint.h>
#include <string.h>


#include "config_tfm.h"
#include "platform/include/tfm_hal_its_encryption.h"
#include "platform/include/tfm_hal_its.h"
#include "platform/include/tfm_platform_system.h"
#include "psa/crypto.h"

/* The cc3xx driver is used directly in this file as the PSA Crypto service
* depends on ITS, so using PSA Crypto APIs would result in circular
* dependencies
*/
#include "nrf_cc3xx_platform_derived_key.h"
#include "nrf_cc3xx_platform_kmu.h"
#include "nrf_cc3xx_platform.h"

#define ITS_ENCRYPTION_SUCCESS 0

#define HUK_KMU_SLOT 2
#define HUK_KMU_SIZE_BITS 128

/* Global encryption counter which resets per boot. The counter ensures that
* the nonce will not be identical for consecutive file writes during the same
* boot.
*/
static uint32_t g_enc_counter;

/* The global nonce seed which is fetched once in every boot. The seed is used
* as part of the nonce and allows the platforms to diversify their nonces
* across resets. Note that the way that this seed is generated is platform
* specific, so the diversification is optional.
*/
static uint8_t g_enc_nonce_seed[TFM_ITS_ENC_NONCE_LENGTH -
sizeof(g_enc_counter)];

/* TFM_ITS_ENC_NONCE_LENGTH is configurable but this implementation expects
* the seed to be 8 bytes and the nonce length to be 12.
*/
#if TFM_ITS_ENC_NONCE_LENGTH != 12
#error "This implementation only supports a ITS nonce of size 12"
#endif

/*
* This implementation doesn't use monotonic counters, but therfore a 64 bit
* seed combined with a counter, that gets reset on each reboot.
* This still has the risk of getting a collision on the seed resulting in
* nonce's beeing the same after a reboot.
* It would still need 3.3x10^9 resets to get a collision with a probability of
* 0.25.
*/
enum tfm_hal_status_t tfm_hal_its_aead_generate_nonce(uint8_t *nonce,
const size_t nonce_size)
{
int err;

if(nonce == NULL){
return TFM_HAL_ERROR_INVALID_INPUT;
}

if(nonce_size < sizeof(g_enc_nonce_seed) + sizeof(g_enc_counter)){
return TFM_HAL_ERROR_INVALID_INPUT;
}

/* To avoid wrap-around of the g_enc_counter and subsequent re-use of the
* nonce we check the counter value for its max value
*/
if(g_enc_counter == UINT32_MAX) {
return TFM_HAL_ERROR_GENERIC;
}

if (g_enc_counter == 0) {
err = nrf_cc3xx_platform_get_nonce_seed(g_enc_nonce_seed);
if (err != 0) {
return TFM_HAL_ERROR_GENERIC;
}
}

memcpy(nonce, g_enc_nonce_seed, sizeof(g_enc_nonce_seed));
memcpy(nonce + sizeof(g_enc_nonce_seed),
&g_enc_counter,
sizeof(g_enc_counter));

g_enc_counter++;

return TFM_HAL_SUCCESS;
}

static bool ctx_is_valid(struct tfm_hal_its_auth_crypt_ctx *ctx)
{
bool ret;

if (ctx == NULL) {
return false;
}

ret = (ctx->deriv_label == NULL && ctx->deriv_label_size != 0) ||
(ctx->aad == NULL && ctx->add_size != 0) ||
(ctx->nonce == NULL && ctx->nonce_size != 0);

return !ret;
}

static enum tfm_hal_status_t tfm_hal_its_aead_init(
struct tfm_hal_its_auth_crypt_ctx *ctx,
nrf_cc3xx_platform_derived_key_ctx_t *platform_ctx,
uint8_t *tag,
size_t tag_size)
{

int err = NRF_CC3XX_PLATFORM_ERROR_INTERNAL;


err = nrf_cc3xx_platform_derived_key_init(platform_ctx);
if (err != NRF_CC3XX_PLATFORM_SUCCESS) {
return TFM_HAL_ERROR_GENERIC;
}

err = nrf_cc3xx_platform_derived_key_set_info(platform_ctx,
HUK_KMU_SLOT,
HUK_KMU_SIZE_BITS,
ctx->deriv_label,
ctx->deriv_label_size);
if (err != NRF_CC3XX_PLATFORM_SUCCESS) {
return TFM_HAL_ERROR_INVALID_INPUT;
}

err = nrf_cc3xx_platform_derived_key_set_cipher(platform_ctx,
ALG_CHACHAPOLY_256_BIT);

if (err != NRF_CC3XX_PLATFORM_SUCCESS) {
return TFM_HAL_ERROR_INVALID_INPUT;
}

err = nrf_cc3xx_platform_derived_key_set_auth_info(platform_ctx,
ctx->nonce,
ctx->nonce_size,
ctx->aad,
ctx->add_size,
tag,
tag_size);
if (err != NRF_CC3XX_PLATFORM_SUCCESS) {
return TFM_HAL_ERROR_INVALID_INPUT;
}

return TFM_HAL_SUCCESS;
}

static void tfm_hal_its_aead_cleanup(
nrf_cc3xx_platform_derived_key_ctx_t *platform_ctx)
{
if(platform_ctx != NULL){
memset(platform_ctx,
0x0,
sizeof(nrf_cc3xx_platform_derived_key_ctx_t));
}
}

enum tfm_hal_status_t tfm_hal_its_aead_encrypt(
struct tfm_hal_its_auth_crypt_ctx *ctx,
const uint8_t *plaintext,
const size_t plaintext_size,
uint8_t *ciphertext,
const size_t ciphertext_size,
uint8_t *tag,
const size_t tag_size)
{
nrf_cc3xx_platform_derived_key_ctx_t platform_ctx = {0};
enum tfm_hal_status_t err = TFM_HAL_ERROR_GENERIC;
int plat_err = NRF_CC3XX_PLATFORM_ERROR_INTERNAL;

if (!ctx_is_valid(ctx) || tag == NULL) {
return TFM_HAL_ERROR_INVALID_INPUT;
}

if (plaintext_size > ciphertext_size) {
return TFM_HAL_ERROR_INVALID_INPUT;
}

err = tfm_hal_its_aead_init(ctx,
&platform_ctx,
tag,
tag_size);
if (err != TFM_HAL_SUCCESS) {
tfm_hal_its_aead_cleanup(&platform_ctx);
return err;
}


plat_err = nrf_cc3xx_platform_derived_key_encrypt(&platform_ctx,
ciphertext,
plaintext_size,
plaintext);

tfm_hal_its_aead_cleanup(&platform_ctx);

if (plat_err != NRF_CC3XX_PLATFORM_SUCCESS) {
return TFM_HAL_ERROR_GENERIC;
}

return TFM_HAL_SUCCESS;
}

enum tfm_hal_status_t tfm_hal_its_aead_decrypt(
struct tfm_hal_its_auth_crypt_ctx *ctx,
const uint8_t *ciphertext,
const size_t ciphertext_size,
uint8_t *tag,
const size_t tag_size,
uint8_t *plaintext,
const size_t plaintext_size)
{
nrf_cc3xx_platform_derived_key_ctx_t platform_ctx = {0};
enum tfm_hal_status_t err = TFM_HAL_ERROR_GENERIC;
int plat_err = NRF_CC3XX_PLATFORM_ERROR_INTERNAL;

if (!ctx_is_valid(ctx) || tag == NULL) {
return TFM_HAL_ERROR_INVALID_INPUT;
}

if (plaintext_size < ciphertext_size) {
return TFM_HAL_ERROR_INVALID_INPUT;
}

err = tfm_hal_its_aead_init(ctx,
&platform_ctx,
tag,
tag_size);
if (err != TFM_HAL_SUCCESS) {
tfm_hal_its_aead_cleanup(&platform_ctx);
return err;
}


plat_err = nrf_cc3xx_platform_derived_key_decrypt(&platform_ctx,
plaintext,
ciphertext_size,
ciphertext);
tfm_hal_its_aead_cleanup(&platform_ctx);

if (plat_err != NRF_CC3XX_PLATFORM_SUCCESS) {
return TFM_HAL_ERROR_GENERIC;
}

return TFM_HAL_SUCCESS;
}

Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ target_sources(platform_s
target_compile_definitions(platform_s
PUBLIC
NRF_SKIP_FICR_NS_COPY_TO_RAM
$<$<BOOL:${ITS_ENCRYPTION}>:ITS_ENCRYPTION>
)

#========================= Platform Non-Secure ================================#
Expand Down
1 change: 1 addition & 0 deletions platform/ext/target/nordic_nrf/common/nrf91/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ target_sources(platform_s
target_compile_definitions(platform_s
PUBLIC
NRF_SKIP_FICR_NS_COPY_TO_RAM
$<$<BOOL:${ITS_ENCRYPTION}>:ITS_ENCRYPTION>
)

#========================= Platform Non-Secure ================================#
Expand Down
Loading

0 comments on commit 7de096f

Please sign in to comment.