2015-04-20 17:51:22 +00:00
|
|
|
/*
|
|
|
|
|
* synergy -- mouse and keyboard sharing utility
|
2024-07-26 22:53:52 +00:00
|
|
|
* Copyright (C) 2015 Symless Ltd.
|
2015-04-20 17:51:22 +00:00
|
|
|
*
|
|
|
|
|
* This package is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
2015-05-03 02:33:52 +00:00
|
|
|
* found in the file LICENSE that should have accompanied this file.
|
2015-04-20 17:51:22 +00:00
|
|
|
*
|
|
|
|
|
* 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/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2024-07-26 22:53:52 +00:00
|
|
|
#include "TlsCertificate.h"
|
2015-04-20 17:51:22 +00:00
|
|
|
|
2024-07-26 22:53:52 +00:00
|
|
|
#include "TlsFingerprint.h"
|
2015-04-20 17:51:22 +00:00
|
|
|
|
|
|
|
|
#include <QCoreApplication>
|
2024-07-02 19:07:06 +00:00
|
|
|
#include <QDir>
|
|
|
|
|
#include <QProcess>
|
2015-04-20 17:51:22 +00:00
|
|
|
|
2024-07-22 16:48:02 +00:00
|
|
|
// RSA Bit length (e.g. 1024/2048/4096)
|
|
|
|
|
static const char *const kCertificateKeyLength = "rsa:";
|
|
|
|
|
|
|
|
|
|
// fingerprint hashing algorithm
|
|
|
|
|
static const char *const kCertificateHashAlgorithm = "-sha256";
|
|
|
|
|
|
|
|
|
|
static const char *const kCertificateLifetime = "365";
|
|
|
|
|
static const char *const kCertificateSubjectInfo = "/CN=Synergy";
|
|
|
|
|
static const char *const kCertificateFilename = "Synergy.pem";
|
|
|
|
|
static const char *const kSslDir = "SSL";
|
2015-04-20 17:51:22 +00:00
|
|
|
|
|
|
|
|
#if defined(Q_OS_WIN)
|
2024-07-22 16:48:02 +00:00
|
|
|
static const char *const kWinOpenSslDir = "OpenSSL";
|
|
|
|
|
static const char *const kWinOpenSslBinary = "openssl.exe";
|
|
|
|
|
static const char *const kConfigFile = "synergy.conf";
|
|
|
|
|
#elif defined(Q_OS_UNIX)
|
|
|
|
|
static const char *const kUnixOpenSslCommand = "openssl";
|
2015-04-20 17:51:22 +00:00
|
|
|
#endif
|
|
|
|
|
|
2024-07-22 16:48:02 +00:00
|
|
|
namespace synergy::gui {
|
|
|
|
|
#if defined(Q_OS_WIN)
|
|
|
|
|
|
|
|
|
|
QString openSslWindowsDir() {
|
|
|
|
|
|
|
|
|
|
auto appDir = QDir(QCoreApplication::applicationDirPath());
|
|
|
|
|
auto openSslDir = QDir(appDir.filePath(kWinOpenSslDir));
|
|
|
|
|
|
|
|
|
|
// in production, openssl is deployed with the app.
|
|
|
|
|
// in development, we can use the openssl path available at compile-time.
|
|
|
|
|
if (!openSslDir.exists()) {
|
|
|
|
|
openSslDir = QDir(OPENSSL_PATH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if the path still isn't found, something is seriously wrong.
|
|
|
|
|
if (!openSslDir.exists()) {
|
2024-08-01 00:13:01 +00:00
|
|
|
qFatal() << "openssl dir not found: " << openSslDir;
|
2024-07-22 16:48:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return QDir::cleanPath(openSslDir.absolutePath());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString openSslWindowsBinary() {
|
|
|
|
|
auto dir = QDir(openSslWindowsDir());
|
|
|
|
|
auto path = dir.filePath(kWinOpenSslBinary);
|
|
|
|
|
|
|
|
|
|
// when installed, there is no openssl bin dir; it's installed at the base.
|
|
|
|
|
// in development, we use the standard dir structure for openssl (bin dir).
|
|
|
|
|
if (!QFile::exists(path)) {
|
|
|
|
|
auto binDir = QDir(dir.filePath("bin"));
|
|
|
|
|
path = binDir.filePath(kWinOpenSslBinary);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if the path still isn't found, something is seriously wrong.
|
|
|
|
|
if (!QFile::exists(path)) {
|
2024-08-01 00:13:01 +00:00
|
|
|
qFatal() << "openssl binary not found: " << path;
|
2024-07-22 16:48:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
} // namespace synergy::gui
|
|
|
|
|
|
|
|
|
|
using namespace synergy::gui;
|
|
|
|
|
|
2024-07-26 22:53:52 +00:00
|
|
|
TlsCertificate::TlsCertificate(QObject *parent) : QObject(parent) {
|
2024-07-02 19:07:06 +00:00
|
|
|
m_ProfileDir = m_CoreInterface.getProfileDir();
|
|
|
|
|
if (m_ProfileDir.isEmpty()) {
|
|
|
|
|
emit error(tr("Failed to get profile directory."));
|
|
|
|
|
}
|
2015-04-20 17:51:22 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-26 22:53:52 +00:00
|
|
|
bool TlsCertificate::runTool(const QStringList &args) {
|
2024-07-02 19:07:06 +00:00
|
|
|
QString program;
|
2015-04-20 17:51:22 +00:00
|
|
|
#if defined(Q_OS_WIN)
|
2024-07-22 16:48:02 +00:00
|
|
|
program = openSslWindowsBinary();
|
2015-04-20 17:51:22 +00:00
|
|
|
#else
|
2024-07-02 19:07:06 +00:00
|
|
|
program = kUnixOpenSslCommand;
|
2015-04-20 17:51:22 +00:00
|
|
|
#endif
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
QStringList environment;
|
2015-04-20 17:51:22 +00:00
|
|
|
#if defined(Q_OS_WIN)
|
2024-07-22 16:48:02 +00:00
|
|
|
auto openSslDir = QDir(openSslWindowsDir());
|
|
|
|
|
auto config = QDir::cleanPath(openSslDir.filePath(kConfigFile));
|
|
|
|
|
environment << QString("OPENSSL_CONF=%1").arg(config);
|
2015-04-20 17:51:22 +00:00
|
|
|
#endif
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
QProcess process;
|
|
|
|
|
process.setEnvironment(environment);
|
|
|
|
|
process.start(program, args);
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
bool success = process.waitForStarted();
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
QString standardError;
|
|
|
|
|
if (success && process.waitForFinished()) {
|
|
|
|
|
m_ToolOutput = process.readAllStandardOutput().trimmed();
|
|
|
|
|
standardError = process.readAllStandardError().trimmed();
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-22 16:48:02 +00:00
|
|
|
if (int code = process.exitCode(); !success || code != 0) {
|
2024-07-02 19:07:06 +00:00
|
|
|
emit error(QString("SSL tool failed: %1\n\nCode: %2\nError: %3")
|
|
|
|
|
.arg(program)
|
|
|
|
|
.arg(process.exitCode())
|
|
|
|
|
.arg(standardError.isEmpty() ? "Unknown" : standardError));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-08-02 12:11:47 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
return true;
|
2015-04-21 11:55:45 +00:00
|
|
|
}
|
2015-04-20 17:51:22 +00:00
|
|
|
|
2024-07-26 22:53:52 +00:00
|
|
|
void TlsCertificate::generateCertificate(
|
2024-07-16 13:36:44 +00:00
|
|
|
const QString &path, const QString &keyLength, bool forceGen) {
|
2024-07-02 19:07:06 +00:00
|
|
|
QString sslDirPath =
|
|
|
|
|
QString("%1%2%3").arg(m_ProfileDir).arg(QDir::separator()).arg(kSslDir);
|
2020-07-28 12:00:20 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
QString filename = QString("%1%2%3")
|
|
|
|
|
.arg(sslDirPath)
|
|
|
|
|
.arg(QDir::separator())
|
|
|
|
|
.arg(kCertificateFilename);
|
2015-04-20 17:51:22 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
QString keySize = kCertificateKeyLength + keyLength;
|
2015-04-20 17:51:22 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
const QString pathToUse = path.isEmpty() ? filename : path;
|
2016-09-30 16:31:55 +00:00
|
|
|
|
2024-07-22 16:48:02 +00:00
|
|
|
if (QFile file(pathToUse); !file.exists() || forceGen) {
|
2024-07-02 19:07:06 +00:00
|
|
|
QStringList arguments;
|
2016-09-30 16:31:55 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// self signed certificate
|
|
|
|
|
arguments.append("req");
|
|
|
|
|
arguments.append("-x509");
|
|
|
|
|
arguments.append("-nodes");
|
2015-04-20 17:51:22 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// valide duration
|
|
|
|
|
arguments.append("-days");
|
|
|
|
|
arguments.append(kCertificateLifetime);
|
2016-09-30 16:31:55 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// subject information
|
|
|
|
|
arguments.append("-subj");
|
2016-09-30 16:31:55 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
QString subInfo(kCertificateSubjectInfo);
|
|
|
|
|
arguments.append(subInfo);
|
2016-09-30 16:31:55 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// private key
|
|
|
|
|
arguments.append("-newkey");
|
|
|
|
|
arguments.append(keySize);
|
2016-09-30 16:31:55 +00:00
|
|
|
|
2024-07-22 16:48:02 +00:00
|
|
|
if (QDir sslDir(sslDirPath); !sslDir.exists()) {
|
2024-07-02 19:07:06 +00:00
|
|
|
sslDir.mkpath(".");
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2015-04-20 17:51:22 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// key output filename
|
|
|
|
|
arguments.append("-keyout");
|
|
|
|
|
arguments.append(pathToUse);
|
2015-04-20 17:51:22 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// certificate output filename
|
|
|
|
|
arguments.append("-out");
|
|
|
|
|
arguments.append(pathToUse);
|
2016-12-28 11:50:32 +00:00
|
|
|
|
|
|
|
|
if (!runTool(arguments)) {
|
2024-07-02 19:07:06 +00:00
|
|
|
return;
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
generateFingerprint(pathToUse);
|
|
|
|
|
emit info(tr("SSL certificate generated."));
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
emit generateFinished();
|
2015-04-20 17:51:22 +00:00
|
|
|
}
|
2020-07-28 12:00:20 +00:00
|
|
|
|
2024-07-26 22:53:52 +00:00
|
|
|
void TlsCertificate::generateFingerprint(const QString &certificateFilename) {
|
2024-07-02 19:07:06 +00:00
|
|
|
QStringList arguments;
|
|
|
|
|
arguments.append("x509");
|
|
|
|
|
arguments.append("-fingerprint");
|
|
|
|
|
arguments.append(kCertificateHashAlgorithm);
|
|
|
|
|
arguments.append("-noout");
|
|
|
|
|
arguments.append("-in");
|
|
|
|
|
arguments.append(certificateFilename);
|
|
|
|
|
|
|
|
|
|
if (!runTool(arguments)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// find the fingerprint from the tool output
|
2024-07-22 16:48:02 +00:00
|
|
|
auto i = m_ToolOutput.indexOf("=");
|
2024-07-02 19:07:06 +00:00
|
|
|
if (i != -1) {
|
|
|
|
|
i++;
|
|
|
|
|
QString fingerprint = m_ToolOutput.mid(i, m_ToolOutput.size() - i);
|
|
|
|
|
|
2024-07-26 22:53:52 +00:00
|
|
|
TlsFingerprint::local().trust(fingerprint, false);
|
2024-07-02 19:07:06 +00:00
|
|
|
emit info(tr("SSL fingerprint generated."));
|
|
|
|
|
} else {
|
|
|
|
|
emit error(tr("Failed to find SSL fingerprint."));
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-28 12:00:20 +00:00
|
|
|
|
2024-07-26 22:53:52 +00:00
|
|
|
QString TlsCertificate::getCertKeyLength(const QString &path) {
|
2020-07-28 12:00:20 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
QStringList arguments;
|
|
|
|
|
arguments.append("rsa");
|
|
|
|
|
arguments.append("-in");
|
|
|
|
|
arguments.append(path);
|
|
|
|
|
arguments.append("-text");
|
|
|
|
|
arguments.append("-noout");
|
|
|
|
|
|
|
|
|
|
if (!runTool(arguments)) {
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
const QString searchStart("Private-Key: (");
|
|
|
|
|
const QString searchEnd(" bit");
|
|
|
|
|
|
|
|
|
|
// Get the line that contains the key length from the output
|
|
|
|
|
const auto indexStart = m_ToolOutput.indexOf(searchStart);
|
|
|
|
|
const auto indexEnd = m_ToolOutput.indexOf(searchEnd, indexStart);
|
|
|
|
|
const auto start = indexStart + searchStart.length();
|
|
|
|
|
const auto end = indexEnd - (indexStart + searchStart.length());
|
|
|
|
|
auto keyLength = m_ToolOutput.mid(start, end);
|
|
|
|
|
|
|
|
|
|
return keyLength;
|
2020-07-28 12:00:20 +00:00
|
|
|
}
|