fix and enable SSL support when OpenSSL is available
Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
		
							parent
							
								
									acec84cf0b
								
							
						
					
					
						commit
						f31fba8766
					
				
					 7 changed files with 158 additions and 239 deletions
				
			
		| 
						 | 
				
			
			@ -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,14 @@ endif()
 | 
			
		|||
 | 
			
		||||
add_definitions(-DDDSI_INCLUDE_NETWORK_PARTITIONS -DDDSI_INCLUDE_SSM)
 | 
			
		||||
 | 
			
		||||
find_package(OpenSSL)
 | 
			
		||||
if(OPENSSL_FOUND)
 | 
			
		||||
  add_definitions(-DDDSI_INCLUDE_SSL)
 | 
			
		||||
  include_directories(${OPENSSL_INCLUDE_DIR})
 | 
			
		||||
  target_link_libraries(ddsc PRIVATE ${OPENSSL_LIBRARIES})
 | 
			
		||||
  message(STATUS "Using OpenSSL ${OPENSSL_VERSION} at ${OPENSSL_INCLUDE_DIR}")
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
include(ddsi/CMakeLists.txt)
 | 
			
		||||
include(ddsc/CMakeLists.txt)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
  void (*ssl_free) (SSL *ssl);
 | 
			
		||||
  void (*bio_vfree) (BIO *bio);
 | 
			
		||||
  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);
 | 
			
		||||
  SSL * (*accept) (BIO *bio, os_socket *sock);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ddsi_ssl_plugins ddsi_tcp_ssl_plugin;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int ddsi_tcp_init (void);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,323 +9,242 @@
 | 
			
		|||
 *
 | 
			
		||||
 * 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;
 | 
			
		||||
static SSL_CTX *ddsi_ssl_ctx = NULL;
 | 
			
		||||
 | 
			
		||||
static SSL * ddsi_ssl_new (void)
 | 
			
		||||
static SSL *ddsi_ssl_new (void)
 | 
			
		||||
{
 | 
			
		||||
  return SSL_new (ddsi_ssl_ctx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsi_ssl_error (SSL * ssl, const char * str, int err)
 | 
			
		||||
static void ddsi_ssl_error (SSL *ssl, const char *str, int err)
 | 
			
		||||
{
 | 
			
		||||
  char buff [128];
 | 
			
		||||
  char buff[128];
 | 
			
		||||
  ERR_error_string ((unsigned) SSL_get_error (ssl, err), buff);
 | 
			
		||||
  DDS_ERROR("tcp/ssl %s %s %d\n", str, buff, err);
 | 
			
		||||
  DDS_ERROR ("tcp/ssl %s %s %d\n", str, buff, err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ddsi_ssl_verify (int ok, X509_STORE_CTX * store)
 | 
			
		||||
static int ddsi_ssl_verify (int ok, X509_STORE_CTX *store)
 | 
			
		||||
{
 | 
			
		||||
  if (!ok)
 | 
			
		||||
  {
 | 
			
		||||
    char issuer[256];
 | 
			
		||||
    X509 * cert = X509_STORE_CTX_get_current_cert (store);
 | 
			
		||||
    X509 *cert = X509_STORE_CTX_get_current_cert (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;
 | 
			
		||||
static CRYPTO_dynlock_value *ddsi_ssl_locks = NULL;
 | 
			
		||||
 | 
			
		||||
static void ddsi_ssl_dynlock_lock (int mode, CRYPTO_dynlock_value * lock, const char * file, int line)
 | 
			
		||||
static void ddsi_ssl_dynlock_lock (int mode, CRYPTO_dynlock_value *lock, const char *file, int line)
 | 
			
		||||
{
 | 
			
		||||
  (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)
 | 
			
		||||
static void ddsi_ssl_lock (int mode, int n, const char *file, int line)
 | 
			
		||||
{
 | 
			
		||||
  ddsi_ssl_dynlock_lock (mode, &ddsi_ssl_locks[n], file, line);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static CRYPTO_dynlock_value * ddsi_ssl_dynlock_create (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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsi_ssl_dynlock_destroy (CRYPTO_dynlock_value * lock, const char * file, int line)
 | 
			
		||||
static void ddsi_ssl_dynlock_destroy (CRYPTO_dynlock_value *lock, const char *file, int line)
 | 
			
		||||
{
 | 
			
		||||
  (void) file;
 | 
			
		||||
  (void) line;
 | 
			
		||||
  os_mutexDestroy (&lock->m_mutex);
 | 
			
		||||
  os_free (lock);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int ddsi_ssl_password (char * buf, int num, int rwflag, void * udata)
 | 
			
		||||
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)
 | 
			
		||||
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 ());
 | 
			
		||||
 | 
			
		||||
  /* 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);
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
  return ctx;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
 | 
			
		||||
  SSL_CTX_free (ctx);
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SSL * ddsi_ssl_connect (os_socket sock)
 | 
			
		||||
static void dds_report_tls_version (const SSL *ssl, const char *oper)
 | 
			
		||||
{
 | 
			
		||||
  SSL * ssl;
 | 
			
		||||
  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 */
 | 
			
		||||
 | 
			
		||||
  ssl = ddsi_ssl_new ();
 | 
			
		||||
  SSL_set_fd (ssl, sock);
 | 
			
		||||
  err = SSL_connect (ssl);
 | 
			
		||||
| 
						 | 
				
			
			@ -335,20 +254,21 @@ 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)
 | 
			
		||||
static BIO *ddsi_ssl_listen (os_socket sock)
 | 
			
		||||
{
 | 
			
		||||
  BIO * bio = BIO_new (BIO_s_accept ());
 | 
			
		||||
  BIO_set_fd (bio, sock, BIO_NOCLOSE);
 | 
			
		||||
  return bio;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SSL * ddsi_ssl_accept (BIO * bio, os_socket * sock)
 | 
			
		||||
static SSL *ddsi_ssl_accept (BIO *bio, os_socket *sock)
 | 
			
		||||
{
 | 
			
		||||
  SSL * ssl = NULL;
 | 
			
		||||
  BIO * nbio;
 | 
			
		||||
  SSL *ssl = NULL;
 | 
			
		||||
  BIO *nbio;
 | 
			
		||||
  int err;
 | 
			
		||||
 | 
			
		||||
  if (BIO_do_accept (bio) > 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -365,23 +285,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 +320,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
 | 
			
		||||
  {
 | 
			
		||||
    os_mutexDestroy (&ddsi_ssl_locks[i].m_mutex);
 | 
			
		||||
    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);
 | 
			
		||||
  }
 | 
			
		||||
  os_free (ddsi_ssl_locks);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsi_ssl_config (void)
 | 
			
		||||
void ddsi_ssl_config_plugin (struct ddsi_ssl_plugins *plugin)
 | 
			
		||||
{
 | 
			
		||||
  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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsi_ssl_plugin (void)
 | 
			
		||||
{
 | 
			
		||||
  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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,12 +59,15 @@ 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;
 | 
			
		||||
        ddsi_factory_free(factory);
 | 
			
		||||
    }
 | 
			
		||||
  ddsi_tran_factory_t 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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ddsi_tran_factory_t ddsi_factory_find_with_len (const char * type, size_t len)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -679,7 +679,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>" },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue