From 248bd66d8eacf2e77d1ca0f38955d516cb64730a Mon Sep 17 00:00:00 2001 From: Paolo Stivanin Date: Fri, 4 Oct 2024 10:19:44 +0200 Subject: [PATCH] Add mbedtls support based on the work of Rockyshen123 (pull#66) --- .circleci/config.yml | 49 ++++++++++++++--- CMakeLists.txt | 16 ++++-- README.md | 8 +-- cmake/FindMbedTLS.cmake | 111 ++++++++++++++++++++++++++++++++++++++ src/utils/whmac_mbedtls.c | 94 ++++++++++++++++++++++++++++++++ src/utils/whmac_openssl.c | 4 +- 6 files changed, 264 insertions(+), 18 deletions(-) create mode 100644 cmake/FindMbedTLS.cmake create mode 100644 src/utils/whmac_mbedtls.c diff --git a/.circleci/config.yml b/.circleci/config.yml index d1c839a..ad779d9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,6 +8,7 @@ jobs: - checkout - run: command: | + export DEBIAN_FRONTEND=noninteractive apt update && apt -y install git gcc clang cmake libcriterion-dev libgcrypt20-dev mkdir build && cd "$_" cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTS=ON .. @@ -15,13 +16,14 @@ jobs: ./tests/test_base32encode ./tests/test_base32decode ./tests/test_cotp - ubuntu2204_gcrypt: + ubuntu2404_gcrypt: docker: - - image: ubuntu:22.04 + - image: ubuntu:24.04 steps: - checkout - run: command: | + export DEBIAN_FRONTEND=noninteractive apt update && apt -y install git gcc clang cmake libcriterion-dev libgcrypt20-dev mkdir build && cd "$_" cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTS=ON .. @@ -36,6 +38,7 @@ jobs: - checkout - run: command: | + export DEBIAN_FRONTEND=noninteractive apt update && apt -y install git gcc clang cmake libcriterion-dev libssl-dev mkdir build && cd "$_" cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTS=ON -DHMAC_WRAPPER=openssl .. @@ -43,13 +46,14 @@ jobs: ./tests/test_base32encode ./tests/test_base32decode ./tests/test_cotp - ubuntu2204_openssl: + ubuntu2404_openssl: docker: - - image: ubuntu:22.04 + - image: ubuntu:24.04 steps: - checkout - run: command: | + export DEBIAN_FRONTEND=noninteractive apt update && apt -y install git gcc clang cmake libcriterion-dev libssl-dev mkdir build && cd "$_" cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTS=ON -DHMAC_WRAPPER=openssl .. @@ -57,12 +61,43 @@ jobs: ./tests/test_base32encode ./tests/test_base32decode ./tests/test_cotp - + debianStable_mbedtls: + docker: + - image: debian:stable + steps: + - checkout + - run: + command: | + export DEBIAN_FRONTEND=noninteractive + apt update && apt -y install git gcc clang cmake libcriterion-dev libmbedtls-dev + mkdir build && cd "$_" + cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTS=ON -DHMAC_WRAPPER=mbedtls .. + make && make install + ./tests/test_base32encode + ./tests/test_base32decode + ./tests/test_cotp + ubuntu2404_mbedtls: + docker: + - image: ubuntu:24.04 + steps: + - checkout + - run: + command: | + export DEBIAN_FRONTEND=noninteractive + apt update && apt -y install git gcc clang cmake libcriterion-dev libmbedtls-dev + mkdir build && cd "$_" + cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTS=ON -DHMAC_WRAPPER=mbedtls .. + make && make install + ./tests/test_base32encode + ./tests/test_base32decode + ./tests/test_cotp workflows: version: 2 build: jobs: - debianStable_gcrypt - - ubuntu2204_gcrypt + - ubuntu2404_gcrypt - debianStable_openssl - - ubuntu2204_openssl + - ubuntu2404_openssl + - debianStable_mbedtls + - ubuntu2404_mbedtls diff --git a/CMakeLists.txt b/CMakeLists.txt index 0881228..27ccf1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,15 +11,15 @@ find_package(PkgConfig) option(BUILD_SHARED_LIBS "Build libcotp as a shared library" ON) option(BUILD_TESTS "Build base32 and cotp tests" OFF) +set(HMAC_WRAPPER "gcrypt" CACHE STRING "Choose between gcrypt (default), openssl or mbedtls for HMAC computation") +set_property(CACHE HMAC_WRAPPER PROPERTY STRINGS "gcrypt" "openssl" "mbedtls") -set(HMAC_WRAPPER "gcrypt" CACHE STRING "library to use during hmac computation") if("${HMAC_WRAPPER}" STREQUAL "gcrypt") set(HMAC_SOURCE_FILES src/utils/whmac_gcrypt.c ) find_package(Gcrypt 1.8.0 REQUIRED) set(HMAC_INCLUDE_DIR ${GCRYPT_INCLUDE_DIR}) - set(HMAC_LIBRARY_DIRS ${GCRYPT_LIBRARY_DIRS}) set(HMAC_LIBRARIES ${GCRYPT_LIBRARIES}) message("libcotp will use gcrypt for hmac") elseif("${HMAC_WRAPPER}" STREQUAL "openssl") @@ -28,15 +28,21 @@ elseif("${HMAC_WRAPPER}" STREQUAL "openssl") src/utils/whmac_openssl.c ) set(HMAC_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR}) - set(HMAC_LIBRARY_DIRS ${OPENSSL_LIBRARY_DIRS}) set(HMAC_LIBRARIES ${OPENSSL_LIBRARIES}) message("libcotp will use openssl for hmac") +elseif("${HMAC_WRAPPER}" STREQUAL "mbedtls") + find_package(MbedTLS REQUIRED) + set(HMAC_SOURCE_FILES + src/utils/whmac_mbedtls.c + ) + set(HMAC_INCLUDE_DIR ${MBEDTLS_INCLUDE_DIRS}) + set(HMAC_LIBRARIES ${MBEDTLS_LIBRARIES}) + message("libcotp will use mbedtls for hmac") else() message("libcotp can't use ${HMAC_WRAPPER} for hmac") endif() include_directories(${HMAC_INCLUDE_DIR}) -link_directories(${HMAC_LIBRARY_DIRS}) if (BUILD_TESTS) add_subdirectory(tests) @@ -109,4 +115,4 @@ if (PkgConfig_FOUND) configure_file("cotp.pc.in" "cotp.pc" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cotp.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig/) -endif() \ No newline at end of file +endif() diff --git a/README.md b/README.md index 23d8ba4..c10e16f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ C library that generates TOTP and HOTP according to [RFC-6238](https://tools.iet ## Requirements - GCC/Clang and CMake to build the library -- libgcrypt >= 1.8.0 or openssl >= 3.0.0 +- libgcrypt >= 1.8.0 or openssl >= 3.0.0 or mbedtls (works with both 2.x and 3.x) ## Build and Install ``` @@ -17,13 +17,13 @@ $ cd libcotp $ mkdir build && cd $_ $ cmake -DCMAKE_INSTALL_PREFIX=/usr .. $ make -# make install +$ sudo make install ``` Available options you can pass to `cmake`: * `-DBUILD_TESTS=ON`: if you want to compile also the tests (default **OFF**, requires criterion) -* `-DBUILD_SHARED_LIBS=ON`: if you want to build libcotp as a shared library (default **ON**) -* `-DHMAC_WRAPPER=""`: you can choose between GCrypt and OpenSSL (default **Gcrypt**) +* `-DBUILD_SHARED_LIBS=OFF`: if you want to build libcotp as a static library (default **ON**) +* `-DHMAC_WRAPPER=""`: you can choose between GCrypt, OpenSSL or MbedTLS (default **Gcrypt**) ## How To Use It ``` diff --git a/cmake/FindMbedTLS.cmake b/cmake/FindMbedTLS.cmake new file mode 100644 index 0000000..ea20c99 --- /dev/null +++ b/cmake/FindMbedTLS.cmake @@ -0,0 +1,111 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# Find the mbedtls library +# +# Input variables: +# +# MBEDTLS_INCLUDE_DIR The mbedtls include directory +# MBEDTLS_INCLUDE_DIRS The mbedtls include directory (deprecated) +# MBEDTLS_LIBRARY Path to mbedtls library +# MBEDX509_LIBRARY Path to mbedx509 library +# MBEDCRYPTO_LIBRARY Path to mbedcrypto library +# +# Result variables: +# +# MBEDTLS_FOUND System has mbedtls +# MBEDTLS_INCLUDE_DIRS The mbedtls include directories +# MBEDTLS_LIBRARIES The mbedtls library names +# MBEDTLS_VERSION Version of mbedtls + +if(DEFINED MBEDTLS_INCLUDE_DIRS AND NOT DEFINED MBEDTLS_INCLUDE_DIR) + message(WARNING "MBEDTLS_INCLUDE_DIRS is deprecated, use MBEDTLS_INCLUDE_DIR instead.") + set(MBEDTLS_INCLUDE_DIR "${MBEDTLS_INCLUDE_DIRS}") + unset(MBEDTLS_INCLUDE_DIRS) +endif() + +if(CURL_USE_PKGCONFIG) + find_package(PkgConfig QUIET) + pkg_check_modules(PC_MBEDTLS "mbedtls") +endif() + +find_path(MBEDTLS_INCLUDE_DIR NAMES "mbedtls/ssl.h" + HINTS + ${PC_MBEDTLS_INCLUDEDIR} + ${PC_MBEDTLS_INCLUDE_DIRS} +) + +find_library(MBEDTLS_LIBRARY NAMES "mbedtls" + HINTS + ${PC_MBEDTLS_LIBDIR} + ${PC_MBEDTLS_LIBRARY_DIRS} +) +find_library(MBEDX509_LIBRARY NAMES "mbedx509" + HINTS + ${PC_MBEDTLS_LIBDIR} + ${PC_MBEDTLS_LIBRARY_DIRS} +) +find_library(MBEDCRYPTO_LIBRARY NAMES "mbedcrypto" + HINTS + ${PC_MBEDTLS_LIBDIR} + ${PC_MBEDTLS_LIBRARY_DIRS} +) + +if(PC_MBEDTLS_VERSION) + set(MBEDTLS_VERSION ${PC_MBEDTLS_VERSION}) +elseif(MBEDTLS_INCLUDE_DIR) + if(EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h") # 3.x + set(_version_header "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h") + elseif(EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h") # 2.x + set(_version_header "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h") + else() + unset(_version_header) + endif() + if(_version_header) + set(_version_regex "#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"([0-9.]+)\"") + file(STRINGS "${_version_header}" _version_str REGEX "${_version_regex}") + string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}") + set(MBEDTLS_VERSION "${_version_str}") + unset(_version_regex) + unset(_version_str) + unset(_version_header) + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MbedTLS + REQUIRED_VARS + MBEDTLS_INCLUDE_DIR + MBEDTLS_LIBRARY + MBEDX509_LIBRARY + MBEDCRYPTO_LIBRARY + VERSION_VAR + MBEDTLS_VERSION +) + +if(MBEDTLS_FOUND) + set(MBEDTLS_INCLUDE_DIRS ${MBEDTLS_INCLUDE_DIR}) + set(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY}) +endif() + +mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY) diff --git a/src/utils/whmac_mbedtls.c b/src/utils/whmac_mbedtls.c new file mode 100644 index 0000000..2e817f3 --- /dev/null +++ b/src/utils/whmac_mbedtls.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include "../whmac.h" +#include "../cotp.h" + +typedef struct whmac_handle_s whmac_handle_t; + +struct whmac_handle_s +{ + mbedtls_md_context_t sha_ctx; + const mbedtls_md_info_t *md_info; + int algo; + size_t dlen; +}; + +int +whmac_check (void) +{ + return 0; +} + +size_t +whmac_getlen (whmac_handle_t *hd) +{ + return mbedtls_md_get_size(hd->md_info); +} + +whmac_handle_t * +whmac_gethandle (int algo) +{ + const mbedtls_md_type_t openssl_algo[] = { + MBEDTLS_MD_SHA1, + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA512, + }; + + whmac_handle_t *whmac_handle = calloc (1, sizeof(*whmac_handle)); + if (whmac_handle == NULL) { + return NULL; + } + + if (algo > 2) { + free (whmac_handle); + return NULL; + } + + mbedtls_md_init (&(whmac_handle->sha_ctx)); + whmac_handle->md_info = mbedtls_md_info_from_type (openssl_algo[algo]); + int ret = mbedtls_md_setup (&(whmac_handle->sha_ctx), whmac_handle->md_info, 1); + if (ret != 0) { + printf ("mbedtls_md_setup() returned -0x%04x\n", -ret); + mbedtls_md_free (&(whmac_handle->sha_ctx)); + free (whmac_handle); + return NULL; + } + + return whmac_handle; +} + +void +whmac_freehandle (whmac_handle_t *hd) +{ + mbedtls_md_free (&(hd->sha_ctx)); + free (hd); +} + +int +whmac_setkey (whmac_handle_t *hd, + unsigned char *buffer, + size_t buflen) +{ + mbedtls_md_hmac_starts (&(hd->sha_ctx), buffer, buflen); + return NO_ERROR; +} + +void +whmac_update (whmac_handle_t *hd, + unsigned char *buffer, + size_t buflen) +{ + mbedtls_md_hmac_update (&(hd->sha_ctx), buffer, buflen); +} + +ssize_t +whmac_finalize (whmac_handle_t *hd, + unsigned char *buffer, + size_t buflen) +{ + mbedtls_md_hmac_finish (&(hd->sha_ctx), buffer); + + return buflen; +} + diff --git a/src/utils/whmac_openssl.c b/src/utils/whmac_openssl.c index 2ce5579..b78378c 100644 --- a/src/utils/whmac_openssl.c +++ b/src/utils/whmac_openssl.c @@ -52,8 +52,8 @@ whmac_gethandle (int algo) size_t params_n = 0; - whmac_handle->mac_params[params_n++] = OSSL_PARAM_construct_utf8_string("digest", (char *)openssl_algo[algo], 0); - whmac_handle->mac_params[params_n] = OSSL_PARAM_construct_end(); + whmac_handle->mac_params[params_n++] = OSSL_PARAM_construct_utf8_string ("digest", (char *)openssl_algo[algo], 0); + whmac_handle->mac_params[params_n] = OSSL_PARAM_construct_end (); } return whmac_handle; }