First attempt at using RSA to sign requests to KAuth helper.
This commit is contained in:
parent
527734e9e8
commit
428ee5b6c8
|
@ -63,6 +63,8 @@ find_package(KF5 REQUIRED
|
|||
WidgetsAddons
|
||||
)
|
||||
|
||||
find_package(Qca-qt5 REQUIRED)
|
||||
|
||||
# use sane compile flags
|
||||
add_definitions(
|
||||
-DQT_USE_QSTRINGBUILDER
|
||||
|
|
|
@ -42,12 +42,13 @@ add_library(kpmcore SHARED ${kpmcore_SRCS})
|
|||
target_link_libraries( kpmcore PUBLIC
|
||||
Qt5::Core
|
||||
PRIVATE
|
||||
${BLKID_LIBRARIES}
|
||||
Qt5::DBus
|
||||
Qt5::Gui
|
||||
qca-qt5
|
||||
KF5::I18n
|
||||
KF5::CoreAddons
|
||||
KF5::WidgetsAddons
|
||||
${BLKID_LIBRARIES}
|
||||
KF5::Auth
|
||||
)
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <QVector>
|
||||
#include <QUuid>
|
||||
|
||||
#include <QtCrypto>
|
||||
|
||||
#include <KAuth>
|
||||
#include <KLocalizedString>
|
||||
#include <KPluginFactory>
|
||||
|
@ -40,6 +42,9 @@ struct CoreBackendManagerPrivate
|
|||
CoreBackend *m_Backend;
|
||||
|
||||
QString m_Uuid;
|
||||
QCA::Initializer init;
|
||||
QCA::PrivateKey privateKey;
|
||||
unsigned int counter = 0;
|
||||
};
|
||||
|
||||
CoreBackendManager::CoreBackendManager() :
|
||||
|
@ -74,14 +79,34 @@ QVector<KPluginMetaData> CoreBackendManager::list() const
|
|||
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"));
|
||||
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();
|
||||
job()->start();
|
||||
|
@ -93,6 +118,8 @@ void CoreBackendManager::startExternalCommandHelper()
|
|||
QObject::connect(job(), &KJob::finished, [=] () { if(d->m_job->error()) exitLoop(); } );
|
||||
loop.exec();
|
||||
QObject::disconnect(conn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CoreBackendManager::stopExternalCommandHelper()
|
||||
|
@ -145,3 +172,13 @@ bool CoreBackendManager::load(const QString& name)
|
|||
void CoreBackendManager::unload()
|
||||
{
|
||||
}
|
||||
|
||||
QCA::PrivateKey CoreBackendManager::privateKey()
|
||||
{
|
||||
return d->privateKey;
|
||||
}
|
||||
|
||||
unsigned int& CoreBackendManager::counter()
|
||||
{
|
||||
return d->counter;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ class QStringList;
|
|||
class KPluginMetaData;
|
||||
class CoreBackend;
|
||||
namespace KAuth { class ExecuteJob; }
|
||||
namespace QCA { class PrivateKey; }
|
||||
struct CoreBackendManagerPrivate;
|
||||
|
||||
/**
|
||||
|
@ -96,8 +97,13 @@ public:
|
|||
*/
|
||||
static void stopExternalCommandHelper();
|
||||
|
||||
/**< @return RSA private key used for signing External Command requests. */
|
||||
QCA::PrivateKey privateKey();
|
||||
|
||||
unsigned int& counter();
|
||||
|
||||
private:
|
||||
void startExternalCommandHelper();
|
||||
bool startExternalCommandHelper();
|
||||
|
||||
private:
|
||||
std::unique_ptr<CoreBackendManagerPrivate> d;
|
||||
|
|
|
@ -25,6 +25,7 @@ qt5_generate_dbus_interface(
|
|||
add_executable(kpmcore_externalcommand util/externalcommandhelper.cpp)
|
||||
|
||||
target_link_libraries(kpmcore_externalcommand
|
||||
qca-qt5
|
||||
Qt5::Core
|
||||
Qt5::DBus
|
||||
KF5::Auth
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "util/externalcommand.h"
|
||||
#include "util/report.h"
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusReply>
|
||||
#include <QEventLoop>
|
||||
|
@ -36,14 +37,14 @@
|
|||
#include <QThread>
|
||||
#include <QVariant>
|
||||
|
||||
#include <QtCrypto>
|
||||
|
||||
#include <KAuth>
|
||||
#include <KJob>
|
||||
#include <KLocalizedString>
|
||||
|
||||
struct ExternalCommandPrivate
|
||||
{
|
||||
QVariantMap arguments;
|
||||
|
||||
Report *m_Report;
|
||||
QString m_Command;
|
||||
QStringList m_Args;
|
||||
|
@ -91,8 +92,7 @@ ExternalCommand::~ExternalCommand()
|
|||
|
||||
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);
|
||||
// d->arguments.insert(QStringLiteral("processChannelMode"), processChannelMode); // FIXME
|
||||
|
||||
// connect(this, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, &ExternalCommand::onFinished);
|
||||
// connect(this, &ExternalCommand::readyReadStandardOutput, this, &ExternalCommand::onReadOutput);
|
||||
|
@ -128,8 +128,17 @@ bool ExternalCommand::start(int timeout)
|
|||
|
||||
bool rval = false;
|
||||
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"),
|
||||
CoreBackendManager::self()->Uuid(),
|
||||
CoreBackendManager::self()->privateKey().signMessage(hash, QCA::EMSA3_Raw),
|
||||
cmd,
|
||||
args(),
|
||||
d->m_Input,
|
||||
|
|
|
@ -40,6 +40,7 @@ ActionReply ExternalCommandHelper::init(const QVariantMap& args)
|
|||
return reply;
|
||||
}
|
||||
m_callerUuid = args[QStringLiteral("callerUuid")].toString();
|
||||
m_publicKey = QCA::PublicKey::fromDER(args[QStringLiteral("pubkey")].toByteArray());
|
||||
|
||||
if (!QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.helperinterface"))) {
|
||||
qWarning() << QDBusConnection::systemBus().lastError().message();
|
||||
|
@ -196,10 +197,19 @@ bool ExternalCommandHelper::copyblocks(const QString& Uuid, const QString& sourc
|
|||
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;
|
||||
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;
|
||||
return reply;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <QString>
|
||||
#include <QProcess>
|
||||
|
||||
class QTimer;
|
||||
#include <QtCrypto>
|
||||
|
||||
using namespace KAuth;
|
||||
|
||||
|
@ -43,7 +43,7 @@ public:
|
|||
|
||||
public Q_SLOTS:
|
||||
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 void exit(const QString& Uuid);
|
||||
|
||||
|
@ -53,11 +53,13 @@ private:
|
|||
|
||||
QEventLoop m_loop;
|
||||
QString m_callerUuid;
|
||||
QCA::Initializer initializer;
|
||||
QCA::PublicKey m_publicKey;
|
||||
unsigned int m_Counter;
|
||||
QString m_command;
|
||||
QString m_sourceDevice;
|
||||
QProcess m_cmd;
|
||||
|
||||
QTimer *timer;
|
||||
// QByteArray output;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue