diff --git a/CMakeLists.txt b/CMakeLists.txt index fc4d790c..720000be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ set(CMAKE_TOOLCHAIN_FILE CMakeToolchain.txt) option(CFG_WERROR "Build with -Werror" TRUE) option(WITH_TEEACL "Build libteeacl" TRUE) +option(WITH_ASTEEC "Build libasteec" TRUE) include(GNUInstallDirs) @@ -47,3 +48,6 @@ if(WITH_TEEACL) add_subdirectory(libteeacl) endif(WITH_TEEACL) add_subdirectory(libseteec) +if(WITH_ASTEEC) + add_subdirectory(libasteec) +endif(WITH_ASTEEC) diff --git a/Makefile b/Makefile index 8a1a86af..0db8898e 100644 --- a/Makefile +++ b/Makefile @@ -20,9 +20,10 @@ libdir ?= $(LIBDIR) includedir ?= $(INCLUDEDIR) WITH_TEEACL ?= 1 +WITH_ASTEEC ?= 1 .PHONY: all build build-libteec build-libckteec build-libseteec \ - build-libteeacl install copy_export clean cscope \ + build-libteeacl build-libasteec install copy_export clean cscope \ clean-cscope \ checkpatch-pre-req checkpatch-modified-patch checkpatch-modified-file \ checkpatch-last-commit-patch checkpatch-last-commit-file \ @@ -44,6 +45,9 @@ build: build-libteec build-tee-supplicant build-libckteec build-libseteec ifeq ($(WITH_TEEACL),1) build: build-libteeacl endif +ifeq ($(WITH_ASTEEC),1) +build: build-libasteec +endif build-libckteec: build-libteec @echo "Building libckteec.so" @@ -57,6 +61,10 @@ build-libteeacl: @echo "Building libteeacl.so" @$(MAKE) --directory=libteeacl --no-print-directory --no-builtin-variables +build-libasteec: build-libteec + @echo "Building libasteec.so" + @$(MAKE) --directory=libasteec --no-print-directory --no-builtin-variables + install: copy_export clean: clean-libteec clean-tee-supplicant clean-cscope clean-libckteec \ @@ -64,6 +72,9 @@ clean: clean-libteec clean-tee-supplicant clean-cscope clean-libckteec \ ifeq ($(WITH_TEEACL),1) clean: clean-libteeacl endif +ifeq ($(WITH_ASTEEC),1) +clean: clean-libasteec +endif clean-libteec: @$(MAKE) --directory=libteec --no-print-directory clean @@ -80,6 +91,9 @@ clean-libseteec: clean-libteeacl: @$(MAKE) --directory=libteeacl --no-print-directory clean +clean-libasteec: + @$(MAKE) --directory=libasteec --no-print-directory clean + cscope: @echo " CSCOPE" ${VPREFIX}find ${CURDIR} -name "*.[chsS]" > cscope.files @@ -172,3 +186,8 @@ endif cp libseteec/include/*.h $(DESTDIR)$(includedir) cp -d ${O}/libseteec/libseteec.so* $(DESTDIR)$(libdir) cp -d ${O}/libseteec/libseteec.a $(DESTDIR)$(libdir) +ifeq ($(WITH_ASTEEC),1) + cp libasteec/include/*.h $(DESTDIR)$(includedir) + cp -d ${O}/libasteec/libasteec.so* $(DESTDIR)$(libdir) + cp -d ${O}/libasteec/libasteec.a $(DESTDIR)$(libdir) +endif diff --git a/libasteec/CMakeLists.txt b/libasteec/CMakeLists.txt new file mode 100644 index 00000000..d4385a4b --- /dev/null +++ b/libasteec/CMakeLists.txt @@ -0,0 +1,60 @@ +project(asteec + VERSION 1.0.0 + LANGUAGES C +) + +add_compile_options(${C_COMPILE_OPTIONS}) + +include(GNUInstallDirs) + +################################################################################ +# Source files +################################################################################ +set(SRC + src/asteec.c +) + +################################################################################ +# Built library +################################################################################ +add_library(asteec ${SRC}) + +configure_file(asteec.pc.in asteec.pc @ONLY) + +set_target_properties(asteec PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} +) + +################################################################################ +# Flags always set +################################################################################ +target_compile_definitions(asteec + PRIVATE -D_GNU_SOURCE + PRIVATE -DBINARY_PREFIX="LT" +) + +################################################################################ +# Public and private header and library dependencies +################################################################################ +target_include_directories(asteec PUBLIC + $ + $ +) + +target_link_libraries(asteec + PRIVATE teec +) + +################################################################################ +# Install targets +################################################################################ +install(TARGETS asteec + DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/asteec.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" +) diff --git a/libasteec/Makefile b/libasteec/Makefile new file mode 100644 index 00000000..c8a3ad2c --- /dev/null +++ b/libasteec/Makefile @@ -0,0 +1,71 @@ +include ../flags.mk +include ../config.mk + +OUT_DIR := $(OO)/libasteec + +.PHONY: all libasteec clean + +all: libasteec +install: libasteec + +LIB_NAME := libasteec +MAJOR_VERSION := 1 +MINOR_VERSION := 0 +PATCH_VERSION := 0 + +LIB_MAJOR := $(LIB_NAME).so.$(MAJOR_VERSION) +LIB_MAJ_MIN := $(LIB_NAME).so.$(MAJOR_VERSION).$(MINOR_VERSION) +LIB_MAJ_MIN_PAT := $(LIB_NAME).so.$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION) +LIBASTEEC_SO_LIBRARY := $(LIB_MAJ_MIN_PAT) +LIBASTEEC_AR_LIBRARY := $(LIB_NAME).a + +LIBASTEEC_SRC_DIR := src + +LIBASTEEC_SRCS = asteec.c + +LIBASTEEC_INCLUDES = ${CURDIR}/include +LIBASTEEC_INCLUDES += ${CURDIR}/../libteec/include + +LIBASTEEC_CFLAGS := $(addprefix -I, $(LIBASTEEC_INCLUDES)) \ + $(CFLAGS) -D_GNU_SOURCE -fPIC + +LIBASTEEC_LFLAGS := $(LDFLAGS) -L$(OUT_DIR)/../libteec -lteec + +LIBASTEEC_OBJ_DIR := $(OUT_DIR) +LIBASTEEC_OBJS := $(patsubst %.c,$(LIBASTEEC_OBJ_DIR)/%.o, $(LIBASTEEC_SRCS)) + +$(LIBASTEEC_OBJ_DIR)/%.o: ${LIBASTEEC_SRC_DIR}/%.c + $(VPREFIX)mkdir -p $(LIBASTEEC_OBJ_DIR) + @echo " CC $<" + $(VPREFIX)$(CC) $(LIBASTEEC_CFLAGS) -c $< -o $@ + +libasteec: $(OUT_DIR)/$(LIBASTEEC_SO_LIBRARY) + +$(OUT_DIR)/$(LIBASTEEC_SO_LIBRARY): $(LIBASTEEC_OBJS) + @echo " LINK $@" + $(VPREFIX)$(CC) -shared -Wl,-soname,$(LIB_MAJOR) -o $@ $+ $(LIBASTEEC_LFLAGS) + @echo "" + +libasteec: $(OUT_DIR)/$(LIBASTEEC_AR_LIBRARY) + +$(OUT_DIR)/$(LIBASTEEC_AR_LIBRARY): $(LIBASTEEC_OBJS) + @echo " AR $@" + $(VPREFIX)$(AR) rcs $@ $+ + +libasteec: + $(VPREFIX)ln -sf $(LIB_MAJ_MIN_PAT) $(OUT_DIR)/$(LIB_MAJ_MIN) + $(VPREFIX)ln -sf $(LIB_MAJ_MIN) $(OUT_DIR)/$(LIB_MAJOR) + $(VPREFIX)ln -sf $(LIB_MAJOR) $(OUT_DIR)/$(LIB_NAME).so + +################################################################################ +# Cleaning up configuration +################################################################################ +clean: + $(RM) $(LIBASTEEC_OBJS) + $(RM) $(OUT_DIR)/$(LIB_MAJ_MIN_PAT) + $(RM) $(OUT_DIR)/$(LIB_MAJ_MIN) + $(RM) $(OUT_DIR)/$(LIB_MAJOR) + $(RM) $(OUT_DIR)/$(LIBASTEEC_SO_LIBRARY) + $(RM) $(OUT_DIR)/$(LIBASTEEC_AR_LIBRARY) + $(call rmdir,$(OUT_DIR)) + diff --git a/libasteec/asteec.pc.in b/libasteec/asteec.pc.in new file mode 100644 index 00000000..bb1ae9cb --- /dev/null +++ b/libasteec/asteec.pc.in @@ -0,0 +1,11 @@ +prefix="@CMAKE_INSTALL_PREFIX@" +exec_prefix="${prefix}" +libdir="${prefix}/lib" +includedir="${prefix}/include" + +Name: @PROJECT_NAME@ +Description: Application Secrets TEE Client library +Version: @PROJECT_VERSION@ +Requires: teec +Cflags: -I"${includedir}" +Libs: -L"${libdir}" -lasteec diff --git a/libasteec/include/asteec.h b/libasteec/include/asteec.h new file mode 100644 index 00000000..1650aea6 --- /dev/null +++ b/libasteec/include/asteec.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Vaisala Oyj. + */ + +#ifndef ASTEEC_H +#define ASTEEC_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * asteec_seal() - Seal secret using hardware unique TA specific key + * + * @param login_method Login method such as TEEC_LOGIN_PUBLIC or TEEC_LOGIN_GROUP + * @param login_gid Group ID, used with TEEC_LOGIN_GROUP and + * TEEC_LOGIN_GROUP_APPLICATION methods + * @param plain Pointer to plain secret + * @param plain_len Byte length of plain secret + * @param sealed Pointer to buffer to receive sealed secret datablob. + * May be NULL when *sealed_len is 0 to query the + * required output size. + * @param sealed_len On input, byte length of buffer @sealed. On output, + * updated with the actual size on success or the required + * size when TEEC_ERROR_SHORT_BUFFER is returned. + * + * @return TEEC_SUCCESS on success, TEEC_ERROR_* on failure + */ +TEEC_Result asteec_seal(uint32_t login_method, gid_t login_gid, + const void *plain, size_t plain_len, + void *sealed, size_t *sealed_len); + +/** + * asteec_unseal() - Unseal secret using hardware unique TA specific key + * + * @param login_method Login method such as TEEC_LOGIN_PUBLIC or TEEC_LOGIN_GROUP + * @param login_gid Group ID, used with TEEC_LOGIN_GROUP and + * TEEC_LOGIN_GROUP_APPLICATION methods + * @param sealed Pointer to sealed secret datablob + * @param sealed_len Byte length of sealed secret datablob + * @param plain Pointer to buffer to receive plain secret. + * May be NULL when *plain_len is 0 to query the + * required output size. + * @param plain_len On input, byte length of buffer @plain. On output, + * updated with the actual size on success or the required + * size when TEEC_ERROR_SHORT_BUFFER is returned. + * + * @return TEEC_SUCCESS on success, TEEC_ERROR_* on failure + */ +TEEC_Result asteec_unseal(uint32_t login_method, gid_t login_gid, + const void *sealed, size_t sealed_len, + void *plain, size_t *plain_len); + +#ifdef __cplusplus +} +#endif + +#endif /* ASTEEC_H */ diff --git a/libasteec/src/app_secrets_ta.h b/libasteec/src/app_secrets_ta.h new file mode 100644 index 00000000..96be794e --- /dev/null +++ b/libasteec/src/app_secrets_ta.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Vaisala Oyj. + */ + +#ifndef APP_SECRETS_TA_H +#define APP_SECRETS_TA_H + +#define APP_SECRETS_TA_UUID \ + { 0x5ca4d9d9, 0xdee4, 0x47f4, \ + { 0x97, 0x7a, 0x7e, 0xad, 0xc0, 0x60, 0xe5, 0x2c } } + +/* + * Seal secret using hardware unique TA specific key + * + * [in] memref[0] Plain secret + * [out] memref[1] Sealed secret datablob + */ +#define TA_APPSECRETS_CMD_SEAL_SECRET 0x0 + +/* + * Unseal secret using hardware unique TA specific key + * + * [in] memref[0] Sealed secret datablob + * [out] memref[1] Plain secret + */ +#define TA_APPSECRETS_CMD_UNSEAL_SECRET 0x1 + +#endif /* APP_SECRETS_TA_H */ diff --git a/libasteec/src/asteec.c b/libasteec/src/asteec.c new file mode 100644 index 00000000..ae4ea86f --- /dev/null +++ b/libasteec/src/asteec.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Vaisala Oyj. + */ + +#include +#include +#include +#include +#include + +#include "app_secrets_ta.h" + +static TEEC_Result open_session(TEEC_Context *ctx, TEEC_Session *session, + uint32_t login_method, gid_t login_gid) +{ + TEEC_UUID uuid = APP_SECRETS_TA_UUID; + void *login_data = NULL; + + switch (login_method) { + case TEEC_LOGIN_PUBLIC: + case TEEC_LOGIN_USER: + case TEEC_LOGIN_APPLICATION: + case TEEC_LOGIN_USER_APPLICATION: + break; + case TEEC_LOGIN_GROUP: + case TEEC_LOGIN_GROUP_APPLICATION: + login_data = &login_gid; + break; + default: + return TEEC_ERROR_BAD_PARAMETERS; + } + + return TEEC_OpenSession(ctx, session, &uuid, + login_method, login_data, NULL, NULL); +} + +TEEC_Result asteec_seal(uint32_t login_method, gid_t login_gid, + const void *plain, size_t plain_len, + void *sealed, size_t *sealed_len) +{ + TEEC_Context ctx = { 0 }; + TEEC_Session session = { 0 }; + TEEC_Operation op = { 0 }; + TEEC_Result res = TEEC_ERROR_GENERIC; + + if (!plain || !plain_len || !sealed_len) + return TEEC_ERROR_BAD_PARAMETERS; + + if (!sealed && *sealed_len) + return TEEC_ERROR_BAD_PARAMETERS; + + res = TEEC_InitializeContext(NULL, &ctx); + if (res != TEEC_SUCCESS) + return res; + + res = open_session(&ctx, &session, login_method, login_gid); + if (res != TEEC_SUCCESS) + goto out_ctx; + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_OUTPUT, + TEEC_NONE, TEEC_NONE); + + op.params[0].tmpref.buffer = (void *)plain; + op.params[0].tmpref.size = plain_len; + + op.params[1].tmpref.buffer = sealed; + op.params[1].tmpref.size = *sealed_len; + + res = TEEC_InvokeCommand(&session, TA_APPSECRETS_CMD_SEAL_SECRET, + &op, NULL); + + if (res == TEEC_SUCCESS || res == TEEC_ERROR_SHORT_BUFFER) + *sealed_len = op.params[1].tmpref.size; + + TEEC_CloseSession(&session); +out_ctx: + TEEC_FinalizeContext(&ctx); + return res; +} + +TEEC_Result asteec_unseal(uint32_t login_method, gid_t login_gid, + const void *sealed, size_t sealed_len, + void *plain, size_t *plain_len) +{ + TEEC_Context ctx = { 0 }; + TEEC_Session session = { 0 }; + TEEC_Operation op = { 0 }; + TEEC_Result res = TEEC_ERROR_GENERIC; + + if (!sealed || !sealed_len || !plain_len) + return TEEC_ERROR_BAD_PARAMETERS; + + if (!plain && *plain_len) + return TEEC_ERROR_BAD_PARAMETERS; + + res = TEEC_InitializeContext(NULL, &ctx); + if (res != TEEC_SUCCESS) + return res; + + res = open_session(&ctx, &session, login_method, login_gid); + if (res != TEEC_SUCCESS) + goto out_ctx; + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_OUTPUT, + TEEC_NONE, TEEC_NONE); + + op.params[0].tmpref.buffer = (void *)sealed; + op.params[0].tmpref.size = sealed_len; + + op.params[1].tmpref.buffer = plain; + op.params[1].tmpref.size = *plain_len; + + res = TEEC_InvokeCommand(&session, TA_APPSECRETS_CMD_UNSEAL_SECRET, + &op, NULL); + + if (res == TEEC_SUCCESS || res == TEEC_ERROR_SHORT_BUFFER) + *plain_len = op.params[1].tmpref.size; + + TEEC_CloseSession(&session); +out_ctx: + TEEC_FinalizeContext(&ctx); + return res; +}