diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,11 +15,8 @@ set(QT_MIN_VERSION "5.6.0") set(KF5_REQUIRED_COMPONENTS I18n DBusAddons CoreAddons IconThemes Config) set(KF5_OPTIONAL_COMPONENTS) - set(QCA_MIN_VERSION 2.0.0) pkg_search_module(SFOS REQUIRED sailfishapp) - pkg_check_modules(QCA2 qca2-qt5>=${QCA_MIN_VERSION} REQUIRED) add_definitions(-DSAILFISHOS) - include_directories(${QCA2_INCLUDEDIR}) add_definitions(-DQT_NO_URL_CAST_FROM_STRING) else() set(KF5_MIN_VERSION "5.42.0") @@ -29,8 +26,6 @@ if(UNIX) set(KF5_OPTIONAL_COMPONENTS ${KF5_OPTIONAL_COMPONENTS} PulseAudioQt) endif() - set(QCA_MIN_VERSION "2.1.0") - find_package(Qca-qt5 ${QCA_MIN_VERSION} REQUIRED) add_definitions(-DQT_NO_URL_CAST_FROM_STRING -DQT_NO_KEYWORDS) endif() diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -42,7 +42,6 @@ Qt5::Network KF5::CoreAddons KF5::KIOCore - qca-qt5 PRIVATE Qt5::DBus Qt5::Gui diff --git a/core/backends/devicelink.h b/core/backends/devicelink.h --- a/core/backends/devicelink.h +++ b/core/backends/devicelink.h @@ -22,8 +22,6 @@ #define DEVICELINK_H #include -#include //Fix build on older QCA -#include #include "core/networkpacket.h" diff --git a/core/kdeconnectconfig.h b/core/kdeconnectconfig.h --- a/core/kdeconnectconfig.h +++ b/core/kdeconnectconfig.h @@ -73,13 +73,9 @@ private: KdeConnectConfig(); - void loadPrivateKey(); void loadCertificate(); struct KdeConnectConfigPrivate* d; - - const QFile::Permissions strict = QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::WriteUser; - }; #endif diff --git a/core/kdeconnectconfig.cpp b/core/kdeconnectconfig.cpp --- a/core/kdeconnectconfig.cpp +++ b/core/kdeconnectconfig.cpp @@ -32,20 +32,15 @@ #include #include #include -#include +#include #include "core_debug.h" #include "dbushelper.h" #include "daemon.h" struct KdeConnectConfigPrivate { - // The Initializer object sets things up, and also does cleanup when it goes out of scope - // Note it's not being used anywhere. That's intended - QCA::Initializer m_qcaInitializer; - - QCA::PrivateKey m_privateKey; - QSslCertificate m_certificate; // Use QSslCertificate instead of QCA::Certificate due to compatibility with QSslSocket + QSslCertificate m_certificate; QSettings* m_config; QSettings* m_trustedDevices; @@ -61,25 +56,13 @@ KdeConnectConfig::KdeConnectConfig() : d(new KdeConnectConfigPrivate) { - //qCDebug(KDECONNECT_CORE) << "QCA supported capabilities:" << QCA::supportedFeatures().join(","); - if(!QCA::isSupported("rsa")) { - qCritical() << "Could not find support for RSA in your QCA installation"; - Daemon::instance()->reportError( - i18n("KDE Connect failed to start"), - i18n("Could not find support for RSA in your QCA installation. If your " - "distribution provides separate packets for QCA-ossl and QCA-gnupg, " - "make sure you have them installed and try again.")); - return; - } - //Make sure base directory exists QDir().mkpath(baseConfigDir().path()); //.config/kdeconnect/config d->m_config = new QSettings(baseConfigDir().absoluteFilePath(QStringLiteral("config")), QSettings::IniFormat); d->m_trustedDevices = new QSettings(baseConfigDir().absoluteFilePath(QStringLiteral("trusted_devices")), QSettings::IniFormat); - loadPrivateKey(); loadCertificate(); } @@ -140,7 +123,6 @@ return list; } - void KdeConnectConfig::addTrustedDevice(const QString& id, const QString& name, const QString& type) { d->m_trustedDevices->beginGroup(id); @@ -189,7 +171,6 @@ return value; } - QDir KdeConnectConfig::deviceConfigDir(const QString& deviceId) { QString deviceConfigPath = baseConfigDir().absoluteFilePath(deviceId); @@ -203,71 +184,32 @@ return QDir(pluginConfigDir); } -void KdeConnectConfig::loadPrivateKey() -{ - QString keyPath = privateKeyPath(); - QFile privKey(keyPath); - if (privKey.exists() && privKey.open(QIODevice::ReadOnly)) { - - d->m_privateKey = QCA::PrivateKey::fromPEM(privKey.readAll()); - - } else { - - d->m_privateKey = QCA::KeyGenerator().createRSA(2048); - - if (!privKey.open(QIODevice::ReadWrite | QIODevice::Truncate)) { - Daemon::instance()->reportError(QStringLiteral("KDE Connect"), i18n("Could not store private key file: %1", keyPath)); - } else { - privKey.setPermissions(strict); - privKey.write(d->m_privateKey.toPEM().toLatin1()); - } - } - - //Extra security check - if (QFile::permissions(keyPath) != strict) { - qCWarning(KDECONNECT_CORE) << "Warning: KDE Connect private key file has too open permissions " << keyPath; - } -} - void KdeConnectConfig::loadCertificate() { - QString certPath = certificatePath(); - QFile cert(certPath); - if (cert.exists() && cert.open(QIODevice::ReadOnly)) { - - d->m_certificate = QSslCertificate::fromPath(certPath).at(0); - - } else { + QFile cert(certificatePath()); + QFile privKey(privateKeyPath()); + if (!cert.exists() || !privKey.exists()) { // No certificate yet. Probably first run. Let's generate one! - QString uuid = QUuid::createUuid().toString(); DbusHelper::filterNonExportableCharacters(uuid); qCDebug(KDECONNECT_CORE) << "My id:" << uuid; - // FIXME: We only use QCA here to generate the cert and key, would be nice to get rid of it completely. - // The same thing we are doing with QCA could be done invoking openssl (although it's potentially less portable): - // openssl req -new -x509 -sha256 -newkey rsa:2048 -nodes -keyout privateKey.pem -days 3650 -out certificate.pem -subj "/O=KDE/OU=KDE Connect/CN=_e6e29ad4_2b31_4b6d_8f7a_9872dbaa9095_" - - QCA::CertificateOptions certificateOptions = QCA::CertificateOptions(); - QDateTime startTime = QDateTime::currentDateTime().addYears(-1); - QDateTime endTime = startTime.addYears(10); - QCA::CertificateInfo certificateInfo; - certificateInfo.insert(QCA::CommonName, uuid); - certificateInfo.insert(QCA::Organization,QStringLiteral("KDE")); - certificateInfo.insert(QCA::OrganizationalUnit,QStringLiteral("Kde connect")); - certificateOptions.setInfo(certificateInfo); - certificateOptions.setFormat(QCA::PKCS10); - certificateOptions.setSerialNumber(QCA::BigInteger(10)); - certificateOptions.setValidityPeriod(startTime, endTime); - - d->m_certificate = QSslCertificate(QCA::Certificate(certificateOptions, d->m_privateKey).toPEM().toLatin1()); - - if (!cert.open(QIODevice::ReadWrite | QIODevice::Truncate)) { - Daemon::instance()->reportError(QStringLiteral("KDE Connect"), i18n("Could not store certificate file: %1", certPath)); - } else { - cert.setPermissions(strict); - cert.write(d->m_certificate.toPem()); + int retVal = QProcess::execute("openssl", {"req", "-new", "-x509", "-sha256", "-newkey", "rsa:2048", "-nodes", "-keyout", privateKeyPath(), "-days", "3650", "-out", certificatePath(), "-subj", "/O=KDE/OU=KDEConnect/CN=" + uuid}); + + if (retVal) { + qWarning(KDECONNECT_CORE) << "Could not generate certificate"; } } + + auto certificates = QSslCertificate::fromPath(certificatePath()); + if (!certificates.isEmpty()) { + d->m_certificate = certificates.at(0); + } + + //Extra security check + const QFile::Permissions strict = QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::WriteUser; + if (QFile::permissions(privateKeyPath()) != strict) { + qCWarning(KDECONNECT_CORE) << "Warning: KDE Connect private key file has too open permissions " << privateKeyPath(); + } } diff --git a/sfos/rpm/kdeconnect-sfos.spec b/sfos/rpm/kdeconnect-sfos.spec --- a/sfos/rpm/kdeconnect-sfos.spec +++ b/sfos/rpm/kdeconnect-sfos.spec @@ -22,7 +22,6 @@ BuildRequires: pkgconfig(Qt5Qml) BuildRequires: pkgconfig(Qt5Quick) BuildRequires: pkgconfig(nemonotifications-qt5) -BuildRequires: pkgconfig(qca2-qt5) >= 2.0.0 BuildRequires: desktop-file-utils BuildRequires: cmake >= 3.0 BuildRequires: extra-cmake-modules >= 5.31.0 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,7 +13,6 @@ Qt5::DBus Qt5::Network Qt5::Test - qca-qt5 ) ecm_add_test(pluginloadtest.cpp LINK_LIBRARIES ${kdeconnect_libraries}) diff --git a/tests/lanlinkprovidertest.cpp b/tests/lanlinkprovidertest.cpp --- a/tests/lanlinkprovidertest.cpp +++ b/tests/lanlinkprovidertest.cpp @@ -69,10 +69,10 @@ // Attributes for test device QString m_deviceId; QString m_name; - QCA::PrivateKey m_privateKey; QSslCertificate m_certificate; + QTemporaryFile m_privateKeyFile; - QSslCertificate generateCertificate(QString&, QCA::PrivateKey&); + QSslCertificate generateCertificate(QString&); void addTrustedDevice(); void removeTrustedDevice(); void setSocketAttributes(QSslSocket* socket); @@ -86,8 +86,7 @@ m_deviceId = QStringLiteral("testdevice"); m_name = QStringLiteral("Test Device"); - m_privateKey = QCA::KeyGenerator().createRSA(2048); - m_certificate = generateCertificate(m_deviceId, m_privateKey); + m_certificate = generateCertificate(m_deviceId); m_lanLinkProvider.onStart(); @@ -312,28 +311,21 @@ QVERIFY2(body.contains("deviceType"), "Device type not found in identity packet"); } -QSslCertificate LanLinkProviderTest::generateCertificate(QString& commonName, QCA::PrivateKey& privateKey) +QSslCertificate LanLinkProviderTest::generateCertificate(QString& commonName) { - QDateTime startTime = QDateTime::currentDateTime(); - QDateTime endTime = startTime.addYears(10); - QCA::CertificateInfo certificateInfo; - certificateInfo.insert(QCA::CommonName,commonName); - certificateInfo.insert(QCA::Organization,QStringLiteral("KDE")); - certificateInfo.insert(QCA::OrganizationalUnit,QStringLiteral("Kde connect")); - - QCA::CertificateOptions certificateOptions(QCA::PKCS10); - certificateOptions.setSerialNumber(10); - certificateOptions.setInfo(certificateInfo); - certificateOptions.setValidityPeriod(startTime, endTime); - certificateOptions.setFormat(QCA::PKCS10); - - QSslCertificate certificate = QSslCertificate(QCA::Certificate(certificateOptions, privateKey).toPEM().toLatin1()); + QTemporaryFile cert; + cert.open(); + m_privateKeyFile.open(); + + QProcess::execute("openssl", QStringLiteral("req -new -x509 -sha256 -newkey rsa:2048 -nodes -keyout %1 -days 3650 -out %2 -subj /O=KDE/OU=KDEConnect/CN=%3").arg(m_privateKeyFile.fileName(), cert.fileName(), commonName).split(" ")); + + QSslCertificate certificate = QSslCertificate::fromPath(cert.fileName()).at(0); return certificate; } void LanLinkProviderTest::setSocketAttributes(QSslSocket* socket) { - socket->setPrivateKey(QSslKey(m_privateKey.toPEM().toLatin1(), QSsl::Rsa)); + socket->setPrivateKey(m_privateKeyFile.fileName()); socket->setLocalCertificate(m_certificate); } diff --git a/tests/networkpackettests.cpp b/tests/networkpackettests.cpp --- a/tests/networkpackettests.cpp +++ b/tests/networkpackettests.cpp @@ -23,7 +23,6 @@ #include "core/networkpacket.h" #include -#include QTEST_GUILESS_MAIN(NetworkPacketTests); diff --git a/tests/testsslsocketlinereader.cpp b/tests/testsslsocketlinereader.cpp --- a/tests/testsslsocketlinereader.cpp +++ b/tests/testsslsocketlinereader.cpp @@ -22,9 +22,10 @@ #include "../core/backends/lan/socketlinereader.h" #include -#include #include #include +#include +#include /* * This class tests the behaviour of socket line reader when the connection if over ssl. Since SSL takes part below application layer, @@ -51,7 +52,6 @@ private: const int PORT = 7894; QTimer m_timer; - QCA::Initializer m_qcaInitializer; QEventLoop m_loop; QList m_packets; Server* m_server; @@ -112,8 +112,8 @@ QVERIFY2(serverSocket != 0, "Null socket returned by server"); QVERIFY2(serverSocket->isOpen(), "Server socket already closed"); - setSocketAttributes(serverSocket, QStringLiteral("Test Server")); - setSocketAttributes(m_clientSocket, QStringLiteral("Test Client")); + setSocketAttributes(serverSocket, QStringLiteral("foo")); + setSocketAttributes(m_clientSocket, QStringLiteral("foo")); serverSocket->setPeerVerifyName(QStringLiteral("Test Client")); serverSocket->setPeerVerifyMode(QSslSocket::VerifyPeer); @@ -174,8 +174,8 @@ QVERIFY2(serverSocket != 0, "Null socket returned by server"); QVERIFY2(serverSocket->isOpen(), "Server socket already closed"); - setSocketAttributes(serverSocket, QStringLiteral("Test Server")); - setSocketAttributes(m_clientSocket, QStringLiteral("Test Client")); + setSocketAttributes(serverSocket, QStringLiteral("foo")); + setSocketAttributes(m_clientSocket, QStringLiteral("foo")); serverSocket->setPeerVerifyName(QStringLiteral("Test Client")); serverSocket->setPeerVerifyMode(QSslSocket::QueryPeer); @@ -231,8 +231,8 @@ QVERIFY2(serverSocket != 0, "Could not open a connection to the client"); - setSocketAttributes(serverSocket, QStringLiteral("Test Server")); - setSocketAttributes(m_clientSocket, QStringLiteral("Test Client")); + setSocketAttributes(serverSocket, QStringLiteral("foo")); + setSocketAttributes(m_clientSocket, QStringLiteral("foo")); // Not adding other device certificate to list of CA certificate, and using VerifyPeer. This should lead to handshake failure serverSocket->setPeerVerifyName(QStringLiteral("Test Client")); @@ -283,23 +283,16 @@ void TestSslSocketLineReader::setSocketAttributes(QSslSocket* socket, QString deviceName) { - QDateTime startTime = QDateTime::currentDateTime(); - QDateTime endTime = startTime.addYears(10); - QCA::CertificateInfo certificateInfo; - certificateInfo.insert(QCA::CommonName,deviceName); - certificateInfo.insert(QCA::Organization,QStringLiteral("KDE")); - certificateInfo.insert(QCA::OrganizationalUnit,QStringLiteral("Kde connect")); + QTemporaryFile cert; + cert.open(); + QTemporaryFile priv; + priv.open(); - QCA::CertificateOptions certificateOptions(QCA::PKCS10); - certificateOptions.setSerialNumber(10); - certificateOptions.setInfo(certificateInfo); - certificateOptions.setValidityPeriod(startTime, endTime); - certificateOptions.setFormat(QCA::PKCS10); + QProcess::execute("openssl", QStringLiteral("req -new -x509 -sha256 -newkey rsa:2048 -nodes -keyout %1 -days 3650 -out %2 -subj /O=KDE/OU=KDEConnect/CN=%3").arg(priv.fileName(), cert.fileName(), deviceName).split(" ")); - QCA::PrivateKey privKey = QCA::KeyGenerator().createRSA(2048); - QSslCertificate certificate = QSslCertificate(QCA::Certificate(certificateOptions, privKey).toPEM().toLatin1()); + QSslCertificate certificate = QSslCertificate::fromPath(cert.fileName()).at(0); - socket->setPrivateKey(QSslKey(privKey.toPEM().toLatin1(), QSsl::Rsa)); + socket->setPrivateKey(priv.fileName()); socket->setLocalCertificate(certificate); }