security: Add Validator
Change-Id: Ib97bbb1a95f43684f14f02d0e50b1b6b6f93979b
diff --git a/src/sync-intro-certificate.h b/src/sync-intro-certificate.h
new file mode 100644
index 0000000..48dae45
--- /dev/null
+++ b/src/sync-intro-certificate.h
@@ -0,0 +1,154 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef SYNC_INTRO_CERTIFICATE_H
+#define SYNC_INTRO_CERTIFICATE_H
+
+#include <ndn-cpp-dev/security/identity-certificate.hpp>
+#include <ndn-cpp-dev/security/signature-sha256-with-rsa.hpp>
+
+namespace Sync {
+
+class IntroCertificate : public ndn::Data
+{
+public:
+ struct Error : public ndn::Data::Error { Error(const std::string &what) : ndn::Data::Error(what) {} };
+
+ IntroCertificate()
+ {}
+
+ /**
+ * @brief Construct IntroCertificate from IdentityCertificate
+ *
+ * @param syncPrefix
+ * @param introduceeCert
+ * @param introducerName
+ */
+ IntroCertificate(const ndn::Name& syncPrefix,
+ const ndn::IdentityCertificate& introduceeCert,
+ const ndn::Name& introducerName); //without version number
+
+ /**
+ * @brief Construct IntroCertificate using a plain data.
+ *
+ * if data is not actually IntroCertificate, Error will be thrown out.
+ *
+ * @param data
+ * @throws ndn::IntroCertificate::Error.
+ */
+ IntroCertificate(const ndn::Data& data);
+
+ virtual
+ ~IntroCertificate() {};
+
+ const ndn::IdentityCertificate&
+ getIntroduceeCert() const
+ {
+ return m_introduceeCert;
+ }
+
+ const ndn::Name&
+ getIntroducerName() const
+ {
+ return m_introducerName;
+ }
+
+ const ndn::Name&
+ getIntroduceeName() const
+ {
+ return m_introduceeName;
+ }
+
+private:
+ ndn::Name m_syncPrefix;
+ ndn::IdentityCertificate m_introduceeCert;
+ ndn::Name m_introducerName;
+ ndn::Name m_introduceeName;
+};
+
+inline
+IntroCertificate::IntroCertificate(const ndn::Name& syncPrefix,
+ const ndn::IdentityCertificate& introduceeCert,
+ const ndn::Name& introducerName)
+ : m_syncPrefix(syncPrefix)
+ , m_introduceeCert(introduceeCert)
+ , m_introducerName(introducerName)
+ , m_introduceeName(introduceeCert.getName().getPrefix(-1))
+{
+ // Naming convention /<sync_prefix>/intro-cert/introducee_certname/introducer_certname/version/
+ ndn::Name dataName = m_syncPrefix;
+ dataName.append("intro-cert").append(introduceeCert.getName().getPrefix(-1).wireEncode()).append(introducerName.wireEncode()).appendVersion();
+
+ setName(dataName);
+ setContent(introduceeCert.wireEncode());
+}
+
+inline
+IntroCertificate::IntroCertificate(const ndn::Data& data)
+ : Data(data)
+{
+ ndn::Name dataName = data.getName();
+ ndn::Name introduceeCertName;
+ ndn::Name introducerName;
+
+ if(dataName.size() < 4 || dataName.get(-4).toEscapedString() != "intro-cert")
+ throw Error("Not a Sync::IntroCertificate");
+
+ m_syncPrefix = dataName.getPrefix(-4);
+
+ try
+ {
+ m_introduceeCert.wireDecode(data.getContent().blockFromValue());
+ m_introducerName.wireDecode(dataName.get(-2).blockFromValue());
+ introduceeCertName.wireDecode(dataName.get(-3).blockFromValue());
+ }
+ catch(ndn::IdentityCertificate::Error& e)
+ {
+ throw Error("Cannot decode introducee cert");
+ }
+ catch(ndn::Name::Error& e)
+ {
+ throw Error("Cannot decode name");
+ }
+ catch(ndn::Block::Error& e)
+ {
+ throw Error("Cannot decode block name");
+ }
+
+ if(introduceeCertName != m_introduceeCert.getName().getPrefix(-1))
+ throw Error("Invalid Sync::IntroCertificate (inconsistent introducee name)");
+
+ m_introduceeName = introduceeCertName;
+
+ try
+ {
+ ndn::SignatureSha256WithRsa sig(data.getSignature());
+ introducerName = sig.getKeyLocator().getName();
+ }
+ catch(ndn::KeyLocator::Error& e)
+ {
+ throw Error("Invalid Sync::IntroCertificate (inconsistent introducer name#1)");
+ }
+ catch(ndn::SignatureSha256WithRsa::Error& e)
+ {
+ throw Error("Invalid Sync::IntroCertificate (inconsistent introducer name#2)");
+ }
+
+ if(m_introducerName != introducerName)
+ throw Error("Invalid Sync::IntroCertificate (inconsistent introducer name#3)");
+
+ if(m_introducerName != introducerName)
+ throw Error("Invalid Sync::IntroCertificate (inconsistent introducer name#3)");
+}
+
+
+} // namespace Sync
+
+#endif //SYNC_INTRO_CERTIFICATE_H
diff --git a/src/sync-logic.cc b/src/sync-logic.cc
index ec4d63e..5bbd83c 100644
--- a/src/sync-logic.cc
+++ b/src/sync-logic.cc
@@ -58,6 +58,7 @@
int SyncLogic::m_instanceCounter = 0;
SyncLogic::SyncLogic (const Name& syncPrefix,
+ const Name& identity,
shared_ptr<Validator> validator,
shared_ptr<Face> face,
LogicUpdateCallback onUpdate,
@@ -65,6 +66,7 @@
: m_state (new FullState)
, m_syncInterestTable (*face->ioService(), time::seconds(m_syncInterestReexpress))
, m_syncPrefix (syncPrefix)
+ , m_identity (identity)
, m_onUpdate (onUpdate)
, m_onRemove (onRemove)
, m_perBranch (false)
@@ -89,12 +91,14 @@
}
SyncLogic::SyncLogic (const Name& syncPrefix,
+ const Name& identity,
shared_ptr<Validator> validator,
shared_ptr<Face> face,
LogicPerBranchCallback onUpdateBranch)
: m_state (new FullState)
, m_syncInterestTable (*face->ioService(), time::seconds (m_syncInterestReexpress))
, m_syncPrefix (syncPrefix)
+ , m_identity (identity)
, m_onUpdateBranch (onUpdateBranch)
, m_perBranch(true)
, m_validator(validator)
@@ -164,6 +168,10 @@
{
_LOG_DEBUG_ID ("<< I " << name);
+ if(name.get(m_syncPrefix.size()).toEscapedString() == "intro-cert")
+ // it is a certificate, validator will take care of it.
+ return;
+
DigestConstPtr digest;
string type;
tie (digest, type) = convertNameToDigestAndType (name);
@@ -636,7 +644,7 @@
syncData.setContent(reinterpret_cast<const uint8_t*>(wireData), size);
syncData.setFreshnessPeriod(m_syncResponseFreshness);
- m_keyChain->sign(syncData);
+ m_keyChain->signByIdentity(syncData, m_identity);
m_face->put(syncData);
diff --git a/src/sync-logic.h b/src/sync-logic.h
index fc63fca..423c8d7 100644
--- a/src/sync-logic.h
+++ b/src/sync-logic.h
@@ -77,12 +77,14 @@
* the app data when new remote names are learned
*/
SyncLogic (const ndn::Name& syncPrefix,
+ const ndn::Name& identity,
ndn::shared_ptr<ndn::Validator> validator,
ndn::shared_ptr<ndn::Face> face,
LogicUpdateCallback onUpdate,
LogicRemoveCallback onRemove);
SyncLogic (const ndn::Name& syncPrefix,
+ const ndn::Name& identity,
ndn::shared_ptr<ndn::Validator> validator,
ndn::shared_ptr<ndn::Face> face,
LogicPerBranchCallback onUpdateBranch);
@@ -182,6 +184,7 @@
SyncInterestTable m_syncInterestTable;
ndn::Name m_syncPrefix;
+ ndn::Name m_identity;
LogicUpdateCallback m_onUpdate;
LogicRemoveCallback m_onRemove;
LogicPerBranchCallback m_onUpdateBranch;
diff --git a/src/sync-socket.cc b/src/sync-socket.cc
index f590338..b37d657 100644
--- a/src/sync-socket.cc
+++ b/src/sync-socket.cc
@@ -30,17 +30,20 @@
using ndn::shared_ptr;
-SyncSocket::SyncSocket (const Name &syncPrefix,
+SyncSocket::SyncSocket (const Name& syncPrefix,
+ const Name& identity,
shared_ptr<Validator> validator,
shared_ptr<Face> face,
NewDataCallback dataCallback,
RemoveCallback rmCallback )
: m_newDataCallback(dataCallback)
+ , m_identity(identity)
, m_validator(validator)
, m_keyChain(new KeyChain())
, m_face(face)
, m_ioService(face->ioService())
, m_syncLogic (syncPrefix,
+ identity,
validator,
face,
bind(&SyncSocket::passCallback, this, _1),
@@ -71,7 +74,7 @@
dataName.append(boost::lexical_cast<string>(session)).append(boost::lexical_cast<string>(sequence));
data->setName(dataName);
- m_keyChain->sign(*data);
+ m_keyChain->signByIdentity(*data, m_identity);
m_face->put(*data);
SeqNo s(session, sequence + 1);
diff --git a/src/sync-socket.h b/src/sync-socket.h
index ee02ae8..f796fed 100644
--- a/src/sync-socket.h
+++ b/src/sync-socket.h
@@ -56,7 +56,8 @@
* @param syncPrefix the name prefix for Sync Interest
* @param dataCallback the callback to process data
*/
- SyncSocket (const ndn::Name &syncPrefix,
+ SyncSocket (const ndn::Name& syncPrefix,
+ const ndn::Name& identity,
ndn::shared_ptr<ndn::Validator> validator,
ndn::shared_ptr<ndn::Face> face,
NewDataCallback dataCallback,
@@ -116,6 +117,7 @@
typedef std::map<ndn::Name, SeqNo> SequenceLog;
NewDataCallback m_newDataCallback;
SequenceLog m_sequenceLog;
+ ndn::Name m_identity;
ndn::shared_ptr<ndn::Validator> m_validator;
ndn::shared_ptr<ndn::KeyChain> m_keyChain;
ndn::shared_ptr<ndn::Face> m_face;
diff --git a/src/sync-validator.cc b/src/sync-validator.cc
new file mode 100644
index 0000000..03c292b
--- /dev/null
+++ b/src/sync-validator.cc
@@ -0,0 +1,259 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "sync-validator.h"
+#include "sync-logging.h"
+#include <ndn-cpp-dev/security/certificate-cache-ttl.hpp>
+#include <queue>
+
+using namespace ndn;
+using namespace std;
+
+INIT_LOGGER ("SyncValidator");
+
+namespace Sync {
+
+const shared_ptr<CertificateCache> SyncValidator::DefaultCertificateCache = shared_ptr<CertificateCache>();
+const shared_ptr<SecRuleRelative> SyncValidator::DefaultDataRule = shared_ptr<SecRuleRelative>();
+
+SyncValidator::SyncValidator(const Name& prefix,
+ const IdentityCertificate& anchor,
+ shared_ptr<Face> face,
+ shared_ptr<SecRuleRelative> rule,
+ shared_ptr<CertificateCache> certificateCache,
+ const int stepLimit)
+ : Validator(face)
+ , m_prefix(prefix)
+ , m_anchor(anchor)
+ , m_stepLimit(stepLimit)
+ , m_certificateCache(certificateCache)
+ , m_dataRule(rule)
+{
+ if(!static_cast<bool>(face))
+ throw Error("Face is not set!");
+
+ if(!static_cast<bool>(m_certificateCache))
+ m_certificateCache = make_shared<CertificateCacheTtl>(m_face->ioService());
+
+ Name certPrefix = prefix;
+ certPrefix.append("intro-cert");
+ m_prefixId = m_face->setInterestFilter (certPrefix,
+ bind(&SyncValidator::onCertInterest, this, _1, _2),
+ bind(&SyncValidator::onCertRegisterFailed, this, _1, _2));
+
+ setAnchor(m_anchor);
+}
+
+void
+SyncValidator::deriveTrustNodes()
+{
+ queue<Name> nodeQueue;
+
+ // Clear existing trust nodes.
+ m_trustedNodes.clear();
+
+ // Add the trust anchor.
+ IntroNode origin(m_anchor);
+ m_trustedNodes[origin.name()] = m_anchor.getPublicKeyInfo();
+ nodeQueue.push(origin.name());
+
+ // BFS trusted nodes.
+ while(!nodeQueue.empty())
+ {
+ // Get next trusted node to process.
+ Nodes::const_iterator it = m_introNodes.find(nodeQueue.front());
+ const PublicKey& publicKey = m_trustedNodes[nodeQueue.front()];
+
+ if(it != m_introNodes.end())
+ {
+ // If the trusted node exists in the graph.
+ IntroNode::const_iterator eeIt = it->second.introduceeBegin();
+ IntroNode::const_iterator eeEnd = it->second.introduceeEnd();
+ for(; eeIt != eeEnd; eeIt++)
+ {
+ // Check the nodes introduced by the trusted node.
+ Edges::const_iterator edgeIt = m_introCerts.find(*eeIt);
+ if(edgeIt != m_introCerts.end()
+ && m_trustedNodes.find(edgeIt->second.getIntroduceeName()) == m_trustedNodes.end()
+ && verifySignature(edgeIt->second, publicKey))
+ {
+ // If the introduced node can be validated, add it into trusted node set and the node queue.
+ m_trustedNodes[edgeIt->second.getIntroduceeName()] = edgeIt->second.getIntroduceeCert().getPublicKeyInfo();
+ nodeQueue.push(edgeIt->second.getIntroduceeName());
+ }
+ }
+ }
+ nodeQueue.pop();
+ }
+}
+
+void
+SyncValidator::checkPolicy (const Data& data,
+ int stepCount,
+ const OnDataValidated& onValidated,
+ const OnDataValidationFailed& onValidationFailed,
+ std::vector<shared_ptr<ValidationRequest> >& nextSteps)
+{
+ if(m_stepLimit == stepCount)
+ return onValidationFailed(data.shared_from_this(),
+ "Maximum steps of validation reached: " + data.getName().toUri());
+
+ if(m_prefix.isPrefixOf(data.getName()))
+ {
+ try
+ {
+ SignatureSha256WithRsa sig(data.getSignature());
+ Name keyLocatorName = sig.getKeyLocator().getName();
+
+ TrustNodes::const_iterator it = m_trustedNodes.find(keyLocatorName);
+ if(m_trustedNodes.end() != it)
+ {
+ if(verifySignature(data, sig, it->second))
+ return onValidated(data.shared_from_this());
+ else
+ return onValidationFailed(data.shared_from_this(),
+ "Cannot verify signature: " + data.getName().toUri());
+ }
+ else
+ {
+ Name interestName = m_prefix;
+ interestName.append("intro-cert").append(keyLocatorName.wireEncode());
+ Interest interest(interestName);
+ interest.setInterestLifetime(500);
+
+ OnDataValidated onKeyValidated = bind(&SyncValidator::onCertificateValidated, this,
+ _1, data.shared_from_this(), onValidated, onValidationFailed);
+
+ OnDataValidationFailed onKeyValidationFailed = bind(&SyncValidator::onCertificateValidationFailed, this,
+ _1, _2, data.shared_from_this(), onValidationFailed);
+
+ shared_ptr<ValidationRequest> nextStep = make_shared<ValidationRequest>(interest,
+ onKeyValidated,
+ onKeyValidationFailed,
+ 1,
+ stepCount + 1);
+ nextSteps.push_back(nextStep);
+
+ return;
+ }
+ }
+ catch(SignatureSha256WithRsa::Error& e)
+ {
+ return onValidationFailed(data.shared_from_this(),
+ "Not SignatureSha256WithRsa signature: " + string(e.what()));
+ }
+ catch(KeyLocator::Error& e)
+ {
+ return onValidationFailed(data.shared_from_this(),
+ "Key Locator is not a name: " + data.getName().toUri());
+ }
+ }
+
+ if(static_cast<bool>(m_dataRule) && m_dataRule->satisfy(data))
+ {
+ try
+ {
+ SignatureSha256WithRsa sig(data.getSignature());
+ Name keyLocatorName = sig.getKeyLocator().getName();
+
+ TrustNodes::const_iterator it = m_trustedNodes.find(keyLocatorName);
+ if(m_trustedNodes.end() != it)
+ {
+ if(verifySignature(data, sig, it->second))
+ return onValidated(data.shared_from_this());
+ else
+ return onValidationFailed(data.shared_from_this(),
+ "Cannot verify signature: " + data.getName().toUri());
+ }
+ else
+ return onValidationFailed(data.shared_from_this(),
+ "Signer cannot be trusted: " + keyLocatorName.toUri());
+ }
+ catch(SignatureSha256WithRsa::Error& e)
+ {
+ return onValidationFailed(data.shared_from_this(),
+ "Not SignatureSha256WithRsa signature: " + string(e.what()));
+ }
+ catch(KeyLocator::Error& e)
+ {
+ return onValidationFailed(data.shared_from_this(),
+ "Key Locator is not a name: " + data.getName().toUri());
+ }
+ }
+ else
+ return onValidationFailed(data.shared_from_this(),
+ "No data rule or rule is not satisfied: " + data.getName().toUri());
+}
+
+void
+SyncValidator::checkPolicy (const Interest& interest,
+ int stepCount,
+ const OnInterestValidated& onValidated,
+ const OnInterestValidationFailed& onValidationFailed,
+ std::vector<shared_ptr<ValidationRequest> >& nextSteps)
+{
+ onValidationFailed(interest.shared_from_this(), "No policy for signed interest checking");
+}
+
+void
+SyncValidator::onCertificateValidated(const shared_ptr<const Data>& signCertificate,
+ const shared_ptr<const Data>& data,
+ const OnDataValidated& onValidated,
+ const OnDataValidationFailed& onValidationFailed)
+{
+ try
+ {
+ IntroCertificate introCert(*signCertificate);
+ addParticipant(introCert);
+
+ if(verifySignature(*data, introCert.getIntroduceeCert().getPublicKeyInfo()))
+ return onValidated(data);
+ else
+ return onValidationFailed(data,
+ "Cannot verify signature: " + data->getName().toUri());
+ }
+ catch(IntroCertificate::Error& e)
+ {
+ return onValidationFailed(data,
+ "Intro cert decoding error: " + string(e.what()));
+ }
+}
+
+void
+SyncValidator::onCertificateValidationFailed(const shared_ptr<const Data>& signCertificate,
+ const string& failureInfo,
+ const shared_ptr<const Data>& data,
+ const OnDataValidationFailed& onValidationFailed)
+{
+ onValidationFailed(data, failureInfo);
+}
+
+void
+SyncValidator::onCertInterest(const Name& prefix, const Interest& interest)
+{
+ Name name = interest.getName();
+ Edges::const_iterator it = m_introCerts.begin();
+ for(; it != m_introCerts.end(); it++)
+ {
+ if(name.isPrefixOf(it->first))
+ {
+ m_face->put(it->second);
+ return;
+ }
+ }
+}
+
+void
+SyncValidator::onCertRegisterFailed(const Name& prefix, const string& msg)
+{
+ _LOG_DEBUG("SyncValidator::onCertRegisterFailed: " << msg);
+}
+
+} // namespace Sync
diff --git a/src/sync-validator.h b/src/sync-validator.h
new file mode 100644
index 0000000..b3cff00
--- /dev/null
+++ b/src/sync-validator.h
@@ -0,0 +1,296 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef SYNC_VALIDATOR_H
+#define SYNC_VALIDATOR_H
+
+#include "sync-intro-certificate.h"
+#include <ndn-cpp-dev/security/validator.hpp>
+#include <ndn-cpp-dev/security/key-chain.hpp>
+#include <ndn-cpp-dev/security/sec-rule-relative.hpp>
+#include <ndn-cpp-dev/security/certificate-cache.hpp>
+#include <map>
+
+namespace Sync {
+
+class SyncValidator : public ndn::Validator
+{
+public:
+ struct Error : public ndn::Validator::Error { Error(const std::string &what) : ndn::Validator::Error(what) {} };
+
+ static const ndn::shared_ptr<ndn::CertificateCache> DefaultCertificateCache;
+ static const ndn::shared_ptr<ndn::SecRuleRelative> DefaultDataRule;
+
+ SyncValidator(const ndn::Name& prefix,
+ const ndn::IdentityCertificate& anchor,
+ ndn::shared_ptr<ndn::Face> face,
+ ndn::shared_ptr<ndn::SecRuleRelative> rule = DefaultDataRule,
+ ndn::shared_ptr<ndn::CertificateCache> certificateCache = DefaultCertificateCache,
+ const int stepLimit = 10);
+
+ virtual
+ ~SyncValidator()
+ {
+ m_face->unsetInterestFilter(m_prefixId);
+ }
+
+ /**
+ * @brief Set the trust anchor
+ *
+ * The anchor should be the participant's own certificate.
+ * This anchor node is the origin of the derived trust graph.
+ * Once the new anchor is set, derive the TrustNode set.
+ *
+ * @param anchor.
+ */
+ inline void
+ setAnchor(const ndn::IdentityCertificate& anchor);
+
+ /**
+ * @brief Add a node into the trust graph.
+ *
+ * The method also create an edge from trust anchor to the node.
+ *
+ * @param introducee.
+ * @return IntroCertificate for the introducee.
+ */
+ inline ndn::shared_ptr<const IntroCertificate>
+ addParticipant(const ndn::IdentityCertificate& introducee);
+
+ /**
+ * @brief Add an edge into the trust graph.
+ *
+ * Create nodes if it is one of the edge's ends and does not exist in the graph.
+ *
+ * @param introCert.
+ */
+ inline void
+ addParticipant(const IntroCertificate& introCert);
+
+#ifdef _TEST
+ bool
+ canTrust(const ndn::Name& certName)
+ {
+ return (m_trustedNodes.find(certName.getPrefix(-1)) != m_trustedNodes.end());
+ }
+#endif //_DEBUG
+
+protected:
+ /***********************
+ * From ndn::Validator *
+ ***********************/
+ virtual void
+ checkPolicy (const ndn::Data& data,
+ int stepCount,
+ const ndn::OnDataValidated& onValidated,
+ const ndn::OnDataValidationFailed& onValidationFailed,
+ std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps);
+
+ virtual void
+ checkPolicy (const ndn::Interest& interest,
+ int stepCount,
+ const ndn::OnInterestValidated& onValidated,
+ const ndn::OnInterestValidationFailed& onValidationFailed,
+ std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps);
+private:
+ void
+ deriveTrustNodes();
+
+
+ void
+ onCertificateValidated(const ndn::shared_ptr<const ndn::Data>& signCertificate,
+ const ndn::shared_ptr<const ndn::Data>& data,
+ const ndn::OnDataValidated& onValidated,
+ const ndn::OnDataValidationFailed& onValidationFailed);
+
+ void
+ onCertificateValidationFailed(const ndn::shared_ptr<const ndn::Data>& signCertificate,
+ const std::string& failureInfo,
+ const ndn::shared_ptr<const ndn::Data>& data,
+ const ndn::OnDataValidationFailed& onValidationFailed);
+
+ void
+ onCertInterest (const ndn::Name& prefix, const ndn::Interest& interest);
+
+ void
+ onCertRegisterFailed(const ndn::Name& prefix, const std::string& msg);
+
+private:
+ class IntroNode;
+
+ // Syncprefix
+ ndn::Name m_prefix;
+
+ // The map
+ typedef std::map<const ndn::Name, IntroNode> Nodes;
+ typedef std::map<const ndn::Name, IntroCertificate> Edges;
+ Nodes m_introNodes;
+ Edges m_introCerts;
+
+ // The derived trust info
+ typedef std::map<const ndn::Name, ndn::PublicKey> TrustNodes;
+ ndn::IdentityCertificate m_anchor;
+ TrustNodes m_trustedNodes;
+
+ // others
+ int m_stepLimit;
+ ndn::shared_ptr<ndn::CertificateCache> m_certificateCache;
+ ndn::KeyChain m_keychain;
+ const ndn::RegisteredPrefixId* m_prefixId;
+ ndn::shared_ptr<ndn::SecRuleRelative> m_dataRule;
+
+ class IntroNode
+ {
+ public:
+ typedef std::vector<ndn::Name>::const_iterator const_iterator;
+
+ IntroNode()
+ {}
+
+ IntroNode(const ndn::IdentityCertificate& idCert)
+ : m_nodeName(idCert.getName().getPrefix(-1))
+ {}
+
+ IntroNode(const IntroCertificate& introCert, bool isIntroducer)
+ {
+ if(isIntroducer)
+ {
+ m_nodeName = introCert.getIntroducerName();
+ m_introduceeCerts.push_back(introCert.getName());
+ }
+ else
+ {
+ m_nodeName = introCert.getIntroduceeName();
+ m_introducerCerts.push_back(introCert.getName());
+ }
+ }
+
+ ~IntroNode()
+ {}
+
+ const ndn::Name&
+ name() const
+ {
+ return m_nodeName;
+ }
+
+ const_iterator
+ introducerBegin() const
+ {
+ return m_introducerCerts.begin();
+ }
+
+ const_iterator
+ introducerEnd() const
+ {
+ return m_introducerCerts.end();
+ }
+
+ const_iterator
+ introduceeBegin() const
+ {
+ return m_introduceeCerts.begin();
+ }
+
+ const_iterator
+ introduceeEnd() const
+ {
+ return m_introduceeCerts.end();
+ }
+
+ void
+ addIntroCertAsIntroducer(const ndn::Name& introCertName)
+ {
+ if(std::find(m_introduceeCerts.begin(), m_introduceeCerts.end(), introCertName) == m_introduceeCerts.end())
+ m_introduceeCerts.push_back(introCertName);
+ }
+
+ void
+ addIntroCertAsIntroducee(const ndn::Name& introCertName)
+ {
+ if(std::find(m_introducerCerts.begin(), m_introducerCerts.end(), introCertName) == m_introducerCerts.end())
+ m_introducerCerts.push_back(introCertName);
+ }
+
+ private:
+ ndn::Name m_nodeName;
+ std::vector<ndn::Name> m_introducerCerts;
+ std::vector<ndn::Name> m_introduceeCerts;
+ };
+
+};
+
+inline void
+SyncValidator::setAnchor(const ndn::IdentityCertificate& anchor)
+{
+ m_anchor = anchor;
+
+ // Add anchor into trust graph if it does not exist.
+ IntroNode origin(m_anchor);
+ Nodes::const_iterator nodeIt = m_introNodes.find(origin.name());
+ if(nodeIt == m_introNodes.end())
+ m_introNodes[origin.name()] = origin;
+
+ deriveTrustNodes();
+}
+
+inline void
+SyncValidator::addParticipant(const IntroCertificate& introCert)
+{
+ // Check if the edge has been added before.
+ ndn::Name certName = introCert.getName();
+ Edges::const_iterator edgeIt = m_introCerts.find(certName);
+ if(edgeIt != m_introCerts.end())
+ return; // the edge has been added before.
+
+ m_introCerts[certName] = introCert;
+
+ // Check if the introducer has been added.
+ Nodes::iterator nodeIt = m_introNodes.find(introCert.getIntroducerName());
+ if(nodeIt == m_introNodes.end())
+ {
+ IntroNode node(introCert, true);
+ m_introNodes[node.name()] = node;
+ }
+ else
+ nodeIt->second.addIntroCertAsIntroducer(certName);
+
+ // Check if the introducee has been added.
+ nodeIt = m_introNodes.find(introCert.getIntroduceeName());
+ if(nodeIt == m_introNodes.end())
+ {
+ IntroNode node(introCert, false);
+ m_introNodes[node.name()] = node;
+ }
+ else
+ nodeIt->second.addIntroCertAsIntroducee(certName);
+
+ // Check if the introducer is one of the trusted nodes.
+ TrustNodes::const_iterator trustNodeIt = m_trustedNodes.find(introCert.getIntroducerName());
+ if(trustNodeIt != m_trustedNodes.end() && verifySignature(introCert, trustNodeIt->second))
+ // If the introducee, add it into trusted node set.
+ m_trustedNodes[introCert.getIntroduceeName()] = introCert.getIntroduceeCert().getPublicKeyInfo();
+}
+
+inline ndn::shared_ptr<const IntroCertificate>
+SyncValidator::addParticipant(const ndn::IdentityCertificate& introducee)
+{
+ ndn::shared_ptr<IntroCertificate> introCert = ndn::make_shared<IntroCertificate>(m_prefix, introducee, m_anchor.getName().getPrefix(-1));
+
+ m_keychain.sign(*introCert, m_anchor.getName());
+
+ addParticipant(*introCert);
+
+ return introCert;
+}
+
+} // namespace Sync
+
+#endif //SYNC_VALIDATOR_H