Merge pull request #107 from eboasson/master

fix and enable SSL support when OpenSSL is available

This has been sitting pretty for some days now and in my opinion it makes sense to merge it — so merging it. The AppVeyor build is not done yet, but it is successful for the exact same commit on the source branch and it also succesful for the next-to-last commit. The last commit in the PR is no more than Travis CI configuration, so it doesn't even affect AppVeyor builds.
This commit is contained in:
eboasson 2019-02-04 16:09:14 +00:00 committed by GitHub
commit 413d9d36eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 314 additions and 269 deletions

View file

@ -5,27 +5,33 @@ language: c
# anchor/alias YAML features.
linux_gcc8: &linux_gcc8
os: linux
dist: xenial
compiler: gcc
addons:
apt:
update: true
sources: [ ubuntu-toolchain-r-test ]
packages: [ gcc-8 g++-8 oracle-java8-set-default maven ]
#packages: [ gcc-8 g++-8 maven cmake ]
packages: [ gcc-8 g++-8 ]
linux_clang60: &linux_clang60
linux_clang: &linux_clang
os: linux
dist: xenial
compiler: clang
addons:
apt:
update: true
sources: [ llvm-toolchain-trusty-6.0, ubuntu-toolchain-r-test ]
packages: [ clang-6.0 oracle-java8-set-default maven ]
#sources: [ ubuntu-toolchain-r-test ]
#packages: [ maven clang ]
osx_xcode94: &osx_xcode94
osx_xcode10_1: &osx_xcode10_1
os: osx
osx_image: xcode94
osx_image: xcode10.1
compiler: clang
addons:
homebrew:
packages:
- pyenv-virtualenv
matrix:
include:
@ -33,13 +39,13 @@ matrix:
env: [ BUILD_TYPE=Debug, C_COMPILER=gcc-8, CXX_COMPILER=g++-8, USE_SANITIZER=none ]
- <<: *linux_gcc8
env: [ BUILD_TYPE=Release, C_COMPILER=gcc-8, CXX_COMPILER=g++-8, USE_SANITIZER=none ]
- <<: *linux_clang60
env: [ BUILD_TYPE=Debug, C_COMPILER=clang-6.0, CXX_COMPILER=clang++-6.0, USE_SANITIZER=address ]
- <<: *linux_clang60
env: [ BUILT_TYPE=Release, C_COMPILER=clang-6.0, CXX_COMPILER=clang++-6.0, USE_SANITIZER=none ]
- <<: *osx_xcode94
- <<: *linux_clang
env: [ BUILD_TYPE=Debug, C_COMPILER=clang, CXX_COMPILER=clang++, USE_SANITIZER=address ]
- <<: *osx_xcode94
- <<: *linux_clang
env: [ BUILT_TYPE=Release, C_COMPILER=clang, CXX_COMPILER=clang++, USE_SANITIZER=none ]
- <<: *osx_xcode10_1
env: [ BUILD_TYPE=Debug, C_COMPILER=clang, CXX_COMPILER=clang++, USE_SANITIZER=address ]
- <<: *osx_xcode10_1
env: [ BUILD_TYPE=Release, C_COMPILER=clang, CXX_COMPILER=clang++, USE_SANITIZER=none ]
@ -49,7 +55,6 @@ before_install:
install:
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
brew install pyenv-virtualenv;
eval "$(pyenv init -)";
pyenv virtualenv conan;
pyenv rehash;
@ -66,7 +71,7 @@ before_script:
script:
- mkdir build
- cd build
- conan install ..
- conan install .. --build missing
- cmake -DBUILD_TESTING=on -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DUSE_SANITIZER=${USE_SANITIZER} -DCMAKE_INSTALL_PREFIX=${PWD}/install ../src
- cmake --build . --target install
- mkdir install/share/CycloneDDS/examples/helloworld/build

View file

@ -1,5 +1,6 @@
[requires]
cunit/2.1-3@bincrafters/stable
OpenSSL/1.1.1a@conan/stable
[generators]
cmake

View file

