Files
deskflow/src/lib/gui/tls/TlsCertificate.cpp

119 lines
3.5 KiB
C++

/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2015 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "TlsCertificate.h"
#include "base/FinalAction.h"
#include "common/Settings.h"
#include "net/FingerprintData.h"
#include "net/FingerprintDatabase.h"
#include "net/SecureUtils.h"
#include <QCoreApplication>
#include <QDir>
#include <QProcess>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
TlsCertificate::TlsCertificate(QObject *parent) : QObject(parent)
{
}
bool TlsCertificate::generateCertificate(const QString &path, int keyLength)
{
qDebug("generating tls certificate: %s", qUtf8Printable(path));
QFileInfo info(path);
QDir dir(info.absolutePath());
if (!dir.exists() && !dir.mkpath(".")) {
qCritical("failed to create directory for tls certificate");
return false;
}
try {
deskflow::generatePemSelfSignedCert(path.toStdString(), keyLength);
} catch (const std::exception &e) {
qCritical() << "failed to generate self-signed pem cert: " << e.what();
return false;
}
qDebug("tls certificate generated");
return generateFingerprint(path);
}
bool TlsCertificate::generateFingerprint(const QString &certificateFilename)
{
qDebug("generating tls fingerprint");
const std::string certPath = certificateFilename.toStdString();
try {
deskflow::FingerprintDatabase db;
db.addTrusted(deskflow::pemFileCertFingerprint(certPath, deskflow::FingerprintType::SHA1));
db.addTrusted(deskflow::pemFileCertFingerprint(certPath, deskflow::FingerprintType::SHA256));
db.write(QStringLiteral("%1/%2").arg(Settings::tlsLocalDb()).toStdString());
qDebug("tls fingerprint generated");
return true;
} catch (const std::exception &e) {
qCritical() << "failed to find tls fingerprint: " << e.what();
return false;
}
}
int TlsCertificate::getCertKeyLength(const QString &path)
{
return deskflow::getCertLength(path.toStdString());
}
QString TlsCertificate::getCertificatePath() const
{
return QStringLiteral("%1/%2").arg(Settings::tlsDir(), kTlsCertificateFilename);
}
bool TlsCertificate::isCertificateValid(const QString &path)
{
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
auto fp = deskflow::fopenUtf8Path(path.toStdString(), "r");
if (!fp) {
qWarning() << tr("could not read from default certificate file");
return false;
}
auto fileClose = deskflow::finally([fp]() { std::fclose(fp); });
auto *cert = PEM_read_X509(fp, nullptr, nullptr, nullptr);
if (!cert) {
qWarning() << tr("could not load default certificate file to memory");
return false;
}
auto certFree = deskflow::finally([cert]() { X509_free(cert); });
auto *pubkey = X509_get_pubkey(cert);
if (!pubkey) {
qWarning() << tr("default certificate key file does not contain valid public key");
return false;
}
auto pubkeyFree = deskflow::finally([pubkey]() { EVP_PKEY_free(pubkey); });
auto type = EVP_PKEY_type(EVP_PKEY_id(pubkey));
if (type != EVP_PKEY_RSA && type != EVP_PKEY_DSA) {
qWarning() << tr("public key in default certificate key file is not RSA or DSA");
return false;
}
auto bits = EVP_PKEY_bits(pubkey);
if (bits < 2048) {
// We could have small keys in old barrier installations
qWarning() << tr("public key in default certificate key file is too small");
return false;
}
return true;
}