Optionally use OpenSSL or LibreSSL instead of bundled crypto-algorithms
crypto-algorithms "have no resistence to side-channel attacks and should not be used in contexts that need cryptographically secure implementations" (see lib/crypto-algorithms/README.md), so using OpenSSL or LibreSSL is preferable. This does solve https://github.com/matrix-org/olm/issues/3 for some platforms, without breaking other platforms without these libraries (like web). Signed-off-by: Lukas Lihotzki <lukas@lihotzki.de>
This commit is contained in:
parent
797183f27f
commit
c7039f5e99
3 changed files with 328 additions and 2 deletions
|
@ -4,6 +4,8 @@ project(olm VERSION 3.2.8 LANGUAGES CXX C)
|
|||
|
||||
option(OLM_TESTS "Build tests" ON)
|
||||
option(BUILD_SHARED_LIBS "Build as a shared library" ON)
|
||||
option(OLM_USE_OPENSSL "Use OpenSSL instead of bundled crypto-algorithms" OFF)
|
||||
option(OLM_USE_LIBRESSL "Use LibreSSL instead of bundled crypto-algorithms" OFF)
|
||||
|
||||
add_definitions(-DOLMLIB_VERSION_MAJOR=${PROJECT_VERSION_MAJOR})
|
||||
add_definitions(-DOLMLIB_VERSION_MINOR=${PROJECT_VERSION_MINOR})
|
||||
|
@ -47,11 +49,23 @@ add_library(olm
|
|||
src/outbound_group_session.c
|
||||
src/pickle_encoding.c
|
||||
|
||||
lib/crypto-algorithms/aes.c
|
||||
lib/crypto-algorithms/sha256.c
|
||||
lib/curve25519-donna/curve25519-donna.c)
|
||||
add_library(Olm::Olm ALIAS olm)
|
||||
|
||||
if(OLM_USE_OPENSSL)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
target_link_libraries(olm OpenSSL::Crypto)
|
||||
target_compile_definitions(olm PRIVATE OLM_USE_OPENSSL)
|
||||
elseif(OLM_USE_LIBRESSL)
|
||||
find_package(LibreSSL REQUIRED)
|
||||
target_link_libraries(olm LibreSSL::Crypto)
|
||||
target_compile_definitions(olm PRIVATE OLM_USE_LIBRESSL)
|
||||
else()
|
||||
target_sources(olm PRIVATE
|
||||
lib/crypto-algorithms/aes.c
|
||||
lib/crypto-algorithms/sha256.c)
|
||||
endif()
|
||||
|
||||
# restrict the exported symbols
|
||||
include(GenerateExportHeader)
|
||||
generate_export_header(olm
|
||||
|
|
227
cmake/FindLibreSSL.cmake
Normal file
227
cmake/FindLibreSSL.cmake
Normal file
|
@ -0,0 +1,227 @@
|
|||
#[=======================================================================[
|
||||
|
||||
Copyright (c) 2019 John Norrbin <jlnorrbin@johnex.se>
|
||||
|
||||
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)
|
|
@ -17,12 +17,23 @@
|
|||
|
||||
#include <cstring>
|
||||
|
||||
#if defined(OLM_USE_OPENSSL) || defined(OLM_USE_LIBRESSL)
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#ifdef OLM_USE_OPENSSL
|
||||
#include <openssl/kdf.h>
|
||||
#else
|
||||
#include <openssl/hkdf.h>
|
||||
#endif
|
||||
#else
|
||||
extern "C" {
|
||||
|
||||
#include "crypto-algorithms/aes.h"
|
||||
#include "crypto-algorithms/sha256.h"
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "ed25519/src/ed25519.h"
|
||||
#include "curve25519-donna.h"
|
||||
|
@ -37,6 +48,8 @@ static const std::size_t SHA256_BLOCK_LENGTH = 64;
|
|||
static const std::uint8_t HKDF_DEFAULT_SALT[32] = {};
|
||||
|
||||
|
||||
#if !defined(OLM_USE_OPENSSL) && !defined(OLM_USE_LIBRESSL)
|
||||
|
||||
template<std::size_t block_size>
|
||||
inline static void xor_block(
|
||||
std::uint8_t * block,
|
||||
|
@ -98,6 +111,20 @@ inline static void hmac_sha256_final(
|
|||
olm::unset(o_pad);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
template <typename T>
|
||||
static T checked(T val) {
|
||||
if (!val) {
|
||||
abort();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
void _olm_crypto_curve25519_generate_key(
|
||||
|
@ -176,6 +203,14 @@ void _olm_crypto_aes_encrypt_cbc(
|
|||
std::uint8_t const * input, std::size_t input_length,
|
||||
std::uint8_t * output
|
||||
) {
|
||||
#if defined(OLM_USE_OPENSSL) || defined(OLM_USE_LIBRESSL)
|
||||
EVP_CIPHER_CTX* ctx = checked(EVP_CIPHER_CTX_new());
|
||||
checked(EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key->key, iv->iv));
|
||||
int output_length[2];
|
||||
checked(EVP_EncryptUpdate(ctx, output, &output_length[0], input, input_length));
|
||||
checked(EVP_EncryptFinal_ex(ctx, output + output_length[0], &output_length[1]));
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
#else
|
||||
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
|
||||
::aes_key_setup(key->key, key_schedule, AES_KEY_BITS);
|
||||
std::uint8_t input_block[AES_BLOCK_LENGTH];
|
||||
|
@ -198,6 +233,7 @@ void _olm_crypto_aes_encrypt_cbc(
|
|||
::aes_encrypt(input_block, output, key_schedule, AES_KEY_BITS);
|
||||
olm::unset(key_schedule);
|
||||
olm::unset(input_block);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -207,6 +243,15 @@ std::size_t _olm_crypto_aes_decrypt_cbc(
|
|||
std::uint8_t const * input, std::size_t input_length,
|
||||
std::uint8_t * output
|
||||
) {
|
||||
#if defined(OLM_USE_OPENSSL) || defined(OLM_USE_LIBRESSL)
|
||||
EVP_CIPHER_CTX* ctx = checked(EVP_CIPHER_CTX_new());
|
||||
checked(EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key->key, iv->iv));
|
||||
int output_length[2];
|
||||
checked(EVP_DecryptUpdate(ctx, output, &output_length[0], input, input_length));
|
||||
checked(EVP_DecryptFinal_ex(ctx, output + output_length[0], &output_length[1]));
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return output_length[0] + output_length[1];
|
||||
#else
|
||||
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
|
||||
::aes_key_setup(key->key, key_schedule, AES_KEY_BITS);
|
||||
std::uint8_t block1[AES_BLOCK_LENGTH];
|
||||
|
@ -223,6 +268,7 @@ std::size_t _olm_crypto_aes_decrypt_cbc(
|
|||
olm::unset(block2);
|
||||
std::size_t padding = output[input_length - 1];
|
||||
return (padding > input_length) ? std::size_t(-1) : (input_length - padding);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -230,11 +276,15 @@ void _olm_crypto_sha256(
|
|||
std::uint8_t const * input, std::size_t input_length,
|
||||
std::uint8_t * output
|
||||
) {
|
||||
#if defined(OLM_USE_OPENSSL) || defined(OLM_USE_LIBRESSL)
|
||||
checked(EVP_Digest(input, input_length, output, nullptr, EVP_sha256(), nullptr));
|
||||
#else
|
||||
::SHA256_CTX context;
|
||||
::sha256_init(&context);
|
||||
::sha256_update(&context, input, input_length);
|
||||
::sha256_final(&context, output);
|
||||
olm::unset(context);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -243,6 +293,9 @@ void _olm_crypto_hmac_sha256(
|
|||
std::uint8_t const * input, std::size_t input_length,
|
||||
std::uint8_t * output
|
||||
) {
|
||||
#if defined(OLM_USE_OPENSSL) || defined(OLM_USE_LIBRESSL)
|
||||
checked(HMAC(EVP_sha256(), key, key_length, input, input_length, output, nullptr));
|
||||
#else
|
||||
std::uint8_t hmac_key[SHA256_BLOCK_LENGTH];
|
||||
::SHA256_CTX context;
|
||||
hmac_sha256_key(key, key_length, hmac_key);
|
||||
|
@ -251,6 +304,7 @@ void _olm_crypto_hmac_sha256(
|
|||
hmac_sha256_final(&context, hmac_key, output);
|
||||
olm::unset(hmac_key);
|
||||
olm::unset(context);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -260,6 +314,36 @@ void _olm_crypto_hkdf_sha256(
|
|||
std::uint8_t const * info, std::size_t info_length,
|
||||
std::uint8_t * output, std::size_t output_length
|
||||
) {
|
||||
#ifdef OLM_USE_OPENSSL
|
||||
EVP_PKEY_CTX *pctx = checked(EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL));
|
||||
checked(EVP_PKEY_derive_init(pctx));
|
||||
checked(EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()));
|
||||
|
||||
if (input_length) {
|
||||
checked(EVP_PKEY_CTX_set1_hkdf_key(pctx, input, input_length));
|
||||
} else {
|
||||
/* OpenSSL HKDF doesn't directly support zero-length keys:
|
||||
* https://github.com/openssl/openssl/issues/8531
|
||||
* Do the extract step manually with HMAC and use HKDF only for expand */
|
||||
uint8_t intermediate[SHA256_OUTPUT_LENGTH];
|
||||
checked(HMAC(EVP_sha256(), nullptr, 0, salt, salt_length, intermediate, nullptr));
|
||||
checked(EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY));
|
||||
checked(EVP_PKEY_CTX_set1_hkdf_key(pctx, intermediate, sizeof(intermediate)));
|
||||
}
|
||||
|
||||
checked(EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, salt_length));
|
||||
checked(EVP_PKEY_CTX_add1_hkdf_info(pctx, info, info_length));
|
||||
checked(EVP_PKEY_derive(pctx, output, &output_length));
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
#elif defined(OLM_USE_LIBRESSL)
|
||||
if (salt_length == 0) {
|
||||
/* LibreSSL HKDF rejects nullptr salt, even if salt_length is 0.
|
||||
* salt needs to be set to something else. */
|
||||
salt = (const uint8_t*)"";
|
||||
}
|
||||
checked(HKDF(output, output_length, EVP_sha256(), input, input_length,
|
||||
salt, salt_length, info, info_length));
|
||||
#else
|
||||
::SHA256_CTX context;
|
||||
std::uint8_t hmac_key[SHA256_BLOCK_LENGTH];
|
||||
std::uint8_t step_result[SHA256_OUTPUT_LENGTH];
|
||||
|
@ -296,4 +380,5 @@ void _olm_crypto_hkdf_sha256(
|
|||
olm::unset(context);
|
||||
olm::unset(hmac_key);
|
||||
olm::unset(step_result);
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue