From d143d3c0e16759ae45e7d9ce2309de68a11de181 Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Thu, 23 Nov 2023 14:03:26 +0000 Subject: [PATCH] wolfSSL: Set up initial port Includes some porting ideas from qursa-uc3m libcoap-wolfssl work. Some common ASN1 code moved from coap_gnutls.c to coap_asn1.c to support RPK. Interoperability requirements DTLS1.3 downgrade requires https://github.com/eclipse/tinydtls/pull/230 https://github.com/wolfSSL/wolfssl/pull/7367 TLS1.3 downgrade requires https://github.com/wolfSSL/wolfssl/pull/7367 (D)TLS1.2 use of RPK requires https://github.com/wolfSSL/wolfssl/pull/7375 MbedTLS using TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 requires https://github.com/wolfSSL/wolfssl/pull/7132 --- .github/workflows/main.yml | 8 +- BUILDING | 3 + CMakeLists.txt | 84 +- CMakeLists.txt.in | 84 +- LICENSE | 7 + Makefile.am | 2 + README.md | 2 + cmake/FindwolfSSL.cmake | 86 + cmake_coap_config.h.in | 3 + configure.ac | 78 +- doc/main.md | 2 + examples/share.libcoap.examples.Makefile | 3 +- include/coap3/coap_asn1_internal.h | 13 + include/coap3/coap_dtls.h | 1 + m4/ac_check_cryptolibs.m4 | 14 + man/coap_address.txt.in | 1 + man/coap_async.txt.in | 1 + man/coap_attribute.txt.in | 1 + man/coap_block.txt.in | 1 + man/coap_cache.txt.in | 1 + man/coap_context.txt.in | 1 + man/coap_deprecated.txt.in | 1 + man/coap_encryption.txt.in | 11 + man/coap_endpoint_client.txt.in | 1 + man/coap_endpoint_server.txt.in | 1 + man/coap_handler.txt.in | 1 + man/coap_init.txt.in | 1 + man/coap_io.txt.in | 1 + man/coap_keepalive.txt.in | 1 + man/coap_locking.txt.in | 1 + man/coap_logging.txt.in | 1 + man/coap_observe.txt.in | 1 + man/coap_oscore.txt.in | 1 + man/coap_pdu_access.txt.in | 1 + man/coap_pdu_setup.txt.in | 1 + man/coap_persist.txt.in | 1 + man/coap_recovery.txt.in | 1 + man/coap_resource.txt.in | 1 + man/coap_session.txt.in | 2 + man/coap_string.txt.in | 1 + man/coap_tls_library.txt.in | 3 + man/coap_uri.txt.in | 1 + scripts/build.sh | 2 + scripts/dist.sh | 2 + src/coap_asn1.c | 48 + src/coap_debug.c | 10 + src/coap_gnutls.c | 78 +- src/coap_notls.c | 6 +- src/coap_sha1.c | 2 +- src/coap_wolfssl.c | 3120 ++++++++++++++++++++++ tests/test_tls.c | 9 + win32/libcoap.vcxproj | 1 + win32/libcoap.vcxproj.filters | 3 + 53 files changed, 3586 insertions(+), 125 deletions(-) create mode 100644 cmake/FindwolfSSL.cmake create mode 100644 src/coap_wolfssl.c diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1a17571ef2..1b62244b2e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,12 +28,12 @@ jobs: strategy: matrix: CC: ["gcc", "clang"] - TLS: ["no", "openssl", "gnutls", "mbedtls"] + TLS: ["no", "openssl", "gnutls", "mbedtls", "wolfssl"] steps: - uses: actions/checkout@v3 - name: setup run: | - sudo apt-get update && sudo apt-get install -y libcunit1-dev libmbedtls-dev libgnutls28-dev libtool libtool-bin exuberant-ctags valgrind + sudo apt-get update && sudo apt-get install -y libcunit1-dev libmbedtls-dev libgnutls28-dev libwolfssl-dev libtool libtool-bin exuberant-ctags valgrind ./autogen.sh - name: configure no-TLS if: matrix.TLS == 'no' @@ -78,14 +78,14 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - TLS: ["no", "openssl", "gnutls", "mbedtls", "tinydtls"] + TLS: ["no", "openssl", "gnutls", "mbedtls", "wolfssl", "tinydtls"] steps: - uses: actions/checkout@v3 with: submodules: recursive - name: setup run: | - sudo apt-get update && sudo apt-get install -y libcunit1-dev libmbedtls-dev libgnutls28-dev + sudo apt-get update && sudo apt-get install -y libcunit1-dev libmbedtls-dev libgnutls28-dev libwolfssl-dev cmake -E make_directory $GITHUB_WORKSPACE/build-${{matrix.TLS}}-cmake - name: configure no-TLS if: matrix.TLS == 'no' diff --git a/BUILDING b/BUILDING index 75f2a49f4b..c787f6e98b 100644 --- a/BUILDING +++ b/BUILDING @@ -99,6 +99,9 @@ Note: FreeBSD requires gmake instead of make when building TinyDTLS - i.e. # With OpenSSL ./configure --with-openssl --enable-tests --enable-shared +# With wolfSSL + ./configure --with-wolfssl --enable-tests --enable-shared + # With GnuTLS ./configure --with-gnutls --enable-tests --enable-shared diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e934132e1..7d1ce3ef56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,17 +103,18 @@ set(DTLS_BACKEND STRING "\ Name of the dtls backend, only relevant if `ENABLE_DTLS` is ON which is default. \ -Possible values: default, gnutls, openssl, tinydtls and mbedtls. \ +Possible values: default, gnutls, openssl, wolfssl, tinydtls and mbedtls. \ If specified then this library will be searched and if found also used. \ If not found then the cmake configuration will stop with an error. \ If not specified, then cmake will try to use the first one found in the following order: \ -gnutls, openssl, tinydtls, mbedtls \ +gnutls, openssl, wolfssl, tinydtls, mbedtls \ ") set_property( CACHE DTLS_BACKEND PROPERTY STRINGS default openssl + wolfssl gnutls tinydtls mbedtls) @@ -425,6 +426,7 @@ set(WITH_GNUTLS OFF) set(WITH_OPENSSL OFF) set(WITH_TINYDTLS OFF) set(WITH_MBEDTLS OFF) +set(WITH_WOLFSSL OFF) function(compile_tinydtls) set(TINYDTLS_SOURCES_DIR ${CMAKE_CURRENT_LIST_DIR}/ext/tinydtls) @@ -509,33 +511,43 @@ if(ENABLE_DTLS) set(COAP_WITH_LIBOPENSSL 1) else() # openssl not found - # libmbedtls (e.g. debian libmbedtls-dev) - find_package(MbedTLS) - if(MbedTLS_FOUND) - set(WITH_MBEDTLS ON) - message(STATUS "compiling with mbedtls support") - set(COAP_WITH_LIBMBEDTLS 1) + # wolfSSL + find_package(wolfSSL) + if(wolfSSL_FOUND) + set(WITH_WOLFSSL ON) + message(STATUS "compiling with wolfssl support") + set(COAP_WITH_LIBWOLFSSL 1) else() - # mbedtls not found - if(USE_VENDORED_TINYDTLS) - compile_tinydtls() + # wolfssl not found + # libmbedtls (e.g. debian libmbedtls-dev) + find_package(MbedTLS) + if(MbedTLS_FOUND) + set(WITH_MBEDTLS ON) + message(STATUS "compiling with mbedtls support") + set(COAP_WITH_LIBMBEDTLS 1) else() - find_package(TinyDTLS) - if(TINYDTLS_FOUND) - + # mbedtls not found + if(USE_VENDORED_TINYDTLS) + compile_tinydtls() else() - # no cryto lib found - message( - FATAL_ERROR - "cannot find any cryto lib, either install one or compile without DTLS support" - ) + find_package(TinyDTLS) + if(TINYDTLS_FOUND) + + else() + # no cryto lib found + message( + FATAL_ERROR + "cannot find any cryto lib, either install one or compile without DTLS support" + ) + endif() + endif() - endif() + set(WITH_TINYDTLS ON) + message(STATUS "compiling with tinydtls support") + set(COAP_WITH_LIBTINYDTLS 1) - set(WITH_TINYDTLS ON) - message(STATUS "compiling with tinydtls support") - set(COAP_WITH_LIBTINYDTLS 1) + endif() endif() @@ -570,6 +582,15 @@ if(ENABLE_DTLS) set(COAP_WITH_LIBOPENSSL 1) endif() + if(DTLS_BACKEND + STREQUAL + "wolfssl") + find_package(wolfSSL REQUIRED) + set(WITH_WOLFSSL ON) + message(STATUS "compiling with wolfssl support") + set(COAP_WITH_LIBWOLFSSL 1) + endif() + if(DTLS_BACKEND STREQUAL "mbedtls") @@ -600,6 +621,16 @@ if(ENABLE_DTLS) endif() +if(WITH_WOLFSSL) + find_library(WOLFSSL_LIBRARY wolfssl HINTS /usr/local/lib) + find_path(WOLFSSL_INCLUDE_DIR wolfssl/wolfcrypt/settings.h HINTS /usr/local/include) + if(WOLFSSL_LIBRARY AND WOLFSSL_INCLUDE_DIR) + message(STATUS "compiling with wolfssl support") + else() + message(FATAL_ERROR "WolfSSL not found") + endif() +endif() + execute_process(COMMAND git describe --tags --dirty --always RESULT_VARIABLE USING_GIT OUTPUT_VARIABLE LIBCOAP_PACKAGE_BUILD @@ -649,10 +680,12 @@ message(STATUS "DTLS_BACKEND:....................${DTLS_BACKEND}") message(STATUS "WITH_GNUTLS:.....................${WITH_GNUTLS}") message(STATUS "WITH_TINYDTLS:...................${WITH_TINYDTLS}") message(STATUS "WITH_OPENSSL:....................${WITH_OPENSSL}") +message(STATUS "WITH_WOLFSSL:....................${WITH_WOLFSSL}") message(STATUS "WITH_MBEDTLS:....................${WITH_MBEDTLS}") message(STATUS "HAVE_LIBTINYDTLS:................${COAP_WITH_LIBTINYDTLS}") message(STATUS "HAVE_LIBGNUTLS:..................${COAP_WITH_LIBGNUTLS}") message(STATUS "HAVE_LIBOPENSSL:.................${COAP_WITH_LIBOPENSSL}") +message(STATUS "HAVE_LIBWOLFSSL:.................${COAP_WITH_LIBWOLFSSL}") message(STATUS "HAVE_LIBMBEDTLS:.................${COAP_WITH_LIBMBEDTLS}") message(STATUS "WITH_EPOLL:......................${WITH_EPOLL}") message(STATUS "WITH_OBSERVE_PERSIST:............${WITH_OBSERVE_PERSIST}") @@ -723,6 +756,7 @@ target_sources( ${CMAKE_CURRENT_LIST_DIR}/src/coap_ws.c # no need to parse those files if we do not need them $<$:${CMAKE_CURRENT_LIST_DIR}/src/coap_openssl.c> + $<$:${CMAKE_CURRENT_LIST_DIR}/src/coap_wolfssl.c> $<$:${CMAKE_CURRENT_LIST_DIR}/src/coap_tinydtls.c> $<$:${CMAKE_CURRENT_LIST_DIR}/src/coap_gnutls.c> $<$:${CMAKE_CURRENT_LIST_DIR}/src/coap_mbedtls.c> @@ -765,7 +799,8 @@ target_include_directories( $ $<$,$>:${CMAKE_BINARY_DIR}/include/tinydtls> $<$:${GNUTLS_INCLUDE_DIR}> - $<$:${MBEDTLS_INCLUDE_DIRS}>) + $<$:${MBEDTLS_INCLUDE_DIRS}> + $<$:${WOLFSSL_INCLUDE_DIR}>) target_link_libraries( ${COAP_LIBRARY_NAME} PUBLIC $<$:OpenSSL::SSL> @@ -775,6 +810,7 @@ target_link_libraries( $<$:${MBEDTLS_LIBRARY}> $<$:${MBEDX509_LIBRARY}> $<$:${MBEDCRYPTO_LIBRARY}> + $<$:${WOLFSSL_LIBRARY}> $<$:ws2_32>) target_compile_options( diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in index cd7e32d626..aee946ef46 100644 --- a/CMakeLists.txt.in +++ b/CMakeLists.txt.in @@ -103,17 +103,18 @@ set(DTLS_BACKEND STRING "\ Name of the dtls backend, only relevant if `ENABLE_DTLS` is ON which is default. \ -Possible values: default, gnutls, openssl, tinydtls and mbedtls. \ +Possible values: default, gnutls, openssl, wolfssl, tinydtls and mbedtls. \ If specified then this library will be searched and if found also used. \ If not found then the cmake configuration will stop with an error. \ If not specified, then cmake will try to use the first one found in the following order: \ -gnutls, openssl, tinydtls, mbedtls \ +gnutls, openssl, wolfssl, tinydtls, mbedtls \ ") set_property( CACHE DTLS_BACKEND PROPERTY STRINGS default openssl + wolfssl gnutls tinydtls mbedtls) @@ -425,6 +426,7 @@ set(WITH_GNUTLS OFF) set(WITH_OPENSSL OFF) set(WITH_TINYDTLS OFF) set(WITH_MBEDTLS OFF) +set(WITH_WOLFSSL OFF) function(compile_tinydtls) set(TINYDTLS_SOURCES_DIR ${CMAKE_CURRENT_LIST_DIR}/ext/tinydtls) @@ -509,33 +511,43 @@ if(ENABLE_DTLS) set(COAP_WITH_LIBOPENSSL 1) else() # openssl not found - # libmbedtls (e.g. debian libmbedtls-dev) - find_package(MbedTLS) - if(MbedTLS_FOUND) - set(WITH_MBEDTLS ON) - message(STATUS "compiling with mbedtls support") - set(COAP_WITH_LIBMBEDTLS 1) + # wolfSSL + find_package(wolfSSL) + if(wolfSSL_FOUND) + set(WITH_WOLFSSL ON) + message(STATUS "compiling with wolfssl support") + set(COAP_WITH_LIBWOLFSSL 1) else() - # mbedtls not found - if(USE_VENDORED_TINYDTLS) - compile_tinydtls() + # wolfssl not found + # libmbedtls (e.g. debian libmbedtls-dev) + find_package(MbedTLS) + if(MbedTLS_FOUND) + set(WITH_MBEDTLS ON) + message(STATUS "compiling with mbedtls support") + set(COAP_WITH_LIBMBEDTLS 1) else() - find_package(TinyDTLS) - if(TINYDTLS_FOUND) - + # mbedtls not found + if(USE_VENDORED_TINYDTLS) + compile_tinydtls() else() - # no cryto lib found - message( - FATAL_ERROR - "cannot find any cryto lib, either install one or compile without DTLS support" - ) + find_package(TinyDTLS) + if(TINYDTLS_FOUND) + + else() + # no cryto lib found + message( + FATAL_ERROR + "cannot find any cryto lib, either install one or compile without DTLS support" + ) + endif() + endif() - endif() + set(WITH_TINYDTLS ON) + message(STATUS "compiling with tinydtls support") + set(COAP_WITH_LIBTINYDTLS 1) - set(WITH_TINYDTLS ON) - message(STATUS "compiling with tinydtls support") - set(COAP_WITH_LIBTINYDTLS 1) + endif() endif() @@ -570,6 +582,15 @@ if(ENABLE_DTLS) set(COAP_WITH_LIBOPENSSL 1) endif() + if(DTLS_BACKEND + STREQUAL + "wolfssl") + find_package(wolfSSL REQUIRED) + set(WITH_WOLFSSL ON) + message(STATUS "compiling with wolfssl support") + set(COAP_WITH_LIBWOLFSSL 1) + endif() + if(DTLS_BACKEND STREQUAL "mbedtls") @@ -600,6 +621,16 @@ if(ENABLE_DTLS) endif() +if(WITH_WOLFSSL) + find_library(WOLFSSL_LIBRARY wolfssl HINTS /usr/local/lib) + find_path(WOLFSSL_INCLUDE_DIR wolfssl/wolfcrypt/settings.h HINTS /usr/local/include) + if(WOLFSSL_LIBRARY AND WOLFSSL_INCLUDE_DIR) + message(STATUS "compiling with wolfssl support") + else() + message(FATAL_ERROR "WolfSSL not found") + endif() +endif() + execute_process(COMMAND git describe --tags --dirty --always RESULT_VARIABLE USING_GIT OUTPUT_VARIABLE LIBCOAP_PACKAGE_BUILD @@ -649,10 +680,12 @@ message(STATUS "DTLS_BACKEND:....................${DTLS_BACKEND}") message(STATUS "WITH_GNUTLS:.....................${WITH_GNUTLS}") message(STATUS "WITH_TINYDTLS:...................${WITH_TINYDTLS}") message(STATUS "WITH_OPENSSL:....................${WITH_OPENSSL}") +message(STATUS "WITH_WOLFSSL:....................${WITH_WOLFSSL}") message(STATUS "WITH_MBEDTLS:....................${WITH_MBEDTLS}") message(STATUS "HAVE_LIBTINYDTLS:................${COAP_WITH_LIBTINYDTLS}") message(STATUS "HAVE_LIBGNUTLS:..................${COAP_WITH_LIBGNUTLS}") message(STATUS "HAVE_LIBOPENSSL:.................${COAP_WITH_LIBOPENSSL}") +message(STATUS "HAVE_LIBWOLFSSL:.................${COAP_WITH_LIBWOLFSSL}") message(STATUS "HAVE_LIBMBEDTLS:.................${COAP_WITH_LIBMBEDTLS}") message(STATUS "WITH_EPOLL:......................${WITH_EPOLL}") message(STATUS "WITH_OBSERVE_PERSIST:............${WITH_OBSERVE_PERSIST}") @@ -723,6 +756,7 @@ target_sources( ${CMAKE_CURRENT_LIST_DIR}/src/coap_ws.c # no need to parse those files if we do not need them $<$:${CMAKE_CURRENT_LIST_DIR}/src/coap_openssl.c> + $<$:${CMAKE_CURRENT_LIST_DIR}/src/coap_wolfssl.c> $<$:${CMAKE_CURRENT_LIST_DIR}/src/coap_tinydtls.c> $<$:${CMAKE_CURRENT_LIST_DIR}/src/coap_gnutls.c> $<$:${CMAKE_CURRENT_LIST_DIR}/src/coap_mbedtls.c> @@ -765,7 +799,8 @@ target_include_directories( $ $<$,$>:${CMAKE_BINARY_DIR}/include/tinydtls> $<$:${GNUTLS_INCLUDE_DIR}> - $<$:${MBEDTLS_INCLUDE_DIRS}>) + $<$:${MBEDTLS_INCLUDE_DIRS}> + $<$:${WOLFSSL_INCLUDE_DIR}>) target_link_libraries( ${COAP_LIBRARY_NAME} PUBLIC $<$:OpenSSL::SSL> @@ -775,6 +810,7 @@ target_link_libraries( $<$:${MBEDTLS_LIBRARY}> $<$:${MBEDX509_LIBRARY}> $<$:${MBEDCRYPTO_LIBRARY}> + $<$:${WOLFSSL_LIBRARY}> $<$:ws2_32>) target_compile_options( diff --git a/LICENSE b/LICENSE index f8280eb921..02e691e9ed 100644 --- a/LICENSE +++ b/LICENSE @@ -115,6 +115,13 @@ When compiled with Mbed TLS support, this software includes components that are licensed under the terms of the Apache 2.0 license (http://www.apache.org/licenses/LICENSE-2.0). +======================================================================== +wolfSSL + +When compiled with wolfSSL support, this software includes components +that are licensed under the terms of the GPLv2 license +(https://www.gnu.org/licenses/old-licenses/gpl-2.0.html). + ======================================================================== SHA1 diff --git a/Makefile.am b/Makefile.am index 16836cdfe2..75a4596e56 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,6 +36,7 @@ EXTRA_DIST = \ cmake/Config.cmake.in \ cmake/FindMbedTLS.cmake \ cmake/FindTinyDTLS.cmake \ + cmake/FindwolfSSL.cmake \ coap_config.h.contiki \ coap_config.h.riot \ coap_config.h.windows \ @@ -219,6 +220,7 @@ libcoap_@LIBCOAP_NAME_SUFFIX@_la_SOURCES = \ src/coap_time.c \ src/coap_tinydtls.c \ src/coap_uri.c \ + src/coap_wolfssl.c \ src/coap_ws.c if COAP_OSCORE_SUPPORT diff --git a/README.md b/README.md index dac614744e..e05bf7cf62 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,8 @@ There is (D)TLS support for the following libraries * [Mbed TLS](https://www.trustedfirmware.org/projects/mbed-tls/) (Minimum version 2.7.10) [PKI and PSK] +* [wolfSSL](https://wolfssl.com) (Minimum version 5.2.0) [PKI, PSK and RPK(5.6.4+)] + * [TinyDTLS](https://github.com/eclipse/tinydtls) [PSK and RPK] [DTLS Only] The examples directory contain a CoAP client, CoAP Resource Directory server diff --git a/cmake/FindwolfSSL.cmake b/cmake/FindwolfSSL.cmake new file mode 100644 index 0000000000..dc1a210456 --- /dev/null +++ b/cmake/FindwolfSSL.cmake @@ -0,0 +1,86 @@ +# FindWolfSSL.cmake +# ----------------- +# +# Find the wolfSSL library. +# +# Imported Targets +# ^^^^^^^^^^^^^^^^ +# +# This module defines the following :prop_tgt:`IMPORTED` targets: +# +# ``wolfssl`` +# The wolfSSL library, if found. +# +# Result Variables +# ^^^^^^^^^^^^^^^^ +# +# This module will set the following variables in your project: +# +# ``wolfSSL_FOUND`` +# System has the wolfSSL library. +# ``WOLFSSL_INCLUDE_DIR`` +# The wolfSSL include directory. +# ``WOLFSSL_LIBRARIES`` +# All wolfSSL libraries. +# +# Hints +# ^^^^^ +# +# Set ``WOLFSSL_ROOT_DIR`` to the root directory of a wolfSSL installation. + +if(WOLFSSL_ROOT_DIR) + set(_WOLFSSL_EXTRA_FIND_ARGS "NO_CMAKE_FIND_ROOT_PATH") +endif() + +find_path( + WOLFSSL_INCLUDE_DIR + NAMES wolfssl/ssl.h + PATH_SUFFIXES include + HINTS ${PROJECT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${WOLFSSL_ROOT_DIR} + ${_WOLFSSL_EXTRA_FIND_ARGS}) + +find_library( + WOLFSSL_LIBRARIES + NAMES wolfssl + PATH_SUFFIXES lib + HINTS ${PROJECT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${WOLFSSL_ROOT_DIR} + ${_WOLFSSL_EXTRA_FIND_ARGS}) + +if(WOLFSSL_LIBRARIES) + set(wolfSSL_FOUND TRUE) +else() + set(wolfSSL_FOUND FALSE) + if(wolfSSL_FIND_REQUIRED) + message(FATAL_ERROR "wolfSSL could not be found") + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + wolfSSL + FOUND_VAR + wolfSSL_FOUND + REQUIRED_VARS + WOLFSSL_INCLUDE_DIR + WOLFSSL_LIBRARIES + VERSION_VAR) + +if(NOT TARGET wolfssl) + add_library( + wolfssl + UNKNOWN + IMPORTED) + set_target_properties( + wolfssl + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WOLFSSL_INCLUDE_DIR}" + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${WOLFSSL_LIBRARIES}") +endif() + +message(STATUS "WOLFSSL_INCLUDE_DIR: ${WOLFSSL_INCLUDE_DIR}") +message(STATUS "WOLFSSL_LIBRARIES: ${WOLFSSL_LIBRARIES}") +message(STATUS "WOLFSSL_ROOT_DIR: ${WOLFSSL_ROOT_DIR}") \ No newline at end of file diff --git a/cmake_coap_config.h.in b/cmake_coap_config.h.in index 2ffd9f87e4..aa981918ed 100644 --- a/cmake_coap_config.h.in +++ b/cmake_coap_config.h.in @@ -68,6 +68,9 @@ /* Define to 1 if the system has openssl */ #cmakedefine COAP_WITH_LIBOPENSSL @COAP_WITH_LIBOPENSSL@ +/* Define to 1 if the system has wolfSSL */ +#cmakedefine COAP_WITH_WOLFSSL @COAP_WITH_WOLFSSL@ + /* Define to 1 if the system has libgnutls28 */ #cmakedefine COAP_WITH_LIBGNUTLS @COAP_WITH_LIBGNUTLS@ diff --git a/configure.ac b/configure.ac index 490ce2fec4..6e4a0d154f 100644 --- a/configure.ac +++ b/configure.ac @@ -366,6 +366,7 @@ AM_CONDITIONAL(BUILD_MANPAGES, [test "x$build_manpages" = "xyes"]) gnutls_version_required=3.3.0 openssl_version_required=1.1.0 mbedtls_version_required=2.7.10 +wolfssl_version_required=5.2.0 tinydtls_version_required=0.8.6 AC_ARG_ENABLE([dtls], @@ -386,6 +387,12 @@ AC_ARG_WITH([openssl], [with_openssl="$withval"], [with_openssl="no"]) +AC_ARG_WITH([wolfssl], + [AS_HELP_STRING([--with-wolfssl], + [Use wolfSSL for DTLS functions])], + [with_wolfssl="$withval"], + [with_wolfssl="no"]) + AC_ARG_WITH([mbedtls], [AS_HELP_STRING([--with-mbedtls], [Use Mbed TLS for DTLS functions])], @@ -404,11 +411,11 @@ AC_ARG_WITH([submodule-tinydtls], [with_submodule_tinydtls="$withval"], [with_submodule_tinydtls="explicit_fallback"]) -if test "x$with_gnutls" = "xyes" -o "x$with_openssl" = "xyes" -o "x$with_mbedtls" = "xyes" -o "x$with_tinydtls" = "xyes"; then +if test "x$with_gnutls" = "xyes" -o "x$with_openssl" = "xyes" -o "x$with_wolfssl" = "xyes" -o "x$with_mbedtls" = "xyes" -o "x$with_tinydtls" = "xyes"; then if test "x$build_dtls" = "xno"; then - # Give an advice that '--with_gnutls', '--with_openssl', '--with-mbedtls' or '--with-tinydtls' was used but + # Give an advice that '--with_gnutls', '--with_openssl', '--with_wolfssl', '--with-mbedtls' or '--with-tinydtls' was used but # DTLS support isn't configured. - AC_MSG_WARN([==> Using the configure options '--with-gnutls', '--with-openssl', '--with-mbedtls' or '--with-tinydtls' without '--enable-dtls' is useless and will be ignored.]) + AC_MSG_WARN([==> Using the configure options '--with-gnutls', '--with-openssl', '--with_wolfssl', '--with-mbedtls' or '--with-tinydtls' without '--enable-dtls' is useless and will be ignored.]) fi fi if test "x$with_submodule_tinydtls" = "xyes"; then @@ -428,6 +435,9 @@ if test "x$build_dtls" = "xyes"; then if test "x$with_openssl" = "xyes"; then TLSCOUNT=`expr $TLSCOUNT + 1` fi + if test "x$with_wolfssl" = "xyes"; then + TLSCOUNT=`expr $TLSCOUNT + 1` + fi if test "x$with_mbedtls" = "xyes"; then TLSCOUNT=`expr $TLSCOUNT + 1` fi @@ -452,6 +462,12 @@ if test "x$build_dtls" = "xyes"; then [have_openssl="yes"], [have_openssl="no"]) + # wolfSSL + PKG_CHECK_MODULES([wolfSSL], + [wolfssl], + [have_wolfssl="yes"], + [have_wolfssl="no"]) + # Mbed TLS [does not have mbedtls.pc pkg-config file] AC_CHECK_LIB(mbedtls, mbedtls_version_get_string, [have_mbedtls="yes"; MbedTLS_CFLAGS="" ; MbedTLS_LIBS="-lmbedtls -lmbedcrypto -lmbedx509"], @@ -511,6 +527,7 @@ if test "x$build_dtls" = "xyes"; then gnutls_version=`$PKG_CONFIG --modversion gnutls` AX_CHECK_GNUTLS_VERSION have_openssl="no" # don't confuse AC_MSG_RESULT at the end of the script + have_wolfssl="no" # don't confuse AC_MSG_RESULT at the end of the script have_mbedtls="no" # don't confuse AC_MSG_RESULT at the end of the script have_tinydtls="no" # don't confuse AC_MSG_RESULT at the end of the script fi @@ -529,6 +546,26 @@ if test "x$build_dtls" = "xyes"; then openssl_version=`$PKG_CONFIG --modversion openssl` AX_CHECK_OPENSSL_VERSION have_gnutls="no" # don't confuse AC_MSG_RESULT at the end of the script + have_wolfssl="no" # don't confuse AC_MSG_RESULT at the end of the script + have_mbedtls="no" # don't confuse AC_MSG_RESULT at the end of the script + have_tinydtls="no" # don't confuse AC_MSG_RESULT at the end of the script + fi + + # The user wants to use explicit wolfSSL if '--with-wolfssl' was set. + if test "x$with_wolfssl" = "xyes"; then + # Some more sanity checking. + if test "x$have_wolfssl" != "xyes"; then + AC_MSG_ERROR([==> You want to build libcoap with DTLS support by the wolfSSL library but pkg-config file 'wolfssl.pc' could not be found! + Install the package(s) that contains the development files for wolfSSL, + or select a different TLS library or disable the DTLS support using '--disable-dtls'.]) + fi + AC_MSG_NOTICE([The use of wolfSSL was explicitly requested with configure option '--with-wolfssl'!]) + + # check for valid wolfSSL version + wolfssl_version=`$PKG_CONFIG --modversion wolfssl` + AX_CHECK_WOLFSSL_VERSION + have_gnutls="no" # don't confuse AC_MSG_RESULT at the end of the script + have_openssl="no" # don't confuse AC_MSG_RESULT at the end of the script have_mbedtls="no" # don't confuse AC_MSG_RESULT at the end of the script have_tinydtls="no" # don't confuse AC_MSG_RESULT at the end of the script fi @@ -548,6 +585,7 @@ if test "x$build_dtls" = "xyes"; then AX_CHECK_MBEDTLS_VERSION have_gnutls="no" # don't confuse AC_MSG_RESULT at the end of the script have_openssl="no" # don't confuse AC_MSG_RESULT at the end of the script + have_wolfssl="no" # don't confuse AC_MSG_RESULT at the end of the script have_tinydtls="no" # don't confuse AC_MSG_RESULT at the end of the script fi @@ -599,6 +637,7 @@ if test "x$build_dtls" = "xyes"; then have_gnutls="no" # don't confuse AC_MSG_RESULT at the end of the script have_openssl="no" # don't confuse AC_MSG_RESULT at the end of the script + have_wolfssl="no" # don't confuse AC_MSG_RESULT at the end of the script have_mbedtls="no" # don't confuse AC_MSG_RESULT at the end of the script fi @@ -611,6 +650,7 @@ if test "x$build_dtls" = "xyes"; then AC_MSG_NOTICE([Using auto selected library GnuTLS for DTLS support!]) with_gnutls_auto="yes" have_openssl="no" # don't confuse AC_MSG_RESULT at the end of the script + have_wolfssl="no" # don't confuse AC_MSG_RESULT at the end of the script have_mbedtls="no" # don't confuse AC_MSG_RESULT at the end of the script have_tinydtls="no" # don't confuse AC_MSG_RESULT at the end of the script @@ -620,10 +660,22 @@ if test "x$build_dtls" = "xyes"; then AX_CHECK_OPENSSL_VERSION AC_MSG_NOTICE([Using auto selected library OpenSSL for DTLS support!]) with_openssl_auto="yes" + have_wolfssl="no" # don't confuse AC_MSG_RESULT at the end of the script have_gnutls="no" # don't confuse AC_MSG_RESULT at the end of the script have_mbedtls="no" # don't confuse AC_MSG_RESULT at the end of the script have_tinydtls="no" # don't confuse AC_MSG_RESULT at the end of the script + # ... and if not found, check if wolfSSL is suitable. + elif test "x$have_wolfssl" = "xyes"; then + wolfssl_version=`$PKG_CONFIG --modversion wolfssl` + AX_CHECK_WOLFSSL_VERSION + AC_MSG_NOTICE([Using auto selected library wolfSSL for DTLS support!]) + with_wolfssl_auto="yes" + have_gnutls="no" # don't confuse AC_MSG_RESULT at the end of the script + have_openssl="no" # don't confuse AC_MSG_RESULT at the end of the script + have_mbedtls="no" # don't confuse AC_MSG_RESULT at the end of the script + have_tinydtls="no" # don't confuse AC_MSG_RESULT at the end of the script + # ... and if not found check Mbed TLS is suitable. elif test "x$have_mbedtls" = "xyes"; then # Mbed TLS [does not have mbedtls.pc pkg-config file] @@ -632,6 +684,7 @@ if test "x$build_dtls" = "xyes"; then AC_MSG_NOTICE([Using auto selected library Mbed TLS for DTLS support!]) with_mbedtls_auto="yes" have_gnutls="no" # don't confuse AC_MSG_RESULT at the end of the script + have_wolfssl="no" # don't confuse AC_MSG_RESULT at the end of the script have_openssl="no" # don't confuse AC_MSG_RESULT at the end of the script have_tinydtls="no" # don't confuse AC_MSG_RESULT at the end of the script @@ -643,13 +696,13 @@ if test "x$build_dtls" = "xyes"; then have_gnutls="no" # don't confuse AC_MSG_RESULT at the end of the script have_mbedtls="no" # don't confuse AC_MSG_RESULT at the end of the script have_openssl="no" # don't confuse AC_MSG_RESULT at the end of the script - + have_wolfssl="no" # don't confuse AC_MSG_RESULT at the end of the script # Note that the TinyDTLS submodule is used only when explicitly requested. # Giving out an error message if we haven't found at least one crypto library. else - AC_MSG_ERROR([==> Option '--enable-dtls' is set but none of the needed cryptography libraries GnuTLS, OpenSSL, Mbed TLS or TinyDTLS could be found! - Install at least one of the package(s) that contains the development files for GnuTLS (>= $gnutls_version_required), OpenSSL(>= $openssl_version_required), Mbed TLS(>= $mbedtls_version_required), or TinyDTLS(>= $tinydtls_version_required) + AC_MSG_ERROR([==> Option '--enable-dtls' is set but none of the needed cryptography libraries GnuTLS, OpenSSL, wolfSSL, Mbed TLS or TinyDTLS could be found! + Install at least one of the package(s) that contains the development files for GnuTLS (>= $gnutls_version_required), OpenSSL(>= $openssl_version_required), wolfSSL(>= $wolfssl_version_required), Mbed TLS(>= $mbedtls_version_required), or TinyDTLS(>= $tinydtls_version_required) or disable the DTLS support using '--disable-dtls'.]) fi fi @@ -665,6 +718,11 @@ if test "x$build_dtls" = "xyes"; then DTLS_LIBS="$OpenSSL_LIBS" AC_DEFINE(COAP_WITH_LIBOPENSSL, [1], [Define to 1 if the system has libssl1.1.]) fi + if test "x$with_wolfssl" = "xyes" -o "x$with_wolfssl_auto" = "xyes"; then + DTLS_CFLAGS="$wolfSSL_CFLAGS" + DTLS_LIBS="$wolfSSL_LIBS" + AC_DEFINE(COAP_WITH_LIBWOLFSSL, [1], [Define to 1 if the system has libwolfssl.]) + fi if test "x$with_mbedtls" = "xyes" -o "x$with_mbedtls_auto" = "xyes"; then DTLS_CFLAGS="$MbedTLS_CFLAGS" DTLS_LIBS="$MbedTLS_LIBS" @@ -682,6 +740,8 @@ fi # Define the Library name extension for the TLS the library was linked against if test "x$with_openssl" = "xyes" -o "x$with_openssl_auto" = "xyes"; then LIBCOAP_DTLS_LIB_EXTENSION_NAME=-openssl +elif test "x$with_wolfssl" = "xyes" -o "x$with_wolfssl_auto" = "xyes"; then + LIBCOAP_DTLS_LIB_EXTENSION_NAME=-wolfssl elif test "x$with_gnutls" = "xyes" -o "x$with_gnutls_auto" = "xyes"; then LIBCOAP_DTLS_LIB_EXTENSION_NAME=-gnutls elif test "x$with_mbedtls" = "xyes" -o "x$with_mbedtls_auto" = "xyes"; then @@ -1262,6 +1322,12 @@ if test "x$with_openssl" = "xyes" -o "x$with_openssl_auto" = "xyes"; then AC_MSG_RESULT([ OPENSSL_CFLAGS : "$OpenSSL_CFLAGS"]) AC_MSG_RESULT([ OPENSSL_LIBS : "$OpenSSL_LIBS"]) fi +if test "x$with_wolfssl" = "xyes" -o "x$with_wolfssl_auto" = "xyes"; then + AC_MSG_RESULT([ build DTLS support : "yes"]) + AC_MSG_RESULT([ --> wolfSSL around : "yes" (found wolfSSL $wolfssl_version)]) + AC_MSG_RESULT([ wolfSSL_CFLAGS : "$wolfSSL_CFLAGS"]) + AC_MSG_RESULT([ wolfSSL_LIBS : "$wolfSSL_LIBS"]) +fi if test "x$with_mbedtls" = "xyes" -o "x$with_mbedtls_auto" = "xyes"; then AC_MSG_RESULT([ build DTLS support : "yes"]) AC_MSG_RESULT([ --> Mbed TLS around : "yes" (found Mbed TLS $mbedtls_version)]) diff --git a/doc/main.md b/doc/main.md index 85ad8852e2..ee0e07740f 100644 --- a/doc/main.md +++ b/doc/main.md @@ -56,6 +56,8 @@ There is (D)TLS support for the following libraries * [Mbed TLS](https://www.trustedfirmware.org/projects/mbed-tls/) (Minimum version 2.7.10) [PKI and PSK] +* [wolfSSL](https://wolfssl.com) (Minimum version 5.2.0) [PKI, PSK and RPK(5.6.4+)] + * [TinyDTLS](https://github.com/eclipse/tinydtls) [PSK and RPK] [DTLS Only] Documentation diff --git a/examples/share.libcoap.examples.Makefile b/examples/share.libcoap.examples.Makefile index 24d4f26645..fd66664154 100644 --- a/examples/share.libcoap.examples.Makefile +++ b/examples/share.libcoap.examples.Makefile @@ -6,7 +6,8 @@ # COPYING for terms of use. # Set external variable LIBCOAP if you need a specific libcoap library. -# E.g. libcoap-3-openssl, libcoap-3-gnutls, libcoap-3-mbedtls or libcoap-3-notls +# E.g. libcoap-3-openssl, libcoap-3-gnutls, libcoap-3-mbedtls, libcoap-3-wolfssl +# or libcoap-3-notls # LIBCOAP?=libcoap-3 diff --git a/include/coap3/coap_asn1_internal.h b/include/coap3/coap_asn1_internal.h index be14bfc325..46e88d7ee2 100644 --- a/include/coap3/coap_asn1_internal.h +++ b/include/coap3/coap_asn1_internal.h @@ -86,6 +86,19 @@ coap_asn1_tag_t asn1_tag_c(const uint8_t **ptr, int *constructed, int *cls); coap_binary_t *get_asn1_tag(coap_asn1_tag_t ltag, const uint8_t *ptr, size_t tlen, asn1_validate validate); +/** + * Abstract SPKI public key from the ASN1. + * + * Internal function. + * + * @param data Pointer to ASN1 object containing EC Private Key + * @param size Length of ASN1 object + * + * @return The publick key (to be freed off by caller) + * or @c NULL if not found + */ +coap_binary_t *get_asn1_spki(const uint8_t *data, size_t size); + /** @} */ #endif /* COAP_ASN1_INTERNAL_H_ */ diff --git a/include/coap3/coap_dtls.h b/include/coap3/coap_dtls.h index a269769d74..10616b6a80 100644 --- a/include/coap3/coap_dtls.h +++ b/include/coap3/coap_dtls.h @@ -96,6 +96,7 @@ typedef enum coap_tls_library_t { COAP_TLS_LIBRARY_OPENSSL, /**< Using OpenSSL library */ COAP_TLS_LIBRARY_GNUTLS, /**< Using GnuTLS library */ COAP_TLS_LIBRARY_MBEDTLS, /**< Using Mbed TLS library */ + COAP_TLS_LIBRARY_WOLFSSL, /**< Using wolfSSL library */ } coap_tls_library_t; /** diff --git a/m4/ac_check_cryptolibs.m4 b/m4/ac_check_cryptolibs.m4 index 2ae862954e..2d4c7538eb 100644 --- a/m4/ac_check_cryptolibs.m4 +++ b/m4/ac_check_cryptolibs.m4 @@ -69,6 +69,20 @@ AC_DEFUN([AX_CHECK_MBEDTLS_VERSION], fi ]) dnl AX_CHECK_MBEDTLS_VERSION +AC_DEFUN([AX_CHECK_WOLFSSL_VERSION], + [AC_MSG_CHECKING([for compatible wolfSSL version (>= $wolfssl_version_required)]) + AS_VERSION_COMPARE([$wolfssl_version], [$wolfssl_version_required], + [AC_MSG_RESULT([no]) + WOLFSSLV=""], + [AC_MSG_RESULT([yes $wolfssl_version]) + WOLFSSLV="$wolfssl_version"], + [AC_MSG_RESULT([yes $wolfssl_version]) + WOLFSSLV="$wolfssl_version"]) + if test "x$WOLFSSLV" = "x"; then + AC_MSG_ERROR([==> wolfSSL $wolfssl_version too old. wolfSSL >= $wolfssl_version_required required for suitable DTLS support build.]) + fi +]) dnl AX_CHECK_WOLFSSL_VERSION + AC_DEFUN([AX_CHECK_TINYDTLS_VERSION], [AC_MSG_CHECKING([for compatible TinyDTLS version (>= $tinydtls_version_required)]) AS_VERSION_COMPARE([$tinydtls_version], [$tinydtls_version_required], diff --git a/man/coap_address.txt.in b/man/coap_address.txt.in index 73ff95c70a..8ae52f37eb 100644 --- a/man/coap_address.txt.in +++ b/man/coap_address.txt.in @@ -73,6 +73,7 @@ const uint8_t *_host_, size_t _host_len_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_async.txt.in b/man/coap_async.txt.in index f13da4a8c7..0406d66791 100644 --- a/man/coap_async.txt.in +++ b/man/coap_async.txt.in @@ -46,6 +46,7 @@ coap_bin_const_t _token_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_attribute.txt.in b/man/coap_attribute.txt.in index bc8c599c9d..e01ef78ba6 100644 --- a/man/coap_attribute.txt.in +++ b/man/coap_attribute.txt.in @@ -31,6 +31,7 @@ coap_str_const_t *_name_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_block.txt.in b/man/coap_block.txt.in index 14f28d1dae..094be84fd6 100644 --- a/man/coap_block.txt.in +++ b/man/coap_block.txt.in @@ -51,6 +51,7 @@ size_t _length_, const uint8_t *_data_, size_t _offset_, size_t _total_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_cache.txt.in b/man/coap_cache.txt.in index 6e0d8c5efd..20a7d58252 100644 --- a/man/coap_cache.txt.in +++ b/man/coap_cache.txt.in @@ -64,6 +64,7 @@ coap_cache_app_data_free_callback_t _callback_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_context.txt.in b/man/coap_context.txt.in index 7b7842f823..d0c04dbd53 100644 --- a/man/coap_context.txt.in +++ b/man/coap_context.txt.in @@ -61,6 +61,7 @@ size_t _max_token_size_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_deprecated.txt.in b/man/coap_deprecated.txt.in index 4dc881459f..e0475d506d 100644 --- a/man/coap_deprecated.txt.in +++ b/man/coap_deprecated.txt.in @@ -74,6 +74,7 @@ unsigned int _max_sockets_, unsigned int *_num_sockets_, coap_tick_t _now_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_encryption.txt.in b/man/coap_encryption.txt.in index 282810f5e1..2b3e37580d 100644 --- a/man/coap_encryption.txt.in +++ b/man/coap_encryption.txt.in @@ -29,6 +29,7 @@ SYNOPSIS For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. @@ -40,6 +41,7 @@ When the libcoap library was built, it will have been compiled using a specific underlying TLS implementation type (e.g. https://www.openssl.org[OpenSSL], https://www.gnutls.org[GnuTLS], https://www.trustedfirmware.org/projects/mbed-tls/[Mbed TLS], +https://wolfssl.com[wolfSSL], https://github.com/eclipse/tinydtls[TinyDTLS] or noTLS). When the libcoap library is linked into an application, it is possible that the application needs to dynamically determine whether DTLS or TLS is @@ -55,11 +57,20 @@ version is 1.1.0. *NOTE:* If Mbed TLS is being used, then the minimum Mbed TLS library version is 2.7.10. +*NOTE:* If wolfSSL is being used, then the minimum wolfSSL library version is +5.2.0. + *NOTE:* If GnuTLS is going to interoperate with TinyDTLS, then a minimum revision of GnuTLS 3.5.5 which supports CCM algorithms is required by TinyDTLS as TinyDTLS currently only supports CCM. +*NOTE:* If wolfSSL is going to interoperate with TinyDTLS, then the library +needs to be build with +'./configure CFLAGS="-DBUILD_TLS_PSK_WITH_AES_128_CCM"' +as TinyDTLS currently only supports CCM. + *NOTE:* For Raw Public Key support, GnuTLS library version must be 3.6.6 or +later. For Raw Public Key support, wolfSSL library version must be 5.6.4 or later. TinyDTLS only supports TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, curve secp256r1 and hash SHA-256. There currently is no OpenSSL or Mbed TLS RPK support (respective library limitations). diff --git a/man/coap_endpoint_client.txt.in b/man/coap_endpoint_client.txt.in index 1cae68fe29..591b5661d2 100644 --- a/man/coap_endpoint_client.txt.in +++ b/man/coap_endpoint_client.txt.in @@ -41,6 +41,7 @@ _proto_, coap_dtls_pki_t *_setup_data_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_endpoint_server.txt.in b/man/coap_endpoint_server.txt.in index e8cf252c96..bb9752fb3a 100644 --- a/man/coap_endpoint_server.txt.in +++ b/man/coap_endpoint_server.txt.in @@ -50,6 +50,7 @@ const char *_groupname_, const char *_ifname_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_handler.txt.in b/man/coap_handler.txt.in index bda627eb50..0e1443c997 100644 --- a/man/coap_handler.txt.in +++ b/man/coap_handler.txt.in @@ -44,6 +44,7 @@ coap_event_handler_t _handler_)*; For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_init.txt.in b/man/coap_init.txt.in index 7fc0caa56d..45a66bde6b 100644 --- a/man/coap_init.txt.in +++ b/man/coap_init.txt.in @@ -26,6 +26,7 @@ SYNOPSIS For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_io.txt.in b/man/coap_io.txt.in index 6ad20ce712..f69cc6dbee 100644 --- a/man/coap_io.txt.in +++ b/man/coap_io.txt.in @@ -53,6 +53,7 @@ size_t _nevents_)*; For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_keepalive.txt.in b/man/coap_keepalive.txt.in index e945234b5c..0dc502ed7c 100644 --- a/man/coap_keepalive.txt.in +++ b/man/coap_keepalive.txt.in @@ -24,6 +24,7 @@ unsigned int _seconds_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_locking.txt.in b/man/coap_locking.txt.in index 59b0037d4b..08256e2001 100644 --- a/man/coap_locking.txt.in +++ b/man/coap_locking.txt.in @@ -48,6 +48,7 @@ coap_code_t _failed_statement_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_logging.txt.in b/man/coap_logging.txt.in index 923561d74d..440189c828 100644 --- a/man/coap_logging.txt.in +++ b/man/coap_logging.txt.in @@ -100,6 +100,7 @@ char *_buffer_, size_t _length_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_observe.txt.in b/man/coap_observe.txt.in index c05c9cb527..d8d296009d 100644 --- a/man/coap_observe.txt.in +++ b/man/coap_observe.txt.in @@ -35,6 +35,7 @@ coap_pdu_type_t _message_type_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_oscore.txt.in b/man/coap_oscore.txt.in index 835c428ef8..26f2ef9fc1 100644 --- a/man/coap_oscore.txt.in +++ b/man/coap_oscore.txt.in @@ -60,6 +60,7 @@ coap_oscore_conf_t *_oscore_conf_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_pdu_access.txt.in b/man/coap_pdu_access.txt.in index 36a1d9b7ec..89ecbc8682 100644 --- a/man/coap_pdu_access.txt.in +++ b/man/coap_pdu_access.txt.in @@ -77,6 +77,7 @@ coap_opt_iterator_t *_oi_, const coap_opt_filter_t *_filter_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_pdu_setup.txt.in b/man/coap_pdu_setup.txt.in index 62e75e94fb..681a4c478f 100644 --- a/man/coap_pdu_setup.txt.in +++ b/man/coap_pdu_setup.txt.in @@ -97,6 +97,7 @@ uint8_t *_buffer_, size_t *_buflen_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_persist.txt.in b/man/coap_persist.txt.in index b102843d57..7c1df2a76e 100644 --- a/man/coap_persist.txt.in +++ b/man/coap_persist.txt.in @@ -46,6 +46,7 @@ uint32_t _start_observe_no_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_recovery.txt.in b/man/coap_recovery.txt.in index a08a734103..e458c3c10b 100644 --- a/man/coap_recovery.txt.in +++ b/man/coap_recovery.txt.in @@ -97,6 +97,7 @@ uint32_t _value_)*; For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_resource.txt.in b/man/coap_resource.txt.in index 066e57cf88..000aebfa5f 100644 --- a/man/coap_resource.txt.in +++ b/man/coap_resource.txt.in @@ -65,6 +65,7 @@ coap_resource_release_userdata_handler_t _callback_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_session.txt.in b/man/coap_session.txt.in index 977f206fe2..41add06391 100644 --- a/man/coap_session.txt.in +++ b/man/coap_session.txt.in @@ -77,6 +77,7 @@ const coap_session_t *_session_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. @@ -199,6 +200,7 @@ of the _session_. OpenSSL: SSL* GnuTLS: gnutls_session_t (implicit *) Mbed TLS: mbedtls_ssl_context* +wolfSSL: WOLFSSL* TinyDTLS: struct dtls_context* ---- diff --git a/man/coap_string.txt.in b/man/coap_string.txt.in index 6671279a06..9870f92773 100644 --- a/man/coap_string.txt.in +++ b/man/coap_string.txt.in @@ -56,6 +56,7 @@ SYNOPSIS For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/man/coap_tls_library.txt.in b/man/coap_tls_library.txt.in index 69cba01a90..5a86a656d7 100644 --- a/man/coap_tls_library.txt.in +++ b/man/coap_tls_library.txt.in @@ -53,6 +53,7 @@ SYNOPSIS For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. @@ -62,6 +63,7 @@ When the libcoap library was built, it will have been compiled using a specific TLS implementation type (e.g. https://www.openssl.org[OpenSSL], https://www.gnutls.org[GnuTLS], https://www.trustedfirmware.org/projects/mbed-tls/[Mbed TLS], +https://wolfssl.com[wolfSSL], https://github.com/eclipse/tinydtls[TinyDTLS] or noTLS). When the libcoap library is linked into an application, it is possible that the application needs to dynamically determine whether DTLS or TLS is @@ -139,6 +141,7 @@ typedef enum coap_tls_library_t { COAP_TLS_LIBRARY_OPENSSL, /* Using OpenSSL library */ COAP_TLS_LIBRARY_GNUTLS, /* Using GnuTLS library */ COAP_TLS_LIBRARY_MBEDTLS, /* Using Mbed TLS library */ + COAP_TLS_LIBRARY_WOLFSSL, /* Using wolfSSL library */ } coap_tls_library_t; typedef struct coap_tls_version_t { diff --git a/man/coap_uri.txt.in b/man/coap_uri.txt.in index 7d459ad6ba..eb9efbf91c 100644 --- a/man/coap_uri.txt.in +++ b/man/coap_uri.txt.in @@ -42,6 +42,7 @@ int _create_port_host_opt_, uint8_t *_buf_, size_t _buflen_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* +*-lcoap-@LIBCOAP_API_VERSION@-wolfssl*, or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with *-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. diff --git a/scripts/build.sh b/scripts/build.sh index 6501a36219..8ebda98e52 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -17,6 +17,8 @@ case "x${TLS}" in ;; xmbedtls) WITH_TLS="--with-mbedtls" ;; + xwolfssl) WITH_TLS="--with-wolfssl" + ;; xtinydtls) WITH_TLS="--with-tinydtls" # Need this as libtinydtls.so has not been installed # as a part of the travis build diff --git a/scripts/dist.sh b/scripts/dist.sh index 06d397fe70..0bcf95c472 100755 --- a/scripts/dist.sh +++ b/scripts/dist.sh @@ -35,6 +35,8 @@ case "x${TLS}" in ;; xmbedtls) WITH_TLS="--with-mbedtls" ;; + xwolfssl) WITH_TLS="--with-wolfssl" + ;; xtinydtls) WITH_TLS="--with-tinydtls --disable-shared" ;; *) WITH_TLS="--with-gnutls" diff --git a/src/coap_asn1.c b/src/coap_asn1.c index da22104f11..1708be008f 100644 --- a/src/coap_asn1.c +++ b/src/coap_asn1.c @@ -100,3 +100,51 @@ get_asn1_tag(coap_asn1_tag_t ltag, const uint8_t *ptr, size_t tlen, } return NULL; } + +/* first part of Raw public key, this is the start of the Subject Public Key */ +static const unsigned char cert_asn1_header1[] = { + 0x30, 0x59, /* SEQUENCE, length 89 bytes */ + 0x30, 0x13, /* SEQUENCE, length 19 bytes */ + 0x06, 0x07, /* OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) */ + 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, +}; +/* PrimeX will get inserted */ +#if 0 +0x06, 0x08, /* OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7) */ + 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, +#endif +static const unsigned char cert_asn1_header2[] = { + 0x03, 0x42, /* BIT STRING, length 66 bytes */ + /* Note: 0 bits (0x00) and no compression (0x04) are already in the certificate */ +}; + +coap_binary_t * +get_asn1_spki(const uint8_t *data, size_t size) { + coap_binary_t *pub_key = get_asn1_tag(COAP_ASN1_BITSTRING, data, size, NULL); + coap_binary_t *prime = get_asn1_tag(COAP_ASN1_IDENTIFIER, data, size, NULL); + coap_binary_t *spki = NULL; + + if (pub_key && prime) { + size_t header_size = sizeof(cert_asn1_header1) + + 2 + + prime->length + + sizeof(cert_asn1_header2); + spki = coap_new_binary(header_size + pub_key->length); + if (spki) { + memcpy(&spki->s[header_size], pub_key->s, pub_key->length); + memcpy(spki->s, cert_asn1_header1, sizeof(cert_asn1_header1)); + spki->s[sizeof(cert_asn1_header1)] = COAP_ASN1_IDENTIFIER; + spki->s[sizeof(cert_asn1_header1)+1] = (u_int8_t)prime->length; + memcpy(&spki->s[sizeof(cert_asn1_header1)+2], + prime->s, prime->length); + memcpy(&spki->s[sizeof(cert_asn1_header1)+2+prime->length], + cert_asn1_header2, sizeof(cert_asn1_header2)); + spki->length = header_size + pub_key->length; + } + } + if (pub_key) + coap_delete_binary(pub_key); + if (prime) + coap_delete_binary(prime); + return spki; +} diff --git a/src/coap_debug.c b/src/coap_debug.c index 64768cbce8..e7548d9547 100644 --- a/src/coap_debug.c +++ b/src/coap_debug.c @@ -1216,6 +1216,16 @@ coap_string_tls_version(char *buffer, size_t bufsize) { (unsigned long)((tls_version->built_version >> 16) & 0xff), (unsigned long)((tls_version->built_version >> 8) & 0xff)); break; + case COAP_TLS_LIBRARY_WOLFSSL: + snprintf(buffer, bufsize, "TLS Library: wolfSSL - runtime %lu.%lu.%lu, " + "libcoap built for %lu.%lu.%lu", + (unsigned long)(tls_version->version >> 24), + (unsigned long)((tls_version->version >> 12) & 0xfff), + (unsigned long)((tls_version->version >> 0) & 0xfff), + (unsigned long)(tls_version->built_version >> 24), + (unsigned long)((tls_version->built_version >> 12) & 0xfff), + (unsigned long)((tls_version->built_version >> 0) & 0xfff)); + break; default: snprintf(buffer, bufsize, "Library type %d unknown", tls_version->type); break; diff --git a/src/coap_gnutls.c b/src/coap_gnutls.c index c11b744c62..f6d78048eb 100644 --- a/src/coap_gnutls.c +++ b/src/coap_gnutls.c @@ -983,60 +983,6 @@ pin_callback(void *user_data, int attempt, } return -1; } -#if (GNUTLS_VERSION_NUMBER >= 0x030606) -/* first part of Raw public key, this is the start of the Subject Public Key */ -static const unsigned char cert_asn1_header1[] = { - 0x30, 0x59, /* SEQUENCE, length 89 bytes */ - 0x30, 0x13, /* SEQUENCE, length 19 bytes */ - 0x06, 0x07, /* OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) */ - 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, -}; -/* PrimeX will get inserted */ -#if 0 -0x06, 0x08, /* OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7) */ - 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, -#endif -static const unsigned char cert_asn1_header2[] = { - 0x03, 0x42, /* BIT STRING, length 66 bytes */ - /* Note: 0 bits (0x00) and no compression (0x04) are already in the certificate */ -}; - -static gnutls_datum_t * -get_asn1_spki(const uint8_t *data, size_t size) { - coap_binary_t *pub_key = get_asn1_tag(COAP_ASN1_BITSTRING, data, size, NULL); - coap_binary_t *prime = get_asn1_tag(COAP_ASN1_IDENTIFIER, data, size, NULL); - gnutls_datum_t *spki = NULL; - - if (pub_key && prime) { - size_t header_size = sizeof(cert_asn1_header1) + - 2 + - prime->length + - sizeof(cert_asn1_header2); - uint8_t *tmp = gnutls_malloc(sizeof(gnutls_datum_t) + - header_size + - pub_key->length); - - if (tmp) { - spki = (gnutls_datum_t *)tmp; - spki->data = &tmp[sizeof(gnutls_datum_t)]; - memcpy(&spki->data[header_size], pub_key->s, pub_key->length); - memcpy(spki->data, cert_asn1_header1, sizeof(cert_asn1_header1)); - spki->data[sizeof(cert_asn1_header1)] = COAP_ASN1_IDENTIFIER; - spki->data[sizeof(cert_asn1_header1)+1] = prime->length; - memcpy(&spki->data[sizeof(cert_asn1_header1)+2], - prime->s, prime->length); - memcpy(&spki->data[sizeof(cert_asn1_header1)+2+prime->length], - cert_asn1_header2, sizeof(cert_asn1_header2)); - spki->size = header_size + pub_key->length; - } - } - if (pub_key) - coap_delete_binary(pub_key); - if (prime) - coap_delete_binary(prime); - return spki; -} -#endif /* GNUTLS_VERSION_NUMBER >= 0x030606 */ /* * return 0 Success (GNUTLS_E_SUCCESS) @@ -1145,12 +1091,16 @@ setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials, if (gnutls_pem_base64_decode2("EC PRIVATE KEY", &key, &der_private) == 0) { - gnutls_datum_t *spki = get_asn1_spki(der_private.data, - der_private.size); + coap_binary_t *spki = get_asn1_spki(der_private.data, + der_private.size); if (spki) { + gnutls_datum_t tspki; + + tspki.data = spki->s; + tspki.size = spki->length; ret = gnutls_certificate_set_rawpk_key_mem(*pki_credentials, - spki, + &tspki, &der_private, GNUTLS_X509_FMT_DER, NULL, COAP_GNUTLS_KEY_RPK, @@ -1158,7 +1108,7 @@ setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials, if (ret >= 0) { have_done_key = 1; } - gnutls_free(spki); + coap_delete_binary(spki); } gnutls_free(der_private.data); } @@ -1256,12 +1206,16 @@ setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials, int have_done_key = 0; if (setup_data->pki_key.key.asn1.private_key_type == COAP_ASN1_PKEY_EC) { - gnutls_datum_t *spki = get_asn1_spki(key.data, - key.size); + coap_binary_t *spki = get_asn1_spki(key.data, + key.size); if (spki) { + gnutls_datum_t tspki; + + tspki.data = spki->s; + tspki.size = spki->length; ret = gnutls_certificate_set_rawpk_key_mem(*pki_credentials, - spki, + &tspki, &key, GNUTLS_X509_FMT_DER, NULL, COAP_GNUTLS_KEY_RPK, @@ -1269,7 +1223,7 @@ setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials, if (ret >= 0) { have_done_key = 1; } - gnutls_free(spki); + coap_delete_binary(spki); } } if (!have_done_key) { diff --git a/src/coap_notls.c b/src/coap_notls.c index 90c9c6b287..0a95510774 100644 --- a/src/coap_notls.c +++ b/src/coap_notls.c @@ -17,7 +17,7 @@ #include "coap3/coap_internal.h" -#if !defined(COAP_WITH_LIBTINYDTLS) && !defined(COAP_WITH_LIBOPENSSL) && !defined(COAP_WITH_LIBGNUTLS) && !defined(COAP_WITH_LIBMBEDTLS) +#if !defined(COAP_WITH_LIBTINYDTLS) && !defined(COAP_WITH_LIBOPENSSL) && !defined(COAP_WITH_LIBWOLFSSL) && !defined(COAP_WITH_LIBGNUTLS) && !defined(COAP_WITH_LIBMBEDTLS) int coap_dtls_is_supported(void) { @@ -400,7 +400,7 @@ coap_crypto_hmac(cose_hmac_alg_t hmac_alg, #endif /* COAP_OSCORE_SUPPORT */ -#else /* !COAP_WITH_LIBTINYDTLS && !COAP_WITH_LIBOPENSSL && !COAP_WITH_LIBGNUTLS */ +#else /* !COAP_WITH_LIBTINYDTLS && !COAP_WITH_LIBOPENSSL && !COAP_WITH_LIBWOLFSSL && !COAP_WITH_LIBGNUTLS */ #ifdef __clang__ /* Make compilers happy that do not like empty modules. As this function is @@ -412,4 +412,4 @@ static inline void dummy(void) { } -#endif /* !COAP_WITH_LIBTINYDTLS && !COAP_WITH_LIBOPENSSL && !COAP_WITH_LIBGNUTLS && !COAP_WITH_LIBMBEDTLS */ +#endif /* !COAP_WITH_LIBTINYDTLS && !COAP_WITH_LIBOPENSSL && !COAP_WITH_LIBWOLFSSL && !COAP_WITH_LIBGNUTLS && !COAP_WITH_LIBMBEDTLS */ diff --git a/src/coap_sha1.c b/src/coap_sha1.c index fef9fde47f..b71915ba46 100644 --- a/src/coap_sha1.c +++ b/src/coap_sha1.c @@ -65,7 +65,7 @@ #include "coap3/coap_internal.h" -#if COAP_WS_SUPPORT && !defined(COAP_WITH_LIBOPENSSL) && !defined(COAP_WITH_LIBGNUTLS) && !defined(COAP_WITH_LIBMBEDTLS) +#if COAP_WS_SUPPORT && !defined(COAP_WITH_LIBOPENSSL) && !defined(COAP_WITH_LIBGNUTLS) && !defined(COAP_WITH_LIBMBEDTLS) && !defined(COAP_WITH_LIBWOLFSSL) /* * Define the SHA1 circular left shift macro */ diff --git a/src/coap_wolfssl.c b/src/coap_wolfssl.c new file mode 100644 index 0000000000..5a7d77dc59 --- /dev/null +++ b/src/coap_wolfssl.c @@ -0,0 +1,3120 @@ +/* + * coap_wolfssl.c -- wolfSSL Transport Layer Support for libcoap + * + * Copyright (C) 2017 Jean-Claude Michelou + * Copyright (C) 2023 Javier Blanco + * Copyright (C) 2018-2024 Jon Shallow + * + * SPDX-License-Identifier: BSD-2-Clause + * + * This file is part of the CoAP library libcoap. Please see README for terms + * of use. + */ + +/** + * @file coap_wolfssl.c + * @brief wolfSSL specific interface functions. + */ + +#include "coap3/coap_internal.h" + +#ifdef COAP_WITH_LIBWOLFSSL + +/* + * Implemented using wolfSSL's OpenSSL compatibility layer based on coap_openssl.c. + * + * It is possible to override the Ciphers, define the Algorithms or Groups + * to use for the SSL negotiations at compile time. This is done by the adding + * of the appropriate -D option to the CFLAGS parameter that is used on the + * ./configure command line. + * E.g. ./configure CFLAGS="-DXX='\"YY\"' -DUU='\"VV\"'" + * The parameter value is case-sensitive and needs the extra " wrapper so that + * it includes the "text" with quotes in the defined parameter.. + * + * The (client) PKI ciphers can be overridden with (example) + * CFLAGS="-DCOAP_WOLFSSL_PKI_CIPHERS='\"TLS13-AES128-GCM-SHA256\"'" + * + * The (client) PSK ciphers can be overridden with (example) + * CFLAGS="-DCOAP_WOLFSSL_PSK_CIPHERS='\"PSK-AES128-CCM\"'" + * + * The Algorithms can be defined by (example) + * CFLAGS="-DCOAP_WOLFSSL_SIGALGS='\"RSA+SHA256\"'" + * + * The Groups (including post-quantum ones, if wolfSSL has been built with liboqs + * and DTLS 1.3 enabled) can be defined using the following example: + * CFLAGS="-DCOAP_WOLFSSL_GROUPS=\"\\\"P-384:P-256:KYBER_LEVEL1\\\"\"" ./configure ... + * + * wolfSSL library building (not libcoap library building) + * + * If wolfSSL is going to interoperate with TinyDTLS, then the wolfSSL library + * needs to be build with + * $ ./configure CFLAGS="-DBUILD_TLS_PSK_WITH_AES_128_CCM" + * as TinyDTLS currently only supports CCM. + * + * If wolfSSL debug logging is required, then the wolfSSL library needs to be built with + * $ ./configure --enable-debug + * + * For extra TLS debugging + * $./configure --enable-debug CFLAGS="-DWOLFSSL_DEBUG_TLS" + * + * If wolfSSL dtls1.3 support is required, then the wolfSSL library needs to be built with + * $ ./configure --enable-dtls13 + * + * If wolfSSL RPK support is required, then the wolfSSL library needs to be built with + * $ ./configure CFLAGS="-DHAVE_RPK" + * + * When building the wolfSSL library from scratch, it is suggested that the library + * built with + * $ ./configure --enable-all + * to get the needed common options. + */ + +#include +#include +#include +#include +#include + +#ifdef COAP_EPOLL_SUPPORT +# include +#endif /* COAP_EPOLL_SUPPORT */ + +#if LIBWOLFSSL_VERSION_HEX < 0x05002000 +#error Must be compiled against wolfSSL 5.2.0 or later +#endif + +#ifdef _WIN32 +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#endif + +/* missing definitions */ +#define WOLFSSL3_AL_FATAL 2 +#define WOLFSSL_TLSEXT_ERR_OK 0 + +/* This structure encapsulates the wolfSSL context object. */ +typedef struct coap_dtls_context_t { + WOLFSSL_CTX *ctx; + WOLFSSL_HMAC_CTX *cookie_hmac; +} coap_dtls_context_t; + +typedef struct coap_tls_context_t { + WOLFSSL_CTX *ctx; +} coap_tls_context_t; + +#define IS_PSK 0x1 +#define IS_PKI 0x2 + +typedef struct coap_wolfssl_context_t { + coap_dtls_context_t dtls; +#if !COAP_DISABLE_TCP + coap_tls_context_t tls; +#endif /* !COAP_DISABLE_TCP */ + coap_dtls_pki_t setup_data; + int psk_pki_enabled; + char *root_ca_file; + char *root_ca_dir; +} coap_wolfssl_context_t; + +typedef struct coap_ssl_data_t { + coap_session_t *session; + const void *pdu; + unsigned pdu_len; + unsigned peekmode; +} coap_ssl_data_t; + +typedef struct coap_wolfssl_env_t { + WOLFSSL *ssl; + coap_tick_t last_timeout; + unsigned int retry_scalar; + coap_ssl_data_t data; + int done_psk_check; + coap_dtls_role_t role; +} coap_wolfssl_env_t; + +typedef enum coap_enc_method_t { + COAP_ENC_PSK, + COAP_ENC_PKI, +} coap_enc_method_t; + +static void * +wolfssl_malloc(size_t size) { + void *ret = XMALLOC(size, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +static void +wolfssl_free(void *ptr) { + if (ptr) + XFREE(ptr, NULL, DYNAMIC_TYPE_TMP_BUFFER); +} + +static char * +wolfssl_strdup(const char *str) { + char *ret = (char *)wolfssl_malloc(strlen(str) + 1); + + if (ret) { + strcpy(ret, str); + } + return ret; +} + +static char * +wolfssl_strndup(const char *str, size_t n) { + size_t len = strnlen(str, n); + char *ret = (char *)wolfssl_malloc(len + 1); + + if (ret) { + strncpy(ret, str, len); + ret[len] = '\0'; + } + return ret; +} + +static coap_wolfssl_env_t * +coap_dtls_new_wolfssl_env(coap_session_t *c_session, coap_dtls_role_t role) { + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)c_session->tls; + + assert(w_env == NULL); + w_env = (coap_wolfssl_env_t *)wolfssl_malloc(sizeof(coap_wolfssl_env_t)); + if (!w_env) { + return NULL; + } + memset(w_env, 0, sizeof(coap_wolfssl_env_t)); + w_env->role = role; + return w_env; +} + +static void +coap_dtls_free_wolfssl_env(coap_wolfssl_env_t *w_env) { + if (w_env) { + wolfssl_free(w_env); + } +} + +#if COAP_CLIENT_SUPPORT +#ifndef WOLFSSL_CIPHER_LIST_MAX_SIZE +#define WOLFSSL_CIPHER_LIST_MAX_SIZE 4096 +#endif /* WOLFSSL_CIPHER_LIST_MAX_SIZE */ + +#ifdef COAP_WOLFSSL_PSK_CIPHERS +static char psk_ciphers[] = COAP_WOLFSSL_PSK_CIPHERS; +#else /* ! COAP_WOLFSSL_PSK_CIPHERS */ +static char psk_ciphers[WOLFSSL_CIPHER_LIST_MAX_SIZE]; +#endif /* ! COAP_WOLFSSL_PSK_CIPHERS */ + +#ifdef COAP_WOLFSSL_PKI_CIPHERS +static char pki_ciphers[] = COAP_WOLFSSL_PKI_CIPHERS; +#else /* ! COAP_WOLFSSL_PKI_CIPHERS */ +static char pki_ciphers[WOLFSSL_CIPHER_LIST_MAX_SIZE]; +#endif /* ! COAP_WOLFSSL_PKI_CIPHERS */ + +static void +set_ciphersuites(WOLFSSL *ssl, coap_enc_method_t method) { +#if ! defined(COAP_WOLFSSL_PSK_CIPHERS) || ! defined(COAP_WOLFSSL_PKI_CIPHERS) + static int processed_ciphers = 0; + + if (!processed_ciphers) { + static char ciphers[WOLFSSL_CIPHER_LIST_MAX_SIZE]; + char *ciphers_ofs = ciphers; + char *cp; +#if ! defined(COAP_WOLFSSL_PSK_CIPHERS) + char *psk_ofs = psk_ciphers; +#endif /* ! COAP_WOLFSSL_PSK_CIPHERS */ +#if ! defined(COAP_WOLFSSL_PKI_CIPHERS) + char *pki_ofs = pki_ciphers; +#endif /* ! COAP_WOLFSSL_PKI_CIPHERS */ + + if (wolfSSL_get_ciphers(ciphers, (int)sizeof(ciphers)) != WOLFSSL_SUCCESS) { + coap_log_warn("set_ciphersuites: Failed to get ciphers\n"); + return; + } + + while (ciphers_ofs) { + cp = strchr(ciphers_ofs, ':'); + if (cp) + *cp = '\000'; + if (strstr(ciphers_ofs, "NULL")) { + /* NULL type not required */ + goto next_a; + } + if (strcmp(ciphers_ofs, "RENEGOTIATION-INFO") == 0) { + /* Skip for now - adding to end */ + goto next_a; + } else if (strstr(ciphers_ofs, "PSK")) { +#if ! defined(COAP_WOLFSSL_PSK_CIPHERS) + if (psk_ofs != psk_ciphers) { + psk_ofs[0] = ':'; + psk_ofs++; + } + strcpy(psk_ofs, ciphers_ofs); + psk_ofs += strlen(ciphers_ofs); + psk_ofs[0] = '\000'; +#endif /* ! COAP_WOLFSSL_PSK_CIPHERS */ + } else { +#if ! defined(COAP_WOLFSSL_PKI_CIPHERS) + if (pki_ofs != pki_ciphers) { + pki_ofs[0] = ':'; + pki_ofs++; + } + strcpy(pki_ofs, ciphers_ofs); + pki_ofs += strlen(ciphers_ofs); + pki_ofs[0] = '\000'; +#endif /* ! COAP_WOLFSSL_PKI_CIPHERS */ + } +next_a: + if (cp) + ciphers_ofs = cp + 1; + else + ciphers_ofs = NULL; + } +#ifndef HAVE_SECURE_RENEGOTIATION + /* + * Need to add in dummy "RENEGOTIATION-INFO" at end. + * This addition will get ignored if the complied library does not + * support it. + */ +#if ! defined(COAP_WOLFSSL_PSK_CIPHERS) + if (psk_ofs != psk_ciphers) { + psk_ofs[0] = ':'; + psk_ofs++; + } + strcpy(psk_ofs, "RENEGOTIATION-INFO"); + psk_ofs += strlen("RENEGOTIATION-INFO"); + psk_ofs[0] = '\000'; +#endif /* ! COAP_WOLFSSL_PSK_CIPHERS */ +#if ! defined(COAP_WOLFSSL_PKI_CIPHERS) + if (pki_ofs != pki_ciphers) { + pki_ofs[0] = ':'; + pki_ofs++; + } + strcpy(pki_ofs, "RENEGOTIATION-INFO"); + pki_ofs += strlen("RENEGOTIATION-INFO"); + pki_ofs[0] = '\000'; +#endif /* ! COAP_WOLFSSL_PSK_CIPHERS */ +#endif /* ! HAVE_SECURE_RENEGOTIATION */ + + processed_ciphers = 1; + } +#endif /* ! COAP_WOLFSSL_PSK_CIPHERS || ! COAP_WOLFSSL_PKI_CIPHERS */ + + if (method == COAP_ENC_PSK) { + wolfSSL_set_cipher_list(ssl, psk_ciphers); + } else { + wolfSSL_set_cipher_list(ssl, pki_ciphers); + } +} +#endif /* COAP_CLIENT_SUPPORT */ + +#if COAP_SERVER_SUPPORT +static int psk_tls_server_name_call_back(WOLFSSL *ssl, int *sd, void *arg); +#endif /* COAP_SERVER_SUPPORT */ +static int tls_verify_call_back(int preverify_ok, WOLFSSL_X509_STORE_CTX *ctx); + +int +coap_dtls_is_supported(void) { + if (wolfSSL_lib_version_hex() < 0x05002000) { + coap_log_warn("wolfSSL version 5.2.0 or later is required\n"); + return 0; + } + return 1; +} + +int +coap_tls_is_supported(void) { +#if !COAP_DISABLE_TCP + if (wolfSSL_lib_version_hex() < 0x05002000) { + coap_log_warn("wolfSSL version 5.2.0 or later is required\n"); + return 0; + } + return 1; +#else /* COAP_DISABLE_TCP */ + return 0; +#endif /* COAP_DISABLE_TCP */ +} + +/* + * return 0 failed + * 1 passed + */ +int +coap_dtls_psk_is_supported(void) { + return 1; +} + +/* + * return 0 failed + * 1 passed + */ +int +coap_dtls_pki_is_supported(void) { + return 1; +} + +/* + * return 0 failed + * 1 passed + */ +int +coap_dtls_pkcs11_is_supported(void) { + return 0; +} + +/* + * return 0 failed + * 1 passed + */ +int +coap_dtls_rpk_is_supported(void) { +#if defined(HAVE_RPK) && LIBWOLFSSL_VERSION_HEX >= 0x05006004 + return 1; +#else /* ! HAVE_RPK || LIBWOLFSSL_VERSION_HEX < 0x05006004 */ + return 0; +#endif /* ! HAVE_RPK || LIBWOLFSSL_VERSION_HEX < 0x05006004 */ +} + +coap_tls_version_t * +coap_get_tls_library_version(void) { + static coap_tls_version_t version; + version.version = wolfSSL_lib_version_hex(); + version.built_version = LIBWOLFSSL_VERSION_HEX; + version.type = COAP_TLS_LIBRARY_WOLFSSL; + + return &version; +} + +static void +coap_wolfssl_log_func(int level, const char *text) { + int use_level; + + switch ((int)level) { + case ERROR_LOG: + use_level = COAP_LOG_DEBUG; + break; + case INFO_LOG: + use_level = COAP_LOG_INFO; + break; + case ENTER_LOG: + use_level = COAP_LOG_INFO; + break; + case LEAVE_LOG: + use_level = COAP_LOG_INFO; + break; + case OTHER_LOG: + use_level = COAP_LOG_DEBUG; + break; + default: + use_level = COAP_LOG_DEBUG; + break; + } + coap_dtls_log(use_level, "%s\n", text); +} + +void +coap_dtls_startup(void) { + if (wolfSSL_library_init() != WOLFSSL_SUCCESS) { + coap_log_err("wolfSSL_library_init: Fail\n"); + return; + } + wolfSSL_load_error_strings(); + wolfSSL_SetLoggingCb(coap_wolfssl_log_func); + wolfSSL_Debugging_ON(); +} + +void +coap_dtls_shutdown(void) { + wolfSSL_ERR_free_strings(); + coap_dtls_set_log_level(COAP_LOG_EMERG); + wolfSSL_Debugging_OFF(); +} + +void * +coap_dtls_get_tls(const coap_session_t *c_session, + coap_tls_library_t *tls_lib) { + if (tls_lib) + *tls_lib = COAP_TLS_LIBRARY_WOLFSSL; + if (c_session) { + coap_wolfssl_env_t *w_env; + + /* To get around const issue */ + memcpy(&w_env, &c_session->tls, sizeof(w_env)); + + return (void *)&w_env->ssl; + } + return NULL; +} + +/* + * Logging levels use the standard CoAP logging levels + */ +static coap_log_t dtls_log_level = COAP_LOG_EMERG; + +void +coap_dtls_set_log_level(coap_log_t level) { + dtls_log_level = level; +} + +coap_log_t +coap_dtls_get_log_level(void) { + return dtls_log_level; +} + +static int +coap_dgram_read(WOLFSSL *ssl, char *out, int outl, void *ctx) { + int ret = 0; + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)ctx; + coap_ssl_data_t *data = w_env ? &w_env->data : NULL; + coap_tick_t now; + + (void)ssl; + if (w_env && !w_env->done_psk_check && w_env->ssl) { + if (wolfSSL_SSL_in_init(w_env->ssl)) { + const char *name = wolfSSL_get_cipher_name(w_env->ssl); + + if (name) { + coap_dtls_log(COAP_LOG_DEBUG," Cipher Suite: %s\n", name); + + if (strstr(name, "PSK") && w_env->role == COAP_DTLS_ROLE_SERVER) { + wolfSSL_set_verify(w_env->ssl, WOLFSSL_VERIFY_NONE, tls_verify_call_back); + w_env->done_psk_check = 1; + } + } + } + } + if (out != NULL) { + if (data != NULL && data->pdu_len > 0) { + if (outl < (int)data->pdu_len) { + memcpy(out, data->pdu, outl); + ret = outl; + } else { + memcpy(out, data->pdu, data->pdu_len); + ret = (int)data->pdu_len; + } + if (!data->peekmode) { + data->pdu_len = 0; + data->pdu = NULL; + } + coap_ticks(&now); + w_env->last_timeout = now; + } else { + ret = WANT_READ; + } + } + return ret; +} + +static int +coap_dgram_write(WOLFSSL *ssl, char *in, int inl, void *ctx) { + int ret = 0; + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)ctx; + coap_ssl_data_t *data = w_env ? &w_env->data : NULL; + coap_tick_t now; + + (void)ssl; + if (data->session) { + if (!coap_netif_available(data->session) +#if COAP_SERVER_SUPPORT + && data->session->endpoint == NULL +#endif /* COAP_SERVER_SUPPORT */ + ) { + /* socket was closed on client due to error */ + errno = ECONNRESET; + return -1; + } + ret = (int)data->session->sock.lfunc[COAP_LAYER_TLS].l_write(data->session, + (const uint8_t *)in, + inl); + if (ret > 0) { + coap_ticks(&now); + w_env->last_timeout = now; + } + } else { + ret = -1; + } + return ret; +} + +#if COAP_CLIENT_SUPPORT +static unsigned int +coap_dtls_psk_client_callback(WOLFSSL *ssl, + const char *hint, + char *identity, + unsigned int max_identity_len, + unsigned char *psk, + unsigned int max_psk_len) { + coap_session_t *c_session; + coap_wolfssl_context_t *w_context; + coap_dtls_cpsk_t *setup_data; + const coap_dtls_cpsk_info_t *cpsk_info; + const coap_bin_const_t *psk_key; + const coap_bin_const_t *psk_identity; + + c_session = (coap_session_t *)wolfSSL_get_app_data(ssl); + if (c_session == NULL) + return 0; + w_context = (coap_wolfssl_context_t *)c_session->context->dtls_context; + if (w_context == NULL) + return 0; + setup_data = &c_session->cpsk_setup_data; + + if (setup_data->validate_ih_call_back) { + coap_bin_const_t temp; + coap_str_const_t lhint; + + temp.s = hint ? (const uint8_t *)hint : (const uint8_t *)""; + temp.length = strlen((const char *)temp.s); + coap_session_refresh_psk_hint(c_session, &temp); + + coap_log_debug("got psk_identity_hint: '%.*s'\n", (int)temp.length, + (const char *)temp.s); + + + lhint.s = temp.s; + lhint.length = temp.length; + cpsk_info = + setup_data->validate_ih_call_back(&lhint, + c_session, + setup_data->ih_call_back_arg); + + if (cpsk_info == NULL) + return 0; + + coap_session_refresh_psk_identity(c_session, &cpsk_info->identity); + coap_session_refresh_psk_key(c_session, &cpsk_info->key); + psk_identity = &cpsk_info->identity; + psk_key = &cpsk_info->key; + } else { + psk_identity = coap_get_session_client_psk_identity(c_session); + psk_key = coap_get_session_client_psk_key(c_session); + } + + if (psk_identity == NULL || psk_key == NULL) { + coap_log_warn("no PSK available\n"); + return 0; + } + + /* identity has to be NULL terminated */ + if (!max_identity_len) + return 0; + max_identity_len--; + if (psk_identity->length > max_identity_len) { + coap_log_warn("psk_identity too large, truncated to %d bytes\n", + max_identity_len); + } else { + /* Reduce to match */ + max_identity_len = (unsigned int)psk_identity->length; + } + memcpy(identity, psk_identity->s, max_identity_len); + identity[max_identity_len] = '\000'; + + if (psk_key->length > max_psk_len) { + coap_log_warn("psk_key too large, truncated to %d bytes\n", + max_psk_len); + } else { + /* Reduce to match */ + max_psk_len = (unsigned int)psk_key->length; + } + memcpy(psk, psk_key->s, max_psk_len); + return max_psk_len; +} + +static unsigned int +coap_dtls_psk_client_cs_callback(WOLFSSL *ssl, const char *hint, + char *identity, unsigned int max_identity_len, + unsigned char *psk, unsigned int max_psk_len, + const char *ciphersuite) { + int key_len = coap_dtls_psk_client_callback(ssl, + hint, + identity, + max_identity_len, + psk, + max_psk_len); + + (void)ciphersuite; + return key_len; +} + +#endif /* COAP_CLIENT_SUPPORT */ + +#if COAP_SERVER_SUPPORT +static unsigned int +coap_dtls_psk_server_callback( + WOLFSSL *ssl, + const char *identity, + unsigned char *psk, + unsigned int max_psk_len) { + coap_session_t *c_session; + coap_dtls_spsk_t *setup_data; + coap_bin_const_t lidentity; + const coap_bin_const_t *psk_key; + + c_session = (coap_session_t *)wolfSSL_get_app_data(ssl); + if (c_session == NULL) + return 0; + + setup_data = &c_session->context->spsk_setup_data; + + /* Track the Identity being used */ + lidentity.s = identity ? (const uint8_t *)identity : (const uint8_t *)""; + lidentity.length = strlen((const char *)lidentity.s); + coap_session_refresh_psk_identity(c_session, &lidentity); + + coap_log_debug("got psk_identity: '%.*s'\n", + (int)lidentity.length, (const char *)lidentity.s); + + if (setup_data->validate_id_call_back) { + psk_key = setup_data->validate_id_call_back(&lidentity, + c_session, + setup_data->id_call_back_arg); + + coap_session_refresh_psk_key(c_session, psk_key); + } else { + psk_key = coap_get_session_server_psk_key(c_session); + } + + if (psk_key == NULL) + return 0; + + if (psk_key->length > max_psk_len) { + coap_log_warn("psk_key too large, truncated to %d bytes\n", + max_psk_len); + } else { + /* Reduce to match */ + max_psk_len = (unsigned int)psk_key->length; + } + memcpy(psk, psk_key->s, max_psk_len); + return max_psk_len; +} +#endif /* COAP_SERVER_SUPPORT */ + +static const char * +ssl_function_definition(unsigned long e) { + static char buff[80]; + + snprintf(buff, sizeof(buff), " at %s:%s", + wolfSSL_ERR_lib_error_string(e), wolfSSL_ERR_func_error_string(e)); + return buff; +} + +static void +coap_dtls_info_callback(const WOLFSSL *ssl, int where, int ret) { + coap_session_t *session = (coap_session_t *)wolfSSL_get_app_data(ssl); + const char *pstr; + int w = where &~SSL_ST_MASK; + + if (w & SSL_ST_CONNECT) + pstr = "wolfSSL_connect"; + else if (w & SSL_ST_ACCEPT) + pstr = "wolfSSL_accept"; + else + pstr = "undefined"; + + if (where & SSL_CB_LOOP) { + coap_dtls_log(COAP_LOG_DEBUG, "* %s: %s:%s\n", + coap_session_str(session), pstr, wolfSSL_state_string_long(ssl)); + } else if (where & SSL_CB_ALERT) { + coap_log_t log_level = COAP_LOG_INFO; + pstr = (where & SSL_CB_READ) ? "read" : "write"; + if ((where & (SSL_CB_WRITE|SSL_CB_READ)) && (ret >> 8) == WOLFSSL3_AL_FATAL) { + session->dtls_event = COAP_EVENT_DTLS_ERROR; + if ((ret & 0xff) != close_notify) + log_level = COAP_LOG_WARN; + } + + /* Need to let CoAP logging know why this session is dying */ + coap_log(log_level, "* %s: SSL3 alert %s:%s:%s\n", + coap_session_str(session), + pstr, + wolfSSL_alert_type_string_long(ret), + wolfSSL_alert_desc_string_long(ret)); + } else if (where & SSL_CB_EXIT) { + if (ret == 0) { + if (dtls_log_level >= COAP_LOG_WARN) { + unsigned long e; + coap_dtls_log(COAP_LOG_WARN, "* %s: %s:failed in %s\n", + coap_session_str(session), pstr, wolfSSL_state_string_long(ssl)); + while ((e = wolfSSL_ERR_get_error())) + coap_dtls_log(COAP_LOG_WARN, "* %s: %s%s\n", + coap_session_str(session), wolfSSL_ERR_reason_error_string(e), + ssl_function_definition(e)); + } + } else if (ret < 0) { + if (dtls_log_level >= COAP_LOG_WARN) { + WOLFSSL *rw_ssl; + + /* Need to do this to not get a compiler warning about const parameters */ + memcpy(&rw_ssl, &ssl, sizeof(rw_ssl)); + int err = wolfSSL_get_error(rw_ssl, ret); + if (err != WOLFSSL_ERROR_WANT_READ && err != WOLFSSL_ERROR_WANT_WRITE && + err != WOLFSSL_ERROR_WANT_CONNECT && err != WOLFSSL_ERROR_WANT_ACCEPT && + err != WOLFSSL_ERROR_WANT_X509_LOOKUP) { + long e; + coap_dtls_log(COAP_LOG_WARN, "* %s: %s:error in %s\n", + coap_session_str(session), pstr, wolfSSL_state_string_long(ssl)); + while ((e = wolfSSL_ERR_get_error())) + coap_dtls_log(COAP_LOG_WARN, "* %s: %s%s\n", + coap_session_str(session), wolfSSL_ERR_reason_error_string(e), + ssl_function_definition(e)); + } + } + } + } + + if (where == SSL_CB_HANDSHAKE_START) { + WOLFSSL *rw_ssl; + + /* Need to do this to not get a compiler warning about const parameters */ + memcpy(&rw_ssl, &ssl, sizeof(rw_ssl)); + if (wolfSSL_is_init_finished(rw_ssl)) + session->dtls_event = COAP_EVENT_DTLS_RENEGOTIATE; + } +} + +/* + * strm + * return +ve data amount + * 0 no more + * -1 error + */ +static int +coap_sock_read(WOLFSSL *ssl, char *out, int outl, void *ctx) { + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)ctx; + int ret = 0; + coap_session_t *session = w_env ? w_env->data.session : NULL; + + (void)ssl; + if (w_env && !w_env->done_psk_check && w_env->ssl && + w_env->role == COAP_DTLS_ROLE_SERVER) { + if (wolfSSL_SSL_in_init(w_env->ssl)) { + const char *name = wolfSSL_get_cipher_name(w_env->ssl); + + if (name) { + coap_dtls_log(COAP_LOG_DEBUG,"Cipher Suite: %s\n", name); + + if (strstr(name, "PSK")) { + wolfSSL_set_verify(w_env->ssl, WOLFSSL_VERIFY_NONE, tls_verify_call_back); + w_env->done_psk_check = 1; + } + } + } + } + if (out != NULL) { + ret =(int)session->sock.lfunc[COAP_LAYER_TLS].l_read(session, (u_char *)out, + outl); + if (ret == 0) { + ret = WANT_READ; + } + } + return ret; +} + +/* + * strm + * return +ve data amount + * 0 no more + * -1 error (error in errno) + */ +static int +coap_sock_write(WOLFSSL *ssl, char *in, int inl, void *ctx) { + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)ctx; + int ret = 0; + coap_session_t *session = w_env ? w_env->data.session : NULL; + + (void)ssl; + ret = (int)session->sock.lfunc[COAP_LAYER_TLS].l_write(session, + (const uint8_t *)in, + inl); + /* Translate layer what returns into what wolfSSL expects */ + if (ret == 0) { + ret = -1; + } else { + if (ret == -1) { + if ((session->state == COAP_SESSION_STATE_CSM || + session->state == COAP_SESSION_STATE_HANDSHAKE) && + (errno == EPIPE || errno == ECONNRESET)) { + /* + * Need to handle a TCP timing window where an agent continues with + * the sending of the next handshake or a CSM. + * However, the peer does not like a certificate and so sends a + * fatal alert and closes the TCP session. + * The sending of the next handshake or CSM may get terminated because + * of the closed TCP session, but there is still an outstanding alert + * to be read in and reported on. + * In this case, pretend that sending the info was fine so that the + * alert can be read (which effectively is what happens with DTLS). + */ + ret = inl; + } + } + } + return ret; +} + +static void +coap_set_user_prefs(WOLFSSL_CTX *ctx) { + (void)ctx; + +#ifdef COAP_WOLFSSL_SIGALGS + wolfSSL_CTX_set1_sigalgs_list(ctx, COAP_WOLFSSL_SIGALGS); +#endif +#ifdef COAP_WOLFSSL_GROUPS + int ret; + ret = wolfSSL_CTX_set1_groups_list(ctx, + (char *) COAP_WOLFSSL_GROUPS); + if (ret != WOLFSSL_SUCCESS) { + coap_log_debug("Failed to set group list\n"); + } +#endif +} + +/* Set up DTLS context if not alread done */ +static int +setup_dtls_context(coap_wolfssl_context_t *w_context) { + if (!w_context->dtls.ctx) { + uint8_t cookie_secret[32]; + + /* Set up DTLS context */ + w_context->dtls.ctx = wolfSSL_CTX_new(wolfDTLS_method()); + if (!w_context->dtls.ctx) + goto error; + wolfSSL_CTX_set_min_proto_version(w_context->dtls.ctx, + DTLS1_2_VERSION); + wolfSSL_CTX_set_ex_data(w_context->dtls.ctx, 0, &w_context->dtls); + coap_set_user_prefs(w_context->dtls.ctx); + memset(cookie_secret, 0, sizeof(cookie_secret)); + if (!wolfSSL_RAND_bytes(cookie_secret, (int)sizeof(cookie_secret))) { + coap_dtls_log(COAP_LOG_WARN, + "Insufficient entropy for random cookie generation"); + coap_prng(cookie_secret, sizeof(cookie_secret)); + } + w_context->dtls.cookie_hmac = wolfSSL_HMAC_CTX_new(); + if (!wolfSSL_HMAC_Init_ex(w_context->dtls.cookie_hmac, cookie_secret, (int)sizeof(cookie_secret), + wolfSSL_EVP_sha256(), NULL)) + goto error; + + wolfSSL_CTX_set_info_callback(w_context->dtls.ctx, coap_dtls_info_callback); + wolfSSL_CTX_set_options(w_context->dtls.ctx, SSL_OP_NO_QUERY_MTU); + wolfSSL_SetIORecv(w_context->dtls.ctx, coap_dgram_read); + wolfSSL_SetIOSend(w_context->dtls.ctx, coap_dgram_write); +#ifdef WOLFSSL_DTLS_MTU + wolfSSL_dtls_set_mtu(context->dtls.ssl, COAP_DEFAULT_MTU); +#endif /* WOLFSSL_DTLS_MTU */ + } + return 1; + +error: + coap_log_warn("wolfssl: unable to set up DTLS context\n"); + return 0; +} + +#if !COAP_DISABLE_TCP + +/* Set up TLS context if not alread done */ +static int +setup_tls_context(coap_wolfssl_context_t *w_context) { + if (!w_context->tls.ctx) { + /* Set up TLS context */ + w_context->tls.ctx = wolfSSL_CTX_new(wolfSSLv23_method()); + if (!w_context->tls.ctx) + goto error; + wolfSSL_CTX_set_ex_data(w_context->tls.ctx, 0, &w_context->tls); + wolfSSL_CTX_set_min_proto_version(w_context->tls.ctx, TLS1_VERSION); + coap_set_user_prefs(w_context->tls.ctx); + wolfSSL_CTX_set_info_callback(w_context->tls.ctx, coap_dtls_info_callback); + wolfSSL_SetIORecv(w_context->tls.ctx, coap_sock_read); + wolfSSL_SetIOSend(w_context->tls.ctx, coap_sock_write); +#if COAP_CLIENT_SUPPORT + if (w_context->psk_pki_enabled & IS_PSK) { + wolfSSL_CTX_set_psk_client_cs_callback(w_context->tls.ctx, + coap_dtls_psk_client_cs_callback); + } +#endif /* COAP_CLIENT_SUPPORT */ + } + return 1; + +error: + coap_log_warn("wolfssl: unable to set up TLS context\n"); + return 0; +} +#endif /* ! COAP_DISABLE_TCP */ + +void * +coap_dtls_new_context(coap_context_t *c_context) { + coap_wolfssl_context_t *w_context; + (void)c_context; + + w_context = (coap_wolfssl_context_t *)wolfssl_malloc(sizeof(coap_wolfssl_context_t)); + if (w_context) { + memset(w_context, 0, sizeof(coap_wolfssl_context_t)); + } + + return w_context; +} + +#if COAP_SERVER_SUPPORT +int +coap_dtls_context_set_spsk(coap_context_t *c_context, + coap_dtls_spsk_t *setup_data + ) { + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)c_context->dtls_context); + + if (!setup_data || !w_context) + return 0; + + if (!setup_dtls_context(w_context)) + return 0; +#if !COAP_DISABLE_TCP + if (!setup_tls_context(w_context)) + return 0; +#endif /* !COAP_DISABLE_TCP */ + + wolfSSL_CTX_set_psk_server_callback(w_context->dtls.ctx, + coap_dtls_psk_server_callback); + +#if !COAP_DISABLE_TCP + wolfSSL_CTX_set_psk_server_callback(w_context->tls.ctx, + coap_dtls_psk_server_callback); +#endif /* !COAP_DISABLE_TCP */ + if (setup_data->psk_info.hint.s) { + char hint[COAP_DTLS_HINT_LENGTH]; + snprintf(hint, sizeof(hint), "%.*s", (int)setup_data->psk_info.hint.length, + setup_data->psk_info.hint.s); + wolfSSL_CTX_use_psk_identity_hint(w_context->dtls.ctx, hint); +#if !COAP_DISABLE_TCP + wolfSSL_CTX_use_psk_identity_hint(w_context->tls.ctx, hint); +#endif /* !COAP_DISABLE_TCP */ + } + if (setup_data->validate_sni_call_back) { + wolfSSL_CTX_set_servername_arg(w_context->dtls.ctx, + &c_context->spsk_setup_data); + wolfSSL_CTX_set_tlsext_servername_callback(w_context->dtls.ctx, + psk_tls_server_name_call_back); +#if !COAP_DISABLE_TCP + wolfSSL_CTX_set_servername_arg(w_context->tls.ctx, + &c_context->spsk_setup_data); + wolfSSL_CTX_set_tlsext_servername_callback(w_context->tls.ctx, + psk_tls_server_name_call_back); +#endif /* !COAP_DISABLE_TCP */ + } + w_context->psk_pki_enabled |= IS_PSK; + return 1; +} +#endif /* COAP_SERVER_SUPPORT */ + +#if COAP_CLIENT_SUPPORT +int +coap_dtls_context_set_cpsk(coap_context_t *c_context, + coap_dtls_cpsk_t *setup_data + ) { + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)c_context->dtls_context); + + if (!setup_data || !w_context) + return 0; + + w_context->psk_pki_enabled |= IS_PSK; + return 1; +} +#endif /* COAP_CLIENT_SUPPORT */ + +/* +Note: The returned key type is not actually used in wolfSSL_use_PrivateKey_ASN1. +The key type is inferred internally by wolfSSL when using wolfSSL_use_PrivateKey_buffer. +*/ +static int +map_key_type(int asn1_private_key_type + ) { + /* some OpenSSL EVP_PKEYs not available in compatibility layer: + COAP_ASN1_PKEY_RSA2, COAP_ASN1_PKEY_DSA[1-4], COAP_ASN1_PKEY_DHX + and COAP_ASN1_PKEY_TLS1_PRF */ + switch (asn1_private_key_type) { + case COAP_ASN1_PKEY_NONE: + return EVP_PKEY_NONE; + case COAP_ASN1_PKEY_RSA: + return EVP_PKEY_RSA; + case COAP_ASN1_PKEY_RSA2: + return EVP_PKEY_RSA; + case COAP_ASN1_PKEY_DSA: + return EVP_PKEY_DSA; + case COAP_ASN1_PKEY_DSA1: + return EVP_PKEY_DSA; + case COAP_ASN1_PKEY_DSA2: + return EVP_PKEY_DSA; + case COAP_ASN1_PKEY_DSA3: + return EVP_PKEY_DSA; + case COAP_ASN1_PKEY_DSA4: + return EVP_PKEY_DSA; + case COAP_ASN1_PKEY_DH: + return EVP_PKEY_DH; + case COAP_ASN1_PKEY_DHX: + return EVP_PKEY_DH; + case COAP_ASN1_PKEY_EC: + return EVP_PKEY_EC; + case COAP_ASN1_PKEY_HMAC: + return EVP_PKEY_HMAC; +#ifdef EVP_PKEY_CMAC + case COAP_ASN1_PKEY_CMAC: + return EVP_PKEY_CMAC; +#endif /* EVP_PKEY_CMAC */ +#ifdef EVP_PKEY_HKDF + case COAP_ASN1_PKEY_TLS1_PRF: + return EVP_PKEY_HKDF; + case COAP_ASN1_PKEY_HKDF: + return EVP_PKEY_HKDF; +#endif /* EVP_PKEY_HKDF */ + default: + coap_log_warn("*** setup_pki_ssl: DTLS: Unknown Private Key type %d for ASN1\n", + asn1_private_key_type); + break; + } + return 0; +} +#if !COAP_DISABLE_TCP +static uint8_t coap_alpn[] = { 4, 'c', 'o', 'a', 'p' }; + +#if COAP_SERVER_SUPPORT +static int +server_alpn_callback(WOLFSSL *ssl COAP_UNUSED, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg COAP_UNUSED + ) { + unsigned char *tout = NULL; + int ret; + if (inlen == 0) + return SSL_TLSEXT_ERR_NOACK; + ret = wolfSSL_select_next_proto(&tout, + outlen, + coap_alpn, + sizeof(coap_alpn), + in, + inlen); + *out = tout; + return (ret != OPENSSL_NPN_NEGOTIATED) ? noack_return : WOLFSSL_TLSEXT_ERR_OK; +} +#endif /* COAP_SERVER_SUPPORT */ +#endif /* !COAP_DISABLE_TCP */ + +static int +setup_pki_ssl(WOLFSSL *ssl, + coap_wolfssl_context_t *w_context, + coap_dtls_pki_t *setup_data, coap_dtls_role_t role) { + WOLFSSL_CTX *ctx = wolfSSL_get_SSL_CTX(ssl); + +#if !defined(HAVE_RPK) || LIBWOLFSSL_VERSION_HEX < 0x05006004 + if (setup_data->is_rpk_not_cert) { + coap_log_err("RPK Support not available in wolfSSL\n"); + return 0; + } +#endif /* ! HAVE_RPK || LIBWOLFSSL_VERSION_HEX < 0x05006004 */ + switch (setup_data->pki_key.key_type) { + case COAP_PKI_KEY_PEM: + if (setup_data->is_rpk_not_cert) { + coap_log_warn("RPK keys cannot be in COAP_PKI_KEY_PEM format\n"); + return 0; + } + if (setup_data->pki_key.key.pem.public_cert && + setup_data->pki_key.key.pem.public_cert[0]) { + if (!(wolfSSL_use_certificate_file(ssl, + setup_data->pki_key.key.pem.public_cert, + WOLFSSL_FILETYPE_PEM))) { + coap_log_warn("*** setup_pki_ssl: (D)TLS: %s: Unable to configure " + "%s Certificate\n", + setup_data->pki_key.key.pem.public_cert, + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return 0; + } + } else if (role == COAP_DTLS_ROLE_SERVER || + (setup_data->pki_key.key.pem.private_key && + setup_data->pki_key.key.pem.private_key[0])) { + coap_log_err("*** setup_pki_ssl: (D)TLS: No %s Certificate defined\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return 0; + } +#if defined(HAVE_RPK) && LIBWOLFSSL_VERSION_HEX >= 0x05006004 + else { + char stype[] = {WOLFSSL_CERT_TYPE_X509, WOLFSSL_CERT_TYPE_RPK}; + wolfSSL_set_server_cert_type(ssl, stype, sizeof(stype)/sizeof(stype[0])); + } +#endif /* HAVE_RPK && LIBWOLFSSL_VERSION_HEX >= 0x05006004 */ + if (setup_data->pki_key.key.pem.private_key && + setup_data->pki_key.key.pem.private_key[0]) { + if (!(wolfSSL_use_PrivateKey_file(ssl, + setup_data->pki_key.key.pem.private_key, + WOLFSSL_FILETYPE_PEM))) { + coap_log_warn("*** setup_pki_ssl: (D)TLS: %s: Unable to configure " + "Client Private Key\n", + setup_data->pki_key.key.pem.private_key); + return 0; + } + } else if (role == COAP_DTLS_ROLE_SERVER || + (setup_data->pki_key.key.pem.public_cert && + setup_data->pki_key.key.pem.public_cert[0])) { + coap_log_err("*** setup_pki_ssl: (D)TLS: No %s Private Key defined\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return 0; + } + if (setup_data->check_common_ca && setup_data->pki_key.key.pem.ca_file && + setup_data->pki_key.key.pem.ca_file[0]) { + if (!wolfSSL_CTX_load_verify_locations_ex(ctx, + setup_data->pki_key.key.pem.ca_file, + NULL, + setup_data->allow_expired_certs ? + WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY : 0)) { + coap_log_warn("Unable to install CAs (%s)\n", + setup_data->pki_key.key.pem.ca_file); + return 0; + } + } + break; + + case COAP_PKI_KEY_PEM_BUF: + if (setup_data->pki_key.key.pem_buf.public_cert && + setup_data->pki_key.key.pem_buf.public_cert_len) { +#if defined(HAVE_RPK) && LIBWOLFSSL_VERSION_HEX >= 0x05006004 + if (setup_data->is_rpk_not_cert) { + unsigned char der_buff[512]; + int ret = -1;; + char ctype[] = {WOLFSSL_CERT_TYPE_RPK}; + char stype[] = {WOLFSSL_CERT_TYPE_RPK}; + + wolfSSL_set_client_cert_type(ssl, ctype, sizeof(ctype)/sizeof(ctype[0])); + wolfSSL_set_server_cert_type(ssl, stype, sizeof(stype)/sizeof(stype[0])); + + ret = wolfSSL_PubKeyPemToDer(setup_data->pki_key.key.pem_buf.public_cert, + (int)setup_data->pki_key.key.pem_buf.public_cert_len, + der_buff, (int)sizeof(der_buff)); + if (ret <= 0) { + ret = wolfSSL_KeyPemToDer(setup_data->pki_key.key.pem_buf.public_cert, + (int)setup_data->pki_key.key.pem_buf.public_cert_len, + der_buff, (int)sizeof(der_buff), NULL); + if (ret > 0) { + coap_binary_t *spki = get_asn1_spki(der_buff, ret); + + if (!spki) { + coap_log_warn("*** setup_pki_ssl: (D)TLS: Unable to find" + "%s RPK SPKI\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + break; + } + if (!wolfSSL_use_PrivateKey_buffer(ssl, der_buff, ret, WOLFSSL_FILETYPE_ASN1)) { + coap_log_warn("*** setup_pki_ssl: (D)TLS: Unable to install " + "%s RPK PEM Private Key\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + } + if (!wolfSSL_use_certificate_buffer(ssl, spki->s, spki->length, WOLFSSL_FILETYPE_ASN1)) { + coap_log_warn("*** setup_pki_ssl: (D)TLS: Unable to install " + "%s RPK PEM Certificate\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + } + coap_delete_binary(spki); + break; + } + } + if (ret <= 0) { + coap_log_warn("*** setup_pki_ssl: (D)TLS: Unable to read " + "%s RPK PEM Certificate\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return 0; + } + if (!wolfSSL_use_certificate_buffer(ssl, der_buff, ret, WOLFSSL_FILETYPE_ASN1)) { + coap_log_warn("*** setup_pki_ssl: (D)TLS: Unable to install " + "%s RPK PEM Certificate\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + } + } else +#endif /* HAVE_RPK && LIBWOLFSSL_VERSION_HEX >= 0x05006004 */ + { + WOLFSSL_BIO *bp = wolfSSL_BIO_new_mem_buf(setup_data->pki_key.key.pem_buf.public_cert, + (int)setup_data->pki_key.key.pem_buf.public_cert_len); + WOLFSSL_X509 *cert = bp ? wolfSSL_PEM_read_bio_X509(bp, NULL, 0, NULL) : NULL; + + if (!cert || !SSL_use_certificate(ssl, cert)) { + coap_log_warn("*** setup_pki_ssl: (D)TLS: Unable to configure " + "Client PEM Certificate\n"); + if (bp) + wolfSSL_BIO_free(bp); + if (cert) + wolfSSL_X509_free(cert); + return 0; + } + if (bp) + wolfSSL_BIO_free(bp); + if (cert) + wolfSSL_X509_free(cert); + } + } else { + coap_log_err("*** setup_pki_ssl: (D)TLS: No %s Certificate defined\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return 0; + } + + if (setup_data->pki_key.key.pem_buf.private_key && + setup_data->pki_key.key.pem_buf.private_key_len) { + WOLFSSL_BIO *bp = wolfSSL_BIO_new_mem_buf(setup_data->pki_key.key.pem_buf.private_key, + (int)setup_data->pki_key.key.pem_buf.private_key_len); + WOLFSSL_EVP_PKEY *pkey = bp ? wolfSSL_PEM_read_bio_PrivateKey(bp, NULL, 0, NULL) : NULL; + + if (!pkey || !wolfSSL_use_PrivateKey(ssl, pkey)) { + coap_log_warn("*** setup_pki_ssl: (D)TLS: Unable to configure " + "%s PEM Private Key\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + if (bp) + wolfSSL_BIO_free(bp); + if (pkey) + wolfSSL_EVP_PKEY_free(pkey); + return 0; + } + if (bp) + wolfSSL_BIO_free(bp); + if (pkey) + wolfSSL_EVP_PKEY_free(pkey); + } else { + coap_log_err("*** setup_pki_ssl: (D)TLS: No %s Private Key defined\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return 0; + } + + if (setup_data->check_common_ca && setup_data->pki_key.key.pem_buf.ca_cert && + setup_data->pki_key.key.pem_buf.ca_cert_len) { + if (!wolfSSL_CTX_load_verify_buffer_ex(ctx, + setup_data->pki_key.key.pem_buf.ca_cert, + setup_data->pki_key.key.pem_buf.ca_cert_len, + SSL_FILETYPE_PEM, + 0, + setup_data->allow_expired_certs ? + WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY : 0)) { + coap_log_warn("Unable to install root CAs\n"); + return 0; + } + } + break; + + case COAP_PKI_KEY_ASN1: + if (setup_data->pki_key.key.asn1.public_cert && + setup_data->pki_key.key.asn1.public_cert_len > 0) { + if (!(wolfSSL_use_certificate_ASN1(ssl, + setup_data->pki_key.key.asn1.public_cert, + (int)setup_data->pki_key.key.asn1.public_cert_len))) { + coap_log_warn("*** setup_pki_ssl: (D)TLS: ASN1: Unable to configure " + "%s Certificate\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return 0; + } + } else if (role == COAP_DTLS_ROLE_SERVER || + (setup_data->pki_key.key.asn1.private_key && + setup_data->pki_key.key.asn1.private_key[0])) { + coap_log_err("*** setup_pki_ssl: (D)TLS: No %s Certificate defined\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return 0; + } + if (setup_data->pki_key.key.asn1.private_key && + setup_data->pki_key.key.asn1.private_key_len > 0) { + int pkey_type = map_key_type(setup_data->pki_key.key.asn1.private_key_type); + if (!(wolfSSL_use_PrivateKey_ASN1(pkey_type, ssl, + setup_data->pki_key.key.asn1.private_key, + (long)setup_data->pki_key.key.asn1.private_key_len))) { + coap_log_warn("*** setup_pki_ssl: (D)TLS: ASN1: Unable to configure " + "%s Private Key\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return 0; + } + } else if (role == COAP_DTLS_ROLE_SERVER || + (setup_data->pki_key.key.asn1.public_cert && + setup_data->pki_key.key.asn1.public_cert_len > 0)) { + coap_log_err("*** setup_pki_ssl: (D)TLS: No %s Private Key defined", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return 0; + } + if (setup_data->check_common_ca && setup_data->pki_key.key.asn1.ca_cert && + setup_data->pki_key.key.asn1.ca_cert_len > 0) { + if (!wolfSSL_CTX_load_verify_buffer_ex(ctx, + setup_data->pki_key.key.asn1.ca_cert, + setup_data->pki_key.key.asn1.ca_cert_len, + SSL_FILETYPE_PEM, + 0, + setup_data->allow_expired_certs ? + WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY : 0)) { + coap_log_warn("Unable to install CAs\n"); + return 0; + } + } + break; + case COAP_PKI_KEY_PKCS11: + /* TODO: check if this can be implemented*/ + coap_log_err("PKCS11 Support not available in wolfSSL\n"); + return 0; + default: + coap_log_err("*** setup_pki_ssl: (D)TLS: Unknown key type %d\n", + setup_data->pki_key.key_type); + return 0; + } + + if (w_context->root_ca_file || w_context->root_ca_dir) { + if (!wolfSSL_CTX_load_verify_locations_ex(ctx, + w_context->root_ca_file, + w_context->root_ca_dir, + setup_data->allow_expired_certs ? + WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY : 0)) { + coap_log_warn("Unable to install root CAs (%s/%s)\n", + w_context->root_ca_file ? w_context->root_ca_file : "NULL", + w_context->root_ca_dir ? w_context->root_ca_dir : "NULL"); + return 0; + } + wolfssl_free(w_context->root_ca_file); + w_context->root_ca_file = NULL; + wolfssl_free(w_context->root_ca_dir); + w_context->root_ca_dir = NULL; + } + return 1; +} + +static char * +get_san_or_cn_from_cert(WOLFSSL_X509 *x509) { + if (x509) { + char *cn; + int n; + WOLF_STACK_OF(WOLFSSL_GENERAL_NAME) *san_list; + char buffer[256]; + + buffer[0] = '\000'; + san_list = wolfSSL_X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL); + if (san_list) { + int san_count = wolfSSL_sk_GENERAL_NAME_num(san_list); + + for (n = 0; n < san_count; n++) { + const WOLFSSL_GENERAL_NAME *name = wolfSSL_sk_GENERAL_NAME_value(san_list, n); + + if (name->type == GEN_DNS) { + const char *dns_name = (const char *)wolfSSL_ASN1_STRING_get0_data(name->d.dNSName); + + /* Make sure that there is not an embedded NUL in the dns_name */ + if (wolfSSL_ASN1_STRING_length(name->d.dNSName) != (int)strlen(dns_name)) + continue; + cn = wolfssl_strdup(dns_name); + wolfSSL_sk_GENERAL_NAME_pop_free(san_list, wolfSSL_GENERAL_NAME_free); + return cn; + } + } + wolfSSL_sk_GENERAL_NAME_pop_free(san_list, wolfSSL_GENERAL_NAME_free); + } + /* Otherwise look for the CN= field */ + wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name((WOLFSSL_X509 *)(x509)), buffer, + sizeof(buffer)); + + /* Need to emulate strcasestr() here. Looking for CN= */ + n = (int)strlen(buffer) - 3; + cn = buffer; + while (n > 0) { + if (((cn[0] == 'C') || (cn[0] == 'c')) && + ((cn[1] == 'N') || (cn[1] == 'n')) && + (cn[2] == '=')) { + cn += 3; + break; + } + cn++; + n--; + } + if (n > 0) { + char *ecn = strchr(cn, '/'); + if (ecn) { + return wolfssl_strndup(cn, ecn-cn); + } else { + return wolfssl_strdup(cn); + } + } + } + return NULL; +} + +static int +tls_verify_call_back(int preverify_ok, WOLFSSL_X509_STORE_CTX *ctx) { + WOLFSSL *ssl = wolfSSL_X509_STORE_CTX_get_ex_data(ctx, + wolfSSL_get_ex_data_X509_STORE_CTX_idx()); + coap_session_t *session = wolfSSL_get_app_data(ssl); + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)session->context->dtls_context); + coap_dtls_pki_t *setup_data = &w_context->setup_data; + int depth = wolfSSL_X509_STORE_CTX_get_error_depth(ctx); + int err = wolfSSL_X509_STORE_CTX_get_error(ctx); + WOLFSSL_X509 *x509 = wolfSSL_X509_STORE_CTX_get_current_cert(ctx); + char *cn = NULL; + int keep_preverify_ok = preverify_ok; + + if (setup_data->is_rpk_not_cert) { + cn = wolfssl_strdup("RPK"); + } else { + cn = get_san_or_cn_from_cert(x509); + } + if (!preverify_ok) { + switch (err) { + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_CERT_HAS_EXPIRED: + case ASN_NO_SIGNER_E: + case ASN_AFTER_DATE_E: + if (setup_data->allow_expired_certs) + preverify_ok = 1; + break; + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + if (setup_data->allow_self_signed && !setup_data->check_common_ca) + preverify_ok = 1; + break; + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: /* Set if the CA is not known */ + if (!setup_data->verify_peer_cert) + preverify_ok = 1; + break; + case X509_V_ERR_UNABLE_TO_GET_CRL: + if (setup_data->allow_no_crl) + preverify_ok = 1; + break; + case X509_V_ERR_CRL_NOT_YET_VALID: + case X509_V_ERR_CRL_HAS_EXPIRED: + if (setup_data->allow_expired_crl) + preverify_ok = 1; + break; + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + case X509_V_ERR_AKID_SKID_MISMATCH: + if (!setup_data->verify_peer_cert) + preverify_ok = 1; + break; + default: + break; + } + if (setup_data->cert_chain_validation && + depth > (setup_data->cert_chain_verify_depth + 1)) { + preverify_ok = 0; + err = X509_V_ERR_CERT_CHAIN_TOO_LONG; + wolfSSL_X509_STORE_CTX_set_error(ctx, err); + } + if (!preverify_ok) { + if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) { + coap_log_warn(" %s: %s: '%s' depth=%d\n", + coap_session_str(session), + "Unknown CA", cn ? cn : "?", depth); + } else { + coap_log_warn(" %s: %s: '%s' depth=%d\n", + coap_session_str(session), + wolfSSL_X509_verify_cert_error_string(err), cn ? cn : "?", depth); + } + } else { + coap_log_info(" %s: %s: overridden: '%s' depth=%d\n", + coap_session_str(session), + wolfSSL_X509_verify_cert_error_string(err), cn ? cn : "?", depth); + } + } + /* Certificate - depth == 0 is the Client Cert */ + if (setup_data->validate_cn_call_back && keep_preverify_ok) { + int length = wolfSSL_i2d_X509(x509, NULL); + + if (length > 0) { + uint8_t *base_buf; + uint8_t *base_buf2 = base_buf = wolfssl_malloc(length); + + /* base_buf2 gets moved to the end */ + wolfSSL_i2d_X509(x509, &base_buf2); + if (!setup_data->validate_cn_call_back(cn, base_buf, length, session, + depth, preverify_ok, + setup_data->cn_call_back_arg)) { + if (depth == 0) { + wolfSSL_X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); + } else { + wolfSSL_X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_CA); + } + preverify_ok = 0; + } + wolfssl_free(base_buf); + } + } + wolfssl_free(cn); + return preverify_ok; +} + +#if COAP_SERVER_SUPPORT + +/* + * During the SSL/TLS initial negotiations, tls_server_name_call_back() is + * called so it is possible to set up an extra callback to determine whether + * this is a PKI or PSK incoming request and adjust the ciphers if necessary + * + * Set up by SSL_CTX_set_tlsext_servername_callback() in + * coap_dtls_context_set_pki() + */ +static int +tls_server_name_call_back(WOLFSSL *ssl, + int *sd COAP_UNUSED, + void *arg) { + coap_dtls_pki_t *setup_data = (coap_dtls_pki_t *)arg; + coap_session_t *session = (coap_session_t *)wolfSSL_get_app_data(ssl); + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)session->context->dtls_context); + + if (!ssl) { + return noack_return; + } + + if (setup_data->validate_sni_call_back) { + /* SNI checking requested */ + const char *sni = wolfSSL_get_servername(ssl, WOLFSSL_SNI_HOST_NAME); + coap_dtls_pki_t sni_setup_data; + coap_dtls_key_t *new_entry; + + if (!sni || !sni[0]) { + sni = ""; + } + new_entry = setup_data->validate_sni_call_back(sni, + setup_data->sni_call_back_arg); + if (!new_entry) { + return fatal_return; + } + sni_setup_data = *setup_data; + sni_setup_data.pki_key = *new_entry; + setup_pki_ssl(ssl, w_context, &sni_setup_data, COAP_DTLS_ROLE_SERVER); + } + + if (w_context->psk_pki_enabled & IS_PSK) { + wolfSSL_set_psk_server_callback(ssl, coap_dtls_psk_server_callback); + } + return SSL_TLSEXT_ERR_OK; +} + +/* + * During the SSL/TLS initial negotiations, psk_tls_server_name_call_back() is + * called to see if SNI is being used. + * + * Set up by SSL_CTX_set_tlsext_servername_callback() + * in coap_dtls_context_set_spsk() + */ +static int +psk_tls_server_name_call_back(WOLFSSL *ssl, + int *sd COAP_UNUSED, + void *arg + ) { + coap_dtls_spsk_t *setup_data = (coap_dtls_spsk_t *)arg; + coap_session_t *c_session = (coap_session_t *)wolfSSL_get_app_data(ssl); + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)c_session->context->dtls_context); + + if (!ssl) { + return noack_return; + } + + if (setup_data->validate_sni_call_back) { + /* SNI checking requested */ + const char *sni = wolfSSL_get_servername(ssl, WOLFSSL_SNI_HOST_NAME); + char lhint[COAP_DTLS_HINT_LENGTH]; + const coap_dtls_spsk_info_t *new_entry; + + if (!sni || !sni[0]) { + sni = ""; + } + new_entry = setup_data->validate_sni_call_back(sni, + c_session, + setup_data->sni_call_back_arg); + coap_session_refresh_psk_key(c_session, + &new_entry->key); + snprintf(lhint, sizeof(lhint), "%.*s", + (int)new_entry->hint.length, + new_entry->hint.s); + wolfSSL_use_psk_identity_hint(ssl, lhint); + } + + if (w_context->psk_pki_enabled & IS_PSK) { + wolfSSL_set_psk_server_callback(ssl, coap_dtls_psk_server_callback); + } + return SSL_TLSEXT_ERR_OK; +} +#endif /* COAP_SERVER_SUPPORT */ + +int +coap_dtls_context_set_pki(coap_context_t *ctx, + const coap_dtls_pki_t *setup_data, + const coap_dtls_role_t role) { + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)ctx->dtls_context); + + if (!setup_data) + return 0; + + w_context->setup_data = *setup_data; + if (!w_context->setup_data.verify_peer_cert) { + /* Needs to be clear so that no CA DNs are transmitted */ + w_context->setup_data.check_common_ca = 0; + if (w_context->setup_data.is_rpk_not_cert) { + /* Disable all of these as they cannot be checked */ + w_context->setup_data.allow_self_signed = 0; + w_context->setup_data.allow_expired_certs = 0; + w_context->setup_data.cert_chain_validation = 0; + w_context->setup_data.cert_chain_verify_depth = 0; + w_context->setup_data.check_cert_revocation = 0; + w_context->setup_data.allow_no_crl = 0; + w_context->setup_data.allow_expired_crl = 0; + w_context->setup_data.allow_bad_md_hash = 0; + w_context->setup_data.allow_short_rsa_length = 0; + } else { + /* Allow all of these but warn if issue */ + w_context->setup_data.allow_self_signed = 1; + w_context->setup_data.allow_expired_certs = 1; + w_context->setup_data.cert_chain_validation = 1; + w_context->setup_data.cert_chain_verify_depth = 10; + w_context->setup_data.check_cert_revocation = 1; + w_context->setup_data.allow_no_crl = 1; + w_context->setup_data.allow_expired_crl = 1; + w_context->setup_data.allow_bad_md_hash = 1; + w_context->setup_data.allow_short_rsa_length = 1; + } + } +#if COAP_SERVER_SUPPORT + if (role == COAP_DTLS_ROLE_SERVER) { + if (!setup_dtls_context(w_context)) + return 0; + if (w_context->dtls.ctx) { +#if defined(HAVE_RPK) && LIBWOLFSSL_VERSION_HEX >= 0x05006004 + char ctype[] = {WOLFSSL_CERT_TYPE_RPK}; + char stype[] = {WOLFSSL_CERT_TYPE_RPK}; +#endif /* HAVE_RPK && LIBWOLFSSL_VERSION_HEX >= 0x05006004 */ + + wolfSSL_CTX_set_servername_arg(w_context->dtls.ctx, + &w_context->setup_data); + wolfSSL_CTX_set_tlsext_servername_callback(w_context->dtls.ctx, + tls_server_name_call_back); + +#if defined(HAVE_RPK) && LIBWOLFSSL_VERSION_HEX >= 0x05006004 + if (w_context->setup_data.is_rpk_not_cert) { + wolfSSL_CTX_set_client_cert_type(w_context->dtls.ctx, ctype, sizeof(ctype)/sizeof(ctype[0])); + wolfSSL_CTX_set_server_cert_type(w_context->dtls.ctx, stype, sizeof(stype)/sizeof(stype[0])); + } +#endif /* HAVE_RPK && LIBWOLFSSL_VERSION_HEX >= 0x05006004 */ + } +#if !COAP_DISABLE_TCP + if (!setup_tls_context(w_context)) + return 0; + if (w_context->tls.ctx) { + wolfSSL_CTX_set_servername_arg(w_context->tls.ctx, + &w_context->setup_data); + wolfSSL_CTX_set_tlsext_servername_callback(w_context->tls.ctx, + tls_server_name_call_back); + + /* For TLS only */ + wolfSSL_CTX_set_alpn_select_cb(w_context->tls.ctx, + server_alpn_callback, NULL); + } +#endif /* !COAP_DISABLE_TCP */ + /* Certificate Revocation */ + if (w_context->setup_data.check_cert_revocation) { + WOLFSSL_X509_VERIFY_PARAM *param; + + param = wolfSSL_X509_VERIFY_PARAM_new(); + wolfSSL_X509_VERIFY_PARAM_set_flags(param, WOLFSSL_CRL_CHECK); + wolfSSL_CTX_set1_param(w_context->dtls.ctx, param); +#if !COAP_DISABLE_TCP + wolfSSL_CTX_set1_param(w_context->tls.ctx, param); +#endif /* !COAP_DISABLE_TCP */ + wolfSSL_X509_VERIFY_PARAM_free(param); + } + /* Verify Peer */ + if (w_context->setup_data.verify_peer_cert) { + wolfSSL_CTX_set_verify(w_context->dtls.ctx, + WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_CLIENT_ONCE | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, + tls_verify_call_back); +#if !COAP_DISABLE_TCP + wolfSSL_CTX_set_verify(w_context->tls.ctx, + WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_CLIENT_ONCE | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, + tls_verify_call_back); +#endif /* !COAP_DISABLE_TCP */ + } else { + wolfSSL_CTX_set_verify(w_context->dtls.ctx, + WOLFSSL_VERIFY_NONE, tls_verify_call_back); +#if !COAP_DISABLE_TCP + wolfSSL_CTX_set_verify(w_context->tls.ctx, + WOLFSSL_VERIFY_NONE, tls_verify_call_back); +#endif /* !COAP_DISABLE_TCP */ + } + + /* Check CA Chain */ + if (w_context->setup_data.cert_chain_validation) { + wolfSSL_CTX_set_verify_depth(w_context->dtls.ctx, + setup_data->cert_chain_verify_depth + 1); +#if !COAP_DISABLE_TCP + wolfSSL_CTX_set_verify_depth(w_context->tls.ctx, + setup_data->cert_chain_verify_depth + 1); +#endif /* !COAP_DISABLE_TCP */ + } + } +#else /* ! COAP_SERVER_SUPPORT */ + (void)role; +#endif /* ! COAP_SERVER_SUPPORT */ + + w_context->psk_pki_enabled |= IS_PKI; + return 1; +} + +int +coap_dtls_context_set_pki_root_cas(coap_context_t *ctx, + const char *ca_file, + const char *ca_dir) { + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)ctx->dtls_context); + + if (!w_context) { + coap_log_warn("coap_context_set_pki_root_cas: (D)TLS environment " + "not set up\n"); + return 0; + } + if (ca_file == NULL && ca_dir == NULL) { + coap_log_warn("coap_context_set_pki_root_cas: ca_file and/or ca_dir " + "not defined\n"); + return 0; + } + if (w_context->root_ca_file) { + wolfssl_free(w_context->root_ca_file); + w_context->root_ca_file = NULL; + } + if (ca_file) { + w_context->root_ca_file = wolfssl_strdup(ca_file); + } + if (w_context->root_ca_dir) { + wolfssl_free(w_context->root_ca_dir); + w_context->root_ca_dir = NULL; + } + if (ca_dir) { + w_context->root_ca_dir = wolfssl_strdup(ca_dir); + } + return 1; +} + +int +coap_dtls_context_check_keys_enabled(coap_context_t *ctx) { + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)ctx->dtls_context); + return w_context->psk_pki_enabled ? 1 : 0; +} + + +void +coap_dtls_free_context(void *handle) { + coap_wolfssl_context_t *w_context = (coap_wolfssl_context_t *)handle; + + if (!w_context) + return; + wolfssl_free(w_context->root_ca_file); + wolfssl_free(w_context->root_ca_dir); + + if (w_context->dtls.ctx) + wolfSSL_CTX_free(w_context->dtls.ctx); + if (w_context->dtls.cookie_hmac) + wolfSSL_HMAC_CTX_free(w_context->dtls.cookie_hmac); + +#if !COAP_DISABLE_TCP + if (w_context->tls.ctx) + wolfSSL_CTX_free(w_context->tls.ctx); +#endif /* !COAP_DISABLE_TCP */ + wolfssl_free(w_context); +} + +#if COAP_SERVER_SUPPORT +void * +coap_dtls_new_server_session(coap_session_t *session) { + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)session->context->dtls_context); + coap_dtls_context_t *dtls; + WOLFSSL *ssl = NULL; + int r; + const coap_bin_const_t *psk_hint; + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + coap_tick_t now; + + if (!w_env) + goto error; + + if (!setup_dtls_context(w_context)) + goto error; + dtls = &w_context->dtls; + + ssl = wolfSSL_new(dtls->ctx); + if (!ssl) { + goto error; + } + wolfSSL_set_app_data(ssl, NULL); + wolfSSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE); +#ifdef WOLFSSL_DTLS_MTU + wolfSSL_dtls_set_mtu(ssl, (long)session->mtu); +#endif /* WOLFSSL_DTLS_MTU */ + w_env->ssl = ssl; + wolfSSL_SetIOWriteCtx(ssl, w_env); + wolfSSL_SetIOReadCtx(ssl, w_env); + wolfSSL_set_app_data(ssl, session); + w_env->data.session = session; + +#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) + if (wolfSSL_send_hrr_cookie(ssl, NULL, 0) != WOLFSSL_SUCCESS) + coap_log_debug("Error: Unable to set cookie with Hello Retry Request\n"); +#endif /* WOLFSSL_DTLS13 && WOLFSSL_SEND_HRR_COOKIE */ + +#ifdef HAVE_SERVER_RENEGOTIATION_INFO + if (wolfSSL_UseSecureRenegotiation(ssl) != WOLFSSL_SUCCESS) { + coap_log_debug("Error: wolfSSL_UseSecureRenegotiation failed\n"); + } +#endif /* HAVE_SERVER_RENEGOTIATION_INFO */ + + if (w_context->psk_pki_enabled & IS_PSK) { + /* hint may get updated if/when handling SNI callback */ + psk_hint = coap_get_session_server_psk_hint(session); + if (psk_hint != NULL && psk_hint->length) { + char *hint = wolfssl_malloc(psk_hint->length + 1); + + if (hint) { + memcpy(hint, psk_hint->s, psk_hint->length); + hint[psk_hint->length] = '\000'; + wolfSSL_use_psk_identity_hint(ssl, hint); + wolfssl_free(hint); + } else { + coap_log_warn("hint malloc failure\n"); + } + } + } + +#if defined(WOLFSSL_DTLS_CH_FRAG) && defined(WOLFSSL_DTLS13) + if (wolfSSL_dtls13_allow_ch_frag(ssl, 1) != WOLFSSL_SUCCESS) { + coap_log_debug("Error: wolfSSL_dtls13_allow_ch_frag failed\n"); + } +#endif /* WOLFSSL_DTLS_CH_FRAG && WOLFSSL_DTLS13 */ + + coap_ticks(&now); + w_env->last_timeout = now; + w_env->ssl = ssl; + + r = wolfSSL_accept(ssl); + if (r == -1) { + int err = wolfSSL_get_error(ssl, r); + if (err != WOLFSSL_ERROR_WANT_READ && err != WOLFSSL_ERROR_WANT_WRITE) + r = 0; + } + + if (r == 0) { + goto error; + } + + return w_env; + +error: + if (ssl) + wolfSSL_free(ssl); + coap_dtls_free_wolfssl_env(w_env); + return NULL; +} +#endif /* COAP_SERVER_SUPPORT */ + +#if COAP_CLIENT_SUPPORT +static int +setup_client_ssl_session(coap_session_t *session, WOLFSSL *ssl) { + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)session->context->dtls_context); + + if (w_context->psk_pki_enabled & IS_PSK) { + coap_dtls_cpsk_t *setup_data = &session->cpsk_setup_data; + + if (setup_data->validate_ih_call_back) { + if (session->proto == COAP_PROTO_DTLS) { + wolfSSL_set_max_proto_version(ssl, + DTLS1_2_VERSION); + } +#if !COAP_DISABLE_TCP + else { + wolfSSL_set_max_proto_version(ssl, + TLS1_2_VERSION); + wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + } +#endif /* !COAP_DISABLE_TCP */ + coap_log_debug("CoAP Client restricted to (D)TLS1.2 with Identity Hint callback\n"); + } + set_ciphersuites(ssl, COAP_ENC_PSK); + + /* Issue SNI if requested */ + if (setup_data->client_sni && + wolfSSL_set_tlsext_host_name(ssl, setup_data->client_sni) != 1) { + coap_log_warn("wolfSSL_set_tlsext_host_name: set '%s' failed", + setup_data->client_sni); + } + wolfSSL_set_psk_client_callback(ssl, coap_dtls_psk_client_callback); + } + if (w_context->psk_pki_enabled & IS_PKI) { + coap_dtls_pki_t *setup_data = &w_context->setup_data; + + set_ciphersuites(ssl, COAP_ENC_PKI); + if (!setup_pki_ssl(ssl, w_context, setup_data, COAP_DTLS_ROLE_CLIENT)) + return 0; + /* libcoap is managing (D)TLS connection based on setup_data options */ +#if !COAP_DISABLE_TCP + if (session->proto == COAP_PROTO_TLS) + wolfSSL_set_alpn_protos(ssl, coap_alpn, sizeof(coap_alpn)); +#endif /* !COAP_DISABLE_TCP */ + + /* Issue SNI if requested */ + if (setup_data->client_sni && + wolfSSL_set_tlsext_host_name(ssl, setup_data->client_sni) != 1) { + coap_log_warn("wolfSSL_set_tlsext_host_name: set '%s' failed", + setup_data->client_sni); + } + /* Certificate Revocation */ + if (setup_data->check_cert_revocation) { + WOLFSSL_X509_VERIFY_PARAM *param; + + param = wolfSSL_X509_VERIFY_PARAM_new(); + wolfSSL_X509_VERIFY_PARAM_set_flags(param, WOLFSSL_CRL_CHECK); + WOLFSSL_CTX *ctx = wolfSSL_get_SSL_CTX(ssl); + /* TODO: we cannot set parameters at ssl level with wolfSSL, review*/ + wolfSSL_CTX_set1_param(ctx, param); + wolfSSL_X509_VERIFY_PARAM_free(param); + } + /* Verify Peer */ + if (setup_data->verify_peer_cert) + wolfSSL_set_verify(ssl, + WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_CLIENT_ONCE | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, + tls_verify_call_back); + else + wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_NONE, tls_verify_call_back); + + /* Check CA Chain */ + if (setup_data->cert_chain_validation) + wolfSSL_set_verify_depth(ssl, setup_data->cert_chain_verify_depth + 1); + + } + return 1; +} + +void * +coap_dtls_new_client_session(coap_session_t *session) { + WOLFSSL *ssl = NULL; + int r; + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)session->context->dtls_context); + coap_dtls_context_t *dtls; + coap_wolfssl_env_t *w_env = + coap_dtls_new_wolfssl_env(session, COAP_DTLS_ROLE_CLIENT); + coap_tick_t now; + + if (!w_env) + goto error; + + if (!setup_dtls_context(w_context)) + goto error; + dtls = &w_context->dtls; + + ssl = wolfSSL_new(dtls->ctx); + if (!ssl) { + goto error; + } + w_env->data.session = session; + wolfSSL_set_app_data(ssl, session); + wolfSSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE); + wolfSSL_SetIOWriteCtx(ssl, w_env); + wolfSSL_SetIOReadCtx(ssl, w_env); +#ifdef WOLFSSL_DTLS_MTU + wolfSSL_dtls_set_mtu(ssl, (long)session->mtu); +#endif /* WOLFSSL_DTLS_MTU */ + + if (!setup_client_ssl_session(session, ssl)) + goto error; +#ifdef HAVE_SERVER_RENEGOTIATION_INFO + if (wolfSSL_UseSecureRenegotiation(ssl) != WOLFSSL_SUCCESS) { + coap_log_debug("Error: wolfSSL_UseSecureRenegotiation failed\n"); + } +#endif /* HAVE_SERVER_RENEGOTIATION_INFO */ + + session->dtls_timeout_count = 0; + +#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) + wolfSSL_NoKeyShares(ssl); +#endif /* WOLFSSL_DTLS13 && WOLFSSL_SEND_HRR_COOKIE */ + r = wolfSSL_connect(ssl); + if (r == -1) { + int ret = wolfSSL_get_error(ssl, r); + if (ret != WOLFSSL_ERROR_WANT_READ && ret != WOLFSSL_ERROR_WANT_WRITE) + r = 0; + } + + if (r == 0) + goto error; + + coap_ticks(&now); + w_env->last_timeout = now; + w_env->ssl = ssl; + return w_env; + +error: + if (ssl) + wolfSSL_free(ssl); + return NULL; +} + +void +coap_dtls_session_update_mtu(coap_session_t *session) { +#ifdef WOLFSSL_DTLS_MTU + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + WOLFSSL *ssl = w_env ? w_env->ssl : NULL; + + if (ssl) + wolfSSL_dtls_set_mtu(ssl, (long)session->mtu); /* Instead of SSL_set_mtu */ +#else /* ! WOLFSSL_DTLS_MTU */ + (void)session; +#endif /* ! WOLFSSL_DTLS_MTU */ +} +#endif /* COAP_CLIENT_SUPPORT */ + +void +coap_dtls_free_session(coap_session_t *session) { + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + WOLFSSL *ssl = w_env ? w_env->ssl : NULL; + + if (ssl) { + if (!wolfSSL_SSL_in_init(ssl) && !(wolfSSL_get_shutdown(ssl) & WOLFSSL_SENT_SHUTDOWN)) { + int r = wolfSSL_shutdown(ssl); + if (r == 0) + r = wolfSSL_shutdown(ssl); + } + w_env->ssl = NULL; + wolfSSL_free(ssl); + if (session->context) + coap_handle_event(session->context, COAP_EVENT_DTLS_CLOSED, session); + } + coap_dtls_free_wolfssl_env(w_env); +} + +ssize_t +coap_dtls_send(coap_session_t *session, + const uint8_t *data, size_t data_len) { + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + WOLFSSL *ssl = w_env ? w_env->ssl : NULL; + int r; + + assert(ssl != NULL); + + session->dtls_event = -1; + coap_log_debug("* %s: dtls: sent %4d bytes\n", + coap_session_str(session), (int)data_len); + r = wolfSSL_write(ssl, data, (int)data_len); + + if (r <= 0) { + int err = wolfSSL_get_error(ssl, r); + if (err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) { + r = 0; + } else { + coap_log_warn("coap_dtls_send: cannot send PDU\n"); + if (err == WOLFSSL_ERROR_ZERO_RETURN) + session->dtls_event = COAP_EVENT_DTLS_CLOSED; + else if (err == WOLFSSL_ERROR_SSL) + session->dtls_event = COAP_EVENT_DTLS_ERROR; + r = -1; + } + } + + if (session->dtls_event >= 0) { + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) + coap_handle_event(session->context, session->dtls_event, session); + if (session->dtls_event == COAP_EVENT_DTLS_ERROR || + session->dtls_event == COAP_EVENT_DTLS_CLOSED) { + coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + r = -1; + } + } + + return r; +} + +int +coap_dtls_is_context_timeout(void) { + return 0; +} + +coap_tick_t +coap_dtls_get_context_timeout(void *dtls_context) { + (void)dtls_context; + return 0; +} + +coap_tick_t +coap_dtls_get_timeout(coap_session_t *session, coap_tick_t now) { + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + unsigned int scalar; + + if (!w_env) + return now; + + assert(session->state == COAP_SESSION_STATE_HANDSHAKE); + + scalar = 1 << w_env->retry_scalar; + if (w_env->last_timeout + COAP_DTLS_RETRANSMIT_COAP_TICKS * scalar > now) { + /* Need to indicate remaining timeout time */ + return w_env->last_timeout + COAP_DTLS_RETRANSMIT_COAP_TICKS * scalar; + } + return now; +} + +/* + * return 1 timed out + * 0 still timing out + */ +int +coap_dtls_handle_timeout(coap_session_t *session) { + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + WOLFSSL *ssl = w_env ? w_env->ssl : NULL; + + assert(ssl != NULL && session->state == COAP_SESSION_STATE_HANDSHAKE); + w_env->retry_scalar++; + if (++session->dtls_timeout_count > session->max_retransmit) { + /* Too many retries */ + coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + return 1; + } + wolfSSL_dtls_retransmit(ssl); + return 0; +} + +#if COAP_SERVER_SUPPORT + +int +coap_dtls_hello(coap_session_t *session, + const uint8_t *data, size_t data_len) { + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + coap_ssl_data_t *ssl_data; + int r; + + if (!w_env) { + w_env = coap_dtls_new_wolfssl_env(session, COAP_DTLS_ROLE_SERVER); + if (w_env) { + session->tls = w_env; + } else { + /* error should have already been reported */ + return -1; + } + } +#ifdef WOLFSSL_DTLS_MTU + coap_dtls_context_t *dtls = &((coap_wolfssl_context_t *)session->context->dtls_context)->dtls; + wolfSSL_dtls_set_mtu(dtls->ssl, (long)session->mtu); +#endif /* WOLFSSL_DTLS_MTU */ + + ssl_data = w_env ? &w_env->data : NULL; + assert(ssl_data != NULL); + + if (ssl_data->pdu_len) { + coap_log_err("** %s: Previous data not read %u bytes\n", + coap_session_str(session), ssl_data->pdu_len); + } + + ssl_data->session = session; + ssl_data->pdu = data; + ssl_data->pdu_len = (unsigned)data_len; + r=1; + + return r; +} + +#endif /* COAP_SERVER_SUPPORT */ + +int +coap_dtls_receive(coap_session_t *session, const uint8_t *data, size_t data_len) { + coap_ssl_data_t *ssl_data; + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + WOLFSSL *ssl = w_env ? w_env->ssl : NULL; + int r; + int in_init = wolfSSL_SSL_in_init(ssl); + uint8_t pdu[COAP_RXBUFFER_SIZE]; + + assert(ssl != NULL); + + ssl_data = &w_env->data; + + if (ssl_data->pdu_len) { + coap_log_err("** %s: Previous data not read %u bytes\n", + coap_session_str(session), ssl_data->pdu_len); + } + ssl_data->pdu = data; + ssl_data->pdu_len = (unsigned)data_len; + + session->dtls_event = -1; + r = wolfSSL_read(ssl, pdu, (int)sizeof(pdu)); + if (r > 0) { + coap_log_debug("* %s: dtls: recv %4d bytes\n", + coap_session_str(session), r); + r = coap_handle_dgram(session->context, session, pdu, (size_t)r); + goto finished; + } else { + int err = wolfSSL_get_error(ssl, r); + if (err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) { + if (in_init && wolfSSL_is_init_finished(ssl)) { + coap_dtls_log(COAP_LOG_INFO, "* %s: Using cipher: %s\n", + coap_session_str(session), wolfSSL_get_cipher((ssl))); + coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session); + session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); + } + r = 0; + } else if (err == APP_DATA_READY) { + r = wolfSSL_read(ssl, pdu, (int)sizeof(pdu)); + if (r > 0) { + r = coap_handle_dgram(session->context, session, pdu, (size_t)r); + goto finished; + } + session->dtls_event = COAP_EVENT_DTLS_ERROR; + r = -1; + } else { + if (err == WOLFSSL_ERROR_ZERO_RETURN) { + /* Got a close notify alert from the remote side */ + session->dtls_event = COAP_EVENT_DTLS_CLOSED; + } else { + session->dtls_event = COAP_EVENT_DTLS_ERROR; + if (err == FATAL_ERROR) { + WOLFSSL_ALERT_HISTORY h; + + if (wolfSSL_get_alert_history(ssl, &h) == WOLFSSL_SUCCESS) { + if (h.last_rx.code != close_notify && h.last_rx.code != -1) { + coap_log_warn("***%s: Alert '%d': %s\n", + coap_session_str(session), h.last_rx.code, + wolfSSL_alert_desc_string_long(h.last_rx.code)); + } + } + } + } + r = -1; + } + if (session->dtls_event >= 0) { + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) + coap_handle_event(session->context, session->dtls_event, session); + if (session->dtls_event == COAP_EVENT_DTLS_ERROR || + session->dtls_event == COAP_EVENT_DTLS_CLOSED) { + coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + ssl_data = NULL; + r = -1; + } + } + } + +finished: + if (ssl_data && ssl_data->pdu_len) { + /* pdu data is held on stack which will not stay there */ + coap_log_debug("coap_dtls_receive: ret %d: remaining data %u\n", r, ssl_data->pdu_len); + ssl_data->pdu_len = 0; + ssl_data->pdu = NULL; + } + return r; +} + +unsigned int +coap_dtls_get_overhead(coap_session_t *session) { + unsigned int overhead = 37; + const WOLFSSL_CIPHER *s_ciph = NULL; + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + WOLFSSL *ssl = w_env ? w_env->ssl : NULL; + + if (ssl != NULL) + s_ciph = wolfSSL_get_current_cipher(ssl); + if (s_ciph) { + unsigned int ivlen, maclen, blocksize = 1, pad = 0; + + const WOLFSSL_EVP_CIPHER *e_ciph; + const WOLFSSL_EVP_MD *e_md; + char cipher[128]; + + e_ciph = wolfSSL_EVP_get_cipherbynid(wolfSSL_CIPHER_get_cipher_nid(s_ciph)); + + switch (WOLFSSL_EVP_CIPHER_mode(e_ciph)) { + + case WOLFSSL_EVP_CIPH_GCM_MODE: +#ifndef WOLFSSL_EVP_GCM_TLS_EXPLICIT_IV_LEN +#define WOLFSSL_EVP_GCM_TLS_EXPLICIT_IV_LEN 8 +#endif +#ifndef WOLFSSL_EVP_GCM_TLS_TAG_LEN +#define WOLFSSL_EVP_GCM_TLS_TAG_LEN 16 +#endif + ivlen = WOLFSSL_EVP_GCM_TLS_EXPLICIT_IV_LEN; + maclen = WOLFSSL_EVP_GCM_TLS_TAG_LEN; + break; + + case WOLFSSL_EVP_CIPH_CCM_MODE: +#ifndef WOLFSSL_EVP_CCM_TLS_EXPLICIT_IV_LEN +#define WOLFSSL_EVP_CCM_TLS_EXPLICIT_IV_LEN 8 +#endif + ivlen = WOLFSSL_EVP_CCM_TLS_EXPLICIT_IV_LEN; + wolfSSL_CIPHER_description(s_ciph, cipher, sizeof(cipher)); + if (strstr(cipher, "CCM8")) + maclen = 8; + else + maclen = 16; + break; + + case WOLFSSL_EVP_CIPH_CBC_MODE: + e_md = wolfSSL_EVP_get_digestbynid(wolfSSL_CIPHER_get_digest_nid(s_ciph)); + blocksize = wolfSSL_EVP_CIPHER_block_size(e_ciph); + ivlen = wolfSSL_EVP_CIPHER_iv_length(e_ciph); + pad = 1; + maclen = wolfSSL_EVP_MD_size(e_md); + break; + + case WOLFSSL_EVP_CIPH_STREAM_CIPHER: + /* Seen with PSK-CHACHA20-POLY1305 */ + ivlen = 8; + maclen = 8; + break; + + default: + wolfSSL_CIPHER_description(s_ciph, cipher, sizeof(cipher)); + coap_log_warn("Unknown overhead for DTLS with cipher %s\n", + cipher); + ivlen = 8; + maclen = 16; + break; + } +#ifndef WOLFSSL_DTLS13_RT_HEADER_LENGTH +#define WOLFSSL_DTLS13_RT_HEADER_LENGTH 13 +#endif + overhead = WOLFSSL_DTLS13_RT_HEADER_LENGTH + ivlen + maclen + blocksize - 1 + + pad; + } + return overhead; +} + +#if !COAP_DISABLE_TCP +#if COAP_CLIENT_SUPPORT +void * +coap_tls_new_client_session(coap_session_t *session) { + WOLFSSL *ssl = NULL; + int r; + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)session->context->dtls_context); + coap_tls_context_t *tls; + coap_wolfssl_env_t *w_env = + coap_dtls_new_wolfssl_env(session, COAP_DTLS_ROLE_CLIENT); + coap_tick_t now; + + if (!w_env) + goto error; + + if (!setup_tls_context(w_context)) + goto error; + tls = &w_context->tls; + + ssl = wolfSSL_new(tls->ctx); + if (!ssl) + goto error; + wolfSSL_SetIOWriteCtx(ssl, w_env); + wolfSSL_SetIOReadCtx(ssl, w_env); + wolfSSL_set_app_data(ssl, session); + w_env->data.session = session; + + if (!setup_client_ssl_session(session, ssl)) + return 0; + + session->tls = w_env; + w_env->ssl = ssl; + r = wolfSSL_connect(ssl); + if (r == -1) { + int ret = wolfSSL_get_error(ssl, r); + if (ret != WOLFSSL_ERROR_WANT_READ && ret != WOLFSSL_ERROR_WANT_WRITE) + r = 0; + if (ret == WOLFSSL_ERROR_WANT_READ) + session->sock.flags |= COAP_SOCKET_WANT_READ; + if (ret == WOLFSSL_ERROR_WANT_WRITE) { + session->sock.flags |= COAP_SOCKET_WANT_WRITE; +#ifdef COAP_EPOLL_SUPPORT + coap_epoll_ctl_mod(&session->sock, + EPOLLOUT | + ((session->sock.flags & COAP_SOCKET_WANT_READ) ? + EPOLLIN : 0), + __func__); +#endif /* COAP_EPOLL_SUPPORT */ + } + } + + if (r == 0) + goto error; + + coap_ticks(&now); + w_env->last_timeout = now; + if (wolfSSL_is_init_finished(ssl)) { + coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session); + session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); + } + + return w_env; + +error: + coap_dtls_free_wolfssl_env(w_env); + if (ssl) + wolfSSL_free(ssl); + return NULL; +} +#endif /* COAP_CLIENT_SUPPORT */ + +#if COAP_SERVER_SUPPORT +void * +coap_tls_new_server_session(coap_session_t *session) { + WOLFSSL *ssl = NULL; + coap_wolfssl_context_t *w_context = + ((coap_wolfssl_context_t *)session->context->dtls_context); + coap_tls_context_t *tls; + int r; + const coap_bin_const_t *psk_hint; + coap_wolfssl_env_t *w_env = + coap_dtls_new_wolfssl_env(session, COAP_DTLS_ROLE_SERVER); + coap_tick_t now; + + if (!w_env) + goto error; + + if (!setup_tls_context(w_context)) + goto error; + tls = &w_context->tls; + + ssl = wolfSSL_new(tls->ctx); + if (!ssl) + goto error; + wolfSSL_SetIOWriteCtx(ssl, w_env); + wolfSSL_SetIOReadCtx(ssl, w_env); + wolfSSL_set_app_data(ssl, session); + + if (w_context->psk_pki_enabled & IS_PSK) { + psk_hint = coap_get_session_server_psk_hint(session); + if (psk_hint != NULL && psk_hint->length) { + char *hint = wolfssl_malloc(psk_hint->length + 1); + + if (hint) { + memcpy(hint, psk_hint->s, psk_hint->length); + hint[psk_hint->length] = '\000'; + wolfSSL_use_psk_identity_hint(ssl, hint); + wolfssl_free(hint); + } else { + coap_log_warn("hint malloc failure\n"); + } + } + } +#if defined(HAVE_RPK) && LIBWOLFSSL_VERSION_HEX >= 0x05006004 + if (w_context->setup_data.is_rpk_not_cert) { + char stype[] = {WOLFSSL_CERT_TYPE_RPK}; + + wolfSSL_set_server_cert_type(ssl, stype, sizeof(stype)/sizeof(stype[0])); + } +#endif /* HAVE_RPK && LIBWOLFSSL_VERSION_HEX >= 0x05006004 */ + + coap_ticks(&now); + w_env->last_timeout = now; + w_env->ssl = ssl; + w_env->data.session = session; + + wolfSSL_set_cipher_list(ssl, "ALL"); + + r = wolfSSL_accept(ssl); + if (r == -1) { + int err = wolfSSL_get_error(ssl, r); + if (err != WOLFSSL_ERROR_WANT_READ && err != WOLFSSL_ERROR_WANT_WRITE) { + r = 0; + } + if (err == WOLFSSL_ERROR_WANT_READ) { + session->sock.flags |= COAP_SOCKET_WANT_READ; + } + if (err == WOLFSSL_ERROR_WANT_WRITE) { + session->sock.flags |= COAP_SOCKET_WANT_WRITE; +#ifdef COAP_EPOLL_SUPPORT + coap_epoll_ctl_mod(&session->sock, + EPOLLOUT | + ((session->sock.flags & COAP_SOCKET_WANT_READ) ? + EPOLLIN : 0), + __func__); +#endif /* COAP_EPOLL_SUPPORT */ + } + } + + if (r == 0) + goto error; + + session->tls = w_env; + if (wolfSSL_is_init_finished(ssl)) { + coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session); + session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); + } + + return w_env; + +error: + if (ssl) + wolfSSL_free(ssl); + coap_dtls_free_wolfssl_env(w_env); + return NULL; +} +#endif /* COAP_SERVER_SUPPORT */ + +void +coap_tls_free_session(coap_session_t *session) { + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + WOLFSSL *ssl = w_env ? w_env->ssl : NULL; + + if (ssl) { + if (!wolfSSL_SSL_in_init(ssl) && !(wolfSSL_get_shutdown(ssl) & WOLFSSL_SENT_SHUTDOWN)) { + int r = wolfSSL_shutdown(ssl); + if (r == 0) + r = wolfSSL_shutdown(ssl); + } + wolfSSL_free(ssl); + w_env->ssl = NULL; + if (session->context) + coap_handle_event(session->context, COAP_EVENT_DTLS_CLOSED, session); + } + coap_dtls_free_wolfssl_env(w_env); +} + +/* + * strm + * return +ve Number of bytes written. + * -1 Error (error in errno). + */ +ssize_t +coap_tls_write(coap_session_t *session, const uint8_t *data, size_t data_len) { + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + WOLFSSL *ssl = w_env ? w_env->ssl : NULL; + int r, in_init; + + if (ssl == NULL) + return -1; + + in_init = !wolfSSL_is_init_finished(ssl); + session->dtls_event = -1; + r = wolfSSL_write(ssl, data, (int)data_len); + + if (r <= 0) { + int err = wolfSSL_get_error(ssl, r); + if (err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) { + if (in_init && wolfSSL_is_init_finished(ssl)) { + coap_dtls_log(COAP_LOG_INFO, "* %s: Using cipher: %s\n", + coap_session_str(session), wolfSSL_get_cipher((ssl))); + coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session); + session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); + } + if (err == WOLFSSL_ERROR_WANT_READ) + session->sock.flags |= COAP_SOCKET_WANT_READ; + else if (err == WOLFSSL_ERROR_WANT_WRITE) { + session->sock.flags |= COAP_SOCKET_WANT_WRITE; +#ifdef COAP_EPOLL_SUPPORT + coap_epoll_ctl_mod(&session->sock, + EPOLLOUT | + ((session->sock.flags & COAP_SOCKET_WANT_READ) ? + EPOLLIN : 0), + __func__); +#endif /* COAP_EPOLL_SUPPORT */ + } + r = 0; + } else { + coap_log_info("***%s: coap_tls_write: cannot send PDU\n", + coap_session_str(session)); + if (err == WOLFSSL_ERROR_ZERO_RETURN) + session->dtls_event = COAP_EVENT_DTLS_CLOSED; + else if (err == WOLFSSL_ERROR_SSL) + session->dtls_event = COAP_EVENT_DTLS_ERROR; + r = -1; + } + } else if (in_init && wolfSSL_is_init_finished(ssl)) { + coap_dtls_log(COAP_LOG_INFO, "* %s: Using cipher: %s\n", + coap_session_str(session), wolfSSL_get_cipher((ssl))); + coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session); + session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); + } + + if (session->dtls_event >= 0) { + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) + coap_handle_event(session->context, session->dtls_event, session); + if (session->dtls_event == COAP_EVENT_DTLS_ERROR || + session->dtls_event == COAP_EVENT_DTLS_CLOSED) { + coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + r = -1; + } + } + + if (r >= 0) { + if (r == (ssize_t)data_len) + coap_log_debug("* %s: tls: sent %4d bytes\n", + coap_session_str(session), r); + else + coap_log_debug("* %s: tls: sent %4d of %4zd bytes\n", + coap_session_str(session), r, data_len); + } + return r; +} + +/* + * strm + * return >=0 Number of bytes read. + * -1 Error (error in errno). + */ +ssize_t +coap_tls_read(coap_session_t *session, uint8_t *data, size_t data_len) { + coap_wolfssl_env_t *w_env = (coap_wolfssl_env_t *)session->tls; + WOLFSSL *ssl = w_env ? w_env->ssl : NULL; + int r, in_init; + + if (ssl == NULL) { + errno = ENXIO; + return -1; + } + + in_init = !wolfSSL_is_init_finished(ssl); + session->dtls_event = -1; + r = wolfSSL_read(ssl, data, (int)data_len); + if (r <= 0) { + int err = wolfSSL_get_error(ssl, r); + if (err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) { + if (in_init && wolfSSL_is_init_finished(ssl)) { + coap_dtls_log(COAP_LOG_INFO, "* %s: Using cipher: %s\n", + coap_session_str(session), wolfSSL_get_cipher((ssl))); + coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session); + session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); + } + if (err == WOLFSSL_ERROR_WANT_READ) + session->sock.flags |= COAP_SOCKET_WANT_READ; + if (err == WOLFSSL_ERROR_WANT_WRITE) { + session->sock.flags |= COAP_SOCKET_WANT_WRITE; +#ifdef COAP_EPOLL_SUPPORT + coap_epoll_ctl_mod(&session->sock, + EPOLLOUT | + ((session->sock.flags & COAP_SOCKET_WANT_READ) ? + EPOLLIN : 0), + __func__); +#endif /* COAP_EPOLL_SUPPORT */ + } + r = 0; + } else { + if (err == WOLFSSL_ERROR_ZERO_RETURN) { + /* Got a close notify alert from the remote side */ + session->dtls_event = COAP_EVENT_DTLS_CLOSED; + } else if (err == WOLFSSL_ERROR_SSL) { + session->dtls_event = COAP_EVENT_DTLS_ERROR; + } else if (err == FATAL_ERROR) { + WOLFSSL_ALERT_HISTORY h; + + session->dtls_event = COAP_EVENT_DTLS_ERROR; + if (wolfSSL_get_alert_history(ssl, &h) == WOLFSSL_SUCCESS) { + if (h.last_rx.code != close_notify && h.last_rx.code != -1) { + coap_log_warn("***%s: Alert '%d': %s\n", + coap_session_str(session), h.last_rx.code, + wolfSSL_alert_desc_string_long(h.last_rx.code)); + } + } + } + r = -1; + } + } else if (in_init && wolfSSL_is_init_finished(ssl)) { + coap_dtls_log(COAP_LOG_INFO, "* %s: Using cipher: %s\n", + coap_session_str(session), wolfSSL_get_cipher((ssl))); + coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session); + session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); + } + + if (session->dtls_event >= 0) { + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) + coap_handle_event(session->context, session->dtls_event, session); + if (session->dtls_event == COAP_EVENT_DTLS_ERROR || + session->dtls_event == COAP_EVENT_DTLS_CLOSED) { + coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + r = -1; + } + } + + if (r > 0) { + coap_log_debug("* %s: tls: recv %4d bytes\n", + coap_session_str(session), r); + } + return r; +} +#endif /* !COAP_DISABLE_TCP */ + +#if COAP_SERVER_SUPPORT +coap_digest_ctx_t * +coap_digest_setup(void) { + WOLFSSL_EVP_MD_CTX *digest_ctx = wolfSSL_EVP_MD_CTX_new(); + + if (digest_ctx) { + wolfSSL_EVP_DigestInit_ex(digest_ctx, wolfSSL_EVP_sha256(), NULL); + } + return digest_ctx; +} + +void +coap_digest_free(coap_digest_ctx_t *digest_ctx) { + wolfSSL_EVP_MD_CTX_free(digest_ctx); +} + +int +coap_digest_update(coap_digest_ctx_t *digest_ctx, + const uint8_t *data, + size_t data_len) { + return wolfSSL_EVP_DigestUpdate(digest_ctx, data, data_len); +} + +int +coap_digest_final(coap_digest_ctx_t *digest_ctx, + coap_digest_t *digest_buffer) { + unsigned int size = sizeof(coap_digest_t); + int ret = wolfSSL_EVP_DigestFinal_ex(digest_ctx, (uint8_t *)digest_buffer, &size); + + coap_digest_free(digest_ctx); + return ret; +} +#endif /* COAP_SERVER_SUPPORT */ + +#if COAP_WS_SUPPORT || COAP_OSCORE_SUPPORT +static void +coap_crypto_output_errors(const char *prefix) { +#if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_WARN + (void)prefix; +#else /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_WARN */ + unsigned long e; + + while ((e = wolfSSL_ERR_get_error())) + coap_log_warn("%s: %s%s\n", + prefix, + wolfSSL_ERR_reason_error_string(e), + ssl_function_definition(e)); +#endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_WARN */ +} +#endif /* COAP_WS_SUPPORT || COAP_OSCORE_SUPPORT */ + +#if COAP_WS_SUPPORT +/* + * The struct hash_algs and the function get_hash_alg() are used to + * determine which hash type to use for creating the required hash object. + */ +static struct hash_algs { + cose_alg_t alg; + const WOLFSSL_EVP_MD *(*get_hash)(void); + size_t length; /* in bytes */ +} hashs[] = { + {COSE_ALGORITHM_SHA_1, wolfSSL_EVP_sha1, 20}, + {COSE_ALGORITHM_SHA_256_64, wolfSSL_EVP_sha256, 8}, + {COSE_ALGORITHM_SHA_256_256, wolfSSL_EVP_sha256, 32}, + {COSE_ALGORITHM_SHA_512, wolfSSL_EVP_sha512, 64}, +}; + +static const WOLFSSL_EVP_MD * +get_hash_alg(cose_alg_t alg, size_t *length) { + size_t idx; + + for (idx = 0; idx < sizeof(hashs) / sizeof(struct hash_algs); idx++) { + if (hashs[idx].alg == alg) { + *length = hashs[idx].length; + return hashs[idx].get_hash(); + } + } + coap_log_debug("get_hash_alg: COSE hash %d not supported\n", alg); + return NULL; +} + +int +coap_crypto_hash(cose_alg_t alg, + const coap_bin_const_t *data, + coap_bin_const_t **hash) { + unsigned int length; + const WOLFSSL_EVP_MD *evp_md; + WOLFSSL_EVP_MD_CTX *evp_ctx = NULL; + coap_binary_t *dummy = NULL; + size_t hash_length; + + if ((evp_md = get_hash_alg(alg, &hash_length)) == NULL) { + coap_log_debug("coap_crypto_hash: algorithm %d not supported\n", alg); + return 0; + } + evp_ctx = wolfSSL_EVP_MD_CTX_new(); + if (evp_ctx == NULL) + goto error; + if (wolfSSL_EVP_DigestInit_ex(evp_ctx, evp_md, NULL) == 0) + goto error; + ; + if (wolfSSL_EVP_DigestUpdate(evp_ctx, data->s, data->length) == 0) + goto error; + ; + dummy = coap_new_binary(EVP_MAX_MD_SIZE); + if (dummy == NULL) + goto error; + if (wolfSSL_EVP_DigestFinal_ex(evp_ctx, dummy->s, &length) == 0) + goto error; + dummy->length = length; + if (hash_length < dummy->length) + dummy->length = hash_length; + *hash = (coap_bin_const_t *)(dummy); + wolfSSL_EVP_MD_CTX_free(evp_ctx); + return 1; + +error: + coap_crypto_output_errors("coap_crypto_hash"); + coap_delete_binary(dummy); + if (evp_ctx) + wolfSSL_EVP_MD_CTX_free(evp_ctx); + return 0; +} +#endif /* COAP_WS_SUPPORT */ + +#if COAP_OSCORE_SUPPORT +#if LIBWOLFSSL_VERSION_HEX < 0x05006000 +static const WOLFSSL_EVP_CIPHER * +EVP_aes_128_ccm(void) { + return "AES-128-CCM"; +} + +static const WOLFSSL_EVP_CIPHER * +EVP_aes_256_ccm(void) { + return "AES-256-CCM"; +} +#endif /* LIBWOLFSSL_VERSION_HEX < 0x05006000 */ + +int +coap_oscore_is_supported(void) { + return 1; +} + +/* + * The struct cipher_algs and the function get_cipher_alg() are used to + * determine which cipher type to use for creating the required cipher + * suite object. + */ +static struct cipher_algs { + cose_alg_t alg; + const WOLFSSL_EVP_CIPHER *(*get_cipher)(void); +} ciphers[] = {{COSE_ALGORITHM_AES_CCM_16_64_128, EVP_aes_128_ccm}, + {COSE_ALGORITHM_AES_CCM_16_64_256, EVP_aes_256_ccm} +}; + +static const WOLFSSL_EVP_CIPHER * +get_cipher_alg(cose_alg_t alg) { + size_t idx; + + for (idx = 0; idx < sizeof(ciphers) / sizeof(struct cipher_algs); idx++) { + if (ciphers[idx].alg == alg) + return ciphers[idx].get_cipher(); + } + coap_log_debug("get_cipher_alg: COSE cipher %d not supported\n", alg); + return NULL; +} + +/* + * The struct hmac_algs and the function get_hmac_alg() are used to + * determine which hmac type to use for creating the required hmac + * suite object. + */ +static struct hmac_algs { + cose_hmac_alg_t hmac_alg; + const WOLFSSL_EVP_MD *(*get_hmac)(void); +} hmacs[] = { + {COSE_HMAC_ALG_HMAC256_256, wolfSSL_EVP_sha256}, + {COSE_HMAC_ALG_HMAC384_384, wolfSSL_EVP_sha384}, + {COSE_HMAC_ALG_HMAC512_512, wolfSSL_EVP_sha512}, +}; + +static const WOLFSSL_EVP_MD * +get_hmac_alg(cose_hmac_alg_t hmac_alg) { + size_t idx; + + for (idx = 0; idx < sizeof(hmacs) / sizeof(struct hmac_algs); idx++) { + if (hmacs[idx].hmac_alg == hmac_alg) + return hmacs[idx].get_hmac(); + } + coap_log_debug("get_hmac_alg: COSE HMAC %d not supported\n", hmac_alg); + return NULL; +} + +int +coap_crypto_check_cipher_alg(cose_alg_t alg) { + return get_cipher_alg(alg) != NULL; +} + +int +coap_crypto_check_hkdf_alg(cose_hkdf_alg_t hkdf_alg) { + cose_hmac_alg_t hmac_alg; + + if (!cose_get_hmac_alg_for_hkdf(hkdf_alg, &hmac_alg)) + return 0; + return get_hmac_alg(hmac_alg) != NULL; +} + +#define C(Func) \ + if (1 != (Func)) { \ + goto error; \ + } + +int +coap_crypto_aead_encrypt(const coap_crypto_param_t *params, + coap_bin_const_t *data, + coap_bin_const_t *aad, + uint8_t *result, + size_t *max_result_len) { + + Aes aes; + int ret; + int result_len; + int nonce_length; + byte *authTag = NULL; + const coap_crypto_aes_ccm_t *ccm; + + if (data == NULL) + return 0; + + assert(params != NULL); + if (!params) + return 0; + + ccm = ¶ms->params.aes; + + if (ccm->key.s == NULL || ccm->nonce == NULL) + goto error; + + result_len = data->length; + nonce_length = 15 - ccm->l; + + memset(&aes, 0, sizeof(aes)); + ret = wc_AesCcmSetKey(&aes, ccm->key.s, ccm->key.length); + if (ret != 0) + goto error; + + authTag = (byte *)malloc(ccm->tag_len * sizeof(byte)); + if (!authTag) { + goto error; + } + ret = wc_AesCcmEncrypt(&aes, result, data->s, data->length, ccm->nonce, + nonce_length, authTag, ccm->tag_len, + aad->s, aad->length); + + if (ret != 0) { + wolfssl_free(authTag); + goto error; + } + + memcpy(result + result_len, authTag, ccm->tag_len); + result_len += sizeof(authTag); + *max_result_len = result_len; + wolfssl_free(authTag); + + return 1; +error: + coap_crypto_output_errors("coap_crypto_aead_encrypt"); + return 0; +} + + +int +coap_crypto_aead_decrypt(const coap_crypto_param_t *params, + coap_bin_const_t *data, + coap_bin_const_t *aad, + uint8_t *result, + size_t *max_result_len) { + + Aes aes; + int ret; + int len; + const coap_crypto_aes_ccm_t *ccm; + + if (data == NULL) + return 0; + + if (data == NULL) + return 0; + + assert(params != NULL); + if (!params) + return 0; + + ccm = ¶ms->params.aes; + byte authTag[ccm->tag_len]; + + if (data->length < ccm->tag_len) { + return 0; + } else { + memcpy(authTag, data->s + data->length - ccm->tag_len, sizeof(authTag)); + data->length -= ccm->tag_len; + } + + if (ccm->key.s == NULL || ccm->nonce == NULL) + goto error; + + memset(&aes, 0, sizeof(aes)); + ret = wc_AesCcmSetKey(&aes, ccm->key.s, ccm->key.length); + if (ret != 0) + goto error; + + len = data->length; + + ret = wc_AesCcmDecrypt(&aes, result, data->s, len, ccm->nonce, + 15 - ccm->l, authTag, sizeof(authTag), + aad->s, aad->length); + + if (ret != 0) + goto error; + + *max_result_len = len; + + return 1; +error: + coap_crypto_output_errors("coap_crypto_aead_decrypt"); + return 0; +} + +int +coap_crypto_hmac(cose_hmac_alg_t hmac_alg, + coap_bin_const_t *key, + coap_bin_const_t *data, + coap_bin_const_t **hmac) { + unsigned int result_len; + const WOLFSSL_EVP_MD *evp_md; + coap_binary_t *dummy = NULL; + + assert(key); + assert(data); + assert(hmac); + + if ((evp_md = get_hmac_alg(hmac_alg)) == 0) { + coap_log_debug("coap_crypto_hmac: algorithm %d not supported\n", hmac_alg); + return 0; + } + dummy = coap_new_binary(EVP_MAX_MD_SIZE); + if (dummy == NULL) + return 0; + result_len = (unsigned int)dummy->length; + if (wolfSSL_HMAC(evp_md, + key->s, + (int)key->length, + data->s, + (int)data->length, + dummy->s, + &result_len)) { + dummy->length = result_len; + *hmac = (coap_bin_const_t *)dummy; + return 1; + } + + coap_crypto_output_errors("coap_crypto_hmac"); + return 0; +} + +#endif /* COAP_OSCORE_SUPPORT */ + +#else /* !COAP_WITH_LIBWOLFSSL */ + +#ifdef __clang__ +/* Make compilers happy that do not like empty modules. As this function is + * never used, we ignore -Wunused-function at the end of compiling this file + */ +#pragma GCC diagnostic ignored "-Wunused-function" +#endif +static inline void +dummy(void) { +} + +#endif /* COAP_WITH_LIBWOLFSSL */ diff --git a/tests/test_tls.c b/tests/test_tls.c index 411446f5ea..759eb1ba87 100644 --- a/tests/test_tls.c +++ b/tests/test_tls.c @@ -34,6 +34,12 @@ #include #endif /* COAP_WITH_LIBOPENSSL */ +#ifdef COAP_WITH_LIBWOLFSSL +#define HAVE_DTLS 1 +#include +#include +#endif /* COAP_WITH_LIBWOLFSSL */ + #ifdef COAP_WITH_LIBGNUTLS #define HAVE_DTLS 1 #include @@ -64,6 +70,9 @@ t_tls2(void) { #if defined(COAP_WITH_LIBOPENSSL) version.version = SSLeay(); version.type = COAP_TLS_LIBRARY_OPENSSL; +#elif defined(COAP_WITH_LIBWOLFSSL) + version.version = wolfSSL_lib_version_hex(); + version.type = COAP_TLS_LIBRARY_WOLFSSL; #elif defined(COAP_WITH_LIBTINYDTLS) const char *vers = dtls_package_version(); version.version = 0; diff --git a/win32/libcoap.vcxproj b/win32/libcoap.vcxproj index ecf4a11829..ddd0245bc2 100644 --- a/win32/libcoap.vcxproj +++ b/win32/libcoap.vcxproj @@ -71,6 +71,7 @@ + diff --git a/win32/libcoap.vcxproj.filters b/win32/libcoap.vcxproj.filters index f7765bed70..28bb2bc655 100644 --- a/win32/libcoap.vcxproj.filters +++ b/win32/libcoap.vcxproj.filters @@ -107,6 +107,9 @@ Source Files + + Source Files + Source Files