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/CommandProcess.cpp
src/DataDownloader.cpp src/DataDownloader.cpp
src/DisplayIsValid.cpp src/DisplayIsValid.cpp
src/FingerprintAcceptDialog.cpp
src/HotkeyDialog.cpp src/HotkeyDialog.cpp
src/IpcClient.cpp src/IpcClient.cpp
src/Ipc.cpp src/Ipc.cpp
@ -104,6 +105,7 @@ set(GUI_UI_FILES
src/AboutDialogBase.ui src/AboutDialogBase.ui
src/ActionDialogBase.ui src/ActionDialogBase.ui
src/AddClientDialogBase.ui src/AddClientDialogBase.ui
src/FingerprintAcceptDialog.ui
src/HotkeyDialogBase.ui src/HotkeyDialogBase.ui
src/LogWindowBase.ui src/LogWindowBase.ui
src/MainWindowBase.ui src/MainWindowBase.ui

View File

@ -158,6 +158,8 @@ void AppConfig::loadSettings()
m_ElevateMode = static_cast<ElevateMode>(elevateMode.toInt()); m_ElevateMode = static_cast<ElevateMode>(elevateMode.toInt());
m_AutoConfigPrompted = settings().value("autoConfigPrompted", false).toBool(); m_AutoConfigPrompted = settings().value("autoConfigPrompted", false).toBool();
m_CryptoEnabled = settings().value("cryptoEnabled", true).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_AutoHide = settings().value("autoHide", false).toBool();
m_AutoStart = settings().value("autoStart", false).toBool(); m_AutoStart = settings().value("autoStart", false).toBool();
m_MinimizeToTray = settings().value("minimizeToTray", 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("elevateModeEnum", static_cast<int>(m_ElevateMode));
settings().setValue("autoConfigPrompted", m_AutoConfigPrompted); settings().setValue("autoConfigPrompted", m_AutoConfigPrompted);
settings().setValue("cryptoEnabled", m_CryptoEnabled); settings().setValue("cryptoEnabled", m_CryptoEnabled);
settings().setValue("requireClientCertificate", m_RequireClientCertificate);
settings().setValue("autoHide", m_AutoHide); settings().setValue("autoHide", m_AutoHide);
settings().setValue("autoStart", m_AutoStart); settings().setValue("autoStart", m_AutoStart);
settings().setValue("minimizeToTray", m_MinimizeToTray); settings().setValue("minimizeToTray", m_MinimizeToTray);
@ -225,6 +228,10 @@ void AppConfig::setCryptoEnabled(bool e) { m_CryptoEnabled = e; }
bool AppConfig::getCryptoEnabled() const { return m_CryptoEnabled; } 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; } void AppConfig::setAutoHide(bool b) { m_AutoHide = b; }
bool AppConfig::getAutoHide() { return m_AutoHide; } bool AppConfig::getAutoHide() { return m_AutoHide; }

View File

@ -91,6 +91,9 @@ class AppConfig: public QObject
void setCryptoEnabled(bool e); void setCryptoEnabled(bool e);
bool getCryptoEnabled() const; bool getCryptoEnabled() const;
void setRequireClientCertificate(bool e);
bool getRequireClientCertificate() const;
void setAutoHide(bool b); void setAutoHide(bool b);
bool getAutoHide(); bool getAutoHide();
@ -132,6 +135,7 @@ protected:
ElevateMode m_ElevateMode; ElevateMode m_ElevateMode;
bool m_AutoConfigPrompted; bool m_AutoConfigPrompted;
bool m_CryptoEnabled; bool m_CryptoEnabled;
bool m_RequireClientCertificate = false;
bool m_AutoHide; bool m_AutoHide;
bool m_AutoStart; bool m_AutoStart;
bool m_MinimizeToTray; 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 "ZeroconfService.h"
#include "DataDownloader.h" #include "DataDownloader.h"
#include "CommandProcess.h" #include "CommandProcess.h"
#include "FingerprintAcceptDialog.h"
#include "QUtility.h" #include "QUtility.h"
#include "ProcessorArch.h" #include "ProcessorArch.h"
#include "SslCertificate.h" #include "SslCertificate.h"
@ -427,7 +428,7 @@ void MainWindow::checkConnected(const QString& line)
void MainWindow::checkFingerprint(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)) { if (!fingerprintRegex.exactMatch(line)) {
return; return;
} }
@ -442,7 +443,16 @@ void MainWindow::checkFingerprint(const QString& line)
barrier::string::from_hex(fingerprintRegex.cap(2).toStdString()) 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 // 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 // still verify fingerprints on old Barrier servers. This way the only time when we are exposed
@ -456,36 +466,19 @@ void MainWindow::checkFingerprint(const QString& line)
static bool messageBoxAlreadyShown = false; static bool messageBoxAlreadyShown = false;
if (!messageBoxAlreadyShown) { if (!messageBoxAlreadyShown) {
stopBarrier(); if (is_client) {
stopBarrier();
}
messageBoxAlreadyShown = true; messageBoxAlreadyShown = true;
QMessageBox::StandardButton fingerprintReply = FingerprintAcceptDialog dialog{this, barrier_type(), fingerprint_sha1, fingerprint_sha256};
QMessageBox::information( if (dialog.exec() == QDialog::Accepted) {
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) {
// restart core process after trusting fingerprint. // restart core process after trusting fingerprint.
db.add_trusted(fingerprint_sha256); db.add_trusted(fingerprint_sha256);
db.write(db_path); db.write(db_path);
startBarrier(); if (is_client) {
startBarrier();
}
} }
messageBoxAlreadyShown = false; messageBoxAlreadyShown = false;
@ -567,8 +560,8 @@ void MainWindow::startBarrier()
args << "--profile-dir" << QString::fromStdString("\"" + barrier::DataDirectories::profile().u8string() + "\""); args << "--profile-dir" << QString::fromStdString("\"" + barrier::DataDirectories::profile().u8string() + "\"");
#endif #endif
if ((barrierType() == barrierClient && !clientArgs(args, app)) if ((barrier_type() == BarrierType::Client && !clientArgs(args, app))
|| (barrierType() == barrierServer && !serverArgs(args, app))) || (barrier_type() == BarrierType::Server && !serverArgs(args, app)))
{ {
stopBarrier(); stopBarrier();
return; return;
@ -583,7 +576,7 @@ void MainWindow::startBarrier()
m_pLogWindow->startNewInstance(); m_pLogWindow->startNewInstance();
appendLogInfo("starting " + QString(barrierType() == barrierServer ? "server" : "client")); appendLogInfo("starting " + QString(barrier_type() == BarrierType::Server ? "server" : "client"));
qDebug() << args; qDebug() << args;
@ -693,6 +686,11 @@ QString MainWindow::configFilename()
return filename; return filename;
} }
BarrierType MainWindow::barrier_type() const
{
return m_pGroupClient->isChecked() ? BarrierType::Client : BarrierType::Server;
}
QString MainWindow::address() QString MainWindow::address()
{ {
QString address = appConfig().networkInterface(); QString address = appConfig().networkInterface();
@ -729,6 +727,10 @@ bool MainWindow::serverArgs(QStringList& args, QString& app)
args << "--log" << appConfig().logFilenameCmd(); args << "--log" << appConfig().logFilenameCmd();
} }
if (!appConfig().getRequireClientCertificate()) {
args << "--disable-client-cert-checking";
}
QString configFilename = this->configFilename(); QString configFilename = this->configFilename();
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
// wrap in quotes in case username contains spaces. // wrap in quotes in case username contains spaces.
@ -983,7 +985,7 @@ void MainWindow::updateZeroconfService()
m_pZeroconfService = NULL; m_pZeroconfService = NULL;
} }
if (m_AppConfig->autoConfig() || barrierType() == barrierServer) { if (m_AppConfig->autoConfig() || barrier_type() == BarrierType::Server) {
m_pZeroconfService = new ZeroconfService(this); m_pZeroconfService = new ZeroconfService(this);
} }
} }

