dbhub: Add basic HTTPS support

This adds basic support for fetching databases via HTTPS using client
certificates. You can include CA certificates to verify any responses
from a server. For now, one test CA certificate is included but it's
easy to add more.

It's also possible to authentify the client using a client certificate,
a client key and a password. As of this commit all three items are
hardcoded.

It's still possible to access any remote database via HTTP but if a
request URL starts with 'https' this new mechanism will be used.

All certificates, keys, and password included in here are taken from my
node.js test server repository. They will be replaced soon-ish.
This commit is contained in:
Martin Kleusberg
2016-10-25 20:42:31 +02:00
parent fad7246400
commit c2a9608c80
9 changed files with 195 additions and 5 deletions
+1
View File
@@ -158,6 +158,7 @@ set(SQLB_RESOURCES
src/icons/icons.qrc
src/translations/flags/flags.qrc
src/translations/translations.qrc
src/certs/CaCerts.qrc
)
set(SQLB_MISC
+3
View File
@@ -1692,6 +1692,9 @@ void MainWindow::reloadSettings()
// Hide or show the File → Remote menu as needed
QAction *remoteMenuAction = ui->menuRemote->menuAction();
remoteMenuAction->setVisible(Settings::getSettingsValue("MainWindow", "remotemenu").toBool());
// Update the remote database connection settings
m_remoteDb.reloadSettings();
}
void MainWindow::httpresponse(QNetworkReply *reply)
+65 -4
View File
@@ -3,6 +3,7 @@
#include <QMessageBox>
#include <QNetworkReply>
#include <QFile>
#include <QSslKey>
#include "RemoteDatabase.h"
#include "version.h"
@@ -12,7 +13,8 @@ RemoteDatabase::RemoteDatabase() :
m_manager(new QNetworkAccessManager),
m_currentReply(nullptr)
{
// TODO Set up SSL configuration here
// Load settings and set up some more stuff while doing so
reloadSettings();
// TODO Add support for proxies here
@@ -27,6 +29,40 @@ RemoteDatabase::~RemoteDatabase()
delete m_manager;
}
void RemoteDatabase::reloadSettings()
{
// Set up SSL configuration
m_sslConfiguration = QSslConfiguration::defaultConfiguration();
m_sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer);
// Load CA certs from resource file
QDir dirCaCerts(":/certs");
QStringList caCertsList = dirCaCerts.entryList();
QList<QSslCertificate> caCerts;
foreach(const QString& caCertName, caCertsList)
{
QFile fileCaCert(":/certs/" + caCertName);
fileCaCert.open(QFile::ReadOnly);
caCerts.push_back(QSslCertificate(&fileCaCert));
fileCaCert.close();
}
m_sslConfiguration.setCaCertificates(caCerts);
// Load client cert
QFile fileClientCert("client.crt");
fileClientCert.open(QFile::ReadOnly);
QSslCertificate clientCert(&fileClientCert);
fileClientCert.close();
m_sslConfiguration.setLocalCertificate(clientCert);
// Load private key
QFile fileClientKey("client.key");
fileClientKey.open(QFile::ReadOnly);
QSslKey clientKey(&fileClientKey, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, "password");
fileClientKey.close();
m_sslConfiguration.setPrivateKey(clientKey);
}
void RemoteDatabase::fetchDatabase(const QString& url)
{
// Check if network is accessible. If not, abort right here
@@ -41,7 +77,10 @@ void RemoteDatabase::fetchDatabase(const QString& url)
request.setUrl(url);
request.setRawHeader("User-Agent", QString("%1 %2").arg(qApp->organizationName()).arg(APP_VERSION).toUtf8());
// TODO Set SSL configuration here
// Set SSL configuration when trying to access a file via the HTTPS protocol
bool https = QUrl(url).scheme().compare("https", Qt::CaseInsensitive) == 0;
if(https)
request.setSslConfiguration(m_sslConfiguration);
// Fetch database and save pending reply. Note that we're only supporting one active download here at the moment.
m_currentReply = m_manager->get(request);
@@ -55,9 +94,12 @@ void RemoteDatabase::fetchDatabase(const QString& url)
connect(m_currentReply, &QNetworkReply::downloadProgress, this, &RemoteDatabase::updateProgress);
}
void RemoteDatabase::gotEncrypted(QNetworkReply* /*reply*/)
void RemoteDatabase::gotEncrypted(QNetworkReply* reply)
{
// TODO Check SSL configuration here and abort reply if it's not good
// Verify the server's certificate using our CA certs. If it's not good, abort the reply here
auto verificationErrors = reply->sslConfiguration().peerCertificate().verify(m_sslConfiguration.caCertificates());
if(!(verificationErrors.size() == 0 || (verificationErrors.size() == 1 && verificationErrors.at(0).error() == QSslError::SelfSignedCertificate)))
reply->abort();
}
void RemoteDatabase::gotReply(QNetworkReply* reply)
@@ -93,6 +135,25 @@ void RemoteDatabase::gotReply(QNetworkReply* reply)
void RemoteDatabase::gotError(QNetworkReply* reply, const QList<QSslError>& errors)
{
// Are there any errors in here that aren't about self-signed certificates and non-matching hostnames?
// TODO What about the hostname mismatch? Can we remove that from the list of ignored errors later?
bool serious_errors = false;
foreach(const QSslError& error, errors)
{
if(error.error() != QSslError::SelfSignedCertificate && error.error() != QSslError::HostNameMismatch)
{
serious_errors = true;
break;
}
}
// Just stop the error checking here and accept the reply if there were no 'serious' errors
if(!serious_errors)
{
reply->ignoreSslErrors(errors);
return;
}
// Build an error message and short it to the user
QString message = tr("Error opening remote database file from %1.\n%2").arg(reply->url().toString()).arg(errors.at(0).errorString());
QMessageBox::warning(0, qApp->applicationName(), message);
+4
View File
@@ -3,6 +3,7 @@
#include <QObject>
#include <QProgressDialog>
#include <QSslConfiguration>
class QNetworkAccessManager;
class QString;
@@ -17,6 +18,8 @@ public:
RemoteDatabase();
virtual ~RemoteDatabase();
void reloadSettings();
void fetchDatabase(const QString& url);
signals:
@@ -31,6 +34,7 @@ private:
QNetworkAccessManager* m_manager;
QProgressDialog m_progress;
QNetworkReply* m_currentReply;
QSslConfiguration m_sslConfiguration;
};
#endif
+5
View File
@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/certs">
<file>mlnt.crt</file>
</qresource>
</RCC>
+31
View File
@@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFXTCCA0WgAwIBAgIJAJYKIz1dqTZBMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTYxMDE3MTMyOTIwWhcNMTcxMDE3MTMyOTIwWjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
CgKCAgEAx/sltVmjQ6YxsnCLK2CQYtGuD4/EsKmePYMaUwCZEHhIdAF2E8cBaMa7
hJFehrQiITsFb74ZQih6d97OO0MzIf8Ox+IN5GZMBtunoqHrQu6zgBrCaJT8/BBX
xJIESl9tGQ3UhsZWW6DL5ds6Fl6N/OUtT8j+TIfi+mtCgYT9eF7Qj9eV+HggSXHy
fqw37UGDodNbphk/MLQwX447keq7qJIDNQq65O6LGNrGae5c3Z4daLHHj5tYOX7a
Kd/7Tnv8sX3nUQArJfOpPgmmGQnrt8oDSjAEP4INa63AVUrsz9FIbtJ+ULgTyqW5
Ud6orUZ9XMuaFXzVlgKRF/PjTiN9PmKByDz08MaUa4y2xMw7Nr2aSnEHObbBRq9k
slnFjlFFVd0jiysg/uUtGkmitOhzMoO5fjEXiPxLI9cweafRJFfqAauHKZ12swAQ
+a/Caws/9WU7lYElW2oxav2+P71BecwpmcRr5KcPYgM2lhNJDdQEy91Z8cr0m/aQ
glIyxs6CAXPPZlJwSknwP94eg3nXvA7Xr2xPBpPL9CC/08T9wJiZCopAaCnoGYyg
x2RdSKvRBESgLvh5FBhLQUYyKGuRwfIKoe3Use+mlaYFZMFPqxR2H9GdI/oeEOoe
zFUBgcP/HGu9/0SJAmFpgEKqTGoCabfrB2VFJV2BZV2vsO8mCWUCAwEAAaNQME4w
HQYDVR0OBBYEFMwuK3aJWDr4sRawyaexyzYPUaKKMB8GA1UdIwQYMBaAFMwuK3aJ
WDr4sRawyaexyzYPUaKKMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB
AI4REr1jWlSHkNWDyRjuyKNc2jrAD+IhaI54pfB1lNwXVN4drgOU8d1k5d11Gqxd
Gaht8iwlKBCa2hiNX52585F6DsrhW8lXpc2pwLigbmle/+uf3jJ+6sa7DVzPiJI8
wToGDxwKZ4qKNW0Z12Kvgt0rJtLcmmrk+91A8AicT3cBe6WLa9opcAXjcx9+QRvA
qs/Wc9krAPmm/G58gmNI5KitdZpPcSkqx9sPsTV9d5CYgUNuY2f6P1RA+1q8LU6i
tBDehpHtrHfXZCGSUv9HlaEwdVFU6L7CTZg8OMbg+d2Eo/nJQwf9ofvk8MUf4bMG
u44hBHfLGo77v7T9v++dSgN3BcydxNt+28bY69v8Lh43SIbuFs1neE9Bx3LwbLw8
ry9lxHFUVah0fyUEA+gxM5GqmtKUcm9CSFkL6lkpYYhz/87z9hyBysQ8icVJclBu
EAXbus9xMcNjOCACJDNoLWOT9WI2sW5X3LXBl7GB4XuyTV5Dx3SvA8liA7KLun2z
v1jBiHIoQ5aiYW4bPqZ+G8oRMnrc7jU5jhpFq0CIbJ5f4bnB44JSRn/gqU9uSK5Y
9QOX+TA1BUBvUy9DuUgioDr+09IHLOXygVPTNfYVD2ozZCDLAtPFLE57NqcOceqG
I6bkjp+skDgkgJKWsbiB7ba03c9sD091b+k+tBSDHtJU
-----END CERTIFICATE-----
+30
View File
@@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFFTCCAv0CAQEwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV
BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
ZDAeFw0xNjEwMTcxNDU4NTNaFw0xNzEwMTcxNDU4NTNaMFwxCzAJBgNVBAYTAkFV
MRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRz
IFB0eSBMdGQxFTATBgNVBAMMDFRlc3QgY2VydCAjMTCCAiIwDQYJKoZIhvcNAQEB
BQADggIPADCCAgoCggIBALU9e88zfZ52lZZXK4PpNEitP9xOf3o7prZsFnRLTGqT
HUB69ZKeJcXrEoMi6Etl6Uek9Q246J2VKNfrORxMoCaukBh4WE2aj9YPFSdQPjEs
y9+YM3wbGIFfeuhAMuoNWm+opulfDEbYoZkPGIN0ouos9BYdjygkZoPBauGcWOky
PO7Peh5gMyuq23idtiHuLxtbh4K8WGNAgUQBrL5jRrZcblTBErH+G6XoQqvX4SF/
TyPqMiD+aj8oVVLBLhWN9C5qYeMltj8CIno8ko1P8PP5KH1rsUaj3UeisGh1rJPw
Tvss9LeEwgcoZcIV2aeRrqHn/XX9VgzCVzIcOMcCUqc9LHsamJjqCs1c0s+ZsHgm
NlR/xzEQNf817fNOBhpDO+ujf2z/qHmubL3pQVQyo+pmDJm7EZ4BcuwG8CnulptR
yJZTWio8pOC9J/R8dci3cyrVLoxgayQdENFrqoKBkRVWGwKbu1OfRAo4hTSjSCIS
UqfAib0Qj/YZrM7flH3U3S1+FXoLjcch1S/btvxVaXG7DhsoH/X3ql7Mnjw0tXJp
Fjlqlf9uD12FJH8Bc3OiSnJnE0sH3VGrW5Zb53SuCKM+r18WrtzWyv9k9EE0gICo
uCwL4AVmSAdU1C8pEymW0RBVqzAEvuEE0ZkhxCXm8ZJBgcuATj0KAjj4r7OMdb+Z
AgMBAAEwDQYJKoZIhvcNAQELBQADggIBAEmM9OAIhUsqk/EI3x4qPDRq16VAARnA
bYebzQ44z4eGgOSIbLGXn+aLCwgYjpsjFCeDjKmy1SRWNFuUCT3afcQGkHXM9g4n
qAVWSEnCDSSwghdPJokPw3peUNzb/cx46kqz7gAUpTW1q3rMAxvTF4igPBsls9fQ
JM1U6daHi8EYl2NXWE4BDQMEDeq92pzEI9rFxka0l7ZkjbZETtz9BktvpSGGhQmx
KryO0g4+4WoJO4RmXY087rWZD3B9cZGJI363legq7TC1qr69076i+cd0q1qQnj73
E05KBtgfHQJtEL3+pQwYU4XU210FoJ/uFA8crE2LgHcPjb6NwZchyNETjXeqm9mv
7U9hGQC8Cq9rllwFtJ4Y2XU6iXYIXcK0Z6Qk82fkAgegDejmft8XqObOyS+pr6Zu
JlhOjUSxr6D/TJOkxp1DtfTFqrvtq0iFMtsagGl7weLlfv0t0QXy1vbVNFvaWfgC
qejq/JrHzsjbamuKAjpmoFv34MwGDt05GVVx7+Qavk/bo/jYXyBlWJpV8GJN9vMi
0Zg3RyX05s2KJWX4PQs2ZncYAKOIZEhKT3LuhqE+eak+++GPt1ul/yNeEDGUIzQW
6B1/tAaQZhoY2plZ1grrnyFr9BhOXLylL/X/Rr2Pw1huexa/K/Gbp+w2rr/3/zop
ZoUymJ60DOFt
-----END CERTIFICATE-----
+54
View File
@@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,FAC500C30C704082
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
-----END RSA PRIVATE KEY-----
+2 -1
View File
@@ -87,7 +87,8 @@ SOURCES += \
RESOURCES += icons/icons.qrc \
translations/flags/flags.qrc \
translations/translations.qrc
translations/translations.qrc \
certs/CaCerts.qrc
FORMS += \
MainWindow.ui \