security: Add configuration based validator

Change-Id: Ic5837f4b02a613966c0a2e969c974ebd0786f769
diff --git a/src/common.hpp b/src/common.hpp
index 063b82f..650f2de 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -12,6 +12,7 @@
 
 #include <ndn-cpp-dev/face.hpp>
 #include <ndn-cpp-dev/security/key-chain.hpp>
+#include <ndn-cpp-dev/security/validator-config.hpp>
 #include <ndn-cpp-dev/util/scheduler.hpp>
 
 #include <ndn-cpp-dev/management/nfd-controller.hpp>
diff --git a/src/main.cpp b/src/main.cpp
index ce89f3f..e360e5d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -10,7 +10,10 @@
 main(int argc, char** argv)
 {
   try {
-    ndn::nrd::Nrd nrd;
+    // TODO: the configFilename should be obtained from command line arguments.
+    std::string configFilename("nrd.conf");
+
+    ndn::nrd::Nrd nrd(configFilename);
     nrd.enableLocalControlHeader();
     nrd.listen();
   }
diff --git a/src/nrd.cpp b/src/nrd.cpp
index 403a32f..f22c000 100644
--- a/src/nrd.cpp
+++ b/src/nrd.cpp
@@ -38,27 +38,31 @@
 Nrd::setInterestFilterFailed(const Name& name, const std::string& msg)
 {
   std::cerr << "Error in setting interest filter (" << name << "): " << msg << std::endl;
-  m_face.shutdown();
+  m_face->shutdown();
 }
 
-Nrd::Nrd()
-  : m_nfdController(new nfd::Controller(m_face))
+Nrd::Nrd(const std::string& validatorConfig)
+  : m_face(new Face())
+  , m_validator(m_face)
+  , m_nfdController(new nfd::Controller(*m_face))
   , m_verbDispatch(COMMAND_VERBS,
                    COMMAND_VERBS + (sizeof(COMMAND_VERBS) / sizeof(VerbAndProcessor)))
 {
   //check whether the components of localhop and localhost prefixes are same
   BOOST_ASSERT(COMMAND_PREFIX.size() == REMOTE_COMMAND_PREFIX.size());
 
+  m_validator.load(validatorConfig);
+
   std::cerr << "Setting interest filter on: " << COMMAND_PREFIX.toUri() << std::endl;
-  m_face.setController(m_nfdController);
-  m_face.setInterestFilter(COMMAND_PREFIX.toUri(),
-                           bind(&Nrd::onRibRequest, this, _2),
-                           bind(&Nrd::setInterestFilterFailed, this, _1, _2));
+  m_face->setController(m_nfdController);
+  m_face->setInterestFilter(COMMAND_PREFIX.toUri(),
+                            bind(&Nrd::onRibRequest, this, _2),
+                            bind(&Nrd::setInterestFilterFailed, this, _1, _2));
 
   std::cerr << "Setting interest filter on: " << REMOTE_COMMAND_PREFIX.toUri() << std::endl;
-  m_face.setInterestFilter(REMOTE_COMMAND_PREFIX.toUri(),
-                           bind(&Nrd::onRibRequest, this, _2),
-                           bind(&Nrd::setInterestFilterFailed, this, _1, _2));
+  m_face->setInterestFilter(REMOTE_COMMAND_PREFIX.toUri(),
+                            bind(&Nrd::onRibRequest, this, _2),
+                            bind(&Nrd::setInterestFilterFailed, this, _1, _2));
 }
 
 void
@@ -71,7 +75,7 @@
   responseData.setContent(encodedControl);
 
   m_keyChain.sign(responseData);
-  m_face.put(responseData);
+  m_face->put(responseData);
 }
 
 void
@@ -86,24 +90,15 @@
 void
 Nrd::onRibRequest(const Interest& request)
 {
-  const Name& command = request.getName();
-  const size_t commandNComps = command.size();
+  m_validator.validate(request,
+                       bind(&Nrd::onRibRequestValidated, this, _1),
+                       bind(&Nrd::onRibRequestValidationFailed, this, _1, _2));
+}
 
