diff --git a/CMakeLists.txt b/CMakeLists.txt index 1148e8ed7..283fba598 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ ENDIF() ## build options SET(PAHO_WITH_SSL FALSE CACHE BOOL "Flag that defines whether to build ssl-enabled binaries too. ") +SET(PAHO_WITH_LIBRESSL FALSE CACHE BOOL "Flag that defines whether to build ssl-enabled binaries with LibreSSL instead of OpenSSL. ") SET(PAHO_WITH_LIBUUID FALSE CACHE BOOL "Flag that defines whether libuuid or a custom uuid implementation should be used") SET(PAHO_BUILD_SHARED TRUE CACHE BOOL "Build shared library") SET(PAHO_BUILD_STATIC FALSE CACHE BOOL "Build static library") diff --git a/cmake/modules/FindLibreSSL.cmake b/cmake/modules/FindLibreSSL.cmake new file mode 100644 index 000000000..d19465e32 --- /dev/null +++ b/cmake/modules/FindLibreSSL.cmake @@ -0,0 +1,227 @@ +#[=======================================================================[ + +Copyright (c) 2019 John Norrbin + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +FindLibreSSL +------------ + +Find the LibreSSL encryption library. + +Optional Components +^^^^^^^^^^^^^^^^^^^ + +This module supports two optional components: SSL and TLS. Both +components have associated imported targets, as described below. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module defines the following imported targets: + +LibreSSL::Crypto + The LibreSSL crypto library, if found. + +LibreSSL::SSL + The LibreSSL ssl library, if found. Requires and includes LibreSSL::Crypto automatically. + +LibreSSL::TLS + The LibreSSL tls library, if found. Requires and includes LibreSSL::SSL and LibreSSL::Crypto automatically. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module will set the following variables in your project: + +LIBRESSL_FOUND + System has the LibreSSL library. If no components are requested it only requires the crypto library. +LIBRESSL_INCLUDE_DIR + The LibreSSL include directory. +LIBRESSL_CRYPTO_LIBRARY + The LibreSSL crypto library. +LIBRESSL_SSL_LIBRARY + The LibreSSL SSL library. +LIBRESSL_TLS_LIBRARY + The LibreSSL TLS library. +LIBRESSL_LIBRARIES + All LibreSSL libraries. +LIBRESSL_VERSION + This is set to $major.$minor.$revision (e.g. 2.6.8). + +Hints +^^^^^ + +Set LIBRESSL_ROOT_DIR to the root directory of an LibreSSL installation. + +]=======================================================================] + +INCLUDE(FindPackageHandleStandardArgs) + +# Set Hints +set(_LIBRESSL_ROOT_HINTS + ${LIBRESSL_ROOT_DIR} + ENV LIBRESSL_ROOT_DIR +) + +# Set Paths +if (WIN32) + file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) + set(_LIBRESSL_ROOT_PATHS + "${_programfiles}/LibreSSL" + ) + unset(_programfiles) +else() + set(_LIBRESSL_ROOT_PATHS + "/usr/local/" + ) +endif() + +# Combine +set(_LIBRESSL_ROOT_HINTS_AND_PATHS + HINTS ${_LIBRESSL_ROOT_HINTS} + PATHS ${_LIBRESSL_ROOT_PATHS} +) + +# Find Include Path +find_path(LIBRESSL_INCLUDE_DIR + NAMES + tls.h + ${_LIBRESSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + include +) + +# Find Crypto Library +find_library(LIBRESSL_CRYPTO_LIBRARY + NAMES + libcrypto + crypto + NAMES_PER_DIR + ${_LIBRESSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + lib +) + +# Find SSL Library +find_library(LIBRESSL_SSL_LIBRARY + NAMES + libssl + ssl + NAMES_PER_DIR + ${_LIBRESSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + lib +) + +# Find TLS Library +find_library(LIBRESSL_TLS_LIBRARY + NAMES + libtls + tls + NAMES_PER_DIR + ${_LIBRESSL_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + lib +) + +# Set Libraries +set(LIBRESSL_LIBRARIES ${LIBRESSL_CRYPTO_LIBRARY} ${LIBRESSL_SSL_LIBRARY} ${LIBRESSL_TLS_LIBRARY}) + +# Mark Variables As Advanced +mark_as_advanced(LIBRESSL_INCLUDE_DIR LIBRESSL_LIBRARIES LIBRESSL_CRYPTO_LIBRARY LIBRESSL_SSL_LIBRARY LIBRESSL_TLS_LIBRARY) + +# Find Version File +if(LIBRESSL_INCLUDE_DIR AND EXISTS "${LIBRESSL_INCLUDE_DIR}/openssl/opensslv.h") + + # Get Version From File + file(STRINGS "${LIBRESSL_INCLUDE_DIR}/openssl/opensslv.h" OPENSSLV.H REGEX "#define LIBRESSL_VERSION_TEXT[ ]+\".*\"") + + # Match Version String + string(REGEX REPLACE ".*\".*([0-9]+)\\.([0-9]+)\\.([0-9]+)\"" "\\1;\\2;\\3" LIBRESSL_VERSION_LIST "${OPENSSLV.H}") + + # Split Parts + list(GET LIBRESSL_VERSION_LIST 0 LIBRESSL_VERSION_MAJOR) + list(GET LIBRESSL_VERSION_LIST 1 LIBRESSL_VERSION_MINOR) + list(GET LIBRESSL_VERSION_LIST 2 LIBRESSL_VERSION_REVISION) + + # Set Version String + set(LIBRESSL_VERSION "${LIBRESSL_VERSION_MAJOR}.${LIBRESSL_VERSION_MINOR}.${LIBRESSL_VERSION_REVISION}") + +endif() + +# Set Find Package Arguments +find_package_handle_standard_args(LibreSSL + REQUIRED_VARS + LIBRESSL_CRYPTO_LIBRARY + LIBRESSL_INCLUDE_DIR + VERSION_VAR + LIBRESSL_VERSION + HANDLE_COMPONENTS + FAIL_MESSAGE + "Could NOT find LibreSSL, try setting the path to LibreSSL using the LIBRESSL_ROOT_DIR environment variable" +) + +# LibreSSL Found +if(LIBRESSL_FOUND) + + # Set LibreSSL::Crypto + if(NOT TARGET LibreSSL::Crypto AND EXISTS "${LIBRESSL_CRYPTO_LIBRARY}") + + # Add Library + add_library(LibreSSL::Crypto UNKNOWN IMPORTED) + + # Set Properties + set_target_properties( + LibreSSL::Crypto + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${LIBRESSL_INCLUDE_DIR}" + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${LIBRESSL_CRYPTO_LIBRARY}" + ) + + endif() # LibreSSL::Crypto + + # Set LibreSSL::SSL + if(NOT TARGET LibreSSL::SSL AND EXISTS "${LIBRESSL_SSL_LIBRARY}") + + # Add Library + add_library(LibreSSL::SSL UNKNOWN IMPORTED) + + # Set Properties + set_target_properties( + LibreSSL::SSL + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${LIBRESSL_INCLUDE_DIR}" + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${LIBRESSL_SSL_LIBRARY}" + INTERFACE_LINK_LIBRARIES LibreSSL::Crypto + ) + + endif() # LibreSSL::SSL + + # Set LibreSSL::TLS + if(NOT TARGET LibreSSL::TLS AND EXISTS "${LIBRESSL_TLS_LIBRARY}") + add_library(LibreSSL::TLS UNKNOWN IMPORTED) + set_target_properties( + LibreSSL::TLS + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${LIBRESSL_INCLUDE_DIR}" + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${LIBRESSL_TLS_LIBRARY}" + INTERFACE_LINK_LIBRARIES LibreSSL::SSL + ) + + endif() # LibreSSL::TLS + +endif(LIBRESSL_FOUND) \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0f795b9a4..4a6e275d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,7 +58,11 @@ IF (NOT PAHO_HIGH_PERFORMANCE) ENDIF() IF (WIN32) - SET(LIBS_SYSTEM ws2_32 crypt32 RpcRT4) + IF (PAHO_WITH_LIBRESSL) + SET(LIBS_SYSTEM ws2_32 crypt32 RpcRT4 bcrypt) + ELSE() + SET(LIBS_SYSTEM ws2_32 crypt32 RpcRT4) + ENDIF() ELSEIF (UNIX) IF(CMAKE_SYSTEM_NAME MATCHES "Linux") SET(LIBS_SYSTEM c dl pthread rt) @@ -189,15 +193,28 @@ ENDIF() INSTALL(FILES MQTTAsync.h MQTTClient.h MQTTClientPersistence.h MQTTProperties.h MQTTReasonCodes.h MQTTSubscribeOpts.h MQTTExportDeclarations.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -IF (PAHO_WITH_SSL) - SET(OPENSSL_ROOT_DIR "" CACHE PATH "Directory containing OpenSSL libraries and includes") - find_package(OpenSSL REQUIRED) +IF (PAHO_WITH_SSL OR PAHO_WITH_LIBRESSL) + + IF (PAHO_WITH_LIBRESSL) + SET(OPENSSL_ROOT_DIR "" CACHE PATH "Directory containing LibreSSL libraries and includes") + find_package(LibreSSL REQUIRED) + SET(SSL_INCLUDE_DIR ${LIBRESSL_INCLUDE_DIR} CACHE PATH "Directory containing SSL includes") + SET(SSL_LIBRARY_NAME LibreSSL CACHE STRING "Name of the used SSL library") + ELSE() + SET(LIBRESSL_ROOT_DIR "" CACHE PATH "Directory containing OpenSSL libraries and includes") + find_package(OpenSSL REQUIRED) + SET(SSL_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR} CACHE PATH "Directory containing SSL includes") + SET(SSL_LIBRARY_NAME OpenSSL CACHE STRING "Name of the used SSL library") + ENDIF() + message("Use ${SSL_LIBRARY_NAME} at ${LIBRESSL_ROOT_DIR}") + message("SSL_INCLUDE_DIR: ${SSL_INCLUDE_DIR} ${LIBRESSL_SSL_LIBRARY} ${LIBRESSL_CRYPTO_LIBRARY}") + IF (PAHO_BUILD_SHARED) ## common compilation for libpaho-mqtt3cs and libpaho-mqtt3as ## Note: SSL libraries must be recompiled due ifdefs ADD_LIBRARY(common_ssl_obj OBJECT ${common_src}) - TARGET_INCLUDE_DIRECTORIES(common_ssl_obj PUBLIC ${OPENSSL_INCLUDE_DIR}) + TARGET_INCLUDE_DIRECTORIES(common_ssl_obj PUBLIC ${SSL_INCLUDE_DIR}) SET_PROPERTY(TARGET common_ssl_obj PROPERTY POSITION_INDEPENDENT_CODE ON) SET_PROPERTY(TARGET common_ssl_obj PROPERTY COMPILE_DEFINITIONS "OPENSSL=1;PAHO_MQTT_EXPORTS=1") @@ -236,7 +253,7 @@ IF (PAHO_WITH_SSL) ${CMAKE_BINARY_DIR}) TARGET_LINK_LIBRARIES(${TARGET} PUBLIC - OpenSSL::SSL OpenSSL::Crypto ${LIBS_SYSTEM}) + ${SSL_LIBRARY_NAME}::SSL ${SSL_LIBRARY_NAME}::Crypto ${LIBS_SYSTEM}) ENDFOREACH() INSTALL(TARGETS paho-mqtt3cs paho-mqtt3as EXPORT eclipse-paho-mqtt-cTargets @@ -249,7 +266,7 @@ IF (PAHO_WITH_SSL) ## common compilation for libpaho-mqtt3cs and libpaho-mqtt3as ## Note: SSL libraries must be recompiled due ifdefs ADD_LIBRARY(common_ssl_obj_static OBJECT ${common_src}) - TARGET_INCLUDE_DIRECTORIES(common_ssl_obj_static PUBLIC ${OPENSSL_INCLUDE_DIR}) + TARGET_INCLUDE_DIRECTORIES(common_ssl_obj_static PUBLIC ${SSL_INCLUDE_DIR}) SET_PROPERTY(TARGET common_ssl_obj_static PROPERTY POSITION_INDEPENDENT_CODE ON) SET_PROPERTY(TARGET common_ssl_obj_static PROPERTY COMPILE_DEFINITIONS "OPENSSL=1;PAHO_MQTT_STATIC=1") @@ -302,7 +319,7 @@ IF (PAHO_WITH_SSL) ${CMAKE_BINARY_DIR}) TARGET_LINK_LIBRARIES(${TARGET} PUBLIC - OpenSSL::SSL OpenSSL::Crypto ${LIBS_SYSTEM}) + ${SSL_LIBRARY_NAME}::SSL ${SSL_LIBRARY_NAME}::Crypto ${LIBS_SYSTEM}) ENDFOREACH() ENDIF() ENDIF() @@ -323,17 +340,17 @@ INSTALL(FILES # Base64 test ADD_EXECUTABLE( Base64Test EXCLUDE_FROM_ALL Base64.c Base64.h ) TARGET_COMPILE_DEFINITIONS( Base64Test PUBLIC "-DBASE64_TEST" ) -IF (PAHO_WITH_SSL) +IF (PAHO_WITH_SSL OR PAHO_WITH_LIBRESSL) ADD_EXECUTABLE( Base64TestOpenSSL EXCLUDE_FROM_ALL Base64.c Base64.h ) - TARGET_LINK_LIBRARIES( Base64TestOpenSSL OpenSSL::SSL OpenSSL::Crypto) + TARGET_LINK_LIBRARIES( Base64TestOpenSSL ${SSL_LIBRARY_NAME}::SSL ${SSL_LIBRARY_NAME}::Crypto) TARGET_COMPILE_DEFINITIONS( Base64TestOpenSSL PUBLIC "-DBASE64_TEST -DOPENSSL=1" ) -ENDIF (PAHO_WITH_SSL) +ENDIF () # SHA1 test ADD_EXECUTABLE( Sha1Test EXCLUDE_FROM_ALL SHA1.c SHA1.h ) TARGET_COMPILE_DEFINITIONS( Sha1Test PUBLIC "-DSHA1_TEST" ) -IF (PAHO_WITH_SSL) +IF (PAHO_WITH_SSL OR PAHO_WITH_LIBRESSL) ADD_EXECUTABLE( Sha1TestOpenSSL EXCLUDE_FROM_ALL SHA1.c SHA1.h ) - TARGET_LINK_LIBRARIES( Sha1TestOpenSSL OpenSSL::SSL OpenSSL::Crypto) + TARGET_LINK_LIBRARIES( Sha1TestOpenSSL ${SSL_LIBRARY_NAME}::SSL ${SSL_LIBRARY_NAME}::Crypto) TARGET_COMPILE_DEFINITIONS( Sha1TestOpenSSL PUBLIC "-DSHA1_TEST -DOPENSSL=1" ) -ENDIF (PAHO_WITH_SSL) +ENDIF () diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 6d9330403..29117fccc 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -37,6 +37,11 @@ #include "WebSocket.h" #include "Proxy.h" +#if defined(OPENSSL) && defined(LIBRESSL_VERSION_NUMBER) + #include +#endif + + static int clientSockCompare(void* a, void* b); static int MQTTAsync_checkConn(MQTTAsync_command* command, MQTTAsyncs* client, int was_connected); #if !defined(NO_PERSISTENCE) @@ -1821,7 +1826,7 @@ thread_return_type WINAPI MQTTAsync_sendThread(void* n) MQTTAsync_unlock_mutex(mqttasync_mutex); #if defined(OPENSSL) -#if OPENSSL_VERSION_NUMBER < 0x1010000fL +#if ((OPENSSL_VERSION_NUMBER < 0x1010000fL) || defined(LIBRESSL_VERSION_NUMBER)) ERR_remove_state(0); #else OPENSSL_thread_stop(); @@ -2330,7 +2335,7 @@ thread_return_type WINAPI MQTTAsync_receiveThread(void* n) #endif #if defined(OPENSSL) -#if OPENSSL_VERSION_NUMBER < 0x1010000fL +#if ((OPENSSL_VERSION_NUMBER < 0x1010000fL) || defined(LIBRESSL_VERSION_NUMBER)) ERR_remove_state(0); #else OPENSSL_thread_stop(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b380e8f18..3d4aa9589 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -417,7 +417,7 @@ IF (PAHO_BUILD_SHARED) ENDIF() -IF (PAHO_WITH_SSL) +IF (PAHO_WITH_SSL OR PAHO_WITH_LIBRESSL) IF (PAHO_BUILD_STATIC) ADD_EXECUTABLE( @@ -931,7 +931,7 @@ IF (PAHO_BUILD_SHARED) ) ENDIF() -IF (PAHO_WITH_SSL) +IF (PAHO_WITH_SSL OR PAHO_WITH_LIBRESSL) IF (PAHO_BUILD_STATIC) ADD_EXECUTABLE( test5-static