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_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)
set(CURL_MINIMUM 7.15.4)
set(EVENT2_MINIMUM 2.0.10)
set(OPENSSL_MINIMUM 0.9.4)
+set(CYASSL_MINIMUM 3.0)
set(ZLIB_MINIMUM 1.2.3)
set(GTK_MINIMUM 3.4.0)
set(GLIB_MINIMUM 2.32.0)
find_package(ICONV REQUIRED)
endif()
+if(WITH_CRYPTO STREQUAL "AUTO" OR WITH_CRYPTO STREQUAL "openssl")
+ tr_get_required_flag(WITH_CRYPTO OPENSSL_IS_REQUIRED)
+ find_package(OpenSSL ${OPENSSL_MINIMUM} ${OPENSSL_IS_REQUIRED})
+ tr_fixup_list_option(WITH_CRYPTO "openssl" OPENSSL_FOUND "AUTO" OPENSSL_IS_REQUIRED)
+ if(WITH_CRYPTO STREQUAL "openssl")
+ set(CRYPTO_PKG "openssl")
+ set(CRYPTO_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR})
+ set(CRYPTO_LIBRARIES ${OPENSSL_LIBRARIES})
+ endif()
+endif()
+if(WITH_CRYPTO STREQUAL "AUTO" OR WITH_CRYPTO STREQUAL "cyassl")
+ tr_get_required_flag(WITH_CRYPTO CYASSL_IS_REQUIRED)
+ find_package(CyaSSL ${CYASSL_MINIMUM} ${CYASSL_IS_REQUIRED})
+ tr_fixup_list_option(WITH_CRYPTO "cyassl" CYASSL_FOUND "AUTO" CYASSL_IS_REQUIRED)
+ if(WITH_CRYPTO STREQUAL "cyassl")
+ set(CRYPTO_PKG "cyassl")
+ set(CRYPTO_INCLUDE_DIRS ${CYASSL_INCLUDE_DIRS})
+ set(CRYPTO_LIBRARIES ${CYASSL_LIBRARIES})
+ endif()
+endif()
+# We should have found the library by now
+if(CRYPTO_PKG STREQUAL "")
+ if(WITH_CRYPTO STREQUAL "AUTO")
+ message(FATAL_ERROR "Unable to find any supported crypto library.")
+ else()
+ message(FATAL_ERROR "Requested crypto library '${WITH_CRYPTO}' is not supported.")
+ endif()
+endif()
+
if(ENABLE_GTK)
tr_get_required_flag(ENABLE_GTK GTK_IS_REQUIRED)
AM_CFLAGS = \
@LIBEVENT_CFLAGS@ \
- @OPENSSL_CFLAGS@ \
@LIBCURL_CFLAGS@ \
@ZLIB_CFLAGS@ \
@PTHREAD_CFLAGS@
@LIBUTP_LIBS@ \
@LIBEVENT_LIBS@ \
@LIBCURL_LIBS@ \
- @OPENSSL_LIBS@ \
+ @CRYPTO_LIBS@ \
@INTLLIBS@ \
@ZLIB_LIBS@ \
@PTHREAD_LIBS@ \
--- /dev/null
+if(CYASSL_PREFER_STATIC_LIB)
+ set(CYASSL_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(_CYASSL QUIET cyassl)
+endif()
+
+find_path(CYASSL_INCLUDE_DIR NAMES cyassl/version.h HINTS ${_CYASSL_INCLUDEDIR})
+find_library(CYASSL_LIBRARY NAMES cyassl HINTS ${_CYASSL_LIBDIR})
+
+if(CYASSL_INCLUDE_DIR)
+ if(_CYASSL_VERSION)
+ set(CYASSL_VERSION ${_CYASSL_VERSION})
+ else()
+ file(STRINGS "${CYASSL_INCLUDE_DIR}/cyassl/version.h" CYASSL_VERSION_STR REGEX "^#define[\t ]+LIBCYASSL_VERSION_STRING[\t ]+\"[^\"]+\"")
+ if(CYASSL_VERSION_STR MATCHES "\"([^\"]+)\"")
+ set(CYASSL_VERSION_STR "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+endif()
+
+set(CYASSL_INCLUDE_DIRS ${CYASSL_INCLUDE_DIR})
+set(CYASSL_LIBRARIES ${CYASSL_LIBRARY})
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(CYASSL
+ REQUIRED_VARS
+ CYASSL_LIBRARY
+ CYASSL_INCLUDE_DIR
+ VERSION_VAR
+ CYASSL_VERSION
+)
+
+mark_as_advanced(CYASSL_INCLUDE_DIR CYASSL_LIBRARY)
+
+if(CYASSL_PREFER_STATIC_LIB)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${CYASSL_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
+ unset(CYASSL_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
+endif()
endif()
endmacro()
+function(tr_list_option_changed NAME ACC VAL FIL STK)
+ get_property(VAR_STRINGS CACHE ${NAME} PROPERTY STRINGS)
+ string(TOUPPER "${VAL}" VAL_UPCASE)
+ foreach(X ${VAR_STRINGS})
+ string(TOUPPER "${X}" X_UPCASE)
+ if("${VAL_UPCASE}" STREQUAL "${X_UPCASE}")
+ if(NOT "${VAL}" STREQUAL "${X}")
+ set_property(CACHE ${NAME} PROPERTY VALUE "${X}")
+ message(STATUS ">>> (list) ${NAME} -> ${X}")
+ endif()
+ return()
+ endif()
+ endforeach()
+ string(REPLACE ";" "', '" VAR_STRINGS "${VAR_STRINGS}")
+ message(FATAL_ERROR "Option '${NAME}' set to unrecognized value '${VAL}'. Should be one of '${VAR_STRINGS}'.")
+endfunction()
+
+macro(tr_list_option NAME DESC VAL)
+ set(${NAME} "${VAL}" CACHE STRING "${DESC}")
+ set_property(CACHE ${NAME} PROPERTY STRINGS "${VAL};${ARGN}")
+ variable_watch(${NAME} tr_list_option_changed)
+endmacro()
+
+macro(tr_fixup_list_option NAME FVAL ISFOUND RVAL ISREQ)
+ if(${ISFOUND})
+ set_property(CACHE ${NAME} PROPERTY VALUE "${FVAL}")
+ elseif(NOT (${ISREQ}))
+ set_property(CACHE ${NAME} PROPERTY VALUE "${RVAL}")
+ endif()
+endmacro()
+
macro(tr_get_required_flag IVAR OVAR)
set(${OVAR})
if (${IVAR} AND NOT ${IVAR} STREQUAL "AUTO")
## MANDATORY for everything
##
##
+
CURL_MINIMUM=7.15.4
AC_SUBST(CURL_MINIMUM)
LIBEVENT_MINIMUM=2.0.10
AC_SUBST(LIBEVENT_MINIMUM)
-OPENSSL_MINIMUM=0.9.4
-AC_SUBST(OPENSSL_MINIMUM)
ZLIB_MINIMUM=1.2.3
AC_SUBST(ZLIB_MINIMUM)
+# crypto backends
+OPENSSL_MINIMUM=0.9.4
+AC_SUBST(OPENSSL_MINIMUM)
+CYASSL_MINIMUM=3.0
+AC_SUBST(CYASSL_MINIMUM)
+
##
##
## MANDATORY for the GTK+ client
AC_SEARCH_LIBS([socket], [socket net])
AC_SEARCH_LIBS([gethostbyname], [nsl bind])
AC_SEARCH_LIBS([quotacursor_skipidtype], [quota])
-PKG_CHECK_MODULES(OPENSSL, [openssl >= $OPENSSL_MINIMUM], , [CHECK_SSL()])
PKG_CHECK_MODULES(LIBCURL, [libcurl >= $CURL_MINIMUM])
PKG_CHECK_MODULES(LIBEVENT, [libevent >= $LIBEVENT_MINIMUM])
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]),
+ [want_crypto=$withval], [want_crypto=auto])
+
+AS_IF([test "x$want_crypto" = "xauto" -o "x$want_crypto" = "xopenssl"], [
+ PKG_CHECK_MODULES(OPENSSL, [openssl >= $OPENSSL_MINIMUM],
+ [want_crypto="openssl"; CRYPTO_PKG="openssl"; CRYPTO_CFLAGS="$OPENSSL_CFLAGS"; CRYPTO_LIBS="$OPENSSL_LIBS"],
+ [AS_IF([test "x$want_crypto" = "xopenssl"],
+ [AC_MSG_ERROR([OpenSSL support requested, but library not found.])]
+ )]
+ )
+])
+AS_IF([test "x$want_crypto" = "xauto" -o "x$want_crypto" = "xcyassl"], [
+ PKG_CHECK_MODULES(CYASSL, [cyassl >= $CYASSL_MINIMUM],
+ [want_crypto="cyassl"; CRYPTO_PKG="cyassl"; CRYPTO_CFLAGS="$CYASSL_CFLAGS"; CRYPTO_LIBS="$CYASSL_LIBS"],
+ [AS_IF([test "x$want_crypto" = "xcyassl"],
+ [AC_MSG_ERROR([CyaSSL support requested, but library not found.])]
+ )]
+ )
+])
+# we should have found the library by now
+AS_IF([test "x$CRYPTO_PKG" = "x"], [
+ AS_IF([test "x$want_crypto" = "xauto"],
+ [AC_MSG_ERROR([Unable to find any supported crypto library.])],
+ [AC_MSG_ERROR([Requested crypto library "$want_crypto" is not supported.])],
+ )
+])
+
+AC_SUBST(CRYPTO_PKG)
+AC_SUBST(CRYPTO_CFLAGS)
+AC_SUBST(CRYPTO_LIBS)
+
+
AC_SYS_LARGEFILE
AC_CHECK_FUNCS([lseek64])
Build libtransmission: yes
* optimized for low-resource systems: ${enable_lightweight}
* µTP enabled: ${build_utp}
+ * crypto library: ${CRYPTO_PKG}
Build Command-Line client: ${build_cli}
AM_CFLAGS = \
@LIBEVENT_CFLAGS@ \
- @OPENSSL_CFLAGS@ \
@LIBCURL_CFLAGS@ \
@SYSTEMD_DAEMON_CFLAGS@ \
@ZLIB_CFLAGS@ \
@LIBUTP_LIBS@ \
@LIBEVENT_LIBS@ \
@LIBCURL_LIBS@ \
- @OPENSSL_LIBS@ \
+ @CRYPTO_LIBS@ \
@INTLLIBS@ \
@SYSTEMD_DAEMON_LIBS@ \
@ZLIB_LIBS@ \
@LIBEVENT_CFLAGS@ \
@GTK_CFLAGS@ \
@LIBCURL_CFLAGS@ \
- @OPENSSL_CFLAGS@ \
@ZLIB_CFLAGS@ \
@PTHREAD_CFLAGS@
@LIBAPPINDICATOR_LIBS@ \
@LIBEVENT_LIBS@ \
@LIBCURL_LIBS@ \
- @OPENSSL_LIBS@ \
+ @CRYPTO_LIBS@ \
@ZLIB_LIBS@ \
@PTHREAD_LIBS@ \
${LIBM}
crypto.c
crypto-utils.c
crypto-utils-fallback.c
- crypto-utils-openssl.c
+ crypto-utils-${CRYPTO_PKG}.c
error.c
fdlimit.c
file.c
${PROJECT_SOURCE_DIR}
${PROJECT_BINARY_DIR}
${ZLIB_INCLUDE_DIRS}
- ${OPENSSL_INCLUDE_DIRS}
+ ${CRYPTO_INCLUDE_DIRS}
${CURL_INCLUDE_DIRS}
${ICONV_INCLUDE_DIRS}
${EVENT2_INCLUDE_DIRS}
target_link_libraries(${TR_NAME}
${CMAKE_THREAD_LIBS_INIT}
${ZLIB_LIBRARIES}
- ${OPENSSL_LIBRARIES}
+ ${CRYPTO_LIBRARIES}
${CURL_LIBRARIES}
${ICONV_LIBRARIES}
${EVENT2_LIBRARIES}
@LIBNATPMP_CFLAGS@ \
@LIBEVENT_CFLAGS@ \
@LIBCURL_CFLAGS@ \
- @OPENSSL_CFLAGS@ \
+ @CRYPTO_CFLAGS@ \
@PTHREAD_CFLAGS@ \
@ZLIB_CFLAGS@
@LIBUTP_LIBS@ \
@LIBCURL_LIBS@ \
@LIBEVENT_LIBS@ \
- @OPENSSL_LIBS@ \
+ @CRYPTO_LIBS@ \
@PTHREAD_LIBS@ \
@ZLIB_LIBS@ \
${LIBM}
--- /dev/null
+/*
+ * 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 <assert.h>
+
+#include <cyassl/ctaocrypt/arc4.h>
+#include <cyassl/ctaocrypt/dh.h>
+#include <cyassl/ctaocrypt/error-crypt.h>
+#include <cyassl/ctaocrypt/random.h>
+#include <cyassl/ctaocrypt/sha.h>
+#include <cyassl/version.h>
+
+#include "transmission.h"
+#include "crypto-utils.h"
+#include "log.h"
+#include "utils.h"
+
+#define TR_CRYPTO_DH_SECRET_FALLBACK
+#include "crypto-utils-fallback.c"
+
+struct tr_dh_ctx
+{
+ DhKey dh;
+ word32 key_length;
+ uint8_t * private_key;
+ word32 private_key_length;
+};
+
+/***
+****
+***/
+
+#define MY_NAME "tr_crypto_utils"
+
+static void
+log_cyassl_error (int error_code,
+ const char * file,
+ int line)
+{
+ if (tr_logLevelIsActive (TR_LOG_ERROR))
+ {
+#if LIBCYASSL_VERSION_HEX >= 0x03000002
+ const char * error_message = CTaoCryptGetErrorString (error_code);
+#else
+ char error_message[CYASSL_MAX_ERROR_SZ];
+ CTaoCryptErrorString (error_code, error_message);
+#endif
+
+ tr_logAddMessage (file, line, TR_LOG_ERROR, MY_NAME, "CyaSSL error: %s", error_message);
+ }
+}
+
+static bool
+check_cyassl_result (int result,
+ const char * file,
+ int line)
+{
+ const bool ret = result == 0;
+ if (!ret)
+ log_cyassl_error (result, file, line);
+ return ret;
+}
+
+#define check_result(result) check_cyassl_result ((result), __FILE__, __LINE__)
+
+/***
+****
+***/
+
+static RNG *
+get_rng (void)
+{
+ static RNG rng;
+ static bool rng_initialized = false;
+
+ if (!rng_initialized)
+ {
+ if (!check_result (InitRng (&rng)))
+ return NULL;
+ rng_initialized = true;
+ }
+
+ return &rng;
+}
+
+/***
+****
+***/
+
+tr_sha1_ctx_t
+tr_sha1_init (void)
+{
+ Sha * handle = tr_new (Sha, 1);
+
+ if (check_result (InitSha (handle)))
+ return handle;
+
+ tr_free (handle);
+ return NULL;
+}
+
+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);
+
+ return check_result (ShaUpdate (handle, data, data_length));
+}
+
+bool
+tr_sha1_final (tr_sha1_ctx_t handle,
+ uint8_t * hash)
+{
+ bool ret = true;
+
+ if (hash != NULL)
+ {
+ assert (handle != NULL);
+
+ ret = check_result (ShaFinal (handle, hash));
+ }
+
+ tr_free (handle);
+ return ret;
+}
+
+/***
+****
+***/
+
+tr_rc4_ctx_t
+tr_rc4_new (void)
+{
+ return tr_new0 (Arc4, 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);
+
+ Arc4SetKey (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);
+
+ Arc4Process (handle, output, input, length);
+}
+
+/***
+****
+***/
+
+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)
+{
+ struct tr_dh_ctx * handle = tr_new0 (struct tr_dh_ctx, 1);
+
+ assert (prime_num != NULL);
+ assert (generator_num != NULL);
+
+ InitDhKey (&handle->dh);
+ if (!check_result (DhSetKey (&handle->dh,
+ prime_num, prime_num_length,
+ generator_num, generator_num_length)))
+ {
+ tr_free (handle);
+ return NULL;
+ }
+
+ handle->key_length = prime_num_length;
+
+ return handle;
+}
+
+void
+tr_dh_free (tr_dh_ctx_t raw_handle)
+{
+ struct tr_dh_ctx * handle = raw_handle;
+
+ if (handle == NULL)
+ return;
+
+ FreeDhKey (&handle->dh);
+ tr_free (handle->private_key);
+ tr_free (handle);
+}
+
+bool
+tr_dh_make_key (tr_dh_ctx_t raw_handle,
+ size_t private_key_length UNUSED,
+ uint8_t * public_key,
+ size_t * public_key_length)
+{
+ struct tr_dh_ctx * handle = raw_handle;
+ word32 my_private_key_length, my_public_key_length;
+
+ assert (handle != NULL);
+ assert (public_key != NULL);
+
+ if (handle->private_key == NULL)
+ handle->private_key = tr_malloc (handle->key_length);
+
+ if (!check_result (DhGenerateKeyPair (&handle->dh, get_rng (),
+ handle->private_key, &my_private_key_length,
+ public_key, &my_public_key_length)))
+ return false;
+
+ tr_dh_align_key (public_key, my_public_key_length, handle->key_length);
+
+ handle->private_key_length = my_private_key_length;
+
+ if (public_key_length != NULL)
+ *public_key_length = handle->key_length;
+
+ return true;
+}
+
+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)
+{
+ struct tr_dh_ctx * handle = raw_handle;
+ struct tr_dh_secret * ret;
+ word32 my_secret_key_length;
+
+ assert (handle != NULL);
+ assert (other_public_key != NULL);
+
+ ret = tr_dh_secret_new (handle->key_length);
+
+ if (check_result (DhAgree (&handle->dh,
+ ret->key, &my_secret_key_length,
+ handle->private_key, handle->private_key_length,
+ other_public_key, other_public_key_length)))
+ {
+ tr_dh_secret_align (ret, my_secret_key_length);
+ }
+ else
+ {
+ tr_dh_secret_free (ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+/***
+****
+***/
+
+bool
+tr_rand_buffer (void * buffer,
+ size_t length)
+{
+ assert (buffer != NULL);
+
+ return check_result (RNG_GenerateBlock (get_rng (), buffer, length));
+}
AM_CFLAGS = \
@LIBEVENT_CFLAGS@ \
@LIBCURL_CFLAGS@ \
- @OPENSSL_CFLAGS@ \
@ZLIB_CFLAGS@ \
@PTHREAD_CFLAGS@ \
${LIBM}
@LIBUTP_LIBS@ \
@LIBEVENT_LIBS@ \
@LIBCURL_LIBS@ \
- @OPENSSL_LIBS@ \
+ @CRYPTO_LIBS@ \
@ZLIB_LIBS@ \
@PTHREAD_LIBS@ \
${LIBM}