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

View File

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

View File

@ -129,12 +129,13 @@ bool ExternalCommand::start(int timeout)
bool rval = false;
if (iface.isValid()) {
QByteArray request;
request.setNum(++CoreBackendManager::self()->counter());
request.setNum(++CoreBackendManager::self()->counter());
request.append(cmd.toUtf8());
for (const auto &argument : qAsConst(d->m_Args))
request.append(argument.toLocal8Bit());
request.append(argument.toUtf8());
request.append(d->m_Input);
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
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());
iface.setTimeout(10 * 24 * 3600 * 1000); // 10 days
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
QDBusPendingCall pcall= iface.asyncCall(QStringLiteral("copyblocks"),
CoreBackendManager::self()->Uuid(),
CoreBackendManager::self()->privateKey().signMessage(hash, QCA::EMSA3_Raw),
source.path(), source.firstByte(), source.length(),
target.path(), target.firstByte(), blockSize);

View File

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

View File

@ -44,15 +44,13 @@ public:
public Q_SLOTS:
ActionReply init(const QVariantMap& args);
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 void exit(const QString& Uuid);
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 QByteArray& signature);
private:
void onReadOutput();
bool isCallerAuthorized(const QString& Uuid);
QEventLoop m_loop;
QString m_callerUuid;
QCA::Initializer initializer;
QCA::PublicKey m_publicKey;
unsigned int m_Counter;

View File

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