-  if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
-      commandNComps < COMMAND_SIGNED_NCOMPS)
-    {
-      std::cerr << "Error: Signature required" << std::endl;
-      sendResponse(command, 401, "Signature required");
-      return;
-    }
-  else if (commandNComps < COMMAND_SIGNED_NCOMPS ||
-      !(COMMAND_PREFIX.isPrefixOf(command)  ||
-       REMOTE_COMMAND_PREFIX.isPrefixOf(command)))
-  {
-      std::cerr << "Error: Malformed Command" << std::endl;
-      sendResponse(command, 400, "Malformed command");
-      return;
-    }
+void
+Nrd::onRibRequestValidated(const shared_ptr<const Interest>& request)
+{
+  const Name& command = request->getName();
 
   //REMOTE_COMMAND_PREFIX number of componenets are same as
   // NRD_COMMAND_PREFIX's so no extra checks are required.
@@ -113,7 +108,7 @@
   if (verbProcessor != m_verbDispatch.end())
     {
       PrefixRegOptions options;
-      if (!extractOptions(request, options))
+      if (!extractOptions(*request, options))
         {
           sendResponse(command, 400, "Malformed command");
           return;
@@ -122,23 +117,30 @@
       /// \todo authorize command
       if (false)
         {
-          sendResponse(request.getName(), 403, "Unauthorized command");
+          sendResponse(request->getName(), 403, "Unauthorized command");
           return;
         }
 
       // \todo add proper log support
       std::cout << "Received options (name, faceid, cost): " << options.getName() <<
-                   ", " << options.getFaceId() << ", "  << options.getCost() << std::endl;
+        ", " << options.getFaceId() << ", "  << options.getCost() << std::endl;
 
       nfd::ControlResponse response;
-      (verbProcessor->second)(this, request, options);
+      (verbProcessor->second)(this, *request, options);
     }
   else
     {
-      sendResponse(request.getName(), 501, "Unsupported command");
+      sendResponse(request->getName(), 501, "Unsupported command");
     }
 }
 
+void
+Nrd::onRibRequestValidationFailed(const shared_ptr<const Interest>& request,
+                                  const std::string& failureInfo)
+{
+  sendResponse(request->getName(), 403, failureInfo);
+}
+
 bool
 Nrd::extractOptions(const Interest& request,
                     PrefixRegOptions& extractedOptions)
@@ -202,8 +204,8 @@
   response.setBody(options.wireEncode());
 
   std::cout << "Success: Name unregistered (" <<
-                options.getName() << ", " <<
-                options.getFaceId() << ")" << std::endl;
+    options.getName() << ", " <<
+    options.getFaceId() << ")" << std::endl;
   sendResponse(request.getName(), response);
   m_managedRib.erase(options);
 }
@@ -218,7 +220,7 @@
   response.setBody(options.wireEncode());
 
   std::cout << "Success: Name registered (" << options.getName() << ", " <<
-                                               options.getFaceId() << ")" << std::endl;
+    options.getFaceId() << ")" << std::endl;
   sendResponse(request.getName(), response);
 }
 
@@ -232,13 +234,12 @@
   // will add next hops one by one..
   m_managedRib.insert(options);
   m_nfdController->start<nfd::FibAddNextHopCommand>(
-     nfd::ControlParameters()
-       .setName(options.getName())
-       .setFaceId(options.getFaceId())
-       .setCost(options.getCost()),
-     bind(&Nrd::onRegSuccess, this, request, options),
-     bind(&Nrd::onCommandError, this, _1, _2, request, options)
-  );
+    nfd::ControlParameters()
+      .setName(options.getName())
+      .setFaceId(options.getFaceId())
+      .setCost(options.getCost()),
+    bind(&Nrd::onRegSuccess, this, request, options),
+    bind(&Nrd::onCommandError, this, _1, _2, request, options));
 }
 
 
