Cryptographically sign copyblocks and exit KAuth helper calls.

This commit is contained in:
Andrius Štikonas 2018-04-13 14:24:05 +03:00
parent 6b558f49d8
commit 231bfbd331
6 changed files with 49 additions and 40 deletions

View File

@ -21,12 +21,12 @@
#include "backend/corebackend.h" #include "backend/corebackend.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QCryptographicHash>
#include <QDebug> #include <QDebug>
#include <QDBusInterface> #include <QDBusInterface>
#include <QStringList> #include <QStringList>
#include <QString> #include <QString>
#include <QVector> #include <QVector>
#include <QUuid>
#include <QtCrypto> #include <QtCrypto>
@ -41,7 +41,6 @@ struct CoreBackendManagerPrivate
KAuth::ExecuteJob *m_job; KAuth::ExecuteJob *m_job;
CoreBackend *m_Backend; CoreBackend *m_Backend;
QString m_Uuid;
QCA::Initializer init; QCA::Initializer init;
QCA::PrivateKey privateKey; QCA::PrivateKey privateKey;
unsigned int counter = 0; unsigned int counter = 0;
@ -104,8 +103,6 @@ bool CoreBackendManager::startExternalCommandHelper()
action.setHelperId(QStringLiteral("org.kde.kpmcore.externalcommand")); action.setHelperId(QStringLiteral("org.kde.kpmcore.externalcommand"));
action.setTimeout(10 * 24 * 3600 * 1000); // 10 days action.setTimeout(10 * 24 * 3600 * 1000); // 10 days
QVariantMap arguments; QVariantMap arguments;
d->m_Uuid = QUuid::createUuid().toString();
arguments.insert(QStringLiteral("callerUuid"), Uuid());
arguments.insert(QStringLiteral("pubkey"), pubkey.toDER()); arguments.insert(QStringLiteral("pubkey"), pubkey.toDER());
action.setArguments(arguments); action.setArguments(arguments);
d->m_job = action.execute(); d->m_job = action.execute();
@ -125,8 +122,12 @@ bool CoreBackendManager::startExternalCommandHelper()
void CoreBackendManager::stopExternalCommandHelper() void CoreBackendManager::stopExternalCommandHelper()
{ {
QDBusInterface iface(QStringLiteral("org.kde.kpmcore.helperinterface"), QStringLiteral("/Helper"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus()); QDBusInterface iface(QStringLiteral("org.kde.kpmcore.helperinterface"), QStringLiteral("/Helper"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus());
if (iface.isValid()) if (iface.isValid()) {
iface.call(QStringLiteral("exit"), CoreBackendManager::self()->Uuid()); QByteArray request;
request.setNum(++CoreBackendManager::self()->counter());
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
iface.call(QStringLiteral("exit"), d->privateKey.signMessage(hash, QCA::EMSA3_Raw));
}
} }
KAuth::ExecuteJob* CoreBackendManager::job() KAuth::ExecuteJob* CoreBackendManager::job()
@ -134,11 +135,6 @@ KAuth::ExecuteJob* CoreBackendManager::job()
return d->m_job; return d->m_job;
} }
QString& CoreBackendManager::Uuid()
{
return d->m_Uuid;
}
bool CoreBackendManager::load(const QString& name) bool CoreBackendManager::load(const QString& name)
{ {
if (backend()) if (backend())

View File

@ -82,11 +82,6 @@ public:
*/ */
CoreBackend* backend(); CoreBackend* backend();
/**
* @return a pointer to the currently loaded backend
*/
QString& Uuid();
/** /**
* @return a pointer to the KAuth job * @return a pointer to the KAuth job
*/ */
@ -95,7 +90,7 @@ public:
/** /**
* stop ExternalCommand Helper * stop ExternalCommand Helper
*/ */
static void stopExternalCommandHelper(); void stopExternalCommandHelper();
/**< @return RSA private key used for signing External Command requests. */ /**< @return RSA private key used for signing External Command requests. */
QCA::PrivateKey privateKey(); QCA::PrivateKey privateKey();

View File

@ -129,12 +129,13 @@ bool ExternalCommand::start(int timeout)
bool rval = false; bool rval = false;
if (iface.isValid()) { if (iface.isValid()) {
QByteArray request; QByteArray request;
request.setNum(++CoreBackendManager::self()->counter());
request.setNum(++CoreBackendManager::self()->counter());
request.append(cmd.toUtf8()); request.append(cmd.toUtf8());
for (const auto &argument : qAsConst(d->m_Args)) for (const auto &argument : qAsConst(d->m_Args))
request.append(argument.toLocal8Bit()); request.append(argument.toUtf8());
request.append(d->m_Input); request.append(d->m_Input);
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512); QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("start"), QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("start"),
@ -185,9 +186,21 @@ bool ExternalCommand::copyBlocks(CopySource& source, CopyTarget& target)
QDBusInterface iface(QStringLiteral("org.kde.kpmcore.helperinterface"), QStringLiteral("/Helper"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus()); QDBusInterface iface(QStringLiteral("org.kde.kpmcore.helperinterface"), QStringLiteral("/Helper"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus());
iface.setTimeout(10 * 24 * 3600 * 1000); // 10 days iface.setTimeout(10 * 24 * 3600 * 1000); // 10 days
if (iface.isValid()) { if (iface.isValid()) {
QByteArray request;
request.setNum(++CoreBackendManager::self()->counter());
request.append(source.path().toUtf8());
request.append(QByteArray::number(source.firstByte()));
request.append(QByteArray::number(source.length()));
request.append(target.path().toUtf8());
request.append(QByteArray::number(target.firstByte()));
request.append(QByteArray::number(blockSize));
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
// Use asynchronous DBus calls, so that we can process reports and progress // Use asynchronous DBus calls, so that we can process reports and progress
QDBusPendingCall pcall= iface.asyncCall(QStringLiteral("copyblocks"), QDBusPendingCall pcall= iface.asyncCall(QStringLiteral("copyblocks"),
CoreBackendManager::self()->Uuid(), CoreBackendManager::self()->privateKey().signMessage(hash, QCA::EMSA3_Raw),
source.path(), source.firstByte(), source.length(), source.path(), source.firstByte(), source.length(),
target.path(), target.firstByte(), blockSize); target.path(), target.firstByte(), blockSize);

View File

@ -36,7 +36,6 @@ ActionReply ExternalCommandHelper::init(const QVariantMap& args)
reply.addData(QStringLiteral("success"), false); reply.addData(QStringLiteral("success"), false);
return reply; return reply;
} }
m_callerUuid = args[QStringLiteral("callerUuid")].toString();
m_publicKey = QCA::PublicKey::fromDER(args[QStringLiteral("pubkey")].toByteArray()); m_publicKey = QCA::PublicKey::fromDER(args[QStringLiteral("pubkey")].toByteArray());
m_Counter = 0; m_Counter = 0;
@ -111,10 +110,23 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr
return true; return true;
} }
bool ExternalCommandHelper::copyblocks(const QString& Uuid, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize) bool ExternalCommandHelper::copyblocks(const QByteArray& signature, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize)
{ {
if (!isCallerAuthorized(Uuid)) QByteArray request;
request.setNum(++m_Counter);
request.append(sourceDevice.toUtf8());
request.append(QByteArray::number(sourceFirstByte));
request.append(QByteArray::number(sourceLength));
request.append(targetDevice.toUtf8());
request.append(QByteArray::number(targetFirstByte));
request.append(QByteArray::number(blockSize));
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
if (!m_publicKey.verifyMessage(hash, signature, QCA::EMSA3_Raw)) {
qCritical() << xi18n("Invalid cryptographic signature");
return false; return false;
}
const qint64 blocksToCopy = sourceLength / blockSize; const qint64 blocksToCopy = sourceLength / blockSize;
qint64 readOffset = sourceFirstByte; qint64 readOffset = sourceFirstByte;
@ -202,7 +214,7 @@ QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const QStr
QByteArray request; QByteArray request;
request.setNum(++m_Counter); request.setNum(++m_Counter);
request.append(command.toLocal8Bit()); request.append(command.toUtf8());
for (const auto &argument : arguments) for (const auto &argument : arguments)
request.append(argument.toUtf8()); request.append(argument.toUtf8());
request.append(input); request.append(input);
@ -227,20 +239,15 @@ QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const QStr
return reply; return reply;
} }
bool ExternalCommandHelper::isCallerAuthorized(const QString& Uuid) void ExternalCommandHelper::exit(const QByteArray& signature)
{ {
if (Uuid != m_callerUuid) { QByteArray request;
qWarning() << "Caller is not authorized"; request.setNum(++m_Counter);
return false; QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
if (!m_publicKey.verifyMessage(hash, signature, QCA::EMSA3_Raw)) {
return;
} }
return true;
}
void ExternalCommandHelper::exit(const QString& Uuid)
{
if (!isCallerAuthorized(Uuid))
return;
m_loop.exit(); m_loop.exit();
if (QDBusConnection::systemBus().unregisterService(QStringLiteral("org.kde.kpmcore.helperinterface"))) if (QDBusConnection::systemBus().unregisterService(QStringLiteral("org.kde.kpmcore.helperinterface")))

View File

@ -44,15 +44,13 @@ public:
public Q_SLOTS: public Q_SLOTS:
ActionReply init(const QVariantMap& args); ActionReply init(const QVariantMap& args);
Q_SCRIPTABLE QVariantMap start(const QByteArray& signature, const QString& command, const QStringList& arguments, const QByteArray& input); Q_SCRIPTABLE QVariantMap start(const QByteArray& signature, const QString& command, const QStringList& arguments, const QByteArray& input);
Q_SCRIPTABLE bool copyblocks(const QString& Uuid, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize); Q_SCRIPTABLE bool copyblocks(const QByteArray& signature, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize);
Q_SCRIPTABLE void exit(const QString& Uuid); Q_SCRIPTABLE void exit(const QByteArray& signature);
private: private:
void onReadOutput(); void onReadOutput();
bool isCallerAuthorized(const QString& Uuid);
QEventLoop m_loop; QEventLoop m_loop;
QString m_callerUuid;
QCA::Initializer initializer; QCA::Initializer initializer;
QCA::PublicKey m_publicKey; QCA::PublicKey m_publicKey;
unsigned int m_Counter; unsigned int m_Counter;

View File

@ -59,5 +59,5 @@ KPMCoreInitializer::KPMCoreInitializer( const char* backend ) : KPMCoreInitializ
KPMCoreInitializer::~KPMCoreInitializer() KPMCoreInitializer::~KPMCoreInitializer()
{ {
CoreBackendManager::stopExternalCommandHelper(); CoreBackendManager::self()->stopExternalCommandHelper();
} }