aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/net
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@unit193.net>2021-11-10 00:54:35 -0500
committerLibravatarUnit 193 <unit193@unit193.net>2021-11-10 00:54:35 -0500
commit58fb7a0cee13d84170aac52f3f89d91888e1afe3 (patch)
tree1d6312ba15f9ece5a8031e5280dfb8b38be8dfa3 /src/lib/net
parent28db84b46139c9bb2bbcac8c6cc56e71d1e35629 (diff)
parentbeb08eb751fa8e1f72042f263316ab5e5ddb596d (diff)
Update upstream source from tag 'upstream/2.4.0+dfsg'
Update to upstream version '2.4.0+dfsg' with Debian dir 4b6668cc08c7b0e56b1e1f7b4e89ecdb316182a0
Diffstat (limited to 'src/lib/net')
-rw-r--r--src/lib/net/CMakeLists.txt4
-rw-r--r--src/lib/net/ConnectionSecurityLevel.h27
-rw-r--r--src/lib/net/FingerprintData.cpp52
-rw-r--r--src/lib/net/FingerprintData.h46
-rw-r--r--src/lib/net/FingerprintDatabase.cpp135
-rw-r--r--src/lib/net/FingerprintDatabase.h53
-rw-r--r--src/lib/net/IDataSocket.cpp4
-rw-r--r--src/lib/net/IDataSocket.h4
-rw-r--r--src/lib/net/IListenSocket.h6
-rw-r--r--src/lib/net/ISocket.h4
-rw-r--r--src/lib/net/ISocketFactory.h15
-rw-r--r--src/lib/net/ISocketMultiplexerJob.h4
-rw-r--r--src/lib/net/NetworkAddress.cpp4
-rw-r--r--src/lib/net/NetworkAddress.h6
-rw-r--r--src/lib/net/SecureListenSocket.cpp36
-rw-r--r--src/lib/net/SecureListenSocket.h15
-rw-r--r--src/lib/net/SecureSocket.cpp356
-rw-r--r--src/lib/net/SecureSocket.h62
-rw-r--r--src/lib/net/SecureUtils.cpp312
-rw-r--r--src/lib/net/SecureUtils.h43
-rw-r--r--src/lib/net/SocketMultiplexer.cpp17
-rw-r--r--src/lib/net/SocketMultiplexer.h6
-rw-r--r--src/lib/net/TCPListenSocket.cpp16
-rw-r--r--src/lib/net/TCPListenSocket.h4
-rw-r--r--src/lib/net/TCPSocket.cpp42
-rw-r--r--src/lib/net/TCPSocket.h10
-rw-r--r--src/lib/net/TCPSocketFactory.cpp21
-rw-r--r--src/lib/net/TCPSocketFactory.h15
-rw-r--r--src/lib/net/TSocketMultiplexerMethodJob.h94
-rw-r--r--src/lib/net/XSocket.cpp6
-rw-r--r--src/lib/net/XSocket.h4
31 files changed, 1042 insertions, 381 deletions
diff --git a/src/lib/net/CMakeLists.txt b/src/lib/net/CMakeLists.txt
index 5439450..8c12ed9 100644
--- a/src/lib/net/CMakeLists.txt
+++ b/src/lib/net/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# 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 LICENSE 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
diff --git a/src/lib/net/ConnectionSecurityLevel.h b/src/lib/net/ConnectionSecurityLevel.h
new file mode 100644
index 0000000..913c2fd
--- /dev/null
+++ b/src/lib/net/ConnectionSecurityLevel.h
@@ -0,0 +1,27 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ 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 LICENSE 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_NET_CONNECTION_SECURITY_LEVEL_H
+#define BARRIER_LIB_NET_CONNECTION_SECURITY_LEVEL_H
+
+enum class ConnectionSecurityLevel {
+ PLAINTEXT,
+ ENCRYPTED,
+ ENCRYPTED_AUTHENTICATED
+};
+
+#endif // BARRIER_LIB_NET_CONNECTION_SECURITY_LEVEL_H
diff --git a/src/lib/net/FingerprintData.cpp b/src/lib/net/FingerprintData.cpp
new file mode 100644
index 0000000..460b39b
--- /dev/null
+++ b/src/lib/net/FingerprintData.cpp
@@ -0,0 +1,52 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ 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 LICENSE 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "base/String.h"
+#include "FingerprintDatabase.h"
+#include "io/filesystem.h"
+#include <algorithm>
+#include <fstream>
+
+namespace barrier {
+
+bool FingerprintData::operator==(const FingerprintData& other) const
+{
+ return algorithm == other.algorithm && data == other.data;
+}
+
+const char* fingerprint_type_to_string(FingerprintType type)
+{
+ switch (type) {
+ case FingerprintType::INVALID: return "invalid";
+ case FingerprintType::SHA1: return "sha1";
+ case FingerprintType::SHA256: return "sha256";
+ }
+ return "invalid";
+}
+
+FingerprintType fingerprint_type_from_string(const std::string& type)
+{
+ if (type == "sha1") {
+ return FingerprintType::SHA1;
+ }
+ if (type == "sha256") {
+ return FingerprintType::SHA256;
+ }
+ return FingerprintType::INVALID;
+}
+
+} // namespace barrier
diff --git a/src/lib/net/FingerprintData.h b/src/lib/net/FingerprintData.h
new file mode 100644
index 0000000..938a695
--- /dev/null
+++ b/src/lib/net/FingerprintData.h
@@ -0,0 +1,46 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ 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 LICENSE 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_NET_FINGERPRINT_DATA_H
+#define BARRIER_LIB_NET_FINGERPRINT_DATA_H
+
+#include <string>
+#include <vector>
+
+namespace barrier {
+
+enum FingerprintType {
+ INVALID,
+ SHA1, // deprecated
+ SHA256,
+};
+
+struct FingerprintData {
+ std::string algorithm;
+ std::vector<std::uint8_t> data;
+
+ bool valid() const { return !algorithm.empty(); }
+
+ bool operator==(const FingerprintData& other) const;
+};
+
+const char* fingerprint_type_to_string(FingerprintType type);
+FingerprintType fingerprint_type_from_string(const std::string& type);
+
+} // namespace barrier
+
+#endif // BARRIER_LIB_NET_FINGERPRINT_TYPE_H
diff --git a/src/lib/net/FingerprintDatabase.cpp b/src/lib/net/FingerprintDatabase.cpp
new file mode 100644
index 0000000..def0de9
--- /dev/null
+++ b/src/lib/net/FingerprintDatabase.cpp
@@ -0,0 +1,135 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ 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 LICENSE 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "base/String.h"
+#include "FingerprintDatabase.h"
+#include "io/filesystem.h"
+#include <algorithm>
+#include <fstream>
+
+namespace barrier {
+
+void FingerprintDatabase::read(const fs::path& path)
+{
+ std::ifstream file;
+ open_utf8_path(file, path, std::ios_base::in);
+ read_stream(file);
+}
+
+void FingerprintDatabase::write(const fs::path& path)
+{
+ std::ofstream file;
+ open_utf8_path(file, path, std::ios_base::out);
+ write_stream(file);
+}
+
+void FingerprintDatabase::read_stream(std::istream& stream)
+{
+ if (!stream.good()) {
+ return;
+ }
+
+ std::string line;
+ while (std::getline(stream, line)) {
+ if (line.empty()) {
+ continue;
+ }
+
+ auto fingerprint = parse_db_line(line);
+ if (!fingerprint.valid()) {
+ continue;
+ }
+
+ fingerprints_.push_back(fingerprint);
+ }
+}
+
+void FingerprintDatabase::write_stream(std::ostream& stream)
+{
+ if (!stream.good()) {
+ return;
+ }
+
+ for (const auto& fingerprint : fingerprints_) {
+ stream << to_db_line(fingerprint) << "\n";
+ }
+}
+
+void FingerprintDatabase::clear()
+{
+ fingerprints_.clear();
+}
+
+void FingerprintDatabase::add_trusted(const FingerprintData& fingerprint)
+{
+ if (is_trusted(fingerprint)) {
+ return;
+ }
+ fingerprints_.push_back(fingerprint);
+}
+
+bool FingerprintDatabase::is_trusted(const FingerprintData& fingerprint)
+{
+ auto found_it = std::find(fingerprints_.begin(), fingerprints_.end(), fingerprint);
+ return found_it != fingerprints_.end();
+}
+
+FingerprintData FingerprintDatabase::parse_db_line(const std::string& line)
+{
+ FingerprintData result;
+
+ // legacy v1 certificate handling
+ if (std::count(line.begin(), line.end(), ':') == 19 && line.size() == 40 + 19) {
+ auto data = string::from_hex(line);
+ if (data.empty()) {
+ return result;
+ }
+ result.algorithm = fingerprint_type_to_string(FingerprintType::SHA1);
+ result.data = data;
+ return result;
+ }
+
+ auto version_end_pos = line.find(':');
+ if (version_end_pos == std::string::npos) {
+ return result;
+ }
+ if (line.substr(0, version_end_pos) != "v2") {
+ return result;
+ }
+ auto algo_start_pos = version_end_pos + 1;
+ auto algo_end_pos = line.find(':', algo_start_pos);
+ if (algo_end_pos == std::string::npos) {
+ return result;
+ }
+ auto algorithm = line.substr(algo_start_pos, algo_end_pos - algo_start_pos);
+ auto data = string::from_hex(line.substr(algo_end_pos + 1));
+
+ if (data.empty()) {
+ return result;
+ }
+
+ result.algorithm = algorithm;
+ result.data = data;
+ return result;
+}
+
+std::string FingerprintDatabase::to_db_line(const FingerprintData& fingerprint)
+{
+ return "v2:" + fingerprint.algorithm + ":" + string::to_hex(fingerprint.data, 2);
+}
+
+} // namespace barrier
diff --git a/src/lib/net/FingerprintDatabase.h b/src/lib/net/FingerprintDatabase.h
new file mode 100644
index 0000000..4927265
--- /dev/null
+++ b/src/lib/net/FingerprintDatabase.h
@@ -0,0 +1,53 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ 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 LICENSE 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_NET_FINGERPRINT_DATABASE_H
+#define BARRIER_LIB_NET_FINGERPRINT_DATABASE_H
+
+#include "FingerprintData.h"
+#include "io/filesystem.h"
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+namespace barrier {
+
+class FingerprintDatabase {
+public:
+ void read(const fs::path& path);
+ void write(const fs::path& path);
+
+ void read_stream(std::istream& stream);
+ void write_stream(std::ostream& stream);
+
+ void clear();
+ void add_trusted(const FingerprintData& fingerprint);
+ bool is_trusted(const FingerprintData& fingerprint);
+
+ const std::vector<FingerprintData>& fingerprints() const { return fingerprints_; }
+
+ static FingerprintData parse_db_line(const std::string& line);
+ static std::string to_db_line(const FingerprintData& fingerprint);
+
+private:
+
+ std::vector<FingerprintData> fingerprints_;
+};
+
+} // namespace barrier
+
+#endif // BARRIER_LIB_NET_FINGERPRINT_DATABASE_H
diff --git a/src/lib/net/IDataSocket.cpp b/src/lib/net/IDataSocket.cpp
index cc679c3..30e00f4 100644
--- a/src/lib/net/IDataSocket.cpp
+++ b/src/lib/net/IDataSocket.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
diff --git a/src/lib/net/IDataSocket.h b/src/lib/net/IDataSocket.h
index c77a99c..0fc41bb 100644
--- a/src/lib/net/IDataSocket.h
+++ b/src/lib/net/IDataSocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
diff --git a/src/lib/net/IListenSocket.h b/src/lib/net/IListenSocket.h
index 73dcc6e..5452a37 100644
--- a/src/lib/net/IListenSocket.h
+++ b/src/lib/net/IListenSocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -41,7 +41,7 @@ public:
*/
virtual IDataSocket*
accept() = 0;
-
+
//@}
// ISocket overrides
diff --git a/src/lib/net/ISocket.h b/src/lib/net/ISocket.h
index 0e9688b..f41fd55 100644
--- a/src/lib/net/ISocket.h
+++ b/src/lib/net/ISocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
diff --git a/src/lib/net/ISocketFactory.h b/src/lib/net/ISocketFactory.h
index e440953..edfc8c9 100644
--- a/src/lib/net/ISocketFactory.h
+++ b/src/lib/net/ISocketFactory.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -20,6 +20,7 @@
#include "common/IInterface.h"
#include "arch/IArchNetwork.h"
+#include "net/ConnectionSecurityLevel.h"
class IDataSocket;
class IListenSocket;
@@ -35,14 +36,12 @@ public:
//@{
//! Create data socket
- virtual IDataSocket* create(
- IArchNetwork::EAddressFamily family,
- bool secure) const = 0;
+ virtual IDataSocket* create(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const = 0;
//! Create listen socket
- virtual IListenSocket* createListen(
- IArchNetwork::EAddressFamily family,
- bool secure) const = 0;
+ virtual IListenSocket* createListen(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const = 0;
//@}
};
diff --git a/src/lib/net/ISocketMultiplexerJob.h b/src/lib/net/ISocketMultiplexerJob.h
index c27fce2..2dab87e 100644
--- a/src/lib/net/ISocketMultiplexerJob.h
+++ b/src/lib/net/ISocketMultiplexerJob.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
diff --git a/src/lib/net/NetworkAddress.cpp b/src/lib/net/NetworkAddress.cpp
index c8ea9c6..3526fc0 100644
--- a/src/lib/net/NetworkAddress.cpp
+++ b/src/lib/net/NetworkAddress.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
diff --git a/src/lib/net/NetworkAddress.h b/src/lib/net/NetworkAddress.h
index 87dc1e4..3a006af 100644
--- a/src/lib/net/NetworkAddress.h
+++ b/src/lib/net/NetworkAddress.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -43,7 +43,7 @@ public:
If \c hostname can be parsed as a numerical address then that's how
it's used, otherwise it's used as a host name. If \c hostname ends
in ":[0-9]+" then that suffix is extracted and used as the port,
- overridding the port parameter. The resulting port must be a valid
+ overriding the port parameter. The resulting port must be a valid
port number (zero is not a valid port number) otherwise \c XSocketAddress
is thrown with an error of \c XSocketAddress::kBadPort. The hostname
is not resolved by the c'tor; use \c resolve to do that.
diff --git a/src/lib/net/SecureListenSocket.cpp b/src/lib/net/SecureListenSocket.cpp
index a137f39..11efc5c 100644
--- a/src/lib/net/SecureListenSocket.cpp
+++ b/src/lib/net/SecureListenSocket.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless 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 LICENSE 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
@@ -20,23 +20,16 @@
#include "SecureSocket.h"
#include "net/NetworkAddress.h"
#include "net/SocketMultiplexer.h"
-#include "net/TSocketMultiplexerMethodJob.h"
+#include "arch/Arch.h"
#include "arch/XArch.h"
#include "common/DataDirectories.h"
#include "base/String.h"
-static const char s_certificateDir[] = { "SSL" };
-static const char s_certificateFilename[] = { "Barrier.pem" };
-
-//
-// SecureListenSocket
-//
-
-SecureListenSocket::SecureListenSocket(
- IEventQueue* events,
- SocketMultiplexer* socketMultiplexer,
- IArchNetwork::EAddressFamily family) :
- TCPListenSocket(events, socketMultiplexer, family)
+SecureListenSocket::SecureListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) :
+ TCPListenSocket(events, socketMultiplexer, family),
+ security_level_{security_level}
{
}
@@ -45,22 +38,15 @@ SecureListenSocket::accept()
{
SecureSocket* socket = NULL;
try {
- socket = new SecureSocket(
- m_events,
- m_socketMultiplexer,
- ARCH->acceptSocket(m_socket, NULL));
+ socket = new SecureSocket(m_events, m_socketMultiplexer,
+ ARCH->acceptSocket(m_socket, NULL), security_level_);
socket->initSsl(true);
if (socket != NULL) {
setListeningJob();
}
- std::string certificateFilename = barrier::string::sprintf("%s/%s/%s",
- DataDirectories::profile().c_str(),
- s_certificateDir,
- s_certificateFilename);
-
- bool loaded = socket->loadCertificates(certificateFilename);
+ bool loaded = socket->load_certificates(barrier::DataDirectories::ssl_certificate_path());
if (!loaded) {
delete socket;
return NULL;
diff --git a/src/lib/net/SecureListenSocket.h b/src/lib/net/SecureListenSocket.h
index d0c6e23..a0e792a 100644
--- a/src/lib/net/SecureListenSocket.h
+++ b/src/lib/net/SecureListenSocket.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless 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 LICENSE 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
@@ -19,18 +19,21 @@
#include "net/TCPListenSocket.h"
#include "common/stdset.h"
+#include "ConnectionSecurityLevel.h"
class IEventQueue;
class SocketMultiplexer;
class IDataSocket;
-class SecureListenSocket : public TCPListenSocket{
+class SecureListenSocket : public TCPListenSocket {
public:
- SecureListenSocket(IEventQueue* events,
- SocketMultiplexer* socketMultiplexer,
- IArchNetwork::EAddressFamily family);
+ SecureListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level);
// IListenSocket overrides
virtual IDataSocket*
accept();
+private:
+ ConnectionSecurityLevel security_level_;
};
diff --git a/src/lib/net/SecureSocket.cpp b/src/lib/net/SecureSocket.cpp
index 855e16b..85e1d38 100644
--- a/src/lib/net/SecureSocket.cpp
+++ b/src/lib/net/SecureSocket.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless 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 LICENSE 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
@@ -16,6 +16,7 @@
*/
#include "SecureSocket.h"
+#include "SecureUtils.h"
#include "net/TSocketMultiplexerMethodJob.h"
#include "base/TMethodEventJob.h"
@@ -25,6 +26,8 @@
#include "base/Log.h"
#include "base/String.h"
#include "common/DataDirectories.h"
+#include "io/filesystem.h"
+#include "net/FingerprintDatabase.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
@@ -40,41 +43,36 @@
#define MAX_ERROR_SIZE 65535
+static const std::size_t MAX_INPUT_BUFFER_SIZE = 1024 * 1024;
static const float s_retryDelay = 0.01f;
enum {
kMsgSize = 128
};
-static const char kFingerprintDirName[] = "SSL/Fingerprints";
-//static const char kFingerprintLocalFilename[] = "Local.txt";
-static const char kFingerprintTrustedServersFilename[] = "TrustedServers.txt";
-//static const char kFingerprintTrustedClientsFilename[] = "TrustedClients.txt";
-
struct Ssl {
SSL_CTX* m_context;
SSL* m_ssl;
};
-SecureSocket::SecureSocket(
- IEventQueue* events,
- SocketMultiplexer* socketMultiplexer,
- IArchNetwork::EAddressFamily family) :
+SecureSocket::SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) :
TCPSocket(events, socketMultiplexer, family),
m_ssl(nullptr),
m_secureReady(false),
- m_fatal(false)
+ m_fatal(false),
+ security_level_{security_level}
{
}
-SecureSocket::SecureSocket(
- IEventQueue* events,
- SocketMultiplexer* socketMultiplexer,
- ArchSocket socket) :
+SecureSocket::SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ ArchSocket socket, ConnectionSecurityLevel security_level) :
TCPSocket(events, socketMultiplexer, socket),
m_ssl(nullptr),
m_secureReady(false),
- m_fatal(false)
+ m_fatal(false),
+ security_level_{security_level}
{
}
@@ -103,6 +101,8 @@ SecureSocket::close()
void SecureSocket::freeSSLResources()
{
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
if (m_ssl->m_ssl != NULL) {
SSL_shutdown(m_ssl->m_ssl);
SSL_free(m_ssl->m_ssl);
@@ -133,30 +133,30 @@ std::unique_ptr<ISocketMultiplexerJob> SecureSocket::newJob()
if (m_connected && !m_secureReady) {
return {};
}
-
+
return TCPSocket::newJob();
}
void
SecureSocket::secureConnect()
{
- setJob(std::make_unique<TSocketMultiplexerMethodJob<SecureSocket>>(
- this, &SecureSocket::serviceConnect,
- getSocket(), isReadable(), isWritable()));
+ setJob(std::make_unique<TSocketMultiplexerMethodJob>([this](auto j, auto r, auto w, auto e)
+ { return serviceConnect(j, r, w, e); },
+ getSocket(), isReadable(), isWritable()));
}
void
SecureSocket::secureAccept()
{
- setJob(std::make_unique<TSocketMultiplexerMethodJob<SecureSocket>>(
- this, &SecureSocket::serviceAccept,
- getSocket(), isReadable(), isWritable()));
+ setJob(std::make_unique<TSocketMultiplexerMethodJob>([this](auto j, auto r, auto w, auto e)
+ { return serviceAccept(j, r, w, e); },
+ getSocket(), isReadable(), isWritable()));
}
TCPSocket::EJobResult
SecureSocket::doRead()
{
- static UInt8 buffer[4096];
+ UInt8 buffer[4096];
memset(buffer, 0, sizeof(buffer));
int bytesRead = 0;
int status = 0;
@@ -173,20 +173,24 @@ SecureSocket::doRead()
else {
return kRetry;
}
-
+
if (bytesRead > 0) {
bool wasEmpty = (m_inputBuffer.getSize() == 0);
-
+
// slurp up as much as possible
do {
m_inputBuffer.write(buffer, bytesRead);
-
+
+ if (m_inputBuffer.getSize() > MAX_INPUT_BUFFER_SIZE) {
+ break;
+ }
+
status = secureRead(buffer, sizeof(buffer), bytesRead);
if (status < 0) {
return kBreak;
}
} while (bytesRead > 0 || status > 0);
-
+
// send input ready if input buffer was empty
if (wasEmpty) {
sendEvent(m_events->forIStream().inputReady());
@@ -204,18 +208,13 @@ SecureSocket::doRead()
m_readable = false;
return kNew;
}
-
+
return kRetry;
}
TCPSocket::EJobResult
SecureSocket::doWrite()
{
- static bool s_retry = false;
- static int s_retrySize = 0;
- static std::unique_ptr<char[]> s_staticBuffer;
- static std::size_t s_staticBufferSize = 0;
-
// write data
int bufferSize = 0;
int bytesWrote = 0;
@@ -224,34 +223,34 @@ SecureSocket::doWrite()
if (!isSecureReady())
return kRetry;
- if (s_retry) {
- bufferSize = s_retrySize;
+ if (do_write_retry_) {
+ bufferSize = do_write_retry_size_;
} else {
bufferSize = m_outputBuffer.getSize();
- if (bufferSize > s_staticBufferSize) {
- s_staticBuffer.reset(new char[bufferSize]);
- s_staticBufferSize = bufferSize;
+ if (bufferSize > do_write_retry_buffer_size_) {
+ do_write_retry_buffer_.reset(new char[bufferSize]);
+ do_write_retry_buffer_size_ = bufferSize;
}
if (bufferSize > 0) {
- memcpy(s_staticBuffer.get(), m_outputBuffer.peek(bufferSize), bufferSize);
+ std::memcpy(do_write_retry_buffer_.get(), m_outputBuffer.peek(bufferSize), bufferSize);
}
}
-
+
if (bufferSize == 0) {
return kRetry;
}
- status = secureWrite(s_staticBuffer.get(), bufferSize, bytesWrote);
+ status = secureWrite(do_write_retry_buffer_.get(), bufferSize, bytesWrote);
if (status > 0) {
- s_retry = false;
+ do_write_retry_ = false;
} else if (status < 0) {
return kBreak;
} else if (status == 0) {
- s_retry = true;
- s_retrySize = bufferSize;
+ do_write_retry_ = true;
+ do_write_retry_size_ = bufferSize;
return kNew;
}
-
+
if (bytesWrote > 0) {
discardWrittenData(bytesWrote);
return kNew;
@@ -263,16 +262,16 @@ SecureSocket::doWrite()
int
SecureSocket::secureRead(void* buffer, int size, int& read)
{
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
if (m_ssl->m_ssl != NULL) {
LOG((CLOG_DEBUG2 "reading secure socket"));
read = SSL_read(m_ssl->m_ssl, buffer, size);
-
- static int retry;
// Check result will cleanup the connection in the case of a fatal
- checkResult(read, retry);
-
- if (retry) {
+ checkResult(read, secure_read_retry_);
+
+ if (secure_read_retry_) {
return 0;
}
@@ -289,17 +288,17 @@ SecureSocket::secureRead(void* buffer, int size, int& read)
int
SecureSocket::secureWrite(const void* buffer, int size, int& wrote)
{
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
if (m_ssl->m_ssl != NULL) {
LOG((CLOG_DEBUG2 "writing secure socket:%p", this));
wrote = SSL_write(m_ssl->m_ssl, buffer, size);
-
- static int retry;
// Check result will cleanup the connection in the case of a fatal
- checkResult(wrote, retry);
+ checkResult(wrote, secure_write_retry_);
- if (retry) {
+ if (secure_write_retry_) {
return 0;
}
@@ -322,6 +321,8 @@ SecureSocket::isSecureReady()
void
SecureSocket::initSsl(bool server)
{
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
m_ssl = new Ssl();
m_ssl->m_context = NULL;
m_ssl->m_ssl = NULL;
@@ -329,54 +330,57 @@ SecureSocket::initSsl(bool server)
initContext(server);
}
-bool SecureSocket::loadCertificates(std::string& filename)
+bool SecureSocket::load_certificates(const barrier::fs::path& path)
{
- if (filename.empty()) {
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
+ if (path.empty()) {
showError("ssl certificate is not specified");
return false;
}
else {
- std::ifstream file(filename.c_str());
- bool exist = file.good();
- file.close();
-
- if (!exist) {
- std::string errorMsg("ssl certificate doesn't exist: ");
- errorMsg.append(filename);
- showError(errorMsg.c_str());
+ if (!barrier::fs::is_regular_file(path)) {
+ showError("ssl certificate doesn't exist: " + path.u8string());
return false;
}
}
int r = 0;
- r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM);
+ r = SSL_CTX_use_certificate_file(m_ssl->m_context, path.u8string().c_str(), SSL_FILETYPE_PEM);
if (r <= 0) {
- showError("could not use ssl certificate");
+ showError("could not use ssl certificate: " + path.u8string());
return false;
}
- r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM);
+ r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, path.u8string().c_str(), SSL_FILETYPE_PEM);
if (r <= 0) {
- showError("could not use ssl private key");
+ showError("could not use ssl private key: " + path.u8string());
return false;
}
r = SSL_CTX_check_private_key(m_ssl->m_context);
if (!r) {
- showError("could not verify ssl private key");
+ showError("could not verify ssl private key: " + path.u8string());
return false;
}
return true;
}
+static int cert_verify_ignore_callback(X509_STORE_CTX*, void*)
+{
+ return 1;
+}
+
void
SecureSocket::initContext(bool server)
{
+ // ssl_mutex_ is assumed to be acquired
+
SSL_library_init();
const SSL_METHOD* method;
-
+
// load & register all cryptos, etc.
OpenSSL_add_all_algorithms();
@@ -394,7 +398,7 @@ SecureSocket::initContext(bool server)
else {
method = SSLv23_client_method();
}
-
+
// create new context from method
SSL_METHOD* m = const_cast<SSL_METHOD*>(method);
m_ssl->m_context = SSL_CTX_new(m);
@@ -403,13 +407,23 @@ SecureSocket::initContext(bool server)
SSL_CTX_set_options(m_ssl->m_context, SSL_OP_NO_SSLv3);
if (m_ssl->m_context == NULL) {
- showError();
+ showError("");
+ }
+
+ if (security_level_ == ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED) {
+ // We want to ask for peer certificate, but not verify it. If we don't ask for peer
+ // certificate, e.g. client won't send it.
+ SSL_CTX_set_verify(m_ssl->m_context, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ nullptr);
+ SSL_CTX_set_cert_verify_callback(m_ssl->m_context, cert_verify_ignore_callback, nullptr);
}
}
void
SecureSocket::createSSL()
{
+ // ssl_mutex_ is assumed to be acquired
+
// I assume just one instance is needed
// get new SSL state with context
if (m_ssl->m_ssl == NULL) {
@@ -421,17 +435,17 @@ SecureSocket::createSSL()
int
SecureSocket::secureAccept(int socket)
{
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
createSSL();
// set connection socket to SSL state
SSL_set_fd(m_ssl->m_ssl, socket);
-
+
LOG((CLOG_DEBUG2 "accepting secure socket"));
int r = SSL_accept(m_ssl->m_ssl);
-
- static int retry;
- checkResult(r, retry);
+ checkResult(r, secure_accept_retry_);
if (isFatal()) {
// tell user and sleep so the socket isn't hammered.
@@ -439,12 +453,30 @@ SecureSocket::secureAccept(int socket)
LOG((CLOG_INFO "client connection may not be secure"));
m_secureReady = false;
ARCH->sleep(1);
- retry = 0;
+ secure_accept_retry_ = 0;
return -1; // Failed, error out
}
// If not fatal and no retry, state is good
- if (retry == 0) {
+ if (secure_accept_retry_ == 0) {
+ if (security_level_ == ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED) {
+ if (verify_cert_fingerprint(
+ barrier::DataDirectories::trusted_clients_ssl_fingerprints_path())) {
+ LOG((CLOG_INFO "accepted secure socket"));
+ if (!ensure_peer_certificate()) {
+ secure_accept_retry_ = 0;
+ disconnect();
+ return -1;// Cert fail, error
+ }
+ }
+ else {
+ LOG((CLOG_ERR "failed to verify server certificate fingerprint"));
+ secure_accept_retry_ = 0;
+ disconnect();
+ return -1; // Fingerprint failed, error
+ }
+ }
+
m_secureReady = true;
LOG((CLOG_INFO "accepted secure socket"));
if (CLOG->getFilter() >= kDEBUG1) {
@@ -455,7 +487,7 @@ SecureSocket::secureAccept(int socket)
}
// If not fatal and retry is set, not ready, and return retry
- if (retry > 0) {
+ if (secure_accept_retry_ > 0) {
LOG((CLOG_DEBUG2 "retry accepting secure socket"));
m_secureReady = false;
ARCH->sleep(s_retryDelay);
@@ -470,38 +502,45 @@ SecureSocket::secureAccept(int socket)
int
SecureSocket::secureConnect(int socket)
{
+ // note that load_certificates acquires ssl_mutex_
+ if (!load_certificates(barrier::DataDirectories::ssl_certificate_path())) {
+ LOG((CLOG_ERR "could not load client certificates"));
+ // FIXME: this is fatal error, but we current don't disconnect because whole logic in this
+ // function needs to be cleaned up
+ }
+
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
createSSL();
// attach the socket descriptor
SSL_set_fd(m_ssl->m_ssl, socket);
-
+
LOG((CLOG_DEBUG2 "connecting secure socket"));
int r = SSL_connect(m_ssl->m_ssl);
-
- static int retry;
- checkResult(r, retry);
+ checkResult(r, secure_connect_retry_);
if (isFatal()) {
LOG((CLOG_ERR "failed to connect secure socket"));
- retry = 0;
+ secure_connect_retry_ = 0;
return -1;
}
// If we should retry, not ready and return 0
- if (retry > 0) {
+ if (secure_connect_retry_ > 0) {
LOG((CLOG_DEBUG2 "retry connect secure socket"));
m_secureReady = false;
ARCH->sleep(s_retryDelay);
return 0;
}
- retry = 0;
+ secure_connect_retry_ = 0;
// No error, set ready, process and return ok
m_secureReady = true;
- if (verifyCertFingerprint()) {
+ if (verify_cert_fingerprint(barrier::DataDirectories::trusted_servers_ssl_fingerprints_path())) {
LOG((CLOG_INFO "connected to secure socket"));
- if (!showCertificate()) {
+ if (!ensure_peer_certificate()) {
disconnect();
return -1;// Cert fail, error
}
@@ -520,21 +559,22 @@ SecureSocket::secureConnect(int socket)
}
bool
-SecureSocket::showCertificate()
+SecureSocket::ensure_peer_certificate()
{
+ // ssl_mutex_ is assumed to be acquired
X509* cert;
char* line;
-
+
// get the server's certificate
cert = SSL_get_peer_certificate(m_ssl->m_ssl);
if (cert != NULL) {
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
- LOG((CLOG_INFO "server ssl certificate info: %s", line));
+ LOG((CLOG_INFO "peer ssl certificate info: %s", line));
OPENSSL_free(line);
X509_free(cert);
}
else {
- showError("server has no ssl certificate");
+ showError("peer has no ssl certificate");
return false;
}
@@ -544,6 +584,8 @@ SecureSocket::showCertificate()
void
SecureSocket::checkResult(int status, int& retry)
{
+ // ssl_mutex_ is assumed to be acquired
+
// ssl errors are a little quirky. the "want" errors are normal and
// should result in a retry.
@@ -568,7 +610,7 @@ SecureSocket::checkResult(int status, int& retry)
case SSL_ERROR_WANT_WRITE:
// Need to make sure the socket is known to be writable so the impending
- // select action actually triggers on a write. This isn't necessary for
+ // select action actually triggers on a write. This isn't necessary for
// m_readable because the socket logic is always readable
m_writable = true;
retry++;
@@ -618,16 +660,15 @@ SecureSocket::checkResult(int status, int& retry)
if (isFatal()) {
retry = 0;
- showError();
+ showError("");
disconnect();
}
}
-void
-SecureSocket::showError(const char* reason)
+void SecureSocket::showError(const std::string& reason)
{
- if (reason != NULL) {
- LOG((CLOG_ERR "%s", reason));
+ if (!reason.empty()) {
+ LOG((CLOG_ERR "%s", reason.c_str()));
}
std::string error = getError();
@@ -658,83 +699,49 @@ SecureSocket::disconnect()
sendEvent(getEvents()->forIStream().inputShutdown());
}
-void SecureSocket::formatFingerprint(std::string& fingerprint, bool hex, bool separator)
+bool SecureSocket::verify_cert_fingerprint(const barrier::fs::path& fingerprint_db_path)
{
- if (hex) {
- // to hexidecimal
- barrier::string::toHex(fingerprint, 2);
- }
-
- // all uppercase
- barrier::string::uppercase(fingerprint);
+ // ssl_mutex_ is assumed to be acquired
- if (separator) {
- // add colon to separate each 2 charactors
- size_t separators = fingerprint.size() / 2;
- for (size_t i = 1; i < separators; i++) {
- fingerprint.insert(i * 3 - 1, ":");
- }
- }
-}
-
-bool
-SecureSocket::verifyCertFingerprint()
-{
// calculate received certificate fingerprint
- X509 *cert = cert = SSL_get_peer_certificate(m_ssl->m_ssl);
- EVP_MD* tempDigest;
- unsigned char tempFingerprint[EVP_MAX_MD_SIZE];
- unsigned int tempFingerprintLen;
- tempDigest = (EVP_MD*)EVP_sha1();
- int digestResult = X509_digest(cert, tempDigest, tempFingerprint, &tempFingerprintLen);
-
- if (digestResult <= 0) {
- LOG((CLOG_ERR "failed to calculate fingerprint, digest result: %d", digestResult));
+ barrier::FingerprintData fingerprint_sha1, fingerprint_sha256;
+ try {
+ auto* cert = SSL_get_peer_certificate(m_ssl->m_ssl);
+ fingerprint_sha1 = barrier::get_ssl_cert_fingerprint(cert,
+ barrier::FingerprintType::SHA1);
+ fingerprint_sha256 = barrier::get_ssl_cert_fingerprint(cert,
+ barrier::FingerprintType::SHA256);
+ } catch (const std::exception& e) {
+ LOG((CLOG_ERR "%s", e.what()));
return false;
}
- // format fingerprint into hexdecimal format with colon separator
- std::string fingerprint(reinterpret_cast<char*>(tempFingerprint), tempFingerprintLen);
- formatFingerprint(fingerprint);
- LOG((CLOG_NOTE "server fingerprint: %s", fingerprint.c_str()));
-
- std::string trustedServersFilename;
- trustedServersFilename = barrier::string::sprintf(
- "%s/%s/%s",
- DataDirectories::profile().c_str(),
- kFingerprintDirName,
- kFingerprintTrustedServersFilename);
+ // note: the GUI parses the following two lines of logs, don't change unnecessarily
+ LOG((CLOG_NOTE "peer fingerprint (SHA1): %s (SHA256): %s",
+ barrier::format_ssl_fingerprint(fingerprint_sha1.data).c_str(),
+ barrier::format_ssl_fingerprint(fingerprint_sha256.data).c_str()));
// Provide debug hint as to what file is being used to verify fingerprint trust
- LOG((CLOG_NOTE "trustedServersFilename: %s", trustedServersFilename.c_str() ));
+ LOG((CLOG_NOTE "fingerprint_db_path: %s", fingerprint_db_path.u8string().c_str()));
- // check if this fingerprint exist
- std::string fileLine;
- std::ifstream file;
- file.open(trustedServersFilename.c_str());
+ barrier::FingerprintDatabase db;
+ db.read(fingerprint_db_path);
- if (!file.is_open()) {
- LOG((CLOG_NOTE "Unable to open trustedServersFile: %s", trustedServersFilename.c_str() ));
+ if (!db.fingerprints().empty()) {
+ LOG((CLOG_NOTE "Read %d fingerprints from: %s", db.fingerprints().size(),
+ fingerprint_db_path.u8string().c_str()));
} else {
- LOG((CLOG_NOTE "Opened trustedServersFilename: %s", trustedServersFilename.c_str() ));
+ LOG((CLOG_NOTE "Could not read fingerprints from: %s",
+ fingerprint_db_path.u8string().c_str()));
}
- bool isValid = false;
- while (!file.eof() && file.is_open()) {
- getline(file,fileLine);
- if (!fileLine.empty()) {
- if (fileLine.compare(fingerprint) == 0) {
- LOG((CLOG_NOTE "Fingerprint matches trusted fingerprint"));
- isValid = true;
- break;
- } else {
- LOG((CLOG_NOTE "Fingerprint does not match trusted fingerprint"));
- }
- }
+ if (db.is_trusted(fingerprint_sha256)) {
+ LOG((CLOG_NOTE "Fingerprint matches trusted fingerprint"));
+ return true;
+ } else {
+ LOG((CLOG_NOTE "Fingerprint does not match trusted fingerprint"));
+ return false;
}
-
- file.close();
- return isValid;
}
MultiplexerJobStatus SecureSocket::serviceConnect(ISocketMultiplexerJob* job,
@@ -765,9 +772,9 @@ MultiplexerJobStatus SecureSocket::serviceConnect(ISocketMultiplexerJob* job,
// Retry case
return {
true,
- std::make_unique<TSocketMultiplexerMethodJob<SecureSocket>>(
- this, &SecureSocket::serviceConnect,
- getSocket(), isReadable(), isWritable())
+ std::make_unique<TSocketMultiplexerMethodJob>([this](auto j, auto r, auto w, auto e)
+ { return serviceConnect(j, r, w, e); },
+ getSocket(), isReadable(), isWritable())
};
}
@@ -795,9 +802,12 @@ MultiplexerJobStatus SecureSocket::serviceAccept(ISocketMultiplexerJob* job,
}
// Retry case
- return {true, std::make_unique<TSocketMultiplexerMethodJob<SecureSocket>>(
- this, &SecureSocket::serviceAccept,
- getSocket(), isReadable(), isWritable())};
+ return {
+ true,
+ std::make_unique<TSocketMultiplexerMethodJob>([this](auto j, auto r, auto w, auto e)
+ { return serviceAccept(j, r, w, e); },
+ getSocket(), isReadable(), isWritable())
+ };
}
void
@@ -822,6 +832,8 @@ showCipherStackDesc(STACK_OF(SSL_CIPHER) * stack) {
void
SecureSocket::showSecureCipherInfo()
{
+ // ssl_mutex_ is assumed to be acquired
+
STACK_OF(SSL_CIPHER) * sStack = SSL_get_ciphers(m_ssl->m_ssl);
if (sStack == NULL) {
@@ -832,8 +844,8 @@ SecureSocket::showSecureCipherInfo()
showCipherStackDesc(sStack);
}
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
- // m_ssl->m_ssl->session->ciphers is not forward compatable,
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ // m_ssl->m_ssl->session->ciphers is not forward compatible,
// In future release of OpenSSL, it's not visible,
STACK_OF(SSL_CIPHER) * cStack = m_ssl->m_ssl->session->ciphers;
#else
@@ -864,6 +876,8 @@ SecureSocket::showSecureLibInfo()
void
SecureSocket::showSecureConnectInfo()
{
+ // ssl_mutex_ is assumed to be acquired
+
const SSL_CIPHER* cipher = SSL_get_current_cipher(m_ssl->m_ssl);
if (cipher != NULL) {
diff --git a/src/lib/net/SecureSocket.h b/src/lib/net/SecureSocket.h
index c602e2d..be7dc0d 100644
--- a/src/lib/net/SecureSocket.h
+++ b/src/lib/net/SecureSocket.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless 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 LICENSE 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
@@ -17,8 +17,11 @@
#pragma once
+#include "ConnectionSecurityLevel.h"
#include "net/TCPSocket.h"
#include "net/XSocket.h"
+#include "io/filesystem.h"
+#include <mutex>
class IEventQueue;
class SocketMultiplexer;
@@ -32,10 +35,10 @@ A secure socket using SSL.
*/
class SecureSocket : public TCPSocket {
public:
- SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family);
- SecureSocket(IEventQueue* events,
- SocketMultiplexer* socketMultiplexer,
- ArchSocket socket);
+ SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ IArchNetwork::EAddressFamily family, ConnectionSecurityLevel security_level);
+ SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ ArchSocket socket, ConnectionSecurityLevel security_level);
~SecureSocket();
// ISocket overrides
@@ -43,7 +46,7 @@ public:
// IDataSocket overrides
virtual void connect(const NetworkAddress&) override;
-
+
std::unique_ptr<ISocketMultiplexerJob> newJob() override;
bool isFatal() const override { return m_fatal; }
void isFatal(bool b) { m_fatal = b; }
@@ -55,35 +58,56 @@ public:
EJobResult doRead() override;
EJobResult doWrite() override;
void initSsl(bool server);
- bool loadCertificates(std::string& CertFile);
+ bool load_certificates(const barrier::fs::path& path);
private:
// SSL
- void initContext(bool server);
- void createSSL();
+ void initContext(bool server); // may only be called with ssl_mutex_ acquired
+ void createSSL(); // may only be called with ssl_mutex_ acquired.
int secureAccept(int s);
int secureConnect(int s);
- bool showCertificate();
- void checkResult(int n, int& retry);
- void showError(const char* reason = NULL);
+ bool ensure_peer_certificate(); // may only be called with ssl_mutex_ acquired
+
+ void checkResult(int n, int& retry); // may only be called with m_ssl_mutex_ acquired.
+
+ void showError(const std::string& reason);
std::string getError();
void disconnect();
- void formatFingerprint(std::string& fingerprint, bool hex = true, bool separator = true);
- bool verifyCertFingerprint();
+
+ // may only be called with ssl_mutex_ acquired
+ bool verify_cert_fingerprint(const barrier::fs::path& fingerprint_db_path);
MultiplexerJobStatus serviceConnect(ISocketMultiplexerJob*, bool, bool, bool);
MultiplexerJobStatus serviceAccept(ISocketMultiplexerJob*, bool, bool, bool);
- void showSecureConnectInfo();
- void showSecureLibInfo();
- void showSecureCipherInfo();
-
+ void showSecureConnectInfo(); // may only be called with ssl_mutex_ acquired
+ void showSecureLibInfo();
+ void showSecureCipherInfo(); // may only be called with ssl_mutex_ acquired
+
void handleTCPConnected(const Event& event, void*);
void freeSSLResources();
private:
+ // all accesses to m_ssl must be protected by this mutex. The only function that is called
+ // from outside SocketMultiplexer thread is close(), so we mostly care about things accessed
+ // by it.
+ std::mutex ssl_mutex_;
+
Ssl* m_ssl;
bool m_secureReady;
bool m_fatal;
+ ConnectionSecurityLevel security_level_ = ConnectionSecurityLevel::ENCRYPTED;
+
+ int secure_accept_retry_ = 0; // used only in secureAccept()
+ int secure_connect_retry_ = 0; // used only in secureConnect()
+ int secure_read_retry_ = 0; // used only in secureRead()
+ int secure_write_retry_ = 0; // used only in secureWrite()
+
+ // The following are used only from doWrite()
+ // FIXME: using std::vector would simplify logic significantly.
+ bool do_write_retry_ = false;
+ int do_write_retry_size_ = 0;
+ std::unique_ptr<char[]> do_write_retry_buffer_;
+ std::size_t do_write_retry_buffer_size_ = 0;
};
diff --git a/src/lib/net/SecureUtils.cpp b/src/lib/net/SecureUtils.cpp
new file mode 100644
index 0000000..c581dd4
--- /dev/null
+++ b/src/lib/net/SecureUtils.cpp
@@ -0,0 +1,312 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ 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 LICENSE 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 <http://www.gnu.org/licenses/>.
+
+ -----------------------------------------------------------------------
+ create_fingerprint_randomart() has been taken from the OpenSSH project.
+ Copyright information follows.
+
+ Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
+ Copyright (c) 2008 Alexander von Gernler. All rights reserved.
+ Copyright (c) 2010,2011 Damien Miller. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "SecureUtils.h"
+#include "base/String.h"
+#include "base/finally.h"
+#include "io/filesystem.h"
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <stdexcept>
+
+#if SYSAPI_WIN32
+// Windows builds require a shim that makes it possible to link to different
+// versions of the Win32 C runtime. See OpenSSL FAQ.
+#include <openssl/applink.c>
+#endif
+
+namespace barrier {
+
+namespace {
+
+const EVP_MD* get_digest_for_type(FingerprintType type)
+{
+ switch (type) {
+ case FingerprintType::SHA1: return EVP_sha1();
+ case FingerprintType::SHA256: return EVP_sha256();
+ }
+ throw std::runtime_error("Unknown fingerprint type " + std::to_string(static_cast<int>(type)));
+}
+
+} // namespace
+
+std::string format_ssl_fingerprint(const std::vector<uint8_t>& fingerprint, bool separator)
+{
+ std::string result = barrier::string::to_hex(fingerprint, 2);
+
+ // all uppercase
+ barrier::string::uppercase(result);
+
+ if (separator) {
+ // add colon to separate each 2 characters
+ size_t separators = result.size() / 2;
+ for (size_t i = 1; i < separators; i++) {
+ result.insert(i * 3 - 1, ":");
+ }
+ }
+ return result;
+}
+
+std::string format_ssl_fingerprint_columns(const std::vector<uint8_t>& fingerprint)
+{
+ auto max_columns = 8;
+
+ std::string hex = barrier::string::to_hex(fingerprint, 2);
+ barrier::string::uppercase(hex);
+ if (hex.empty() || hex.size() % 2 != 0) {
+ return hex;
+ }
+
+ std::string separated;
+ for (std::size_t i = 0; i < hex.size(); i += max_columns * 2) {
+ for (std::size_t j = i; j < i + 16 && j < hex.size() - 1; j += 2) {
+ separated.push_back(hex[j]);
+ separated.push_back(hex[j + 1]);
+ separated.push_back(':');
+ }
+ separated.push_back('\n');
+ }
+ separated.pop_back(); // we don't need last newline character
+ return separated;
+}
+
+FingerprintData get_ssl_cert_fingerprint(X509* cert, FingerprintType type)
+{
+ if (!cert) {
+ throw std::runtime_error("certificate is null");
+ }
+
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int digest_length = 0;
+ int result = X509_digest(cert, get_digest_for_type(type), digest, &digest_length);
+
+ if (result <= 0) {
+ throw std::runtime_error("failed to calculate fingerprint, digest result: " +
+ std::to_string(result));
+ }
+
+ std::vector<std::uint8_t> digest_vec;
+ digest_vec.assign(reinterpret_cast<std::uint8_t*>(digest),
+ reinterpret_cast<std::uint8_t*>(digest) + digest_length);
+ return {fingerprint_type_to_string(type), digest_vec};
+}
+
+FingerprintData get_pem_file_cert_fingerprint(const std::string& path, FingerprintType type)
+{
+ auto fp = fopen_utf8_path(path, "r");
+ if (!fp) {
+ throw std::runtime_error("Could not open certificate path");
+ }
+ auto file_close = finally([fp]() { std::fclose(fp); });
+
+ X509* cert = PEM_read_X509(fp, nullptr, nullptr, nullptr);
+ if (!cert) {
+ throw std::runtime_error("Certificate could not be parsed");
+ }
+ auto cert_free = finally([cert]() { X509_free(cert); });
+
+ return get_ssl_cert_fingerprint(cert, type);
+}
+
+void generate_pem_self_signed_cert(const std::string& path)
+{
+ auto expiration_days = 365;
+
+ auto* private_key = EVP_PKEY_new();
+ if (!private_key) {
+ throw std::runtime_error("Could not allocate private key for certificate");
+ }
+ auto private_key_free = finally([private_key](){ EVP_PKEY_free(private_key); });
+
+ auto* rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
+ if (!rsa) {
+ throw std::runtime_error("Failed to generate RSA key");
+ }
+ EVP_PKEY_assign_RSA(private_key, rsa);
+
+ auto* cert = X509_new();
+ if (!cert) {
+ throw std::runtime_error("Could not allocate certificate");
+ }
+ auto cert_free = finally([cert]() { X509_free(cert); });
+
+ ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
+ X509_gmtime_adj(X509_get_notBefore(cert), 0);
+ X509_gmtime_adj(X509_get_notAfter(cert), expiration_days * 24 * 3600);
+ X509_set_pubkey(cert, private_key);
+
+ auto* name = X509_get_subject_name(cert);
+ X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char *>("Barrier"), -1, -1, 0);
+ X509_set_issuer_name(cert, name);
+
+ X509_sign(cert, private_key, EVP_sha256());
+
+ auto fp = fopen_utf8_path(path.c_str(), "r");
+ if (!fp) {
+ throw std::runtime_error("Could not open certificate output path");
+ }
+ auto file_close = finally([fp]() { std::fclose(fp); });
+
+ PEM_write_PrivateKey(fp, private_key, nullptr, nullptr, 0, nullptr, nullptr);
+ PEM_write_X509(fp, cert);
+}
+
+/*
+ Draw an ASCII-Art representing the fingerprint so human brain can
+ profit from its built-in pattern recognition ability.
+ This technique is called "random art" and can be found in some
+ scientific publications like this original paper:
+
+ "Hash Visualization: a New Technique to improve Real-World Security",
+ Perrig A. and Song D., 1999, International Workshop on Cryptographic
+ Techniques and E-Commerce (CrypTEC '99)
+ sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
+
+ The subject came up in a talk by Dan Kaminsky, too.
+
+ If you see the picture is different, the key is different.
+ If the picture looks the same, you still know nothing.
+
+ The algorithm used here is a worm crawling over a discrete plane,
+ leaving a trace (augmenting the field) everywhere it goes.
+ Movement is taken from dgst_raw 2bit-wise. Bumping into walls
+ makes the respective movement vector be ignored for this turn.
+ Graphs are not unambiguous, because circles in graphs can be
+walked in either direction.
+ */
+
+/*
+ Field sizes for the random art. Have to be odd, so the starting point
+ can be in the exact middle of the picture, and FLDBASE should be >=8 .
+ Else pictures would be too dense, and drawing the frame would
+ fail, too, because the key type would not fit in anymore.
+*/
+#define FLDBASE 8
+#define FLDSIZE_Y (FLDBASE + 1)
+#define FLDSIZE_X (FLDBASE * 2 + 1)
+
+std::string create_fingerprint_randomart(const std::vector<std::uint8_t>& dgst_raw)
+{
+ /*
+ * Chars to be used after each other every time the worm
+ * intersects with itself. Matter of taste.
+ */
+ const char* augmentation_string = " .o+=*BOX@%&#/^SE";
+ char *p;
+ std::uint8_t field[FLDSIZE_X][FLDSIZE_Y];
+ std::size_t i;
+ std::uint32_t b;
+ int x, y;
+ std::size_t len = strlen(augmentation_string) - 1;
+
+ std::vector<char> retval;
+ retval.reserve((FLDSIZE_X + 3) * (FLDSIZE_Y + 2));
+
+ auto add_char = [&retval](char ch) { retval.push_back(ch); };
+
+ /* initialize field */
+ std::memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
+ x = FLDSIZE_X / 2;
+ y = FLDSIZE_Y / 2;
+
+ /* process raw key */
+ for (i = 0; i < dgst_raw.size(); i++) {
+ /* each byte conveys four 2-bit move commands */
+ int input = dgst_raw[i];
+ for (b = 0; b < 4; b++) {
+ /* evaluate 2 bit, rest is shifted later */
+ x += (input & 0x1) ? 1 : -1;
+ y += (input & 0x2) ? 1 : -1;
+
+ /* assure we are still in bounds */
+ x = std::max(x, 0);
+ y = std::max(y, 0);
+ x = std::min(x, FLDSIZE_X - 1);
+ y = std::min(y, FLDSIZE_Y - 1);
+
+ /* augment the field */
+ if (field[x][y] < len - 2)
+ field[x][y]++;
+ input = input >> 2;
+ }
+ }
+
+ /* mark starting point and end point*/
+ field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
+ field[x][y] = len;
+
+ /* output upper border */
+ add_char('+');
+ for (i = 0; i < FLDSIZE_X; i++)
+ add_char('-');
+ add_char('+');
+ add_char('\n');
+
+ /* output content */
+ for (y = 0; y < FLDSIZE_Y; y++) {
+ add_char('|');
+ for (x = 0; x < FLDSIZE_X; x++)
+ add_char(augmentation_string[std::min<int>(field[x][y], len)]);
+ add_char('|');
+ add_char('\n');
+ }
+
+ /* output lower border */
+ add_char('+');
+ for (i = 0; i < FLDSIZE_X; i++)
+ add_char('-');
+ add_char('+');
+
+ return std::string{retval.data(), retval.size()};
+}
+
+} // namespace barrier
diff --git a/src/lib/net/SecureUtils.h b/src/lib/net/SecureUtils.h
new file mode 100644
index 0000000..c4d51f3
--- /dev/null
+++ b/src/lib/net/SecureUtils.h
@@ -0,0 +1,43 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ 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 LICENSE 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_NET_SECUREUTILS_H
+#define BARRIER_LIB_NET_SECUREUTILS_H
+
+#include "FingerprintData.h"
+#include <openssl/ossl_typ.h>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace barrier {
+
+std::string format_ssl_fingerprint(const std::vector<std::uint8_t>& fingerprint,
+ bool separator = true);
+std::string format_ssl_fingerprint_columns(const std::vector<uint8_t>& fingerprint);
+
+FingerprintData get_ssl_cert_fingerprint(X509* cert, FingerprintType type);
+
+FingerprintData get_pem_file_cert_fingerprint(const std::string& path, FingerprintType type);
+
+void generate_pem_self_signed_cert(const std::string& path);
+
+std::string create_fingerprint_randomart(const std::vector<std::uint8_t>& dgst_raw);
+
+} // namespace barrier
+
+#endif // BARRIER_LIB_NET_SECUREUTILS_H
diff --git a/src/lib/net/SocketMultiplexer.cpp b/src/lib/net/SocketMultiplexer.cpp
index cdb9039..5a2328e 100644
--- a/src/lib/net/SocketMultiplexer.cpp
+++ b/src/lib/net/SocketMultiplexer.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -26,7 +26,6 @@
#include "arch/Arch.h"
#include "arch/XArch.h"
#include "base/Log.h"
-#include "base/TMethodJob.h"
#include "common/stdvector.h"
//
@@ -58,8 +57,7 @@ SocketMultiplexer::SocketMultiplexer() :
m_jobListLockLocker(NULL)
{
// start thread
- m_thread = new Thread(new TMethodJob<SocketMultiplexer>(
- this, &SocketMultiplexer::serviceThread));
+ m_thread = new Thread([this](){ service_thread(); });
}
SocketMultiplexer::~SocketMultiplexer()
@@ -95,7 +93,7 @@ void SocketMultiplexer::addSocket(ISocket* socket, std::unique_ptr<ISocketMultip
if (i == m_socketJobMap.end()) {
// we *must* put the job at the end so the order of jobs in
// the list continue to match the order of jobs in pfds in
- // serviceThread().
+ // service_thread().
JobCursor j = m_socketJobs.insert(m_socketJobs.end(), std::move(job));
m_update = true;
m_socketJobMap.insert(std::make_pair(socket, j));
@@ -125,7 +123,7 @@ SocketMultiplexer::removeSocket(ISocket* socket)
// remove job. rather than removing it from the map we put NULL
// in the list instead so the order of jobs in the list continues
- // to match the order of jobs in pfds in serviceThread().
+ // to match the order of jobs in pfds in service_thread().
SocketJobMap::iterator i = m_socketJobMap.find(socket);
if (i != m_socketJobMap.end()) {
if (*(i->second)) {
@@ -138,8 +136,7 @@ SocketMultiplexer::removeSocket(ISocket* socket)
unlockJobList();
}
-void
-SocketMultiplexer::serviceThread(void*)
+void SocketMultiplexer::service_thread()
{
std::vector<IArchNetwork::PollEntry> pfds;
IArchNetwork::PollEntry pfd;
@@ -179,7 +176,7 @@ SocketMultiplexer::serviceThread(void*)
pfd.m_events |= IArchNetwork::kPOLLOUT;
}
pfds.push_back(pfd);
- }
+ }
jobCursor = nextCursor(cursor);
}
deleteCursor(cursor);
diff --git a/src/lib/net/SocketMultiplexer.h b/src/lib/net/SocketMultiplexer.h
index 9891558..b13c725 100644
--- a/src/lib/net/SocketMultiplexer.h
+++ b/src/lib/net/SocketMultiplexer.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -67,7 +67,7 @@ private:
// and m_update while m_pollable and m_polling are true. all other
// threads must only modify these when m_pollable and m_polling are
// false. only the service thread sets m_polling.
- void serviceThread(void*);
+ void service_thread();
// create, iterate, and destroy a cursor. a cursor is used to
// safely iterate through the job list while other threads modify
diff --git a/src/lib/net/TCPListenSocket.cpp b/src/lib/net/TCPListenSocket.cpp
index 26f03b0..2c305fc 100644
--- a/src/lib/net/TCPListenSocket.cpp
+++ b/src/lib/net/TCPListenSocket.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -70,8 +70,10 @@ TCPListenSocket::bind(const NetworkAddress& addr)
ARCH->bindSocket(m_socket, addr.getAddress());
ARCH->listenOnSocket(m_socket);
- auto new_job = std::make_unique<TSocketMultiplexerMethodJob<TCPListenSocket>>(
- this, &TCPListenSocket::serviceListening, m_socket, true, false);
+ auto new_job = std::make_unique<TSocketMultiplexerMethodJob>(
+ [this](auto j, auto r, auto w, auto e)
+ { return serviceListening(j, r, w, e); },
+ m_socket, true, false);
m_socketMultiplexer->addSocket(this, std::move(new_job));
}
@@ -136,8 +138,10 @@ TCPListenSocket::accept()
void
TCPListenSocket::setListeningJob()
{
- auto new_job = std::make_unique<TSocketMultiplexerMethodJob<TCPListenSocket>>(
- this, &TCPListenSocket::serviceListening, m_socket, true, false);
+ auto new_job = std::make_unique<TSocketMultiplexerMethodJob>(
+ [this](auto j, auto r, auto w, auto e)
+ { return serviceListening(j, r, w, e); },
+ m_socket, true, false);
m_socketMultiplexer->addSocket(this, std::move(new_job));
}
diff --git a/src/lib/net/TCPListenSocket.h b/src/lib/net/TCPListenSocket.h
index f3ababc..109c1c3 100644
--- a/src/lib/net/TCPListenSocket.h
+++ b/src/lib/net/TCPListenSocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
diff --git a/src/lib/net/TCPSocket.cpp b/src/lib/net/TCPSocket.cpp
index 09a8f17..fa7edcc 100644
--- a/src/lib/net/TCPSocket.cpp
+++ b/src/lib/net/TCPSocket.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -33,9 +33,7 @@
#include <cstdlib>
#include <memory>
-//
-// TCPSocket
-//
+static const std::size_t MAX_INPUT_BUFFER_SIZE = 1024 * 1024;
TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family) :
IDataSocket(events),
@@ -335,19 +333,23 @@ TCPSocket::doRead()
UInt8 buffer[4096];
memset(buffer, 0, sizeof(buffer));
size_t bytesRead = 0;
-
+
bytesRead = ARCH->readSocket(m_socket, buffer, sizeof(buffer));
-
+
if (bytesRead > 0) {
bool wasEmpty = (m_inputBuffer.getSize() == 0);
-
+
// slurp up as much as possible
do {
m_inputBuffer.write(buffer, (UInt32)bytesRead);
+ if (m_inputBuffer.getSize() > MAX_INPUT_BUFFER_SIZE) {
+ break;
+ }
+
bytesRead = ARCH->readSocket(m_socket, buffer, sizeof(buffer));
} while (bytesRead > 0);
-
+
// send input ready if input buffer was empty
if (wasEmpty) {
sendEvent(m_events->forIStream().inputReady());
@@ -365,7 +367,7 @@ TCPSocket::doRead()
m_readable = false;
return kNew;
}
-
+
return kRetry;
}
@@ -384,7 +386,7 @@ TCPSocket::doWrite()
discardWrittenData(bytesWrote);
return kNew;
}
-
+
return kRetry;
}
@@ -424,18 +426,20 @@ std::unique_ptr<ISocketMultiplexerJob> TCPSocket::newJob()
if (!(m_readable || m_writable)) {
return {};
}
- return std::make_unique<TSocketMultiplexerMethodJob<TCPSocket>>(
- this, &TCPSocket::serviceConnecting,
- m_socket, m_readable, m_writable);
+ return std::make_unique<TSocketMultiplexerMethodJob>(
+ [this](auto j, auto r, auto w, auto e)
+ { return serviceConnecting(j, r, w, e); },
+ m_socket, m_readable, m_writable);
}
else {
- if (!(m_readable || (m_writable && (m_outputBuffer.getSize() > 0)))) {
+ auto writable = m_writable && (m_outputBuffer.getSize() > 0);
+ if (!(m_readable || writable)) {
return {};
}
- return std::make_unique<TSocketMultiplexerMethodJob<TCPSocket>>(
- this, &TCPSocket::serviceConnected,
- m_socket, m_readable,
- m_writable && (m_outputBuffer.getSize() > 0));
+ return std::make_unique<TSocketMultiplexerMethodJob>(
+ [this](auto j, auto r, auto w, auto e)
+ { return serviceConnected(j, r, w, e); },
+ m_socket, m_readable, writable);
}
}
diff --git a/src/lib/net/TCPSocket.h b/src/lib/net/TCPSocket.h
index 0b98888..45aed07 100644
--- a/src/lib/net/TCPSocket.h
+++ b/src/lib/net/TCPSocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -59,7 +59,7 @@ public:
// IDataSocket overrides
virtual void connect(const NetworkAddress&);
-
+
virtual std::unique_ptr<ISocketMultiplexerJob> newJob();
protected:
@@ -68,7 +68,7 @@ protected:
kRetry, //!< Retry the same job
kNew //!< Require a new job
};
-
+
ArchSocket getSocket() { return m_socket; }
IEventQueue* getEvents() { return m_events; }
virtual EJobResult doRead();
@@ -105,7 +105,7 @@ protected:
IEventQueue* m_events;
StreamBuffer m_inputBuffer;
StreamBuffer m_outputBuffer;
-
+
private:
Mutex m_mutex;
ArchSocket m_socket;
diff --git a/src/lib/net/TCPSocketFactory.cpp b/src/lib/net/TCPSocketFactory.cpp
index 6ff4ef8..30e930e 100644
--- a/src/lib/net/TCPSocketFactory.cpp
+++ b/src/lib/net/TCPSocketFactory.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -40,11 +40,12 @@ TCPSocketFactory::~TCPSocketFactory()
// do nothing
}
-IDataSocket*
-TCPSocketFactory::create(IArchNetwork::EAddressFamily family, bool secure) const
+IDataSocket* TCPSocketFactory::create(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const
{
- if (secure) {
- SecureSocket* secureSocket = new SecureSocket(m_events, m_socketMultiplexer, family);
+ if (security_level != ConnectionSecurityLevel::PLAINTEXT) {
+ SecureSocket* secureSocket = new SecureSocket(m_events, m_socketMultiplexer, family,
+ security_level);
secureSocket->initSsl (false);
return secureSocket;
}
@@ -53,12 +54,12 @@ TCPSocketFactory::create(IArchNetwork::EAddressFamily family, bool secure) const
}
}
-IListenSocket*
-TCPSocketFactory::createListen(IArchNetwork::EAddressFamily family, bool secure) const
+IListenSocket* TCPSocketFactory::createListen(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const
{
IListenSocket* socket = NULL;
- if (secure) {
- socket = new SecureListenSocket(m_events, m_socketMultiplexer, family);
+ if (security_level != ConnectionSecurityLevel::PLAINTEXT) {
+ socket = new SecureListenSocket(m_events, m_socketMultiplexer, family, security_level);
}
else {
socket = new TCPListenSocket(m_events, m_socketMultiplexer, family);
diff --git a/src/lib/net/TCPSocketFactory.h b/src/lib/net/TCPSocketFactory.h
index 0195ec4..ac21cab 100644
--- a/src/lib/net/TCPSocketFactory.h
+++ b/src/lib/net/TCPSocketFactory.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -31,12 +31,11 @@ public:
virtual ~TCPSocketFactory();
// ISocketFactory overrides
- virtual IDataSocket* create(
- IArchNetwork::EAddressFamily family,
- bool secure) const;
- virtual IListenSocket* createListen(
- IArchNetwork::EAddressFamily family,
- bool secure) const;
+ virtual IDataSocket* create(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const;
+
+ virtual IListenSocket* createListen(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const;
private:
IEventQueue* m_events;
diff --git a/src/lib/net/TSocketMultiplexerMethodJob.h b/src/lib/net/TSocketMultiplexerMethodJob.h
index 9e74cdd..4b571ab 100644
--- a/src/lib/net/TSocketMultiplexerMethodJob.h
+++ b/src/lib/net/TSocketMultiplexerMethodJob.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -25,81 +25,43 @@
/*!
A socket multiplexer job class that invokes a member function.
*/
-template <class T>
class TSocketMultiplexerMethodJob : public ISocketMultiplexerJob {
public:
- using Method = MultiplexerJobStatus (T::*)(ISocketMultiplexerJob*, bool, bool, bool);
+ using RunFunction = std::function<MultiplexerJobStatus(ISocketMultiplexerJob*, bool, bool, bool)>;
//! run() invokes \c object->method(arg)
- TSocketMultiplexerMethodJob(T* object, Method method,
- ArchSocket socket, bool readable, bool writeable);
- virtual ~TSocketMultiplexerMethodJob();
+ TSocketMultiplexerMethodJob(const RunFunction& func,
+ ArchSocket socket, bool readable, bool writable) :
+ func_{func},
+ m_socket(ARCH->copySocket(socket)),
+ m_readable(readable),
+ m_writable(writable)
+ {
+ }
+
+ ~TSocketMultiplexerMethodJob() override
+ {
+ ARCH->closeSocket(m_socket);
+ }
// IJob overrides
- virtual MultiplexerJobStatus run(bool readable, bool writable, bool error) override;
- virtual ArchSocket getSocket() const override;
- virtual bool isReadable() const override;
- virtual bool isWritable() const override;
+ virtual MultiplexerJobStatus run(bool readable, bool writable, bool error) override
+ {
+ if (func_) {
+ return func_(this, readable, writable, error);
+ }
+ return {false, {}};
+ }
+
+ virtual ArchSocket getSocket() const override { return m_socket; }
+ virtual bool isReadable() const override { return m_readable; }
+ virtual bool isWritable() const override { return m_writable; }
private:
- T* m_object;
- Method m_method;
+ RunFunction func_;
ArchSocket m_socket;
bool m_readable;
bool m_writable;
- void* m_arg;
};
-template <class T>
-inline
-TSocketMultiplexerMethodJob<T>::TSocketMultiplexerMethodJob(T* object,
- Method method, ArchSocket socket,
- bool readable, bool writable) :
- m_object(object),
- m_method(method),
- m_socket(ARCH->copySocket(socket)),
- m_readable(readable),
- m_writable(writable)
-{
- // do nothing
-}
-
-template <class T>
-inline
-TSocketMultiplexerMethodJob<T>::~TSocketMultiplexerMethodJob()
-{
- ARCH->closeSocket(m_socket);
-}
-
-template <class T>
-inline MultiplexerJobStatus TSocketMultiplexerMethodJob<T>::run(bool read, bool write, bool error)
-{
- if (m_object != NULL) {
- return (m_object->*m_method)(this, read, write, error);
- }
- return {false, {}};
-}
-
-template <class T>
-inline
-ArchSocket
-TSocketMultiplexerMethodJob<T>::getSocket() const
-{
- return m_socket;
-}
-
-template <class T>
-inline
-bool
-TSocketMultiplexerMethodJob<T>::isReadable() const
-{
- return m_readable;
-}
-template <class T>
-inline
-bool
-TSocketMultiplexerMethodJob<T>::isWritable() const
-{
- return m_writable;
-}
diff --git a/src/lib/net/XSocket.cpp b/src/lib/net/XSocket.cpp
index eed7a26..6a50537 100644
--- a/src/lib/net/XSocket.cpp
+++ b/src/lib/net/XSocket.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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
@@ -63,7 +63,7 @@ std::string XSocketAddress::getWhat() const noexcept
"invalid port" // m_port may not be set to the bad port
};
return format(s_errorID[m_error], s_errorMsg[m_error],
- m_hostname.c_str(),
+ m_hostname.c_str(),
barrier::string::sprintf("%d", m_port).c_str());
}
diff --git a/src/lib/net/XSocket.h b/src/lib/net/XSocket.h
index d12278e..cafe59c 100644
--- a/src/lib/net/XSocket.h
+++ b/src/lib/net/XSocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* 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 LICENSE 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