Skip to content

Commit

Permalink
feat: add option to link against custom crypto implementations
Browse files Browse the repository at this point in the history
We seek the option to link against custom crypto implementations
to be used for key storage and crypto computational tasks.
This is introduced as an configurable option.

In the work, common crypto part of the codespace
has been moved public include file folder.

Add feature that ensured that the externally loaded keys
are memzero'ed after their use.

Add automated build processes with multiple different
compiler types and CMake flag combinations.
More might be added in the future.

Update the repository documentation for external key loading.

---------

Co-authored-by: Benjamin Bruun <[email protected]>
  • Loading branch information
peterbornerup and benjaminbruun committed Jul 30, 2024
1 parent bd06b44 commit 70d714c
Show file tree
Hide file tree
Showing 20 changed files with 306 additions and 76 deletions.
24 changes: 23 additions & 1 deletion .github/workflows/cmake-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ concurrency:

jobs:
cmake-build-and-test:
strategy:
matrix:
flags: ["", "-DCONFIG_EXTERNAL_KEY_LOAD=y"]
compiler: [gcc, clang]

runs-on: ubuntu-20.04
timeout-minutes: 15

Expand All @@ -26,11 +31,28 @@ jobs:

- name: Install Embedded Toolchain
uses: carlosperate/[email protected]
if: matrix.compiler == 'gcc'

- name: Install CLANG
run: |
sudo apt-get update
sudo apt-get install -y clang
if: matrix.compiler == 'clang'

- name: Add key loaders to tests
run: |
echo "void ss_load_key_external(const uint8_t *key_id, size_t in_len, uint8_t *key, size_t *key_len){memcpy(key, key_id, in_len);*key_len = in_len;}" >> src/softsim/main.c
echo "void ss_load_key_external(const uint8_t *key_id, size_t in_len, uint8_t *key, size_t *key_len){memcpy(key, key_id, in_len);*key_len = in_len;}" >> tests/ota/ota_test.c
echo "void ss_load_key_external(const uint8_t *key_id, size_t in_len, uint8_t *key, size_t *key_len){memcpy(key, key_id, in_len);*key_len = in_len;}" >> tests/aes/aes_test.c
if: matrix.flags == '-DCONFIG_EXTERNAL_KEY_LOAD=y'

- name: Configure and Build Project
run: |
cmake -S . -B build -DBUILD_TESTING=y -DCONFIG_USE_SYSTEM_HEAP=y -DCONFIG_ENABLE_SANITIZE=y
cmake -S . -B build -DBUILD_TESTING=y -DCONFIG_USE_SYSTEM_HEAP=y -DCONFIG_ENABLE_SANITIZE=y ${{ matrix.flags }}
cmake --build build
env:
CC: ${{ matrix.compiler }}
CXX: ${{ matrix.compiler }}++