View File

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

View File

@ -55,107 +55,6 @@
</item> </item>
</layout> </layout>
</item> </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> <item>
<widget class="QRadioButton" name="m_pRadioInternalConfig"> <widget class="QRadioButton" name="m_pRadioInternalConfig">
<property name="text"> <property name="text">
@ -305,6 +204,107 @@
</layout> </layout>
</widget> </widget>
</item> </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> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint"> <property name="sizeConstraint">

View File

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

View File

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

View File

@ -65,6 +65,11 @@ void SslCertificate::generate_fingerprint(const barrier::fs::path& cert_path)
{ {
try { try {
auto local_path = barrier::DataDirectories::local_ssl_fingerprints_path(); 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; barrier::FingerprintDatabase db;
db.add_trusted(barrier::get_pem_file_cert_fingerprint(cert_path.u8string(), db.add_trusted(barrier::get_pem_file_cert_fingerprint(cert_path.u8string(),
barrier::FingerprintType::SHA1)); barrier::FingerprintType::SHA1));

View File

@ -66,7 +66,7 @@ ZeroconfService::ZeroconfService(MainWindow* mainWindow) :
m_ServiceRegistered(false) m_ServiceRegistered(false)
{ {
silence_avahi_warning(); silence_avahi_warning();
if (m_pMainWindow->barrierType() == MainWindow::barrierServer) { if (m_pMainWindow->barrier_type() == BarrierType::Server) {
if (registerService(true)) { if (registerService(true)) {
m_pZeroconfBrowser = new ZeroconfBrowser(this); m_pZeroconfBrowser = new ZeroconfBrowser(this);
connect(m_pZeroconfBrowser, SIGNAL( 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 // save screen change script path
args.m_screenChangeScript = argv[++i]; 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())); LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, args.m_exename.c_str(), argv[i], args.m_exename.c_str()));
return false; 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" << "Options:\n"
<< " -a, --address <address> listen for clients on the given address.\n" << " -a, --address <address> listen for clients on the given address.\n"
<< " -c, --config <pathname> use the named configuration file instead.\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" << "Default options are marked with a *\n"
<< "\n" << "\n"
<< "The argument for --address is of the form: [<hostname>][:<port>]. The\n" << "The argument for --address is of the form: [<hostname>][:<port>]. The\n"
@ -655,11 +658,18 @@ ServerApp::handleResume(const Event&, void*)
ClientListener* ClientListener*
ServerApp::openClientListener(const NetworkAddress& address) 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( ClientListener* listen = new ClientListener(
address, address,
new TCPSocketFactory(m_events, getSocketMultiplexer()), new TCPSocketFactory(m_events, getSocketMultiplexer()),
m_events, m_events, security_level);
args().m_enableCrypto);
m_events->adoptHandler( m_events->adoptHandler(
m_events->forClientListener().connected(), listen, m_events->forClientListener().connected(), listen,

View File

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

View File

@ -127,6 +127,12 @@ Client::connect()
return; return;
} }
auto security_level = ConnectionSecurityLevel::PLAINTEXT;
if (m_useSecureNetwork) {
// client always authenticates server
security_level = ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED;
}
try { try {
// resolve the server hostname. do this every time we connect // resolve the server hostname. do this every time we connect
// in case we couldn't resolve the address earlier or the address // in case we couldn't resolve the address earlier or the address
@ -145,9 +151,8 @@ Client::connect()
} }
// create the socket // create the socket
IDataSocket* socket = m_socketFactory->create( IDataSocket* socket = m_socketFactory->create(ARCH->getAddrFamily(m_serverAddress.getAddress()),
ARCH->getAddrFamily(m_serverAddress.getAddress()), security_level);
m_useSecureNetwork);
m_socket = dynamic_cast<TCPSocket*>(socket); m_socket = dynamic_cast<TCPSocket*>(socket);
// filter socket messages, including a packetizing filter // 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 "common/IInterface.h"
#include "arch/IArchNetwork.h" #include "arch/IArchNetwork.h"
#include "net/ConnectionSecurityLevel.h"
class IDataSocket; class IDataSocket;
class IListenSocket; class IListenSocket;
@ -35,14 +36,12 @@ public:
//@{ //@{
//! Create data socket //! Create data socket
virtual IDataSocket* create( virtual IDataSocket* create(IArchNetwork::EAddressFamily family,
IArchNetwork::EAddressFamily family, ConnectionSecurityLevel security_level) const = 0;
bool secure) const = 0;
//! Create listen socket //! Create listen socket
virtual IListenSocket* createListen( virtual IListenSocket* createListen(IArchNetwork::EAddressFamily family,
IArchNetwork::EAddressFamily family, ConnectionSecurityLevel security_level) const = 0;
bool secure) const = 0;
//@} //@}
}; };

View File

@ -25,11 +25,11 @@
#include "common/DataDirectories.h" #include "common/DataDirectories.h"
#include "base/String.h" #include "base/String.h"
SecureListenSocket::SecureListenSocket( SecureListenSocket::SecureListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
IEventQueue* events, IArchNetwork::EAddressFamily family,
SocketMultiplexer* socketMultiplexer, ConnectionSecurityLevel security_level) :
IArchNetwork::EAddressFamily family) : TCPListenSocket(events, socketMultiplexer, family),
TCPListenSocket(events, socketMultiplexer, family) security_level_{security_level}
{ {
} }
@ -38,10 +38,8 @@ SecureListenSocket::accept()
{ {
SecureSocket* socket = NULL; SecureSocket* socket = NULL;
try { try {
socket = new SecureSocket( socket = new SecureSocket(m_events, m_socketMultiplexer,
m_events, ARCH->acceptSocket(m_socket, NULL), security_level_);
m_socketMultiplexer,
ARCH->acceptSocket(m_socket, NULL));
socket->initSsl(true); socket->initSsl(true);
if (socket != NULL) { if (socket != NULL) {

View File

@ -19,6 +19,7 @@
#include "net/TCPListenSocket.h" #include "net/TCPListenSocket.h"
#include "common/stdset.h" #include "common/stdset.h"
#include "ConnectionSecurityLevel.h"
class IEventQueue; class IEventQueue;
class SocketMultiplexer; class SocketMultiplexer;
@ -26,11 +27,13 @@ class IDataSocket;
class SecureListenSocket : public TCPListenSocket { class SecureListenSocket : public TCPListenSocket {
public: public:
SecureListenSocket(IEventQueue* events, SecureListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family,
IArchNetwork::EAddressFamily family); ConnectionSecurityLevel security_level);
// IListenSocket overrides // IListenSocket overrides
virtual IDataSocket* virtual IDataSocket*
accept(); accept();
private:
ConnectionSecurityLevel security_level_;
}; };

View File

@ -54,25 +54,24 @@ struct Ssl {
SSL* m_ssl; SSL* m_ssl;
}; };
SecureSocket::SecureSocket( SecureSocket::SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
IEventQueue* events, IArchNetwork::EAddressFamily family,
SocketMultiplexer* socketMultiplexer, ConnectionSecurityLevel security_level) :
IArchNetwork::EAddressFamily family) :
TCPSocket(events, socketMultiplexer, family), TCPSocket(events, socketMultiplexer, family),
m_ssl(nullptr), m_ssl(nullptr),
m_secureReady(false), m_secureReady(false),
m_fatal(false) m_fatal(false),
security_level_{security_level}
{ {
} }
SecureSocket::SecureSocket( SecureSocket::SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
IEventQueue* events, ArchSocket socket, ConnectionSecurityLevel security_level) :
SocketMultiplexer* socketMultiplexer,
ArchSocket socket) :
TCPSocket(events, socketMultiplexer, socket), TCPSocket(events, socketMultiplexer, socket),
m_ssl(nullptr), m_ssl(nullptr),
m_secureReady(false), 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; return true;
} }
static int cert_verify_ignore_callback(X509_STORE_CTX*, void*)
{
return 1;
}
void void
SecureSocket::initContext(bool server) SecureSocket::initContext(bool server)
{ {
@ -397,6 +401,14 @@ SecureSocket::initContext(bool server)
if (m_ssl->m_context == NULL) { 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 void
@ -437,6 +449,24 @@ SecureSocket::secureAccept(int socket)
// If not fatal and no retry, state is good // If not fatal and no retry, state is good
if (retry == 0) { 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; m_secureReady = true;
LOG((CLOG_INFO "accepted secure socket")); LOG((CLOG_INFO "accepted secure socket"));
if (CLOG->getFilter() >= kDEBUG1) { if (CLOG->getFilter() >= kDEBUG1) {
@ -462,6 +492,12 @@ SecureSocket::secureAccept(int socket)
int int
SecureSocket::secureConnect(int socket) 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(); createSSL();
// attach the socket descriptor // attach the socket descriptor
@ -491,9 +527,9 @@ SecureSocket::secureConnect(int socket)
retry = 0; retry = 0;
// No error, set ready, process and return ok // No error, set ready, process and return ok
m_secureReady = true; m_secureReady = true;
if (verifyCertFingerprint()) { if (verify_cert_fingerprint(barrier::DataDirectories::trusted_servers_ssl_fingerprints_path())) {
LOG((CLOG_INFO "connected to secure socket")); LOG((CLOG_INFO "connected to secure socket"));
if (!showCertificate()) { if (!ensure_peer_certificate()) {
disconnect(); disconnect();
return -1;// Cert fail, error return -1;// Cert fail, error
} }
@ -512,7 +548,7 @@ SecureSocket::secureConnect(int socket)
} }
bool bool
SecureSocket::showCertificate() SecureSocket::ensure_peer_certificate()
{ {
X509* cert; X509* cert;
char* line; char* line;
@ -521,12 +557,12 @@ SecureSocket::showCertificate()
cert = SSL_get_peer_certificate(m_ssl->m_ssl); cert = SSL_get_peer_certificate(m_ssl->m_ssl);
if (cert != NULL) { if (cert != NULL) {
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); 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); OPENSSL_free(line);
X509_free(cert); X509_free(cert);
} }
else { else {
showError("server has no ssl certificate"); showError("peer has no ssl certificate");
return false; return false;
} }
@ -649,8 +685,7 @@ SecureSocket::disconnect()
sendEvent(getEvents()->forIStream().inputShutdown()); sendEvent(getEvents()->forIStream().inputShutdown());
} }
bool bool SecureSocket::verify_cert_fingerprint(const barrier::fs::path& fingerprint_db_path)
SecureSocket::verifyCertFingerprint()
{ {
// calculate received certificate fingerprint // calculate received certificate fingerprint
barrier::FingerprintData fingerprint_sha1, fingerprint_sha256; 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 // 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_sha1.data).c_str(),
barrier::format_ssl_fingerprint(fingerprint_sha256.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 // 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())); LOG((CLOG_NOTE "fingerprint_db_path: %s", fingerprint_db_path.u8string().c_str()));

View File

@ -17,6 +17,7 @@
#pragma once #pragma once
#include "ConnectionSecurityLevel.h"
#include "net/TCPSocket.h" #include "net/TCPSocket.h"
#include "net/XSocket.h" #include "net/XSocket.h"
#include "io/filesystem.h" #include "io/filesystem.h"
@ -33,10 +34,10 @@ A secure socket using SSL.
*/ */
class SecureSocket : public TCPSocket { class SecureSocket : public TCPSocket {
public: public:
SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family); SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
SecureSocket(IEventQueue* events, IArchNetwork::EAddressFamily family, ConnectionSecurityLevel security_level);
SocketMultiplexer* socketMultiplexer, SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
ArchSocket socket); ArchSocket socket, ConnectionSecurityLevel security_level);
~SecureSocket(); ~SecureSocket();
// ISocket overrides // ISocket overrides
@ -64,12 +65,12 @@ private:
void createSSL(); void createSSL();
int secureAccept(int s); int secureAccept(int s);
int secureConnect(int s); int secureConnect(int s);
bool showCertificate(); bool ensure_peer_certificate();
void checkResult(int n, int& retry); void checkResult(int n, int& retry);
void showError(const std::string& reason); void showError(const std::string& reason);
std::string getError(); std::string getError();
void disconnect(); void disconnect();
bool verifyCertFingerprint(); bool verify_cert_fingerprint(const barrier::fs::path& fingerprint_db_path);
MultiplexerJobStatus serviceConnect(ISocketMultiplexerJob*, bool, bool, bool); MultiplexerJobStatus serviceConnect(ISocketMultiplexerJob*, bool, bool, bool);
MultiplexerJobStatus serviceAccept(ISocketMultiplexerJob*, bool, bool, bool); MultiplexerJobStatus serviceAccept(ISocketMultiplexerJob*, bool, bool, bool);
@ -86,4 +87,5 @@ private:
Ssl* m_ssl; Ssl* m_ssl;
bool m_secureReady; bool m_secureReady;
bool m_fatal; bool m_fatal;
ConnectionSecurityLevel security_level_ = ConnectionSecurityLevel::ENCRYPTED;
}; };

View File

@ -40,11 +40,12 @@ TCPSocketFactory::~TCPSocketFactory()
// do nothing // do nothing
} }
IDataSocket* IDataSocket* TCPSocketFactory::create(IArchNetwork::EAddressFamily family,
TCPSocketFactory::create(IArchNetwork::EAddressFamily family, bool secure) const ConnectionSecurityLevel security_level) const
{ {
if (secure) { if (security_level != ConnectionSecurityLevel::PLAINTEXT) {
SecureSocket* secureSocket = new SecureSocket(m_events, m_socketMultiplexer, family); SecureSocket* secureSocket = new SecureSocket(m_events, m_socketMultiplexer, family,
security_level);
secureSocket->initSsl (false); secureSocket->initSsl (false);
return secureSocket; return secureSocket;
} }
@ -53,12 +54,12 @@ TCPSocketFactory::create(IArchNetwork::EAddressFamily family, bool secure) const
} }
} }
IListenSocket* IListenSocket* TCPSocketFactory::createListen(IArchNetwork::EAddressFamily family,
TCPSocketFactory::createListen(IArchNetwork::EAddressFamily family, bool secure) const ConnectionSecurityLevel security_level) const
{ {
IListenSocket* socket = NULL; IListenSocket* socket = NULL;
if (secure) { if (security_level != ConnectionSecurityLevel::PLAINTEXT) {
socket = new SecureListenSocket(m_events, m_socketMultiplexer, family); socket = new SecureListenSocket(m_events, m_socketMultiplexer, family, security_level);
} }
else { else {
socket = new TCPListenSocket(m_events, m_socketMultiplexer, family); socket = new TCPListenSocket(m_events, m_socketMultiplexer, family);

View File

@ -31,12 +31,11 @@ public:
virtual ~TCPSocketFactory(); virtual ~TCPSocketFactory();
// ISocketFactory overrides // ISocketFactory overrides
virtual IDataSocket* create( virtual IDataSocket* create(IArchNetwork::EAddressFamily family,
IArchNetwork::EAddressFamily family, ConnectionSecurityLevel security_level) const;
bool secure) const;
virtual IListenSocket* createListen( virtual IListenSocket* createListen(IArchNetwork::EAddressFamily family,
IArchNetwork::EAddressFamily family, ConnectionSecurityLevel security_level) const;
bool secure) const;
private: private:
IEventQueue* m_events; IEventQueue* m_events;

View File

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

View File

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

View File

@ -115,7 +115,8 @@ TEST_F(NetworkTests, sendToClient_mockData)
// server // server
SocketMultiplexer serverSocketMultiplexer; SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &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<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient; NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig; NiceMock<MockConfig> serverConfig;
@ -173,7 +174,8 @@ TEST_F(NetworkTests, sendToClient_mockFile)
// server // server
SocketMultiplexer serverSocketMultiplexer; SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &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<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient; NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig; NiceMock<MockConfig> serverConfig;
@ -230,7 +232,8 @@ TEST_F(NetworkTests, sendToServer_mockData)
// server // server
SocketMultiplexer serverSocketMultiplexer; SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &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<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient; NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig; NiceMock<MockConfig> serverConfig;
@ -287,7 +290,8 @@ TEST_F(NetworkTests, sendToServer_mockFile)
// server // server
SocketMultiplexer serverSocketMultiplexer; SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &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<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient; NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig; NiceMock<MockConfig> serverConfig;