add support for auto generated self-signed certificates for SSL encryption

This commit is contained in:
Michael Zanetti 2017-08-02 23:50:19 +02:00
parent 2b4972de52
commit 66870dccfe
7 changed files with 128 additions and 18 deletions

View File

@ -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
{ {

View File

@ -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;

View File

@ -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 \

View File

@ -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;

View File

@ -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

View File

@ -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 \

View File

@ -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