Merge pull request #1346 from p12tic/client-identity-verification

Implement client identity verification [SECURITY VULNERABILITIES CVE-2021-42072, CVE-2021-42073]
This commit is contained in:
Povilas Kanapickas 2021-11-01 05:15:48 +02:00 committed by GitHub
commit b5adc93e2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 680 additions and 255 deletions

View File

@ -0,0 +1,7 @@
SECURITY ISSUE
Barrier now supports client identity verification (fixes CVE-2021-42072, CVE-2021-42073).
To support seamless upgrades from older versions of Barrier this is currently disabled by default.
The feature can be enabled in the settings dialog. If enabled, older clients of Barrier will be
rejected.

View File

@ -0,0 +1 @@
Barrier client now sends certificate that the server can verify.

View File

@ -29,6 +29,7 @@ set(GUI_SOURCE_FILES
src/CommandProcess.cpp
src/DataDownloader.cpp
src/DisplayIsValid.cpp
src/FingerprintAcceptDialog.cpp
src/HotkeyDialog.cpp
src/IpcClient.cpp
src/Ipc.cpp
@ -104,6 +105,7 @@ set(GUI_UI_FILES
src/AboutDialogBase.ui
src/ActionDialogBase.ui
src/AddClientDialogBase.ui
src/FingerprintAcceptDialog.ui
src/HotkeyDialogBase.ui
src/LogWindowBase.ui
src/MainWindowBase.ui

View File

@ -158,6 +158,8 @@ void AppConfig::loadSettings()
m_ElevateMode = static_cast<ElevateMode>(elevateMode.toInt());
m_AutoConfigPrompted = settings().value("autoConfigPrompted", false).toBool();
m_CryptoEnabled = settings().value("cryptoEnabled", true).toBool();
// TODO: set default value of requireClientCertificate to true on Barrier 2.5.0
m_RequireClientCertificate = settings().value("requireClientCertificate", false).toBool();
m_AutoHide = settings().value("autoHide", false).toBool();
m_AutoStart = settings().value("autoStart", false).toBool();
m_MinimizeToTray = settings().value("minimizeToTray", false).toBool();
@ -181,6 +183,7 @@ void AppConfig::saveSettings()
settings().setValue("elevateModeEnum", static_cast<int>(m_ElevateMode));
settings().setValue("autoConfigPrompted", m_AutoConfigPrompted);
settings().setValue("cryptoEnabled", m_CryptoEnabled);
settings().setValue("requireClientCertificate", m_RequireClientCertificate);
settings().setValue("autoHide", m_AutoHide);
settings().setValue("autoStart", m_AutoStart);
settings().setValue("minimizeToTray", m_MinimizeToTray);
@ -225,6 +228,10 @@ void AppConfig::setCryptoEnabled(bool e) { m_CryptoEnabled = e; }
bool AppConfig::getCryptoEnabled() const { return m_CryptoEnabled; }
void AppConfig::setRequireClientCertificate(bool e) { m_RequireClientCertificate = e; }
bool AppConfig::getRequireClientCertificate() const { return m_RequireClientCertificate; }
void AppConfig::setAutoHide(bool b) { m_AutoHide = b; }
bool AppConfig::getAutoHide() { return m_AutoHide; }

View File

@ -91,6 +91,9 @@ class AppConfig: public QObject
void setCryptoEnabled(bool e);
bool getCryptoEnabled() const;
void setRequireClientCertificate(bool e);
bool getRequireClientCertificate() const;
void setAutoHide(bool b);
bool getAutoHide();
@ -132,6 +135,7 @@ protected:
ElevateMode m_ElevateMode;
bool m_AutoConfigPrompted;
bool m_CryptoEnabled;
bool m_RequireClientCertificate = false;
bool m_AutoHide;
bool m_AutoStart;
bool m_MinimizeToTray;

View File

@ -0,0 +1,65 @@
/*
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 "FingerprintAcceptDialog.h"
#include "ui_FingerprintAcceptDialog.h"
#include "net/SecureUtils.h"
FingerprintAcceptDialog::FingerprintAcceptDialog(QWidget *parent,
BarrierType type,
const barrier::FingerprintData& fingerprint_sha1,
const barrier::FingerprintData& fingerprint_sha256) :
QDialog(parent),
ui_{std::make_unique<Ui::FingerprintAcceptDialog>()}
{
ui_->setupUi(this);
if (type == BarrierType::Server) {
ui_->label_sha1->hide();
ui_->label_sha1_fingerprint_full->hide();
} else {
ui_->label_sha1_fingerprint_full->setText(
QString::fromStdString(barrier::format_ssl_fingerprint(fingerprint_sha1.data)));
}
ui_->label_sha256_fingerprint_full->setText(
QString::fromStdString(barrier::format_ssl_fingerprint_columns(fingerprint_sha256.data)));
ui_->label_sha256_fingerprint_randomart->setText(
QString::fromStdString(barrier::create_fingerprint_randomart(fingerprint_sha256.data)));
QString explanation;
if (type == BarrierType::Server) {
explanation = tr("This is a client fingerprint. You should compare this "
"fingerprint to the one on your client's screen. If the "
"two don't match exactly, then it's probably not the client "
"you're expecting (it could be a malicious user).\n\n"
"To automatically trust this fingerprint for future "
"connections, click Yes. To reject this fingerprint and "
"disconnect the client, click No.");
} else {
explanation = tr("This is a server fingerprint. You should compare this "
"fingerprint to the one on your server's screen. If the "
"two don't match exactly, then it's probably not the server "
"you're expecting (it could be a malicious user).\n\n"
"To automatically trust this fingerprint for future "
"connections, click Yes. To reject this fingerprint and "
"disconnect from the server, click No.");
}
ui_->label_explanation->setText(explanation);
}
FingerprintAcceptDialog::~FingerprintAcceptDialog() = default;

View File

@ -0,0 +1,45 @@
/*
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_GUI_FINGERPRINT_ACCEPT_DIALOG_H
#define BARRIER_GUI_FINGERPRINT_ACCEPT_DIALOG_H
#include "net/FingerprintData.h"
#include "barrier/BarrierType.h"
#include <QDialog>
#include <memory>
namespace Ui {
class FingerprintAcceptDialog;
}
class FingerprintAcceptDialog : public QDialog
{
Q_OBJECT
public:
explicit FingerprintAcceptDialog(QWidget* parent,
BarrierType type,
const barrier::FingerprintData& fingerprint_sha1,
const barrier::FingerprintData& fingerprint_sha256);
~FingerprintAcceptDialog() override;
private:
std::unique_ptr<Ui::FingerprintAcceptDialog> ui_;
};
#endif // BARRIER_GUI_FINGERPRINT_ACCEPT_DIALOG_H

View File

@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FingerprintAcceptDialog</class>
<widget class="QDialog" name="FingerprintAcceptDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>400</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Security question</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item row="6" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::No|QDialogButtonBox::Yes</set>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="label_sha1">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>SHA1 (deprecated, compare to old servers only)</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QLabel" name="label_explanation">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>10</number>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="label_sha1_fingerprint_full">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_title">
<property name="text">
<string>Do you trust this fingerprint?</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_sha256_fingerprint_randomart">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Courier</family>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_sha256_fingerprint_full">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_sha256">
<property name="text">
<string>SHA256:</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>FingerprintAcceptDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>FingerprintAcceptDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -26,6 +26,7 @@
#include "ZeroconfService.h"
#include "DataDownloader.h"
#include "CommandProcess.h"
#include "FingerprintAcceptDialog.h"
#include "QUtility.h"
#include "ProcessorArch.h"
#include "SslCertificate.h"
@ -427,7 +428,7 @@ void MainWindow::checkConnected(const QString& line)
void MainWindow::checkFingerprint(const QString& line)
{
QRegExp fingerprintRegex(".*server fingerprint \\(SHA1\\): ([A-F0-9:]+) \\(SHA256\\): ([A-F0-9:]+)");
QRegExp fingerprintRegex(".*peer fingerprint \\(SHA1\\): ([A-F0-9:]+) \\(SHA256\\): ([A-F0-9:]+)");
if (!fingerprintRegex.exactMatch(line)) {
return;
}
@ -442,7 +443,16 @@ void MainWindow::checkFingerprint(const QString& line)
barrier::string::from_hex(fingerprintRegex.cap(2).toStdString())
};
auto db_path = barrier::DataDirectories::trusted_servers_ssl_fingerprints_path();
bool is_client = barrier_type() == BarrierType::Client;
auto db_path = is_client
? barrier::DataDirectories::trusted_servers_ssl_fingerprints_path()
: barrier::DataDirectories::trusted_clients_ssl_fingerprints_path();
auto db_dir = db_path.parent_path();
if (!barrier::fs::exists(db_dir)) {
barrier::fs::create_directories(db_dir);
}
// We compare only SHA256 fingerprints, but show both SHA1 and SHA256 so that the users can
// still verify fingerprints on old Barrier servers. This way the only time when we are exposed
@ -456,37 +466,20 @@ void MainWindow::checkFingerprint(const QString& line)
static bool messageBoxAlreadyShown = false;
if (!messageBoxAlreadyShown) {
if (is_client) {
stopBarrier();
}
messageBoxAlreadyShown = true;
QMessageBox::StandardButton fingerprintReply =
QMessageBox::information(
this, tr("Security question"),
tr("Do you trust this fingerprint?\n\n"
"SHA256:\n"
"%1\n"
"%2\n\n"
"SHA1 (obsolete, when using old Barrier server):\n"
"%3\n\n"
"This is a server fingerprint. You should compare this "
"fingerprint to the one on your server's screen. If the "
"two don't match exactly, then it's probably not the server "
"you're expecting (it could be a malicious user).\n\n"
"To automatically trust this fingerprint for future "
"connections, click Yes. To reject this fingerprint and "
"disconnect from the server, click No.")
.arg(QString::fromStdString(barrier::format_ssl_fingerprint(fingerprint_sha256.data)))
.arg(QString::fromStdString(
barrier::create_fingerprint_randomart(fingerprint_sha256.data)))
.arg(QString::fromStdString(barrier::format_ssl_fingerprint(fingerprint_sha1.data))),
QMessageBox::Yes | QMessageBox::No);
if (fingerprintReply == QMessageBox::Yes) {
FingerprintAcceptDialog dialog{this, barrier_type(), fingerprint_sha1, fingerprint_sha256};
if (dialog.exec() == QDialog::Accepted) {
// restart core process after trusting fingerprint.
db.add_trusted(fingerprint_sha256);
db.write(db_path);
if (is_client) {
startBarrier();
}
}
messageBoxAlreadyShown = false;
}
@ -567,8 +560,8 @@ void MainWindow::startBarrier()
args << "--profile-dir" << QString::fromStdString("\"" + barrier::DataDirectories::profile().u8string() + "\"");
#endif
if ((barrierType() == barrierClient && !clientArgs(args, app))
|| (barrierType() == barrierServer && !serverArgs(args, app)))
if ((barrier_type() == BarrierType::Client && !clientArgs(args, app))
|| (barrier_type() == BarrierType::Server && !serverArgs(args, app)))
{
stopBarrier();
return;
@ -583,7 +576,7 @@ void MainWindow::startBarrier()
m_pLogWindow->startNewInstance();
appendLogInfo("starting " + QString(barrierType() == barrierServer ? "server" : "client"));
appendLogInfo("starting " + QString(barrier_type() == BarrierType::Server ? "server" : "client"));
qDebug() << args;
@ -693,6 +686,11 @@ QString MainWindow::configFilename()
return filename;
}
BarrierType MainWindow::barrier_type() const
{
return m_pGroupClient->isChecked() ? BarrierType::Client : BarrierType::Server;
}
QString MainWindow::address()
{
QString address = appConfig().networkInterface();
@ -729,6 +727,10 @@ bool MainWindow::serverArgs(QStringList& args, QString& app)
args << "--log" << appConfig().logFilenameCmd();
}
if (!appConfig().getRequireClientCertificate()) {
args << "--disable-client-cert-checking";
}
QString configFilename = this->configFilename();
#if defined(Q_OS_WIN)
// wrap in quotes in case username contains spaces.
@ -983,7 +985,7 @@ void MainWindow::updateZeroconfService()
m_pZeroconfService = NULL;
}
if (m_AppConfig->autoConfig() || barrierType() == barrierServer) {
if (m_AppConfig->autoConfig() || barrier_type() == BarrierType::Server) {
m_pZeroconfService = new ZeroconfService(this);
}
}

View File

@ -20,6 +20,8 @@
#define MAINWINDOW__H
#include "barrier/BarrierType.h"
#include <QMainWindow>
#include <QSystemTrayIcon>
#include <QSettings>
@ -76,12 +78,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
barrierTransfering
};
enum qBarrierType
{
barrierClient,
barrierServer
};
enum qLevel {
Error,
Info
@ -98,7 +94,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
public:
void setVisible(bool visible);
int barrierType() const { return m_pGroupClient->isChecked() ? barrierClient : barrierServer; }
BarrierType barrier_type() const;
int barrierState() const { return m_BarrierState; }
QString hostname() const { return m_pLineEditHostname->text(); }
QString configFilename();

View File

@ -55,107 +55,6 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="m_pLabelFingerprint">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>SSL Fingerprint:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_pLabelLocalFingerprint">
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolbutton_show_fingerprint">
<property name="text">
<string>...</string>
</property>
<property name="arrowType">
<enum>Qt::DownArrow</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QFrame" name="frame_fingerprint_details">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item row="1" column="1">
<widget class="QLabel" name="label_sha256_randomart">
<property name="font">
<font>
<family>Courier</family>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_sha1">
<property name="text">
<string>SHA1 (deprecated, compare to old clients only):</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="label_sha1_fingerprint_full">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_sha256">
<property name="text">
<string>SHA256:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_sha256_fingerprint_full">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_pRadioInternalConfig">
<property name="text">
@ -305,6 +204,107 @@
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="m_pLabelFingerprint">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>SSL Fingerprint:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_pLabelLocalFingerprint">
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolbutton_show_fingerprint">
<property name="text">
<string>...</string>
</property>
<property name="arrowType">
<enum>Qt::DownArrow</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QFrame" name="frame_fingerprint_details">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item row="1" column="1">
<widget class="QLabel" name="label_sha256_randomart">
<property name="font">
<font>
<family>Courier</family>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_sha1">
<property name="text">
<string>SHA1 (deprecated, compare to old clients and servers only):</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="label_sha1_fingerprint_full">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_sha256">
<property name="text">
<string>SHA256:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_sha256_fingerprint_full">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">

View File

@ -51,6 +51,7 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
m_pCheckBoxAutoStart->setChecked(appConfig().getAutoStart());
m_pCheckBoxMinimizeToTray->setChecked(appConfig().getMinimizeToTray());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled());
checkbox_require_client_certificate->setChecked(m_appConfig.getRequireClientCertificate());
#if defined(Q_OS_WIN)
m_pComboElevate->setCurrentIndex(static_cast<int>(appConfig().elevateMode()));
@ -67,6 +68,7 @@ void SettingsDialog::accept()
m_appConfig.setPort(m_pSpinBoxPort->value());
m_appConfig.setNetworkInterface(m_pLineEditInterface->text());
m_appConfig.setCryptoEnabled(m_pCheckBoxEnableCrypto->isChecked());
m_appConfig.setRequireClientCertificate(checkbox_require_client_certificate->isChecked());
m_appConfig.setLogLevel(m_pComboLogLevel->currentIndex());
m_appConfig.setLogToFile(m_pCheckBoxLogToFile->isChecked());
m_appConfig.setLogFilename(m_pLineEditLogFilename->text());

View File

@ -142,6 +142,16 @@
<string>Networking</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QLabel" name="m_pLabel_21">
<property name="text">
<string>&amp;Address:</string>
</property>
<property name="buddy">
<cstring>m_pLineEditInterface</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="m_pLabel_20">
<property name="text">
@ -171,16 +181,6 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="m_pLabel_21">
<property name="text">
<string>&amp;Address:</string>
</property>
<property name="buddy">
<cstring>m_pLineEditInterface</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="m_pLineEditInterface">
<property name="enabled">
@ -188,13 +188,20 @@
</property>
</widget>
</item>
<item row="2" column="0">
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="m_pCheckBoxEnableCrypto">
<property name="text">
<string>Enable &amp;SSL</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="checkbox_require_client_certificate">
<property name="text">
<string>Require client certificate</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -216,19 +223,20 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="m_pLabel_3">
<property name="minimumSize">
<size>
<width>75</width>
<height>0</height>
</size>
<item row="1" column="0">
<widget class="QCheckBox" name="m_pCheckBoxLogToFile">
<property name="text">
<string>Log to file:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="m_pButtonBrowseLog">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Logging level:</string>
</property>
<property name="buddy">
<cstring>m_pComboLogLevel</cstring>
<string>Browse...</string>
</property>
</widget>
</item>
@ -271,10 +279,19 @@
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="m_pCheckBoxLogToFile">
<item row="0" column="0">
<widget class="QLabel" name="m_pLabel_3">
<property name="minimumSize">
<size>
<width>75</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Log to file:</string>
<string>&amp;Logging level:</string>
</property>
<property name="buddy">
<cstring>m_pComboLogLevel</cstring>
</property>
</widget>
</item>
@ -285,16 +302,6 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="m_pButtonBrowseLog">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -65,6 +65,11 @@ void SslCertificate::generate_fingerprint(const barrier::fs::path& cert_path)
{
try {
auto local_path = barrier::DataDirectories::local_ssl_fingerprints_path();
auto local_dir = local_path.parent_path();
if (!barrier::fs::exists(local_dir)) {
barrier::fs::create_directories(local_dir);
}
barrier::FingerprintDatabase db;
db.add_trusted(barrier::get_pem_file_cert_fingerprint(cert_path.u8string(),
barrier::FingerprintType::SHA1));

View File

@ -66,7 +66,7 @@ ZeroconfService::ZeroconfService(MainWindow* mainWindow) :
m_ServiceRegistered(false)
{
silence_avahi_warning();
if (m_pMainWindow->barrierType() == MainWindow::barrierServer) {
if (m_pMainWindow->barrier_type() == BarrierType::Server) {
if (registerService(true)) {
m_pZeroconfBrowser = new ZeroconfBrowser(this);
connect(m_pZeroconfBrowser, SIGNAL(

View File

@ -65,7 +65,9 @@ ArgParser::parseServerArgs(ServerArgs& args, int argc, const char* const* argv)
// save screen change script path
args.m_screenChangeScript = argv[++i];
}
else {
else if (isArg(i, argc, argv, nullptr, "--disable-client-cert-checking")) {
args.check_client_certificates = false;
} else {
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, args.m_exename.c_str(), argv[i], args.m_exename.c_str()));
return false;
}

View File

@ -0,0 +1,26 @@
/*
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_BARRIER_BARRIER_TYPE_H
#define BARRIER_LIB_BARRIER_BARRIER_TYPE_H
enum class BarrierType {
Server,
Client
};
#endif // BARRIER_LIB_BARRIER_BARRIER_TYPE_H

View File

@ -148,7 +148,10 @@ ServerApp::help()
<< "Options:\n"
<< " -a, --address <address> listen for clients on the given address.\n"
<< " -c, --config <pathname> use the named configuration file instead.\n"
<< HELP_COMMON_INFO_1 << WINAPI_INFO << HELP_SYS_INFO << HELP_COMMON_INFO_2 << "\n"
<< HELP_COMMON_INFO_1
<< " --disable-client-cert-checking disable client SSL certificate \n"
" checking (deprecated)\n"
<< WINAPI_INFO << HELP_SYS_INFO << HELP_COMMON_INFO_2 << "\n"
<< "Default options are marked with a *\n"
<< "\n"
<< "The argument for --address is of the form: [<hostname>][:<port>]. The\n"
@ -655,11 +658,18 @@ ServerApp::handleResume(const Event&, void*)
ClientListener*
ServerApp::openClientListener(const NetworkAddress& address)
{
auto security_level = ConnectionSecurityLevel::PLAINTEXT;
if (args().m_enableCrypto) {
security_level = ConnectionSecurityLevel::ENCRYPTED;
if (args().check_client_certificates) {
security_level = ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED;
}
}
ClientListener* listen = new ClientListener(
address,
new TCPSocketFactory(m_events, getSocketMultiplexer()),
m_events,
args().m_enableCrypto);
m_events, security_level);
m_events->adoptHandler(
m_events->forClientListener().connected(), listen,

View File

@ -30,4 +30,5 @@ public:
String m_configFile;
Config* m_config;
String m_screenChangeScript;
bool check_client_certificates = true;
};

View File

@ -127,6 +127,12 @@ Client::connect()
return;
}
auto security_level = ConnectionSecurityLevel::PLAINTEXT;
if (m_useSecureNetwork) {
// client always authenticates server
security_level = ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED;
}
try {
// resolve the server hostname. do this every time we connect
// in case we couldn't resolve the address earlier or the address
@ -145,9 +151,8 @@ Client::connect()
}
// create the socket
IDataSocket* socket = m_socketFactory->create(
ARCH->getAddrFamily(m_serverAddress.getAddress()),
m_useSecureNetwork);
IDataSocket* socket = m_socketFactory->create(ARCH->getAddrFamily(m_serverAddress.getAddress()),
security_level);
m_socket = dynamic_cast<TCPSocket*>(socket);
// filter socket messages, including a packetizing filter

View File

@ -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

View File

@ -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;
//@}
};

View File

@ -25,11 +25,11 @@
#include "common/DataDirectories.h"
#include "base/String.h"
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}
{
}
@ -38,10 +38,8 @@ 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) {

View File

@ -19,6 +19,7 @@
#include "net/TCPListenSocket.h"
#include "common/stdset.h"
#include "ConnectionSecurityLevel.h"
class IEventQueue;
class SocketMultiplexer;
@ -26,11 +27,13 @@ class IDataSocket;
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_;
};

View File

@ -54,25 +54,24 @@ struct Ssl {
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}
{
}
@ -362,6 +361,11 @@ bool SecureSocket::load_certificates(const barrier::fs::path& path)
return true;
}
static int cert_verify_ignore_callback(X509_STORE_CTX*, void*)
{
return 1;
}
void
SecureSocket::initContext(bool server)
{
@ -397,6 +401,14 @@ SecureSocket::initContext(bool server)
if (m_ssl->m_context == NULL) {
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
@ -437,6 +449,24 @@ SecureSocket::secureAccept(int socket)
// If not fatal and no retry, state is good
if (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()) {
retry = 0;
disconnect();
return -1;// Cert fail, error
}
}
else {
LOG((CLOG_ERR "failed to verify server certificate fingerprint"));
retry = 0;
disconnect();
return -1; // Fingerprint failed, error
}
}
m_secureReady = true;
LOG((CLOG_INFO "accepted secure socket"));
if (CLOG->getFilter() >= kDEBUG1) {
@ -462,6 +492,12 @@ SecureSocket::secureAccept(int socket)
int
SecureSocket::secureConnect(int socket)
{
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
}
createSSL();
// attach the socket descriptor
@ -491,9 +527,9 @@ SecureSocket::secureConnect(int socket)
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
}
@ -512,7 +548,7 @@ SecureSocket::secureConnect(int socket)
}
bool
SecureSocket::showCertificate()
SecureSocket::ensure_peer_certificate()
{
X509* cert;
char* line;
@ -521,12 +557,12 @@ SecureSocket::showCertificate()
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;
}
@ -649,8 +685,7 @@ SecureSocket::disconnect()
sendEvent(getEvents()->forIStream().inputShutdown());
}
bool
SecureSocket::verifyCertFingerprint()
bool SecureSocket::verify_cert_fingerprint(const barrier::fs::path& fingerprint_db_path)
{
// calculate received certificate fingerprint
barrier::FingerprintData fingerprint_sha1, fingerprint_sha256;
@ -666,12 +701,10 @@ SecureSocket::verifyCertFingerprint()
}
// note: the GUI parses the following two lines of logs, don't change unnecessarily
LOG((CLOG_NOTE "server fingerprint (SHA1): %s (SHA256): %s",
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()));
auto fingerprint_db_path = barrier::DataDirectories::trusted_servers_ssl_fingerprints_path();
// Provide debug hint as to what file is being used to verify fingerprint trust
LOG((CLOG_NOTE "fingerprint_db_path: %s", fingerprint_db_path.u8string().c_str()));

View File

@ -17,6 +17,7 @@
#pragma once
#include "ConnectionSecurityLevel.h"
#include "net/TCPSocket.h"
#include "net/XSocket.h"
#include "io/filesystem.h"
@ -33,10 +34,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
@ -64,12 +65,12 @@ private:
void createSSL();
int secureAccept(int s);
int secureConnect(int s);
bool showCertificate();
bool ensure_peer_certificate();
void checkResult(int n, int& retry);
void showError(const std::string& reason);
std::string getError();
void disconnect();
bool verifyCertFingerprint();
bool verify_cert_fingerprint(const barrier::fs::path& fingerprint_db_path);
MultiplexerJobStatus serviceConnect(ISocketMultiplexerJob*, bool, bool, bool);
MultiplexerJobStatus serviceAccept(ISocketMultiplexerJob*, bool, bool, bool);
@ -86,4 +87,5 @@ private:
Ssl* m_ssl;
bool m_secureReady;
bool m_fatal;
ConnectionSecurityLevel security_level_ = ConnectionSecurityLevel::ENCRYPTED;
};

View File

@ -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);

View File

@ -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;

View File

@ -36,18 +36,17 @@
ClientListener::ClientListener(const NetworkAddress& address,
ISocketFactory* socketFactory,
IEventQueue* events,
bool enableCrypto) :
ConnectionSecurityLevel security_level) :
m_socketFactory(socketFactory),
m_server(NULL),
m_events(events),
m_useSecureNetwork(enableCrypto)
security_level_{security_level}
{
assert(m_socketFactory != NULL);
try {
m_listen = m_socketFactory->createListen(
ARCH->getAddrFamily(address.getAddress()),
m_useSecureNetwork);
m_listen = m_socketFactory->createListen(ARCH->getAddrFamily(address.getAddress()),
security_level);
// setup event handler
m_events->adoptHandler(m_events->forIListenSocket().connecting(),
@ -140,7 +139,7 @@ ClientListener::handleClientConnecting(const Event&, void*)
// When using non SSL, server accepts clients immediately, while SSL
// has to call secure accept which may require retry
if (!m_useSecureNetwork) {
if (security_level_ == ConnectionSecurityLevel::PLAINTEXT) {
m_events->addEvent(Event(m_events->forClientListener().accepted(),
socket->getEventTarget()));
}

View File

@ -23,6 +23,7 @@
#include "base/Event.h"
#include "common/stddeque.h"
#include "common/stdset.h"
#include "net/ConnectionSecurityLevel.h"
class ClientProxy;
class ClientProxyUnknown;
@ -36,10 +37,8 @@ class IDataSocket;
class ClientListener {
public:
// The factories are adopted.
ClientListener(const NetworkAddress&,
ISocketFactory*,
IEventQueue* events,
bool enableCrypto);
ClientListener(const NetworkAddress&, ISocketFactory*, IEventQueue* events,
ConnectionSecurityLevel security_level);
~ClientListener();
//! @name manipulators
@ -86,6 +85,6 @@ private:
WaitingClients m_waitingClients;
Server* m_server;
IEventQueue* m_events;
bool m_useSecureNetwork;
ConnectionSecurityLevel security_level_;
ClientSockets m_clientSockets;
};

View File

@ -115,7 +115,8 @@ TEST_F(NetworkTests, sendToClient_mockData)
// server
SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
ClientListener listener(serverAddress, serverSocketFactory, &m_events, false);
ClientListener listener(serverAddress, serverSocketFactory, &m_events,
ConnectionSecurityLevel::PLAINTEXT);
NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig;
@ -173,7 +174,8 @@ TEST_F(NetworkTests, sendToClient_mockFile)
// server
SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
ClientListener listener(serverAddress, serverSocketFactory, &m_events, false);
ClientListener listener(serverAddress, serverSocketFactory, &m_events,
ConnectionSecurityLevel::PLAINTEXT);
NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig;
@ -230,7 +232,8 @@ TEST_F(NetworkTests, sendToServer_mockData)
// server
SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
ClientListener listener(serverAddress, serverSocketFactory, &m_events, false);
ClientListener listener(serverAddress, serverSocketFactory, &m_events,
ConnectionSecurityLevel::PLAINTEXT);
NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig;
@ -287,7 +290,8 @@ TEST_F(NetworkTests, sendToServer_mockFile)
// server
SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
ClientListener listener(serverAddress, serverSocketFactory, &m_events, false);
ClientListener listener(serverAddress, serverSocketFactory, &m_events,
ConnectionSecurityLevel::PLAINTEXT);
NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig;