First attempt at using RSA to sign requests to KAuth helper.

This commit is contained in:
Andrius Štikonas 2018-04-13 00:43:12 +03:00
parent 527734e9e8
commit 428ee5b6c8
8 changed files with 81 additions and 13 deletions

View File

@ -63,6 +63,8 @@ find_package(KF5 REQUIRED
WidgetsAddons WidgetsAddons
) )
find_package(Qca-qt5 REQUIRED)
# use sane compile flags # use sane compile flags
add_definitions( add_definitions(
-DQT_USE_QSTRINGBUILDER -DQT_USE_QSTRINGBUILDER

View File

@ -42,12 +42,13 @@ add_library(kpmcore SHARED ${kpmcore_SRCS})
target_link_libraries( kpmcore PUBLIC target_link_libraries( kpmcore PUBLIC
Qt5::Core Qt5::Core
PRIVATE PRIVATE
${BLKID_LIBRARIES}
Qt5::DBus Qt5::DBus
Qt5::Gui Qt5::Gui
qca-qt5
KF5::I18n KF5::I18n
KF5::CoreAddons KF5::CoreAddons
KF5::WidgetsAddons KF5::WidgetsAddons
${BLKID_LIBRARIES}
KF5::Auth KF5::Auth
) )

View File

@ -28,6 +28,8 @@
#include <QVector> #include <QVector>
#include <QUuid> #include <QUuid>
#include <QtCrypto>
#include <KAuth> #include <KAuth>
#include <KLocalizedString> #include <KLocalizedString>
#include <KPluginFactory> #include <KPluginFactory>
@ -40,6 +42,9 @@ struct CoreBackendManagerPrivate
CoreBackend *m_Backend; CoreBackend *m_Backend;
QString m_Uuid; QString m_Uuid;
QCA::Initializer init;
QCA::PrivateKey privateKey;
unsigned int counter = 0;
}; };
CoreBackendManager::CoreBackendManager() : CoreBackendManager::CoreBackendManager() :
@ -74,14 +79,34 @@ QVector<KPluginMetaData> CoreBackendManager::list() const
return KPluginLoader::findPlugins(QString(), filter); return KPluginLoader::findPlugins(QString(), filter);
} }
void CoreBackendManager::startExternalCommandHelper() bool CoreBackendManager::startExternalCommandHelper()
{ {
// Generate RSA key pair for signing external command requests
if (!QCA::isSupported("pkey") || !QCA::PKey::supportedIOTypes().contains(QCA::PKey::RSA)) {
qCritical() << xi18n("QCA does not support RSA.");
return false;
}
d->privateKey = QCA::KeyGenerator().createRSA(4096);
if(d->privateKey.isNull()) {
qCritical() << xi18n("Failed to make private RSA key.");
return false;
}
if (!d->privateKey.canSign()) {
qCritical() << xi18n("Generated key cannot be used for signatures.");
return false;
}
QCA::PublicKey pubkey = d->privateKey.toPublicKey();
KAuth::Action action = KAuth::Action(QStringLiteral("org.kde.kpmcore.externalcommand.init")); KAuth::Action action = KAuth::Action(QStringLiteral("org.kde.kpmcore.externalcommand.init"));
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(); d->m_Uuid = QUuid::createUuid().toString();
arguments.insert(QStringLiteral("callerUuid"), Uuid()); arguments.insert(QStringLiteral("callerUuid"), Uuid());
arguments.insert(QStringLiteral("pubkey"), pubkey.toDER());
action.setArguments(arguments); action.setArguments(arguments);
d->m_job = action.execute(); d->m_job = action.execute();
job()->start(); job()->start();
@ -93,6 +118,8 @@ void CoreBackendManager::startExternalCommandHelper()
QObject::connect(job(), &KJob::finished, [=] () { if(d->m_job->error()) exitLoop(); } ); QObject::connect(job(), &KJob::finished, [=] () { if(d->m_job->error()) exitLoop(); } );
loop.exec(); loop.exec();
QObject::disconnect(conn); QObject::disconnect(conn);
return true;
} }
void CoreBackendManager::stopExternalCommandHelper() void CoreBackendManager::stopExternalCommandHelper()
@ -145,3 +172,13 @@ bool CoreBackendManager::load(const QString& name)
void CoreBackendManager::unload() void CoreBackendManager::unload()
{ {
} }
QCA::PrivateKey CoreBackendManager::privateKey()
{
return d->privateKey;
}
unsigned int& CoreBackendManager::counter()
{
return d->counter;
}

View File

@ -32,6 +32,7 @@ class QStringList;
class KPluginMetaData; class KPluginMetaData;
class CoreBackend; class CoreBackend;
namespace KAuth { class ExecuteJob; } namespace KAuth { class ExecuteJob; }
namespace QCA { class PrivateKey; }
struct CoreBackendManagerPrivate; struct CoreBackendManagerPrivate;
/** /**
@ -96,8 +97,13 @@ public:
*/ */
static void stopExternalCommandHelper(); static void stopExternalCommandHelper();
/**< @return RSA private key used for signing External Command requests. */
QCA::PrivateKey privateKey();
unsigned int& counter();
private: private:
void startExternalCommandHelper(); bool startExternalCommandHelper();
private: private:
std::unique_ptr<CoreBackendManagerPrivate> d; std::unique_ptr<CoreBackendManagerPrivate> d;

View File

