security: Add configuration based validator

configuration file format can be found at: http://redmine.named-data.net/projects/ndn-cpp-dev/wiki/CommandValidatorConf

Change-Id: Icc2725f349aed7513f35f2cccdcd4463fadeef31
diff --git a/src/security/conf/checker.hpp b/src/security/conf/checker.hpp
new file mode 100644
index 0000000..1ec2323
--- /dev/null
+++ b/src/security/conf/checker.hpp
@@ -0,0 +1,481 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SECURITY_CONF_CHECKER_HPP
+#define NDN_SECURITY_CONF_CHECKER_HPP
+
+#include "key-locator-checker.hpp"
+#include "../../util/io.hpp"
+#include <boost/algorithm/string.hpp>
+
+#include "common.hpp"
+
+namespace ndn {
+namespace security {
+namespace conf {
+
+class Checker
+{
+public:
+  typedef function<void(const shared_ptr<const Interest>&)> OnInterestChecked;
+  typedef function<void(const shared_ptr<const Interest>&, const std::string&)> OnInterestCheckFailed;
+  typedef function<void(const shared_ptr<const Data>&)> OnDataChecked;
+  typedef function<void(const shared_ptr<const Data>&, const std::string&)> OnDataCheckFailed;
+
+
+  virtual
+  ~Checker()
+  {
+  }
+
+  /**
+   * @brief check if data satisfies condition defined in the specific checker implementation
+   *
+   * @param data Data packet
+   * @param onValidated Callback function which is called when data is immediately valid
+   * @param onValidationFailed Call function which is called when data is immediately invalid
+   * @return -1 if data is immediately invalid (onValidationFailed has been called)
+   *          1 if data is immediately valid (onValidated has been called)
+   *          0 if further signature verification is needed.
+   */
+  virtual int8_t
+  check(const Data& data,
+        const OnDataChecked& onValidated,
+        const OnDataCheckFailed& onValidationFailed) = 0;
+
+  /**
+   * @brief check if interest satisfies condition defined in the specific checker implementation
+   *
+   * @param interest Interest packet
+   * @param onValidated Callback function which is called when interest is immediately valid
+   * @param onValidationFailed Call function which is called when interest is immediately invalid
+   * @return -1 if interest is immediately invalid (onValidationFailed has been called)
+   *          1 if interest is immediately valid (onValidated has been called)
+   *          0 if further signature verification is needed.
+   */
+  virtual int8_t
+  check(const Interest& interest,
+        const OnInterestChecked& onValidated,
+        const OnInterestCheckFailed& onValidationFailed) = 0;
+};
+
+class CustomizedChecker : public Checker
+{
+  enum
+    {
+      INTEREST_SIG_VALUE = -1,
+      INTEREST_SIG_INFO = -2,
+    };
+
+public:
+  CustomizedChecker(uint32_t sigType,
+                    shared_ptr<KeyLocatorChecker> keyLocatorChecker)
+    : m_sigType(sigType)
+    , m_keyLocatorChecker(keyLocatorChecker)
+  {
+    if (m_sigType == Signature::Sha256WithRsa && !static_cast<bool>(m_keyLocatorChecker))
+      throw Error("Strong signature requires KeyLocatorChecker");
+  }
+
+  virtual int8_t
+  check(const Data& data,
+        const OnDataChecked& onValidated,
+        const OnDataCheckFailed& onValidationFailed)
+  {
+    return check(data, data.getSignature(), onValidated, onValidationFailed);
+  }
+
+  virtual int8_t
+  check(const Interest& interest,
+        const OnInterestChecked& onValidated,
+        const OnInterestCheckFailed& onValidationFailed)
+  {
+    const Name& interestName = interest.getName();
+    Signature signature(interestName[INTEREST_SIG_INFO].blockFromValue(),
+                        interestName[INTEREST_SIG_VALUE].blockFromValue());
+    return check(interest, signature, onValidated, onValidationFailed);
+  }
+
+private:
+  template<class Packet, class OnValidated, class OnFailed>
+  int8_t
+  check(const Packet& packet, const Signature& signature,
+        const OnValidated& onValidated,
+        const OnFailed& onValidationFailed)
+  {
+    if (m_sigType != signature.getType())
+      {
+        onValidationFailed(packet.shared_from_this(),
+                           "Signature type does not match: " +
+                           boost::lexical_cast<std::string>(m_sigType) +
+                           "!=" +
+                           boost::lexical_cast<std::string>(signature.getType()));
+        return -1;
+      }
+
+    switch (signature.getType())
+      {
+      case Signature::Sha256WithRsa:
+        {
+          try
+            {
+              SignatureSha256WithRsa sig(signature);
+
+              std::string failInfo;
+              if (m_keyLocatorChecker->check(packet, sig.getKeyLocator(), failInfo))
+                return 0;
+              else
+                {
+                  onValidationFailed(packet.shared_from_this(), failInfo);
+                  return -1;
+                }
+            }
+          catch (const SignatureSha256WithRsa::Error& e)
+            {
+              onValidationFailed(packet.shared_from_this(),
+                                 "Cannot decode Sha256WithRsa signature!");
+              return -1;
+            }
+        }
+      case Signature::Sha256:
+        return 0;
+      default:
+        {
+          onValidationFailed(packet.shared_from_this(),
+                             "Unsupported signature type: " +
+                             boost::lexical_cast<std::string>(signature.getType()));
+          return -1;
+        }
+      }
+  }
+
+private:
+  uint32_t m_sigType;
+  shared_ptr<KeyLocatorChecker> m_keyLocatorChecker;
+};
+
+class HierarchicalChecker : public CustomizedChecker
+{
+public:
+  HierarchicalChecker(uint32_t sigType)
+    : CustomizedChecker(sigType,
+        make_shared<HyperKeyLocatorNameChecker>("^(<>*)$", "\\1",
+                                                "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
+                                                "\\1\\2",
+                                                KeyLocatorChecker::RELATION_IS_PREFIX_OF))
+  {
+  }
+};
+
+class FixedSignerChecker : public Checker
+{
+  enum
+    {
+      INTEREST_SIG_VALUE = -1,
+      INTEREST_SIG_INFO = -2,
+    };
+public:
+  FixedSignerChecker(uint32_t sigType,
+                     const std::vector<shared_ptr<IdentityCertificate> >& signers)
+    : m_sigType(sigType)
+  {
+    for (std::vector<shared_ptr<IdentityCertificate> >::const_iterator it = signers.begin();
+         it != signers.end(); it++)
+      m_signers[(*it)->getName().getPrefix(-1)] = (*it);
+  }
+
+  virtual int8_t
+  check(const Data& data,
+        const OnDataChecked& onValidated,
+        const OnDataCheckFailed& onValidationFailed)
+  {
+    return check(data, data.getSignature(), onValidated, onValidationFailed);
+  }
+
+  virtual int8_t
+  check(const Interest& interest,
+        const OnInterestChecked& onValidated,
+        const OnInterestCheckFailed& onValidationFailed)
+  {
+    const Name& interestName = interest.getName();
+    Signature signature(interestName[INTEREST_SIG_INFO].blockFromValue(),
+                        interestName[INTEREST_SIG_VALUE].blockFromValue());
+    return check(interest, signature, onValidated, onValidationFailed);
+  }
+
+private:
+  template<class Packet, class OnValidated, class OnFailed>
+  int8_t
+  check(const Packet& packet, const Signature& signature,
+        const OnValidated& onValidated,
+        const OnFailed& onValidationFailed)
+  {
+    if (m_sigType != signature.getType())
+      {
+        onValidationFailed(packet.shared_from_this(),
+                           "Signature type does not match: "
+                           + boost::lexical_cast<std::string>(m_sigType)
+                           + "!="
+                           + boost::lexical_cast<std::string>(signature.getType()));
+        return -1;
+      }
+
+    switch(signature.getType())
+      {
+      case Signature::Sha256WithRsa:
+        {
+          try
+            {
+              SignatureSha256WithRsa sig(signature);
+
+              const Name& keyLocatorName = sig.getKeyLocator().getName();
+              if (m_signers.find(keyLocatorName) == m_signers.end())
+                {
+                  onValidationFailed(packet.shared_from_this(),
+                                     "Signer is not in the fixed signer list: "
+                                     + keyLocatorName.toUri());
+                  return -1;
+                }
+
+              if (Validator::verifySignature(packet, sig,
+                                             m_signers[keyLocatorName]->getPublicKeyInfo()))
+                {
+                  onValidated(packet.shared_from_this());
+                  return 1;
+                }
+              else
+                {
+                  onValidationFailed(packet.shared_from_this(),
+                                     "Signature cannot be validated!");
+                  return -1;
+                }
+            }
+          catch (const KeyLocator::Error& e)
+            {
+              onValidationFailed(packet.shared_from_this(),
+                                 "KeyLocator does not have name!");
+              return -1;
+            }
+          catch (const SignatureSha256WithRsa::Error& e)
+            {
+              onValidationFailed(packet.shared_from_this(),
+                                 "Cannot decode signature!");
+              return -1;
+            }
+        }
+      case Signature::Sha256:
+        {
+          onValidationFailed(packet.shared_from_this(),
+                             "FixedSigner does not allow Sha256 signature type!");
+          return -1;
+        }
+      default:
+        {
+          onValidationFailed(packet.shared_from_this(),
+                             "Unsupported signature type: "
+                             + boost::lexical_cast<std::string>(signature.getType()));
+          return -1;
+        }
+      }
+  }
+
+private:
+  typedef std::map<Name, shared_ptr<IdentityCertificate> > SignerList;
+
+  uint32_t m_sigType;
+  SignerList m_signers;
+};
+
+class CheckerFactory
+{
+public:
+  /**
+   * @brief create a checker from configuration file.
+   *
+   * @param configSection The section containing the definition of checker.
+   * @param configFilename The configuration file name.
+   * @return a shared pointer to the created checker.
+   */
+  static shared_ptr<Checker>
+  create(const ConfigSection& configSection, const std::string& configFilename)
+  {
+    ConfigSection::const_iterator propertyIt = configSection.begin();
+
+    // Get checker.type
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
+      throw Error("Expect <checker.type>!");
+
+    std::string type = propertyIt->second.data();
+
+    if (boost::iequals(type, "customized"))
+      return createCustomizedChecker(configSection, configFilename);
+    else if (boost::iequals(type, "hierarchical"))
+      return createHierarchicalChecker(configSection, configFilename);
+    else if (boost::iequals(type, "fixed-signer"))
+      return createFixedSignerChecker(configSection, configFilename);
+    else
+      throw Error("Unsupported checker type: " + type);
+  }
+
+private:
+  static shared_ptr<Checker>
+  createCustomizedChecker(const ConfigSection& configSection,
+                          const std::string& configFilename)
+  {
+    ConfigSection::const_iterator propertyIt = configSection.begin();
+    propertyIt++;
+
+    // Get checker.sig-type
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type"))
+      throw Error("Expect <checker.sig-type>!");
+
+    std::string sigType = propertyIt->second.data();
+    propertyIt++;
+
+    // Get checker.key-locator
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator"))
+      throw Error("Expect <checker.key-locator>!");
+
+    shared_ptr<KeyLocatorChecker> keyLocatorChecker =
+      KeyLocatorCheckerFactory::create(propertyIt->second, configFilename);
+    propertyIt++;
+
+    if (propertyIt != configSection.end())
+      throw Error("Expect the end of checker!");
+
+    return make_shared<CustomizedChecker>(boost::cref(getSigType(sigType)),
+                                          boost::cref(keyLocatorChecker));
+  }
+
+  static shared_ptr<Checker>
+  createHierarchicalChecker(const ConfigSection& configSection,
+                            const std::string& configFilename)
+  {
+    ConfigSection::const_iterator propertyIt = configSection.begin();
+    propertyIt++;
+
+    // Get checker.sig-type
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type"))
+      throw Error("Expect <checker.sig-type>!");
+
+    std::string sigType = propertyIt->second.data();
+    propertyIt++;
+
+    if (propertyIt != configSection.end())
+      throw Error("Expect the end of checker!");
+
+    return make_shared<HierarchicalChecker>(boost::cref(getSigType(sigType)));
+  }
+
+  static shared_ptr<Checker>
+  createFixedSignerChecker(const ConfigSection& configSection,
+                           const std::string& configFilename)
+  {
+    ConfigSection::const_iterator propertyIt = configSection.begin();
+    propertyIt++;
+
+    // Get checker.sig-type
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type"))
+      throw Error("Expect <checker.sig-type>!");
+
+    std::string sigType = propertyIt->second.data();
+    propertyIt++;
+
+    std::vector<shared_ptr<IdentityCertificate> > signers;
+    for (; propertyIt != configSection.end(); propertyIt++)
+      {
+        if (!boost::iequals(propertyIt->first, "signer"))
+          throw Error("Expect <checker.signer> but get <checker."
+                      + propertyIt->first + ">");
+
+        signers.push_back(getSigner(propertyIt->second, configFilename));
+      }
+
+    if (propertyIt != configSection.end())
+      throw Error("Expect the end of checker!");
+
+    return shared_ptr<FixedSignerChecker>(new FixedSignerChecker(getSigType(sigType),
+                                                                 signers));
+  }
+
+  static shared_ptr<IdentityCertificate>
+  getSigner(const ConfigSection& configSection, const std::string& configFilename)
+  {
+    using namespace boost::filesystem;
+
+    ConfigSection::const_iterator propertyIt = configSection.begin();
+
+    // Get checker.signer.type
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
+      throw Error("Expect <checker.signer.type>!");
+
+    std::string type = propertyIt->second.data();
+    propertyIt++;
+
+    if (boost::iequals(type, "file"))
+      {
+        // Get checker.signer.file-name
+        if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name"))
+          throw Error("Expect <checker.signer.file-name>!");
+
+        path certfilePath = absolute(propertyIt->second.data(),
+                                     path(configFilename).parent_path());
+        propertyIt++;
+
+        if (propertyIt != configSection.end())
+          throw Error("Expect the end of checker.signer");
+
+        shared_ptr<IdentityCertificate> idCert
+          = io::load<IdentityCertificate>(certfilePath.c_str());
+
+        if (static_cast<bool>(idCert))
+          return idCert;
+        else
+          throw Error("Cannot read certificate from file: "
+                      + certfilePath.native());
+      }
+    else if (boost::iequals(type, "base64"))
+      {
+        // Get checker.signer.base64-string
+        if (propertyIt == configSection.end() ||
+            !boost::iequals(propertyIt->first, "base64-string"))
+          throw Error("Expect <checker.signer.base64-string>!");
+
+        std::stringstream ss(propertyIt->second.data());
+        propertyIt++;
+
+        if (propertyIt != configSection.end())
+          throw Error("Expect the end of checker.signer");
+
+        shared_ptr<IdentityCertificate> idCert = io::load<IdentityCertificate>(ss);
+
+        if (static_cast<bool>(idCert))
+          return idCert;
+        else
+          throw Error("Cannot decode certificate from string");
+      }
+    else
+      throw Error("Unsupported checker.signer type: " + type);
+  }
+
+  static int32_t
+  getSigType(const std::string& sigType)
+  {
+    if (boost::iequals(sigType, "rsa-sha256"))
+      return Signature::Sha256WithRsa;
+    else if (boost::iequals(sigType, "sha256"))
+      return Signature::Sha256;
+    else
+      return -1;
+  }
+};
+
+} // namespace conf
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_SEC_CONF_RULE_SIGNER_HPP
diff --git a/src/security/conf/common.hpp b/src/security/conf/common.hpp
new file mode 100644
index 0000000..ba68e2a
--- /dev/null
+++ b/src/security/conf/common.hpp
@@ -0,0 +1,34 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SECURITY_CONF_COMMON_HPP
+#define NDN_SECURITY_CONF_COMMON_HPP
+
+#include <string>
+#include <boost/property_tree/ptree.hpp>
+
+namespace ndn {
+namespace security {
+namespace conf {
+
+typedef boost::property_tree::ptree ConfigSection;
+
+class Error : public std::runtime_error
+{
+public:
+  explicit
+  Error(const std::string& what)
+    : std::runtime_error(what)
+  {
+  }
+};
+
+} // namespace conf
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_CONF_COMMON_HPP
diff --git a/src/security/conf/filter.hpp b/src/security/conf/filter.hpp
new file mode 100644
index 0000000..1db7498
--- /dev/null
+++ b/src/security/conf/filter.hpp
@@ -0,0 +1,224 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SECURITY_CONF_FILTER_HPP
+#define NDN_SECURITY_CONF_FILTER_HPP
+
+#include "../../common.hpp"
+#include "../../data.hpp"
+#include "../../interest.hpp"
+#include "../../util/regex.hpp"
+#include <boost/algorithm/string.hpp>
+
+#include "common.hpp"
+
+namespace ndn {
+namespace security {
+namespace conf {
+
+class Filter
+{
+public:
+  virtual
+  ~Filter()
+  {
+  }
+
+  virtual bool
+  match(const Data& data) = 0;
+
+  virtual bool
+  match(const Interest& interest) = 0;
+};
+
+class RelationNameFilter : public Filter
+{
+public:
+  enum Relation
+    {
+      RELATION_EQUAL,
+      RELATION_IS_PREFIX_OF,
+      RELATION_IS_STRICT_PREFIX_OF,
+    };
+
+  RelationNameFilter(const Name& name, Relation relation)
+    : m_name(name)
+    , m_relation(relation)
+  {
+  }
+
+  virtual
+  ~RelationNameFilter()
+  {
+  }
+
+  virtual bool
+  match(const Data& data)
+  {
+    return match(data.getName());
+  }
+
+  virtual bool
+  match(const Interest& interest)
+  {
+    if (interest.getName().size() < 2)
+      return false;
+
+    Name signedName = interest.getName().getPrefix(-2);
+    return match(signedName);
+  }
+
+private:
+  bool
+  match(const Name& name)
+  {
+    switch (m_relation)
+      {
+      case RELATION_EQUAL:
+        return (name == m_name);
+      case RELATION_IS_PREFIX_OF:
+        return m_name.isPrefixOf(name);
+      case RELATION_IS_STRICT_PREFIX_OF:
+        return (m_name.isPrefixOf(name) && m_name != name);
+      default:
+        return false;
+      }
+  }
+
+private:
+  Name m_name;
+  Relation m_relation;
+};
+
+class RegexNameFilter : public Filter
+{
+public:
+  explicit
+  RegexNameFilter(const Regex& regex)
+    : m_regex(regex)
+  {
+  }
+
+  virtual
+  ~RegexNameFilter()
+  {
+  }
+
+  virtual bool
+  match(const Data& data)
+  {
+    return m_regex.match(data.getName());
+  }
+
+  virtual bool
+  match(const Interest& interest)
+  {
+    if (interest.getName().size() < 2)
+      return false;
+
+    Name signedName = interest.getName().getPrefix(-2);
+    return m_regex.match(signedName);
+  }
+
+private:
+  Regex m_regex;
+};
+
+class FilterFactory
+{
+public:
+  static shared_ptr<Filter>
+  create(const ConfigSection& configSection)
+  {
+    ConfigSection::const_iterator propertyIt = configSection.begin();
+
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
+      throw Error("Expect <filter.type>!");
+
+    std::string type = propertyIt->second.data();
+
+    if (boost::iequals(type, "name"))
+      return createNameFilter(configSection);
+    else
+      throw Error("Unsupported filter.type: " + type);
+  }
+private:
+  static shared_ptr<Filter>
+  createNameFilter(const ConfigSection& configSection)
+  {
+    ConfigSection::const_iterator propertyIt = configSection.begin();
+    propertyIt++;
+
+    if (propertyIt == configSection.end())
+      throw Error("Expect more properties for filter(name)");
+
+    if (boost::iequals(propertyIt->first, "name"))
+      {
+        // Get filter.name
+        Name name;
+        try
+          {
+            name = Name(propertyIt->second.data());
+          }
+        catch (Name::Error& e)
+          {
+            throw Error("Wrong filter.name: " + propertyIt->second.data());
+          }
+
+        propertyIt++;
+
+        // Get filter.relation
+        if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation"))
+          throw Error("Expect <filter.relation>!");
+
+        std::string relationString = propertyIt->second.data();
+        propertyIt++;
+
+        RelationNameFilter::Relation relation;
+        if (boost::iequals(relationString, "equal"))
+          relation = RelationNameFilter::RELATION_EQUAL;
+        else if (boost::iequals(relationString, "is-prefix-of"))
+          relation = RelationNameFilter::RELATION_IS_PREFIX_OF;
+        else if (boost::iequals(relationString, "is-strict-prefix-of"))
+          relation = RelationNameFilter::RELATION_IS_STRICT_PREFIX_OF;
+        else
+          throw Error("Unsupported relation: " + relationString);
+
+
+        if (propertyIt != configSection.end())
+          throw Error("Expect the end of filter!");
+
+        return make_shared<RelationNameFilter>(boost::cref(name),
+                                               boost::cref(relation));
+      }
+    else if (boost::iequals(propertyIt->first, "regex"))
+      {
+        std::string regexString = propertyIt->second.data();
+        propertyIt++;
+
+        if (propertyIt != configSection.end())
+          throw Error("Expect the end of filter!");
+
+        try
+          {
+            return shared_ptr<RegexNameFilter>(new RegexNameFilter(regexString));
+          }
+        catch (const Regex::Error& e)
+          {
+            throw Error("Wrong filter.regex: " + regexString);
+          }
+      }
+    else
+      throw Error("Wrong filter(name) properties");
+  }
+};
+
+} // namespace conf
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_CONF_FILTER_HPP
diff --git a/src/security/conf/key-locator-checker.hpp b/src/security/conf/key-locator-checker.hpp
new file mode 100644
index 0000000..0f667f7
--- /dev/null
+++ b/src/security/conf/key-locator-checker.hpp
@@ -0,0 +1,362 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SECURITY_CONF_KEY_LOCATOR_CHECKER_HPP
+#define NDN_SECURITY_CONF_KEY_LOCATOR_CHECKER_HPP
+
+#include "../../common.hpp"
+#include "../../data.hpp"
+#include "../../interest.hpp"
+#include <boost/algorithm/string.hpp>
+
+#include "common.hpp"
+
+namespace ndn {
+namespace security {
+namespace conf {
+
+class KeyLocatorCheckerFactory;
+
+class KeyLocatorChecker
+{
+public:
+  enum Relation
+    {
+      RELATION_EQUAL,
+      RELATION_IS_PREFIX_OF,
+      RELATION_IS_STRICT_PREFIX_OF,
+    };
+
+  virtual
+  ~KeyLocatorChecker()
+  {
+  }
+
+  bool
+  check(const Data& data,
+        const KeyLocator& keyLocator,
+        std::string& failInfo)
+  {
+    return check(data.getName(), keyLocator, failInfo);
+  }
+
+  bool
+  check(const Interest& interest,
+        const KeyLocator& keyLocator,
+        std::string& failInfo)
+  {
+    if (interest.getName().size() < 2)
+      {
+        failInfo = "No Signature";
+        return false;
+      }
+
+    Name signedName = interest.getName().getPrefix(-2);
+    return check(signedName, keyLocator, failInfo);
+  }
+
+protected:
+
+  virtual bool
+  check(const Name& packetName,
+        const KeyLocator& keyLocator,
+        std::string& failInfo) = 0;
+
+  bool
+  checkRelation(const Relation& relation, const Name& name1, const Name& name2)
+  {
+    switch (relation)
+      {
+      case RELATION_EQUAL:
+        return (name1 == name2);
+      case RELATION_IS_PREFIX_OF:
+        return name1.isPrefixOf(name2);
+      case RELATION_IS_STRICT_PREFIX_OF:
+        return (name1.isPrefixOf(name2) && name1 != name2);
+      default:
+        return false;
+      }
+  }
+};
+
+class RelationKeyLocatorNameChecker : public KeyLocatorChecker
+{
+public:
+  RelationKeyLocatorNameChecker(const Name& name,
+                                const KeyLocatorChecker::Relation& relation)
+    : m_name(name)
+    , m_relation(relation)
+  {
+  }
+
+protected:
+  virtual bool
+  check(const Name& packetName,
+        const KeyLocator& keyLocator,
+        std::string& failInfo)
+  {
+    try
+      {
+        if (checkRelation(m_relation, m_name, keyLocator.getName()))
+          return true;
+
+        failInfo = "KeyLocatorChecker failed!";
+        return false;
+      }
+    catch (const KeyLocator::Error& e)
+      {
+        failInfo = "KeyLocator does not have name";
+        return false;
+      }
+  }
+
+private:
+  Name m_name;
+  KeyLocatorChecker::Relation m_relation;
+};
+
+class RegexKeyLocatorNameChecker : public KeyLocatorChecker
+{
+public:
+  RegexKeyLocatorNameChecker(const Regex& regex)
+    : m_regex(regex)
+  {
+  }
+
+protected:
+  virtual bool
+  check(const Name& packetName,
+        const KeyLocator& keyLocator,
+        std::string& failInfo)
+  {
+    try
+      {
+        if (m_regex.match(keyLocator.getName()))
+          return true;
+
+        failInfo = "KeyLocatorChecker failed!";
+        return false;
+      }
+    catch (const KeyLocator::Error& e)
+      {
+        failInfo = "KeyLocator does not have name";
+        return false;
+      }
+  }
+
+private:
+  Regex m_regex;
+};
+
+class HyperKeyLocatorNameChecker : public KeyLocatorChecker
+{
+public:
+  HyperKeyLocatorNameChecker(const std::string& pExpr, const std::string pExpand,
+                             const std::string& kExpr, const std::string kExpand,
+                             const Relation& hyperRelation)
+    : m_hyperPRegex(new Regex(pExpr, pExpand))
+    , m_hyperKRegex(new Regex(kExpr, kExpand))
+    , m_hyperRelation(hyperRelation)
+  {
+  }
+
+protected:
+  virtual bool
+  check(const Name& packetName,
+        const KeyLocator& keyLocator,
+        std::string& failInfo)
+  {
+    try
+      {
+        if (m_hyperPRegex->match(packetName) &&
+            m_hyperKRegex->match(keyLocator.getName()) &&
+            checkRelation(m_hyperRelation,
+                          m_hyperKRegex->expand(),
+                          m_hyperPRegex->expand()))
+          return true;
+
+        failInfo = "KeyLocatorChecker failed!";
+        return false;
+      }
+    catch (const KeyLocator::Error& e)
+      {
+        failInfo = "KeyLocator does not have name";
+        return false;
+      }
+
+  }
+
+private:
+  shared_ptr<Regex> m_hyperPRegex;
+  shared_ptr<Regex> m_hyperKRegex;
+  Relation m_hyperRelation;
+};
+
+
+class KeyLocatorCheckerFactory
+{
+public:
+  static shared_ptr<KeyLocatorChecker>
+  create(const ConfigSection& configSection, const std::string& filename)
+  {
+    ConfigSection::const_iterator propertyIt = configSection.begin();
+
+    // Get checker.key-locator.type
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
+      throw Error("Expect <checker.key-locator.type>!");
+
+    std::string type = propertyIt->second.data();
+
+    if (boost::iequals(type, "name"))
+      return createKeyLocatorNameChecker(configSection, filename);
+    else
+      throw Error("Unsupported checker.key-locator.type: " + type);
+  }
+
+private:
+  static shared_ptr<KeyLocatorChecker>
+  createKeyLocatorNameChecker(const ConfigSection& configSection,
+                              const std::string& filename)
+  {
+    ConfigSection::const_iterator propertyIt = configSection.begin();
+    propertyIt++;
+
+    if (propertyIt == configSection.end())
+      throw Error("Expect more checker.key-locator properties");
+
+    if (boost::iequals(propertyIt->first, "name"))
+      {
+        Name name;
+        try
+          {
+            name = Name(propertyIt->second.data());
+          }
+        catch (Name::Error& e)
+          {
+            throw Error("Invalid checker.key-locator.name: "
+                        + propertyIt->second.data());
+          }
+        propertyIt++;
+
+        if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation"))
+          throw Error("Expect <checker.key-locator.relation>!");
+
+        std::string relationString = propertyIt->second.data();
+        propertyIt++;
+
+        KeyLocatorChecker::Relation relation;
+        if (boost::iequals(relationString, "equal"))
+          relation = KeyLocatorChecker::RELATION_EQUAL;
+        else if (boost::iequals(relationString, "is-prefix-of"))
+          relation = KeyLocatorChecker::RELATION_IS_PREFIX_OF;
+        else if (boost::iequals(relationString, "is-strict-prefix-of"))
+          relation = KeyLocatorChecker::RELATION_IS_STRICT_PREFIX_OF;
+        else
+          throw Error("Unsupported relation: " + relationString);
+
+        if (propertyIt != configSection.end())
+          throw Error("Expect the end of checker.key-locator!");
+
+        return shared_ptr<RelationKeyLocatorNameChecker>
+          (new RelationKeyLocatorNameChecker(name, relation));
+      }
+    else if (boost::iequals(propertyIt->first, "regex"))
+      {
+        std::string regexString = propertyIt->second.data();
+        propertyIt++;
+
+        if (propertyIt != configSection.end())
+          throw Error("Expect the end of checker.key-locator!");
+
+        try
+          {
+            return shared_ptr<RegexKeyLocatorNameChecker>
+              (new RegexKeyLocatorNameChecker(regexString));
+          }
+        catch (const Regex::Error& e)
+          {
+            throw Error("Invalid checker.key-locator.regex: " + regexString);
+          }
+      }
+    else if (boost::iequals(propertyIt->first, "hyper-relation"))
+      {
+        const ConfigSection& hSection = propertyIt->second;
+
+        ConfigSection::const_iterator hPropertyIt = hSection.begin();
+
+        // Get k-regex
+        if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-regex"))
+          throw Error("Expect <checker.key-locator.hyper-relation.k-regex>!");
+
+        std::string kRegex = hPropertyIt->second.data();
+        hPropertyIt++;
+
+        // Get k-expand
+        if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-expand"))
+          throw Error("Expect <checker.key-locator.hyper-relation.k-expand>!");
+
+        std::string kExpand = hPropertyIt->second.data();
+        hPropertyIt++;
+
+        // Get h-relation
+        if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "h-relation"))
+          throw Error("Expect <checker.key-locator.hyper-relation.h-relation>!");
+
+        std::string hRelation = hPropertyIt->second.data();
+        hPropertyIt++;
+
+        // Get p-regex
+        if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-regex"))
+          throw Error("Expect <checker.key-locator.hyper-relation.p-regex>!");
+
+        std::string pRegex = hPropertyIt->second.data();
+        hPropertyIt++;
+
+        // Get p-expand
+        if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-expand"))
+          throw Error("Expect <checker.key-locator.hyper-relation.p-expand>!");
+
+        std::string pExpand = hPropertyIt->second.data();
+        hPropertyIt++;
+
+        if (hPropertyIt != hSection.end())
+          throw Error("Expect the end of checker.key-locator.hyper-relation!");
+
+        KeyLocatorChecker::Relation relation;
+        if (boost::iequals(hRelation, "equal"))
+          relation = KeyLocatorChecker::RELATION_EQUAL;
+        else if (boost::iequals(hRelation, "is-prefix-of"))
+          relation = KeyLocatorChecker::RELATION_IS_PREFIX_OF;
+        else if (boost::iequals(hRelation, "is-strict-prefix-of"))
+          relation = KeyLocatorChecker::RELATION_IS_STRICT_PREFIX_OF;
+        else
+          throw Error("Unsupported checker.key-locator.hyper-relation.h-relation: "
+                      + hRelation);
+
+        try
+          {
+            return shared_ptr<HyperKeyLocatorNameChecker>
+              (new HyperKeyLocatorNameChecker(pRegex, pExpand,
+                                              kRegex, kExpand,
+                                              relation));
+          }
+        catch (const Regex::Error& e)
+          {
+            throw Error("Invalid regex for key-locator.hyper-relation");
+          }
+      }
+    else
+      throw Error("Unsupported checker.key-locator");
+  }
+};
+
+
+} // namespace conf
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_CONF_KEY_LOCATOR_CHECKER_HPP
diff --git a/src/security/conf/rule.hpp b/src/security/conf/rule.hpp
new file mode 100644
index 0000000..560c440
--- /dev/null
+++ b/src/security/conf/rule.hpp
@@ -0,0 +1,106 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SECURITY_CONF_RULE_HPP
+#define NDN_SECURITY_CONF_RULE_HPP
+
+#include "filter.hpp"
+#include "checker.hpp"
+
+
+namespace ndn {
+namespace security {
+namespace conf {
+
+template<class Packet>
+class Rule
+{
+public:
+  Rule(const std::string& id)
+    : m_id(id)
+  {
+  }
+
+  virtual
+  ~Rule()
+  {
+  }
+
+  const std::string&
+  getId()
+  {
+    return m_id;
+  }
+
+  void
+  addFilter(const shared_ptr<Filter>& filter)
+  {
+    m_filters.push_back(filter);
+  }
+
+  void
+  addChecker(const shared_ptr<Checker>& checker)
+  {
+    m_checkers.push_back(checker);
+  }
+
+  bool
+  match(const Packet& packet)
+  {
+    if (m_filters.empty())
+      return true;
+
+    for (FilterList::iterator it = m_filters.begin();
+         it != m_filters.end(); it++)
+      {
+        if (!(*it)->match(packet))
+          return false;
+      }
+
+    return true;
+  }
+
+  /**
+   * @brief check if packet satisfies certain condition
+   *
+   * @param packet The packet
+   * @param onValidated Callback function which is called when packet is immediately valid
+   * @param onValidationFailed Call function which is called when packet is immediately invalid
+   * @return -1 if packet is immediately invalid (onValidationFailed has been called)
+   *          1 if packet is immediately valid (onValidated has been called)
+   *          0 if further signature verification is needed.
+   */
+  template<class ValidatedCallback, class ValidationFailureCallback>
+  int8_t
+  check(const Packet& packet,
+        const ValidatedCallback& onValidated,
+        const ValidationFailureCallback& onValidationFailed)
+  {
+    for (CheckerList::iterator it = m_checkers.begin();
+         it != m_checkers.end(); it++)
+      {
+        int8_t result = (*it)->check(packet, onValidated, onValidationFailed);
+        if (result >= 0)
+          return result;
+      }
+    return -1;
+  }
+
+private:
+  typedef std::vector<shared_ptr<Filter> > FilterList;
+  typedef std::vector<shared_ptr<Checker> > CheckerList;
+
+  std::string m_id;
+  FilterList m_filters;
+  CheckerList m_checkers;
+};
+
+} // namespace conf
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_CONF_RULE_HPP