Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 148a7131 authored by Vineet Garg's avatar Vineet Garg

Initial working implementation of ssl

parent 7d514bdd
......@@ -50,6 +50,6 @@ add_subdirectory(plasmoid)
add_subdirectory(cli)
add_subdirectory(fileitemactionplugin)
add_subdirectory(tests)
# add_subdirectory(tests)
install(PROGRAMS kdeconnect-non-plasma.desktop DESTINATION ${XDG_APPS_INSTALL_DIR})
......@@ -16,6 +16,7 @@ set(kdeconnectcore_SRCS
backends/linkprovider.cpp
backends/devicelink.cpp
backends/pairinghandler.cpp
kdeconnectplugin.cpp
kdeconnectpluginconfig.cpp
......
......@@ -2,8 +2,10 @@
set(backends_kdeconnect_SRCS
${backends_kdeconnect_SRCS}
backends/lan/server.cpp
backends/lan/lanlinkprovider.cpp
backends/lan/landevicelink.cpp
backends/lan/lanpairinghandler.cpp
backends/lan/uploadjob.cpp
backends/lan/downloadjob.cpp
backends/lan/socketlinereader.cpp
......
......@@ -31,9 +31,10 @@
#include "downloadjob.h"
#include "socketlinereader.h"
LanDeviceLink::LanDeviceLink(const QString& deviceId, LinkProvider* parent, QTcpSocket* socket)
LanDeviceLink::LanDeviceLink(const QString& deviceId, LinkProvider* parent, QSslSocket* socket)
: DeviceLink(deviceId, parent)
, mSocketLineReader(new SocketLineReader(socket))
, onSsl(false)
{
connect(mSocketLineReader, SIGNAL(readyRead()),
this, SLOT(dataReceived()));
......@@ -48,6 +49,10 @@ LanDeviceLink::LanDeviceLink(const QString& deviceId, LinkProvider* parent, QTcp
socket->setParent(this);
}
void LanDeviceLink::setOnSsl(bool value) {
onSsl = value;
}
bool LanDeviceLink::sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np)
{
......@@ -57,7 +62,9 @@ bool LanDeviceLink::sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np
np.setPayloadTransferInfo(job->getTransferInfo());
}
np.encrypt(key);
if (!onSsl) {
np.encrypt(key);
}
int written = mSocketLineReader->write(np.serialize());
......
......@@ -23,7 +23,7 @@
#include <QObject>
#include <QString>
#include <QTcpSocket>
#include <QSslSocket>
#include "../devicelink.h"
......@@ -35,8 +35,9 @@ class LanDeviceLink
Q_OBJECT
public:
LanDeviceLink(const QString& deviceId, LinkProvider* parent, QTcpSocket* socket);
LanDeviceLink(const QString& deviceId, LinkProvider* parent, QSslSocket* socket);
void setOnSsl(bool value);
bool sendPackage(NetworkPackage& np);
bool sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np);
......@@ -45,6 +46,7 @@ private Q_SLOTS:
private:
SocketLineReader* mSocketLineReader;
bool onSsl;
};
......
This diff is collapsed.
......@@ -23,10 +23,14 @@
#include <QObject>
#include <QTcpServer>
#include <QSslSocket>
#include <QUdpSocket>
#include <QtNetwork/qsslsocket.h>
#include "../linkprovider.h"
#include "netaddress.h"
#include "server.h"
#include "landevicelink.h"
class LanLinkProvider
: public LinkProvider
......@@ -39,24 +43,28 @@ public:
QString name() { return "LanLinkProvider"; }
int priority() { return PRIORITY_HIGH; }
void addLink(LanDeviceLink* deviceLink, NetworkPackage* receivedPackage);
public Q_SLOTS:
virtual void onNetworkChange();
virtual void onStart();
virtual void onStop();
void connected();
void encrypted();
void connectError();
private Q_SLOTS:
void newUdpConnection();
void newConnection();
void newConnection(QSslSocket*);
void dataReceived();
void deviceLinkDestroyed(QObject* destroyedDeviceLink);
void sslErrors(QList<QSslError> errors);
private:
static void configureSocket(QTcpSocket* socket);
static void configureSocket(QSslSocket* socket);
QTcpServer* mTcpServer;
Server* mServer;
QUdpSocket* mUdpServer;
QUdpSocket mUdpSocket;
const static quint16 port = 1714;
......@@ -68,7 +76,7 @@ private:
NetworkPackage* np;
QHostAddress sender;
};
QMap<QTcpSocket*, PendingConnect> receivedIdentityPackages;
QMap<QSslSocket*, PendingConnect> receivedIdentityPackages;
};
......
/**
* Copyright 2015 Vineet Garg <grg.vineet@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lanpairinghandler.h"
LanPairingHandler::LanPairingHandler() {
}
NetworkPackage* LanPairingHandler::createPairPackage(Device *device) {
NetworkPackage* np = new NetworkPackage("");
return np;
}
void LanPairingHandler::packageReceived(Device *device) {
}
void LanPairingHandler::requestPairing(Device *device) {
}
void LanPairingHandler::acceptPairing(Device *device) {
}
void LanPairingHandler::rejectPairing(Device *device) {
}
void LanPairingHandler::pairingDone(Device *device) {
}
/**
* Copyright 2015 Vineet Garg <grg.vineet@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KDECONNECT_LANPAIRINGHANDLER_H
#define KDECONNECT_LANPAIRINGHANDLER_H
#include "../pairinghandler.h"
class LanPairingHandler
: public PairingHandler
{
public:
LanPairingHandler();
virtual ~LanPairingHandler() { }
virtual NetworkPackage* createPairPackage(Device *device);
virtual void packageReceived(Device *device);
virtual void requestPairing(Device *device);
virtual void acceptPairing(Device *device);
virtual void rejectPairing(Device *device);
virtual void pairingDone(Device *device);
};
#endif //KDECONNECT_LANPAIRINGHANDLER_H
/**
* Copyright 2015 Vineet Garg <grg.vineet@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "server.h"
#include "kdeconnectconfig.h"
#include "lanlinkprovider.h"
#include <QSslKey>
#include <QSslSocket>
#include <QSslError>
Server::Server(QObject * parent)
:QTcpServer(parent)
{
}
void Server::incomingConnection(qintptr socketDescriptor) {
qDebug() << "Incoming connection";
QSslSocket *serverSocket = new QSslSocket;
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
qDebug() << "Setting socket descriptor";
connect(serverSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
Q_EMIT newConnection(serverSocket);
qDebug() << "Signal emiited";
} else {
qDebug() << "Delete socket";
delete serverSocket;
}
}
void Server::disconnected() {
QSslSocket* socket = qobject_cast<QSslSocket*>(sender());
qDebug() << socket->errorString();
}
/**
* Copyright 2015 Vineet Garg <grg.vineet@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KDECONNECT_SERVER_H
#define KDECONNECT_SERVER_H
#include <QTcpServer>
#include <QSslError>
#include <QtNetwork/qsslsocket.h>
class Server
: public QTcpServer
{
Q_OBJECT
public:
Server(QObject* parent = 0);
virtual ~Server() {}
protected:
virtual void incomingConnection(qintptr socketDescriptor);
public Q_SLOTS:
void disconnected();
Q_SIGNALS:
void newConnection(QSslSocket*);
};
#endif //KDECONNECT_SERVER_H
......@@ -21,7 +21,7 @@
#include "socketlinereader.h"
SocketLineReader::SocketLineReader(QTcpSocket* socket, QObject* parent)
SocketLineReader::SocketLineReader(QSslSocket* socket, QObject* parent)
: QObject(parent)
, mSocket(socket)
{
......
......@@ -24,7 +24,7 @@
#include <QObject>
#include <QString>
#include <QQueue>
#include <QTcpSocket>
#include <QSslSocket>
#include <QHostAddress>
/*
......@@ -37,7 +37,7 @@ class SocketLineReader
Q_OBJECT
public:
SocketLineReader(QTcpSocket* socket, QObject* parent = 0);
SocketLineReader(QSslSocket* socket, QObject* parent = 0);
QByteArray readLine() { return mPackages.dequeue(); }
qint64 write(const QByteArray& data) { return mSocket->write(data); }
......@@ -52,7 +52,7 @@ private Q_SLOTS:
private:
QByteArray lastChunk;
QTcpSocket* mSocket;
QSslSocket* mSocket;
QQueue<QByteArray> mPackages;
};
......
/**
* Copyright 2015 Vineet Garg <grg.vineet@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pairinghandler.h"
PairingHandler::PairingHandler() {
//gcc complains if we don't add something to compile on a class with virtual functions
}
\ No newline at end of file
/**
* Copyright 2015 Vineet Garg <grg.vineet@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KDECONNECT_PAIRINGHANDLER_H
#define KDECONNECT_PAIRINGHANDLER_H
#include <networkpackage.h>
#include <device.h>
class PairingHandler {
public:
PairingHandler();
virtual ~PairingHandler() { }
virtual NetworkPackage* createPairPackage(Device *device) = 0;
virtual void packageReceived(Device *device) = 0;
virtual void requestPairing(Device *device) = 0;
virtual void acceptPairing(Device *device) = 0;
virtual void rejectPairing(Device *device) = 0;
virtual void pairingDone(Device *device) = 0;
};
#endif //KDECONNECT_PAIRINGHANDLER_H
......@@ -122,10 +122,10 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink*
{
const QString& id = identityPackage.get<QString>("deviceId");
//qCDebug(KDECONNECT_CORE) << "Device discovered" << id << "via" << dl->provider()->name();
qCDebug(KDECONNECT_CORE) << "Device discovered" << id << "via" << dl->provider()->name();
if (d->mDevices.contains(id)) {
//qCDebug(KDECONNECT_CORE) << "It is a known device";
qCDebug(KDECONNECT_CORE) << "It is a known device " << identityPackage.get<QString>("deviceName");
Device* device = d->mDevices[id];
bool wasReachable = device->isReachable();
device->addLink(identityPackage, dl);
......@@ -133,7 +133,7 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink*
Q_EMIT deviceVisibilityChanged(id, true);
}
} else {
//qCDebug(KDECONNECT_CORE) << "It is a new device";
qCDebug(KDECONNECT_CORE) << "It is a new device " << identityPackage.get<QString>("deviceName");
Device* device = new Device(this, identityPackage, dl);
connect(device, SIGNAL(reachableStatusChanged()), this, SLOT(onDeviceStatusChanged()));
......
......@@ -58,9 +58,9 @@ Device::Device(QObject* parent, const QString& id)
m_deviceType = str2type(info.deviceType);
m_publicKey = QCA::RSAPublicKey::fromPEM(info.publicKey);
m_pairingTimeut.setSingleShot(true);
m_pairingTimeut.setInterval(30 * 1000); //30 seconds of timeout
connect(&m_pairingTimeut, SIGNAL(timeout()),
m_pairingTimeout.setSingleShot(true);
m_pairingTimeout.setInterval(30 * 1000); //30 seconds of timeout
connect(&m_pairingTimeout, SIGNAL(timeout()),
this, SLOT(pairingTimeout()));
//Register in bus
......@@ -221,7 +221,7 @@ void Device::requestPair()
return;
}
m_pairingTimeut.start();
m_pairingTimeout.start();
}
void Device::unpair()
......@@ -277,6 +277,14 @@ void Device::addLink(const NetworkPackage& identityPackage, DeviceLink* link)
setName(identityPackage.get<QString>("deviceName"));
m_deviceType = str2type(identityPackage.get<QString>("deviceType"));
// Set certificate if the link is on ssl, and it is added to identity package
// This is always sets certificate when link is added to device
if (identityPackage.has("certificate")) {
qDebug() << "Got certificate" ;
m_certificate = QSslCertificate(identityPackage.get<QByteArray>("certificate"));
// qDebug() << m_certificate.toText();
}
//Theoretically we will never add two links from the same provider (the provider should destroy
//the old one before this is called), so we do not have to worry about destroying old links.
//-- Actually, we should not destroy them or the provider will store an invalid ref!
......@@ -341,7 +349,7 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
qCDebug(KDECONNECT_CORE) << "Already" << (wantsPair? "paired":"unpaired");
if (m_pairStatus == Device::Requested) {
m_pairStatus = Device::NotPaired;
m_pairingTimeut.stop();
m_pairingTimeout.stop();
Q_EMIT pairingFailed(i18n("Canceled by other peer"));
}
return;
......@@ -356,7 +364,7 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
qCDebug(KDECONNECT_CORE) << "ERROR decoding key";
if (m_pairStatus == Device::Requested) {
m_pairStatus = Device::NotPaired;
m_pairingTimeut.stop();
m_pairingTimeout.stop();
}
Q_EMIT pairingFailed(i18n("Received incorrect key"));
return;
......@@ -383,7 +391,7 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
m_pairStatus = Device::NotPaired;
if (prevPairStatus == Device::Requested) {
m_pairingTimeut.stop();
m_pairingTimeout.stop();
Q_EMIT pairingFailed(i18n("Canceled by other peer"));
} else if (prevPairStatus == Device::Paired) {
unpairInternal();
......@@ -451,10 +459,10 @@ void Device::setAsPaired()
m_pairStatus = Device::Paired;
m_pairingTimeut.stop(); //Just in case it was started
m_pairingTimeout.stop(); //Just in case it was started
//Save device info in the config
KdeConnectConfig::instance()->addTrustedDevice(id(), name(), type2str(m_deviceType), m_publicKey.toPEM());
KdeConnectConfig::instance()->addTrustedDevice(id(), name(), type2str(m_deviceType), m_publicKey.toPEM(), QString(m_certificate.toPem()));
reloadPlugins(); //Will actually load the plugins
......
......@@ -28,6 +28,7 @@
#include <QSslKey>
#include <QTimer>
#include <QtCrypto>
#include <QtNetwork/qsslcertificate.h>
#include "networkpackage.h"
......@@ -141,6 +142,7 @@ private: //Fields (TODO: dPointer!)
QString m_deviceName;
DeviceType m_deviceType;
QCA::PublicKey m_publicKey;
QSslCertificate m_certificate;
PairStatus m_pairStatus;
int m_protocolVersion;
......@@ -149,7 +151,7 @@ private: //Fields (TODO: dPointer!)
QMultiMap<QString, KdeConnectPlugin*> m_pluginsByIncomingInterface;
QMultiMap<QString, KdeConnectPlugin*> m_pluginsByOutgoingInterface;
QTimer m_pairingTimeut;
QTimer m_pairingTimeout;
const QSet<QString> m_incomingCapabilities;
const QSet<QString> m_outgoingCapabilities;
......
......@@ -33,6 +33,7 @@
#include <QCoreApplication>
#include <QHostInfo>
#include <QSettings>
#include <QtNetwork/qsslcertificate.h>
#include "core_debug.h"
#include "dbushelper.h"
......@@ -41,10 +42,11 @@
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 inteneded
// Note it's not being used anywhere. That's intended
QCA::Initializer mQcaInitializer;
QCA::PrivateKey privateKey;
QSslCertificate certificate; // Use QSslCertificate instead of QCA::Certificate due to compatibility with QSslSocket
QSettings* config;
......@@ -106,6 +108,42 @@ KdeConnectConfig::KdeConnectConfig()
}
}
QString certPath = certificatePath();
QFile cert(certPath);
if (cert.exists() && cert.open(QIODevice::ReadOnly)) {
// d->certificate = QCA::Certificate::fromPEMFile(certPath);
d->certificate = QSslCertificate::fromPath(certPath).value(0);
} else {
QCA::CertificateOptions certificateOptions = QCA::CertificateOptions();
// TODO : Set serial number for certificate. Time millis or any constant number?
QCA::BigInteger bigInteger(10);
QDateTime startTime = QDateTime::currentDateTime();
QDateTime endTime = startTime.addYears(10);
QCA::CertificateInfo certificateInfo;
certificateInfo.insert(QCA::CommonName,d->config->value("id", "unknown id").toString());
certificateInfo.insert(QCA::Organization,"KDE");
certificateInfo.insert(QCA::OrganizationalUnit,"Kde connect");
certificateOptions.setFormat(QCA::PKCS10);
certificateOptions.setSerialNumber(bigInteger);
certificateOptions.setInfo(certificateInfo);
certificateOptions.setValidityPeriod(startTime, endTime);
certificateOptions.setFormat(QCA::PKCS10);
// d->certificate = QCA::Certificate(certificateOptions, d->privateKey);
d->certificate = QSslCertificate(QCA::Certificate(certificateOptions, d->privateKey).toPEM().toLatin1());
if (!cert.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
Daemon::instance()->reportError(QLatin1String("KDE Connect"), i18n("Could not store certificate file: %1", certPath));
} else {
cert.setPermissions(strict);
cert.write(d->certificate.toPem());
}
}
//Extra security check
if (QFile::permissions(keyPath) != strict) {
qCDebug(KDECONNECT_CORE) << "Warning: KDE Connect private key file has too open permissions " << keyPath;
......@@ -157,6 +195,16 @@ QCA::PublicKey KdeConnectConfig::publicKey()
return d->privateKey.toPublicKey();
}
QString KdeConnectConfig::certificatePath()
{
return baseConfigDir().absoluteFilePath("certificate.pem");
}
QSslCertificate KdeConnectConfig::certificate()
{
return d->certificate;
}
QDir KdeConnectConfig::baseConfigDir()
{
QString configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
......@@ -172,13 +220,14 @@ QStringList KdeConnectConfig::trustedDevices()
return list;
}
void KdeConnectConfig::addTrustedDevice(QString id, QString name, QString type, QString publicKey)
void KdeConnectConfig::addTrustedDevice(QString id, QString name, QString type, QString publicKey, QString certificate)
{
d->config->beginGroup("trustedDevices");
d->config->beginGroup(id);
d->config->setValue("name", name);
d->config->setValue("type", type);
d->config->setValue("publicKey", publicKey);
d->config->setValue("certificate", certificate);
d->config->endGroup();
d->config->endGroup();
d->config->sync();
......@@ -195,6 +244,7 @@ KdeConnectConfig::DeviceInfo KdeConnectConfig::getTrustedDevice(QString id)
info.deviceName = d->config->value("name", QLatin1String("unnamed")).toString();
info.deviceType = d->config->value("type", QLatin1String("unknown")).toString();
info.publicKey = d->config->value("publicKey", QString()).toString();
info.certificate = d->config->value("certificate", QString()).toString();
d->config->endGroup();
d->config->endGroup();
......@@ -212,6 +262,29 @@ void KdeConnectConfig::removeTrustedDevice(QString deviceId)
//We do not remove the config files.
}
// Utility functions to set and get a value
void KdeConnectConfig::setDeviceProperty(QString deviceId, QString key, QString value)
{
d->config->beginGroup("trustedDevices");
d->config->beginGroup(deviceId);
d->config->setValue(key, value);
d->config->endGroup();
d->config->endGroup();