@ -80,6 +80,7 @@ if(EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")
else()
conan_basic_setup()
endif()
conan_define_targets()
endif()
# Set reasonably strict warning options for clang, gcc, msvc

View file

@ -0,0 +1,34 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
if(TARGET CONAN_PKG::OpenSSL)
add_library(OpenSSL::SSL INTERFACE IMPORTED)
target_link_libraries(OpenSSL::SSL INTERFACE CONAN_PKG::OpenSSL)
set(OPENSSL_FOUND TRUE)
else()
# Loop over a list of possible module paths (without the current directory).
get_filename_component(DIR "${CMAKE_CURRENT_LIST_DIR}" ABSOLUTE)
foreach(MODULE_DIR ${CMAKE_MODULE_PATH} ${CMAKE_ROOT}/Modules)
get_filename_component(MODULE_DIR "${MODULE_DIR}" ABSOLUTE)
if(NOT MODULE_DIR STREQUAL DIR)
if(EXISTS "${MODULE_DIR}/FindOpenSSL.cmake")
set(FIND_PACKAGE_FILE "${MODULE_DIR}/FindOpenSSL.cmake")
break()
endif()
endif()
endforeach()
if(FIND_PACKAGE_FILE)
include("${FIND_PACKAGE_FILE}")
endif()
endif()

View file

@ -19,7 +19,6 @@ FUNCTION(PREPEND var prefix)
SET(${var} "${listVar}" PARENT_SCOPE)
ENDFUNCTION(PREPEND)
option(DDSC_SHARED "Build DDSC as a shared library" ON)
if(DDSC_SHARED AND ((NOT DEFINED BUILD_SHARED_LIBS) OR BUILD_SHARED_LIBS))
@ -34,6 +33,20 @@ endif()
add_definitions(-DDDSI_INCLUDE_NETWORK_PARTITIONS -DDDSI_INCLUDE_SSM)
option(DDSC_ENABLE_OPENSSL "Enable openssl support" ON)
if(DDSC_ENABLE_OPENSSL)
find_package(OpenSSL)
if(OPENSSL_FOUND)
add_definitions(-DDDSI_INCLUDE_SSL)
target_link_libraries(ddsc PRIVATE OpenSSL::SSL)
if(CMAKE_GENERATOR MATCHES "Visual Studio")
set_target_properties(ddsc PROPERTIES LINK_FLAGS "/ignore:4099")
endif()
else()
message(FATAL_ERROR "To build without openssl support, set DDSC_ENABLE_OPENSSL to OFF")
endif()
endif()
include(ddsi/CMakeLists.txt)
include(ddsc/CMakeLists.txt)

View file

@ -15,14 +15,13 @@
#ifdef DDSI_INCLUDE_SSL
#ifdef _WIN32
/* WinSock2 must be included before openssl headers
otherwise winsock will be used */
/* supposedly WinSock2 must be included before openssl headers otherwise winsock will be used */
#include <WinSock2.h>
#endif
#include <openssl/ssl.h>
void ddsi_ssl_plugin (void);
struct ddsi_ssl_plugins;
void ddsi_ssl_config_plugin (struct ddsi_ssl_plugins *plugin);
#endif
#endif

View file

@ -20,20 +20,17 @@
struct ddsi_ssl_plugins
{
void (*config) (void);
c_bool (*init) (void);
bool (*init) (void);
void (*fini) (void);
void (*ssl_free) (SSL *ssl);
void (*bio_vfree) (BIO *bio);
os_ssize_t (*read) (SSL * ssl, void * buf, os_size_t len, int * err);
os_ssize_t (*write) (SSL * ssl, const void * msg, os_size_t len, int * err);
ssize_t (*read) (SSL *ssl, void *buf, size_t len, int *err);
ssize_t (*write) (SSL *ssl, const void *msg, size_t len, int *err);
SSL * (*connect) (os_socket sock);
BIO * (*listen) (os_socket sock);
SSL * (*accept) (BIO *bio, os_socket *sock);
};
struct ddsi_ssl_plugins ddsi_tcp_ssl_plugin;
#endif
int ddsi_tcp_init (void);

View file

@ -36,7 +36,7 @@ typedef struct ddsi_tran_qos * ddsi_tran_qos_t;
/* Function pointer types */
typedef ssize_t (*ddsi_tran_read_fn_t) (ddsi_tran_conn_t, unsigned char *, size_t, nn_locator_t *);
typedef ssize_t (*ddsi_tran_read_fn_t) (ddsi_tran_conn_t, unsigned char *, size_t, bool, nn_locator_t *);
typedef ssize_t (*ddsi_tran_write_fn_t) (ddsi_tran_conn_t, const nn_locator_t *, size_t, const os_iovec_t *, uint32_t);
typedef int (*ddsi_tran_locator_fn_t) (ddsi_tran_base_t, nn_locator_t *);
typedef bool (*ddsi_tran_supports_fn_t) (int32_t);
@ -220,8 +220,8 @@ inline int ddsi_conn_locator (ddsi_tran_conn_t conn, nn_locator_t * loc) {
inline ssize_t ddsi_conn_write (ddsi_tran_conn_t conn, const nn_locator_t *dst, size_t niov, const os_iovec_t *iov, uint32_t flags) {
return conn->m_closed ? -1 : (conn->m_write_fn) (conn, dst, niov, iov, flags);
}
inline ssize_t ddsi_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, nn_locator_t *srcloc) {
return conn->m_closed ? -1 : conn->m_read_fn (conn, buf, len, srcloc);
inline ssize_t ddsi_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, bool allow_spurious, nn_locator_t *srcloc) {
return conn->m_closed ? -1 : conn->m_read_fn (conn, buf, len, allow_spurious, srcloc);
}
bool ddsi_conn_peer_locator (ddsi_tran_conn_t conn, nn_locator_t * loc);
void ddsi_conn_disable_multiplexing (ddsi_tran_conn_t conn);

View file

@ -213,6 +213,13 @@ enum many_sockets_mode {
MSM_MANY_UNICAST
};
#ifdef DDSI_INCLUDE_SSL
struct ssl_min_version {
int major;
int minor;
};
#endif
struct config
{
int valid;
@ -301,6 +308,7 @@ struct config
char * ssl_rand_file;
char * ssl_key_pass;
char * ssl_ciphers;
struct ssl_min_version ssl_min_version;
#endif

View file

@ -63,7 +63,7 @@ static char *ddsi_raweth_to_string (ddsi_tran_factory_t tran, char *dst, size_t
return dst;
}
static ssize_t ddsi_raweth_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, nn_locator_t *srcloc)
static ssize_t ddsi_raweth_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, bool allow_spurious, nn_locator_t *srcloc)
{
int err;
ssize_t ret;
@ -71,6 +71,7 @@ static ssize_t ddsi_raweth_conn_read (ddsi_tran_conn_t conn, unsigned char * buf
struct sockaddr_ll src;
struct iovec msg_iov;
socklen_t srclen = (socklen_t) sizeof (src);
(void) allow_spurious;
msg_iov.iov_base = (void*) buf;
msg_iov.iov_len = len;

View file

@ -9,16 +9,20 @@
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "os/os.h"
#include "ddsi/ddsi_tcp.h"
#include "ddsi/ddsi_ssl.h"
#include "ddsi/q_config.h"
#include "ddsi/q_log.h"
#include "os/os_heap.h"
#include "ddsi/ddsi_tcp.h"
#ifdef DDSI_INCLUDE_SSL
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/opensslconf.h>
static SSL_CTX *ddsi_ssl_ctx = NULL;
@ -43,128 +47,76 @@ static int ddsi_ssl_verify (int ok, X509_STORE_CTX * store)
int err = X509_STORE_CTX_get_error (store);
/* Check if allowing self-signed certificates */
if
(
config.ssl_self_signed &&
((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ||
(err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN))
)
{
if (config.ssl_self_signed && ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) || (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)))
ok = 1;
}
else
{
X509_NAME_oneline (X509_get_issuer_name (cert), issuer, sizeof (issuer));
DDS_ERROR
(
"tcp/ssl failed to verify certificate from %s : %s\n",
issuer,
X509_verify_cert_error_string (err)
);
DDS_ERROR ("tcp/ssl failed to verify certificate from %s: %s\n", issuer, X509_verify_cert_error_string (err));
}
}
return ok;
}
static os_ssize_t ddsi_ssl_read (SSL * ssl, void * buf, os_size_t len, int * err)
static ssize_t ddsi_ssl_read (SSL *ssl, void *buf, size_t len, int *err)
{
int ret;
assert (len <= INT32_MAX);
if (SSL_get_shutdown (ssl) != 0)
{
return -1;
}
/* Returns -1 on error or 0 on shutdown */
ret = SSL_read (ssl, buf, (int) len);
const int ret = SSL_read (ssl, buf, (int) len);
switch (SSL_get_error (ssl, ret))
{
case SSL_ERROR_NONE:
{
/* Success */
break;
}
return ret;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
{
*err = os_sockEAGAIN;
ret = -1;
break;
}
return -1;
case SSL_ERROR_ZERO_RETURN:
default:
{
/* Connection closed or error */
*err = os_getErrno ();
ret = -1;
break;
return -1;
}
}
return ret;
}
static os_ssize_t ddsi_ssl_write (SSL * ssl, const void * buf, os_size_t len, int * err)
static ssize_t ddsi_ssl_write (SSL *ssl, const void *buf, size_t len, int *err)
{
int ret;
assert(len <= INT32_MAX);
if (SSL_get_shutdown (ssl) != 0)
{
return -1;
}
/* Returns -1 on error or 0 on shutdown */
ret = SSL_write (ssl, buf, (int) len);
const int ret = SSL_write (ssl, buf, (int) len);
switch (SSL_get_error (ssl, ret))
{
case SSL_ERROR_NONE:
{
/* Success */
break;
}
return ret;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
{
*err = os_sockEAGAIN;
ret = -1;
break;
}
return -1;
case SSL_ERROR_ZERO_RETURN:
default:
{
/* Connection closed or error */
*err = os_getErrno ();
ret = -1;
break;
return -1;
}
}
return ret;
}
/* Standard OpenSSL init and thread support routines. See O'Reilly. */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static unsigned long ddsi_ssl_id (void)
{
return os_threadIdToInteger (os_threadIdSelf ());
return (unsigned long) os_threadIdToInteger (os_threadIdSelf ());
}
typedef struct CRYPTO_dynlock_value
{
typedef struct CRYPTO_dynlock_value {
os_mutex m_mutex;
}
CRYPTO_dynlock_value;
} CRYPTO_dynlock_value;
static CRYPTO_dynlock_value *ddsi_ssl_locks = NULL;
@ -173,14 +125,10 @@ static void ddsi_ssl_dynlock_lock (int mode, CRYPTO_dynlock_value * lock, const
(void) file;
(void) line;
if (mode & CRYPTO_LOCK)
{
os_mutexLock (&lock->m_mutex);
}
else
{
os_mutexUnlock (&lock->m_mutex);
}
}
static void ddsi_ssl_lock (int mode, int n, const char *file, int line)
{
@ -189,10 +137,9 @@ static void ddsi_ssl_lock (int mode, int n, const char * file, int line)
static CRYPTO_dynlock_value *ddsi_ssl_dynlock_create (const char *file, int line)
{
CRYPTO_dynlock_value * val = os_malloc (sizeof (*val));
(void) file;
(void) line;
CRYPTO_dynlock_value *val = os_malloc (sizeof (*val));
os_mutexInit (&val->m_mutex);
return val;
}
@ -204,130 +151,133 @@ static void ddsi_ssl_dynlock_destroy (CRYPTO_dynlock_value * lock, const char *
os_mutexDestroy (&lock->m_mutex);
os_free (lock);
}
#endif
static int ddsi_ssl_password (char *buf, int num, int rwflag, void *udata)
{
(void) rwflag;
(void) udata;
if ((unsigned int) num < strlen (config.ssl_key_pass) + 1)
{
return (0);
}
if (num < 0 || (size_t) num < strlen (config.ssl_key_pass) + 1)
return 0;
OS_WARNING_MSVC_OFF(4996);
strcpy (buf, config.ssl_key_pass);
OS_WARNING_MSVC_ON(4996);
return (int) strlen (config.ssl_key_pass);
}
static SSL_CTX *ddsi_ssl_ctx_init (void)
{
int i;
SSL_CTX * ctx = SSL_CTX_new (TLSv1_method ());
SSL_CTX *ctx = SSL_CTX_new (SSLv23_method ());
unsigned disallow_TLSv1_2;
/* Load certificates */
if (! SSL_CTX_use_certificate_file (ctx, config.ssl_keystore, SSL_FILETYPE_PEM))
{
DDS_LOG
(
DDS_LC_ERROR | DDS_LC_CONFIG,
"tcp/ssl failed to load certificate from file: %s\n",
config.ssl_keystore
);
DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load certificate from file: %s\n", config.ssl_keystore);
goto fail;
}
/* Set password and callback */
SSL_CTX_set_default_passwd_cb (ctx, ddsi_ssl_password);
/* Get private key */
if (! SSL_CTX_use_PrivateKey_file (ctx, config.ssl_keystore, SSL_FILETYPE_PEM))
{
DDS_LOG
(
DDS_LC_ERROR | DDS_LC_CONFIG,
"tcp/ssl failed to load private key from file: %s\n",
config.ssl_keystore
);
DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load private key from file: %s\n", config.ssl_keystore);
goto fail;
}
/* Load CAs */
if (! SSL_CTX_load_verify_locations (ctx, config.ssl_keystore, 0))
{
DDS_LOG
(
DDS_LC_ERROR | DDS_LC_CONFIG,
"tcp/ssl failed to load CA from file: %s\n",
config.ssl_keystore
);
DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load CA from file: %s\n", config.ssl_keystore);
goto fail;
}
/* Set ciphers */
if (! SSL_CTX_set_cipher_list (ctx, config.ssl_ciphers))
{
DDS_LOG
(
DDS_LC_ERROR | DDS_LC_CONFIG,
"tcp/ssl failed to set ciphers: %s\n",
config.ssl_ciphers
);
DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to set ciphers: %s\n", config.ssl_ciphers);
goto fail;
}
/* Load randomness from file (optional) */
if (config.ssl_rand_file[0] != '\0')
{
if (! RAND_load_file (config.ssl_rand_file, 4096))
{
DDS_LOG
(
DDS_LC_ERROR | DDS_LC_CONFIG,
"tcp/ssl failed to load random seed from file: %s\n",
config.ssl_rand_file
);
DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load random seed from file: %s\n", config.ssl_rand_file);
goto fail;
}
}
/* Set certificate verification policy from configuration */
if (config.ssl_verify)
{
i = SSL_VERIFY_PEER;
if (config.ssl_verify_client)
{
i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
}
SSL_CTX_set_verify (ctx, i, ddsi_ssl_verify);
}
if (!config.ssl_verify)
SSL_CTX_set_verify (ctx, SSL_VERIFY_NONE, NULL);
else
{
SSL_CTX_set_verify (ctx, SSL_VERIFY_NONE, NULL);
int i = SSL_VERIFY_PEER;
if (config.ssl_verify_client)
i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
SSL_CTX_set_verify (ctx, i, ddsi_ssl_verify);
}
SSL_CTX_set_options (ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
switch (config.ssl_min_version.major)
{
case 1:
switch (config.ssl_min_version.minor)
{
case 2:
disallow_TLSv1_2 = 0;
break;
case 3:
#ifdef SSL_OP_NO_TLSv1_2
disallow_TLSv1_2 = SSL_OP_NO_TLSv1_2;
#else
DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl: openssl version does not support disabling TLSv1.2 as required by config\n");
goto fail;
#endif
break;
default:
DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl: can't set minimum requested TLS version to %d.%d\n", config.ssl_min_version.major, config.ssl_min_version.minor);
goto fail;
}
break;
default:
DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl: can't set minimum requested TLS version to %d.%d\n", config.ssl_min_version.major, config.ssl_min_version.minor);
goto fail;
}
SSL_CTX_set_options (ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | disallow_TLSv1_2);
return ctx;
fail:
SSL_CTX_free (ctx);
return NULL;
}
static void dds_report_tls_version (const SSL *ssl, const char *oper)
{
if (ssl)
{
char issuer[256], subject[256];
X509_NAME_oneline (X509_get_issuer_name (SSL_get_peer_certificate (ssl)), issuer, sizeof (issuer));
X509_NAME_oneline (X509_get_subject_name (SSL_get_peer_certificate (ssl)), subject, sizeof (subject));
DDS_TRACE("tcp/ssl %s %s issued by %s [%s]\n", oper, subject, issuer, SSL_get_version (ssl));
}
}
static SSL *ddsi_ssl_connect (os_socket sock)
{
SSL *ssl;
int err;
/* Connect SSL over connected socket */
/* Connect SSL over connected socket; on Win64 a SOCKET is 64-bit type is forced into an int by
the OpenSSL API. Lots of software does use openssl on Win64, so it appears that it is
safe to do so, and moreover, that it will remain safe to do so, given Microsoft's track
record of maintaining backwards compatibility. The SSL API is in the wrong of course ... */
ssl = ddsi_ssl_new ();
OS_WARNING_MSVC_OFF(4244);
SSL_set_fd (ssl, sock);
OS_WARNING_MSVC_ON(4244);
err = SSL_connect (ssl);
if (err != 1)
{
@ -335,13 +285,17 @@ static SSL * ddsi_ssl_connect (os_socket sock)
SSL_free (ssl);
ssl = NULL;
}
dds_report_tls_version (ssl, "connected to");
return ssl;
}
static BIO *ddsi_ssl_listen (os_socket sock)
{
/* See comment in ddsi_ssl_connect concerning casting the socket to an int */
BIO * bio = BIO_new (BIO_s_accept ());
OS_WARNING_MSVC_OFF(4244);
BIO_set_fd (bio, sock, BIO_NOCLOSE);
OS_WARNING_MSVC_ON(4244);
return bio;
}
@ -365,23 +319,29 @@ static SSL * ddsi_ssl_accept (BIO * bio, os_socket * sock)
ssl = NULL;
}
}
dds_report_tls_version (ssl, "accepted from");
return ssl;
}
static c_bool ddsi_ssl_init (void)
static bool ddsi_ssl_init (void)
{
unsigned locks = (unsigned) CRYPTO_num_locks ();
unsigned i;
ddsi_ssl_locks = os_malloc (sizeof (CRYPTO_dynlock_value) * locks);
for (i = 0; i < locks; i++)
{
os_mutexInit (&ddsi_ssl_locks[i].m_mutex);
}
ERR_load_BIO_strings ();
SSL_load_error_strings ();
SSL_library_init ();
OpenSSL_add_all_algorithms ();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
{
const int locks = CRYPTO_num_locks ();
assert (locks >= 0);
ddsi_ssl_locks = os_malloc (sizeof (CRYPTO_dynlock_value) * (size_t) locks);
for (int i = 0; i < locks; i++)
os_mutexInit (&ddsi_ssl_locks[i].m_mutex);
}
#endif
/* Leave these in place: OpenSSL 1.1 defines them as no-op macros that not even reference the symbol,
therefore leaving them in means we get compile time errors if we the library expects the callbacks
to be defined and we somehow failed to detect that previously */
CRYPTO_set_id_callback (ddsi_ssl_id);
CRYPTO_set_locking_callback (ddsi_ssl_lock);
CRYPTO_set_dynlock_create_callback (ddsi_ssl_dynlock_create);
@ -394,43 +354,36 @@ static c_bool ddsi_ssl_init (void)
static void ddsi_ssl_fini (void)
{
unsigned locks = (unsigned) CRYPTO_num_locks ();
unsigned i;
SSL_CTX_free (ddsi_ssl_ctx);
CRYPTO_set_id_callback (NULL);
CRYPTO_set_locking_callback (NULL);
CRYPTO_set_dynlock_create_callback (NULL);
CRYPTO_set_dynlock_lock_callback (NULL);
CRYPTO_set_dynlock_destroy_callback (NULL);
CRYPTO_set_id_callback (0);
CRYPTO_set_locking_callback (0);
CRYPTO_set_dynlock_create_callback (0);
CRYPTO_set_dynlock_lock_callback (0);
CRYPTO_set_dynlock_destroy_callback (0);
ERR_free_strings ();
EVP_cleanup ();
for (i = 0; i < locks; i++)
#if OPENSSL_VERSION_NUMBER < 0x10100000L
{
const int locks = CRYPTO_num_locks ();
for (int i = 0; i < locks; i++)
os_mutexDestroy (&ddsi_ssl_locks[i].m_mutex);
}
os_free (ddsi_ssl_locks);
}
static void ddsi_ssl_config (void)
{
if (config.ssl_enable)
{
ddsi_tcp_ssl_plugin.init = ddsi_ssl_init;
ddsi_tcp_ssl_plugin.fini = ddsi_ssl_fini;
ddsi_tcp_ssl_plugin.ssl_free = SSL_free;
ddsi_tcp_ssl_plugin.bio_vfree = BIO_vfree;
ddsi_tcp_ssl_plugin.read = ddsi_ssl_read;
ddsi_tcp_ssl_plugin.write = ddsi_ssl_write;
ddsi_tcp_ssl_plugin.connect = ddsi_ssl_connect;
ddsi_tcp_ssl_plugin.listen = ddsi_ssl_listen;
ddsi_tcp_ssl_plugin.accept = ddsi_ssl_accept;
}
#endif
}
void ddsi_ssl_plugin (void)
void ddsi_ssl_config_plugin (struct ddsi_ssl_plugins *plugin)
{
ddsi_tcp_ssl_plugin.config = ddsi_ssl_config;
plugin->init = ddsi_ssl_init;
plugin->fini = ddsi_ssl_fini;
plugin->ssl_free = SSL_free;
plugin->bio_vfree = BIO_vfree;
plugin->read = ddsi_ssl_read;
plugin->write = ddsi_ssl_write;
plugin->connect = ddsi_ssl_connect;
plugin->listen = ddsi_ssl_listen;
plugin->accept = ddsi_ssl_accept;
}
#endif /* DDSI_INCLUDE_SSL */

View file

@ -30,16 +30,11 @@ typedef struct ddsi_tran_factory * ddsi_tcp_factory_g_t;
static os_atomic_uint32_t ddsi_tcp_init_g = OS_ATOMIC_UINT32_INIT(0);
#ifdef DDSI_INCLUDE_SSL
struct ddsi_ssl_plugins ddsi_tcp_ssl_plugin =
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
static struct ddsi_ssl_plugins ddsi_tcp_ssl_plugin;
#endif
static const char * ddsi_name = "tcp";
/* Stateless singleton instance handed out as client connection */
static struct ddsi_tran_conn ddsi_tcp_conn_client;
/*
ddsi_tcp_conn: TCP connection for reading and writing. Mutex prevents concurrent
writes to socket. Is reference counted. Peer port is actually contained in peer
@ -74,6 +69,10 @@ typedef struct ddsi_tcp_listener
}
* ddsi_tcp_listener_t;
/* Stateless singleton instance handed out as client connection */
static struct ddsi_tcp_conn ddsi_tcp_conn_client;
static int ddsi_tcp_cmp_conn (const struct ddsi_tcp_conn *c1, const struct ddsi_tcp_conn *c2)
{
const os_sockaddr *a1s = (os_sockaddr *)&c1->m_peer_addr;
@ -348,7 +347,7 @@ OS_WARNING_MSVC_ON(4267);
}
#ifdef DDSI_INCLUDE_SSL
static os_ssize_t ddsi_tcp_conn_read_ssl (ddsi_tcp_conn_t tcp, void * buf, os_size_t len, int * err)
static ssize_t ddsi_tcp_conn_read_ssl (ddsi_tcp_conn_t tcp, void * buf, size_t len, int * err)
{
return (ddsi_tcp_ssl_plugin.read) (tcp->m_ssl, buf, len, err);
}
@ -396,7 +395,7 @@ static int err_is_AGAIN_or_WOULDBLOCK (int err)
return 0;
}
static ssize_t ddsi_tcp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, nn_locator_t *srcloc)
static ssize_t ddsi_tcp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, bool allow_spurious, nn_locator_t *srcloc)
{
ddsi_tcp_conn_t tcp = (ddsi_tcp_conn_t) conn;
ssize_t (*rd) (ddsi_tcp_conn_t, void *, size_t, int * err) = ddsi_tcp_conn_read_plain;
@ -437,11 +436,11 @@ static ssize_t ddsi_tcp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s
{
if (err_is_AGAIN_or_WOULDBLOCK (err))
{
if (ddsi_tcp_select (tcp->m_sock, true, pos) == false)
{
if (allow_spurious && pos == 0)
return 0;
else if (ddsi_tcp_select (tcp->m_sock, true, pos) == false)
break;
}
}
else
{
DDS_LOG(DDS_LC_TCP, "%s read: sock %"PRIsock" error %d\n", ddsi_name, tcp->m_sock, err);
@ -471,7 +470,7 @@ OS_WARNING_MSVC_OFF(4267);
}
#ifdef DDSI_INCLUDE_SSL
static os_ssize_t ddsi_tcp_conn_write_ssl (ddsi_tcp_conn_t conn, const void * buf, os_size_t len, int * err)
static ssize_t ddsi_tcp_conn_write_ssl (ddsi_tcp_conn_t conn, const void * buf, size_t len, int * err)
{
return (ddsi_tcp_ssl_plugin.write) (conn->m_ssl, buf, len, err);
}
@ -541,7 +540,7 @@ static ssize_t ddsi_tcp_conn_write (ddsi_tran_conn_t base, const nn_locator_t *d
{
#ifdef DDSI_INCLUDE_SSL
char msgbuf[4096]; /* stack buffer for merging smallish writes without requiring allocations */
struct iovec iovec; /* iovec used for msgbuf */
os_iovec_t iovec; /* iovec used for msgbuf */
#endif
ssize_t ret;
size_t len;
@ -603,7 +602,7 @@ static ssize_t ddsi_tcp_conn_write (ddsi_tran_conn_t base, const nn_locator_t *d
{
int i;
char * ptr;
iovec.iov_len = len;
iovec.iov_len = (os_iov_len_t) len;
iovec.iov_base = (len <= sizeof (msgbuf)) ? msgbuf : os_malloc (len);
ptr = iovec.iov_base;
for (i = 0; i < (int) msg.msg_iovlen; i++)
@ -732,8 +731,7 @@ static ddsi_tran_conn_t ddsi_tcp_create_conn (uint32_t port, ddsi_tran_qos_t qos
{
(void) qos;
(void) port;
return (ddsi_tran_conn_t) &ddsi_tcp_conn_client;
return &ddsi_tcp_conn_client.m_base;
}
static int ddsi_tcp_listen (ddsi_tran_listener_t listener)
@ -936,7 +934,7 @@ static void ddsi_tcp_conn_delete (ddsi_tcp_conn_t conn)
static void ddsi_tcp_close_conn (ddsi_tran_conn_t tc)
{
if (tc != (ddsi_tran_conn_t) &ddsi_tcp_conn_client)
if (tc != &ddsi_tcp_conn_client.m_base)
{
char buff[DDSI_LOCSTRLEN];
nn_locator_t loc;
@ -952,7 +950,7 @@ static void ddsi_tcp_close_conn (ddsi_tran_conn_t tc)
static void ddsi_tcp_release_conn (ddsi_tran_conn_t conn)
{
if (conn != (ddsi_tran_conn_t) &ddsi_tcp_conn_client)
if (conn != &ddsi_tcp_conn_client.m_base)
{
ddsi_tcp_conn_delete ((ddsi_tcp_conn_t) conn);
}
@ -964,13 +962,6 @@ static void ddsi_tcp_unblock_listener (ddsi_tran_listener_t listener)
os_socket sock;
int ret;
#ifdef DDSI_INCLUDE_SSL
if (ddsi_tcp_ssl_plugin.bio_vfree)
{
(ddsi_tcp_ssl_plugin.bio_vfree) (tl->m_bio);
}
#endif
/* Connect to own listener socket to wake listener from blocking 'accept()' */
ddsi_tcp_sock_new (&sock, 0);
if (sock != OS_INVALID_SOCKET)
@ -1020,6 +1011,12 @@ static void ddsi_tcp_unblock_listener (ddsi_tran_listener_t listener)
static void ddsi_tcp_release_listener (ddsi_tran_listener_t listener)
{
ddsi_tcp_listener_t tl = (ddsi_tcp_listener_t) listener;
#ifdef DDSI_INCLUDE_SSL
if (ddsi_tcp_ssl_plugin.bio_vfree)
{
(ddsi_tcp_ssl_plugin.bio_vfree) (tl->m_bio);
}
#endif
ddsi_tcp_sock_free (tl->m_sock, "listener");
os_free (tl);
}
@ -1097,17 +1094,14 @@ int ddsi_tcp_init (void)
#endif
memset (&ddsi_tcp_conn_client, 0, sizeof (ddsi_tcp_conn_client));
ddsi_tcp_base_init (&ddsi_tcp_conn_client);
ddsi_tcp_base_init (&ddsi_tcp_conn_client.m_base);
#ifdef DDSI_INCLUDE_SSL
if (ddsi_tcp_ssl_plugin.config)
{
(ddsi_tcp_ssl_plugin.config) ();
}
if (ddsi_tcp_ssl_plugin.init)
if (config.ssl_enable)
{
ddsi_name = "tcp/ssl";
if (! (ddsi_tcp_ssl_plugin.init) ())
ddsi_ssl_config_plugin (&ddsi_tcp_ssl_plugin);
if (! ddsi_tcp_ssl_plugin.init ())
{
DDS_ERROR("Failed to initialize OpenSSL\n");
return -1;

View file

@ -31,7 +31,7 @@ extern inline int ddsi_tran_locator (ddsi_tran_base_t base, nn_locator_t * loc);
extern inline int ddsi_listener_locator (ddsi_tran_listener_t listener, nn_locator_t * loc);
extern inline int ddsi_listener_listen (ddsi_tran_listener_t listener);
extern inline ddsi_tran_conn_t ddsi_listener_accept (ddsi_tran_listener_t listener);
extern inline ssize_t ddsi_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, nn_locator_t *srcloc);
extern inline ssize_t ddsi_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, bool allow_spurious, nn_locator_t *srcloc);
extern inline ssize_t ddsi_conn_write (ddsi_tran_conn_t conn, const nn_locator_t *dst, size_t niov, const os_iovec_t *iov, uint32_t flags);
void ddsi_factory_add (ddsi_tran_factory_t factory)
@ -60,10 +60,13 @@ ddsi_tran_factory_t ddsi_factory_find (const char * type)
void ddsi_tran_factories_fini (void)
{
ddsi_tran_factory_t factory;
while ((factory = ddsi_tran_factories) != NULL) {
ddsi_tran_factories = factory->m_factory;
while ((factory = ddsi_tran_factories) != NULL)
{
/* Keep the factory in the list for the duration of "factory_free" so that
conversion of locator kind to factory remains possible. */
ddsi_tran_factory_t next = factory->m_factory;
ddsi_factory_free (factory);
ddsi_tran_factories = next;
}
}

View file

@ -48,7 +48,7 @@ static struct ddsi_udp_config ddsi_udp_config_g;
static struct ddsi_tran_factory ddsi_udp_factory_g;
static os_atomic_uint32_t ddsi_udp_init_g = OS_ATOMIC_UINT32_INIT(0);
static ssize_t ddsi_udp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, nn_locator_t *srcloc)
static ssize_t ddsi_udp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, bool allow_spurious, nn_locator_t *srcloc)
{
int err;
ssize_t ret;
@ -56,6 +56,7 @@ static ssize_t ddsi_udp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s
os_sockaddr_storage src;
os_iovec_t msg_iov;
socklen_t srclen = (socklen_t) sizeof (src);
(void) allow_spurious;
msg_iov.iov_base = (void*) buf;
msg_iov.iov_len = (os_iov_len_t)len; /* Windows uses unsigned, POSIX (except Linux) int */

View file

@ -165,6 +165,9 @@ DUPF(durability_cdr);
DUPF(transport_selector);
DUPF(many_sockets_mode);
DU(deaf_mute);
#ifdef DDSI_INCLUDE_SSL
DUPF(min_tls_version);
#endif
#undef DUPF
#undef DU
#undef PF
@ -679,7 +682,7 @@ static const struct cfgelem ssl_cfgelems[] = {
"<p>This enables SSL/TLS for TCP.</p>" },
{ LEAF("CertificateVerification"), 1, "true", ABSOFF(ssl_verify), 0, uf_boolean, 0, pf_boolean,
"<p>If disabled this allows SSL connections to occur even if an X509 certificate fails verification.</p>" },
{ LEAF("VerifyClient"), 1, "false", ABSOFF(ssl_verify_client), 0, uf_boolean, 0, pf_boolean,
{ LEAF("VerifyClient"), 1, "true", ABSOFF(ssl_verify_client), 0, uf_boolean, 0, pf_boolean,
"<p>This enables an SSL server checking the X509 certificate of a connecting client.</p>" },
{ LEAF("SelfSignedCertificates"), 1, "false", ABSOFF(ssl_self_signed), 0, uf_boolean, 0, pf_boolean,
"<p>This enables the use of self signed X509 certificates.</p>" },
@ -691,6 +694,8 @@ static const struct cfgelem ssl_cfgelems[] = {
"<p>The set of ciphers used by SSL/TLS</p>" },
{ LEAF("EntropyFile"), 1, "", ABSOFF(ssl_rand_file), 0, uf_string, ff_free, pf_string,
"<p>The SSL/TLS random entropy file name.</p>" },
{ LEAF("MinimumTLSVersion"), 1, "1.3", ABSOFF(ssl_min_version), 0, uf_min_tls_version, 0, pf_min_tls_version,
"<p>The minimum TLS version that may be negotiated, valid values are 1.2 and 1.3.</p>" },
END_MARKER
};
#endif
@ -1408,6 +1413,30 @@ static void pf_besmode(struct cfgst *cfgst, void *parent, struct cfgelem const *
cfg_log(cfgst, "%s%s", str, is_default ? " [def]" : "");
}
#ifdef DDSI_INCLUDE_SSL
static int uf_min_tls_version(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value)
{
static const char *vs[] = {
"1.2", "1.3", NULL
};
static const struct ssl_min_version ms[] = {
{1,2}, {1,3}, {0,0}
};
int idx = list_index(vs, value);
struct ssl_min_version *elem = cfg_address(cfgst, parent, cfgelem);
assert(sizeof(vs) / sizeof(*vs) == sizeof(ms) / sizeof(*ms));
if ( idx < 0 )
return cfg_error(cfgst, "'%s': undefined value", value);
*elem = ms[idx];
return 1;
}
static void pf_min_tls_version(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default)
{
struct ssl_min_version *p = cfg_address(cfgst, parent, cfgelem);
cfg_log(cfgst, "%d.%d%s", p->major, p->minor, is_default ? " [def]" : "");
}
#endif
static int uf_durability_cdr(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value)
{

View file

@ -2970,7 +2970,13 @@ static bool do_packet
/* Read in DDSI header plus MSG_LEN sub message that follows it */
sz = ddsi_conn_read (conn, buff, stream_hdr_size, &srcloc);
sz = ddsi_conn_read (conn, buff, stream_hdr_size, true, &srcloc);
if (sz == 0)
{
/* Spurious read -- which at this point is still ok */
nn_rmsg_commit (rmsg);
return true;
}
/* Read in remainder of packet */
@ -2998,7 +3004,7 @@ static bool do_packet
}
else
{
sz = ddsi_conn_read (conn, buff + stream_hdr_size, ml->length - stream_hdr_size, NULL);
sz = ddsi_conn_read (conn, buff + stream_hdr_size, ml->length - stream_hdr_size, false, NULL);
if (sz > 0)
{
sz = (ssize_t) ml->length;
@ -3010,7 +3016,7 @@ static bool do_packet
{
/* Get next packet */
sz = ddsi_conn_read (conn, buff, buff_len, &srcloc);
sz = ddsi_conn_read (conn, buff, buff_len, true, &srcloc);
}
if (sz > 0 && !gv.deaf)