THRIFT-3369 Provide SSL/TLS client for c_glib
Client: c_glib
Patch: Gonzalo Aguilar Delgado <gaguilar@level2crm.com>
This closes #1185
diff --git a/.gitignore b/.gitignore
index 0a98a13..288f1b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -150,6 +150,7 @@
/lib/c_glib/test/testframedtransport
/lib/c_glib/test/testmemorybuffer
/lib/c_glib/test/testoptionalrequired
+/lib/c_glib/test/testtransportsslsocket
/lib/c_glib/test/testsimpleserver
/lib/c_glib/test/teststruct
/lib/c_glib/test/testthrifttest
@@ -215,6 +216,8 @@
/lib/haxe/test/bin
/lib/hs/dist
/lib/java/build
+/lib/js/dist
+/lib/js/doc
/lib/js/test/build
/lib/netcore/**/.vs
/lib/netcore/**/bin
diff --git a/configure.ac b/configure.ac
index 8a15ede..09c6d9e 100755
--- a/configure.ac
+++ b/configure.ac
@@ -132,7 +132,6 @@
with_rs="no"
fi
-
AX_THRIFT_LIB(cpp, [C++], yes)
have_cpp=no
if test "$with_cpp" = "yes"; then
@@ -147,8 +146,6 @@
have_cpp="yes"
fi
- AX_CHECK_OPENSSL()
-
AX_LIB_EVENT([1.0])
have_libevent=$success
@@ -199,6 +196,12 @@
fi
AM_CONDITIONAL(WITH_C_GLIB, [test "$have_glib2" = "yes" -a "$have_gobject2" = "yes"])
+echo "OpenSSL check"
+if test "$have_cpp" = "yes" -o "$have_c_glib" = "yes"; then
+ echo "Have cpp or c so we check for OpenSSL"
+ AX_CHECK_OPENSSL()
+fi
+
AX_THRIFT_LIB(csharp, [C#], yes)
if test "$with_csharp" = "yes"; then
PKG_CHECK_MODULES(MONO, mono >= 2.11.0, mono_2_11=yes, mono_2_11=no)
diff --git a/lib/c_glib/CMakeLists.txt b/lib/c_glib/CMakeLists.txt
index dd9892c..5e277f0 100644
--- a/lib/c_glib/CMakeLists.txt
+++ b/lib/c_glib/CMakeLists.txt
@@ -54,6 +54,17 @@
src/thrift/c_glib/server/thrift_simple_server.c
)
+# If OpenSSL is not found just ignore the OpenSSL stuff
+find_package(OpenSSL)
+if(OPENSSL_FOUND AND WITH_OPENSSL)
+ list( APPEND thriftcpp_SOURCES
+ src/thrift/c_glib/transport/thrift_ssl_socket.c
+ )
+ include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
+ list(APPEND SYSLIBS "${OPENSSL_LIBRARIES}")
+endif()
+
+
# Contains the thrift specific ADD_LIBRARY_THRIFT and TARGET_LINK_LIBRARIES_THRIFT
include(ThriftMacros)
diff --git a/lib/c_glib/Makefile.am b/lib/c_glib/Makefile.am
index 452f6a4..b66c89b 100755
--- a/lib/c_glib/Makefile.am
+++ b/lib/c_glib/Makefile.am
@@ -45,6 +45,7 @@
src/thrift/c_glib/transport/thrift_buffered_transport_factory.c \
src/thrift/c_glib/transport/thrift_framed_transport_factory.c \
src/thrift/c_glib/transport/thrift_socket.c \
+ src/thrift/c_glib/transport/thrift_ssl_socket.c \
src/thrift/c_glib/transport/thrift_server_transport.c \
src/thrift/c_glib/transport/thrift_server_socket.c \
src/thrift/c_glib/transport/thrift_buffered_transport.c \
@@ -54,7 +55,8 @@
src/thrift/c_glib/server/thrift_server.c \
src/thrift/c_glib/server/thrift_simple_server.c
-libthrift_c_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS)
+libthrift_c_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(OPENSSL_INCLUDES)
+libthrift_c_glib_la_LDFLAGS = $(AM_LDFLAGS) $(OPENSSL_LDFLAGS) $(OPENSSL_LIBS)
include_thriftdir = $(includedir)/thrift/c_glib
include_thrift_HEADERS = \
@@ -79,6 +81,8 @@
src/thrift/c_glib/transport/thrift_server_socket.h \
src/thrift/c_glib/transport/thrift_server_transport.h \
src/thrift/c_glib/transport/thrift_socket.h \
+ src/thrift/c_glib/transport/thrift_platform_socket.h \
+ src/thrift/c_glib/transport/thrift_ssl_socket.h \
src/thrift/c_glib/transport/thrift_transport.h \
src/thrift/c_glib/transport/thrift_transport_factory.h \
src/thrift/c_glib/transport/thrift_buffered_transport_factory.h \
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_platform_socket.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_platform_socket.h
new file mode 100644
index 0000000..ef4f00d
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_platform_socket.h
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// clang-format off
+
+#ifndef _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_
+# define _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_
+
+#ifdef _WIN32
+# define THRIFT_GET_SOCKET_ERROR ::WSAGetLastError()
+# define THRIFT_ERRNO (*_errno())
+# define THRIFT_EINPROGRESS WSAEINPROGRESS
+# define THRIFT_EAGAIN WSAEWOULDBLOCK
+# define THRIFT_EINTR WSAEINTR
+# define THRIFT_ECONNRESET WSAECONNRESET
+# define THRIFT_ENOTCONN WSAENOTCONN
+# define THRIFT_ETIMEDOUT WSAETIMEDOUT
+# define THRIFT_EWOULDBLOCK WSAEWOULDBLOCK
+# define THRIFT_EPIPE WSAECONNRESET
+# define THRIFT_NO_SOCKET_CACHING SO_EXCLUSIVEADDRUSE
+# define THRIFT_INVALID_SOCKET INVALID_SOCKET
+# define THRIFT_SOCKETPAIR thrift_socketpair
+# define THRIFT_FCNTL thrift_fcntl
+# define THRIFT_O_NONBLOCK 1
+# define THRIFT_F_GETFL 0
+# define THRIFT_F_SETFL 1
+# define THRIFT_GETTIMEOFDAY thrift_gettimeofday
+# define THRIFT_CLOSESOCKET closesocket
+# define THRIFT_CLOSE _close
+# define THRIFT_OPEN _open
+# define THRIFT_FTRUNCATE _chsize_s
+# define THRIFT_FSYNC _commit
+# define THRIFT_LSEEK _lseek
+# define THRIFT_WRITE _write
+# define THRIFT_READ _read
+# define THRIFT_FSTAT _fstat
+# define THRIFT_STAT _stat
+# ifdef _WIN32_WCE
+# define THRIFT_GAI_STRERROR(...) thrift_wstr2str(gai_strerrorW(__VA_ARGS__))
+# else
+# define THRIFT_GAI_STRERROR gai_strerrorA
+# endif
+# define THRIFT_SSIZET ptrdiff_t
+# define THRIFT_SNPRINTF _snprintf
+# define THRIFT_SLEEP_SEC thrift_sleep
+# define THRIFT_SLEEP_USEC thrift_usleep
+# define THRIFT_TIMESPEC thrift_timespec
+# define THRIFT_CTIME_R thrift_ctime_r
+# define THRIFT_POLL thrift_poll
+# if WINVER <= 0x0502 //XP, Server2003
+# define THRIFT_POLLFD thrift_pollfd
+# define THRIFT_POLLIN 0x0300
+# define THRIFT_POLLOUT 0x0010
+# else //Vista, Win7...
+# define THRIFT_POLLFD pollfd
+# define THRIFT_POLLIN POLLIN
+# define THRIFT_POLLOUT POLLOUT
+# endif //WINVER
+# define THRIFT_SHUT_RDWR SD_BOTH
+#else //not _WIN32
+# include <errno.h>
+# define THRIFT_GET_SOCKET_ERROR errno
+# define THRIFT_ERRNO errno
+# define THRIFT_EINTR EINTR
+# define THRIFT_EINPROGRESS EINPROGRESS
+# define THRIFT_ECONNRESET ECONNRESET
+# define THRIFT_ENOTCONN ENOTCONN
+# define THRIFT_ETIMEDOUT ETIMEDOUT
+# define THRIFT_EWOULDBLOCK EWOULDBLOCK
+# define THRIFT_EAGAIN EAGAIN
+# define THRIFT_EPIPE EPIPE
+# define THRIFT_NO_SOCKET_CACHING SO_REUSEADDR
+# define THRIFT_INVALID_SOCKET (-1)
+# define THRIFT_SOCKETPAIR socketpair
+# define THRIFT_FCNTL fcntl
+# define THRIFT_O_NONBLOCK O_NONBLOCK
+# define THRIFT_F_GETFL F_GETFL
+# define THRIFT_F_SETFL F_SETFL
+# define THRIFT_GETTIMEOFDAY gettimeofday
+# define THRIFT_CLOSESOCKET close
+# define THRIFT_CLOSE close
+# define THRIFT_OPEN open
+# define THRIFT_FTRUNCATE ftruncate
+# define THRIFT_FSYNC fsync
+# define THRIFT_LSEEK lseek
+# define THRIFT_WRITE write
+# define THRIFT_READ read
+# define THRIFT_STAT stat
+# define THRIFT_FSTAT fstat
+# define THRIFT_GAI_STRERROR gai_strerror
+# define THRIFT_SSIZET ssize_t
+# define THRIFT_SNPRINTF snprintf
+# define THRIFT_SLEEP_SEC sleep
+# define THRIFT_SLEEP_USEC usleep
+# define THRIFT_TIMESPEC timespec
+# define THRIFT_CTIME_R ctime_r
+# define THRIFT_POLL poll
+# define THRIFT_POLLFD pollfd
+# define THRIFT_POLLIN POLLIN
+# define THRIFT_POLLOUT POLLOUT
+# define THRIFT_SHUT_RDWR SHUT_RDWR
+#endif
+
+#endif // _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c
new file mode 100644
index 0000000..f7c42cc
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c
@@ -0,0 +1,770 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <openssl/ssl.h>
+#include <pthread.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_socket.h>
+#include <thrift/c_glib/transport/thrift_ssl_socket.h>
+
+#if defined(WIN32)
+#define MUTEX_TYPE HANDLE
+#define MUTEX_SETUP(x) (x) = CreateMutex(NULL, FALSE, NULL)
+#define MUTEX_CLEANUP(x) CloseHandle(x)
+#define MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE)
+#define MUTEX_UNLOCK(x) ReleaseMutex(x)
+#else
+#define MUTEX_TYPE pthread_mutex_t
+#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
+#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
+#define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
+#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
+#endif
+
+#define OPENSSL_VERSION_NO_THREAD_ID 0x10000000L
+
+
+/* object properties */
+enum _ThriftSSLSocketProperties
+{
+ PROP_THRIFT_SSL_SOCKET_CONTEXT = 3,
+ PROP_THRIFT_SSL_SELF_SIGNED
+};
+
+/* To hold a global state management of openssl for all instances */
+static gboolean thrift_ssl_socket_openssl_initialized=FALSE;
+/* Should this be keept at class level? */
+static SSL_CTX* thrift_ssl_socket_global_context=NULL;
+/* This array will store all of the mutexes available to OpenSSL. */
+static MUTEX_TYPE *thrift_ssl_socket_global_mutex_buf=NULL;
+
+
+/**
+ * OpenSSL uniq id function.
+ *
+ * @return thread id
+ */
+static unsigned long thrift_ssl_socket_static_id_function(void)
+{
+#if defined(WIN32)
+ return GetCurrentThreadId();
+#else
+ return ((unsigned long) pthread_self());
+#endif
+}
+
+static void thrift_ssl_socket_static_locking_callback(int mode, int n, const char* unk, int id) {
+ if (mode & CRYPTO_LOCK)
+ MUTEX_LOCK(thrift_ssl_socket_global_mutex_buf[n]);
+ else
+ MUTEX_UNLOCK(thrift_ssl_socket_global_mutex_buf[n]);
+}
+
+static int thrift_ssl_socket_static_thread_setup(void)
+{
+ int i;
+
+ thrift_ssl_socket_global_mutex_buf = malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
+ if (!thrift_ssl_socket_global_mutex_buf)
+ return 0;
+ for (i = 0; i < CRYPTO_num_locks( ); i++)
+ MUTEX_SETUP(thrift_ssl_socket_global_mutex_buf[i]);
+ CRYPTO_set_id_callback(thrift_ssl_socket_static_id_function);
+ CRYPTO_set_locking_callback(thrift_ssl_socket_static_locking_callback);
+ return 1;
+}
+
+static int thrift_ssl_socket_static_thread_cleanup(void)
+{
+ int i;
+ if (!thrift_ssl_socket_global_mutex_buf)
+ return 0;
+ CRYPTO_set_id_callback(NULL);
+ CRYPTO_set_locking_callback(NULL);
+ for (i = 0; i < CRYPTO_num_locks( ); i++)
+ MUTEX_CLEANUP(thrift_ssl_socket_global_mutex_buf[i]);
+ free(thrift_ssl_socket_global_mutex_buf);
+ thrift_ssl_socket_global_mutex_buf = NULL;
+ return 1;
+}
+
+/*
+static void* thrift_ssl_socket_dyn_lock_create_callback(const char* unk, int id) {
+ g_print("We should create a lock\n");
+ return NULL;
+}
+
+static void thrift_ssl_socket_dyn_lock_callback(int mode, void* lock, const char* unk, int id) {
+ if (lock != NULL) {
+ if (mode & CRYPTO_LOCK) {
+ g_printf("We should lock thread %d\n");
+ } else {
+ g_printf("We should unlock thread %d\n");
+ }
+ }
+}
+
+static void thrift_ssl_socket_dyn_lock_destroy_callback(void* lock, const char* unk, int id) {
+ g_printf("We must destroy the lock\n");
+}
+ */
+
+
+G_DEFINE_TYPE(ThriftSSLSocket, thrift_ssl_socket, THRIFT_TYPE_SOCKET)
+
+
+/* implements thrift_transport_is_open */
+gboolean
+thrift_ssl_socket_is_open (ThriftTransport *transport)
+{
+ return thrift_socket_is_open(transport);
+}
+
+/* overrides thrift_transport_peek */
+gboolean
+thrift_ssl_socket_peek (ThriftTransport *transport, GError **error)
+{
+ gboolean retval = FALSE;
+ ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+ if (thrift_ssl_socket_is_open (transport))
+ {
+ int rc;
+ gchar byte;
+ rc = SSL_peek(ssl_socket->ssl, &byte, 1);
+ if (rc < 0) {
+ g_set_error (error,
+ THRIFT_TRANSPORT_ERROR,
+ THRIFT_SSL_SOCKET_ERROR_SSL,
+ "failed to peek at socket - id?");
+ }
+ if (rc == 0) {
+ ERR_clear_error();
+ }
+ retval = (rc > 0);
+ }
+ return retval;
+}
+
+/* implements thrift_transport_open */
+gboolean
+thrift_ssl_socket_open (ThriftTransport *transport, GError **error)
+{
+ if (!thrift_socket_open(transport, error)) {
+ return FALSE;
+ }
+
+ if (!THRIFT_SSL_SOCKET_GET_CLASS(transport)->handle_handshake(transport, error)) {
+ GError *tmperr;
+ thrift_socket_close(transport, &tmperr);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* implements thrift_transport_close */
+gboolean
+thrift_ssl_socket_close (ThriftTransport *transport, GError **error)
+{
+ gboolean retval = FALSE;
+ if(THRIFT_SSL_SOCKET(transport)->ssl) {
+ int rc = SSL_shutdown(THRIFT_SSL_SOCKET(transport)->ssl);
+ if (rc < 0) {
+ int errno_copy = THRIFT_SSL_SOCKET_ERROR_SSL;
+ }
+ SSL_free(THRIFT_SSL_SOCKET(transport)->ssl);
+ THRIFT_SSL_SOCKET(transport)->ssl = NULL;
+ ERR_remove_state(0);
+ }
+ return thrift_socket_close(transport, error);
+}
+
+/* implements thrift_transport_read */
+gint32
+thrift_ssl_socket_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ guint maxRecvRetries_ = 10;
+ ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+ guint bytes = 0;
+ guint retries = 0;
+ for (retries=0; retries < maxRecvRetries_; retries++) {
+ bytes = SSL_read(ssl_socket->ssl, buf, len);
+ if (bytes >= 0)
+ break;
+ int errno_copy = THRIFT_GET_SOCKET_ERROR;
+ if (SSL_get_error(ssl_socket->ssl, bytes) == SSL_ERROR_SYSCALL) {
+ if (ERR_get_error() == 0 && errno_copy == THRIFT_EINTR) {
+ continue;
+ }
+ }
+ g_set_error (error, THRIFT_TRANSPORT_ERROR,
+ THRIFT_TRANSPORT_ERROR_RECEIVE,
+ "failed to read %d bytes - %s", len, strerror(errno));
+ return -1;
+ }
+ return bytes;
+}
+
+/* implements thrift_transport_read_end
+ * called when write is complete. nothing to do on our end. */
+gboolean
+thrift_ssl_socket_read_end (ThriftTransport *transport, GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+/* implements thrift_transport_write */
+gboolean
+thrift_ssl_socket_write (ThriftTransport *transport, const gpointer buf,
+ const guint32 len, GError **error)
+{
+ ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+ gint ret = 0;
+ guint sent = 0;
+ ThriftSocket *socket = THRIFT_SSL_SOCKET (transport);
+ g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET, FALSE);
+
+ while (sent < len)
+ {
+ ret = SSL_write (ssl_socket->ssl, (guint8 *)buf + sent, len - sent);
+ if (ret < 0)
+ {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR,
+ THRIFT_TRANSPORT_ERROR_SEND,
+ "failed to send %d bytes - %s", len, strerror(errno));
+ return FALSE;
+ }
+ sent += ret;
+ }
+
+ return sent==len;
+}
+
+/* implements thrift_transport_write_end
+ * called when write is complete. nothing to do on our end. */
+gboolean
+thrift_ssl_socket_write_end (ThriftTransport *transport, GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+/* implements thrift_transport_flush
+ * flush pending data. since we are not buffered, this is a no-op */
+gboolean
+thrift_ssl_socket_flush (ThriftTransport *transport, GError **error)
+{
+ ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+ gint ret = 0;
+ guint sent = 0;
+ BIO* bio = SSL_get_wbio(ssl_socket->ssl);
+ if (bio == NULL) {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR,
+ THRIFT_TRANSPORT_ERROR_SEND,
+ "failed to flush, wbio returned null");
+ return FALSE;
+ }
+ if (BIO_flush(bio) != 1) {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR,
+ THRIFT_TRANSPORT_ERROR_SEND,
+ "failed to flush it returned error");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+gboolean
+thrift_ssl_socket_handle_handshake(ThriftTransport * transport, GError **error)
+{
+ ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+ ThriftSocket *socket = THRIFT_SOCKET (transport);
+ g_return_val_if_fail (thrift_transport_is_open (transport), FALSE);
+
+ if(THRIFT_SSL_SOCKET_GET_CLASS(ssl_socket)->create_ssl_context(transport, error)){
+ /*Context created*/
+ SSL_set_fd(ssl_socket->ssl, socket->sd);
+ int rc;
+ if(ssl_socket->server){
+ rc = SSL_accept(ssl_socket->ssl);
+ }else{
+ rc = SSL_connect(ssl_socket->ssl);
+ }
+ if (rc <= 0) {
+ fprintf(stderr,"The error returned was %d\n", SSL_get_error(ssl_socket->ssl, rc));
+ thrift_ssl_socket_get_error(error, "Not possible to connect", THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE);
+ return FALSE;
+ }
+ }else
+ return FALSE;
+
+ return thrift_ssl_socket_authorize(transport, error);
+}
+
+gboolean
+thrift_ssl_socket_create_ssl_context(ThriftTransport * transport, GError **error)
+{
+ ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (transport);
+
+ if(socket->ctx!=NULL){
+ if(socket->ssl!=NULL) {
+ return TRUE;
+ }
+
+ socket->ssl = SSL_new(socket->ctx);
+ if (socket->ssl == NULL) {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR,
+ THRIFT_SSL_SOCKET_ERROR_TRANSPORT,
+ "Unable to create SSL context");
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ *
+ * @param ssl_socket The ssl socket
+ * @param file_name The file name of the PEM certificate chain
+ * @return
+ */
+gboolean thrift_ssl_load_cert_from_file(ThriftSSLSocket *ssl_socket, const char *file_name)
+{
+ char error_buffer[255];
+ if (!thrift_ssl_socket_openssl_initialized) {
+ g_error("OpenSSL is not initialized yet");
+ return FALSE;
+ }
+ int rc = SSL_CTX_load_verify_locations(ssl_socket->ctx, file_name, NULL);
+ if (rc != 1) { /*verify authentication result*/
+ ERR_error_string_n(ERR_get_error(), error_buffer, 254);
+ g_warning("Load of certificates failed: %s!", error_buffer);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Load a certificate chain from memory
+ * @param ssl_socket the ssl socket
+ * @param chain_certs the buffer to load PEM from
+ * @return
+ */
+gboolean thrift_ssl_load_cert_from_buffer(ThriftSSLSocket *ssl_socket, const char chain_certs[])
+{
+ gboolean retval = FALSE;
+ /* Load chain of certs*/
+ X509 *cacert=NULL;
+ BIO *mem = BIO_new_mem_buf(chain_certs,strlen(chain_certs));
+ X509_STORE *cert_store = SSL_CTX_get_cert_store(ssl_socket->ctx);
+
+ if(cert_store!=NULL){
+ int index = 0;
+ while ((cacert = PEM_read_bio_X509(mem, NULL, 0, NULL))!=NULL) {
+ if(cacert) {
+ g_debug("Our certificate name is %s", cacert->name);
+ X509_STORE_add_cert(cert_store, cacert);
+ X509_free(cacert);
+ cacert=NULL;
+ } /* Free immediately */
+ index++;
+ }
+ retval=TRUE;
+ }
+ BIO_free(mem);
+ return retval;
+}
+
+gboolean
+thrift_ssl_socket_authorize(ThriftTransport * transport, GError **error)
+{
+ ThriftSocket *socket = THRIFT_SOCKET (transport);
+ ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+ ThriftSSLSocketClass *cls = THRIFT_SSL_SOCKET_GET_CLASS(ssl_socket);
+ gboolean authorization_result = FALSE;
+
+ if(cls!=NULL && ssl_socket->ssl!=NULL){
+ int rc = SSL_get_verify_result(ssl_socket->ssl);
+ if (rc != X509_V_OK) { /* verify authentication result */
+ if (rc == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && ssl_socket->allow_selfsigned) {
+ g_debug("The certificate is a self-signed certificate and configuration allows it");
+ } else {
+ g_error("The certificate verification failed: %s (%d)", X509_verify_cert_error_string(rc), rc);
+ return FALSE;
+ }
+ }
+
+ X509* cert = SSL_get_peer_certificate(ssl_socket->ssl);
+ if (cert == NULL) {
+ if (SSL_get_verify_mode(ssl_socket->ssl) & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ g_error("No certificate present");
+ return FALSE;
+ }
+
+ g_debug("No certificate required");
+ return TRUE;
+ }
+
+ /* certificate is present, since we don't support access manager we are done */
+ if (cls->authorize_peer == NULL) {
+ X509_free(cert);
+ g_debug("Certificate presented but we're not checking it");
+ return TRUE;
+ } else {
+ /* both certificate and access manager are present */
+ struct sockaddr_storage sa;
+ socklen_t saLength = sizeof(struct sockaddr_storage);
+
+ if (getpeername(socket->sd, (struct sockaddr*)&sa, &saLength) != 0) {
+ sa.ss_family = AF_UNSPEC;
+ }
+
+ authorization_result = cls->authorize_peer(transport, cert, &sa, error);
+ }
+
+ if(cert != NULL) {
+ X509_free(cert);
+ }
+ }
+
+ return authorization_result;
+}
+
+
+/* initializes the instance */
+static void
+thrift_ssl_socket_init (ThriftSSLSocket *socket)
+{
+ GError *error = NULL;
+ socket->ssl = NULL;
+ socket->ctx = thrift_ssl_socket_context_initialize(SSLTLS, &error);
+ if(socket->ctx == NULL) {
+ g_info("The SSL context was not automatically initialized with protocol %d", SSLTLS);
+ if(error!=NULL){
+ g_info("Reported reason %s", error->message);
+ g_error_free (error);
+ }
+ }
+ socket->server = FALSE;
+ socket->allow_selfsigned = FALSE;
+
+}
+
+/* destructor */
+static void
+thrift_ssl_socket_finalize (GObject *object)
+{
+ ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (object);
+ GError *error=NULL;
+ g_debug("Instance %p destroyed",object);
+ if(socket->ssl != NULL)
+ {
+ thrift_ssl_socket_close(THRIFT_TRANSPORT(object), &error);
+ socket->ssl=NULL;
+ }
+
+ if(socket->ctx!=NULL){
+ g_debug("Freeing the context for the instance");
+ SSL_CTX_free(socket->ctx);
+ }
+ socket->ctx=NULL;
+
+
+ if (G_OBJECT_CLASS (thrift_ssl_socket_parent_class)->finalize)
+ (*G_OBJECT_CLASS (thrift_ssl_socket_parent_class)->finalize) (object);
+}
+
+/* property accessor */
+void
+thrift_ssl_socket_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (object);
+ THRIFT_UNUSED_VAR (pspec);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_SSL_SOCKET_CONTEXT:
+ g_value_set_pointer (value, socket->ctx);
+ break;
+ }
+}
+
+/* property mutator */
+void
+thrift_ssl_socket_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (object);
+
+ THRIFT_UNUSED_VAR (pspec);
+ switch (property_id)
+ {
+ case PROP_THRIFT_SSL_SOCKET_CONTEXT:
+ if(socket->ctx!=NULL){
+ g_debug("Freeing the context since we are setting a new one");
+ SSL_CTX_free(socket->ctx);
+ }
+ socket->ctx = g_value_get_pointer(value); // We copy the context
+ break;
+
+ case PROP_THRIFT_SSL_SELF_SIGNED:
+ socket->allow_selfsigned = g_value_get_boolean(value);
+ break;
+ default:
+ g_warning("Trying to set property %i that doesn't exists!", property_id);
+ /* thrift_socket_set_property(object, property_id, value, pspec); */
+ break;
+ }
+}
+
+void
+thrift_ssl_socket_initialize_openssl(void)
+{
+ if(thrift_ssl_socket_openssl_initialized){
+ return;
+ }
+ thrift_ssl_socket_openssl_initialized=TRUE;
+ SSL_library_init();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ ERR_load_BIO_strings();
+
+ /* Setup locking */
+ g_debug("We setup %d threads locks", thrift_ssl_socket_static_thread_setup());
+
+ /* dynamic locking
+ CRYPTO_set_dynlock_create_callback(thrift_ssl_socket_dyn_lock_create_callback);
+ CRYPTO_set_dynlock_lock_callback(thrift_ssl_socket_dyn_lock_callback);
+ CRYPTO_set_dynlock_destroy_callback(thrift_ssl_socket_dyn_lock_destroy_callback);
+ */
+}
+
+
+void thrift_ssl_socket_finalize_openssl(void)
+{
+
+ /* FIXME This should not be here */
+ if (thrift_ssl_socket_global_context != NULL) {
+ SSL_CTX_free(thrift_ssl_socket_global_context);
+ thrift_ssl_socket_global_context = NULL;
+ }
+
+ if (!thrift_ssl_socket_openssl_initialized) {
+ return;
+ }
+ thrift_ssl_socket_openssl_initialized = FALSE;
+
+ g_debug("We cleared %d threads locks", thrift_ssl_socket_static_thread_cleanup());
+ /* Not supported
+ CRYPTO_set_locking_callback(NULL);
+ CRYPTO_set_dynlock_create_callback(NULL);
+ CRYPTO_set_dynlock_lock_callback(NULL);
+ CRYPTO_set_dynlock_destroy_callback(NULL);
+ */
+ ERR_free_strings();
+ EVP_cleanup();
+ CRYPTO_cleanup_all_ex_data();
+ ERR_remove_state(0);
+}
+
+
+/* initializes the class */
+static void
+thrift_ssl_socket_class_init (ThriftSSLSocketClass *cls)
+{
+ ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
+ GParamSpec *param_spec = NULL;
+
+ g_debug("Initialization of ThriftSSLSocketClass");
+ /* setup accessors and mutators */
+ gobject_class->get_property = thrift_ssl_socket_get_property;
+ gobject_class->set_property = thrift_ssl_socket_set_property;
+ param_spec = g_param_spec_pointer ("ssl_context",
+ "SSLContext",
+ "Set the SSL context for handshake with the remote host",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_THRIFT_SSL_SOCKET_CONTEXT,
+ param_spec);
+ param_spec = g_param_spec_boolean ("ssl_accept_selfsigned",
+ "Accept Self Signed",
+ "Whether or not accept self signed certificate",
+ FALSE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_THRIFT_SSL_SELF_SIGNED,
+ param_spec);
+
+ // This must be supported in future
+ // param_spec = g_param_spec_uint ("port",
+ // "port (construct)",
+ // "Set the port of the remote host",
+ // 0, /* min */
+ // 65534, /* max */
+ // 9090, /* default by convention */
+ // G_PARAM_CONSTRUCT_ONLY |
+ // G_PARAM_READWRITE);
+ // g_object_class_install_property (gobject_class, PROP_THRIFT_SSL_SOCKET_PORT,
+ // param_spec);
+
+
+
+ /* Class methods */
+ cls->handle_handshake = thrift_ssl_socket_handle_handshake;
+ cls->create_ssl_context = thrift_ssl_socket_create_ssl_context;
+
+ /* Override */
+ gobject_class->finalize = thrift_ssl_socket_finalize;
+ ttc->is_open = thrift_ssl_socket_is_open;
+ ttc->peek = thrift_ssl_socket_peek;
+ ttc->open = thrift_ssl_socket_open;
+ ttc->close = thrift_ssl_socket_close;
+ ttc->read = thrift_ssl_socket_read;
+ ttc->read_end = thrift_ssl_socket_read_end;
+ ttc->write = thrift_ssl_socket_write;
+ ttc->write_end = thrift_ssl_socket_write_end;
+ ttc->flush = thrift_ssl_socket_flush;
+}
+
+
+/*
+ * Public API
+ */
+ThriftSSLSocket*
+thrift_ssl_socket_new(ThriftSSLSocketProtocol ssl_protocol, GError **error)
+{
+ ThriftSSLSocket *thriftSSLSocket = NULL;
+ /* Create the context */
+ if(thrift_ssl_socket_global_context==NULL){
+ if((thrift_ssl_socket_global_context=thrift_ssl_socket_context_initialize(ssl_protocol, error))==NULL){
+ // FIXME Do error control
+ return thriftSSLSocket;
+ }
+ }
+
+ /* FIXME if the protocol is different? */
+ thriftSSLSocket = g_object_new (THRIFT_TYPE_SSL_SOCKET, "ssl_context", thrift_ssl_socket_global_context, NULL);
+ return thriftSSLSocket;
+}
+
+void thrift_ssl_socket_set_manager(ThriftSSLSocket *ssl_socket, AUTHORIZATION_MANAGER_CALLBACK callback)
+{
+ ThriftSSLSocketClass *sslSocketClass = THRIFT_SSL_SOCKET_GET_CLASS (ssl_socket);
+ if(sslSocketClass){
+ sslSocketClass->authorize_peer = callback;
+ }
+}
+
+
+ThriftSSLSocket*
+thrift_ssl_socket_new_with_host(ThriftSSLSocketProtocol ssl_protocol, gchar *hostname, guint port, GError **error)
+{
+ ThriftSSLSocket *thriftSSLSocket = NULL;
+ /* Create the context */
+ if(thrift_ssl_socket_global_context==NULL){
+ if((thrift_ssl_socket_global_context=thrift_ssl_socket_context_initialize(ssl_protocol, error))==NULL){
+ // FIXME Do error control
+ return thriftSSLSocket;
+ }
+ }
+ /* FIXME if the protocol is different? */
+ thriftSSLSocket = g_object_new (THRIFT_TYPE_SSL_SOCKET, "ssl_context", thrift_ssl_socket_global_context, "hostname", hostname, "port", port, NULL);
+ return thriftSSLSocket;
+}
+
+
+SSL_CTX*
+thrift_ssl_socket_context_initialize(ThriftSSLSocketProtocol ssl_protocol, GError **error)
+{
+ SSL_CTX* context = NULL;
+ switch(ssl_protocol){
+ case SSLTLS:
+ context = SSL_CTX_new(SSLv23_method());
+ break;
+#ifndef OPENSSL_NO_SSL3
+ case SSLv3:
+ context = SSL_CTX_new(SSLv3_method());
+ break;
+#endif
+ case TLSv1_0:
+ context = SSL_CTX_new(TLSv1_method());
+ break;
+ case TLSv1_1:
+ context = SSL_CTX_new(TLSv1_1_method());
+ break;
+ case TLSv1_2:
+ context = SSL_CTX_new(TLSv1_2_method());
+ break;
+ default:
+ g_set_error (error, THRIFT_TRANSPORT_ERROR,
+ THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE,
+ "The SSL protocol is unknown for %d", ssl_protocol);
+ return NULL;
+ break;
+ }
+
+ if (context == NULL) {
+ thrift_ssl_socket_get_error(error, "No cipher overlay", THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE);
+ return NULL;
+ }
+ SSL_CTX_set_mode(context, SSL_MODE_AUTO_RETRY);
+
+ // Disable horribly insecure SSLv2 and SSLv3 protocols but allow a handshake
+ // with older clients so they get a graceful denial.
+ if (ssl_protocol == SSLTLS) {
+ SSL_CTX_set_options(context, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(context, SSL_OP_NO_SSLv3); // THRIFT-3164
+ }
+
+ return context;
+}
+
+void thrift_ssl_socket_get_error(GError **error, const guchar *error_msg, guint thrift_error_no)
+{
+ unsigned long error_code;
+ while ((error_code = ERR_get_error()) != 0) {
+ const char* reason = ERR_reason_error_string(error_code);
+ if (reason == NULL) {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR,
+ thrift_error_no,
+ "SSL error %lX: %s", error_code, error_msg);
+ }else{
+ g_set_error (error, THRIFT_TRANSPORT_ERROR,
+ thrift_error_no,
+ "SSL error %lX %s: %s", error_code,reason, error_msg);
+ }
+ }
+}
+
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.h
new file mode 100644
index 0000000..0153495
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.h
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _THRIFT_SSL_SOCKET_H
+#define _THRIFT_SSL_SOCKET_H
+
+#include <glib-object.h>
+#include <glib.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+#include <sys/socket.h>
+
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_socket.h>
+#include <thrift/c_glib/transport/thrift_platform_socket.h>
+
+G_BEGIN_DECLS
+
+/*! \file thrift_ssl_socket.h
+ * \brief SSL Socket implementation of a Thrift transport. Subclasses the
+ * ThriftSocket class. Based on plain openssl.
+ * In the future we should take a look to https://issues.apache.org/jira/browse/THRIFT-1016
+ */
+
+/* type macros */
+#define THRIFT_TYPE_SSL_SOCKET (thrift_ssl_socket_get_type ())
+#define THRIFT_SSL_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_SSL_SOCKET, ThriftSSLSocket))
+#define THRIFT_IS_SSL_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_SSL_SOCKET))
+#define THRIFT_SSL_SOCKET_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_SSL_SOCKET, ThriftSSLSocketClass))
+#define THRIFT_IS_SSL_SOCKET_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_SSL_SOCKET))
+#define THRIFT_SSL_SOCKET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_SSL_SOCKET, ThriftSSLSocketClass))
+
+
+/* define error/exception types */
+typedef enum
+{
+ THRIFT_SSL_SOCKET_ERROR_TRANSPORT=7,
+ THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE,
+ THRIFT_SSL_SOCKET_ERROR_SSL
+} ThriftSSLSocketError;
+
+
+typedef struct _ThriftSSLSocket ThriftSSLSocket;
+
+/*!
+ * Thrift SSL Socket instance.
+ */
+struct _ThriftSSLSocket
+{
+ ThriftSocket parent;
+
+ /* private */
+ SSL *ssl;
+ SSL_CTX* ctx;
+ gboolean server;
+ gboolean allow_selfsigned;
+};
+
+typedef struct _ThriftSSLSocketClass ThriftSSLSocketClass;
+typedef gboolean (* AUTHORIZATION_MANAGER_CALLBACK) (ThriftTransport * transport, X509 *cert, struct sockaddr_storage *addr, GError **error);
+
+/*!
+ * Thrift Socket class.
+ */
+struct _ThriftSSLSocketClass
+{
+ ThriftSocketClass parent;
+
+ gboolean (* handle_handshake) (ThriftTransport * transport, GError **error);
+ gboolean (* create_ssl_context) (ThriftTransport * transport, GError **error);
+ gboolean (* authorize_peer) (ThriftTransport * transport, X509 *cert, struct sockaddr_storage *addr, GError **error);
+
+ /* Padding to allow adding up to 12 new virtual functions without
+ * breaking ABI. */
+ gpointer padding[12];
+};
+
+enum _ThriftSSLSocketProtocol {
+ SSLTLS = 0, /* Supports SSLv2 and SSLv3 handshake but only negotiates at TLSv1_0 or later. */
+/*SSLv2 = 1, HORRIBLY INSECURE! */
+ SSLv3 = 2, /* Supports SSLv3 only - also horribly insecure! */
+ TLSv1_0 = 3, /* Supports TLSv1_0 or later. */
+ TLSv1_1 = 4, /* Supports TLSv1_1 or later. */
+ TLSv1_2 = 5, /* Supports TLSv1_2 or later. */
+ LATEST = TLSv1_2
+};
+typedef enum _ThriftSSLSocketProtocol ThriftSSLSocketProtocol;
+
+
+/* Internal functions */
+SSL_CTX*
+thrift_ssl_socket_context_initialize(ThriftSSLSocketProtocol ssl_protocol, GError **error);
+
+
+/* used by THRIFT_TYPE_SSL_SOCKET */
+GType thrift_ssl_socket_get_type (void);
+
+/* Public API */
+
+/**
+ * @brief Returns a error message for a defined error code.
+ *
+ * It uses gobject error functionality to get the error code of the last error
+ * produced by this API.
+ *
+ * @param error Pointer to the error message.
+ * @param error_msg Adds this message to the error that will be added to the
+ * code.
+ * @param thrift_error_no number of the error triggered.
+ *
+ * @see https://developer.gnome.org/glib/stable/glib-Error-Reporting.html#g-set-error
+ */
+void thrift_ssl_socket_get_error(GError **error, const guchar *error_msg, guint thrift_error_no);
+
+/**
+ * @brief Set a pinning manager instead of the default one.
+ *
+ * The pinning manager will be used during the SSL handshake to check certificate
+ * and pinning parameters.
+ *
+ * @param ssl_socket SSL Socket to operate on.
+ * @param callback function that will take the control while validating pinning
+ *
+ */
+void thrift_ssl_socket_set_manager(ThriftSSLSocket *ssl_socket, AUTHORIZATION_MANAGER_CALLBACK callback);
+
+/* This is the SSL API */
+ThriftSSLSocket*
+thrift_ssl_socket_new_with_host(ThriftSSLSocketProtocol ssl_protocol, gchar *hostname, guint port, GError **error);
+ThriftSSLSocket*
+thrift_ssl_socket_new(ThriftSSLSocketProtocol ssl_protocol, GError **error);
+gboolean
+thrift_ssl_load_cert_from_file(ThriftSSLSocket *ssl_socket, const char *file_name);
+gboolean
+thrift_ssl_load_cert_from_buffer(ThriftSSLSocket *ssl_socket, const char chain_certs[]);
+
+/**
+ * @brief Initialization function
+ *
+ * It will initialize OpenSSL function. This initialization will be done app
+ * wide. So if you want to initialize it by yourself you should not call it.
+ * But it means you must handle OpenSSL initialization and handle locking.
+ *
+ * It should be called before anything else.
+ *
+ *
+ */
+void
+thrift_ssl_socket_initialize_openssl(void);
+/**
+ * @brief Finalization function
+ *
+ * It clears all resources initialized in initialize function.
+ *
+ * It should be called after anything else.
+ *
+ *
+ */
+void
+thrift_ssl_socket_finalize_openssl(void);
+
+G_END_DECLS
+#endif
diff --git a/lib/c_glib/test/Makefile.am b/lib/c_glib/test/Makefile.am
index 3dc5418..8c6c48d 100755
--- a/lib/c_glib/test/Makefile.am
+++ b/lib/c_glib/test/Makefile.am
@@ -37,16 +37,17 @@
gen-c_glib/t_test_thrift_test_types.h
AM_CPPFLAGS = -I../src -I./gen-c_glib
-AM_CFLAGS = -g -Wall -Wextra -pedantic $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) \
+AM_CFLAGS = -g -Wall -Wextra -pedantic $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(OPENSSL_INCLUDES) \
@GCOV_CFLAGS@
AM_CXXFLAGS = $(AM_CFLAGS)
-AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) @GCOV_LDFLAGS@
+AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) $(OPENSSL_LIBS) @GCOV_LDFLAGS@
check_PROGRAMS = \
testserialization \
testapplicationexception \
testcontainertest \
testtransportsocket \
+ testtransportsslsocket \
testbinaryprotocol \
testcompactprotocol \
testbufferedtransport \
@@ -100,6 +101,16 @@
$(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
$(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o
+
+testtransportsslsocket_SOURCES = testtransportsslsocket.c
+testtransportsslsocket_LDADD = \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_socket.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_buffered_transport.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o
+
+
testbinaryprotocol_SOURCES = testbinaryprotocol.c
testbinaryprotocol_LDADD = \
$(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
diff --git a/lib/c_glib/test/testtransportsslsocket.c b/lib/c_glib/test/testtransportsslsocket.c
new file mode 100644
index 0000000..b4688f9
--- /dev/null
+++ b/lib/c_glib/test/testtransportsslsocket.c
@@ -0,0 +1,581 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <netdb.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport.h>
+#include <thrift/c_glib/transport/thrift_server_transport.h>
+#include <thrift/c_glib/transport/thrift_server_socket.h>
+#include <thrift/c_glib/transport/thrift_ssl_socket.h>
+
+//#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
+#define TEST_DATA { "GET / HTTP/1.1\n\n" }
+
+
+/* substituted functions to test failures of system and library calls */
+static int socket_error = 0;
+int
+my_socket(int domain, int type, int protocol)
+{
+ if (socket_error == 0)
+ {
+ return socket (domain, type, protocol);
+ }
+ return -1;
+}
+
+static int recv_error = 0;
+ssize_t
+my_recv(int socket, void *buffer, size_t length, int flags)
+{
+ if (recv_error == 0)
+ {
+ return recv (socket, buffer, length, flags);
+ }
+ return -1;
+}
+
+static int send_error = 0;
+ssize_t
+my_send(int socket, const void *buffer, size_t length, int flags)
+{
+ if (send_error == 0)
+ {
+ return send (socket, buffer, length, flags);
+ }
+ return -1;
+}
+
+#define socket my_socket
+#define recv my_recv
+#define send my_send
+#include "../src/thrift/c_glib/transport/thrift_ssl_socket.c"
+#undef socket
+#undef recv
+#undef send
+
+static void thrift_ssl_socket_server (const int port);
+
+/* test object creation and destruction */
+static void
+test_ssl_create_and_destroy(void)
+{
+ gchar *hostname = NULL;
+ guint port = 0;
+
+ GObject *object = NULL;
+ object = g_object_new (THRIFT_TYPE_SSL_SOCKET, NULL);
+ assert (object != NULL);
+ g_object_get (G_OBJECT(object), "hostname", &hostname, "port", &port, NULL);
+ g_free (hostname);
+ g_object_unref (object);
+}
+
+static void
+test_ssl_create_and_set_properties(void)
+{
+ gchar *hostname = NULL;
+ guint port = 0;
+ SSL_CTX* ssl_ctx= NULL;
+ GError *error=NULL;
+
+ GObject *object = NULL;
+ object = thrift_ssl_socket_new(SSLTLS, &error);
+ g_object_get (G_OBJECT(object), "hostname", &hostname, "port", &port, "ssl_context", &ssl_ctx, NULL);
+ assert (ssl_ctx!=NULL);
+
+ g_free (hostname);
+ g_object_unref (object);
+}
+
+static void
+test_ssl_open_and_close(void)
+{
+ ThriftSSLSocket *tSSLSocket = NULL;
+ ThriftTransport *transport = NULL;
+ GError *error=NULL;
+
+ /* open a connection and close it */
+ tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", 51188, &error);
+
+ transport = THRIFT_TRANSPORT (tSSLSocket);
+ thrift_ssl_socket_open (transport, NULL);
+ assert (thrift_ssl_socket_is_open (transport) == TRUE);
+ thrift_ssl_socket_close (transport, NULL);
+ assert (thrift_ssl_socket_is_open (transport) == FALSE);
+
+ /* test close failure */
+ THRIFT_SOCKET(tSSLSocket)->sd = -1;
+ thrift_ssl_socket_close (transport, NULL);
+ g_object_unref (tSSLSocket);
+
+ /* try a hostname lookup failure */
+ tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost.broken", 51188, &error);
+ transport = THRIFT_TRANSPORT (tSSLSocket);
+ assert (thrift_ssl_socket_open (transport, &error) == FALSE);
+ g_object_unref (tSSLSocket);
+ g_error_free (error);
+ error = NULL;
+
+ /* try an error call to socket() */
+ tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", 51188, &error);
+ transport = THRIFT_TRANSPORT (tSSLSocket);
+ socket_error = 1;
+ assert (thrift_ssl_socket_open (transport, &error) == FALSE);
+ socket_error = 0;
+ g_object_unref (tSSLSocket);
+ g_error_free (error);
+}
+
+
+
+/**
+ * Print the common name of certificate
+ */
+unsigned char * get_cn_name(X509_NAME* const name)
+{
+ int idx = -1;
+ unsigned char *utf8 = NULL;
+
+ do
+ {
+ if(!name) break; /* failed */
+
+ idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
+ if(!(idx > -1)) break; /* failed */
+
+ X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx);
+ if(!entry) break; /* failed */
+
+ ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
+ if(!data) break; /* failed */
+
+ int length = ASN1_STRING_to_UTF8(&utf8, data);
+ if(!utf8 || !(length > 0)) break; /* failed */
+
+ } while (0);
+ return utf8;
+}
+
+/*
+ * Handle IPV4 and IPV6 addr
+ */
+void *get_in_addr(struct sockaddr *sa)
+{
+ if (sa->sa_family == AF_INET)
+ return &(((struct sockaddr_in*)sa)->sin_addr);
+ return &(((struct sockaddr_in6*)sa)->sin6_addr);
+}
+
+int verify_ip(char * hostname, struct sockaddr_storage *addr)
+{
+ struct addrinfo *addr_info,*p;
+ struct addrinfo hints;
+ int res;
+ int retval = 0;
+
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
+ hints.ai_socktype = SOCK_STREAM;
+
+
+ if ( (res = getaddrinfo(hostname, NULL, &hints, &addr_info) ) != 0)
+ {
+ // get the host info
+ g_error("Cannot get the host address");
+ return retval;
+ }
+ // loop through all the results and connect to the first we can
+ char dnshost[INET6_ADDRSTRLEN]; // bigger addr supported IPV6
+ char socket_ip[INET6_ADDRSTRLEN];
+ if(inet_ntop(addr->ss_family, get_in_addr(addr), socket_ip, INET6_ADDRSTRLEN)==socket_ip){
+ g_debug("We are connected to host %s checking against certificate...", socket_ip);
+ int sizeip = socket_ip!=NULL ? strlen(socket_ip) : 0;
+ for(p = addr_info; p != NULL; p = p->ai_next) {
+ if(inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), dnshost, INET6_ADDRSTRLEN)==dnshost){
+ if(dnshost!=NULL){
+ g_info("DNS address [%i -> %s]", p->ai_addr, dnshost);
+ if(!strncmp(dnshost, socket_ip, sizeip)){
+ retval=1;
+ break; // if we get here, we must have connected successfully
+ }
+ }
+ }
+ }
+ }
+
+ if(addr_info)
+ freeaddrinfo(addr_info);
+
+ return retval;
+}
+
+static void
+read_from_file(char *buffer, long size, const char *file_name)
+{
+ char ch;
+ long index=0;
+ FILE *fp;
+
+ fp = fopen(file_name,"r"); // read mode
+
+ if( fp == NULL )
+ {
+ perror("Error while opening the file.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("The contents of %s file are :\n", file_name);
+
+ while(index<size && ( ch = fgetc(fp) ) != EOF ){
+ buffer[index++] = ch;
+ }
+
+ fclose(fp);
+}
+
+#define ISSUER_CN_PINNING "The Apache Software Foundation"
+#define SUBJECT_CN_PINNING "localhost"
+#define CERT_SERIAL_NUMBER "1"
+
+gboolean verify_certificate_sn(X509 *cert, const unsigned char *serial_number)
+{
+ gboolean retval = FALSE;
+
+ ASN1_INTEGER *serial = X509_get_serialNumber(cert);
+
+ BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
+ if (!bn) {
+ fprintf(stderr, "unable to convert ASN1INTEGER to BN\n");
+ return EXIT_FAILURE;
+ }
+ char *tmp = BN_bn2dec(bn);
+ if (!tmp) {
+ g_warning(stderr, "unable to convert BN to decimal string.\n");
+ BN_free(bn);
+ return EXIT_FAILURE;
+ }
+// if (strlen(tmp) >= len) {
+// g_warn(stderr, "buffer length shorter than serial number\n");
+// BN_free(bn);
+// OPENSSL_free(tmp);
+// return EXIT_FAILURE;
+// }
+ if(!strncmp(serial_number, tmp, strlen(serial_number))){
+ retval=TRUE;
+ }else{
+ g_warning("Serial number is not valid");
+ }
+
+ BN_free(bn);
+ OPENSSL_free(tmp);
+ return retval;
+}
+
+gboolean my_access_manager(ThriftTransport * transport, X509 *cert, struct sockaddr_storage *addr, GError **error)
+{
+ ThriftSSLSocket *sslSocket = THRIFT_SSL_SOCKET (transport);
+
+ g_info("Processing access to the server");
+ X509_NAME* iname = cert ? X509_get_issuer_name(cert) : NULL;
+ X509_NAME* sname = cert ? X509_get_subject_name(cert) : NULL;
+
+ /* Issuer is the authority we trust that warrants nothing useful */
+ const unsigned char * issuer = get_cn_name(iname);
+ if(issuer){
+ gboolean valid = TRUE;
+ g_info("Issuer (cn) %s", issuer);
+
+ // Issuer pinning
+ if(strncmp(ISSUER_CN_PINNING, issuer, strlen(ISSUER_CN_PINNING))){
+ g_warning("The Issuer of the certificate is not valid");
+ valid=FALSE;
+ }
+ OPENSSL_free(issuer);
+ if(!valid)
+ return valid;
+ }
+
+
+ /* Subject is who the certificate is issued to by the authority */
+ const unsigned char * subject = get_cn_name(sname);
+ if(subject){
+ g_info("Subject (cn) %s", subject);
+ gboolean valid = TRUE;
+
+ // Subject pinning
+ if(strncmp(SUBJECT_CN_PINNING, subject, strlen(SUBJECT_CN_PINNING))){
+ g_warning("The subject of the certificate is not valid");
+ valid=FALSE;
+ }
+
+ if(!valid)
+ return valid;
+
+ // Host pinning
+ if(verify_ip(subject, addr)){
+ g_info("Verified subject");
+ }else{
+ g_info("Cannot verify subject");
+ valid=FALSE;
+ }
+ OPENSSL_free(subject);
+
+ if(!valid)
+ return valid;
+ }
+
+ if(!verify_certificate_sn(cert, CERT_SERIAL_NUMBER)){
+ return FALSE;
+ }else{
+ g_info("Verified serial number");
+ }
+
+ return TRUE;
+
+}
+
+
+
+
+#ifdef BUILD_SERVER
+static void
+test_ssl_authorization_manager(void)
+{
+ int status=0;
+ pid_t pid;
+ ThriftSSLSocket *tSSLsocket = NULL;
+ ThriftTransport *transport = NULL;
+ // int port = 51199;
+ int port = 443;
+ GError *error=NULL;
+
+ guchar buf[17] = TEST_DATA; /* a buffer */
+
+ // pid = fork ();
+ // assert ( pid >= 0 );
+ //
+ // if ( pid == 0 )
+ // {
+ // /* child listens */
+ // thrift_ssl_socket_server (port);
+ // exit (0);
+ // } else {
+ /* parent connects, wait a bit for the socket to be created */
+ sleep (1);
+
+ // Test against level2 owncloud certificate
+ tSSLsocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", port, &error);
+ thrift_ssl_socket_set_manager(tSSLsocket, my_access_manager); // Install pinning manager
+ //thrift_ssl_load_cert_from_file(tSSLsocket, "./owncloud.level2crm.pem");
+ unsigned char cert_buffer[65534];
+ read_from_file(cert_buffer, 65534, "../../keys/client.pem");
+ if(!thrift_ssl_load_cert_from_buffer(tSSLsocket, cert_buffer)){
+ g_warning("Certificates cannot be loaded!");
+ }
+
+ transport = THRIFT_TRANSPORT (tSSLsocket);
+ assert (thrift_ssl_socket_open (transport, NULL) == TRUE);
+ assert (thrift_ssl_socket_is_open (transport));
+
+ thrift_ssl_socket_write (transport, buf, 17, NULL);
+
+ /* write fail */
+ send_error = 1;
+ // thrift_ssl_socket_write (transport, buf, 1, NULL);
+ // send_error = 0;
+
+ // thrift_ssl_socket_write_end (transport, NULL);
+ // thrift_ssl_socket_flush (transport, NULL);
+ thrift_ssl_socket_close (transport, NULL);
+ g_object_unref (tSSLsocket);
+
+ // assert ( wait (&status) == pid );
+ assert ( status == 0 );
+ // }
+}
+#endif
+
+
+/* test ThriftSocket's peek() implementation */
+//static void
+//test_ssl_peek(void)
+//{
+// gint status;
+// pid_t pid;
+// guint port = 51199;
+// gchar data = 'A';
+// ThriftTransport *client_transport;
+// GError *error = NULL;
+//
+// client_transport = g_object_new (THRIFT_TYPE_SSL_SOCKET,
+// "hostname", "localhost",
+// "port", port,
+// NULL);
+//
+// /* thrift_transport_peek returns FALSE when the socket is closed */
+// g_assert (thrift_transport_is_open (client_transport) == FALSE);
+// g_assert (thrift_transport_peek (client_transport, &error) == FALSE);
+// g_assert (error == NULL);
+//
+// pid = fork ();
+// g_assert (pid >= 0);
+//
+// if (pid == 0)
+// {
+// ThriftServerTransport *server_transport = NULL;
+//
+// g_object_unref (client_transport);
+//
+// /* child listens */
+// server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+// "port", port,
+// NULL);
+// g_assert (server_transport != NULL);
+//
+// thrift_server_transport_listen (server_transport, &error);
+// g_assert (error == NULL);
+//
+// client_transport = g_object_new
+// (THRIFT_TYPE_BUFFERED_TRANSPORT,
+// "transport", thrift_server_transport_accept (server_transport, &error),
+// "r_buf_size", 0,
+// "w_buf_size", sizeof data,
+// NULL);
+// g_assert (error == NULL);
+// g_assert (client_transport != NULL);
+//
+// /* write exactly one character to the client */
+// g_assert (thrift_transport_write (client_transport,
+// &data,
+// sizeof data,
+// &error) == TRUE);
+//
+// thrift_transport_flush (client_transport, &error);
+// thrift_transport_write_end (client_transport, &error);
+// thrift_transport_close (client_transport, &error);
+//
+// g_object_unref (client_transport);
+// g_object_unref (server_transport);
+//
+// exit (0);
+// }
+// else {
+// /* parent connects, wait a bit for the socket to be created */
+// sleep (1);
+//
+// /* connect to the child */
+// thrift_transport_open (client_transport, &error);
+// g_assert (error == NULL);
+// g_assert (thrift_transport_is_open (client_transport) == TRUE);
+//
+// /* thrift_transport_peek returns TRUE when the socket is open and there is
+// data available to be read */
+// g_assert (thrift_transport_peek (client_transport, &error) == TRUE);
+// g_assert (error == NULL);
+//
+// /* read exactly one character from the server */
+// g_assert_cmpint (thrift_transport_read (client_transport,
+// &data,
+// sizeof data,
+// &error), ==, sizeof data);
+//
+// /* thrift_transport_peek returns FALSE when the socket is open but there is
+// no (more) data available to be read */
+// g_assert (thrift_transport_is_open (client_transport) == TRUE);
+// g_assert (thrift_transport_peek (client_transport, &error) == FALSE);
+// g_assert (error == NULL);
+//
+// thrift_transport_read_end (client_transport, &error);
+// thrift_transport_close (client_transport, &error);
+//
+// g_object_unref (client_transport);
+//
+// g_assert (wait (&status) == pid);
+// g_assert (status == 0);
+// }
+//}
+
+static void
+thrift_ssl_socket_server (const int port)
+{
+ int bytes = 0;
+ ThriftServerTransport *transport = NULL;
+ ThriftTransport *client = NULL;
+ guchar buf[10]; /* a buffer */
+ guchar match[10] = TEST_DATA;
+
+ ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+ "port", port, NULL);
+
+ transport = THRIFT_SERVER_TRANSPORT (tsocket);
+ thrift_server_transport_listen (transport, NULL);
+ client = thrift_server_transport_accept (transport, NULL);
+ assert (client != NULL);
+
+ /* read 10 bytes */
+ bytes = thrift_ssl_socket_read (client, buf, 10, NULL);
+ assert (bytes == 10); /* make sure we've read 10 bytes */
+ assert ( memcmp(buf, match, 10) == 0 ); /* make sure what we got matches */
+
+ /* failed read */
+ recv_error = 1;
+ thrift_ssl_socket_read (client, buf, 1, NULL);
+ recv_error = 0;
+
+ thrift_ssl_socket_read_end (client, NULL);
+ thrift_ssl_socket_close (client, NULL);
+ g_object_unref (tsocket);
+ g_object_unref (client);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int retval;
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+ g_type_init();
+#endif
+
+ g_test_init (&argc, &argv, NULL);
+
+ thrift_ssl_socket_initialize_openssl();
+
+ g_test_add_func ("/testtransportsslsocket/CreateAndDestroy", test_ssl_create_and_destroy);
+ g_test_add_func ("/testtransportsslsocket/CreateAndSetProperties", test_ssl_create_and_set_properties);
+ g_test_add_func ("/testtransportsslsocket/OpenAndClose", test_ssl_open_and_close);
+ // This test is disabled because server is not ready
+ // g_test_add_func ("/testtransportsslsocket/AuthorizationManagerPinning", test_ssl_authorization_manager);
+ // g_test_add_func ("/testtransportsslsocket/Peek", test_ssl_peek);
+
+ retval = g_test_run ();
+
+ thrift_ssl_socket_finalize_openssl();
+
+ return retval;
+}
+
diff --git a/lib/py/src/transport/TSSLSocket.py b/lib/py/src/transport/TSSLSocket.py
index 0f7d45e..bf4689a 100644
--- a/lib/py/src/transport/TSSLSocket.py
+++ b/lib/py/src/transport/TSSLSocket.py
@@ -40,10 +40,10 @@
# ciphers argument is not available for Python < 2.7.0
_has_ciphers = sys.hexversion >= 0x020700F0
- # For pythoon >= 2.7.9, use latest TLS that both client and server
+ # For python >= 2.7.9, use latest TLS that both client and server
# supports.
# SSL 2.0 and 3.0 are disabled via ssl.OP_NO_SSLv2 and ssl.OP_NO_SSLv3.
- # For pythoon < 2.7.9, use TLS 1.0 since TLSv1_X nor OP_NO_SSLvX is
+ # For python < 2.7.9, use TLS 1.0 since TLSv1_X nor OP_NO_SSLvX is
# unavailable.
_default_protocol = ssl.PROTOCOL_SSLv23 if _has_ssl_context else \
ssl.PROTOCOL_TLSv1
diff --git a/test/c_glib/src/test_client.c b/test/c_glib/src/test_client.c
index 3ae9325..9713e8c 100644
--- a/test/c_glib/src/test_client.c
+++ b/test/c_glib/src/test_client.c
@@ -30,6 +30,7 @@
#include <thrift/c_glib/protocol/thrift_compact_protocol.h>
#include <thrift/c_glib/transport/thrift_buffered_transport.h>
#include <thrift/c_glib/transport/thrift_framed_transport.h>
+#include <thrift/c_glib/transport/thrift_ssl_socket.h>
#include <thrift/c_glib/transport/thrift_socket.h>
#include <thrift/c_glib/transport/thrift_transport.h>
@@ -75,29 +76,34 @@
int
main (int argc, char **argv)
{
- static gchar *host = NULL;
- static gint port = 9090;
- static gchar *transport_option = NULL;
- static gchar *protocol_option = NULL;
- static gint num_tests = 1;
+ static gchar * host = NULL;
+ static gint port = 9090;
+ static gboolean ssl = FALSE;
+ static gchar * transport_option = NULL;
+ static gchar * protocol_option = NULL;
+ static gint num_tests = 1;
static
GOptionEntry option_entries[] ={
- { "host", 0, 0, G_OPTION_ARG_STRING, &host,
+ { "host", 'h', 0, G_OPTION_ARG_STRING, &host,
"Host to connect (=localhost)", NULL },
- { "port", 0, 0, G_OPTION_ARG_INT, &port,
+ { "port", 'p', 0, G_OPTION_ARG_INT, &port,
"Port number to connect (=9090)", NULL },
- { "transport", 0, 0, G_OPTION_ARG_STRING, &transport_option,
+ { "ssl", 's', 0, G_OPTION_ARG_NONE, &ssl,
+ "Enable SSL", NULL },
+ { "transport", 't', 0, G_OPTION_ARG_STRING, &transport_option,
"Transport: buffered, framed (=buffered)", NULL },
- { "protocol", 0, 0, G_OPTION_ARG_STRING, &protocol_option,
+ { "protocol", 'r', 0, G_OPTION_ARG_STRING, &protocol_option,
"Protocol: binary, compact (=binary)", NULL },
- { "testloops", 'n', 0, G_OPTION_ARG_INT, &num_tests,
+ { "testloops", 'n', 0, G_OPTION_ARG_INT, &num_tests,
"Number of tests (=1)", NULL },
{ NULL }
};
struct sigaction sigpipe_action;
+ GType socket_type = THRIFT_TYPE_SOCKET;
+ gchar *socket_name = "ip";
GType transport_type = THRIFT_TYPE_BUFFERED_TRANSPORT;
gchar *transport_name = "buffered";
GType protocol_type = THRIFT_TYPE_BINARY_PROTOCOL;
@@ -164,12 +170,19 @@
}
}
+ if (ssl) {
+ socket_type = THRIFT_TYPE_SSL_SOCKET;
+ socket_name = "ip-ssl";
+ printf("Type name %s\n", g_type_name (socket_type));
+ }
+
if (!options_valid)
return 254;
- printf ("Connecting (%s/%s) to: %s:%d\n",
+ printf ("Connecting (%s/%s) to: %s/%s:%d\n",
transport_name,
protocol_name,
+ socket_name,
host,
port);
@@ -181,11 +194,22 @@
sigpipe_action.sa_flags = SA_RESETHAND;
sigaction (SIGPIPE, &sigpipe_action, NULL);
+ if (ssl) {
+ thrift_ssl_socket_initialize_openssl();
+ }
+
/* Establish all our connection objects */
- socket = g_object_new (THRIFT_TYPE_SOCKET,
+ socket = g_object_new (socket_type,
"hostname", host,
"port", port,
NULL);
+
+ if (ssl && !thrift_ssl_load_cert_from_file(THRIFT_SSL_SOCKET(socket), "../keys/CA.pem")) {
+ fprintf(stderr, "Unable to load validation certificate ../keys/CA.pem - did you run in the test/c_glib directory?\n");
+ g_object_unref (socket);
+ return 253;
+ }
+
transport = g_object_new (transport_type,
"transport", socket,
NULL);
@@ -277,10 +301,11 @@
printf (" = void\n");
}
else {
+ if(error!=NULL){
printf ("%s\n", error->message);
- g_error_free (error);
- error = NULL;
-
+ g_error_free (error);
+ error = NULL;
+ }
fail_count++;
}
@@ -439,8 +464,8 @@
fail_count++;
}
- // TODO: add testBinary()
-
+ // TODO: add testBinary()
+
/**
* STRUCT TEST
*/
@@ -1575,6 +1600,7 @@
}
else {
printf ("Connect failed: %s\n", error->message);
+ g_object_unref (socket);
g_error_free (error);
error = NULL;
@@ -1596,5 +1622,9 @@
g_object_unref (transport);
g_free (host);
+ if (ssl) {
+ thrift_ssl_socket_finalize_openssl();
+ }
+
return fail_count;
}
diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json
index edf0fbb..4ca2050 100644
--- a/test/known_failures_Linux.json
+++ b/test/known_failures_Linux.json
@@ -11,6 +11,7 @@
"cpp-cpp_compact_http-ip-ssl",
"cpp-cpp_header_buffered-ip-ssl",
"cpp-cpp_header_framed-ip-ssl",
+ "cpp-cpp_header_http-domain",
"cpp-cpp_header_http-ip-ssl",
"cpp-cpp_json_buffered-ip-ssl",
"cpp-cpp_json_framed-ip",
@@ -35,7 +36,10 @@
"cpp-java_json_http-ip-ssl",
"cpp-perl_binary_buffered-ip-ssl",
"cpp-perl_binary_framed-ip-ssl",
- "cpp-py_binary-accel_framed-ip-ssl",
+ "csharp-c_glib_binary_buffered-ip-ssl",
+ "csharp-c_glib_binary_framed-ip-ssl",
+ "csharp-c_glib_compact_buffered-ip-ssl",
+ "csharp-c_glib_compact_framed-ip-ssl",
"csharp-cpp_binary_buffered-ip-ssl",
"csharp-cpp_binary_framed-ip-ssl",
"csharp-cpp_compact_buffered-ip-ssl",
@@ -101,6 +105,8 @@
"d-cpp_json_framed-ip-ssl",
"d-cpp_json_http-ip",
"d-cpp_json_http-ip-ssl",
+ "d-d_binary_http-ip",
+ "d-d_compact_http-ip",
"d-dart_binary_framed-ip",
"d-dart_binary_http-ip",
"d-dart_compact_framed-ip",
@@ -220,8 +226,6 @@
"hs-dart_json_framed-ip",
"hs-py3_json_buffered-ip",
"hs-py3_json_framed-ip",
- "hs-py_json_buffered-ip",
- "hs-py_json_framed-ip",
"java-d_compact_buffered-ip",
"java-d_compact_buffered-ip-ssl",
"java-d_compact_framed-ip",
diff --git a/test/tests.json b/test/tests.json
index 09d4c89..5de36f5 100644
--- a/test/tests.json
+++ b/test/tests.json
@@ -12,6 +12,9 @@
"client": {
"command": [
"test_client"
+ ],
+ "sockets": [
+ "ip-ssl"
]
},
"transports": [
diff --git a/tutorial/c_glib/Makefile.am b/tutorial/c_glib/Makefile.am
index 565f635..15a9995 100755
--- a/tutorial/c_glib/Makefile.am
+++ b/tutorial/c_glib/Makefile.am
@@ -24,9 +24,9 @@
gen-c_glib/shared_types.h \
gen-c_glib/tutorial_types.h
-AM_CFLAGS = -g -Wall -Wextra -pedantic $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) @GCOV_CFLAGS@
+AM_CFLAGS = -g -Wall -Wextra -pedantic $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(OPENSSL_INCLUDES) @GCOV_CFLAGS@
AM_CPPFLAGS = -I$(top_srcdir)/lib/c_glib/src -Igen-c_glib
-AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) @GCOV_LDFLAGS@
+AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) $(OPENSSL_LDFLAGS) $(OPENSSL_LIBS) @GCOV_LDFLAGS@
THRIFT = $(top_builddir)/compiler/cpp/thrift
@@ -55,6 +55,7 @@
tutorial_server_SOURCES = \
c_glib_server.c
+tutorial_server_LDFLAGS = $(OPENSSL_LIBS)
tutorial_server_LDADD = \
libtutorialgencglib.la \