diff --git a/CMakeLists.txt b/CMakeLists.txt index a31fa4b8..a73bb883 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,3 +48,4 @@ if(WITH_TEEACL) add_subdirectory (libteeacl) endif(WITH_TEEACL) add_subdirectory (libseteec) +add_subdirectory (libptateec) diff --git a/Makefile b/Makefile index b156f42a..4a537341 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ includedir ?= $(INCLUDEDIR) WITH_TEEACL ?= 1 .PHONY: all build build-libteec build-libckteec build-libseteec \ - build-libteeacl install copy_export clean cscope \ + build-libteeacl built-libptateec install copy_export clean cscope \ clean-cscope \ checkpatch-pre-req checkpatch-modified-patch checkpatch-modified-file \ checkpatch-last-commit-patch checkpatch-last-commit-file \ @@ -40,7 +40,7 @@ build-tee-supplicant: build-libteec @echo "Building tee-supplicant" $(MAKE) --directory=tee-supplicant --no-print-directory --no-builtin-variables CFG_TEE_SUPP_LOG_LEVEL=$(CFG_TEE_SUPP_LOG_LEVEL) -build: build-libteec build-tee-supplicant build-libckteec build-libseteec +build: build-libteec build-tee-supplicant build-libckteec build-libseteec build-libptateec ifeq ($(WITH_TEEACL),1) build: build-libteeacl endif @@ -57,10 +57,14 @@ build-libteeacl: @echo "Building libteeacl.so" @$(MAKE) --directory=libteeacl --no-print-directory --no-builtin-variables +build-libptateec: build-libteec + @echo "Building libptateec.so" + @$(MAKE) --directory=libptateec --no-print-directory --no-builtin-variables + install: copy_export clean: clean-libteec clean-tee-supplicant clean-cscope clean-libckteec \ - clean-libseteec + clean-libseteec clean-libptateec ifeq ($(WITH_TEEACL),1) clean: clean-libteeacl endif @@ -80,6 +84,9 @@ clean-libseteec: clean-libteeacl: @$(MAKE) --directory=libteeacl --no-print-directory clean +clean-libptateec: + @$(MAKE) --directory=libptateec --no-print-directory clean + cscope: @echo " CSCOPE" ${VPREFIX}find ${CURDIR} -name "*.[chsS]" > cscope.files @@ -172,3 +179,6 @@ endif cp libseteec/include/*.h $(DESTDIR)$(includedir) cp -d ${O}/libseteec/libseteec.so* $(DESTDIR)$(libdir) cp -d ${O}/libseteec/libseteec.a $(DESTDIR)$(libdir) + cp libptateec/include/*.h $(DESTDIR)$(INCLUDEDIR) + cp -d ${O}/libptateec/libptateec.so* $(DESTDIR)$(LIBDIR) + cp -d ${O}/libptateec/libptateec.a $(DESTDIR)$(LIBDIR) diff --git a/libptateec/CMakeLists.txt b/libptateec/CMakeLists.txt new file mode 100644 index 00000000..28daebac --- /dev/null +++ b/libptateec/CMakeLists.txt @@ -0,0 +1,66 @@ +project(ptateec + VERSION 0.1.0 + LANGUAGES C) + +################################################################################ +# Packages +################################################################################ +find_package(Threads REQUIRED) +if(NOT THREADS_FOUND) + message(FATAL_ERROR "Threads not found") +endif() + +include(GNUInstallDirs) + +################################################################################ +# Source files +################################################################################ +set (SRC + src/pta.c + src/pta_imx_manufacturing_protection.c +) + +################################################################################ +# Built library +################################################################################ +add_library (ptateec ${SRC}) + +set_target_properties (ptateec PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} +) + +################################################################################ +# Flags always set +################################################################################ +target_compile_definitions (ptateec + PRIVATE -D_GNU_SOURCE + PRIVATE -DBINARY_PREFIX="LT" +) + +################################################################################ +# Optional flags +################################################################################ + +################################################################################ +# Public and private header and library dependencies +################################################################################ +target_include_directories(ptateec + PUBLIC $ + $ + PRIVATE src +) + +target_link_libraries (ptateec + PRIVATE pthread + PRIVATE teec +) + +################################################################################ +# Install targets +################################################################################ +install (TARGETS ptateec + DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +add_subdirectory(include) diff --git a/libptateec/Makefile b/libptateec/Makefile new file mode 100644 index 00000000..ed8a5442 --- /dev/null +++ b/libptateec/Makefile @@ -0,0 +1,71 @@ +include ../flags.mk +include ../config.mk + +OUT_DIR := $(OO)/libptateec + +.PHONY: all libptateec clean + +all: libptateec +install: libptateec + +LIB_NAME := libptateec +MAJOR_VERSION := 0 +MINOR_VERSION := 1 +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) +LIBPTATEEC_SO_LIBRARY := $(LIB_MAJ_MIN_PAT) +LIBPTATEEC_AR_LIBRARY := $(LIB_NAME).a + +LIBPTATEEC_SRC_DIR := src + +LIBPTATEEC_SRCS = pta.c \ + pta_imx_manufacturing_protection.c + +LIBPTATEEC_INCLUDES = ${CURDIR}/include +LIBPTATEEC_INCLUDES += ${CURDIR}/../public + +LIBPTATEEC_CFLAGS := $(addprefix -I, $(LIBPTATEEC_INCLUDES)) \ + $(CFLAGS) -D_GNU_SOURCE -fPIC + +LIBPTATEEC_LFLAGS := $(LDFLAGS) -L$(OUT_DIR)/../libteec -lteec -lpthread + +LIBPTATEEC_OBJ_DIR := $(OUT_DIR) +LIBPTATEEC_OBJS := $(patsubst %.c,$(LIBPTATEEC_OBJ_DIR)/%.o, $(LIBPTATEEC_SRCS)) + +$(LIBPTATEEC_OBJ_DIR)/%.o: ${LIBPTATEEC_SRC_DIR}/%.c + $(VPREFIX)mkdir -p $(LIBPTATEEC_OBJ_DIR) + @echo " CC $<" + $(VPREFIX)$(CC) $(LIBPTATEEC_CFLAGS) -c $< -o $@ + +libptateec: $(OUT_DIR)/$(LIBPTATEEC_SO_LIBRARY) + +$(OUT_DIR)/$(LIBPTATEEC_SO_LIBRARY): $(LIBPTATEEC_OBJS) + @echo " LINK $@" + $(VPREFIX)$(CC) -shared -Wl,-soname,$(LIB_MAJOR) -o $@ $+ $(LIBPTATEEC_LFLAGS) + @echo "" + +libptateec: $(OUT_DIR)/$(LIBPTATEEC_AR_LIBRARY) + +$(OUT_DIR)/$(LIBPTATEEC_AR_LIBRARY): $(LIBPTATEEC_OBJS) + @echo " AR $@" + $(VPREFIX)$(AR) rcs $@ $+ + +libptateec: + $(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) $(LIBPTATEEC_OBJS) + $(RM) $(OUT_DIR)/$(LIB_MAJ_MIN_PAT) + $(RM) $(OUT_DIR)/$(LIB_MAJ_MIN) + $(RM) $(OUT_DIR)/$(LIB_MAJOR) + $(RM) $(OUT_DIR)/$(LIBPTATEEC_SO_LIBRARY) + $(RM) $(OUT_DIR)/$(LIBPTATEEC_AR_LIBRARY) + $(call rmdir,$(OUT_DIR)) diff --git a/libptateec/include/CMakeLists.txt b/libptateec/include/CMakeLists.txt new file mode 100644 index 00000000..50e45a82 --- /dev/null +++ b/libptateec/include/CMakeLists.txt @@ -0,0 +1,7 @@ +project (libptateec-headers C) + +FILE(GLOB INSTALL_HEADERS "*.h") + +add_library(${PROJECT_NAME} INTERFACE) + +install (FILES ${INSTALL_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/libptateec/include/pta_tee.h b/libptateec/include/pta_tee.h new file mode 100644 index 00000000..f05a9d72 --- /dev/null +++ b/libptateec/include/pta_tee.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023, Foundries.io + */ + +#ifndef PTA_TEE_H +#define PTA_TEE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * pta_imx_mprotect_get_key() - Retrieves the iMX CAAM Manufacturing Protection + * EC public key. The components x,y are retrieved in RAW format and should + * be converted to DER or PEM as required. + * + * For the 256 bit curve, this will generate two 32 byte components therefore + * requiring at least a 64 byte buffer. + * + * @key: [out] Public key in RAW format. + * @len: [in/out] Key length in bytes. + * + * @return TEEC_ERROR_BAD_PARAMETERS Invalid parameters provided on input. + * @return TEEC_ERROR_ACCESS_DENIED Error opening the TEE session. + * @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion. + * @return TEEC_ERROR_GENERIC Error unspecified. + * @return TEEC_ERROR_SHORT_BUFFER Error small buffer provided. + * @return TEEC_ERROR_COMMUNICATION Some other thread closed the connection. + * @return TEEC_SUCCESS On success. + * + */ +TEEC_Result pta_imx_mprotect_get_key(char *key, size_t *len); + +/** + * pta_imx_mprotect_sign() - Signs a message using the Manufacturing Protection + * EC private key. + * + * This function takes message data as input and outputs a signature over a + * message composed of the content of the MPMR, followed by the input-data + * message. + * + * @message: [in] Message to sign. + * @mlen: [in] Message length in bytes. + * @signature: [out] Generated signature. + * @slen: [in/out] Signature length in bytes. + * @mpmr: [out] MPMR data. + * @len: [in/out] MPMR length in bytes. + * + * @return TEEC_ERROR_BAD_PARAMETERS Invalid parameters provided on input. + * @return TEEC_ERROR_ACCESS_DENIED Error opening the TEE session. + * @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion. + * @return TEEC_ERROR_GENERIC Error unspecified. + * @return TEEC_ERROR_COMMUNICATION Some other thread closed the connection. + * @return TEEC_ERROR_SHORT_BUFFER Error small buffer provided. + * @return TEEC_SUCCESS On success. + * + */ +TEEC_Result pta_imx_mprotect_sign(char *message, size_t mlen, char *signature, + size_t *slen, char *mpmr, size_t *len); + +/** + * pta_imx_mprotect_final() - Closes the OP-TEE session + * + * This function may fail with TEEC_ERROR_BUSY if there are unfulfilled calls + * pending. + * + * @return TEEC_ERROR_BUSY PTA is still in use. + * @return TEEC_SUCCESS On success. + * + */ +TEEC_Result pta_imx_mprotect_final(void); + +#ifdef __cplusplus +} +#endif + +#endif /*PTA_TEE_H*/ diff --git a/libptateec/src/pta.c b/libptateec/src/pta.c new file mode 100644 index 00000000..dd1672c5 --- /dev/null +++ b/libptateec/src/pta.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2023, Foundries.io Ltd + */ + +#ifndef BINARY_PREFIX +#define BINARY_PREFIX "ptateec" +#endif + +#include "pta.h" + +TEEC_Result pta_open_session(struct pta_context *ctx) +{ + TEEC_Result ret = TEEC_SUCCESS; + + pthread_mutex_lock(&ctx->lock); + if (!ctx->open) { + ret = TEEC_InitializeContext(NULL, &ctx->context); + if (!ret) { + ret = TEEC_OpenSession(&ctx->context, &ctx->session, + &ctx->uuid, TEEC_LOGIN_PUBLIC, + NULL, NULL, NULL); + if (!ret) + ctx->open = true; + } + } + if (ctx->open) + atomic_fetch_add(&ctx->count, 1); + pthread_mutex_unlock(&ctx->lock); + + return ret; +} + +TEEC_Result pta_invoke_cmd(struct pta_context *ctx, uint32_t cmd_id, + TEEC_Operation *op, uint32_t *error_origin) +{ + TEEC_Result ret = TEEC_SUCCESS; + + pthread_mutex_lock(&ctx->lock); + if (!ctx->open) { + atomic_store(&ctx->count, 0); + pthread_mutex_unlock(&ctx->lock); + + return TEEC_ERROR_COMMUNICATION; + } + pthread_mutex_unlock(&ctx->lock); + ret = TEEC_InvokeCommand(&ctx->session, cmd_id, op, error_origin); + atomic_fetch_sub(&ctx->count, 1); + + return ret; +} + +TEEC_Result pta_final(struct pta_context *ctx) +{ + TEEC_Result ret = TEEC_SUCCESS; + + pthread_mutex_lock(&ctx->lock); + if (!ctx->open) { + pthread_mutex_unlock(&ctx->lock); + return TEEC_SUCCESS; + } + + if (atomic_load(&ctx->count)) { + ret = TEEC_ERROR_BUSY; + } else { + TEEC_CloseSession(&ctx->session); + TEEC_FinalizeContext(&ctx->context); + ctx->open = false; + } + pthread_mutex_unlock(&ctx->lock); + + return ret; +} diff --git a/libptateec/src/pta.h b/libptateec/src/pta.h new file mode 100644 index 00000000..f8c91418 --- /dev/null +++ b/libptateec/src/pta.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023, Foundries.io Ltd + */ +#ifndef PTATEEC_PTA_H +#define PTATEEC_PTA_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct pta_context { + pthread_mutex_t lock; /* Serialize session creation/deletion */ + TEEC_Context context; + TEEC_Session session; + TEEC_UUID uuid; /* PTA Unique Identifier */ + bool open; /* PTA session state */ + atomic_int count; /* PTA session number of users */ +}; + +/** + * This set of wrappers aims at protecting PTA access in a multithreaded + * environment. + * + * Each call to the PTA expects balanced open/invoke operations + * + * pta_xxxx_foo() + * { + * pta_open_session(); + * [...] + * pta_invoke_cmd(); + * [...] + * } + */ + +/** + * pta_open_session() - Opens a session with the PTA uuid in the pta_context. + * If the session is already open it will increment a session counter. + * + * @ctx: PTA context information. + * @ctx->uuid defines the target PTA. + * + */ +TEEC_Result pta_open_session(struct pta_context *ctx); + +/** + * pta_invoke_cmd() - Invokes a command in the PTA + * + * @ctx: Opened PTA context information. + * @cmd_id: Command passed to target PTA. + * @operation: TEE operation arguments passed to target PTA. + * @error_origin: Output TEE_ORIGIN_* emitter of the result code. + */ +TEEC_Result pta_invoke_cmd(struct pta_context *ctx, uint32_t cmd_id, + TEEC_Operation *operation, uint32_t *error_origin); +/** + * pta_final() - Attempts to close the session with the PTA. + * The session will not be closed while there are active users. + * + * @ctx: Opened PTA context information. + */ +TEEC_Result pta_final(struct pta_context *ctx); + +#endif diff --git a/libptateec/src/pta_imx_manufacturing_protection.c b/libptateec/src/pta_imx_manufacturing_protection.c new file mode 100644 index 00000000..5758054c --- /dev/null +++ b/libptateec/src/pta_imx_manufacturing_protection.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2023, Foundries.io Ltd + * + * The CAAM features a "manufacturing protection" attestation feature. + * + * It is a authentication process used to authenticate the chip to + * the OEM's server. + * + * The authentication process can ensure the chip: + * - is a genuine NXP part + * - is a correct part type + * - has been properly fused + * - is running a authenticated software + * - runs in secure/trusted mode. + */ + +#ifndef BINARY_PREFIX +#define BINARY_PREFIX "ptateec" +#endif + +#include "pta.h" +#include "pta_imx_manufacturing_protection.h" + +static struct pta_context manufacturing_protection_pta_ctx = { + .lock = PTHREAD_MUTEX_INITIALIZER, + .uuid = PTA_MANUFACT_PROTEC_UUID, +}; + +TEEC_Result pta_imx_mprotect_get_key(char *key, size_t *len) +{ + TEEC_Result ret = TEEC_SUCCESS; + TEEC_Operation op = { 0 }; + + if (!key || !len || !*len) + return TEEC_ERROR_BAD_PARAMETERS; + + ret = pta_open_session(&manufacturing_protection_pta_ctx); + if (ret) { + if (ret == TEEC_ERROR_OUT_OF_MEMORY) + return ret; + return TEEC_ERROR_ACCESS_DENIED; + } + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE, + TEEC_NONE, TEEC_NONE); + + op.params[0].tmpref.buffer = key; + op.params[0].tmpref.size = *len; + + ret = pta_invoke_cmd(&manufacturing_protection_pta_ctx, + PTA_IMX_MP_CMD_GET_PUBLIC_KEY, &op, NULL); + + if (ret != TEEC_SUCCESS) { + if (ret == TEEC_ERROR_SHORT_BUFFER) { + /* Update with expected length */ + *len = op.params[0].tmpref.size; + return ret; + } else if (ret == TEEC_ERROR_COMMUNICATION || + ret == TEEC_ERROR_OUT_OF_MEMORY) { + return ret; + } + return TEEC_ERROR_GENERIC; + } + + *len = op.params[0].tmpref.size; + + return TEEC_SUCCESS; +} + +TEEC_Result pta_imx_mprotect_sign(char *msg, size_t msg_len, + char *sig, size_t *sig_len, + char *mpmr, size_t *mpmr_len) +{ + TEEC_Result ret = TEEC_SUCCESS; + TEEC_Operation op = { 0 }; + + if (!msg || !sig || !sig_len || !mpmr || !mpmr_len) + return TEEC_ERROR_BAD_PARAMETERS; + + if (!msg_len || !*sig_len || !*mpmr_len) + return TEEC_ERROR_BAD_PARAMETERS; + + ret = pta_open_session(&manufacturing_protection_pta_ctx); + if (ret) { + if (ret == TEEC_ERROR_OUT_OF_MEMORY) + return ret; + return TEEC_ERROR_ACCESS_DENIED; + } + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_OUTPUT, + TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE); + + op.params[0].tmpref.buffer = msg; + op.params[0].tmpref.size = msg_len; + op.params[1].tmpref.buffer = sig; + op.params[1].tmpref.size = *sig_len; + op.params[2].tmpref.buffer = mpmr; + op.params[2].tmpref.size = *mpmr_len; + + ret = pta_invoke_cmd(&manufacturing_protection_pta_ctx, + PTA_IMX_MP_CMD_SIGNATURE_MPMR, &op, NULL); + + if (ret != TEEC_SUCCESS) { + if (ret == TEEC_ERROR_SHORT_BUFFER) { + /* Update with the expected lengths */ + *sig_len = op.params[1].tmpref.size; + *mpmr_len = op.params[2].tmpref.size; + return ret; + } else if (ret == TEEC_ERROR_COMMUNICATION || + ret == TEEC_ERROR_OUT_OF_MEMORY) { + return ret; + } + + return TEEC_ERROR_GENERIC; + } + + *sig_len = op.params[1].tmpref.size; + *mpmr_len = op.params[2].tmpref.size; + + return TEEC_SUCCESS; +} + +TEEC_Result pta_imx_mprotect_final(void) +{ + return pta_final(&manufacturing_protection_pta_ctx); +} diff --git a/libptateec/src/pta_imx_manufacturing_protection.h b/libptateec/src/pta_imx_manufacturing_protection.h new file mode 100644 index 00000000..fe4c274d --- /dev/null +++ b/libptateec/src/pta_imx_manufacturing_protection.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright 2018-2019, 2023 NXP + */ +#ifndef PTA_IMX_MANUFACTURING_PROTECTION_H +#define PTA_IMX_MANUFACTURING_PROTECTION_H + +#define PTA_MANUFACT_PROTEC_UUID { 0x83268b7c, 0x85e3, 0x11e8, \ + { 0xad, 0xc0, 0xfa, 0x7a, 0xe0, 0x1b, 0xbe, 0xbc} } + +/* + * Sign the given message with the manufacturing protection private key + * + * [in] memref[0].buffer Message buffer + * [in] memref[0].size Message size + * [out] memref[1].buffer Signature buffer + * [out] memref[1].size Signature size + * [out] memref[2].buffer MPMR buffer + * [out] memref[2].size MPMR size + */ +#define PTA_IMX_MP_CMD_SIGNATURE_MPMR 0 + +/* + * Get the manufacturing protection public key + * + * [out] memref[0].buffer Public key buffer + * [out] memref[0].size Public key size + * + * Return codes: + * TEE_SUCCESS - Invoke command success + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param + */ +#define PTA_IMX_MP_CMD_GET_PUBLIC_KEY 1 + +#endif /* PTA_IMX_MANUFACTURING_PROTECTION_H */