Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

problem: unsecured websocket is rarely used in production #3695

Merged
merged 1 commit into from
Oct 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ test_xpub_verbose
test_mock_pub_sub
test_proxy_hwm
test_ws_transport
test_wss_transport
unittest_ip_resolver
unittest_mtrie
unittest_poller
Expand Down
11 changes: 10 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,14 @@ matrix:
apt:
packages:
- lcov
- env: BUILD_TYPE=valgrind CURVE=tweetnacl DRAFT=enabled
- env: BUILD_TYPE=valgrind CURVE=tweetnacl DRAFT=enabled TLS=enabled
os: linux
dist: xenial
addons:
apt:
packages:
- valgrind
- libgnutls-dev
- env: BUILD_TYPE=default CURVE=libsodium GSSAPI=enabled PGM=enabled NORM=enabled
os: linux
addons:
Expand All @@ -70,6 +72,13 @@ matrix:
- libsodium-dev
- asciidoc
- xmlto
- env: BUILD_TYPE=default DRAFT=enabled TLS=enabled
os: linux
dist: xenial
addons:
apt:
packages:
- libgnutls-dev
- env: BUILD_TYPE=default CURVE=libsodium DRAFT=enabled GSSAPI=enabled PGM=enabled NORM=enabled TIPC=enabled USE_NSS=yes
os: linux
addons:
Expand Down
21 changes: 20 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,12 @@ src_libzmq_la_SOURCES += \
external/sha1/sha1.h
endif

if HAVE_WSS
src_libzmq_la_SOURCES += \
src/wss_engine.cpp \
src/wss_engine.hpp
endif

if ON_MINGW
src_libzmq_la_LDFLAGS = \
-no-undefined \
Expand Down Expand Up @@ -342,11 +348,16 @@ src_libzmq_la_CXXFLAGS = @LIBZMQ_EXTRA_CXXFLAGS@ $(CODE_COVERAGE_CXXFLAGS) \
$(LIBUNWIND_CFLAGS)
src_libzmq_la_LIBADD = $(CODE_COVERAGE_LDFLAGS) $(LIBUNWIND_LIBS)

if HAVE_WS
if USE_NSS
src_libzmq_la_CPPFLAGS += ${NSS3_CFLAGS}
src_libzmq_la_LIBADD += ${NSS3_LIBS}
endif

if USE_GNUTLS
src_libzmq_la_CPPFLAGS += ${GNUTLS_CFLAGS}
src_libzmq_la_LIBADD += ${GNUTLS_LIBS}
endif

if USE_LIBSODIUM
src_libzmq_la_CPPFLAGS += ${sodium_CFLAGS}
src_libzmq_la_LIBADD += ${sodium_LIBS}
Expand Down Expand Up @@ -850,6 +861,14 @@ tests_test_ws_transport_LDADD = ${TESTUTIL_LIBS} src/libzmq.la ${NSS3_LIBS}
tests_test_ws_transport_CPPFLAGS = ${TESTUTIL_CPPFLAGS} ${NSS3_CFLAGS}
endif

if HAVE_WSS
test_apps += \
tests/test_wss_transport
tests_test_wss_transport_SOURCES = tests/test_wss_transport.cpp
tests_test_wss_transport_LDADD = ${TESTUTIL_LIBS} src/libzmq.la ${GNUTLS_LIBS}
tests_test_wss_transport_CPPFLAGS = ${TESTUTIL_CPPFLAGS} ${GNUTLS_CFLAGS}
endif

if !ON_MINGW
if !ON_CYGWIN
test_apps += \
Expand Down
4 changes: 4 additions & 0 deletions builds/valgrind/ci_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ CONFIG_OPTS+=("PKG_CONFIG_PATH=${BUILD_PREFIX}/lib/pkgconfig")
CONFIG_OPTS+=("--prefix=${BUILD_PREFIX}")
CONFIG_OPTS+=("--enable-valgrind")

if [ -n "$TLS" ] && [ "$TLS" == "enabled" ]; then
CONFIG_OPTS+=("--with-tls=yes")
fi

