security: Introduce hierarchical validator
Change-Id: Ie99abc2b8de4ff227c21e34fef19544c01a9f5dd
diff --git a/src/chat-dialog-backend.cpp b/src/chat-dialog-backend.cpp
index 2644006..f175615 100644
--- a/src/chat-dialog-backend.cpp
+++ b/src/chat-dialog-backend.cpp
@@ -10,8 +10,11 @@
#include "chat-dialog-backend.hpp"
+#include <QFile>
+
#ifndef Q_MOC_RUN
#include <ndn-cxx/util/io.hpp>
+#include <ndn-cxx/security/validator-regex.hpp>
#include "logging.h"
#endif
@@ -29,6 +32,7 @@
const Name& routingPrefix,
const std::string& chatroomName,
const std::string& nick,
+ const Name& signingId,
QObject* parent)
: QThread(parent)
, m_localRoutingPrefix(routingPrefix)
@@ -36,6 +40,7 @@
, m_userChatPrefix(userChatPrefix)
, m_chatroomName(chatroomName)
, m_nick(nick)
+ , m_signingId(signingId)
{
updatePrefixes();
}
@@ -74,14 +79,38 @@
{
BOOST_ASSERT(m_sock == nullptr);
- m_face = unique_ptr<ndn::Face>(new ndn::Face);
+ m_face = make_shared<ndn::Face>();
m_scheduler = unique_ptr<ndn::Scheduler>(new ndn::Scheduler(m_face->getIoService()));
+ // initialize validator
+ shared_ptr<ndn::IdentityCertificate> anchor = loadTrustAnchor();
+
+ if (static_cast<bool>(anchor)) {
+ shared_ptr<ndn::ValidatorRegex> validator =
+ make_shared<ndn::ValidatorRegex>(m_face.get()); // TODO: Change to Face*
+ validator->addDataVerificationRule(
+ make_shared<ndn::SecRuleRelative>("^<>*<%F0.>(<>*)$",
+ "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
+ ">", "\\1", "\\1\\2", true));
+ validator->addDataVerificationRule(
+ make_shared<ndn::SecRuleRelative>("(<>*)$",
+ "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
+ ">", "\\1", "\\1\\2", true));
+ validator->addTrustAnchor(anchor);
+
+ m_validator = validator;
+ }
+ else
+ m_validator = shared_ptr<ndn::Validator>();
+
+
// create a new SyncSocket
m_sock = make_shared<chronosync::Socket>(m_chatroomPrefix,
m_routableUserChatPrefix,
ref(*m_face),
- bind(&ChatDialogBackend::processSyncUpdate, this, _1));
+ bind(&ChatDialogBackend::processSyncUpdate, this, _1),
+ m_signingId,
+ m_validator);
// schedule a new join event
m_scheduler->scheduleEvent(time::milliseconds(600),
@@ -94,6 +123,40 @@
}
}
+class IoDeviceSource
+{
+public:
+ typedef char char_type;
+ typedef boost::iostreams::source_tag category;
+
+ explicit
+ IoDeviceSource(QIODevice& source)
+ : m_source(source)
+ {
+ }
+
+ std::streamsize
+ read(char* buffer, std::streamsize n)
+ {
+ return m_source.read(buffer, n);
+ }
+private:
+ QIODevice& m_source;
+};
+
+shared_ptr<ndn::IdentityCertificate>
+ChatDialogBackend::loadTrustAnchor()
+{
+ QFile anchorFile(":/security/anchor.cert");
+
+ if (!anchorFile.open(QIODevice::ReadOnly)) {
+ return {};
+ }
+
+ boost::iostreams::stream<IoDeviceSource> anchorFileStream(anchorFile);
+ return ndn::io::load<ndn::IdentityCertificate>(anchorFileStream);
+}
+
void
ChatDialogBackend::close()
{
@@ -105,6 +168,7 @@
m_scheduler->cancelAllEvents();
m_helloEventId.reset();
m_roster.clear();
+ m_validator.reset();
m_sock.reset();
}
@@ -131,7 +195,13 @@
if (updates[i].high - updates[i].low < 3) {
for (chronosync::SeqNo seq = updates[i].low; seq <= updates[i].high; ++seq) {
m_sock->fetchData(updates[i].session, seq,
- bind(&ChatDialogBackend::processChatData, this, _1, true),
+ [this] (const shared_ptr<const ndn::Data>& data) {
+ this->processChatData(data, true, true);
+ },
+ [this] (const shared_ptr<const ndn::Data>& data, const std::string& msg) {
+ this->processChatData(data, true, false);
+ },
+ ndn::OnTimeout(),
2);
_LOG_DEBUG("<<< Fetching " << updates[i].session << "/" << seq);
}
@@ -139,7 +209,13 @@
else {
// There are too many msgs to fetch, let's just fetch the latest one
m_sock->fetchData(updates[i].session, updates[i].high,
- bind(&ChatDialogBackend::processChatData, this, _1, false),
+ [this] (const shared_ptr<const ndn::Data>& data) {
+ this->processChatData(data, false, true);
+ },
+ [this] (const shared_ptr<const ndn::Data>& data, const std::string& msg) {
+ this->processChatData(data, false, false);
+ },
+ ndn::OnTimeout(),
2);
}
@@ -156,7 +232,9 @@
}
void
-ChatDialogBackend::processChatData(const ndn::shared_ptr<const ndn::Data>& data, bool needDisplay)
+ChatDialogBackend::processChatData(const ndn::shared_ptr<const ndn::Data>& data,
+ bool needDisplay,
+ bool isValidated)
{
SyncDemo::ChatMessage msg;
@@ -223,10 +301,16 @@
this, remoteSessionPrefix));
// If chat message, notify the frontend
- if (msg.type() == SyncDemo::ChatMessage::CHAT)
- emit chatMessageReceived(QString::fromStdString(msg.from()),
- QString::fromStdString(msg.data()),
- msg.timestamp());
+ if (msg.type() == SyncDemo::ChatMessage::CHAT) {
+ if (isValidated)
+ emit chatMessageReceived(QString::fromStdString(msg.from()),
+ QString::fromStdString(msg.data()),
+ msg.timestamp());
+ else
+ emit chatMessageReceived(QString::fromStdString(msg.from() + " (Unverified)"),
+ QString::fromStdString(msg.data()),
+ msg.timestamp());
+ }
// Notify frontend to plot notification on DigestTree.
emit messageReceived(QString::fromStdString(remoteSessionPrefix.toUri()));