security: Add signing and validating process

Change-Id: Ic9edfcf56f044821e167d7e49b75a9023b67fbcd
diff --git a/src/conf-file-processor.cpp b/src/conf-file-processor.cpp
index 214b3a0..a45199b 100644
--- a/src/conf-file-processor.cpp
+++ b/src/conf-file-processor.cpp
@@ -108,6 +108,10 @@
   {
     ret = processConfSectionAdvertising(SectionAttributeTree);
   }
+  else if (section == "security")
+  {
+    ret = processConfSectionSecurity(SectionAttributeTree);
+  }
   else
   {
     std::cerr << "Wrong configuration Command: " << section << std::endl;
@@ -117,7 +121,7 @@
 
 bool
 ConfFileProcessor::processConfSectionGeneral(boost::property_tree::ptree
-                                            SectionAttributeTree)
+                                             SectionAttributeTree)
 {
   try {
     std::string network = SectionAttributeTree.get<string>("network");
@@ -152,7 +156,7 @@
     cerr << ex.what() << endl;
     return false;
   }
-  
+
   try {
     int32_t lsaRefreshTime = SectionAttributeTree.get<int32_t>("lsa-refresh-time");
     if (lsaRefreshTime >= LSA_REFRESH_TIME_MIN &&
@@ -170,7 +174,7 @@
     std::cerr << ex.what() << std::endl;
     return false;
   }
-  
+
   try {
     std::string logLevel = SectionAttributeTree.get<string>("log-level");
     if ( boost::iequals(logLevel, "info") || boost::iequals(logLevel, "debug")) {
@@ -186,7 +190,7 @@
     std::cerr << ex.what() << std::endl;
     return false;
   }
-  
+
   try {
     std::string logDir = SectionAttributeTree.get<string>("log-dir");
     if (boost::filesystem::exists(logDir)) {
@@ -253,6 +257,7 @@
     std::cerr << ex.what() << std::endl;
     return false;
   }
+
   return true;
 }
 
@@ -308,7 +313,7 @@
   }
   for (boost::property_tree::ptree::const_iterator tn =
            SectionAttributeTree.begin(); tn != SectionAttributeTree.end(); ++tn) {
-      
+
     if (tn->first == "neighbor")
     {
       try {
@@ -362,7 +367,7 @@
     std::cerr << ex.what() << std::endl;
     return false;
   }
-  
+
   try {
     /* Radius and angle is mandatory configuration parameter in hyperbolic section.
      * Even if router can have hyperbolic routing calculation off but other router
@@ -382,7 +387,7 @@
       return false;
     }
   }
-  
+
   return true;
 }
 
@@ -438,4 +443,44 @@
   }
   return true;
 }
+
+bool
+ConfFileProcessor::processConfSectionSecurity(boost::property_tree::ptree section)
+{
+  ConfigSection::const_iterator it = section.begin();
+
+  if (it == section.end() || it->first != "validator")
+    {
+      std::cerr << "Error: Expect validator section!" << std::endl;
+      return false;
+    }
+
+  m_nlsr.loadValidator(it->second, m_confFileName);
+
+  for (; it != section.end(); it++)
+    {
+      using namespace boost::filesystem;
+      if (it->first != "cert-to-publish")
+        {
+          std::cerr << "Error: Expect cert-to-publish!" << std::endl;
+          return false;
+        }
+
+      std::string file = it->second.data();
+      path certfilePath = absolute(file, path(m_confFileName).parent_path());
+      ndn::shared_ptr<ndn::IdentityCertificate> idCert =
+        ndn::io::load<ndn::IdentityCertificate>(certfilePath.string());
+
+      if (!static_cast<bool>(idCert))
+        {
+          std::cerr << "Error: Cannot load cert-to-publish: " << file << "!" << std::endl;
+          return false;
+        }
+
+      m_nlsr.loadCertToPublish(idCert);
+    }
+
+  return true;
+}
+
 }//namespace NLSR
diff --git a/src/conf-file-processor.hpp b/src/conf-file-processor.hpp
index f7d8f1e..cc715b0 100644
--- a/src/conf-file-processor.hpp
+++ b/src/conf-file-processor.hpp
@@ -67,7 +67,12 @@
   bool
   processConfSectionAdvertising(boost::property_tree::ptree SectionAttributeTree);
 
+  bool
+  processConfSectionSecurity(boost::property_tree::ptree SectionAttributeTree);
+
 private:
+  typedef boost::property_tree::ptree ConfigSection;
+
   std::string m_confFileName;
   Nlsr& m_nlsr;
 };
diff --git a/src/hello-protocol.cpp b/src/hello-protocol.cpp
index cd82e27..91b68a9 100644
--- a/src/hello-protocol.cpp
+++ b/src/hello-protocol.cpp
@@ -41,7 +41,7 @@
   i.setInterestLifetime(ndn::time::seconds(seconds));
   i.setMustBeFresh(true);
   m_nlsr.getNlsrFace().expressInterest(i,
-                                       ndn::bind(&HelloProtocol::processContent,
+                                       ndn::bind(&HelloProtocol::onContent,
                                                  this,
                                                  _1, _2),
                                        ndn::bind(&HelloProtocol::processInterestTimedOut,
@@ -90,7 +90,7 @@
     data.setFreshnessPeriod(ndn::time::seconds(10)); // 10 sec
     data.setContent(reinterpret_cast<const uint8_t*>(INFO_COMPONENT.c_str()),
                     INFO_COMPONENT.size());
-    m_keyChain.sign(data);
+    m_nlsr.getKeyChain().sign(data, m_nlsr.getDefaultCertName());
     std::cout << ">> D: " << data << std::endl;
     _LOG_DEBUG("Sending out data for name: " << data.getName());
     m_nlsr.getNlsrFace().put(data);
@@ -148,12 +148,19 @@
   }
 }
 
+void
+HelloProtocol::onContent(const ndn::Interest& interest, const ndn::Data& data)
+{
+  m_nlsr.getValidator().validate(data,
+                                 ndn::bind(&HelloProtocol::onContentValidated, this, _1),
+                                 ndn::bind(&HelloProtocol::onContentValidationFailed,
+                                           this, _1, _2));
+}
 
 void
-HelloProtocol::processContent(const ndn::Interest& interest,
-                              const ndn::Data& data)
+HelloProtocol::onContentValidated(const ndn::shared_ptr<const ndn::Data>& data)
 {
-  ndn::Name dataName = data.getName();
+  ndn::Name dataName = data->getName();
   std::cout << "Data received for name: " << dataName << std::endl;
   _LOG_DEBUG("Data received for name: " << dataName);
   if (dataName.get(-3).toUri() == INFO_COMPONENT) {
@@ -195,4 +202,11 @@
   }
 }
 
+void
+HelloProtocol::onContentValidationFailed(const ndn::shared_ptr<const ndn::Data>& data,
+                                         const std::string& msg)
+{
+  _LOG_DEBUG("Validation Error: " << msg);
+}
+
 } //namespace nlsr
diff --git a/src/hello-protocol.hpp b/src/hello-protocol.hpp
index fc84457..ac0433a 100644
--- a/src/hello-protocol.hpp
+++ b/src/hello-protocol.hpp
@@ -58,11 +58,17 @@
   processInterestTimedOut(const ndn::Interest& interest);
 
   void
-  processContent(const ndn::Interest& interest, const ndn::Data& data);
+  onContent(const ndn::Interest& interest, const ndn::Data& data);
+
+  void
+  onContentValidated(const ndn::shared_ptr<const ndn::Data>& data);
+
+  void
+  onContentValidationFailed(const ndn::shared_ptr<const ndn::Data>& data,
+                            const std::string& msg);
 
 private:
   Nlsr& m_nlsr;
-  ndn::KeyChain m_keyChain;
   static const std::string INFO_COMPONENT;
 };
 
diff --git a/src/lsdb.cpp b/src/lsdb.cpp
index e3d3dd5..bb1150e 100644
--- a/src/lsdb.cpp
+++ b/src/lsdb.cpp
@@ -755,7 +755,7 @@
   interest.setInterestLifetime(ndn::time::seconds(interestLifeTime));
   interest.setMustBeFresh(true);
   m_nlsr.getNlsrFace().expressInterest(interest,
-                                       ndn::bind(&Lsdb::processContent,
+                                       ndn::bind(&Lsdb::onContent,
                                                  this, _1, _2),
                                        ndn::bind(&Lsdb::processInterestTimedOut,
                                                  this, _1, timeoutCount));
@@ -819,8 +819,7 @@
       std::string content = nameLsa->getData();
       data.setContent(reinterpret_cast<const uint8_t*>(content.c_str()),
                       content.size());
-      m_keyChain.sign(data);
-      //std::cout << ">> D: " << data << std::endl;
+      m_nlsr.getKeyChain().sign(data, m_nlsr.getDefaultCertName());
       m_nlsr.getNlsrFace().put(data);
     }
   }
@@ -840,8 +839,7 @@
       std::string content = adjLsa->getData();
       data.setContent(reinterpret_cast<const uint8_t*>(content.c_str()),
                       content.size());
-      m_keyChain.sign(data);
-      //std::cout << ">> D: " << data << std::endl;
+      m_nlsr.getKeyChain().sign(data, m_nlsr.getDefaultCertName());
       m_nlsr.getNlsrFace().put(data);
     }
   }
@@ -861,20 +859,28 @@
       std::string content = corLsa->getData();
       data.setContent(reinterpret_cast<const uint8_t*>(content.c_str()),
                       content.size());
-      m_keyChain.sign(data);
-      //std::cout << ">> D: " << data << std::endl;
+      m_nlsr.getKeyChain().sign(data, m_nlsr.getDefaultCertName());
       m_nlsr.getNlsrFace().put(data);
     }
   }
 }
 
 void
-Lsdb::processContent(const ndn::Interest& interest, const ndn::Data& data)
+Lsdb::onContent(const ndn::Interest& interest, const ndn::Data& data)
 {
-  const ndn::Name& dataName = data.getName();
-  std::cout << "Data received for LSA(name): " << dataName << std::endl;
+  m_nlsr.getValidator().validate(data,
+                                 ndn::bind(&Lsdb::onContentValidated, this, _1),
+                                 ndn::bind(&Lsdb::onContentValidationFailed, this, _1, _2));
+
+}
+
+void
+Lsdb::onContentValidated(const ndn::shared_ptr<const ndn::Data>& data)
+{
+  const ndn::Name& dataName = data->getName();
+  std::cout << "Data received for name: " << dataName << std::endl;
   _LOG_DEBUG("Data received for LSA(name): " << dataName);
-  string dataContent(reinterpret_cast<const char*>(data.getContent().value()));
+  string dataContent(reinterpret_cast<const char*>(data->getContent().value()));
   string chkString("LSA");
   int32_t lsaPosition = util::getNameComponentPosition(dataName, chkString);
   if (lsaPosition >= 0) {
@@ -909,6 +915,12 @@
 }
 
 void
+Lsdb::onContentValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, const std::string& msg)
+{
+  std::cerr << "Validation Error: " << msg << std::endl;
+}
+
+void
 Lsdb::processContentNameLsa(const ndn::Name& lsaKey,
                             uint32_t lsSeqNo, std::string& dataContent)
 {
@@ -1003,4 +1015,3 @@
 }
 
 }//namespace nlsr
-
diff --git a/src/lsdb.hpp b/src/lsdb.hpp
index 56c4245..79d6e2c 100644
--- a/src/lsdb.hpp
+++ b/src/lsdb.hpp
@@ -183,7 +183,13 @@
                                   uint32_t interestedlsSeqNo);
 
   void
-  processContent(const ndn::Interest& interest, const ndn::Data& data);
+  onContent(const ndn::Interest& interest, const ndn::Data& data);
+
+  void
+  onContentValidated(const ndn::shared_ptr<const ndn::Data>& data);
+
+  void
+  onContentValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, const std::string& msg);
 
   void
   processContentNameLsa(const ndn::Name& lsaKey,
@@ -208,7 +214,6 @@
   cancelScheduleLsaExpiringEvent(ndn::EventId eid);
 
   Nlsr& m_nlsr;
-  ndn::KeyChain m_keyChain;
   std::list<NameLsa> m_nameLsdb;
   std::list<AdjLsa> m_adjLsdb;
   std::list<CoordinateLsa> m_corLsdb;
diff --git a/src/nlsr.cpp b/src/nlsr.cpp
index 833b650..02a366b 100644
--- a/src/nlsr.cpp
+++ b/src/nlsr.cpp
@@ -89,7 +89,7 @@
                          (*it).getConnectingFaceUri(), (*it).getLinkCost(), 31536000);
      m_fib.setStrategy((*it).getName(), strategy);
   }
-  
+
   m_fib.setStrategy(m_confParam.getChronosyncPrefix(), strategy);
   m_fib.setStrategy(m_confParam.getLsaPrefix(), strategy);
 }
@@ -123,6 +123,70 @@
   m_syncLogicHandler.createSyncSocket(boost::ref(*this));
   //m_interestManager.scheduleInfoInterest(10);
   m_helloProtocol.scheduleInterest(10);
+
+  intializeKey();
+  registerKeyPrefix();
+}
+
+void
+Nlsr::intializeKey()
+{
+  m_defaultIdentity = m_confParam.getRouterPrefix();
+  m_defaultIdentity.append("NLSR");
+
+  ndn::Name keyName = m_keyChain.generateRsaKeyPairAsDefault(m_defaultIdentity);
+
+  ndn::shared_ptr<ndn::IdentityCertificate> certificate = m_keyChain.selfSign(keyName);
+  m_keyChain.signByIdentity(*certificate, m_confParam.getRouterPrefix());
+
+  m_keyChain.addCertificateAsIdentityDefault(*certificate);
+  loadCertToPublish(certificate);
+
+  m_defaultCertName = certificate->getName();
+}
+
+void
+Nlsr::registerKeyPrefix()
+{
+  ndn::Name keyPrefix = DEFAULT_BROADCAST_PREFIX;
+  keyPrefix.append("KEYS");
+  m_nlsrFace.setInterestFilter(keyPrefix,
+                                  ndn::bind(&Nlsr::onKeyInterest,
+                                            this, _1, _2),
+                                  ndn::bind(&Nlsr::onKeyPrefixRegSuccess, this, _1),
+                                  ndn::bind(&Nlsr::registrationFailed, this, _1));
+
+}
+
+void
+Nlsr::onKeyInterest(const ndn::Name& name, const ndn::Interest& interest)
+{
+  const ndn::Name& interestName = interest.getName();
+
+  ndn::Name certName = interestName.getSubName(name.size());
+
+  if (certName[-2].toUri() == "ID-CERT")
+    {
+      certName = certName.getPrefix(-1);
+    }
+  else if (certName[-1].toUri() != "ID-CERT")
+    return; //Wrong key interest.
+
+  ndn::shared_ptr<const ndn::IdentityCertificate> cert = getCertificate(certName);
+
+  if (!static_cast<bool>(cert))
+    return; // cert is not found
+
+  Data data(interestName);
+  data.setContent(cert->wireEncode());
+  m_keyChain.signWithSha256(data);
+
+  m_nlsrFace.put(data);
+}
+
+void
+Nlsr::onKeyPrefixRegSuccess(const ndn::Name& name)
+{
 }
 
 void
diff --git a/src/nlsr.hpp b/src/nlsr.hpp
index 8db25c2..b0d5126 100644
--- a/src/nlsr.hpp
+++ b/src/nlsr.hpp
@@ -28,6 +28,7 @@
 
 #include <ndn-cxx/face.hpp>
 #include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/security/certificate-cache-ttl.hpp>
 #include <ndn-cxx/util/scheduler.hpp>
 
 #include "conf-parameter.hpp"
@@ -41,9 +42,13 @@
 #include "communication/sync-logic-handler.hpp"
 #include "hello-protocol.hpp"
 
+#include "validator.hpp"
+
 
 namespace nlsr {
 
+static ndn::Name DEFAULT_BROADCAST_PREFIX("/ndn/broadcast");
+
 class Nlsr
 {
   class Error : public std::runtime_error
@@ -75,6 +80,9 @@
     , m_namePrefixTable(*this)
     , m_syncLogicHandler(m_nlsrFace.getIoService())
     , m_helloProtocol(*this)
+
+    , m_certificateCache(new ndn::CertificateCacheTtl(m_nlsrFace.getIoService()))
+    , m_validator(m_nlsrFace, DEFAULT_BROADCAST_PREFIX, m_certificateCache)
   {}
 
   void
@@ -255,11 +263,71 @@
   void
   initialize();
 
+  void
+  intializeKey();
+
+  void
+  loadValidator(boost::property_tree::ptree section,
+                const std::string& filename)
+  {
+    m_validator.load(section, filename);
+  }
+
+  Validator&
+  getValidator()
+  {
+    return m_validator;
+  }
+
+  void
+  loadCertToPublish(ndn::shared_ptr<ndn::IdentityCertificate> certificate)
+  {
+    if (static_cast<bool>(certificate))
+      m_certToPublish[certificate->getName().getPrefix(-1)] = certificate; // key is cert name
+                                                                           // without version
+  }
+
+  ndn::shared_ptr<const ndn::IdentityCertificate>
+  getCertificate(const ndn::Name& certificateNameWithoutVersion)
+  {
+    CertMap::iterator it = m_certToPublish.find(certificateNameWithoutVersion);
+
+    if (it != m_certToPublish.end())
+      {
+        return it->second;
+      }
+
+    return m_certificateCache->getCertificate(certificateNameWithoutVersion);
+  }
+
+  ndn::KeyChain&
+  getKeyChain()
+  {
+    return m_keyChain;
+  }
+
+  const ndn::Name&
+  getDefaultCertName()
+  {
+    return m_defaultCertName;
+  }
+
 private:
   void
   registerPrefixes();
 
+  void
+  registerKeyPrefix();
+
+  void
+  onKeyInterest(const ndn::Name& name, const ndn::Interest& interest);
+
+  void
+  onKeyPrefixRegSuccess(const ndn::Name& name);
+
 private:
+  typedef std::map<ndn::Name, ndn::shared_ptr<ndn::IdentityCertificate> > CertMap;
+
   ndn::Face m_nlsrFace;
   ndn::Scheduler m_scheduler;
   ConfParameter m_confParam;
@@ -279,6 +347,13 @@
   SyncLogicHandler m_syncLogicHandler;
   int32_t m_apiPort;
   HelloProtocol m_helloProtocol;
+
+  ndn::shared_ptr<ndn::CertificateCacheTtl> m_certificateCache;
+  CertMap m_certToPublish;
+  Validator m_validator;
+  ndn::KeyChain m_keyChain;
+  ndn::Name m_defaultIdentity;
+  ndn::Name m_defaultCertName;
 };
 
 } //namespace nlsr
diff --git a/src/validator.hpp b/src/validator.hpp
new file mode 100644
index 0000000..fd4bac8
--- /dev/null
+++ b/src/validator.hpp
@@ -0,0 +1,134 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014  The University of Memphis,
+ *                     Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR 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 3 of the License, or (at your option) any later version.
+ *
+ * NLSR 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
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author Yingdi Yu <yingdi@cs.ucla.edu>
+ **/
+
+#ifndef NLSR_VALIDATOR_HPP
+#define NLSR_VALIDATOR_HPP
+
+#include <ndn-cxx/security/validator-config.hpp>
+
+namespace nlsr {
+
+class Validator : public ndn::ValidatorConfig
+{
+public:
+  class Error : public ndn::ValidatorConfig::Error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : ndn::ValidatorConfig::Error(what)
+    {
+    }
+  };
+
+  explicit
+  Validator(ndn::Face& face,
+            const ndn::Name broadcastPrefix,
+            const ndn::shared_ptr<ndn::CertificateCache>& cache,
+            const int stepLimit = 10)
+    : ndn::ValidatorConfig(face, cache, stepLimit)
+    , m_broadcastPrefix(broadcastPrefix)
+  {
+    m_broadcastPrefix.append("KEYS");
+  }
+
+  virtual
+  ~Validator()
+  {
+  }
+
+  const ndn::Name&
+  getBroadcastPrefix()
+  {
+    return m_broadcastPrefix;
+  }
+
+  void
+  setBroadcastPrefix(const ndn::Name& broadcastPrefix)
+  {
+    m_broadcastPrefix = broadcastPrefix;
+  }
+
+protected:
+  typedef std::vector<ndn::shared_ptr<ndn::ValidationRequest> > NextSteps;
+
+  virtual void
+  checkPolicy(const ndn::Data& data,
+              int nSteps,
+              const ndn::OnDataValidated& onValidated,
+              const ndn::OnDataValidationFailed& onValidationFailed,
+              NextSteps& nextSteps)
+  {
+    ndn::ValidatorConfig::checkPolicy(data, nSteps,
+                                      onValidated, onValidationFailed,
+                                      nextSteps);
+
+    for (NextSteps::iterator it = nextSteps.begin(); it != nextSteps.end(); it++)
+      {
+        ndn::Name broadcastName = m_broadcastPrefix;
+        broadcastName.append((*it)->m_interest.getName());
+
+        (*it)->m_interest.setName(broadcastName);
+      }
+  }
+
+  virtual void
+  checkPolicy(const ndn::Interest& interest,
+              int nSteps,
+              const ndn::OnInterestValidated& onValidated,
+              const ndn::OnInterestValidationFailed& onValidationFailed,
+              NextSteps& nextSteps)
+  {
+    ndn::ValidatorConfig::checkPolicy(interest, nSteps,
+                                      onValidated, onValidationFailed,
+                                      nextSteps);
+
+    for (NextSteps::iterator it = nextSteps.begin(); it != nextSteps.end(); it++)
+      {
+        ndn::Name broadcastName = m_broadcastPrefix;
+        broadcastName.append((*it)->m_interest.getName());
+
+        (*it)->m_interest.setName(broadcastName);
+      }
+
+  }
+
+  void
+  onData(const ndn::Interest& interest,
+         const ndn::Data& data,
+         const ndn::shared_ptr<ndn::ValidationRequest>& nextStep)
+  {
+
+    ndn::shared_ptr<ndn::Data> internalData = ndn::make_shared<ndn::Data>();
+    internalData->wireDecode(data.getContent().blockFromValue());
+    validate(*internalData,
+             nextStep->m_onValidated, nextStep->m_onDataValidated, nextStep->m_nSteps);
+  }
+
+private:
+  ndn::Name m_broadcastPrefix;
+};
+
+
+} // namespace nlsr
+
+#endif // NLSR_VALIDATOR_HPP