refactor: use new Fingerprint database

based-on: 50534ecb43
   based-on: be8ba0d132
This commit is contained in:
sithlord48 2025-02-08 14:10:39 -05:00 committed by Nick Bolton
parent 298b1047c4
commit d0d5182425
8 changed files with 83 additions and 196 deletions

View file

@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2024 Chris Rizzitello <sithord48@gmail.com>
* SPDX-FileCopyrightText: (C) 2024 - 2025 Chris Rizzitello <sithord48@gmail.com>
* SPDX-FileCopyrightText: (C) 2012 - 2024 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2008 Volker Lanz <vl@fidra.de>
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -13,6 +13,7 @@
#include "dialogs/ServerConfigDialog.h"
#include "dialogs/SettingsDialog.h"
#include "base/String.h"
#include "common/constants.h"
#include "gui/Logger.h"
#include "gui/config/ConfigScopes.h"
@ -23,7 +24,9 @@
#include "gui/string_utils.h"
#include "gui/style_utils.h"
#include "gui/styles.h"
#include "gui/tls/TlsFingerprint.h"
#include "net/FingerprintDatabase.h"
#include "net/SecureUtils.h"
#include "platform/wayland.h"
#if defined(Q_OS_LINUX)
@ -466,7 +469,29 @@ void MainWindow::updateSize()
void MainWindow::showMyFingerprint()
{
QMessageBox::information(this, "TLS fingerprint", TlsFingerprint::local().readFirst());
auto localPath = QStringLiteral("%1/%2").arg(getTlsPath(), kFingerprintLocalFilename).toStdString();
if (!QFile::exists(QString::fromStdString(localPath))) {
QMessageBox::information(
this, tr("TLS fingerprint Error"),
tr("Unable to read localfinger print: %1\n You may want to regenerate your keys.")
.arg(QString::fromStdString(localPath))
);
return;
}
deskflow::FingerprintDatabase db;
db.read(localPath);
if (db.fingerprints().empty()) {
QMessageBox::information(
this, tr("TLS fingerprint Error"),
tr("Unable to read localDatabase\n You may want to regenerate your keys.")
.arg(QString::fromStdString(localPath))
);
return;
}
const auto fingerprint = QString::fromStdString(deskflow::formatSSLFingerprint(db.fingerprints().front().data));
QMessageBox::information(this, "TLS fingerprint", fingerprint);
}
void MainWindow::setModeServer()
@ -669,8 +694,13 @@ void MainWindow::checkFingerprint(const QString &line)
return;
}
auto fingerprint = match.captured(1);
if (TlsFingerprint::trustedServers().isTrusted(fingerprint)) {
auto localPath = QStringLiteral("%1/%2").arg(getTlsPath(), kFingerprintTrustedServersFilename).toStdString();
deskflow::FingerprintDatabase db;
db.read(localPath);
const deskflow::FingerprintData fingerprint{"sha1", deskflow::string::fromHex(match.captured(1).toStdString())};
if (db.isTrusted(fingerprint)) {
return;
}
@ -690,13 +720,13 @@ void MainWindow::checkFingerprint(const QString &line)
"you're expecting (it could be a malicious user).</p>"
"<p>Do you want to trust this fingerprint for future "
"connections? If you don't, a connection cannot be made.</p>")
.arg(fingerprint),
.arg(QString::fromStdString(deskflow::formatSSLFingerprint(fingerprint.data))),
QMessageBox::Yes | QMessageBox::No
);
if (fingerprintReply == QMessageBox::Yes) {
// start core process again after trusting fingerprint.
TlsFingerprint::trustedServers().trust(fingerprint);
db.addTrusted(fingerprint);
db.write(localPath);
m_coreProcess.start();
}
@ -897,7 +927,8 @@ void MainWindow::updateLocalFingerprint()
{
bool fingerprintExists = false;
try {
fingerprintExists = TlsFingerprint::local().fileExists();
auto localPath = QStringLiteral("%1/%2").arg(getTlsPath(), kFingerprintLocalFilename).toStdString();
fingerprintExists = QFile::exists(QString::fromStdString(localPath));
} catch (const std::exception &e) {
qDebug() << e.what();
qFatal() << "failed to check if fingerprint exists";
@ -1026,3 +1057,9 @@ void MainWindow::showAndActivate()
m_actionRestore->setVisible(false);
m_actionMinimize->setVisible(true);
}
QString MainWindow::getTlsPath()
{
CoreTool coreTool;
return QStringLiteral("%1/%2").arg(coreTool.getProfileDir(), kSslDir);
}

View file

@ -164,6 +164,8 @@ private:
void updateStatus();
void showAndActivate();
QString getTlsPath();
VersionChecker m_versionChecker;
bool m_secureSocket = false;
deskflow::gui::config::ServerConfigDialogState m_serverConfigDialogState;

View file

@ -29,4 +29,5 @@ const auto kDebugBuild = false;
const auto kSslDir = "tls";
const auto kCertificateFilename = "@CMAKE_PROJECT_NAME@.pem";
const auto kFingerprintLocalFilename = "local-fingerprint";
const auto kFingerprintTrustedServersFilename = "trusted-servers";

View file

@ -77,8 +77,6 @@ add_library(${target} STATIC
proxy/QSettingsProxy.h
tls/TlsCertificate.cpp
tls/TlsCertificate.h
tls/TlsFingerprint.cpp
tls/TlsFingerprint.h
tls/TlsUtility.cpp
tls/TlsUtility.h
validators/AliasValidator.cpp

View file

@ -7,9 +7,10 @@
#include "TlsCertificate.h"
#include "TlsFingerprint.h"
#include "common/constants.h"
#include "gui/core/CoreTool.h"
#include "net/FingerprintData.h"
#include "net/FingerprintDatabase.h"
#include "net/SecureUtils.h"
#include <QCoreApplication>
@ -47,7 +48,18 @@ bool TlsCertificate::generateFingerprint(const QString &certificateFilename)
try {
auto fingerprint =
deskflow::pemFileCertFingerprint(certificateFilename.toStdString(), deskflow::FingerprintType::SHA1);
TlsFingerprint::local().trust(QString::fromStdString(deskflow::formatSSLFingerprint(fingerprint)), false);
CoreTool coreTool;
QString profileDir = coreTool.getProfileDir();
auto localPath = QStringLiteral("%1/%2/%3").arg(profileDir, kSslDir, kFingerprintLocalFilename).toStdString();
const deskflow::FingerprintData data{"sha1", fingerprint};
deskflow::FingerprintDatabase db;
db.addTrusted(data);
db.write(localPath);
qDebug("tls fingerprint generated");
return true;
} catch (const std::exception &e) {

View file

@ -1,131 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2015 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "TlsFingerprint.h"
#include "gui/core/CoreTool.h"
#include <QDir>
#include <QTextStream>
// TODO: Reduce duplication of these strings between here and SecureSocket.cpp
static const char kDirName[] = "tls";
static const char kLocalFilename[] = "local-fingerprint";
static const char kTrustedServersFilename[] = "trusted-servers";
static const char kTrustedClientsFilename[] = "trusted-clients";
TlsFingerprint::TlsFingerprint(const QString &filename) : m_Filename(filename)
{
}
void TlsFingerprint::trust(const QString &fingerprintText, bool append) const
{
TlsFingerprint::persistDirectory();
QIODevice::OpenMode openMode;
if (append) {
openMode = QIODevice::Append;
} else {
openMode = QIODevice::WriteOnly;
}
QFile file(filePath());
if (file.open(openMode)) {
QTextStream out(&file);
out << fingerprintText << "\n";
file.close();
}
}
bool TlsFingerprint::fileExists() const
{
QString dirName = TlsFingerprint::directoryPath();
if (!QDir(dirName).exists()) {
return false;
}
QFile file(filePath());
return file.exists();
}
bool TlsFingerprint::isTrusted(const QString &fingerprintText) const
{
const QStringList list = readList();
for (const auto &trusted : list) {
if (trusted == fingerprintText) {
return true;
}
}
return false;
}
QStringList TlsFingerprint::readList(const int readTo) const
{
QStringList list;
QString dirName = TlsFingerprint::directoryPath();
if (!QDir(dirName).exists()) {
return list;
}
QFile file(filePath());
if (file.open(QIODevice::ReadOnly)) {
QTextStream in(&file);
while (!in.atEnd()) {
list.append(in.readLine());
if (list.size() == readTo) {
break;
}
}
file.close();
}
return list;
}
QString TlsFingerprint::readFirst() const
{
QStringList list = readList(1);
return list.at(0);
}
QString TlsFingerprint::filePath() const
{
QString dir = TlsFingerprint::directoryPath();
return QString("%1/%2").arg(dir, m_Filename);
}
void TlsFingerprint::persistDirectory()
{
QDir dir(TlsFingerprint::directoryPath());
if (!dir.exists()) {
dir.mkpath(".");
}
}
QString TlsFingerprint::directoryPath()
{
CoreTool coreTool;
QString profileDir = coreTool.getProfileDir();
return QString("%1/%2").arg(profileDir, kDirName);
}
TlsFingerprint TlsFingerprint::local()
{
return TlsFingerprint(kLocalFilename);
}
TlsFingerprint TlsFingerprint::trustedServers()
{
return TlsFingerprint(kTrustedServersFilename);
}
TlsFingerprint TlsFingerprint::trustedClients()
{
return TlsFingerprint(kTrustedClientsFilename);
}

View file

@ -1,34 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2015 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include <QString>
class TlsFingerprint
{
private:
explicit TlsFingerprint(const QString &filename);
public:
static TlsFingerprint local();
static TlsFingerprint trustedServers();
static TlsFingerprint trustedClients();
static QString directoryPath();
static QString localFingerprint();
static bool localFingerprintExists();
static void persistDirectory();
void trust(const QString &fingerprintText, bool append = true) const;
bool isTrusted(const QString &fingerprintText) const;
QStringList readList(const int readTo = -1) const;
QString readFirst() const;
QString filePath() const;
bool fileExists() const;
private:
QString m_Filename;
};

View file

@ -15,6 +15,7 @@
#include "base/TMethodEventJob.h"
#include "common/constants.h"
#include "mt/Lock.h"
#include "net/FingerprintDatabase.h"
#include "net/TCPSocket.h"
#include "net/TSocketMultiplexerMethodJob.h"
#include <net/InverseSockets/SslLogger.h>
@ -621,34 +622,35 @@ bool SecureSocket::verifyCertFingerprint()
return false;
}
auto fingerprint = deskflow::formatSSLFingerprint(fingerprint_raw);
LOG((CLOG_NOTE "server fingerprint: %s", fingerprint.c_str()));
LOG((CLOG_NOTE "server fingerprint: %s", deskflow::formatSSLFingerprint(fingerprint_raw).c_str()));
std::string trustedServersFilename;
trustedServersFilename = deskflow::string::sprintf(
std::string trustedServersFilename = deskflow::string::sprintf(
"%s/%s/%s", ARCH->getProfileDirectory().c_str(), kSslDir, kFingerprintTrustedServersFilename
);
// check if this fingerprint exist
std::string fileLine;
std::ifstream file;
file.open(deskflow::filesystem::path(trustedServersFilename));
bool isValid = false;
if (file.is_open()) {
while (!file.eof()) {
getline(file, fileLine);
if (!fileLine.empty() && !fileLine.compare(fingerprint)) {
isValid = true;
break;
}
}
deskflow::openUtf8Path(file, trustedServersFilename);
deskflow::FingerprintDatabase db;
db.read(trustedServersFilename);
if (!db.fingerprints().empty()) {
LOG((CLOG_NOTE "read %d fingerprints from %s", db.fingerprints().size(), trustedServersFilename.c_str()));
} else {
LOG((CLOG_ERR "fail to open trusted fingerprints file: %s", trustedServersFilename.c_str()));
LOG((CLOG_ERR "failed to open trusted fingerprints file: %s", trustedServersFilename.c_str()));
return false;
}
file.close();
return isValid;
deskflow::FingerprintData fingerprint{"sha1", fingerprint_raw};
if (!db.isTrusted(fingerprint)) {
LOG((CLOG_WARN "fingerprint does not match trusted fingerprint"));
return false;
}
LOG((CLOG_NOTE "fingerprint matches trusted fingerprint"));
return true;
}
ISocketMultiplexerJob *SecureSocket::serviceConnect(ISocketMultiplexerJob *job, bool, bool write, bool error)