diff --git a/CMakeLists.txt b/CMakeLists.txt index cd52905..ebef363 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,13 +43,11 @@ set(SRC_EXAMPLE_DIR ${PROJECT_SOURCE_DIR}/test) find_package(OpenSSL REQUIRED) -if(DEFINED ENV{NDEBUG}) - add_definitions(-DNDEBUG=1 -O2) -else() - add_definitions(-g -O0) - add_definitions(-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all) - link_libraries("-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all") -endif() +# Add this to get some additional runtime checks. +# Warning: it's incompatible with tools like Valgrind and you have to add it to the app using this lib too. +# add_definitions("-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all") +# link_libraries("-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all") + add_definitions(-Wall -Woverflow -Wextra -Wswitch -Wmissing-prototypes -Wstrict-prototypes -Wformat -Wtype-limits -Wundef -Wconversion -Wno-shadow -Wno-conversion -Wno-sign-conversion -Wno-unused-parameter -Wno-sign-compare) # TODO enable -Wconversion -Wsign-conversion -Wsign-compare -Wunused-parameter add_definitions(-Wformat -Wformat-security -Wno-declaration-after-statement -Wno-vla) # -Wpointer-arith -pedantic -DPEDANTIC # -Werror @@ -75,6 +73,7 @@ set(SECUTIL_LIB_SRC ${SRC_DIR}/certstatus/certstatus.c ${SRC_DIR}/connections/conn.c ${SRC_DIR}/connections/http.c ${SRC_DIR}/connections/tls.c + ${SRC_DIR}/credentials/cert.c ${SRC_DIR}/credentials/credentials.c ${SRC_DIR}/credentials/key.c ${SRC_DIR}/credentials/store.c diff --git a/Makefile b/Makefile index d080f41..41ed47d 100644 --- a/Makefile +++ b/Makefile @@ -57,12 +57,16 @@ endif # Note: stuff for testing purposes should go here ################################################################################ -ifdef NDEBUG +ifdef DEBUG + DEBUG_FLAGS ?= -g -O0 +# Add this to get some additional runtime checks. +# Warning: it's incompatible with tools like Valgrind and you have to add it to the app using this lib too +# DEBUG_FLAGS += -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all +else DEBUG_FLAGS ?= -O2 override DEBUG_FLAGS += -DNDEBUG=1 -else - DEBUG_FLAGS ?= -g -O0 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all # not every compiler(version) supports -Og endif + override CFLAGS += $(DEBUG_FLAGS) -Wall -Woverflow -Wextra -Wswitch -Wmissing-prototypes -Wstrict-prototypes -Wformat -Wtype-limits -Wundef -Wconversion override CFLAGS += -Wno-shadow -Wno-conversion -Wno-sign-conversion -Wno-sign-compare -Wno-unused-parameter # TODO clean up code and enable -Wshadow -Wconversion -Wsign-conversion -Wsign-compare -Wunused-parameter override CFLAGS += -Wformat -Wformat-security -Wno-declaration-after-statement -Wno-vla # -Wpointer-arith -pedantic -DPEDANTIC # -Werror @@ -150,11 +154,13 @@ ifeq ($(COV_ENABLED), 1) endif $(MAKE) COMPILE_TYPE=$(COMPILE_TYPE) build_only -util: +util: $(OUT_DIR)/$(OUTLIB) $(MAKE) -C util SECUTILS_USE_UTA="$(SECUTILS_USE_UTA)" \ CFLAGS="$(CFLAGS) $(LOCAL_CFLAGS)" LDFLAGS="$(LDFLAGS)" -build_all: build util +build_all: + $(MAKE) build + $(MAKE) util # Binary output target $(OUT_DIR)/$(OUTLIB).$(VERSION): $(OBJS) @@ -219,10 +225,10 @@ clean_uta: $(OUT_DIR)/$(OUTLIB)* $(OUT_DIR)/util/$(OUTBIN) $(OUT_DIR)/util/icvutil.o clean: + $(MAKE) -C util clean rm -rf $(OUT_DIR)/$(OUTLIB)* $(OUT_DIR)/util/$(OUTBIN) $(BUILDDIR) clean_all: clean clean_deb - $(MAKE) -C util clean rm -rf doc refman.pdf *.gcov reports doc: doc/html refman.pdf diff --git a/debian/rules b/debian/rules index f94832c..cb55fb2 100755 --- a/debian/rules +++ b/debian/rules @@ -25,7 +25,8 @@ override_dh_auto_clean: # adding compile flags as, defaults are commonly debug flags override_dh_auto_build: -# CFLAGS="-O2 -DNDEBUG" CXXFLAGS="-O2 -DNDEBUG" DEBUG_FLAGS="" LDFLAGS="" # can be used to avoid dependency on libasan and libubsan +# clear DEBUG_FLAGS so that the default debian options get applied + DEBUG_FLAGS="" \ OPENSSL_DIR=/usr CC=$(CC) CXX=$(CXX) AR=$(AR) \ dh_auto_build -- -j1 build_only util diff --git a/include/secutils/certstatus/certstatus.h b/include/secutils/certstatus/certstatus.h index eb7948d..f9ab7b7 100644 --- a/include/secutils/certstatus/certstatus.h +++ b/include/secutils/certstatus/certstatus.h @@ -17,6 +17,7 @@ #define SECUTILS_CERTSTATUS_H_ #include + #include "../util/log.h" #if OPENSSL_VERSION_NUMBER < 0x10101000L diff --git a/include/secutils/certstatus/crl_mgmt.h b/include/secutils/certstatus/crl_mgmt.h index ccf488b..5a59c18 100644 --- a/include/secutils/certstatus/crl_mgmt.h +++ b/include/secutils/certstatus/crl_mgmt.h @@ -17,7 +17,8 @@ #define SECUTILS_HEADER_CRL_MGMT_H #include -#include + +#include "../basic.h" #ifdef __cplusplus extern "C" { diff --git a/include/secutils/certstatus/crls.h b/include/secutils/certstatus/crls.h index 9b5e5d6..5c2ecd3 100644 --- a/include/secutils/certstatus/crls.h +++ b/include/secutils/certstatus/crls.h @@ -16,6 +16,8 @@ #ifndef SECUTILS_CRLS_H_ #define SECUTILS_CRLS_H_ +#include "../basic.h" + #include /*!***************************************************************************** diff --git a/include/secutils/credentials/cert.h b/include/secutils/credentials/cert.h index 1bf046a..fe72859 100644 --- a/include/secutils/credentials/cert.h +++ b/include/secutils/credentials/cert.h @@ -26,8 +26,7 @@ #include /* for strcmp, strlen */ #include "../basic.h" -#include "../operators.h" -# include "../util/log.h" +#include "../util/log.h" #include diff --git a/include/secutils/credentials/verify.h b/include/secutils/credentials/verify.h index c3bfbeb..bbf0ad3 100644 --- a/include/secutils/credentials/verify.h +++ b/include/secutils/credentials/verify.h @@ -74,15 +74,13 @@ bool verify_cb_cert(X509_STORE_CTX* store_ctx, X509* cert, int err); /*!***************************************************************************** * @brief attempt to verify certificate * - * @param ctx (optional) pointer to UTA context, unused * @param cert certificate to be verified * @param untrusted (optional) intermediate certs that may be useful for building * the chain of certificates between the cert and the trusted certs in the trust store * @param trust_store pointer to structure containing trusted (root) certs and further verification parameters * @note trust_store may contain CRLs loaded via STORE_load_crl_dir() - * @return < 0 on on verification error, 0 for invalid cert, 1 for vaild cert + * @return < 0 on on verification error, 0 for invalid cert, 1 for valid cert *******************************************************************************/ -int CREDENTIALS_verify_cert(OPTIONAL uta_ctx* ctx, X509* cert, - OPTIONAL const STACK_OF(X509) * untrusted, X509_STORE* trust_store); +int CREDENTIALS_verify_cert(X509* cert, OPTIONAL const STACK_OF(X509) * untrusted, X509_STORE* trust_store); #endif /* SECUTILS_VERIFY_H_ */ diff --git a/include/secutils/storage/files_dv.h b/include/secutils/storage/files_dv.h index bf87542..e00adcc 100644 --- a/include/secutils/storage/files_dv.h +++ b/include/secutils/storage/files_dv.h @@ -25,6 +25,8 @@ #include +#include "../util/util.h" + #include "../storage/uta_api.h" #define MAX_UTA_PASS_LEN (MAX_B64_CHARS_PER_BYTE * TA_OUTLEN + 1) #include "files.h" diff --git a/include/secutils/storage/files_icv.h b/include/secutils/storage/files_icv.h index f361e9b..af50913 100644 --- a/include/secutils/storage/files_icv.h +++ b/include/secutils/storage/files_icv.h @@ -20,6 +20,7 @@ #include "../storage/uta_api.h" #include +#include /*! * @brief (re-)protect integrity of file (of any type that allows appending text) with ICV derived via UTA @@ -126,5 +127,16 @@ bool FILES_store_cert_pem(OPTIONAL uta_ctx* ctx, const X509* cert, const char* f */ bool FILES_store_crl_pem_icv(OPTIONAL uta_ctx* ctx, const X509_CRL* crl, const char* file, OPTIONAL const char* desc); +/*! + * @brief Calculates a file's ICV and, if it is equal to the ICV stored in the file, returns the content without ICV. + * + * @param ctx pointer to UTA context, which typically is part of the libsecutils context + * @param path path to the file, can be relative or absolute + * @note if \p path is relative, it is transformed into absolute path + * @return \c OPENSSL_STRING containing content of the file if ICV matches, otherwise null pointer. + * In case of an error, message is logged and null pointer is returned. + * @warning Returned \c OPENSSL_STRING must be freed using function \c OPENSSL_free(). + */ +OPENSSL_STRING FILE_get_file_content_if_existing_icv_is_valid(uta_ctx* ctx, const char* path); #endif /* SECUTILS_FILES_ICV_H_ */ diff --git a/include/secutils/util/util.h b/include/secutils/util/util.h index 11c82fc..0719785 100644 --- a/include/secutils/util/util.h +++ b/include/secutils/util/util.h @@ -30,11 +30,12 @@ # include # include "../basic.h" -# include "../operators.h" # include # include +# include "../storage/uta_api.h" + static const char *const UTIL_SECUTILS_NAME = "secutils"; /*!< short name of this library */ static const int UTIL_max_path_len = 512; /*!< max length of file path name */ @@ -370,6 +371,7 @@ size_t UTIL_url_encode(const char *source, # define HEX_BITS 4 # define HEX_MASK 0x0f # define MAX_DIGIT 9 +# define ICV_LEN16 16 /*! * @brief The function converts a binary string into a sequence of hex values. @@ -435,4 +437,33 @@ int UTIL_base64_encode_to_buf(const unsigned char *data, int len, unsigned char *UTIL_base64_decode(const char *b64_data, int b64_len, int *decoded_len); +/*! + * @brief derive integrity protection hash for data with given len, using key as DV. + * + * @param ctx pointer to uta context object + * @param data pointer to data from which the ICV will be calculated + * @param data_len size of data from which the ICV will be calculated + * @param key_dv The derivation value for key for which the ICV is calculated + * @param icv_out Pointer to a buffer where the resulting ICV will be stored. This buffer must be at least + * ICV_LEN16 in size. + * @return true if calculating the ICV is successful, false otherwise + */ +bool UTIL_calculate_icv(uta_ctx* ctx, const unsigned char* data, const size_t data_len, const char* key_dv, + unsigned char* icv_out); + +/*! + * @brief implementation of the function UTIL_calculate_icv. + * @note this function was created to avoid code repetition (the same computation is needed in files_icv.c). + * + * @param ctx pointer to uta context object + * @param data pointer to data from which the ICV will be calculated + * @param data_len size of data from which the ICV will be calculated + * @param key_dv The derivation value for key for which the ICV is calculated + * @param mac Pointer to a buffer where the resulting ICV will be stored. This buffer must be at least + * ICV_LEN16 in size. + * @return true if calculating the ICV is successful, false otherwise + */ +bool UTIL_calculate_icv_impl(uta_ctx* ctx, const unsigned char* data, const size_t data_len, const char* key_dv, + unsigned char* mac); + #endif /* SECUTILS_UTIL_H_ */ diff --git a/src/certstatus/certstatus.c b/src/certstatus/certstatus.c index 5ee6c09..528cb0b 100644 --- a/src/certstatus/certstatus.c +++ b/src/certstatus/certstatus.c @@ -1,13 +1,13 @@ -/** +/** * @file certstatus.c -* +* * @brief Certificate status checking using CRLs and/or OCSP * * @copyright Copyright (c) Siemens Mobility GmbH, 2021 * * @author David von Oheimb * -* This work is licensed under the terms of the Apache Software License +* This work is licensed under the terms of the Apache Software License * 2.0. See the COPYING file in the top-level directory. * * SPDX-License-Identifier: Apache-2.0 @@ -28,7 +28,7 @@ # include #endif -#include +#include "secutils/operators.h" static unsigned int num_CDPs(const X509* cert) { diff --git a/src/certstatus/crls.c b/src/certstatus/crls.c index c9d545d..370e303 100644 --- a/src/certstatus/crls.c +++ b/src/certstatus/crls.c @@ -27,7 +27,7 @@ #include #include -#include +#include "secutils/operators.h" /* adapted from OpenSSL:crypto/x509/t_crl.c */ void UTIL_print_crl(OPTIONAL BIO* bio, OPTIONAL const X509_CRL* crl) diff --git a/src/certstatus/ocsp.c b/src/certstatus/ocsp.c index 5ff03a0..10da48e 100644 --- a/src/certstatus/ocsp.c +++ b/src/certstatus/ocsp.c @@ -29,7 +29,7 @@ # include # endif -# include +#include "secutils/operators.h" OCSP_RESPONSE* CONN_load_OCSP_http(const char* url, int timeout, const OCSP_REQUEST* req, diff --git a/src/config/config.c b/src/config/config.c index 6598a13..93c833e 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -22,7 +22,7 @@ #include #include -#include +#include "secutils/operators.h" /* adapted from OpenSSL:apps/include/apps.h */ static opt_t vpm_opts[] = { OPT_V_OPTIONS, OPT_END }; diff --git a/src/config/config_update.c b/src/config/config_update.c index 0d0d66b..58ab986 100644 --- a/src/config/config_update.c +++ b/src/config/config_update.c @@ -17,7 +17,7 @@ #include #include -#include +#include "secutils/operators.h" static void skip_space(char** p) diff --git a/src/config/opt.c b/src/config/opt.c index f41a454..ebd39ec 100644 --- a/src/config/opt.c +++ b/src/config/opt.c @@ -19,7 +19,7 @@ #include /* for strtoimax on Linux */ -#include +#include "secutils/operators.h" const char OPT_more_str[] = "-M"; const char OPT_section_str[] = "-S"; diff --git a/src/connections/conn.c b/src/connections/conn.c index 907587f..f61f2ba 100644 --- a/src/connections/conn.c +++ b/src/connections/conn.c @@ -21,7 +21,7 @@ # include #endif -#include +#include "secutils/operators.h" static const char* skip_scheme(const char* str) { diff --git a/src/connections/http.c b/src/connections/http.c index 3859e96..454992f 100644 --- a/src/connections/http.c +++ b/src/connections/http.c @@ -16,7 +16,6 @@ #if !defined(OPENSSL_NO_OCSP) && !defined(OPENSSL_NO_SOCK) # include -# include # include # include # ifndef SECUTILS_NO_TLS @@ -29,6 +28,8 @@ # endif # include +# include "secutils/operators.h" + /* TODO replace this all by new API in http.h of OpenSSL 3.0 */ static int REQ_CTX_i2d(OCSP_REQ_CTX* rctx, const char* content_type, diff --git a/src/connections/tls.c b/src/connections/tls.c index d611c1b..b141a41 100644 --- a/src/connections/tls.c +++ b/src/connections/tls.c @@ -29,7 +29,7 @@ #include #endif -#include +#include "secutils/operators.h" bool TLS_init(void) { diff --git a/src/credentials/cert.c b/src/credentials/cert.c index bc16638..6886d24 100644 --- a/src/credentials/cert.c +++ b/src/credentials/cert.c @@ -19,7 +19,7 @@ #include #include -#include +#include "secutils/operators.h" X509 *CERT_load(const char *file, OPTIONAL const char *source, diff --git a/src/credentials/credentials.c b/src/credentials/credentials.c index 58fdb64..df3218e 100644 --- a/src/credentials/credentials.c +++ b/src/credentials/credentials.c @@ -27,7 +27,7 @@ #include #include -#include +#include "secutils/operators.h" /* this type is part of the genCMPClient API */ struct credentials diff --git a/src/credentials/key.c b/src/credentials/key.c index c0f2314..d57e4e1 100644 --- a/src/credentials/key.c +++ b/src/credentials/key.c @@ -20,7 +20,7 @@ #include #include -#include +#include "secutils/operators.h" EVP_PKEY* KEY_new(const char* spec) { diff --git a/src/credentials/store.c b/src/credentials/store.c index 328ad07..339d558 100644 --- a/src/credentials/store.c +++ b/src/credentials/store.c @@ -26,7 +26,7 @@ #include #include -#include +#include "secutils/operators.h" typedef struct STORE_ex_st { diff --git a/src/credentials/trusted.c b/src/credentials/trusted.c index ef07eda..d862854 100644 --- a/src/credentials/trusted.c +++ b/src/credentials/trusted.c @@ -20,7 +20,7 @@ #include #include -#include +#include "secutils/operators.h" static const char* config_file(void) { diff --git a/src/credentials/verify.c b/src/credentials/verify.c index fcfb263..d2be773 100644 --- a/src/credentials/verify.c +++ b/src/credentials/verify.c @@ -23,7 +23,7 @@ #include #include -#include +#include "secutils/operators.h" bool STORE_CTX_tls_active(const X509_STORE_CTX* ctx) @@ -183,8 +183,7 @@ bool verify_cb_cert(X509_STORE_CTX* store_ctx, X509* cert, int err) return verify_cb != 0 and (*verify_cb)(0, store_ctx) != 0; } -int CREDENTIALS_verify_cert(OPTIONAL uta_ctx* uta_ctx, X509* cert, - OPTIONAL const STACK_OF(X509) * untrusted_certs, X509_STORE* trust_store) +int CREDENTIALS_verify_cert(X509* cert, OPTIONAL const STACK_OF(X509) * untrusted_certs, X509_STORE* trust_store) { int result = -1; X509_STORE_CTX* store_ctx = 0; diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c index 5c6a8c8..da0b263 100644 --- a/src/crypto/crypto.c +++ b/src/crypto/crypto.c @@ -13,7 +13,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include "secutils/operators.h" #include #include diff --git a/src/storage/files.c b/src/storage/files.c index 771b23f..bc90d96 100644 --- a/src/storage/files.c +++ b/src/storage/files.c @@ -33,7 +33,7 @@ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #include # include -#include +#include "secutils/operators.h" static file_format_t adjust_format(const char* * file, file_format_t format, bool engine_ok) { diff --git a/src/storage/files_dv.c b/src/storage/files_dv.c index 576cf1e..01f6cba 100644 --- a/src/storage/files_dv.c +++ b/src/storage/files_dv.c @@ -28,7 +28,7 @@ static const char* const DV_SECTION = "dv"; /*! name of DVFILE section with DV s #include #include -#include +#include "secutils/operators.h" /* Get device-specific password (base64 encoded) */ static bool getBase64Password(OPTIONAL uta_ctx* ctx, const unsigned char* dv, char* pw) diff --git a/src/storage/files_icv.c b/src/storage/files_icv.c index 958e755..d2cfa62 100644 --- a/src/storage/files_icv.c +++ b/src/storage/files_icv.c @@ -13,15 +13,16 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include +#include #include #include #include #include -#include -#include +#include "secutils/operators.h" #define ICVLEN 16 @@ -37,43 +38,10 @@ */ static bool calculate_icv_hex(OPTIONAL uta_ctx* ctx, const void* data, size_t len, const char* name, char* buf) { - unsigned char key[TA_OUTLEN]; unsigned char md[SHA256_DIGEST_LENGTH]; - unsigned int md_len; - -/* Derive an ICV key from the trust anchor */ -#ifdef SECUTILS_USE_UTA - bool uta_res = uta_getkey(ctx, (const unsigned char*)name, strnlen(name, UTIL_max_path_len), key, TA_OUTLEN); - - if(not uta_res) - { - LOG(FL_ERR, "Could not get key for '%s' from UTA", name); - return false; - } -#else - if(ctx not_eq 0) - { - LOG(FL_ERR, "UTA not available"); - return false; - } - /* some trivial emulation of trust anchor */ -#if TA_OUTLEN != SHA256_DIGEST_LENGTH -#error Cannot produce KEY with length other than SHA256_DIGEST_LENGTH -#endif - if(0 is_eq SHA256((const unsigned char*)name, strlen(name), key)) - { - LOG(FL_ERR, "ERROR during SHA256 calculation from: %s", name); - return false; - } - unsigned char tmp = key[3]; - key[3] = key[25]; - key[25] = key[10]; - key[10] = tmp; -#endif - if(0 is_eq HMAC(EVP_sha256(), key, TA_OUTLEN, data, len, md, &md_len) or md_len < ICVLEN) + if (false is_eq UTIL_calculate_icv_impl(ctx, data, len, name, md)) { - LOG(FL_ERR, "Could not calculate HMAC used as ICV for '%s'", name); return false; } @@ -135,13 +103,13 @@ static bool protect_or_check_icv(OPTIONAL uta_ctx* ctx, const char* file, const } else { - buf = OPENSSL_malloc(fsize); + buf = OPENSSL_malloc((size_t)fsize); if(buf is_eq 0) { LOG(FL_ERR, "Out of memory reading file '%s'", file); goto err; } - if((size_t)fsize not_eq fread(buf, 1, fsize, f)) + if((size_t)fsize not_eq fread(buf, 1, (size_t)fsize, f)) { LOG(FL_ERR, "Could not read file '%s'", file); goto err; @@ -155,7 +123,7 @@ static bool protect_or_check_icv(OPTIONAL uta_ctx* ctx, const char* file, const { if(found) { - fsize -= ICV_LINE_LEN; /* strip existing ICV */ + fsize -= (long)ICV_LINE_LEN; /* strip existing ICV */ if(fseek(f, fsize, SEEK_SET) is_eq EOF) { LOG(FL_ERR, "Could not strip ICV from file '%s'", file); @@ -171,7 +139,7 @@ static bool protect_or_check_icv(OPTIONAL uta_ctx* ctx, const char* file, const goto err; } } - if(not calculate_icv_hex(ctx, buf, fsize - (protect ? 0 : ICV_LINE_LEN), location, icv_hex)) + if(not calculate_icv_hex(ctx, buf, (size_t)(fsize - (protect ? 0 : (long)ICV_LINE_LEN)), location, icv_hex)) { LOG(FL_ERR, "Could not calculate ICV for file '%s'", file); goto err; @@ -289,3 +257,104 @@ bool FILES_store_crl_pem_icv(OPTIONAL uta_ctx* ctx, const X509_CRL* crl, const c } return true; } + +static inline long get_file_size(FILE* f) +{ + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + return fsize; +} + +OPENSSL_STRING FILE_get_file_content_if_existing_icv_is_valid(uta_ctx* ctx, const char* path) +{ + if(0 is_eq ctx) + { + LOG(FL_ERR, "No context"); + return 0; + } + + if(0 is_eq path) + { + LOG(FL_ERR, "No path to ICV file"); + return 0; + } + + char absolute_path[PATH_MAX]; + if(0 is_eq realpath(path, absolute_path)) + { + LOG(FL_ERR, "Could not resolve absolute path from: %s", path); + return 0; + } + + // open file + FILE* file = fopen(absolute_path, "rb"); + if(0 is_eq file) + { + LOG(FL_ERR, "Could not open file '%s'", absolute_path); + return 0; + } + + const long file_size = get_file_size(file); + + if(file_size < 0) + { + LOG(FL_ERR, "Could not get size of file '%s'", absolute_path); + } + else if(0 is_eq file_size) + { + LOG(FL_ERR, "File '%s' is empty", absolute_path); + } + else + { + OPENSSL_STRING content = OPENSSL_malloc((size_t)file_size + 1); + if(0 is_eq content) + { + LOG(FL_ERR, "Out of memory reading file '%s'", absolute_path); + goto error; + } + if((size_t)file_size not_eq fread(content, sizeof *content, (size_t)file_size, file)) + { + LOG(FL_ERR, "Could not read file '%s'", absolute_path); + goto error; + } + content[file_size] = '\0'; + + const long icv_tag_start_index = file_size - (long)ICV_LINE_LEN; + const char* icv_tag_start = content + icv_tag_start_index; + const char* icv_hex_start = content + file_size - ICV_HEX_LEN - 1; + + const bool found = (file_size >= ICV_LINE_LEN) and (0 is_eq strncmp(icv_tag_start, ICV_TAG, strlen(ICV_TAG))); + if(false is_eq found) + { + LOG(FL_ERR, "Could not find ICV at end of file '%s'", absolute_path); + goto error; + } + + // read original ICV + char original_icv_hex[ICV_HEX_LEN + 1] = {'\0'}; + strncpy(original_icv_hex, icv_hex_start, ICV_HEX_LEN); + + // calculate ICV + char icv_hex[ICV_HEX_LEN + 1] = {'\0'}; + if(not calculate_icv_hex(ctx, content, (size_t)icv_tag_start_index, absolute_path, icv_hex)) + { + LOG(FL_ERR, "Could not calculate ICV for file '%s'", absolute_path); + goto error; + } + + // if ICVs are equal then return whole file content without ICV + if(0 is_eq strncmp(original_icv_hex, icv_hex, ICV_HEX_LEN)) + { + fclose(file); + // "remove" ICV part in string content + content[icv_tag_start_index] = '\0'; + return content; + } + error: + OPENSSL_free(content); + } + + fclose(file); + return 0; +} diff --git a/src/storage/uta_api.c b/src/storage/uta_api.c index e2a910f..fc6c064 100644 --- a/src/storage/uta_api.c +++ b/src/storage/uta_api.c @@ -21,7 +21,7 @@ #include #include -#include +#include "secutils/operators.h" #if DVLEN not_eq UTA_LEN_DV_V1 #error DVLEN not_eq UTA_LEN_DV_V1 /* mismatch with uta.h */ diff --git a/src/util/extensions.c b/src/util/extensions.c index 4b5453b..14d2730 100644 --- a/src/util/extensions.c +++ b/src/util/extensions.c @@ -16,7 +16,7 @@ #include "util/extensions.h" #include "util/log.h" -#include +#include "secutils/operators.h" X509_EXTENSIONS* EXTENSIONS_new(void) diff --git a/src/util/log.c b/src/util/log.c index f8ff0fa..5b45bf7 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -16,12 +16,12 @@ #include #include -#include - #include #include +#include "secutils/operators.h" + // use the GNU-specific `strerror_r` // https://man7.org/linux/man-pages/man3/strerror.3.html : SYNOPSIS #define _GNU_SOURCE diff --git a/src/util/util.c b/src/util/util.c index 5c1d3c3..ee6b00c 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -24,7 +24,7 @@ #include -#include +#include "secutils/operators.h" int UTIL_atoint(const char* str) { @@ -660,3 +660,86 @@ unsigned char* UTIL_base64_decode(const char* b64_data, int b64_len, int* decode BIO_free_all(bio_b64); return decoded_data; } + + +bool UTIL_calculate_icv_impl(uta_ctx* ctx, const unsigned char* data, const size_t data_len, const char* key_dv, + unsigned char* mac) +{ + unsigned char dk[TA_OUTLEN]; + unsigned int md_len; + +/* Derive an ICV key from the trust anchor */ +#ifdef SECUTILS_USE_UTA + const bool uta_res = + uta_getkey(ctx, (const unsigned char*)key_dv, strnlen(key_dv, UTIL_max_path_len), dk, TA_OUTLEN); + if(not uta_res) + { + LOG(FL_ERR, "Could not get key for '%s' from UTA", key_dv); + return false; + } +#else /* SECUTILS_USE_UTA */ + if(ctx not_eq 0) + { + LOG(FL_ERR, "UTA not available"); + return false; + } + /* trivial emulation of trust anchor */ +#if TA_OUTLEN != SHA256_DIGEST_LENGTH +#error Cannot produce KEY with length other than SHA256_DIGEST_LENGTH +#endif + if(0 is_eq SHA256((const unsigned char*)key_dv, strlen(key_dv), dk)) + { + LOG(FL_ERR, "ERROR during SHA256 calculation from: %s", key_dv); + return false; + } + unsigned char tmp = dk[3]; + dk[3] = dk[25]; + dk[25] = dk[10]; + dk[10] = tmp; +#endif /* SECUTILS_USE_UTA */ + + if(0 is_eq HMAC(EVP_sha256(), dk, TA_OUTLEN, data, data_len, mac, &md_len) or md_len < ICV_LEN16) + { + LOG(FL_ERR, "Could not calculate HMAC used as ICV for '%s'", key_dv); + return false; + } + return true; +} + + +bool UTIL_calculate_icv(uta_ctx* ctx, const unsigned char* data, const size_t data_len, const char* key_dv, + unsigned char* icv_out) +{ + unsigned char mac[SHA256_DIGEST_LENGTH]; + + if (0 is_eq ctx) + { + LOG(FL_ERR, "No context"); + return false; + } + + if (0 is_eq data) + { + LOG(FL_ERR, "No data to calculate ICV from"); + return false; + } + + if (0 is_eq key_dv) + { + LOG(FL_ERR, "No key_dv to calculate ICV for"); + return false; + } + + if (0 is_eq icv_out) + { + LOG(FL_ERR, "Invalid output buffer"); + return false; + } + + if (false is_eq UTIL_calculate_icv_impl(ctx, data, data_len, key_dv, mac)) + { + return false; + } + memcpy(icv_out, mac, ICV_LEN16); + return true; +}