@@ -246,12 +247,11 @@
 Nrd::deleteEntry(const Interest& request, const PrefixRegOptions& options)
 {
   m_nfdController->start<nfd::FibRemoveNextHopCommand>(
-     nfd::ControlParameters()
-       .setName(options.getName())
-       .setFaceId(options.getFaceId()),
-     bind(&Nrd::onUnRegSuccess, this, request, options),
-     bind(&Nrd::onCommandError, this, _1, _2, request, options)
-  );
+    nfd::ControlParameters()
+      .setName(options.getName())
+      .setFaceId(options.getFaceId()),
+    bind(&Nrd::onUnRegSuccess, this, request, options),
+    bind(&Nrd::onCommandError, this, _1, _2, request, options));
 }
 
 
@@ -259,7 +259,7 @@
 Nrd::listen()
 {
   std::cout << "NRD started: listening for incoming interests" << std::endl;
-  m_face.processEvents();
+  m_face->processEvents();
 }
 
 
@@ -275,7 +275,7 @@
 {
   std::cout << "Error: couldn't enable local control header "
             << "(code: " << code << ", info: " << reason << ")" << std::endl;
-  m_face.shutdown();
+  m_face->shutdown();
 }
 
 
@@ -286,8 +286,7 @@
     nfd::ControlParameters()
       .setLocalControlFeature(nfd::LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID),
     bind(&Nrd::onControlHeaderSuccess, this),
-    bind(&Nrd::onControlHeaderError, this, _1, _2)
-  );
+    bind(&Nrd::onControlHeaderError, this, _1, _2));
 }
 
 } // namespace nrd
diff --git a/src/nrd.hpp b/src/nrd.hpp
index 7e1473e..49df0b5 100644
--- a/src/nrd.hpp
+++ b/src/nrd.hpp
@@ -15,7 +15,8 @@
 class Nrd
 {
 public:
-  Nrd();
+  explicit
+  Nrd(const std::string& validatorConfig);
 
   void
   onRibRequest(const Interest& request);
@@ -35,6 +36,14 @@
   sendResponse(const Name& name,
                uint32_t code,
                const std::string& text);
+
+  void
+  onRibRequestValidated(const shared_ptr<const Interest>& request);
+
+  void
+  onRibRequestValidationFailed(const shared_ptr<const Interest>& request,
+                               const std::string& failureInfo);
+
   void
   onCommandError(uint32_t code, const std::string& error,
                  const ndn::Interest& interest,
@@ -66,8 +75,9 @@
                  PrefixRegOptions& extractedOptions);
 private:
   Rib m_managedRib;
-  ndn::Face m_face;
+  ndn::shared_ptr<ndn::Face> m_face;
   ndn::KeyChain m_keyChain;
+  ndn::ValidatorConfig m_validator;
   shared_ptr<nfd::Controller> m_nfdController;
 
   typedef boost::function<void(Nrd*,
diff --git a/validator.conf.sample b/validator.conf.sample
new file mode 100644
index 0000000..224d3d8
--- /dev/null
+++ b/validator.conf.sample
@@ -0,0 +1,40 @@
+rule
+{
+  id "NRD Prefix Registration Command Rule"
+  for interest
+  filter
+  {
+    type name
+    regex ^<localhost><nrd>[<register><unregister>]<>{3}$
+  }
+  checker
+  {
+    type customized
+    sig-type rsa-sha256
+    key-locator
+    {
+      type name
+      regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT>$
+    }
+  }
+}
+rule
+{
+  id "Testbed Hierarchy Rule"
+  for data
+  filter
+  {
+    type name
+    regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT><>$
+  }
+  checker
+  {
+    type hierarchical
+    sig-type rsa-sha256
+  }
+}
+trust-anchor
+{
+  type file
+  file-name "trust-anchor.cert"
+}
\ No newline at end of file