Skip to content

Commit

Permalink
Add support for embedded Zephyr RTOS (#1621)
Browse files Browse the repository at this point in the history
* Zephyr RTOS support

This commit adds initial support for the zephyr operating system. Some
minor changes to the library build system have been made for it to be
compilable with zephyr. Furthermore, we added support for an embedded
build option to disable standard library methods for random number
generation.

* Zephyr: added algorithm selection

The algorithms can now be selected with Kconfig. Per default, we only
enable the algorithms selected by NIST to be standardized. However, all
supported algorithms can be enabled or disabled individually on a per
project basis.

* Zephyr: added testable samples

Added two sample applications within the zephyr directory for KEMs and
Signatures. These are also intended for CI testing.

* Zephyr: added CI tests

* Zephyr: Add documentation

Signed-off-by: Tobias Frauenschläger <[email protected]>
  • Loading branch information
Frauschi authored Dec 20, 2023
1 parent 8449e54 commit 4906c3f
Show file tree
Hide file tree
Showing 20 changed files with 858 additions and 21 deletions.
2 changes: 1 addition & 1 deletion .CMake/compiler_opts.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
add_compile_options(${OQS_OPT_FLAG})

# If this is not a dist build we also need to set the OQS_USE_[EXTENSION] flags
if(NOT ${OQS_DIST_BUILD})
if(NOT ${OQS_DIST_BUILD} AND NOT CMAKE_CROSSCOMPILING)
include(${CMAKE_CURRENT_LIST_DIR}/gcc_clang_intrinsics.cmake)
endif()
endif()
Expand Down
46 changes: 46 additions & 0 deletions .github/workflows/zephyr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Zephyr tests

on: [push, pull_request]

jobs:

zephyr_test:
runs-on: ubuntu-22.04
container: ghcr.io/zephyrproject-rtos/ci:latest
env:
CMAKE_PREFIX_PATH: /opt/toolchains
strategy:
fail-fast: false
matrix:
config:
- zephyr-ref: v3.4.0
- zephyr-ref: v3.5.0

steps:
- name: Init west workspace
run: west init --mr ${{ matrix.config.zephyr-ref }} zephyr

- name: Update west.yml
working-directory: zephyr/zephyr
run: |
REF=$(echo '${{ github.ref }}' | sed -e 's/\//\\\//g')
sed -e 's/remotes:/remotes:\n \- name: liboqs\n url\-base: https:\/\/github.com\/${{ github.repository_owner }}/' -i west.yml
sed -e "s/projects:/projects:\n \- name: liboqs\n path: modules\/crypto\/liboqs\n remote: liboqs\n revision: $REF/" -i west.yml
- name: Update west workspace
working-directory: zephyr
run: west update -n -o=--depth=1

- name: Export zephyr
working-directory: zephyr
run: west zephyr-export

- name: Run Signature test
working-directory: zephyr
run: |
west twister --integration -T modules/crypto/liboqs/zephyr -s samples/Signatures/sample.crypto.liboqs_signature_example -vvv
- name: Run KEM test
working-directory: zephyr
run: |
west twister --integration -T modules/crypto/liboqs/zephyr -s samples/KEMs/sample.crypto.liboqs_kem_example -vvv
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ option(OQS_BUILD_ONLY_LIB "Build only liboqs and do not expose build targets for
set(OQS_MINIMAL_BUILD "" CACHE STRING "Only build specifically listed algorithms.")
option(OQS_PERMIT_UNSUPPORTED_ARCHITECTURE "Permit compilation on an an unsupported architecture." OFF)
option(OQS_STRICT_WARNINGS "Enable all compiler warnings." OFF)
option(OQS_EMBEDDED_BUILD "Compile liboqs for an Embedded environment without a full standard library." OFF)

set(OQS_OPT_TARGET auto CACHE STRING "The target microarchitecture for optimization.")

Expand Down
9 changes: 9 additions & 0 deletions CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The following options can be passed to CMake before the build file generation pr
- [USE_SANITIZER](#USE_SANITIZER)
- [OQS_ENABLE_TEST_CONSTANT_TIME](#OQS_ENABLE_TEST_CONSTANT_TIME)
- [OQS_STRICT_WARNINGS](#OQS_STRICT_WARNINGS)
- [OQS_EMBEDDED_BUILD](#OQS_EMBEDDED_BUILD)

## BUILD_SHARED_LIBS

Expand Down Expand Up @@ -155,4 +156,12 @@ Can be `ON` or `OFF`. When `ON`, all compiler warnings are enabled and treated a

**Default**: `OFF`.

## OQS_EMBEDDED_BUILD

Can be `ON` or `OFF`. When `ON`, calls to standard library functions typically not present in a bare-metal embedded environment are excluded from compilation.

At the moment, this is **only** considered for random number generation, as both `getentropy()` and a file based `/dev/urandom` are not available on embedded targets (e.g. the Zephyr port).

**Attention**: When this option is enabled, you have to supply a custom callback for obtaining random numbers using the `OQS_randombytes_custom_algorithm()` API before accessing the cryptographic API. Otherwise, all key generation and signing operations will fail.

**Default**: `OFF`.
6 changes: 3 additions & 3 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ target_include_directories(oqs
)
set_target_properties(oqs
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib"
VERSION ${OQS_VERSION_TEXT}
SOVERSION 5
# For Windows DLLs
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")

configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/liboqsConfig.cmake"
Expand Down
33 changes: 18 additions & 15 deletions src/common/rand/rand.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,27 @@ OQS_API void OQS_randombytes(uint8_t *random_array, size_t bytes_to_read) {
oqs_randombytes_algorithm(random_array, bytes_to_read);
}

#if !defined(_WIN32)
#if defined(__APPLE__)
// Select the implementation for OQS_randombytes_system
#if defined(_WIN32)
void OQS_randombytes_system(uint8_t *random_array, size_t bytes_to_read) {
HCRYPTPROV hCryptProv;
if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) ||
!CryptGenRandom(hCryptProv, (DWORD) bytes_to_read, random_array)) {
exit(EXIT_FAILURE); // better to fail than to return bad random data
}
CryptReleaseContext(hCryptProv, 0);
}
#elif defined(__APPLE__)
void OQS_randombytes_system(uint8_t *random_array, size_t bytes_to_read) {
arc4random_buf(random_array, bytes_to_read);
}
#else
#if defined(OQS_HAVE_GETENTROPY)
#elif defined(OQS_EMBEDDED_BUILD)
void OQS_randombytes_system(uint8_t *random_array, size_t bytes_to_read) {
fprintf(stderr, "OQS_randombytes_system is not available in an embedded build.\n");
fprintf(stderr, "Call OQS_randombytes_custom_algorithm() to set a custom method for your system.\n");
exit(EXIT_FAILURE);
}
#elif defined(OQS_HAVE_GETENTROPY)
void OQS_randombytes_system(uint8_t *random_array, size_t bytes_to_read) {
while (bytes_to_read > 256) {
if (getentropy(random_array, 256)) {
Expand Down Expand Up @@ -96,17 +110,6 @@ void OQS_randombytes_system(uint8_t *random_array, size_t bytes_to_read) {
fclose(handle);
}
#endif
#endif
#else
void OQS_randombytes_system(uint8_t *random_array, size_t bytes_to_read) {
HCRYPTPROV hCryptProv;
if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) ||
!CryptGenRandom(hCryptProv, (DWORD) bytes_to_read, random_array)) {
exit(EXIT_FAILURE); // better to fail than to return bad random data
}
CryptReleaseContext(hCryptProv, 0);
}
#endif

#ifdef OQS_USE_OPENSSL
#define OQS_RAND_POLL_RETRY 3 // in case failure to get randomness is a temporary problem, allow some repeats
Expand Down
8 changes: 6 additions & 2 deletions src/common/rand/rand.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ extern "C" {
/**
* Switches OQS_randombytes to use the specified algorithm.
*
* @warning In case you have set a custom algorithm using `OQS_randombytes_custom_algorithm`
* before, this function will overwrite it again. Hence, you have to set your custom
* algorithm again after calling this function.
*
* @param[in] algorithm The name of the algorithm to use.
* @return OQS_SUCCESS if `algorithm` is a supported algorithm name, OQS_ERROR otherwise.
*/
Expand All @@ -36,7 +40,7 @@ OQS_API OQS_STATUS OQS_randombytes_switch_algorithm(const char *algorithm);
/**
* Switches OQS_randombytes to use the given function.
*
* This allows additional custom RNGs besides the provided ones. The provided RNG
* This allows additional custom RNGs besides the provided ones. The provided RNG
* function must have the same signature as `OQS_randombytes`.
*
* @param[in] algorithm_ptr Pointer to the RNG function to use.
Expand All @@ -48,7 +52,7 @@ OQS_API void OQS_randombytes_custom_algorithm(void (*algorithm_ptr)(uint8_t *, s
*
* This implementation uses whichever algorithm has been selected by
* OQS_randombytes_switch_algorithm. The default is OQS_randombytes_system, which
* reads bytes directly from `/dev/urandom`.
* reads bytes from a system specific default source.
*
* The caller is responsible for providing a buffer allocated with sufficient room.
*
Expand Down
2 changes: 2 additions & 0 deletions src/oqsconfig.h.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#cmakedefine OQS_USE_SHA2_OPENSSL 1
#cmakedefine OQS_USE_SHA3_OPENSSL 1

#cmakedefine OQS_EMBEDDED_BUILD 1

#cmakedefine OQS_USE_ADX_INSTRUCTIONS 1
#cmakedefine OQS_USE_AES_INSTRUCTIONS 1
#cmakedefine OQS_USE_AVX_INSTRUCTIONS 1
Expand Down
153 changes: 153 additions & 0 deletions zephyr/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# SPDX-License-Identifier: MIT

# Only add liboqs Zephyr module if enabled in Kconfig
if(CONFIG_LIBOQS)
# Workarounds for Zephyr
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
# We have to set that manually as CMake can't detect it properly in Zephyr
set(CMAKE_SIZEOF_VOID_P 8)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
# Workaround as the generic name "arm" is not a supported architecture in liboqs.
# In Zephyr, however, it is exclusively used for 32-bit ARM architectures.
set(CMAKE_SYSTEM_PROCESSOR "armv7")

# We have to set that manually as CMake can't detect it properly in Zephyr
set(CMAKE_SIZEOF_VOID_P 4)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "posix")
# Workaround to enable the native Zephyr builds on the Linux host system.
if(BOARD MATCHES "native_posix|native_sim")
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR})
else()
message(FATAL_ERROR "Unsupported board ${BOARD} with posix architecture")
endif()

# We have to set that manually as CMake can't detect it properly in Zephyr
set(CMAKE_SIZEOF_VOID_P 8)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86")
# We have to set that manually as CMake can't detect it properly in Zephyr
set(CMAKE_SIZEOF_VOID_P 4)
endif()

# Configuration for liboqs
set(OQS_DIST_BUILD OFF)
set(OQS_BUILD_ONLY_LIB ON)
set(OQS_USE_OPENSSL OFF)
set(OQS_EMBEDDED_BUILD ON)

set(CMAKE_CROSSCOMPILING ON)

# Disable features by hand, as CMake won't find them properly with Zephyr
set(CMAKE_HAVE_GETENTROPY OFF)
set(CMAKE_HAVE_ALIGNED_ALLOC OFF)
set(CMAKE_HAVE_POSIX_MEMALIGN OFF)
set(CMAKE_HAVE_MEMALIGN OFF)
set(CMAKE_HAVE_EXPLICIT_BZERO OFF)
set(CMAKE_HAVE_MEMSET_S OFF)
set(CC_SUPPORTS_WA_NOEXECSTACK OFF)
set(LD_SUPPORTS_WL_Z_NOEXECSTACK OFF)

# Algorithm selection (based on Kconfig)
if(CONFIG_LIBOQS_ENABLE_KEM_BIKE)
set(OQS_ENABLE_KEM_BIKE ON)
else()
set(OQS_ENABLE_KEM_BIKE OFF)
endif()

if(CONFIG_LIBOQS_ENABLE_KEM_FRODOKEM)
set(OQS_ENABLE_KEM_FRODOKEM ON)
else()
set(OQS_ENABLE_KEM_FRODOKEM OFF)
endif()

if(CONFIG_LIBOQS_ENABLE_KEM_NTRUPRIME)
set(OQS_ENABLE_KEM_NTRUPRIME ON)
else()
set(OQS_ENABLE_KEM_NTRUPRIME OFF)
endif()

if(CONFIG_LIBOQS_ENABLE_KEM_CLASSIC_MCELIECE)
set(OQS_ENABLE_KEM_CLASSIC_MCELIECE ON)
else()
set(OQS_ENABLE_KEM_CLASSIC_MCELIECE OFF)
endif()

if(CONFIG_LIBOQS_ENABLE_KEM_HQC)
set(OQS_ENABLE_KEM_HQC ON)
else()
set(OQS_ENABLE_KEM_HQC OFF)
endif()

if(CONFIG_LIBOQS_ENABLE_KEM_KYBER)
set(OQS_ENABLE_KEM_KYBER ON)
else()
set(OQS_ENABLE_KEM_KYBER OFF)
endif()

if(CONFIG_LIBOQS_ENABLE_SIG_DILITHIUM)
set(OQS_ENABLE_SIG_DILITHIUM ON)
else()
set(OQS_ENABLE_SIG_DILITHIUM OFF)
endif()

if(CONFIG_LIBOQS_ENABLE_SIG_FALCON)
set(OQS_ENABLE_SIG_FALCON ON)
else()
set(OQS_ENABLE_SIG_FALCON OFF)
endif()

if(CONFIG_LIBOQS_ENABLE_SIG_SPHINCS)
set(OQS_ENABLE_SIG_SPHINCS ON)
else()
set(OQS_ENABLE_SIG_SPHINCS OFF)
endif()

# Add the actual liboqs targets
add_subdirectory(.. build)

# Add target specific options to all liboqs targets
zephyr_get_targets(.. "STATIC_LIBRARY;OBJECT_LIBRARY" ALL_TARGETS)
foreach(target ${ALL_TARGETS})
# Zephyr include directories
target_include_directories(${target} PRIVATE
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_INCLUDE_DIRECTORIES>
)

# Zephyr system include directories
target_include_directories(${target} SYSTEM PRIVATE
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>
)

# Definitions
target_compile_definitions(${target} PRIVATE
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_COMPILE_DEFINITIONS>
)

# Compile options (includes compiler flags)
target_compile_options(${target} PRIVATE
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_COMPILE_OPTIONS>
$<TARGET_PROPERTY:compiler,no_builtin>
)

# liboqs depends on unistd.h, which ultimately needs the generated syscall_list.h file,
# which is generated as part of ${SYSCALL_LIST_H_TARGET} target. Therefore, we have to
# make sure that target is built before liboqs.
add_dependencies(${target} ${SYSCALL_LIST_H_TARGET})

# We don't want position independent code
set_target_properties(${target} PROPERTIES POSITION_INDEPENDENT_CODE OFF)
endforeach()

# Link the liboqs library
zephyr_link_libraries(oqs)

# Include the liboqs headers
zephyr_include_directories(${CMAKE_CURRENT_BINARY_DIR}/build/include)

if(CMAKE_SYSTEM_PROCESSOR MATCHES "armv7")
# Undo the workaround from above to not interfere with other modules
set(CMAKE_SYSTEM_PROCESSOR "arm")
elseif(CMAKE_SYSTEM_PROCESSOR EQUAL CMAKE_HOST_SYSTEM_PROCESSOR)
# Undo the workaround from above to not interfere with other modules
set(CMAKE_SYSTEM_PROCESSOR "posix")
endif()
endif()
Loading

0 comments on commit 4906c3f

Please sign in to comment.