/*! * \copyright Copyright (c) 2017-2018 Governikus GmbH & Co. KG, Germany */ #include "RemoteTlsServer.h" #include "AppSettings.h" #include "Env.h" #include "Randomizer.h" #include "RemoteHelper.h" #include "SecureStorage.h" #include "TlsChecker.h" #include #include #include #include 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; } if (!RemoteHelper::checkAndGenerateKey()) { 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 = SecureStorage::getInstance().getTlsConfigRemote(cipherCfg).getConfiguration(); const auto& settings = Env::getSingleton()->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&>::of(&QSslSocket::sslErrors), this, &RemoteTlsServer::onSslErrors); connect(mSocket.data(), QOverload::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& pErrors) { if (pErrors.size() == 1 && pErrors.first().error() == QSslError::SelfSignedCertificate) { const auto& pairingCiphers = SecureStorage::getInstance().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, qInfo(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()->getRemoteServiceSettings(); const auto& pairingCiphers = SecureStorage::getInstance().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 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(); }