add policy checker

Change-Id: I90c50d15b1d9d97832c66ce90e39524729f12a0f
diff --git a/core/conf/checker.cpp b/core/conf/checker.cpp
new file mode 100644
index 0000000..8c63458
--- /dev/null
+++ b/core/conf/checker.cpp
@@ -0,0 +1,176 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "checker.hpp"
+
+#include <boost/algorithm/string.hpp>
+
+namespace nsl {
+namespace conf {
+
+Checker::~Checker()
+{
+}
+
+CustomizedChecker::CustomizedChecker(uint32_t sigType,
+                                     shared_ptr<KeyLocatorChecker> keyLocatorChecker)
+  : m_sigType(sigType)
+  , m_keyLocatorChecker(keyLocatorChecker)
+{
+  switch (sigType) {
+  case tlv::SignatureSha256WithRsa:
+  case tlv::SignatureSha256WithEcdsa:
+    {
+      if (!static_cast<bool>(m_keyLocatorChecker))
+        throw Error("Strong signature requires KeyLocatorChecker");
+
+      return;
+    }
+  case tlv::DigestSha256:
+    return;
+  default:
+    throw Error("Unsupported signature type");
+  }
+}
+
+bool
+CustomizedChecker::check(const Data& data)
+{
+  const Signature signature = data.getSignature();
+  if (m_sigType != signature.getType())
+    return false;
+
+  if (signature.getType() == tlv::DigestSha256)
+    return true;
+
+  try {
+    switch (signature.getType()) {
+    case tlv::SignatureSha256WithRsa:
+    case tlv::SignatureSha256WithEcdsa:
+      {
+        if (!signature.hasKeyLocator())
+          return false;
+        break;
+      }
+    default:
+      return false;
+    }
+  }
+  catch (KeyLocator::Error&) {
+    return false;
+  }
+  catch (tlv::Error& e) {
+    return false;
+  }
+
+  std::string failInfo;
+  return m_keyLocatorChecker->check(data, signature.getKeyLocator(), failInfo);
+}
+
+HierarchicalChecker::HierarchicalChecker(uint32_t sigType)
+  : CustomizedChecker(sigType,
+      make_shared<HyperKeyLocatorNameChecker>("^(<>*)$", "\\1",
+                                              "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
+                                              "\\1\\2",
+                                              KeyLocatorChecker::RELATION_IS_PREFIX_OF))
+{
+}
+
+shared_ptr<Checker>
+CheckerFactory::create(const ConfigSection& configSection)
+{
+  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);
+  else if (boost::iequals(type, "hierarchical"))
+    return createHierarchicalChecker(configSection);
+  else
+    throw Error("Unsupported checker type: " + type);
+}
+
+shared_ptr<Checker>
+CheckerFactory::createCustomizedChecker(const ConfigSection& configSection)
+{
+  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);
+  propertyIt++;
+
+  if (propertyIt != configSection.end())
+    throw Error("Expect the end of checker");
+
+  return make_shared<CustomizedChecker>(getSigType(sigType), keyLocatorChecker);
+}
+
+shared_ptr<Checker>
+CheckerFactory::createHierarchicalChecker(const ConfigSection& configSection)
+{
+  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>(getSigType(sigType));
+}
+
+uint32_t
+CheckerFactory::getSigType(const std::string& sigType)
+{
+  if (boost::iequals(sigType, "rsa-sha256"))
+    return tlv::SignatureSha256WithRsa;
+  else if (boost::iequals(sigType, "ecdsa-sha256"))
+    return tlv::SignatureSha256WithEcdsa;
+  else if (boost::iequals(sigType, "sha256"))
+    return tlv::DigestSha256;
+  else
+    throw Error("Unsupported signature type");
+}
+
+} // namespace conf
+} // namespace nsl
diff --git a/core/conf/checker.hpp b/core/conf/checker.hpp
new file mode 100644
index 0000000..bc253f3
--- /dev/null
+++ b/core/conf/checker.hpp
@@ -0,0 +1,98 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#ifndef NSL_CONF_CHECKER_HPP
+#define NSL_CONF_CHECKER_HPP
+
+#include "common.hpp"
+#include "config.hpp"
+#include "key-locator-checker.hpp"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace nsl {
+namespace conf {
+
+class Checker
+{
+public:
+  virtual
+  ~Checker();
+
+  /**
+   * @brief check if data satisfies condition defined in the specific checker implementation
+   *
+   * @param data Data packet
+   * @return false if data cannot pass checking
+   */
+  virtual bool
+  check(const Data& data) = 0;
+};
+
+class CustomizedChecker : public Checker
+{
+public:
+  CustomizedChecker(uint32_t sigType, shared_ptr<KeyLocatorChecker> keyLocatorChecker);
+
+  virtual bool
+  check(const Data& data);
+
+private:
+  uint32_t m_sigType;
+  shared_ptr<KeyLocatorChecker> m_keyLocatorChecker;
+};
+
+class HierarchicalChecker : public CustomizedChecker
+{
+public:
+  explicit
+  HierarchicalChecker(uint32_t sigType);
+};
+
+class CheckerFactory
+{
+public:
+  /**
+   * @brief create a checker from configuration file.
+   *
+   * @param configSection The section containing the definition of checker.
+   * @return a shared pointer to the created checker.
+   */
+  static shared_ptr<Checker>
+  create(const ConfigSection& configSection);
+
+private:
+  static shared_ptr<Checker>
+  createCustomizedChecker(const ConfigSection& configSection);
+
+  static shared_ptr<Checker>
+  createHierarchicalChecker(const ConfigSection& configSection);
+
+  static uint32_t
+  getSigType(const std::string& sigType);
+};
+
+} // namespace conf
+} // namespace nsl
+
+#endif // NSL_CONF_CHECKER_HPP
diff --git a/core/conf/config.hpp b/core/conf/config.hpp
new file mode 100644
index 0000000..ec3d5f5
--- /dev/null
+++ b/core/conf/config.hpp
@@ -0,0 +1,45 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#ifndef NSL_CONF_CONFIG_HPP
+#define NSL_CONF_CONFIG_HPP
+
+#include <boost/property_tree/ptree.hpp>
+
+namespace nsl {
+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 nsl
+
+#endif // NSL_CONF_CONFIG_HPP
diff --git a/core/conf/filter.cpp b/core/conf/filter.cpp
new file mode 100644
index 0000000..6838d92
--- /dev/null
+++ b/core/conf/filter.cpp
@@ -0,0 +1,158 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+
+#include "filter.hpp"
+
+#include <boost/algorithm/string.hpp>
+
+namespace nsl {
+namespace conf {
+
+Filter::~Filter()
+{
+}
+
+bool
+Filter::match(const Data& data)
+{
+  return matchName(data.getName());
+}
+
+RelationNameFilter::RelationNameFilter(const Name& name, Relation relation)
+  : m_name(name)
+  , m_relation(relation)
+{
+}
+
+RelationNameFilter::~RelationNameFilter()
+{
+}
+
+bool
+RelationNameFilter::matchName(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.size() < name.size());
+  default:
+    return false;
+  }
+}
+
+RegexNameFilter::RegexNameFilter(const ndn::Regex& regex)
+  : m_regex(regex)
+{
+}
+
+RegexNameFilter::~RegexNameFilter()
+{
+}
+
+bool
+RegexNameFilter::matchName(const Name& name)
+{
+  return m_regex.match(name);
+}
+
+shared_ptr<Filter>
+FilterFactory::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);
+}
+
+shared_ptr<Filter>
+FilterFactory::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>(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 filter!");
+
+    try {
+      return shared_ptr<RegexNameFilter>(new RegexNameFilter(regexString));
+    }
+    catch (ndn::Regex::Error& e) {
+      throw Error("Wrong filter.regex: " + regexString);
+    }
+  }
+  else
+    throw Error("Wrong filter(name) properties");
+}
+
+} // namespace conf
+} // namespace ndn
diff --git a/core/conf/filter.hpp b/core/conf/filter.hpp
new file mode 100644
index 0000000..fe399f5
--- /dev/null
+++ b/core/conf/filter.hpp
@@ -0,0 +1,110 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#ifndef NSL_CONF_FILTER_HPP
+#define NSL_CONF_FILTER_HPP
+
+#include "common.hpp"
+#include "config.hpp"
+#include <ndn-cxx/util/regex.hpp>
+
+namespace nsl {
+namespace conf {
+
+/**
+ * @brief Filter is one of the classes used by ValidatorConfig.
+ *
+ * The ValidatorConfig class consists of a set of rules.
+ * The Filter class is a part of a rule and is used to match packet.
+ * Matched packets will be checked against the checkers defined in the rule.
+ */
+
+class Filter
+{
+public:
+
+  virtual
+  ~Filter();
+
+  bool
+  match(const Data& data);
+
+protected:
+  virtual bool
+  matchName(const Name& name) = 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);
+
+  virtual
+  ~RelationNameFilter();
+
+protected:
+  virtual bool
+  matchName(const Name& name);
+
+private:
+  Name m_name;
+  Relation m_relation;
+};
+
+class RegexNameFilter : public Filter
+{
+public:
+  explicit
+  RegexNameFilter(const ndn::Regex& regex);
+
+  virtual
+  ~RegexNameFilter();
+
+protected:
+  virtual bool
+  matchName(const Name& name);
+
+private:
+  ndn::Regex m_regex;
+};
+
+class FilterFactory
+{
+public:
+  static shared_ptr<Filter>
+  create(const ConfigSection& configSection);
+
+private:
+  static shared_ptr<Filter>
+  createNameFilter(const ConfigSection& configSection);
+};
+
+} // namespace conf
+} // namespace ndn
+
+#endif // NSL_CONF_FILTER_HPP
diff --git a/core/conf/key-locator-checker.cpp b/core/conf/key-locator-checker.cpp
new file mode 100644
index 0000000..2fd27bc
--- /dev/null
+++ b/core/conf/key-locator-checker.cpp
@@ -0,0 +1,277 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "key-locator-checker.hpp"
+
+#include <boost/algorithm/string.hpp>
+
+namespace nsl {
+namespace conf {
+
+KeyLocatorChecker::~KeyLocatorChecker()
+{
+}
+
+bool
+KeyLocatorChecker::check(const Data& data, const KeyLocator& keyLocator, std::string& failInfo)
+{
+  return check(data.getName(), keyLocator, failInfo);
+}
+
+bool
+KeyLocatorChecker::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;
+  }
+}
+
+RelationKeyLocatorNameChecker::RelationKeyLocatorNameChecker(const Name& name,
+  const KeyLocatorChecker::Relation& relation)
+  : m_name(name)
+  , m_relation(relation)
+{
+}
+
+bool
+RelationKeyLocatorNameChecker::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 (KeyLocator::Error&) {
+    failInfo = "KeyLocator does not have name";
+    return false;
+  }
+}
+
+RegexKeyLocatorNameChecker::RegexKeyLocatorNameChecker(const ndn::Regex& regex)
+  : m_regex(regex)
+{
+}
+
+bool
+RegexKeyLocatorNameChecker::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 (KeyLocator::Error&) {
+    failInfo = "KeyLocator does not have name";
+    return false;
+  }
+}
+
+HyperKeyLocatorNameChecker::HyperKeyLocatorNameChecker(const std::string& pExpr,
+                                                       const std::string pExpand,
+                                                       const std::string& kExpr,
+                                                       const std::string kExpand,
+                                                       const Relation& hyperRelation)
+  : m_hyperPRegex(new ndn::Regex(pExpr, pExpand))
+  , m_hyperKRegex(new ndn::Regex(kExpr, kExpand))
+  , m_hyperRelation(hyperRelation)
+{
+}
+
+bool
+HyperKeyLocatorNameChecker::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 (KeyLocator::Error&) {
+    failInfo = "KeyLocator does not have name";
+    return false;
+  }
+}
+
+shared_ptr<KeyLocatorChecker>
+KeyLocatorCheckerFactory::create(const ConfigSection& configSection)
+{
+  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);
+  else
+    throw Error("Unsupported checker.key-locator.type: " + type);
+}
+
+shared_ptr<KeyLocatorChecker>
+KeyLocatorCheckerFactory::createKeyLocatorNameChecker(const ConfigSection& configSection)
+{
+  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 (ndn::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 (ndn::Regex::Error& e) {
+      throw Error("Invalid regex for key-locator.hyper-relation");
+    }
+  }
+  else
+    throw Error("Unsupported checker.key-locator");
+}
+
+} // namespace conf
+} // namespace nsl
diff --git a/core/conf/key-locator-checker.hpp b/core/conf/key-locator-checker.hpp
new file mode 100644
index 0000000..921faa2
--- /dev/null
+++ b/core/conf/key-locator-checker.hpp
@@ -0,0 +1,127 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#ifndef NSL_CONF_KEY_LOCATOR_CHECKER_HPP
+#define NSL_CONF_KEY_LOCATOR_CHECKER_HPP
+
+#include "common.hpp"
+#include "config.hpp"
+#include <ndn-cxx/util/regex.hpp>
+
+namespace nsl {
+namespace conf {
+
+class KeyLocatorCheckerFactory;
+
+/**
+ * @brief KeyLocatorChecker is one of the classes used by ValidatorConfig.
+ *
+ * The ValidatorConfig class consists of a set of rules.
+ * The KeyLocatorChecker class is part of a rule and is used to check if the KeyLocator field of a
+ * packet satisfy the requirements.
+ */
+
+
+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);
+
+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);
+};
+
+class RelationKeyLocatorNameChecker : public KeyLocatorChecker
+{
+public:
+  RelationKeyLocatorNameChecker(const Name& name, const KeyLocatorChecker::Relation& relation);
+
+protected:
+  virtual bool
+  check(const Name& packetName, const KeyLocator& keyLocator, std::string& failInfo);
+
+private:
+  Name m_name;
+  KeyLocatorChecker::Relation m_relation;
+};
+
+class RegexKeyLocatorNameChecker : public KeyLocatorChecker
+{
+public:
+  explicit
+  RegexKeyLocatorNameChecker(const ndn::Regex& regex);
+
+protected:
+  virtual bool
+  check(const Name& packetName, const KeyLocator& keyLocator, std::string& failInfo);
+
+private:
+  ndn::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);
+
+protected:
+  virtual bool
+  check(const Name& packetName, const KeyLocator& keyLocator, std::string& failInfo);
+
+private:
+  shared_ptr<ndn::Regex> m_hyperPRegex;
+  shared_ptr<ndn::Regex> m_hyperKRegex;
+  Relation m_hyperRelation;
+};
+
+
+class KeyLocatorCheckerFactory
+{
+public:
+  static shared_ptr<KeyLocatorChecker>
+  create(const ConfigSection& configSection);
+
+private:
+  static shared_ptr<KeyLocatorChecker>
+  createKeyLocatorNameChecker(const ConfigSection& configSection);
+};
+
+
+} // namespace conf
+} // namespace nsl
+
+#endif // NSL_CONF_KEY_LOCATOR_CHECKER_HPP
diff --git a/core/conf/rule.cpp b/core/conf/rule.cpp
new file mode 100644
index 0000000..a4b571f
--- /dev/null
+++ b/core/conf/rule.cpp
@@ -0,0 +1,81 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "rule.hpp"
+
+namespace nsl {
+namespace conf {
+
+Rule::Rule(const std::string& id)
+  : m_id(id)
+{
+}
+
+Rule::~Rule()
+{
+}
+
+const std::string&
+Rule::getId()
+{
+  return m_id;
+}
+
+void
+Rule::addFilter(const shared_ptr<Filter>& filter)
+{
+  m_filters.push_back(filter);
+}
+
+void
+Rule::addChecker(const shared_ptr<Checker>& checker)
+{
+  m_checkers.push_back(checker);
+}
+
+bool
+Rule::match(const Data& data)
+{
+  if (m_filters.empty())
+    return true;
+
+  for (auto& filter : m_filters) {
+    if (!filter->match(data))
+      return false;
+  }
+
+  return true;
+}
+
+bool
+Rule::check(const Data& data)
+{
+  for (auto& checker : m_checkers) {
+    bool result = checker->check(data);
+    if (result)
+      return result;
+  }
+
+  return false;
+}
+
+} // namespace conf
+} // namespace nsl
diff --git a/core/conf/rule.hpp b/core/conf/rule.hpp
new file mode 100644
index 0000000..5ec229f
--- /dev/null
+++ b/core/conf/rule.hpp
@@ -0,0 +1,73 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#ifndef NSL_CONF_RULE_HPP
+#define NSL_CONF_RULE_HPP
+
+#include "filter.hpp"
+#include "checker.hpp"
+
+namespace nsl {
+namespace conf {
+
+class Rule
+{
+public:
+  explicit
+  Rule(const std::string& id);
+
+  virtual
+  ~Rule();
+
+  const std::string&
+  getId();
+
+  void
+  addFilter(const shared_ptr<Filter>& filter);
+
+  void
+  addChecker(const shared_ptr<Checker>& checker);
+
+  bool
+  match(const Data& data);
+
+  /**
+   * @brief check if data satisfies certain condition
+   *
+   * @param packet The packet
+   * @return false if data is immediately invalid
+   */
+  bool
+  check(const Data& data);
+
+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 nsl
+
+#endif // NSL_CONF_RULE_HPP
diff --git a/core/policy-checker.cpp b/core/policy-checker.cpp
new file mode 100644
index 0000000..b0d6531
--- /dev/null
+++ b/core/policy-checker.cpp
@@ -0,0 +1,170 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "policy-checker.hpp"
+#include <ndn-cxx/util/time.hpp>
+#include <ndn-cxx/security/validator.hpp>
+#include <boost/algorithm/string.hpp>
+
+namespace nsl {
+
+using ndn::time::system_clock;
+
+PolicyChecker::PolicyChecker()
+{
+}
+
+void
+PolicyChecker::reset()
+{
+  m_dataRules.clear();
+}
+
+void
+PolicyChecker::loadPolicy(const conf::ConfigSection& configSection)
+{
+  reset();
+
+  for (const auto& section : configSection) {
+    if (boost::iequals(section.first, "rule")) {
+      onConfigRule(section.second);
+    }
+    else
+      throw Error("Error in loading policy checker: unrecognized section " + section.first);
+  }
+}
+
+void
+PolicyChecker::onConfigRule(const conf::ConfigSection& section)
+{
+  using namespace nsl::conf;
+
+  auto it = section.begin();
+
+  // Get rule.id
+  if (it == section.end() || !boost::iequals(it->first, "id"))
+    throw Error("Expect <rule.id>");
+
+  std::string ruleId = it->second.data();
+  it++;
+
+  // Get rule.for
+  if (it == section.end() || !boost::iequals(it->first, "for"))
+    throw Error("Expect <rule.for> in rule: " + ruleId);
+
+  std::string usage = it->second.data();
+  it++;
+
+  bool isForData;
+  if (boost::iequals(usage, "data"))
+    isForData = true;
+  else if (boost::iequals(usage, "interest"))
+    isForData = false;
+  else
+    throw Error("Unrecognized <rule.for>: " + usage + " in rule: " + ruleId);
+
+  // Get rule.filter(s)
+  std::vector<shared_ptr<Filter> > filters;
+  for (; it != section.end(); it++) {
+    if (!boost::iequals(it->first, "filter")) {
+      if (boost::iequals(it->first, "checker"))
+        break;
+      throw Error("Expect <rule.filter> in rule: " + ruleId);
+    }
+
+    filters.push_back(FilterFactory::create(it->second));
+    continue;
+  }
+
+  // Get rule.checker(s)
+  std::vector<shared_ptr<Checker> > checkers;
+  for (; it != section.end(); it++) {
+    if (!boost::iequals(it->first, "checker"))
+      throw Error("Expect <rule.checker> in rule: " + ruleId);
+
+    checkers.push_back(CheckerFactory::create(it->second));
+    continue;
+  }
+
+  // Check other stuff
+  if (it != section.end())
+    throw Error("Expect the end of rule: " + ruleId);
+
+  if (checkers.size() == 0)
+    throw Error("No <rule.checker> is specified in rule: " + ruleId);
+
+  if (isForData) {
+    auto rule = make_shared<conf::Rule>(ruleId);
+    for (size_t i = 0; i < filters.size(); i++)
+      rule->addFilter(filters[i]);
+    for (size_t i = 0; i < checkers.size(); i++)
+      rule->addChecker(checkers[i]);
+
+    m_dataRules.push_back(rule);
+  }
+}
+
+bool
+PolicyChecker::check(const Timestamp& dataTimestamp, const Data& data,
+                     const Timestamp& keyTimestamp, const ndn::IdentityCertificate& cert)
+{
+  system_clock::TimePoint dataTs((time::seconds(dataTimestamp)));
+  system_clock::TimePoint keyTs((time::seconds(keyTimestamp)));
+  system_clock::TimePoint endTs = cert.getNotAfter();
+  system_clock::TimePoint startTs = cert.getNotBefore();
+
+  if (dataTs > endTs || dataTs < keyTs || dataTs < startTs)
+    return false;
+
+  if (!checkRule(data))
+    return false;
+
+  Name keyLocatorName;
+  try {
+    keyLocatorName = data.getSignature().getKeyLocator().getName();
+  }
+  catch (tlv::Error&) {
+    return false;
+  }
+
+  if (!keyLocatorName.isPrefixOf(cert.getName()))
+    return false;
+
+  if (!ndn::Validator::verifySignature(data, cert.getPublicKeyInfo()))
+    return false;
+
+  return true;
+}
+
+bool
+PolicyChecker::checkRule(const Data& data)
+{
+  for (auto& rule : m_dataRules) {
+    if (rule->match(data)) {
+      return rule->check(data);
+    }
+  }
+
+  return false;
+}
+
+
+} // namespace nsl
diff --git a/core/policy-checker.hpp b/core/policy-checker.hpp
new file mode 100644
index 0000000..8eea548
--- /dev/null
+++ b/core/policy-checker.hpp
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#ifndef NSL_CORE_POLICY_CHECKER_HPP
+#define NSL_CORE_POLICY_CHECKER_HPP
+
+#include "common.hpp"
+#include "db.hpp"
+#include "util/non-negative-integer.hpp"
+#include "conf/config.hpp"
+#include "conf/rule.hpp"
+#include <ndn-cxx/security/identity-certificate.hpp>
+
+
+namespace nsl {
+
+class PolicyChecker
+{
+public:
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
+  };
+
+public:
+  PolicyChecker();
+
+  void
+  reset();
+
+  void
+  loadPolicy(const conf::ConfigSection& policy);
+
+  bool
+  check(const Timestamp& dataTimestamp, const Data& data,
+        const Timestamp& keyTimestamp, const ndn::IdentityCertificate& cert);
+private:
+
+  void
+  onConfigRule(const conf::ConfigSection& section);
+
+  bool
+  checkRule(const Data& data);
+
+private:
+  typedef std::vector<shared_ptr<conf::Rule>> DataRuleList;
+
+  DataRuleList m_dataRules;
+};
+
+} // namespace nsl
+
+#endif // NSL_CORE_POLICY_CHECKER_HPP
diff --git a/tests/core/identity-fixture.hpp b/tests/core/identity-fixture.hpp
new file mode 100644
index 0000000..3ea68f6
--- /dev/null
+++ b/tests/core/identity-fixture.hpp
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#ifndef NSL_TESTS_IDENTITY_FIXTURE_HPP
+#define NSL_TESTS_IDENTITY_FIXTURE_HPP
+
+#include "unit-test-time-fixture.hpp"
+#include <ndn-cxx/security/key-chain.hpp>
+#include <vector>
+
+#include <boost/filesystem.hpp>
+
+namespace nsl {
+namespace tests {
+
+class IdentityFixture : public UnitTestTimeFixture
+{
+public:
+  IdentityFixture()
+    : m_keyChainTmpPath(boost::filesystem::path(TEST_KEYCHAIN_PATH) / "IdentityFixture")
+    , m_keyChain(std::string("pib-sqlite3:").append(m_keyChainTmpPath.string()),
+                 std::string("tpm-file:").append(m_keyChainTmpPath.string()))
+  {
+  }
+
+  ~IdentityFixture()
+  {
+    for (const auto& identity : m_identities) {
+      m_keyChain.deleteIdentity(identity);
+    }
+
+    boost::filesystem::remove_all(m_keyChainTmpPath);
+  }
+  /// @brief add identity, return true if succeed.
+  bool
+  addIdentity(const Name& identity,
+              const ndn::KeyParams& params = ndn::KeyChain::DEFAULT_KEY_PARAMS)
+  {
+    try {
+      m_keyChain.createIdentity(identity, params);
+      m_identities.push_back(identity);
+      return true;
+    }
+    catch (std::runtime_error&) {
+      return false;
+    }
+  }
+
+protected:
+  boost::filesystem::path m_keyChainTmpPath;
+  ndn::KeyChain m_keyChain;
+  std::vector<Name> m_identities;
+};
+
+} // namespace tests
+} // namespace nsl
+
+#endif // NSL_TESTS_IDENTITY_FIXTURE_HPP
diff --git a/tests/core/policy-checker.t.cpp b/tests/core/policy-checker.t.cpp
new file mode 100644
index 0000000..75c2ef4
--- /dev/null
+++ b/tests/core/policy-checker.t.cpp
@@ -0,0 +1,193 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "policy-checker.hpp"
+#include "identity-fixture.hpp"
+#include <boost/property_tree/info_parser.hpp>
+
+#include "boost-test.hpp"
+
+namespace nsl {
+namespace tests {
+
+BOOST_FIXTURE_TEST_SUITE(TestPolicyChecker, IdentityFixture)
+
+BOOST_AUTO_TEST_CASE(TimeCheck)
+{
+  const std::string CONFIG =
+    "rule                                               \n"
+    "{                                                  \n"
+    "  id \"Simple Rule\"                               \n"
+    "  for data                                         \n"
+    "  checker                                          \n"
+    "  {                                                \n"
+    "    type customized                                \n"
+    "    sig-type rsa-sha256                            \n"
+    "    key-locator                                    \n"
+    "    {                                              \n"
+    "      type name                                    \n"
+    "      hyper-relation                               \n"
+    "      {                                            \n"
+    "        k-regex ^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$ \n"
+    "        k-expand \\\\1\\\\2                        \n"
+    "        h-relation is-strict-prefix-of             \n"
+    "        p-regex ^(<>*)$                            \n"
+    "        p-expand \\\\1                             \n"
+    "      }                                            \n"
+    "    }                                              \n"
+    "  }                                                \n"
+    "}                                                  \n";
+
+  std::istringstream input(CONFIG);
+  conf::ConfigSection policy;
+  BOOST_REQUIRE_NO_THROW(boost::property_tree::read_info(input, policy));
+
+  PolicyChecker policyChecker;
+  policyChecker.loadPolicy(policy);
+
+  Name identity("/test/id");
+  addIdentity(identity);
+  Name selfSignedCertName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
+  auto selfSignedCert = m_keyChain.getCertificate(selfSignedCertName);
+
+  time::system_clock::TimePoint notBefore = time::system_clock::now();
+  time::system_clock::TimePoint notAfter = time::system_clock::now() + time::seconds(10);
+  std::vector<ndn::CertificateSubjectDescription> subDesc;
+
+  auto unsignedCert =
+    m_keyChain.prepareUnsignedIdentityCertificate(selfSignedCert->getPublicKeyName(),
+                                                  selfSignedCert->getPublicKeyInfo(),
+                                                  identity,
+                                                  notBefore,
+                                                  notAfter,
+                                                  subDesc);
+
+  m_keyChain.sign(*unsignedCert, selfSignedCertName);
+  m_keyChain.addCertificate(*unsignedCert);
+
+  time::system_clock::TimePoint dataTs1 = time::system_clock::now() + time::seconds(5);
+  time::system_clock::TimePoint dataTs2 = time::system_clock::now() + time::seconds(1);
+  time::system_clock::TimePoint dataTs3 = time::system_clock::now() + time::seconds(15);
+  time::system_clock::TimePoint dataTs4 = time::system_clock::now() - time::seconds(1);
+  time::system_clock::TimePoint keyTs1 = time::system_clock::now() + time::seconds(2);
+  time::system_clock::TimePoint keyTs2 = time::system_clock::now() - time::seconds(2);
+  Timestamp dataTimestamp1 = time::toUnixTimestamp(dataTs1).count() / 1000;
+  Timestamp dataTimestamp2 = time::toUnixTimestamp(dataTs2).count() / 1000;
+  Timestamp dataTimestamp3 = time::toUnixTimestamp(dataTs3).count() / 1000;
+  Timestamp dataTimestamp4 = time::toUnixTimestamp(dataTs4).count() / 1000;
+  Timestamp keyTimestamp1 = time::toUnixTimestamp(keyTs1).count() / 1000;
+  Timestamp keyTimestamp2 = time::toUnixTimestamp(keyTs2).count() / 1000;
+
+  Data data("/test/id/data");
+  m_keyChain.sign(data, unsignedCert->getName());
+
+  BOOST_CHECK_EQUAL(policyChecker.check(dataTimestamp1, data, keyTimestamp1, *unsignedCert), true);
+  BOOST_CHECK_EQUAL(policyChecker.check(dataTimestamp2, data, keyTimestamp1, *unsignedCert), false);
+  BOOST_CHECK_EQUAL(policyChecker.check(dataTimestamp3, data, keyTimestamp1, *unsignedCert), false);
+  BOOST_CHECK_EQUAL(policyChecker.check(dataTimestamp4, data, keyTimestamp2, *unsignedCert), false);
+}
+
+BOOST_AUTO_TEST_CASE(RuleCheck)
+{
+  const std::string CONFIG =
+    "rule                                               \n"
+    "{                                                  \n"
+    "  id \"Simple Rule\"                               \n"
+    "  for data                                         \n"
+    "  checker                                          \n"
+    "  {                                                \n"
+    "    type customized                                \n"
+    "    sig-type rsa-sha256                            \n"
+    "    key-locator                                    \n"
+    "    {                                              \n"
+    "      type name                                    \n"
+    "      hyper-relation                               \n"
+    "      {                                            \n"
+    "        k-regex ^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$ \n"
+    "        k-expand \\\\1\\\\2                        \n"
+    "        h-relation is-strict-prefix-of             \n"
+    "        p-regex ^(<>*)$                            \n"
+    "        p-expand \\\\1                             \n"
+    "      }                                            \n"
+    "    }                                              \n"
+    "  }                                                \n"
+    "}                                                  \n";
+
+  std::istringstream input(CONFIG);
+  conf::ConfigSection policy;
+  BOOST_REQUIRE_NO_THROW(boost::property_tree::read_info(input, policy));
+
+  PolicyChecker policyChecker;
+  policyChecker.loadPolicy(policy);
+
+
+  Name identity("/test/id");
+  addIdentity(identity);
+  Name selfSignedCertName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
+  auto selfSignedCert = m_keyChain.getCertificate(selfSignedCertName);
+
+  time::system_clock::TimePoint notBefore = time::system_clock::now();
+  time::system_clock::TimePoint notAfter = time::system_clock::now() + time::seconds(10);
+  std::vector<ndn::CertificateSubjectDescription> subDesc;
+
+  auto unsignedCert =
+    m_keyChain.prepareUnsignedIdentityCertificate(selfSignedCert->getPublicKeyName(),
+                                                  selfSignedCert->getPublicKeyInfo(),
+                                                  identity,
+                                                  notBefore,
+                                                  notAfter,
+                                                  subDesc);
+
+  m_keyChain.sign(*unsignedCert, selfSignedCertName);
+  m_keyChain.addCertificate(*unsignedCert);
+
+  time::system_clock::TimePoint dataTs1 = time::system_clock::now() + time::seconds(5);
+  time::system_clock::TimePoint keyTs1 = time::system_clock::now() + time::seconds(2);
+  Timestamp dataTimestamp1 = time::toUnixTimestamp(dataTs1).count() / 1000;
+  Timestamp keyTimestamp1 = time::toUnixTimestamp(keyTs1).count() / 1000;
+
+
+  Data data1("/test/id/data");
+  m_keyChain.sign(data1, unsignedCert->getName());
+  BOOST_CHECK_EQUAL(policyChecker.check(dataTimestamp1, data1, keyTimestamp1, *unsignedCert),
+                    true);
+
+  Data data2("/test/id");
+  m_keyChain.sign(data2, unsignedCert->getName());
+  BOOST_CHECK_EQUAL(policyChecker.check(dataTimestamp1, data2, keyTimestamp1, *unsignedCert),
+                    false);
+
+  Data data3("/test/wrong");
+  m_keyChain.sign(data3, unsignedCert->getName());
+  BOOST_CHECK_EQUAL(policyChecker.check(dataTimestamp1, data3, keyTimestamp1, *unsignedCert),
+                    false);
+
+  Data data4("/test");
+  m_keyChain.sign(data4, unsignedCert->getName());
+  BOOST_CHECK_EQUAL(policyChecker.check(dataTimestamp1, data4, keyTimestamp1, *unsignedCert),
+                    false);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nsl
diff --git a/tests/core/unit-test-time-fixture.hpp b/tests/core/unit-test-time-fixture.hpp
new file mode 100644
index 0000000..e70d66e
--- /dev/null
+++ b/tests/core/unit-test-time-fixture.hpp
@@ -0,0 +1,69 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#ifndef NSL_TESTS_UNIT_TESTS_UNIT_TEST_TIME_FIXTURE_HPP
+#define NSL_TESTS_UNIT_TESTS_UNIT_TEST_TIME_FIXTURE_HPP
+
+#include <ndn-cxx/util/time-unit-test-clock.hpp>
+
+#include <boost/asio.hpp>
+
+namespace nsl {
+namespace tests {
+
+class UnitTestTimeFixture
+{
+public:
+  UnitTestTimeFixture()
+    : steadyClock(make_shared<ndn::time::UnitTestSteadyClock>())
+    , systemClock(make_shared<ndn::time::UnitTestSystemClock>())
+  {
+    time::setCustomClocks(steadyClock, systemClock);
+  }
+
+  ~UnitTestTimeFixture()
+  {
+    time::setCustomClocks(nullptr, nullptr);
+  }
+
+  void
+  advanceClocks(const time::nanoseconds& tick, size_t nTicks = 1)
+  {
+    for (size_t i = 0; i < nTicks; ++i) {
+      steadyClock->advance(tick);
+      systemClock->advance(tick);
+
+      if (io.stopped())
+        io.reset();
+      io.poll();
+    }
+  }
+
+public:
+  shared_ptr<ndn::time::UnitTestSteadyClock> steadyClock;
+  shared_ptr<ndn::time::UnitTestSystemClock> systemClock;
+  boost::asio::io_service io;
+};
+
+} // namespace tests
+} // namespace nsl
+
+#endif // NSL_TESTS_UNIT_TESTS_UNIT_TEST_TIME_FIXTURE_HPP