- name: Test Project
run: cd build && ctest --output-on-failure
Expand Down
17 changes: 16 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ option(CONFIG_ENABLE_SANITIZE "Build with -fsanitize=address -fsanitize=undefine
option(CONFIG_USE_SYSTEM_HEAP "Use free/malloc instead of port_free/port_malloc")
option(CONFIG_USE_LOGS "Set SS_LOGP macro to link against ss_logp")
option(CONFIG_USE_EXPERIMENTAL_SUSPEND_COMMAND "Building with experimental support for suspend")
option(CONFIG_USE_UTILS "Use the extra functionality found in the collective utils folder" ON)
option(CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION "Use external crypto implementations")
option(CONFIG_EXTERNAL_KEY_LOAD "Use crypto exstension for loading keys")
option(CONFIG_USE_UTILS "Use the extra functionality found in the collective utils folder")

if(CONFIG_USE_SYSTEM_HEAP)
add_compile_definitions(CONFIG_USE_SYSTEM_HEAP)
Expand All @@ -26,6 +28,19 @@ if(CONFIG_USE_EXPERIMENTAL_SUSPEND_COMMAND)
add_compile_definitions(CONFIG_USE_EXPERIMENTAL_SUSPEND_COMMAND)
endif()

if(CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION AND CONFIG_EXTERNAL_KEY_LOAD)
message(FATAL_ERROR "CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION and CONFIG_EXTERNAL_KEY_LOAD should not be used together")
endif()

if(CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION)
message(STATUS "Using external crypto implementation")
add_compile_definitions(-DCONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION)
endif()

if(CONFIG_EXTERNAL_KEY_LOAD)
add_compile_definitions(-DCONFIG_EXTERNAL_KEY_LOAD)
endif()

if(CONFIG_ENABLE_SANITIZE)
add_compile_options(-fsanitize=address -fsanitize=undefined)
add_link_options(-fsanitize=address -fsanitize=undefined)
Expand Down
35 changes: 27 additions & 8 deletions include/onomondo/softsim/config.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
#ifndef INCLUDE_ONOMONDO_SOFTSIM_CONFIG_H_
#define INCLUDE_ONOMONDO_SOFTSIM_CONFIG_H_
/*
* Copyright (c) 2024 Onomondo ApS. All rights reserved.
*
* SPDX-License-Identifier: GPL-3.0-only
*/

/*
* This file solely exist to print config opitons at compile time
*/
#pragma once

#ifdef CONFIG_USE_SYSTEM_HEAP
#pragma message "Using CONFIG_USE_SYSTEM_HEAP"
#else // DEFAULT
#pragma message "Using port_malloc and port_free instead of system default"
#endif // CONFIG_USE_SYSTEM_HEAP
#pragma message "Using CONFIG_USE_SYSTEM_HEAP"
#else
#pragma message "Using port_malloc and port_free instead of system default"
#endif // CONFIG_USE_SYSTEM_HEAP

#ifdef CONFIG_USE_EXPERIMENTAL_SUSPEND_COMMAND
#pragma message "Building with experimental support for suspend"
#pragma message "Building with experimental support for suspend"
#endif // CONFIG_USE_EXPERIMENTAL_SUSPEND_COMMAND
#endif // INCLUDE_ONOMONDO_SOFTSIM_CONFIG_H_

#if defined(CONFIG_EXTERNAL_KEY_LOAD) && defined(CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION)
#error "External CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION implementation and CONFIG_EXTERNAL_KEY_LOAD should not be enabled at the same time."
#endif // CONFIG_EXTERNAL_KEY_LOAD && EXTERNAL_CRYPTO_IMPLEMENTATION

#ifdef CONFIG_EXTERNAL_KEY_LOAD
#pragma message "Enabling CONFIG_EXTERNAL_KEY_LOAD"
#endif // CONFIG_EXTERNAL_KEY_LOAD

#ifdef CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION
#pragma message "Enabling CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION"
#endif // CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION

64 changes: 64 additions & 0 deletions include/onomondo/softsim/crypto.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2024 Onomondo ApS. All rights reserved.
*
* SPDX-License-Identifier: GPL-3.0-only
*/

#pragma once

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

#define AES_BLOCKSIZE 16

/* See also ETSI TS 102 225, section 5.1.1 and 5.1.2 */
enum enc_algorithm {
NONE,
TRIPLE_DES_CBC2,
AES_CBC,
AES_CMAC,
};

/*! Perform an in-place AES decryption with the common settings of OTA
* (CBC mode, zero IV).
* \param[inout] buffer user provided memory with plaintext to decrypt.
* \param[in] buffer_len length of the plaintext data to decrypt (multiple of 16).
* \param[in] key AES key.
* \param[in] key_len length of the AES key. */
void ss_utils_aes_decrypt(uint8_t *buffer, size_t buffer_len, const uint8_t *key, size_t key_len);

/*! Perform an in-place AES encryption with the common settings of OTA
* (CBC mode, zero IV).
* \param[inout] buffer user provided memory with plaintext to encrypt.
* \param[in] buffer_len length of the plaintext data to encrypt (multiple of 16).
* \param[in] key 16 byte AES key.
* \param[in] key_len length of the AES key. */
void ss_utils_aes_encrypt(uint8_t *buffer, size_t buffer_len, const uint8_t *key, size_t key_len);

/*! Perform an in-place 3DES decryption with the common settings of OTA
* (CBC mode, 16-byte key, zero IV).
* \param[inout] buffer user provided memory with plaintext to decrypt.
* \param[in] buffer_len length of the plaintext data to decrypt (multiple of 8).
* \param[in] key 16 byte DES key. */
void ss_utils_3des_decrypt(uint8_t *buffer, size_t buffer_len, const uint8_t *key);

/*! Perform an in-place 3DES encryption with the common settings of OTA
* (CBC mode, 16-byte key, zero IV).
* \param[inout] buffer user provided memory with plaintext to encrypt.
* \param[in] buffer_len length of the plaintext data to encrypt (multiple of 8).
* \param[in] key 16 byte DES key. */
void ss_utils_3des_encrypt(uint8_t *buffer, size_t buffer_len, const uint8_t *key);

/*! Calculate cryptographic checksum (CC) using a specified algorithm.
* \param[out] cc user provided memory for resulting cryptographic checksum.
* \param[out] cc_len length of user provided memory for resulting cryptographic checksum.
* \param[in] key cryptographic key.
* \param[in] key_len cryptographic key length.
* \param[in] data1 user buffer containing part 1 of the data.
* \param[in] data1_len length of data part 1 (must be multiple of blocksize)
* \param[in] data2 user buffer containing part 2 of the data.
* \param[in] data2_len length of data part 2 (unpadded).
* \returns 0 on success, -EINVAL on error. */
int ss_utils_ota_calc_cc(uint8_t *cc, size_t cc_len, uint8_t *key, size_t key_len, enum enc_algorithm alg,
uint8_t *data1, size_t data1_len, uint8_t *data2, size_t data2_len);
44 changes: 44 additions & 0 deletions include/onomondo/utils/ss_crypto_extension.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2024 Onomondo ApS. All rights reserved.
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#pragma once

/*
* Motivation here is to provide a simple mechanism for importing keys from
* different locations than the file-system. Some platforms are very limited
* w.r.t. security and crypto engines.
*
* By doing this we can with relative ease enable the use of
* dedicated secure zones. Those zones however aren't suitable for storing all
* SoftSIM internal data. This is _a_ compromise that allows some sense of secure key storage.
*
* This mechanism is completely optional. By storing the key identifiers instead of keys in the
* A00X files we can use the key ID to fetch the correct key from secure storage. The keys will still
* live in potential non-secure RAM while in use. Immediately after use the keys are zeroed out.
*
* At all times where a dedicated crypto engine or other secure implementations exist (i.e. ARM TrustZone)
* the CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION should be used.
*
* This function is called immediately before the block encryption/decryption is carried out.
*/

#ifdef CONFIG_EXTERNAL_KEY_LOAD

#include <stddef.h>
#include <stdint.h>
#include <string.h>
/*!
* \brief Load a key from an external source
*
* This function is called when the SoftSIM needs to load a key from an external
* source. The key is loaded into the buffer provided.
*
* \param key_id buffer with the key ID.
* \param key buffer with the resolved key. The key is loaded into this buffer.
* \param in_len Length of the key_id buffer
* \param key_len Length of the key_buffer. After loading the key this should hold the length of the key.
*/
void ss_load_key_external(const uint8_t *key_id, size_t in_len, uint8_t *key, size_t *key_len) __attribute__((weak));
#endif /* ifdef CONFIG_EXTERNAL_KEY_LOAD */
3 changes: 2 additions & 1 deletion src/softsim/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ add_library(storage STATIC storage.c fs.c)
target_include_directories(storage PUBLIC ${CMAKE_SOURCE_DIR}/include)

add_executable(softsim main.c)
target_link_libraries(softsim uicc milenage crypto storage)
target_link_libraries(softsim uicc milenage crypto storage $<$<TARGET_EXISTS:utils>:utils>)

19 changes: 11 additions & 8 deletions src/softsim/crypto/aes-encblock.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
* See README for more details.
*/

#include <onomondo/softsim/crypto.h>
#include "includes.h"

#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
Expand All @@ -18,15 +18,18 @@
* @key: Key for AES
* @in: Input data (16 bytes)
* @out: Output of the AES block operation (16 bytes)
* Returns: 0 on success, -1 on failure
* Returns: 0
*/

/* adjusted from Jouni Malinen impl */
int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
{
void *ctx;
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
aes_encrypt(ctx, in, out);
aes_encrypt_deinit(ctx);
// ss_utils_aes_encrypt will overwrite input buffer
uint8_t buf[AES_BLOCK_SIZE];
memcpy(buf, in, AES_BLOCK_SIZE);

ss_utils_aes_encrypt(buf, AES_BLOCK_SIZE, key, AES_BLOCK_SIZE);
memcpy(out, buf, AES_BLOCK_SIZE);

return 0;
}
6 changes: 3 additions & 3 deletions src/softsim/uicc/uicc_remote_cmd.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2024 Onomondo ApS. All rights reserved.
*
* SPDX-License-Identifier: GPL-3.0-only
*
* SPDX-License-Identifier: GPL-3.0-only
*/

#include "uicc_remote_cmd.h"
Expand All @@ -14,6 +14,7 @@
#include <onomondo/softsim/file.h>
#include <onomondo/softsim/log.h>
#include <onomondo/softsim/softsim.h>
#include <onomondo/softsim/crypto.h>

#include "context.h"
#include "fcp.h"
Expand All @@ -22,7 +23,6 @@
#include "uicc_pin.h"
#include "utils.h"
#include "utils_3des.h"
#include "utils_aes.h"
#include "utils_ota.h"

/* Information element identifier for command packets, as used in TS 23.048
Expand Down
3 changes: 3 additions & 0 deletions src/softsim/uicc/utils_3des.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
#include "utils.h"
#include "utils_3des.h"
#include "crypto/des_i.h"
#include <onomondo/softsim/crypto.h>

#ifndef CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION
void setup_key(const uint8_t *src, struct des3_key_s *dest)
{
/* The library wants keys in 24byte form, but we have the 16byte form */
Expand Down Expand Up @@ -137,3 +139,4 @@ void ss_utils_3des_cc_cleanup(struct utils_3des_cc_ctx *cc)
ss_memzero(cc->key, sizeof(cc->key));
SS_FREE(cc->key);
}
#endif // CONFIG_EXTERNAL_CRYPTO_IMPLEMENTATION
15 changes: 6 additions & 9 deletions src/softsim/uicc/utils_3des.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
/*
* Copyright (c) 2024 Onomondo ApS. All rights reserved.
*
* SPDX-License-Identifier: GPL-3.0-only
*
* SPDX-License-Identifier: GPL-3.0-only
*/

#pragma once

#include <stddef.h>
#include <stdint.h>

#define DES_BLOCKSIZE 8
#define TRIPLE_DES_KEYLEN 16

void ss_utils_3des_decrypt(uint8_t *buffer, size_t buffer_len,
const uint8_t *key);
void ss_utils_3des_encrypt(uint8_t *buffer, size_t buffer_len,
const uint8_t *key);

struct des3_key_s;
struct utils_3des_cc_ctx {
struct des3_key_s *key;
Expand All @@ -23,6 +21,5 @@ struct utils_3des_cc_ctx {
};

void ss_utils_3des_cc_setup(struct utils_3des_cc_ctx *cc, const uint8_t *key);
void ss_utils_3des_cc_feed(struct utils_3des_cc_ctx *cc, const uint8_t *data,
size_t data_len);
void ss_utils_3des_cc_feed(struct utils_3des_cc_ctx *cc, const uint8_t *data, size_t data_len);
void ss_utils_3des_cc_cleanup(struct utils_3des_cc_ctx *cc);
Loading

0 comments on commit 70d714c

Please sign in to comment.