@ -25,6 +25,7 @@ qt5_generate_dbus_interface(
add_executable(kpmcore_externalcommand util/externalcommandhelper.cpp) add_executable(kpmcore_externalcommand util/externalcommandhelper.cpp)
target_link_libraries(kpmcore_externalcommand target_link_libraries(kpmcore_externalcommand
qca-qt5
Qt5::Core Qt5::Core
Qt5::DBus Qt5::DBus
KF5::Auth KF5::Auth

View File

@ -25,6 +25,7 @@
#include "util/externalcommand.h" #include "util/externalcommand.h"
#include "util/report.h" #include "util/report.h"
#include <QCryptographicHash>
#include <QDBusInterface> #include <QDBusInterface>
#include <QDBusReply> #include <QDBusReply>
#include <QEventLoop> #include <QEventLoop>
@ -36,14 +37,14 @@
#include <QThread> #include <QThread>
#include <QVariant> #include <QVariant>
#include <QtCrypto>
#include <KAuth> #include <KAuth>
#include <KJob> #include <KJob>
#include <KLocalizedString> #include <KLocalizedString>
struct ExternalCommandPrivate struct ExternalCommandPrivate
{ {
QVariantMap arguments;
Report *m_Report; Report *m_Report;
QString m_Command; QString m_Command;
QStringList m_Args; QStringList m_Args;
@ -91,8 +92,7 @@ ExternalCommand::~ExternalCommand()
void ExternalCommand::setup(const QProcess::ProcessChannelMode processChannelMode) void ExternalCommand::setup(const QProcess::ProcessChannelMode processChannelMode)
{ {
d->arguments.insert(QStringLiteral("environment"), QStringList() << QStringLiteral("LC_ALL=C") << QStringLiteral("LVM_SUPPRESS_FD_WARNINGS=1")); // d->arguments.insert(QStringLiteral("processChannelMode"), processChannelMode); // FIXME
d->arguments.insert(QStringLiteral("processChannelMode"), processChannelMode);
// connect(this, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, &ExternalCommand::onFinished); // connect(this, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, &ExternalCommand::onFinished);
// connect(this, &ExternalCommand::readyReadStandardOutput, this, &ExternalCommand::onReadOutput); // connect(this, &ExternalCommand::readyReadStandardOutput, this, &ExternalCommand::onReadOutput);
@ -128,8 +128,17 @@ bool ExternalCommand::start(int timeout)
bool rval = false; bool rval = false;
if (iface.isValid()) { if (iface.isValid()) {
QByteArray request;
request.setNum(++CoreBackendManager::self()->counter());
request.append(cmd.toUtf8());
for (const auto &argument : qAsConst(d->m_Args))
request.append(argument.toLocal8Bit());
request.append(d->m_Input);
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("start"), QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("start"),
CoreBackendManager::self()->Uuid(), CoreBackendManager::self()->privateKey().signMessage(hash, QCA::EMSA3_Raw),
cmd, cmd,
args(), args(),
d->m_Input, d->m_Input,

View File

@ -40,6 +40,7 @@ ActionReply ExternalCommandHelper::init(const QVariantMap& args)
return reply; return reply;
} }
m_callerUuid = args[QStringLiteral("callerUuid")].toString(); m_callerUuid = args[QStringLiteral("callerUuid")].toString();
m_publicKey = QCA::PublicKey::fromDER(args[QStringLiteral("pubkey")].toByteArray());
if (!QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.helperinterface"))) { if (!QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.helperinterface"))) {
qWarning() << QDBusConnection::systemBus().lastError().message(); qWarning() << QDBusConnection::systemBus().lastError().message();
@ -196,10 +197,19 @@ bool ExternalCommandHelper::copyblocks(const QString& Uuid, const QString& sourc
return rval; return rval;
} }
QVariantMap ExternalCommandHelper::start(const QString& Uuid, const QString& command, const QStringList& arguments, const QByteArray& input, const QStringList& environment) QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const QString& command, const QStringList& arguments, const QByteArray& input, const QStringList& environment)
{ {
QVariantMap reply; QVariantMap reply;
if (!isCallerAuthorized(Uuid)) {
QByteArray request;
request.setNum(++m_Counter);
request.append(command.toLocal8Bit());
for (const auto &argument : arguments)
request.append(argument.toUtf8());
request.append(input);
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
if (!m_publicKey.verifyMessage(hash, signature, QCA::EMSA3_Raw)) {
qCritical() << xi18n("Invalid cryptographic signature");
reply[QStringLiteral("success")] = false; reply[QStringLiteral("success")] = false;
return reply; return reply;
} }

View File

@ -24,7 +24,7 @@
#include <QString> #include <QString>
#include <QProcess> #include <QProcess>
class QTimer; #include <QtCrypto>
using namespace KAuth; using namespace KAuth;
@ -43,7 +43,7 @@ public:
public Q_SLOTS: public Q_SLOTS:
ActionReply init(const QVariantMap& args); ActionReply init(const QVariantMap& args);
Q_SCRIPTABLE QVariantMap start(const QString& Uuid, const QString& command, const QStringList& arguments, const QByteArray& input, const QStringList& environment); Q_SCRIPTABLE QVariantMap start(const QByteArray& signature, const QString& command, const QStringList& arguments, const QByteArray& input, const QStringList& environment);
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 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 void exit(const QString& Uuid);
@ -53,11 +53,13 @@ private:
QEventLoop m_loop; QEventLoop m_loop;
QString m_callerUuid; QString m_callerUuid;
QCA::Initializer initializer;
QCA::PublicKey m_publicKey;
unsigned int m_Counter;
QString m_command; QString m_command;
QString m_sourceDevice; QString m_sourceDevice;
QProcess m_cmd; QProcess m_cmd;
QTimer *timer;
// QByteArray output; // QByteArray output;
}; };