security: Add Validator

Change-Id: Ib97bbb1a95f43684f14f02d0e50b1b6b6f93979b
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