AusweisApp2/src/remote_device/RemoteTlsServer.cpp

198 lines
5.6 KiB
C++

/*!
* \copyright Copyright (c) 2017-2019 Governikus GmbH & Co. KG, Germany
*/
#include "RemoteTlsServer.h"
#include "AppSettings.h"
#include "LogHandler.h"
#include "Randomizer.h"
#include "SecureStorage.h"
#include "TlsChecker.h"
#include <QHostAddress>
#include <QLoggingCategory>
#include <QNetworkProxy>
#include <QSharedPointer>
Q_DECLARE_LOGGING_CATEGORY(remote_device)
using namespace governikus;
RemoteTlsServer::RemoteTlsServer()
: QTcpServer()
, mPsk()
{
#ifndef QT_NO_NETWORKPROXY
//listening with proxy leads to socket error QNativeSocketEnginePrivate::InvalidProxyTypeString
setProxy(QNetworkProxy(QNetworkProxy::NoProxy));
#endif
}
bool RemoteTlsServer::listen()
{
if (isListening())
{
return false;
}
auto& remoteServiceSettings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
const bool invalidLength = !TlsChecker::hasValidCertificateKeyLength(remoteServiceSettings.getCertificate());
if (!remoteServiceSettings.checkAndGenerateKey(invalidLength))
{
qCCritical(remote_device) << "Cannot get required key/certificate for tls";
return false;
}
static quint16 usedServerPort = 0;
if (!QTcpServer::listen(QHostAddress::Any, usedServerPort))
{
qCCritical(remote_device) << "Listen failed:" << serverError() << ", " << errorString();
return false;
}
if (usedServerPort == 0)
{
usedServerPort = serverPort();
}
return true;
}
void RemoteTlsServer::incomingConnection(qintptr pSocketDescriptor)
{
if (mSocket.isNull())
{
mSocket = new QSslSocket();
const auto cipherCfg = mPsk.isEmpty() ? SecureStorage::TlsSuite::DEFAULT : SecureStorage::TlsSuite::PSK;
QSslConfiguration config = Env::getSingleton<SecureStorage>()->getTlsConfigRemote(cipherCfg).getConfiguration();
const auto& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
config.setPrivateKey(settings.getKey());
config.setLocalCertificate(settings.getCertificate());
config.setPeerVerifyMode(QSslSocket::VerifyPeer);
if (mPsk.isEmpty())
{
config.setCaCertificates(settings.getTrustedCertificates());
}
mSocket->setSslConfiguration(config);
if (Q_LIKELY(mSocket->setSocketDescriptor(pSocketDescriptor)))
{
connect(mSocket.data(), QOverload<const QList<QSslError>&>::of(&QSslSocket::sslErrors),
this, &RemoteTlsServer::onSslErrors);
connect(mSocket.data(), QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
this, &RemoteTlsServer::onError);
connect(mSocket.data(), &QSslSocket::preSharedKeyAuthenticationRequired,
this, &RemoteTlsServer::onPreSharedKeyAuthenticationRequired);
connect(mSocket.data(), &QSslSocket::encrypted, this, &RemoteTlsServer::onEncrypted);
mSocket->startServerEncryption();
}
else
{
delete mSocket.data();
}
}
else
{
QTcpSocket socket;
socket.setSocketDescriptor(pSocketDescriptor);
socket.abort();
qCDebug(remote_device) << "Socket already connected...";
}
}
void RemoteTlsServer::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator)
{
qCDebug(remote_device) << "Client requests pairing | identity:" << pAuthenticator->identity() << "| hint:" << pAuthenticator->identityHint();
pAuthenticator->setPreSharedKey(mPsk);
}
void RemoteTlsServer::onError(QAbstractSocket::SocketError pSocketError)
{
qCDebug(remote_device) << "Socket error:" << pSocketError;
mSocket->deleteLater();
}
void RemoteTlsServer::onSslErrors(const QList<QSslError>& pErrors)
{
if (pErrors.size() == 1 && pErrors.first().error() == QSslError::SelfSignedCertificate)
{
const auto& pairingCiphers = Env::getSingleton<SecureStorage>()->getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getCiphers();
if (pairingCiphers.contains(mSocket->sessionCipher()))
{
qCDebug(remote_device) << "Client requests pairing | cipher:" << mSocket->sessionCipher() << "| certificate:" << mSocket->peerCertificate();
mSocket->ignoreSslErrors();
return;
}
}
qCDebug(remote_device) << "Client is not allowed | cipher:" << mSocket->sessionCipher() << "| certificate:" << mSocket->peerCertificate() << "| error:" << pErrors;
}
void RemoteTlsServer::onEncrypted()
{
const auto& cfg = mSocket->sslConfiguration();
TlsChecker::logSslConfig(cfg, spawnMessageLogger(remote_device));
if (!TlsChecker::hasValidCertificateKeyLength(cfg.peerCertificate()))
{
qCCritical(remote_device) << "Client denied... abort connection!";
mSocket->abort();
mSocket->deleteLater();
return;
}
qCDebug(remote_device) << "Client connected";
auto& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
const auto& pairingCiphers = Env::getSingleton<SecureStorage>()->getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getCiphers();
if (pairingCiphers.contains(cfg.sessionCipher()))
{
qCDebug(remote_device) << "Pairing completed | Add certificate:" << cfg.peerCertificate();
settings.addTrustedCertificate(cfg.peerCertificate());
settings.save();
setPairing(false);
}
else
{
auto info = settings.getRemoteInfo(cfg.peerCertificate());
info.setLastConnected(QDateTime::currentDateTime());
settings.updateRemoteInfo(info);
}
mSocket->disconnect(this);
Q_EMIT newConnection(mSocket.data());
}
void RemoteTlsServer::setPairing(bool pEnable)
{
if (pEnable)
{
std::uniform_int_distribution<int> uni(0, 9999);
QByteArray pin = QByteArray::number(uni(Randomizer::getInstance().getGenerator()));
pin.prepend(4 - pin.size(), '0');
mPsk = pin;
Q_EMIT firePskChanged(mPsk);
}
else if (!mPsk.isEmpty())
{
mPsk.clear();
Q_EMIT firePskChanged(mPsk);
}
}
QSslCertificate RemoteTlsServer::getCurrentCertificate() const
{
return mSocket ? mSocket->sslConfiguration().peerCertificate() : QSslCertificate();
}