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

pull/135/head
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
}
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.*/
QStringList GuhSettings::allKeys() const
{

View File

@ -51,6 +51,7 @@ public:
static QString logPath();
static QString settingsPath();
static QString translationsPath();
static QString storagePath();
// forwarded QSettings methods
QStringList allKeys() const;

View File

@ -10,7 +10,7 @@ INSTALLS += target
QT *= sql xml websockets bluetooth dbus
LIBS += -L$$top_builddir/libguh/ -lguh
LIBS += -L$$top_builddir/libguh/ -lguh -lssl -lcrypto
# Translations
TRANSLATIONS *= $$top_srcdir/translations/guhd-en_US.ts \

View File

@ -33,7 +33,7 @@
*/
#include "servermanager.h"
#include "guhsettings.h"
#include "guhcore.h"
#include <QSslCertificate>
#include <QSslConfiguration>
@ -47,23 +47,37 @@ ServerManager::ServerManager(GuhConfiguration* configuration, QObject *parent) :
m_sslConfiguration(QSslConfiguration())
{
// 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.";
} else {
qCDebug(dcConnection) << "SSL library version:" << QSslSocket::sslLibraryVersionString();
// load SSL configuration settings
GuhSettings settings(GuhSettings::SettingsRoleGlobal);
qCDebug(dcConnection) << "Loading SSL-configuration from" << settings.fileName();
QString configCertificateFileName = configuration->sslCertificate();
QString configKeyFileName = configuration->sslCertificateKey();
settings.beginGroup("SSL");
QString certificateFileName = settings.value("certificate", QVariant("/etc/ssl/certs/guhd-certificate.crt")).toString();
QString keyFileName = settings.value("certificate-key", QVariant("/etc/ssl/private/guhd-certificate.key")).toString();
settings.endGroup();
QString fallbackCertificateFileName = GuhSettings::storagePath() + "/certs/guhd-certificate.crt";
QString fallbackKeyFileName = GuhSettings::storagePath() + "/certs/guhd-certificate.key";
if (!loadCertificate(keyFileName, certificateFileName)) {
qCWarning(dcConnection) << "SSL encryption disabled";
bool certsLoaded = false;
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 {
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.setPrivateKey(m_certificateKey);
m_sslConfiguration.setLocalCertificate(m_certificate);
@ -137,20 +151,20 @@ bool ServerManager::loadCertificate(const QString &certificateKeyFileName, const
{
QFile certificateKeyFile(certificateKeyFileName);
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;
}
m_certificateKey = QSslKey(certificateKeyFile.readAll(), QSsl::Rsa);
qCDebug(dcWebServer) << "Loaded successfully private certificate key " << certificateKeyFileName;
qCDebug(dcConnection) << "Loaded private certificate key " << certificateKeyFileName;
certificateKeyFile.close();
QFile certificateFile(certificateFileName);
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;
}
m_certificate = QSslCertificate(certificateFile.readAll());
qCDebug(dcWebServer) << "Loaded successfully certificate file " << certificateFileName;
qCDebug(dcConnection) << "Loaded certificate file " << certificateFileName;
certificateFile.close();
return true;

View File

@ -35,6 +35,8 @@
#include "mocktcpserver.h"
#endif
#include "openssl/ssl.h"
class QSslConfiguration;
class QSslCertificate;
class QSslKey;
@ -85,6 +87,81 @@ private:
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

View File

@ -9,7 +9,7 @@ INCLUDEPATH += $$top_srcdir/server/ \
$$top_srcdir/tests/auto/
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 \
../mocktcpserver.cpp \

View File

@ -13,7 +13,7 @@ INCLUDEPATH += $$top_srcdir/server/ \
$$top_srcdir/libguh \
$$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')
INSTALLS += target