if [ -z $CURVE ]; then
CONFIG_OPTS+=("--disable-curve")
elif [ $CURVE == "libsodium" ]; then
Expand Down
4 changes: 4 additions & 0 deletions ci_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ if [ $BUILD_TYPE == "default" ]; then
CONFIG_OPTS+=("--with-poller=${POLLER}")
fi

if [ -n "$TLS" ] && [ "$TLS" == "enabled" ]; then
CONFIG_OPTS+=("--with-tls=yes")
fi

if [ -z $DRAFT ] || [ $DRAFT == "disabled" ]; then
CONFIG_OPTS+=("--enable-drafts=no")
elif [ $DRAFT == "enabled" ]; then
Expand Down
33 changes: 24 additions & 9 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -553,36 +553,51 @@ AM_CONDITIONAL(HAVE_CURVE, test "x$curve_library" != "x")
AM_CONDITIONAL(USE_WEPOLL, test "$poller" = "wepoll")

# Check requiring packages for WebSocket
sha1_library=""
ws_crypto_library=""

AC_ARG_ENABLE([ws],
[AS_HELP_STRING([--disable-ws], [Disable WebSocket transport [default=no]])])

AC_ARG_WITH([nss],
[AS_HELP_STRING([--with-nss], [use nss instead of built-in sha1 [default=no]])])

AC_ARG_WITH([tls],
[AS_HELP_STRING([--with-tls], [Enable TLS (WSS transport) [default=no]])])

if test "x$enable_ws" != "xno"; then
if test "x$with_nss" = "xyes"; then
if test "x$with_tls" = "xyes"; then
PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.1.4], [
ws_crypto_library="gnutls"
AC_DEFINE(ZMQ_USE_GNUTLS, [1], [Use GNUTLS for TLS])
AC_DEFINE(ZMQ_HAVE_WS, [1], [Using websocket])
AC_DEFINE(ZMQ_HAVE_WSS, [1], [WSS enabled])
AC_MSG_NOTICE(Using gnutls)
],[
AC_MSG_ERROR([GnuTLS is not installed. Install it, then run configure again])
])
elif test "x$with_nss" = "xyes"; then
PKG_CHECK_MODULES([NSS3], [nss], [
PKGCFG_NAMES_PRIVATE="$PKGCFG_NAMES_PRIVATE nss"
AC_DEFINE(ZMQ_USE_NSS, [1], [Using NSS])
AC_DEFINE(ZMQ_HAVE_WS, [1], [Using websocket])
sha1_library="nss"
ws_crypto_library="nss"
AC_MSG_NOTICE(Using NSS)
], [
AC_MSG_ERROR(nss is not installed. Install it, then run configure again)
AC_MSG_ERROR([nss is not installed. Install it, then run configure again])
])
else
AC_DEFINE(ZMQ_USE_BUILTIN_SHA1, [1], [Using built-in sha1])
AC_DEFINE(ZMQ_HAVE_WS, [1], [Using websocket])
sha1_library="builtin"
AC_DEFINE(ZMQ_USE_BUILTIN_SHA1, [1], [Using built-in sha1])
AC_MSG_NOTICE(Using builting SHA1)
ws_crypto_library="builtin"
fi
fi

AM_CONDITIONAL(HAVE_WS, test "x$sha1_library" != "x")
AM_CONDITIONAL(USE_NSS, test "x$sha1_library" = "xnss")
AM_CONDITIONAL(USE_BUILTIN_SHA1, test "x$sha1_library" = "xbuiltin")
AM_CONDITIONAL(HAVE_WS, test "x$ws_crypto_library" != "x")
AM_CONDITIONAL(USE_NSS, test "x$ws_crypto_library" = "xnss")
AM_CONDITIONAL(USE_BUILTIN_SHA1, test "x$ws_crypto_library" = "xbuiltin")
AM_CONDITIONAL(USE_GNUTLS, test "x$ws_crypto_library" = "xgnutls")
AM_CONDITIONAL(HAVE_WSS, test "x$ws_crypto_library" = "xgnutls")

