diff --git a/src/plugin/ns/CMakeLists.txt b/src/plugin/ns/CMakeLists.txt
index 50e260c5..fb497ed6 100644
--- a/src/plugin/ns/CMakeLists.txt
+++ b/src/plugin/ns/CMakeLists.txt
@@ -20,8 +20,42 @@ if (SYNERGY_ADD_HEADERS)
list(APPEND sources ${headers})
endif()
+if (WIN32)
+ set(OPENSSL_INCLUDE ../../../ext/openssl/inc32)
+endif()
+
+if (APPLE)
+ set(OPENSSL_INCLUDE ../../../ext/openssl/include)
+endif()
+
+include_directories(
+ ../../lib/
+ ${OPENSSL_INCLUDE}
+)
+
add_library(ns SHARED ${sources})
+if (WIN32)
+ set(OPENSSL_LIBS
+ ${CMAKE_SOURCE_DIR}/ext/openssl/out32dll/libeay32.lib
+ ${CMAKE_SOURCE_DIR}/ext/openssl/out32dll/ssleay32.lib
+ )
+endif()
+
+if (UNIX)
+ if (APPLE)
+ set(OPENSSL_LIBS
+ ${CMAKE_SOURCE_DIR}/ext/openssl/libssl.a
+ ${CMAKE_SOURCE_DIR}/ext/openssl/libcrypto.a
+ )
+ else()
+ set(OPENSSL_LIBS ssl crypto)
+ endif()
+endif()
+
+target_link_libraries(ns
+ arch base client common io mt net ipc platform server synergy cryptopp ${libs} ${OPENSSL_LIBS})
+
if (WIN32)
add_custom_command(
TARGET ns
diff --git a/src/plugin/ns/SecureSocket.cpp b/src/plugin/ns/SecureSocket.cpp
new file mode 100644
index 00000000..50e5f506
--- /dev/null
+++ b/src/plugin/ns/SecureSocket.cpp
@@ -0,0 +1,294 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software Ltd.
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "SecureSocket.h"
+
+#include "base/String.h"
+#include
+#include
+
+//
+// SecureSocket
+//
+struct CSsl {
+ SSL_CTX* m_context;
+ SSL* m_ssl;
+};
+CSecureSocket::CSecureSocket() :
+ m_ready(false),
+ m_errorSize(65535)
+{
+ m_ssl = new CSsl();
+ m_ssl->m_context = NULL;
+ m_ssl->m_ssl = NULL;
+ m_error = new char[m_errorSize];
+}
+
+CSecureSocket::~CSecureSocket()
+{
+ if (m_ssl->m_ssl != NULL) {
+ SSL_free(m_ssl->m_ssl);
+ }
+ if (m_ssl->m_context != NULL) {
+ SSL_CTX_free(m_ssl->m_context);
+ }
+
+ delete[] m_error;
+}
+
+void
+CSecureSocket::initContext(bool server)
+{
+ SSL_library_init();
+
+ const SSL_METHOD* method;
+
+ // load & register all cryptos, etc.
+ OpenSSL_add_all_algorithms();
+
+ // load all error messages
+ SSL_load_error_strings();
+
+ if (server) {
+ // create new server-method instance
+ method = SSLv3_server_method();
+ }
+ else {
+ // create new client-method instance
+ method = SSLv3_client_method();
+ }
+
+ // create new context from method
+ m_ssl->m_context = SSL_CTX_new(method);
+ if (m_ssl->m_context == NULL) {
+ showError();
+ }
+}
+
+void
+CSecureSocket::loadCertificates(const char* filename)
+{
+ int r = 0;
+ r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename, SSL_FILETYPE_PEM);
+ if (r <= 0) {
+ showError();
+ }
+
+ r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename, SSL_FILETYPE_PEM);
+ if (r <= 0) {
+ showError();
+ }
+
+ //verify private key
+ r = SSL_CTX_check_private_key(m_ssl->m_context);
+ if (!r) {
+ showError();
+ }
+}
+void
+CSecureSocket::createSSL()
+{
+ // I assume just one instance is needed
+ // get new SSL state with context
+ if (m_ssl->m_ssl == NULL) {
+ m_ssl->m_ssl = SSL_new(m_ssl->m_context);
+ }
+}
+
+void
+CSecureSocket::accept(int socket)
+{
+ createSSL();
+
+ // set connection socket to SSL state
+ SSL_set_fd(m_ssl->m_ssl, socket);
+
+ // do SSL-protocol accept
+ int r = SSL_accept(m_ssl->m_ssl);
+
+ bool retry = checkResult(r);
+ while (retry) {
+ ARCH->sleep(.5f);
+ r = SSL_accept(m_ssl->m_ssl);
+ retry = checkResult(r);
+ }
+
+ m_ready = true;
+}
+
+void
+CSecureSocket::connect(int socket)
+{
+ createSSL();
+
+ // attach the socket descriptor
+ SSL_set_fd(m_ssl->m_ssl, socket);
+
+ int r = SSL_connect(m_ssl->m_ssl);
+
+ bool retry = checkResult(r);
+ while (retry) {
+ ARCH->sleep(.5f);
+ r = SSL_connect(m_ssl->m_ssl);
+ retry = checkResult(r);
+ }
+
+ m_ready= true;
+ showCertificate();
+}
+
+size_t
+CSecureSocket::write(const void* buffer, int size)
+{
+ bool retry = false;
+ int n = 0;
+ if (m_ssl != NULL) {
+ n = SSL_write(m_ssl->m_ssl, buffer, size);
+ retry = checkResult(n);
+ if (retry) {
+ n = 0;
+ }
+ }
+
+ return n > 0 ? n : 0;
+}
+
+size_t
+CSecureSocket::read(void* buffer, int size)
+{
+ bool retry = false;
+ int n = 0;
+ if (m_ssl != NULL) {
+ n = SSL_read(m_ssl->m_ssl, buffer, size);
+ retry = checkResult(n);
+ if (retry) {
+ n = 0;
+ }
+ }
+
+ return n > 0 ? n : 0;
+}
+
+void
+CSecureSocket::showCertificate()
+{
+ X509* cert;
+ char* line;
+
+ // get the server's certificate
+ cert = SSL_get_peer_certificate(m_ssl->m_ssl);
+ if (cert != NULL) {
+ LOG((CLOG_INFO "server certificate"));
+ line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
+ LOG((CLOG_INFO "subject: %s", line));
+ OPENSSL_free(line);
+ line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
+ LOG((CLOG_INFO "issuer: %s", line));
+ OPENSSL_free(line);
+ X509_free(cert);
+ }
+ else {
+ LOG((CLOG_INFO "no certificates"));
+ }
+}
+
+bool
+CSecureSocket::checkResult(int n)
+{
+ bool retry = false;
+ int errorCode = SSL_get_error(m_ssl->m_ssl, n);
+
+ switch (errorCode) {
+ case SSL_ERROR_NONE:
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ LOG((CLOG_DEBUG2 "secure socket error: SSL_ERROR_WANT_READ"));
+ retry = true;
+ break;
+
+ case SSL_ERROR_WANT_WRITE:
+ LOG((CLOG_DEBUG2 "secure socket error: SSL_ERROR_WANT_WRITE"));
+ retry = true;
+ break;
+
+ case SSL_ERROR_WANT_CONNECT:
+ LOG((CLOG_DEBUG2 "secure socket error: SSL_ERROR_WANT_CONNECT"));
+ retry = true;
+ break;
+
+ case SSL_ERROR_WANT_ACCEPT:
+ LOG((CLOG_DEBUG2 "secure socket error: SSL_ERROR_WANT_ACCEPT"));
+ retry = true;
+ break;
+
+ case SSL_ERROR_SYSCALL:
+ throwError("Secure socket syscall error");
+ break;
+ case SSL_ERROR_SSL:
+ throwError("Secure socket error");
+ break;
+
+ default:
+ // possible cases:
+ // SSL_ERROR_WANT_X509_LOOKUP, SSL_ERROR_ZERO_RETURN
+ showError();
+ }
+
+ return retry;
+}
+
+void
+CSecureSocket::showError()
+{
+ if (getError()) {
+ LOG((CLOG_ERR "secure socket error: %s", m_error));
+ }
+}
+
+
+void
+CSecureSocket::throwError(const char* reason)
+{
+ if (getError()) {
+ throw XSecureSocket(synergy::string::sprintf(
+ "%s: %s", reason, m_error));
+ }
+}
+
+bool
+CSecureSocket::getError()
+{
+ unsigned long e = ERR_get_error();
+ bool errorUpdated = false;
+
+ if (e != 0) {
+ ERR_error_string_n(e, m_error, m_errorSize);
+ errorUpdated = true;
+ }
+ else {
+ LOG((CLOG_DEBUG "can not detect any error in secure socket"));
+ }
+
+ return errorUpdated;
+}
+
+bool
+CSecureSocket::isReady()
+{
+ return m_ready;
+}
diff --git a/src/plugin/ns/SecureSocket.h b/src/plugin/ns/SecureSocket.h
new file mode 100644
index 00000000..cd7800be
--- /dev/null
+++ b/src/plugin/ns/SecureSocket.h
@@ -0,0 +1,59 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software Ltd.
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include "base/XBase.h"
+#include "base/Log.h"
+
+//! Generic socket exception
+XBASE_SUBCLASS(XSecureSocket, XBase);
+
+//! SSL
+/*!
+Secure socket layer using OpenSSL.
+*/
+
+struct CSsl;
+
+class CSecureSocket {
+public:
+ CSecureSocket();
+ ~CSecureSocket();
+
+ void initContext(bool server);
+ void loadCertificates(const char* CertFile);
+ void createSSL();
+ void accept(int s);
+ void connect(int s);
+ size_t write(const void* buffer, int size);
+ size_t read(void* buffer, int size);
+ bool isReady();
+
+private:
+ void showCertificate();
+ bool checkResult(int n);
+ void showError();
+ void throwError(const char* reason);
+ bool getError();
+
+private:
+ CSsl* m_ssl;
+ bool m_ready;
+ char* m_error;
+ const size_t m_errorSize;
+};