mirror of https://github.com/nymea/nymea.git
add support for auto generated self-signed certificates for SSL encryption
parent
2b4972de52
commit
66870dccfe
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ public:
|
|||
static QString logPath();
|
||||
static QString settingsPath();
|
||||
static QString translationsPath();
|
||||
static QString storagePath();
|
||||
|
||||
// forwarded QSettings methods
|
||||
QStringList allKeys() const;
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue