add support for auto generated self-signed certificates for SSL encryption
This commit is contained in:
parent
2b4972de52
commit
66870dccfe
@ -233,6 +233,24 @@ QString GuhSettings::translationsPath()
|
|||||||
#endif // SNAPPY
|
#endif // SNAPPY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString GuhSettings::storagePath()
|
||||||
|
{
|
||||||
|
QString path;
|
||||||
|
#ifdef SNAPPY
|
||||||
|
path = QString(qgetenv("SNAP_DATA"));
|
||||||
|
#else
|
||||||
|
QString organisationName = QCoreApplication::instance()->organizationName();
|
||||||
|
if (organisationName == "guh-test") {
|
||||||
|
path = "/tmp/" + organisationName + "/";
|
||||||
|
} else if (GuhSettings::isRoot()) {
|
||||||
|
path = "/var/lib/" + organisationName + "/";
|
||||||
|
} else {
|
||||||
|
path = QDir::homePath() + "/.local/share/" + organisationName + "/";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Return a list of all settings keys.*/
|
/*! Return a list of all settings keys.*/
|
||||||
QStringList GuhSettings::allKeys() const
|
QStringList GuhSettings::allKeys() const
|
||||||
{
|
{
|
||||||
|
|||||||
@ -51,6 +51,7 @@ public:
|
|||||||
static QString logPath();
|
static QString logPath();
|
||||||
static QString settingsPath();
|
static QString settingsPath();
|
||||||
static QString translationsPath();
|
static QString translationsPath();
|
||||||
|
static QString storagePath();
|
||||||
|
|
||||||
// forwarded QSettings methods
|
// forwarded QSettings methods
|
||||||
QStringList allKeys() const;
|
QStringList allKeys() const;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ INSTALLS += target
|
|||||||
|
|
||||||
QT *= sql xml websockets bluetooth dbus
|
QT *= sql xml websockets bluetooth dbus
|
||||||
|
|
||||||
LIBS += -L$$top_builddir/libguh/ -lguh
|
LIBS += -L$$top_builddir/libguh/ -lguh -lssl -lcrypto
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
TRANSLATIONS *= $$top_srcdir/translations/guhd-en_US.ts \
|
TRANSLATIONS *= $$top_srcdir/translations/guhd-en_US.ts \
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "servermanager.h"
|
#include "servermanager.h"
|
||||||
#include "guhsettings.h"
|
#include "guhcore.h"
|
||||||
|
|
||||||
#include <QSslCertificate>
|
#include <QSslCertificate>
|
||||||
#include <QSslConfiguration>
|
#include <QSslConfiguration>
|
||||||
@ -47,23 +47,37 @@ ServerManager::ServerManager(GuhConfiguration* configuration, QObject *parent) :
|
|||||||
m_sslConfiguration(QSslConfiguration())
|
m_sslConfiguration(QSslConfiguration())
|
||||||
{
|
{
|
||||||
// check SSL
|
// check SSL
|
||||||
if (!QSslSocket::supportsSsl()) {
|
if (!configuration->sslEnabled()) {
|
||||||
|
qCDebug(dcConnection) << "SSL encryption disabled by config.";
|
||||||
|
} else if (!QSslSocket::supportsSsl()) {
|
||||||
qCWarning(dcConnection) << "SSL is not supported/installed on this platform.";
|
qCWarning(dcConnection) << "SSL is not supported/installed on this platform.";
|
||||||
} else {
|
} else {
|
||||||
qCDebug(dcConnection) << "SSL library version:" << QSslSocket::sslLibraryVersionString();
|
qCDebug(dcConnection) << "SSL library version:" << QSslSocket::sslLibraryVersionString();
|
||||||
|
|
||||||
// load SSL configuration settings
|
QString configCertificateFileName = configuration->sslCertificate();
|
||||||
GuhSettings settings(GuhSettings::SettingsRoleGlobal);
|
QString configKeyFileName = configuration->sslCertificateKey();
|
||||||
qCDebug(dcConnection) << "Loading SSL-configuration from" << settings.fileName();
|
|
||||||
|
|
||||||
settings.beginGroup("SSL");
|
QString fallbackCertificateFileName = GuhSettings::storagePath() + "/certs/guhd-certificate.crt";
|
||||||
QString certificateFileName = settings.value("certificate", QVariant("/etc/ssl/certs/guhd-certificate.crt")).toString();
|
QString fallbackKeyFileName = GuhSettings::storagePath() + "/certs/guhd-certificate.key";
|
||||||
QString keyFileName = settings.value("certificate-key", QVariant("/etc/ssl/private/guhd-certificate.key")).toString();
|
|
||||||
settings.endGroup();
|
|
||||||
|
|
||||||
if (!loadCertificate(keyFileName, certificateFileName)) {
|
bool certsLoaded = false;
|
||||||
qCWarning(dcConnection) << "SSL encryption disabled";
|
if (loadCertificate(configKeyFileName, configCertificateFileName)) {
|
||||||
|
qCDebug(dcConnection) << "Using SSL certificate:" << configKeyFileName;
|
||||||
|
certsLoaded = true;
|
||||||
|
} else if (loadCertificate(fallbackKeyFileName, fallbackCertificateFileName)) {
|
||||||
|
certsLoaded = true;
|
||||||
|
qCWarning(dcConnection) << "Using fallback self-signed SSL certificate:" << fallbackCertificateFileName;
|
||||||
} else {
|
} else {
|
||||||
|
qCDebug(dcConnection) << "Generating self signed certificates...";
|
||||||
|
CertificateGenerator::generate(fallbackCertificateFileName, fallbackKeyFileName);
|
||||||
|
if (loadCertificate(fallbackKeyFileName, fallbackCertificateFileName)) {
|
||||||
|
qCWarning(dcConnection) << "Using newly created self-signed SSL certificate:" << fallbackCertificateFileName;
|
||||||
|
certsLoaded = true;
|
||||||
|
} else {
|
||||||
|
qCWarning(dcConnection) << "Failed to load SSL certificates. SSL encryption disabled.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (certsLoaded) {
|
||||||
m_sslConfiguration.setProtocol(QSsl::TlsV1_2);
|
m_sslConfiguration.setProtocol(QSsl::TlsV1_2);
|
||||||
m_sslConfiguration.setPrivateKey(m_certificateKey);
|
m_sslConfiguration.setPrivateKey(m_certificateKey);
|
||||||
m_sslConfiguration.setLocalCertificate(m_certificate);
|
m_sslConfiguration.setLocalCertificate(m_certificate);
|
||||||
@ -137,20 +151,20 @@ bool ServerManager::loadCertificate(const QString &certificateKeyFileName, const
|
|||||||
{
|
{
|
||||||
QFile certificateKeyFile(certificateKeyFileName);
|
QFile certificateKeyFile(certificateKeyFileName);
|
||||||
if (!certificateKeyFile.open(QIODevice::ReadOnly)) {
|
if (!certificateKeyFile.open(QIODevice::ReadOnly)) {
|
||||||
qCWarning(dcWebServer) << "Could not open" << certificateKeyFile.fileName() << ":" << certificateKeyFile.errorString();
|
qCWarning(dcConnection) << "Could not open" << certificateKeyFile.fileName() << ":" << certificateKeyFile.errorString();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_certificateKey = QSslKey(certificateKeyFile.readAll(), QSsl::Rsa);
|
m_certificateKey = QSslKey(certificateKeyFile.readAll(), QSsl::Rsa);
|
||||||
qCDebug(dcWebServer) << "Loaded successfully private certificate key " << certificateKeyFileName;
|
qCDebug(dcConnection) << "Loaded private certificate key " << certificateKeyFileName;
|
||||||
certificateKeyFile.close();
|
certificateKeyFile.close();
|
||||||
|
|
||||||
QFile certificateFile(certificateFileName);
|
QFile certificateFile(certificateFileName);
|
||||||
if (!certificateFile.open(QIODevice::ReadOnly)) {
|
if (!certificateFile.open(QIODevice::ReadOnly)) {
|
||||||
qCWarning(dcWebServer) << "Could not open" << certificateFile.fileName() << ":" << certificateFile.errorString();
|
qCWarning(dcConnection) << "Could not open" << certificateFile.fileName() << ":" << certificateFile.errorString();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_certificate = QSslCertificate(certificateFile.readAll());
|
m_certificate = QSslCertificate(certificateFile.readAll());
|
||||||
qCDebug(dcWebServer) << "Loaded successfully certificate file " << certificateFileName;
|
qCDebug(dcConnection) << "Loaded certificate file " << certificateFileName;
|
||||||
certificateFile.close();
|
certificateFile.close();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -35,6 +35,8 @@
|
|||||||
#include "mocktcpserver.h"
|
#include "mocktcpserver.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "openssl/ssl.h"
|
||||||
|
|
||||||
class QSslConfiguration;
|
class QSslConfiguration;
|
||||||
class QSslCertificate;
|
class QSslCertificate;
|
||||||
class QSslKey;
|
class QSslKey;
|
||||||
@ -85,6 +87,81 @@ private:
|
|||||||
bool loadCertificate(const QString &certificateKeyFileName, const QString &certificateFileName);
|
bool loadCertificate(const QString &certificateKeyFileName, const QString &certificateFileName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CertificateGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void generate(const QString &certificateFilename, const QString &keyFilename) {
|
||||||
|
EVP_PKEY * pkey = nullptr;
|
||||||
|
RSA * rsa = nullptr;
|
||||||
|
X509 * x509 = nullptr;
|
||||||
|
X509_NAME * name = nullptr;
|
||||||
|
BIO * bp_public = nullptr, * bp_private = nullptr;
|
||||||
|
const char * buffer = nullptr;
|
||||||
|
long size;
|
||||||
|
|
||||||
|
pkey = EVP_PKEY_new();
|
||||||
|
q_check_ptr(pkey);
|
||||||
|
rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
|
||||||
|
q_check_ptr(rsa);
|
||||||
|
EVP_PKEY_assign_RSA(pkey, rsa);
|
||||||
|
x509 = X509_new();
|
||||||
|
q_check_ptr(x509);
|
||||||
|
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
|
||||||
|
X509_gmtime_adj(X509_get_notBefore(x509), 0); // not before current time
|
||||||
|
X509_gmtime_adj(X509_get_notAfter(x509), 31536000L); // not after a year from this point
|
||||||
|
X509_set_pubkey(x509, pkey);
|
||||||
|
name = X509_get_subject_name(x509);
|
||||||
|
q_check_ptr(name);
|
||||||
|
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"AT", -1, -1, 0);
|
||||||
|
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"Guh GmbH", -1, -1, 0);
|
||||||
|
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"guh core autocreated", -1, -1, 0);
|
||||||
|
X509_set_issuer_name(x509, name);
|
||||||
|
X509_sign(x509, pkey, EVP_sha1());
|
||||||
|
bp_private = BIO_new(BIO_s_mem());
|
||||||
|
q_check_ptr(bp_private);
|
||||||
|
if(PEM_write_bio_PrivateKey(bp_private, pkey, nullptr, nullptr, 0, nullptr, nullptr) != 1)
|
||||||
|
{
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
X509_free(x509);
|
||||||
|
BIO_free_all(bp_private);
|
||||||
|
qFatal("PEM_write_bio_PrivateKey");
|
||||||
|
}
|
||||||
|
bp_public = BIO_new(BIO_s_mem());
|
||||||
|
q_check_ptr(bp_public);
|
||||||
|
if(PEM_write_bio_X509(bp_public, x509) != 1)
|
||||||
|
{
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
X509_free(x509);
|
||||||
|
BIO_free_all(bp_public);
|
||||||
|
BIO_free_all(bp_private);
|
||||||
|
qFatal("PEM_write_bio_PrivateKey");
|
||||||
|
}
|
||||||
|
size = BIO_get_mem_data(bp_public, &buffer);
|
||||||
|
q_check_ptr(buffer);
|
||||||
|
QFileInfo certFi(certificateFilename);
|
||||||
|
QDir dir;
|
||||||
|
QFile certfile(certificateFilename);
|
||||||
|
if (!dir.mkpath(certFi.absolutePath()) || !certfile.open(QFile::WriteOnly | QFile::Truncate) || certfile.write(buffer, size) != size) {
|
||||||
|
qWarning() << "Error writing certificate file" << certificateFilename;
|
||||||
|
}
|
||||||
|
certfile.close();
|
||||||
|
|
||||||
|
size = BIO_get_mem_data(bp_private, &buffer);
|
||||||
|
q_check_ptr(buffer);
|
||||||
|
QFileInfo keyFi(keyFilename);
|
||||||
|
QFile keyFile(keyFilename);
|
||||||
|
if (!dir.mkpath(keyFi.absolutePath()) || !keyFile.open(QFile::WriteOnly | QFile::Truncate) || keyFile.write(buffer, size) != size) {
|
||||||
|
qWarning() << "Error writing key file" << keyFilename;
|
||||||
|
}
|
||||||
|
keyFile.close();
|
||||||
|
|
||||||
|
EVP_PKEY_free(pkey); // this will also free the rsa key
|
||||||
|
X509_free(x509);
|
||||||
|
BIO_free_all(bp_public);
|
||||||
|
BIO_free_all(bp_private);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SERVERMANAGER_H
|
#endif // SERVERMANAGER_H
|
||||||
|
|||||||
@ -9,7 +9,7 @@ INCLUDEPATH += $$top_srcdir/server/ \
|
|||||||
$$top_srcdir/tests/auto/
|
$$top_srcdir/tests/auto/
|
||||||
|
|
||||||
LIBS += -L$$top_builddir/libguh/ -lguh -L$$top_builddir/plugins/mock/ \
|
LIBS += -L$$top_builddir/libguh/ -lguh -L$$top_builddir/plugins/mock/ \
|
||||||
-L$$top_builddir/tests/libguh-core/ -lguh-core
|
-L$$top_builddir/tests/libguh-core/ -lguh-core -lssl -lcrypto
|
||||||
|
|
||||||
SOURCES += ../guhtestbase.cpp \
|
SOURCES += ../guhtestbase.cpp \
|
||||||
../mocktcpserver.cpp \
|
../mocktcpserver.cpp \
|
||||||
|
|||||||
@ -13,7 +13,7 @@ INCLUDEPATH += $$top_srcdir/server/ \
|
|||||||
$$top_srcdir/libguh \
|
$$top_srcdir/libguh \
|
||||||
$$top_srcdir/tests/auto/
|
$$top_srcdir/tests/auto/
|
||||||
|
|
||||||
LIBS += -L$$top_builddir/libguh/ -lguh
|
LIBS += -L$$top_builddir/libguh/ -lguh -lssl -lcrypto
|
||||||
|
|
||||||
target.path = /usr/lib/$$system('dpkg-architecture -q DEB_HOST_MULTIARCH')
|
target.path = /usr/lib/$$system('dpkg-architecture -q DEB_HOST_MULTIARCH')
|
||||||
INSTALLS += target
|
INSTALLS += target
|
||||||
|
|||||||
Reference in New Issue
Block a user