diff --git a/CMakeLists.txt b/CMakeLists.txt index c67ac2884..04f20f7ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ tr_auto_option(USE_SYSTEM_MINIUPNPC "Use system miniupnpc library" AUTO) tr_auto_option(USE_SYSTEM_NATPMP "Use system natpmp library" AUTO) tr_auto_option(USE_SYSTEM_UTP "Use system utp library" AUTO) tr_auto_option(USE_SYSTEM_B64 "Use system b64 library" AUTO) -tr_list_option(WITH_CRYPTO "Use specified crypto library" AUTO openssl cyassl) +tr_list_option(WITH_CRYPTO "Use specified crypto library" AUTO openssl cyassl polarssl) tr_auto_option(WITH_INOTIFY "Enable inotify support (on systems that support it)" AUTO) tr_auto_option(WITH_KQUEUE "Enable kqueue support (on systems that support it)" AUTO) tr_auto_option(WITH_SYSTEMD "Add support for systemd startup notification (on systems that support it)" AUTO) @@ -96,6 +96,7 @@ set(CURL_MINIMUM 7.15.4) set(EVENT2_MINIMUM 2.0.10) set(OPENSSL_MINIMUM 0.9.4) set(CYASSL_MINIMUM 3.0) +set(POLARSSL_MINIMUM 1.3) set(ZLIB_MINIMUM 1.2.3) set(GTK_MINIMUM 3.4.0) set(GLIB_MINIMUM 2.32.0) @@ -157,6 +158,16 @@ if(WITH_CRYPTO STREQUAL "AUTO" OR WITH_CRYPTO STREQUAL "cyassl") set(CRYPTO_LIBRARIES ${CYASSL_LIBRARIES}) endif() endif() +if(WITH_CRYPTO STREQUAL "AUTO" OR WITH_CRYPTO STREQUAL "polarssl") + tr_get_required_flag(WITH_CRYPTO POLARSSL_IS_REQUIRED) + find_package(PolarSSL ${POLARSSL_MINIMUM} ${POLARSSL_IS_REQUIRED}) + tr_fixup_list_option(WITH_CRYPTO "polarssl" POLARSSL_FOUND "AUTO" POLARSSL_IS_REQUIRED) + if(WITH_CRYPTO STREQUAL "polarssl") + set(CRYPTO_PKG "polarssl") + set(CRYPTO_INCLUDE_DIRS ${POLARSSL_INCLUDE_DIRS}) + set(CRYPTO_LIBRARIES ${POLARSSL_LIBRARIES}) + endif() +endif() # We should have found the library by now if(CRYPTO_PKG STREQUAL "") if(WITH_CRYPTO STREQUAL "AUTO") diff --git a/cmake/FindPolarSSL.cmake b/cmake/FindPolarSSL.cmake new file mode 100644 index 000000000..0a958e008 --- /dev/null +++ b/cmake/FindPolarSSL.cmake @@ -0,0 +1,47 @@ +if(POLARSSL_PREFER_STATIC_LIB) + set(POLARSSL_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if(WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES .a .lib ${CMAKE_FIND_LIBRARY_SUFFIXES}) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + endif() +endif() + +if(UNIX) + find_package(PkgConfig QUIET) + pkg_check_modules(_POLARSSL QUIET polarssl) +endif() + +find_path(POLARSSL_INCLUDE_DIR NAMES polarssl/version.h HINTS ${_POLARSSL_INCLUDEDIR}) +find_library(POLARSSL_LIBRARY NAMES polarssl HINTS ${_POLARSSL_LIBDIR}) + +if(POLARSSL_INCLUDE_DIR) + if(_POLARSSL_VERSION) + set(POLARSSL_VERSION ${_POLARSSL_VERSION}) + else() + file(STRINGS "${POLARSSL_INCLUDE_DIR}/polarssl/version.h" POLARSSL_VERSION_STR REGEX "^#define[\t ]+POLARSSL_VERSION_STRING[\t ]+\"[^\"]+\"") + if(POLARSSL_VERSION_STR MATCHES "\"([^\"]+)\"") + set(POLARSSL_VERSION "${CMAKE_MATCH_1}") + endif() + endif() +endif() + +set(POLARSSL_INCLUDE_DIRS ${POLARSSL_INCLUDE_DIR}) +set(POLARSSL_LIBRARIES ${POLARSSL_LIBRARY}) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(PolarSSL + REQUIRED_VARS + POLARSSL_LIBRARY + POLARSSL_INCLUDE_DIR + VERSION_VAR + POLARSSL_VERSION +) + +mark_as_advanced(POLARSSL_INCLUDE_DIR POLARSSL_LIBRARY) + +if(POLARSSL_PREFER_STATIC_LIB) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${POLARSSL_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) + unset(POLARSSL_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) +endif() diff --git a/configure.ac b/configure.ac index f73d5ac2a..d619c4703 100644 --- a/configure.ac +++ b/configure.ac @@ -50,6 +50,8 @@ OPENSSL_MINIMUM=0.9.4 AC_SUBST(OPENSSL_MINIMUM) CYASSL_MINIMUM=3.0 AC_SUBST(CYASSL_MINIMUM) +POLARSSL_MINIMUM=0x01030000 # 1.3 +AC_SUBST(POLARSSL_MINIMUM) ## ## @@ -123,7 +125,7 @@ PKG_CHECK_MODULES(ZLIB, [zlib >= $ZLIB_MINIMUM]) AC_ARG_WITH([crypto], AS_HELP_STRING([--with-crypto=PKG], - [Use specified crypto library: auto (default), openssl, cyassl]), + [Use specified crypto library: auto (default), openssl, cyassl, polarssl]), [want_crypto=$withval], [want_crypto=auto]) AS_IF([test "x$want_crypto" = "xauto" -o "x$want_crypto" = "xopenssl"], [ @@ -142,6 +144,27 @@ AS_IF([test "x$want_crypto" = "xauto" -o "x$want_crypto" = "xcyassl"], [ )] ) ]) +AS_IF([test "x$want_crypto" = "xauto" -o "x$want_crypto" = "xpolarssl"], [ + AC_CHECK_HEADER([polarssl/version.h], + [AC_EGREP_CPP([version_ok], [#include + #if defined (POLARSSL_VERSION_NUMBER) && POLARSSL_VERSION_NUMBER >= $POLARSSL_MINIMUM + version_ok + #endif], + [AC_CHECK_LIB([polarssl], [dhm_init], + [want_crypto="polarssl"; CRYPTO_PKG="polarssl"; CRYPTO_CFLAGS=""; CRYPTO_LIBS="-lpolarssl"], + [AS_IF([test "x$want_crypto" = "xpolarssl"], + [AC_MSG_ERROR([PolarSSL support requested, but library not found.])] + )] + )], + [AS_IF([test "x$want_crypto" = "xpolarssl"], + [AC_MSG_ERROR([PolarSSL support requested, but version not suitable.])] + )] + )], + [AS_IF([test "x$want_crypto" = "xpolarssl"], + [AC_MSG_ERROR([PolarSSL support requested, but headers not found.])] + )] + ) +]) # we should have found the library by now AS_IF([test "x$CRYPTO_PKG" = "x"], [ AS_IF([test "x$want_crypto" = "xauto"], diff --git a/libtransmission/crypto-utils-polarssl.c b/libtransmission/crypto-utils-polarssl.c new file mode 100644 index 000000000..128a93cf9 --- /dev/null +++ b/libtransmission/crypto-utils-polarssl.c @@ -0,0 +1,299 @@ +/* + * This file Copyright (C) Mnemosyne LLC + * + * It may be used under the GNU GPL versions 2 or 3 + * or any future license endorsed by Mnemosyne LLC. + * + * $Id$ + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "transmission.h" +#include "crypto-utils.h" +#include "log.h" +#include "platform.h" +#include "utils.h" + +#define TR_CRYPTO_DH_SECRET_FALLBACK +#include "crypto-utils-fallback.c" + +/*** +**** +***/ + +#define MY_NAME "tr_crypto_utils" + +static void +log_polarssl_error (int error_code, + const char * file, + int line) +{ + if (tr_logLevelIsActive (TR_LOG_ERROR)) + { + char error_message[256]; + polarssl_strerror (error_code, error_message, sizeof (error_message)); + tr_logAddMessage (file, line, TR_LOG_ERROR, MY_NAME, "PolarSSL error: %s", error_message); + } +} + +#define log_error(error_code) log_polarssl_error(error_code, __FILE__, __LINE__) + +static bool +check_polarssl_result (int result, + int expected_result, + const char * file, + int line) +{ + const bool ret = result == expected_result; + if (!ret) + log_polarssl_error (result, file, line); + return ret; +} + +#define check_result(result) check_polarssl_result ((result), 0, __FILE__, __LINE__) +#define check_result_eq(result, x_result) check_polarssl_result ((result), (x_result), __FILE__, __LINE__) + +/*** +**** +***/ + +static int +my_rand (void * context UNUSED, unsigned char * buffer, size_t buffer_size) +{ + size_t i; + + for (i = 0; i < buffer_size; ++i) + buffer[i] = tr_rand_int_weak (256); + + return 0; +} + +static ctr_drbg_context * +get_rng (void) +{ + static ctr_drbg_context rng; + static bool rng_initialized = false; + + if (!rng_initialized) + { + if (!check_result (ctr_drbg_init (&rng, &my_rand, NULL, NULL, 0))) + return NULL; + rng_initialized = true; + } + + return &rng; +} + +static tr_lock * +get_rng_lock (void) +{ + static tr_lock * lock = NULL; + + if (lock == NULL) + lock = tr_lockNew (); + + return lock; +} + +/*** +**** +***/ + +tr_sha1_ctx_t +tr_sha1_init (void) +{ + sha1_context * handle = tr_new (sha1_context, 1); + sha1_starts (handle); + return handle; +} + +bool +tr_sha1_update (tr_sha1_ctx_t handle, + const void * data, + size_t data_length) +{ + assert (handle != NULL); + + if (data_length == 0) + return true; + + assert (data != NULL); + + sha1_update (handle, data, data_length); + return true; +} + +bool +tr_sha1_final (tr_sha1_ctx_t handle, + uint8_t * hash) +{ + if (hash != NULL) + { + assert (handle != NULL); + + sha1_finish (handle, hash); + } + + tr_free (handle); + return true; +} + +/*** +**** +***/ + +tr_rc4_ctx_t +tr_rc4_new (void) +{ + return tr_new0 (arc4_context, 1); +} + +void +tr_rc4_free (tr_rc4_ctx_t handle) +{ + tr_free (handle); +} + +void +tr_rc4_set_key (tr_rc4_ctx_t handle, + const uint8_t * key, + size_t key_length) +{ + assert (handle != NULL); + assert (key != NULL); + + arc4_setup (handle, key, key_length); +} + +void +tr_rc4_process (tr_rc4_ctx_t handle, + const void * input, + void * output, + size_t length) +{ + assert (handle != NULL); + + if (length == 0) + return; + + assert (input != NULL); + assert (output != NULL); + + arc4_crypt (handle, length, input, output); +} + +/*** +**** +***/ + +tr_dh_ctx_t +tr_dh_new (const uint8_t * prime_num, + size_t prime_num_length, + const uint8_t * generator_num, + size_t generator_num_length) +{ + dhm_context * handle = tr_new0 (dhm_context, 1); + + assert (prime_num != NULL); + assert (generator_num != NULL); + + dhm_init (handle); + + if (!check_result (mpi_read_binary (&handle->P, prime_num, prime_num_length)) || + !check_result (mpi_read_binary (&handle->G, generator_num, generator_num_length))) + { + dhm_free (handle); + return NULL; + } + + handle->len = prime_num_length; + + return handle; +} + +void +tr_dh_free (tr_dh_ctx_t handle) +{ + if (handle == NULL) + return; + + dhm_free (handle); +} + +bool +tr_dh_make_key (tr_dh_ctx_t raw_handle, + size_t private_key_length, + uint8_t * public_key, + size_t * public_key_length) +{ + dhm_context * handle = raw_handle; + + assert (handle != NULL); + assert (public_key != NULL); + + if (public_key_length != NULL) + *public_key_length = handle->len; + + return check_result (dhm_make_public (handle, private_key_length, public_key, + handle->len, my_rand, NULL)); +} + +tr_dh_secret_t +tr_dh_agree (tr_dh_ctx_t raw_handle, + const uint8_t * other_public_key, + size_t other_public_key_length) +{ + dhm_context * handle = raw_handle; + struct tr_dh_secret * ret; + size_t secret_key_length; + + assert (handle != NULL); + assert (other_public_key != NULL); + + if (!check_result (dhm_read_public (handle, other_public_key, + other_public_key_length))) + return NULL; + + ret = tr_dh_secret_new (handle->len); + + secret_key_length = handle->len; + + if (!check_result (dhm_calc_secret (handle, ret->key, + &secret_key_length, my_rand, NULL))) + { + tr_dh_secret_free (ret); + return NULL; + } + + tr_dh_secret_align (ret, secret_key_length); + + return ret; +} + +/*** +**** +***/ + +bool +tr_rand_buffer (void * buffer, + size_t length) +{ + bool ret; + tr_lock * rng_lock = get_rng_lock (); + + assert (buffer != NULL); + + tr_lockLock (rng_lock); + ret = check_result (ctr_drbg_random (get_rng (), buffer, length)); + tr_lockUnlock (rng_lock); + + return ret; +}