types.h
util.h)
+if (HAVE_QCA2)
+ set(SOURCES ${SOURCES} keyevent.cpp)
+ set(HEADERS ${HEADERS} keyevent.h)
+endif(HAVE_QCA2)
+
if(APPLE)
set(SOURCES ${SOURCES} mac_utils.cpp)
set(HEADERS ${HEADERS} mac_utils.h)
CtcpEvent = 0x00050000,
CtcpEventFlush
+
+#ifdef HAVE_QCA2
+ ,KeyEvent = 0x00060000
+#endif
};
EventManager(QObject *parent = 0);
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2013 by the Quassel Project *
+ * devel@quassel-irc.org *
+ * *
+ * 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. *
+ * *
+ * 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "keyevent.h"
+
+Event *KeyEvent::create(EventManager::EventType type, QVariantMap &map, Network *network)
+{
+ if (type == EventManager::KeyEvent)
+ return new KeyEvent(type, map, network);
+
+ return 0;
+}
+
+
+KeyEvent::KeyEvent(EventManager::EventType type, QVariantMap &map, Network *network)
+ : IrcEvent(type, map, network)
+{
+ _exchangeType = static_cast<ExchangeType>(map.take("exchangeType").toInt());
+ _target = map.take("target").toString();
+ _key = map.take("key").toByteArray();
+}
+
+
+void KeyEvent::toVariantMap(QVariantMap &map) const
+{
+ IrcEvent::toVariantMap(map);
+ map["exchangeType"] = exchangeType();
+ map["target"] = target();
+ map["key"] = key();
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2013 by the Quassel Project *
+ * devel@quassel-irc.org *
+ * *
+ * 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. *
+ * *
+ * 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef KEYEVENT_H
+#define KEYEVENT_H
+
+#include "ircevent.h"
+
+class KeyEvent : public IrcEvent
+{
+public:
+ enum ExchangeType {
+ Init,
+ Finish
+ };
+
+ explicit KeyEvent(EventManager::EventType type, Network *network, const QString &prefix, const QString &target,
+ ExchangeType exchangeType, const QByteArray &key,
+ const QDateTime ×tamp = QDateTime())
+ : IrcEvent(type, network, prefix),
+ _exchangeType(exchangeType),
+ _target(target),
+ _key(key)
+ {
+ setTimestamp(timestamp);
+ }
+
+
+ inline ExchangeType exchangeType() const { return _exchangeType; }
+ inline void setExchangeType(ExchangeType type) { _exchangeType = type; }
+
+ inline QString target() const { return _target; }
+ inline void setTarget(const QString &target) { _target = target; }
+
+ inline QByteArray key() const { return _key; }
+ inline void setKey(const QByteArray &key) { _key = key; }
+
+ static Event *create(EventManager::EventType type, QVariantMap &map, Network *network);
+
+protected:
+ explicit KeyEvent(EventManager::EventType type, QVariantMap &map, Network *network);
+ void toVariantMap(QVariantMap &map) const;
+
+ virtual inline QString className() const { return "KeyEvent"; }
+ virtual inline void debugInfo(QDebug &dbg) const
+ {
+ NetworkEvent::debugInfo(dbg);
+ dbg << ", prefix = " << qPrintable(prefix())
+ << ", target = " << qPrintable(target())
+ << ", exchangetype = " << (exchangeType() == Init ? "init" : "finish")
+ << ", key = " << qPrintable(key());
+ }
+
+
+private:
+ ExchangeType _exchangeType;
+ QString _target;
+ QByteArray _key;
+};
+
+
+#endif
#include "netsplit.h"
#include "quassel.h"
+#ifdef HAVE_QCA2
+# include "keyevent.h"
+#endif
+
CoreSessionEventProcessor::CoreSessionEventProcessor(CoreSession *session)
: BasicHandler("handleCtcp", session),
_coreSession(session)
}
+#ifdef HAVE_QCA2
+void CoreSessionEventProcessor::processKeyEvent(KeyEvent *e)
+{
+ if (!Cipher::neededFeaturesAvailable()) {
+ emit newEvent(new MessageEvent(Message::Error, e->network(), tr("Unable to perform key exchange."), e->prefix(), e->target(), Message::None, e->timestamp()));
+ return;
+ }
+ CoreNetwork *net = qobject_cast<CoreNetwork*>(e->network());
+ Cipher *c = net->cipher(e->target());
+ if (!c) // happens when there is no CoreIrcChannel for the target (i.e. never?)
+ return;
+
+ if (e->exchangeType() == KeyEvent::Init) {
+ QByteArray pubKey = c->parseInitKeyX(e->key());
+ if (pubKey.isEmpty()) {
+ emit newEvent(new MessageEvent(Message::Error, e->network(), tr("Unable to parse the DH1080_INIT. Key exchange failed."), e->prefix(), e->target(), Message::None, e->timestamp()));
+ return;
+ } else {
+ net->setCipherKey(e->target(), c->key());
+ emit newEvent(new MessageEvent(Message::Info, e->network(), tr("Your key is set and messages will be encrypted."), e->prefix(), e->target(), Message::None, e->timestamp()));
+ QList<QByteArray> p;
+ p << net->serverEncode(e->target()) << net->serverEncode("DH1080_FINISH ")+pubKey;
+ net->putCmd("NOTICE", p);
+ }
+ } else {
+ if (c->parseFinishKeyX(e->key())) {
+ net->setCipherKey(e->target(), c->key());
+ emit newEvent(new MessageEvent(Message::Info, e->network(), tr("Your key is set and messages will be encrypted."), e->prefix(), e->target(), Message::None, e->timestamp()));
+ } else {
+ emit newEvent(new MessageEvent(Message::Info, e->network(), tr("Failed to parse DH1080_FINISH. Key exchange failed."), e->prefix(), e->target(), Message::None, e->timestamp()));
+ }
+ }
+}
+#endif
+
+
/* RPL_WELCOME */
void CoreSessionEventProcessor::processIrcEvent001(IrcEvent *e)
{
class IrcEventNumeric;
class Netsplit;
+#ifdef HAVE_QCA2
+class KeyEvent;
+#endif
+
class CoreSessionEventProcessor : public BasicHandler
{
Q_OBJECT
Q_INVOKABLE void processIrcEventQuit(IrcEvent *event);
Q_INVOKABLE void lateProcessIrcEventQuit(IrcEvent *event);
Q_INVOKABLE void processIrcEventTopic(IrcEvent *event);
+#ifdef HAVE_QCA2
+ Q_INVOKABLE void processKeyEvent(KeyEvent *event);
+#endif
Q_INVOKABLE void processIrcEvent001(IrcEvent *event); // RPL_WELCOME
Q_INVOKABLE void processIrcEvent005(IrcEvent *event); // RPL_ISUPPORT
}
+void CoreUserInputHandler::handleKeyx(const BufferInfo &bufferInfo, const QString &msg)
+{
+#ifdef HAVE_QCA2
+ if (!bufferInfo.isValid())
+ return;
+
+ if (!Cipher::neededFeaturesAvailable())
+ return;
+
+ QStringList parms = msg.split(' ', QString::SkipEmptyParts);
+
+ if (parms.count() == 0 && !bufferInfo.bufferName().isEmpty())
+ parms.prepend(bufferInfo.bufferName());
+ else if (parms.count() != 1) {
+ emit displayMsg(Message::Info, bufferInfo.bufferName(),
+ tr("[usage] /keyx [<nick|channel>] Initiates a DH1080 key exchange with the target."));
+ return;
+ }
+
+ QString target = parms.at(0);
+
+ Cipher *cipher = network()->cipher(target);
+ if (!cipher) // happens when there is no CoreIrcChannel for the target
+ return;
+
+ QByteArray pubKey = cipher->initKeyExchange();
+ if (pubKey.isEmpty())
+ emit displayMsg(Message::Error, bufferInfo.bufferName(), tr("Failed to initiate key exchange with %1.").arg(target));
+ else {
+ QList<QByteArray> params;
+ params << serverEncode(target) << serverEncode("DH1080_INIT ") + pubKey;
+ emit putCmd("NOTICE", params);
+ emit displayMsg(Message::Info, bufferInfo.bufferName(), tr("Initiated key exchange with %1.").arg(target));
+ }
+#else
+ Q_UNUSED(msg)
+ emit displayMsg(Message::Error, bufferInfo.bufferName(), tr("Error: Setting an encryption key requires Quassel to have been built "
+ "with support for the Qt Cryptographic Architecture (QCA) library. "
+ "Contact your distributor about a Quassel package with QCA "
+ "support, or rebuild Quassel with QCA present."));
+#endif
+}
+
+
void CoreUserInputHandler::handleKick(const BufferInfo &bufferInfo, const QString &msg)
{
QString nick = msg.section(' ', 0, 0, QString::SectionSkipEmpty);
void handleDevoice(const BufferInfo &bufferInfo, const QString &text);
void handleInvite(const BufferInfo &bufferInfo, const QString &text);
void handleJoin(const BufferInfo &bufferInfo, const QString &text);
+ void handleKeyx(const BufferInfo &bufferInfo, const QString &text);
void handleKick(const BufferInfo &bufferInfo, const QString &text);
void handleKill(const BufferInfo &bufferInfo, const QString &text);
void handleList(const BufferInfo &bufferInfo, const QString &text);
#ifdef HAVE_QCA2
# include "cipher.h"
+# include "keyevent.h"
#endif
IrcParser::IrcParser(CoreSession *session) :
if (!net->isChannelName(target))
target = nickFromMask(prefix);
}
- events << new IrcEventRawMessage(EventManager::IrcEventRawNotice, net, params[1], prefix, target, e->timestamp());
+
+#ifdef HAVE_QCA2
+ // Handle DH1080 key exchange
+ if (params[1].startsWith("DH1080_INIT")) {
+ events << new KeyEvent(EventManager::KeyEvent, net, prefix, target, KeyEvent::Init, params[1].mid(12));
+ } else if (params[1].startsWith("DH1080_FINISH")) {
+ events << new KeyEvent(EventManager::KeyEvent, net, prefix, target, KeyEvent::Finish, params[1].mid(14));
+ } else
+#endif
+ events << new IrcEventRawMessage(EventManager::IrcEventRawNotice, net, params[1], prefix, target, e->timestamp());
}
}
break;