# build using pgm
have_pgm_library="no"
Expand Down
6 changes: 6 additions & 0 deletions include/zmq.h
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,12 @@ ZMQ_EXPORT void zmq_threadclose (void *thread_);
#define ZMQ_SOCKS_PASSWORD 100
#define ZMQ_IN_BATCH_SIZE 101
#define ZMQ_OUT_BATCH_SIZE 102
#define ZMQ_WSS_KEY_PEM 103
#define ZMQ_WSS_CERT_PEM 104
#define ZMQ_WSS_TRUST_PEM 105
#define ZMQ_WSS_HOSTNAME 106
#define ZMQ_WSS_TRUST_SYSTEM 107


/* DRAFT Context options */
#define ZMQ_ZERO_COPY_RECV 10
Expand Down
10 changes: 10 additions & 0 deletions src/address.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ zmq::address_t::~address_t ()
}
#endif

#ifdef ZMQ_HAVE_WSS
else if (protocol == protocol_name::wss) {
LIBZMQ_DELETE (resolved.ws_addr);
}
#endif

#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
&& !defined ZMQ_HAVE_VXWORKS
else if (protocol == protocol_name::ipc) {
Expand Down Expand Up @@ -96,6 +102,10 @@ int zmq::address_t::to_string (std::string &addr_) const
if (protocol == protocol_name::ws && resolved.ws_addr)
return resolved.ws_addr->to_string (addr_);
#endif
#ifdef ZMQ_HAVE_WSS
if (protocol == protocol_name::wss && resolved.ws_addr)
return resolved.ws_addr->to_string (addr_);
#endif
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
&& !defined ZMQ_HAVE_VXWORKS
if (protocol == protocol_name::ipc && resolved.ipc_addr)
Expand Down
3 changes: 3 additions & 0 deletions src/address.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ static const char udp[] = "udp";
#ifdef ZMQ_HAVE_WS
static const char ws[] = "ws";
#endif
#ifdef ZMQ_HAVE_WSS
static const char wss[] = "wss";
#endif
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
&& !defined ZMQ_HAVE_VXWORKS
static const char ipc[] = "ipc";
Expand Down
12 changes: 12 additions & 0 deletions src/ctx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
#include <nss.h>
#endif

#ifdef ZMQ_USE_GNUTLS
#include <gnutls/gnutls.h>
#endif

#define ZMQ_CTX_TAG_VALUE_GOOD 0xabadcafe
#define ZMQ_CTX_TAG_VALUE_BAD 0xdeadbeef

Expand Down Expand Up @@ -95,6 +99,10 @@ zmq::ctx_t::ctx_t () :
#ifdef ZMQ_USE_NSS
NSS_NoDB_Init (NULL);
#endif

#ifdef ZMQ_USE_GNUTLS
gnutls_global_init ();
#endif
}

bool zmq::ctx_t::check_tag ()
Expand Down Expand Up @@ -131,6 +139,10 @@ zmq::ctx_t::~ctx_t ()
NSS_Shutdown ();
#endif

#ifdef ZMQ_USE_GNUTLS
gnutls_global_deinit ();
#endif

// Remove the tag, so that the object is considered dead.
_tag = ZMQ_CTX_TAG_VALUE_BAD;
}
Expand Down
23 changes: 22 additions & 1 deletion src/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ zmq::options_t::options_t () :
out_batch_size (8192),
zero_copy (true),
router_notify (0),
monitor_event_version (1)
monitor_event_version (1),
wss_trust_system (false)
{
memset (curve_public_key, 0, CURVE_KEYSIZE);
memset (curve_secret_key, 0, CURVE_KEYSIZE);
Expand Down Expand Up @@ -784,6 +785,26 @@ int zmq::options_t::setsockopt (int option_,
return 0;
}
break;

case ZMQ_WSS_KEY_PEM:
// TODO: check if valid certificate
wss_key_pem = std::string ((char *) optval_, optvallen_);
return 0;
case ZMQ_WSS_CERT_PEM:
// TODO: check if valid certificate
wss_cert_pem = std::string ((char *) optval_, optvallen_);
return 0;
case ZMQ_WSS_TRUST_PEM:
// TODO: check if valid certificate
wss_trust_pem = std::string ((char *) optval_, optvallen_);
return 0;
case ZMQ_WSS_HOSTNAME:
wss_hostname = std::string ((char *) optval_, optvallen_);
return 0;
case ZMQ_WSS_TRUST_SYSTEM:
return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
&wss_trust_system);

#endif

default:
Expand Down
7 changes: 7 additions & 0 deletions src/options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,13 @@ struct options_t

// Version of monitor events to emit
int monitor_event_version;

// WSS Keys
std::string wss_key_pem;
std::string wss_cert_pem;
std::string wss_trust_pem;
std::string wss_hostname;
bool wss_trust_system;
};

inline bool get_effective_conflate_option (const options_t &options)
Expand Down
26 changes: 24 additions & 2 deletions src/session_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,14 @@ zmq::session_base_t::session_base_t (class io_thread_t *io_thread_,
_socket (socket_),
_io_thread (io_thread_),
_has_linger_timer (false),
_addr (addr_)
_addr (addr_),
_wss_hostname (NULL)
{
if (options_.wss_hostname.length () > 0) {
_wss_hostname = (char *) malloc (options_.wss_hostname.length () + 1);
assert (_wss_hostname);
strcpy (_wss_hostname, options_.wss_hostname.c_str ());
somdoron marked this conversation as resolved.
Show resolved Hide resolved
}
}

const zmq::endpoint_uri_pair_t &zmq::session_base_t::get_endpoint () const
Expand All @@ -138,6 +144,9 @@ zmq::session_base_t::~session_base_t ()
if (_engine)
_engine->terminate ();

if (_wss_hostname)
free (_wss_hostname);

LIBZMQ_DELETE (_addr);
}

Expand Down Expand Up @@ -563,6 +572,10 @@ zmq::session_base_t::connecter_factory_entry_t
connecter_factory_entry_t (protocol_name::ws,
&zmq::session_base_t::create_connecter_ws),
#endif
#ifdef ZMQ_HAVE_WSS
connecter_factory_entry_t (protocol_name::wss,
&zmq::session_base_t::create_connecter_wss),
#endif
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
&& !defined ZMQ_HAVE_VXWORKS
connecter_factory_entry_t (protocol_name::ipc,
Expand Down Expand Up @@ -690,7 +703,16 @@ zmq::own_t *zmq::session_base_t::create_connecter_ws (io_thread_t *io_thread_,
bool wait_)
{
return new (std::nothrow)
ws_connecter_t (io_thread_, this, options, _addr, wait_);
ws_connecter_t (io_thread_, this, options, _addr, wait_, false, NULL);
}
#endif

#ifdef ZMQ_HAVE_WSS
zmq::own_t *zmq::session_base_t::create_connecter_wss (io_thread_t *io_thread_,
bool wait_)
{
return new (std::nothrow) ws_connecter_t (io_thread_, this, options, _addr,
wait_, true, _wss_hostname);
}
#endif

Expand Down
5 changes: 5 additions & 0 deletions src/session_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ class session_base_t : public own_t, public io_object_t, public i_pipe_events
own_t *create_connecter_ipc (io_thread_t *io_thread_, bool wait_);
own_t *create_connecter_tcp (io_thread_t *io_thread_, bool wait_);
own_t *create_connecter_ws (io_thread_t *io_thread_, bool wait_);
own_t *create_connecter_wss (io_thread_t *io_thread_, bool wait_);

typedef void (session_base_t::*start_connecting_fun_t) (
io_thread_t *io_thread);
Expand Down Expand Up @@ -191,6 +192,10 @@ class session_base_t : public own_t, public io_object_t, public i_pipe_events
// Protocol and address to use when connecting.
address_t *_addr;

// TLS handshake, we need to take a copy when the session is created,
// in order to maintain the value at the creation time
char *_wss_hostname;

session_base_t (const session_base_t &);
const session_base_t &operator= (const session_base_t &);
};
Expand Down
Loading