security: Convert ValidatorConfig to ValidationPolicyConfig

The security API also provides a convenience ValidatorConfig helper.

Change-Id: Ic86dec4904b917361cb4740204de4b6710d2a386
Refs: #3920
diff --git a/docs/tutorials/security-validator-config.rst b/docs/tutorials/security-validator-config.rst
index 9df0020..044161d 100644
--- a/docs/tutorials/security-validator-config.rst
+++ b/docs/tutorials/security-validator-config.rst
@@ -9,7 +9,7 @@
 The configuration file consists of **rules** and **trust-anchors** that will be used in
 validation. **Rules** tell the validator how to validate a packet, while **trust-anchors**
 tell the validator which certificates are valid immediately. Here is an example of
-configuration file containing two rules.
+configuration file containing two rules and a trust anchor.
 
 ::
 
@@ -30,7 +30,7 @@
         key-locator
         {
           type name
-          name /ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT
+          name /ndn/edu/ucla/yingdi/KEY/ksk-1234
           relation equal
         }
       }
@@ -61,64 +61,73 @@
 -  The second part is to check whether further validation process is
    necessary.
 
-When receiving a packet, the validator will apply rules in the configuration file
-one-by-one against the packet, until finding a rule that the packet qualifies for. And the
-second part of the matched rule will be used to check the validity of the packet. If the
-packet cannot qualify for any rules, it is treated as an invalid packet. Once a packet has
-been matched by a rule, the rest rules will not be applied against the packet. Therefore,
-you should always put the most specific rule to the top, otherwise it will become useless.
+When a packet is presented for validation, the validator will check the rules one-by-one
+in the configuration file using **for** and **filter** conditions against the packet,
+until finding a rule for which the packet qualifies. After that, the **checker**
+conditions of the matched rule will be used to check the validity of the packet.  If the
+packet does not match any rules, it is treated as an invalid packet. Once a packet has
+been matched by a rule, the remaining rules are not applied to the packet (i.e., the
+matched rule "captures" the packet). Therefore, you should always put the most specific
+rule first.
 
 In the example configuration, the first rule indicates that all the data packets under the
-name prefix ``/localhost/example`` must be signed by a key whose certificate name is
-``/ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT``. If a packet does not have a name under prefix
-``/localhost/example``, validator will skip the first rule and apply the second rule. The
-second rule indicates that any data packets must be validated along a hierarchy. And a
-certificate stored in a file "testbed-trust-anchor.cert" is valid.
+name prefix ``/localhost/example`` must be signed by a certificate whose name (the key
+part) is ``/ndn/edu/ucla/yingdi/KEY/ksk-1234``. If a packet does not have a name under
+prefix ``/localhost/example``, the validator will skip the first rule and apply the second
+rule. The second rule indicates that all other data packets must be validated using the
+hierarchical policy (data name should be prefix or equal to the identity part of the
+certificate name).  The example configuration defines that all certificate chains must be
+rooted in the certificate defined in the file "testbed-trust-anchor.cert".
 
 Rules in general
 ----------------
 
-A rule has four types of properties: **id**, **for**, **filter**, and **checker**.
+A rule has four properties: **id**, **for**, **filter**, and **checker**.
 
-The property **id** uniquely identifies the rule in the configuration file. As long as
+The **id** property uniquely identifies the rule in the configuration file. As long as
 being unique, any name can be given to a rule, e.g., "Simple Rule", "Testbed Validation
 Rule". A rule must have one and only one **id** property.
 
-A rule is either used to validate an interest packet or a data packet.  This information
-is specified in the property **for**. Only two value can be specified: **data** and
-**interest**. A rule must have one and only one **for** property.
+A rule is either used to validate a data packet or an interest packet.  This information
+is specified in the **for** property, which can be either **data** or **interest**.  A
+rule must have exactly one **for** property.
 
-The property **filter** further constrains the packets that can be checked by the
-rule. Filter property is not required in a rule, in this case, the rule will capture all
-the packets passed to it. A rule may contain more than one filters, in this case, a packet
-can be checked by a rule only if the packet satisfies all the filters.
+The **filter** property further constrains the packets that can be checked by the
+rule. The filter property is not required in a rule; if omitted, the rule will capture all
+packets passed to it.  A rule may contain multiple filters, in this case, a packet
+is captured by the rule only if all filters are satisfied.
 
 .. note::
     **ATTENTION: A packet that satisfies all the filters may not be valid**.
 
-The property **checker** defines the conditions that a matched packet must fulfill to be
+The **checker** property defines the conditions that a matched packet must fulfill to be
 treated as a valid packet. A rule must have at least one **checker** property. A packet is
 treated as valid if it can pass at least one of the checkers and as invalid when it cannot
 pass any checkers.
 
-**filter** and **checker** have their own properties. Next, we will introduce them
-separately.
-
 Filter Property
 ---------------
 
-Filter has its own **type** property. Although a rule may contain more than one filters,
-there is at most one filter of each type. So far, only one type of filter is defined:
-**name**. In other word, only one filter can be specified in a rule for now.
+Filter has a **type** property and type-specific properties.  Although a rule can contain
+more than one filters, there can be at most one filter of each type.
+
+Currently, only the packet name filter is defined.
 
 Name Filter
 ~~~~~~~~~~~
 
-There are two ways to express the conditions on name. The first way is to specify a
-relationship between the packet name and a particular name.  In this case, two more
-properties are required: **name** and **relation**. A packet can fulfill the condition if
-the **name** has a **relation\* to the packet name. Three types of **\ relation\*\* has
-been defined: **equal**, **is-prefix-of**, **is-strict-prefix-of**. For example, a filter
+There are two ways to express the conditions on packet name:
+
+- relationship between the packet name and the specified name
+- :doc:`NDN regular expression <utils-ndn-regex>`  match.
+
+Name and Relation
+^^^^^^^^^^^^^^^^^
+
+In the first case, two more properties are required: **name** and **relation**. A packet
+can fulfill the condition if the **name** has a **relation** to the packet's name. Three
+types of **relation** has been defined: **equal**, **is-prefix-of**,
+**is-strict-prefix-of**. For example, the filter
 
 ::
 
@@ -129,8 +138,9 @@
       relation equal
     }
 
-shall only capture a packet with the exact name ``/localhost/example``.
-And a filter
+will capture only a packet with the exact name ``/localhost/example``.
+
+The filter
 
 ::
 
@@ -141,8 +151,8 @@
       relation is-prefix-of
     }
 
-shall capture a packet with name ``/localhost/example`` or ``/localhost/example/data``, but
-cannot catch a packet with name ``/localhost/another_example``. And a filter
+will capture a packet with name ``/localhost/example`` or ``/localhost/example/data``, but
+will not capture a packet with name ``/localhost/another_example``. And the filter
 
 ::
 
@@ -153,42 +163,46 @@
       relation is-strict-prefix-of
     }
 
-shall capture a packet with name ``/localhost/example/data``, but cannot catch a packet
+will capture a packet with name ``/localhost/example/data``, but will not capture a packet
 with name ``/localhost/example``.
 
+NDN Regular Expression Match
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 The second way is to specify an :doc:`utils-ndn-regex` that can match the packet. In this
-case, only one property **regex** is required. For example, a filter
+case, only one property **regex** is required. For example, the filter
 
 ::
 
     filter
     {
       type name
-      regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT>$
+      regex ^<>*<KEY><><><>$
     }
 
-shall capture all the identity certificates.
+will capture all certificates.
 
 Checker Property
 ----------------
 
 Passing all the filters in a rule only indicates that a packet can be checked using the
-rule, and it does not necessarily implies that the packet is valid. The validity of a
+rule, and it does not necessarily imply that the packet is valid. The validity of a
 packet is determined by the property **checker**, which defines the conditions that a
 valid packet must fulfill.
 
-Same as **filter**, **checker** has a property **type**. We have defined three types of
-checkers: **customized**, and **hierarchical**, and **fixed-signer**. As suggested by its
-name, **customized** checker allows you to customize the conditions according to specific
-requirements. **hierarchical** checker and **fixed-signer** checker are pre-defined
-shortcuts, which specify specific trust models separately.
+Same as **filter**, **checker** has a property **type**. We have defined two types of
+checkers:
+
+- **customized** is a checker that allows customization of the conditions according to specific
+  requirements;
+
+- **hierarchical** is a checker with pre-defined hierarchical trust model.
 
 Customized Checker
 ~~~~~~~~~~~~~~~~~~
 
-So far, we only allow three customized properties in a customized
-checker: **sig-type**, **key-locator**. All of them are related to the
-``SignatureInfo`` of a packet.
+The customized checker requires two properties: **sig-type**, **key-locator**.  Both must
+appear exactly once and are related to the ``SignatureInfo`` of a packet.
 
 ::
 
@@ -202,18 +216,16 @@
       }
     }
 
-The property **sig-type** specifies the acceptable signature type.  Right now three
-signature types have been defined: **rsa-sha256** and **ecdsa-sha256** (which are strong
-signature types) and **sha256** (which is a weak signature type).  If sig-type is sha256,
-then **key-locator** will be ignored. Validator will simply calculate the digest of a
-packet and compare it with the one in ``SignatureValue``. If sig-type is rsa-sha256 or
-ecdsa-sha256, you have to further customize the checker with **key-locator**.
+The property **sig-type** specifies the acceptable signature type and can be
+**rsa-sha256**, **ecdsa-sha256** (strong signature types), or **sha256** (weak signature
+type).  If sig-type is sha256, **key-locator** is ignored, and the validator will simply
+calculate the digest of a packet and compare it with the one in ``SignatureValue``. If
+sig-type is rsa-sha256 or ecdsa-sha256, you have to further customize the checker with
+**key-locator**.
 
-The property **key-locator** which specifies the conditions on ``KeyLocator``. If the
+The property **key-locator** specifies the conditions on ``KeyLocator``. If the
 **key-locator** property is specified, it requires the existence of the ``KeyLocator``
-field in ``SignatureInfo``.  Although there are more than one types of ``KeyLocator``
-defined in the `Packet Format <http://named-data.net/doc/ndn-tlv/signature.html>`__,
-**key-locator** property only supports one type: **name**:
+field in ``SignatureInfo``.  **key-locator** property only supports one type: **name**:
 
 ::
 
@@ -223,9 +235,9 @@
       ...
     }
 
-Such a key-locator property specifies the conditions on the certificate name of the
-signing key. Since the conditions are about name, they can be specified in the same way as
-the name filter. For example, a checker could be:
+This key-locator property specifies the conditions on the certificate name of the signing
+key. Since the conditions are about name, they can be specified in the same way as the
+name filter. For example, a checker can be:
 
 ::
 
@@ -236,23 +248,23 @@
       key-locator
       {
         type name
-        name /ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT
+        name /ndn/edu/ucla/yingdi/KEY/ksk-1234
         relation equal
       }
     }
 
-This checker property requires that the packet must have a ``rsa-sha256`` signature generated
-by a key whose certificate name is ``/ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT``.
+This checker property requires that the packet must have a ``rsa-sha256`` signature that
+can be verified with ``/ndn/edu/ucla/yingdi/KEY/ksk-1234`` key.
 
 Besides the two ways to express conditions on the ``KeyLocator`` name (name and regex),
 you can further constrain the ``KeyLocator`` name using the information extracted from the
 packet name. This third type of condition is expressed via a property
 **hyper-relation**. The **hyper-relation** property consists of three parts:
 
-- an NDN regular expression that can extract information from packet name
-- an NDN regular expression that can extract information from ``KeyLocator`` name
-- relation from the part extracted from ``KeyLocator`` name to the one extracted from the
-   packet name
+- an NDN regular expression that extracts information from the packet name
+- an NDN regular expression that extracts information from the ``KeyLocator`` name
+- relation from the part extracted from the ``KeyLocator`` name to the one extracted from
+  the packet name
 
 For example, a checker:
 
@@ -267,8 +279,8 @@
         type name
         hyper-relation
         {
-          k-regex ^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$
-          k-expand \\1\\2
+          k-regex ^(<>*)<KEY><>$
+          k-expand \\1
           h-relation is-prefix-of
           p-regex ^(<>*)$
           p-expand \\1
@@ -277,30 +289,8 @@
       }
     }
 
-requires the packet name must be under the corresponding namespace of the ``KeyLocator``
-name.
-
-In some cases, you can even customize checker with another property For example:
-
-::
-
-    checker
-    {
-      type customized
-      sig-type rsa-sha256
-      key-locator
-      {
-        type name
-        hyper-relation
-        {
-          k-regex ^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$
-          k-expand \\1\\2
-          h-relation is-prefix-of
-          p-regex ^(<>*)$
-          p-expand \\1
-        }
-      }
-    }
+requires the packet name must be under the corresponding namespace (identity part) of the
+``KeyLocator`` name.
 
 Hierarchical Checker
 ~~~~~~~~~~~~~~~~~~~~
@@ -329,8 +319,8 @@
         type name
         hyper-relation
         {
-          k-regex ^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$
-          k-expand \\1\\2
+          k-regex ^(<>*)<KEY><>$
+          k-expand \\1
           h-relation is-prefix-of
           p-regex ^(<>*)$
           p-expand \\1
@@ -338,42 +328,14 @@
       }
     }
 
-Fixed-Signer Checker
-~~~~~~~~~~~~~~~~~~~~
-
-In some cases, you only accept packets signed with pre-trusted certificates,
-i.e. "one-step validation". Such a trust model can be expressed with **fixed-signer**
-checker. And you only need to specify the trusted certificate via property **signer**. The
-definition of **signer** is the same as **trust-anchor**. For example:
-
-::
-
-    checker
-    {
-      type fixed-signer
-      sig-type rsa-sha256
-      signer
-      {
-        type file
-        file-name "trusted-signer.cert"
-      }
-      signer
-      {
-        type base64
-        base64-string "Bv0DGwdG...amHFvHIMDw=="
-      }
-    }
-
 .. _validator-conf-trust-anchors:
 
 Trust Anchors
 -------------
 
-Although **trust-anchor** is always not required in the configuration file (for example,
-if fixed-signer checker is used), it is very common to have a few trust-anchors in the
-configuration file, otherwise most packets cannot be validated. A configuration file may
-contain more than one trust anchors, but the order of trust anchors does not matter. The
-structure of trust-anchor is same as the **signer** in fixed-signer checker, for example:
+**trust-anchor** is a necessary option in order to properly validate packets.  A
+configuration file may contain more than one trust anchors and the order of trust anchors
+does not matter. The structure of trust-anchor is as follows:
 
 ::
 
@@ -389,7 +351,7 @@
     }
 
 You may also specify a trust-anchor directory. All certificates under this directory are
-taken as trust anchors. For example, if all trust anchors are put into
+taken as static trust anchors. For example, if all trust anchors are put into
 ``/usr/local/etc/ndn/keys``.
 
 ::
@@ -397,7 +359,7 @@
     trust-anchor
     {
       type dir
-      file-name /usr/local/etc/ndn/keys
+      dir /usr/local/etc/ndn/keys
     }
 
 If certificates under the directory might be changed during runtime, you can set a refresh
@@ -408,11 +370,11 @@
     trust-anchor
     {
       type dir
-      file-name /usr/local/etc/ndn/keys
+      dir /usr/local/etc/ndn/keys
       refresh 1h ; refresh certificates every hour, other units include m (for minutes) and s (for seconds)
     }
 
-There is another special trust anchor **any**.  As long as such a trust-anchor is defined
+There is also a special trust anchor **any**.  As long as such a trust-anchor is defined
 in config file, packet validation will be turned off.
 
 .. note::
@@ -430,6 +392,10 @@
 Example Configuration For NLSR
 ------------------------------
 
+.. note::
+   **These example assumes the v1 certificate naming convention that is no longer in
+   use. The example will be updated later.**
+
 The trust model of NLSR is semi-hierarchical. An example certificate signing hierarchy is:
 
 ::
@@ -584,43 +550,63 @@
 
 ::
 
-    rule
-    {
-      id "NRD Prefix Registration Command Rule"
-      for interest
-      filter
-      {
-        type name
-        regex ^<localhost><nrd>[<register><unregister><advertise><withdraw>]
-      }
-      checker
-      {
-        type customized
-        sig-type rsa-sha256
-        key-locator
-        {
-          type name
-          regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT>$
-        }
-      }
-    }
-    rule
-    {
-      id "Testbed Hierarchy Rule"
-      for data
-      filter
-      {
-        type name
-        regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT><>$
-      }
-      checker
-      {
-        type hierarchical
-        sig-type rsa-sha256
-      }
-    }
-    trust-anchor
-    {
-      type file
-      file-name "testbed-trust-anchor.cert"
-    }
+     rule
+     {
+       id "RIB Prefix Registration Command Rule"
+       for interest                         ; rule for Interests (to validate CommandInterests)
+       filter
+       {
+         type name                          ; condition on interest name (w/o signature)
+         regex ^[<localhop><localhost>]<nfd><rib>[<register><unregister>]<><><>$ ; prefix before
+                                                                                 ; SigInfo & SigValue
+       }
+       checker
+       {
+         type customized
+         sig-type rsa-sha256                ; interest must have a rsa-sha256 signature
+         key-locator
+         {
+           type name                        ; key locator must be the certificate name of the
+                                            ; signing key
+           regex ^<>*<KEY><><><>$
+         }
+       }
+       checker
+       {
+         type customized
+         sig-type ecdsa-sha256                ; interest must have a ecdsa-sha256 signature
+         key-locator
+         {
+           type name                        ; key locator must be the certificate name of the
+                                            ; signing key
+           regex ^<>*<KEY><><><>$
+         }
+       }
+     }
+     rule
+     {
+       id "NDN Testbed Hierarchy Rule"
+       for data                             ; rule for Data (to validate NDN certificates)
+       filter
+       {
+         type name                          ; condition on data name
+         regex ^<>*<KEY><><><>$
+       }
+       checker
+       {
+         type hierarchical                  ; the certificate name of the signing key and
+                                            ; the data name must follow the hierarchical model
+         sig-type rsa-sha256                ; data must have a rsa-sha256 signature
+       }
+       checker
+       {
+         type hierarchical                  ; the certificate name of the signing key and
+                                            ; the data name must follow the hierarchical model
+         sig-type ecdsa-sha256              ; data must have a ecdsa-sha256 signature
+       }
+     }
+     trust-anchor
+     {
+       type file
+       file-name keys/ndn-testbed-root.ndncert.base64
+     }
diff --git a/src/security/conf/checker.hpp b/src/security/conf/checker.hpp
deleted file mode 100644
index b928906..0000000
--- a/src/security/conf/checker.hpp
+++ /dev/null
@@ -1,483 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2017 Regents of the University of California.
- *
- * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
- *
- * ndn-cxx library is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * ndn-cxx library 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 Lesser General Public License for more details.
- *
- * You should have received copies of the GNU General Public License and GNU Lesser
- * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- *
- * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
- */
-
-#ifndef NDN_SECURITY_CONF_CHECKER_HPP
-#define NDN_SECURITY_CONF_CHECKER_HPP
-
-#include "common.hpp"
-
-#include "key-locator-checker.hpp"
-#include "../../util/io.hpp"
-#include "../validator.hpp"
-#include "../v1/identity-certificate.hpp"
-
-#include <boost/algorithm/string.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.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
-   * @retval -1 if data is immediately invalid
-   * @retval  1 if data is immediately valid
-   * @retval  0 if further signature verification is needed.
-   */
-  virtual int8_t
-  check(const Data& data) = 0;
-
-  /**
-   * @brief check if interest satisfies condition defined in the specific checker implementation
-   *
-   * @param interest Interest packet
-   * @retval -1 if interest is immediately invalid
-   * @retval  1 if interest is immediately valid
-   * @retval  0 if further signature verification is needed.
-   */
-  virtual int8_t
-  check(const Interest& interest) = 0;
-};
-
-class CustomizedChecker : public Checker
-{
-public:
-  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))
-          BOOST_THROW_EXCEPTION(Error("Strong signature requires KeyLocatorChecker"));
-        return;
-      }
-      case tlv::DigestSha256:
-        return;
-      default:
-        BOOST_THROW_EXCEPTION(Error("Unsupported signature type"));
-    }
-  }
-
-  int8_t
-  check(const Data& data) override
-  {
-    return check(data, data.getSignature());
-  }
-
-  int8_t
-  check(const Interest& interest) override
-  {
-    try {
-      const Name& interestName = interest.getName();
-      Signature signature(interestName[command_interest::POS_SIG_INFO].blockFromValue(),
-                          interestName[command_interest::POS_SIG_VALUE].blockFromValue());
-      return check(interest, signature);
-    }
-    catch (const Signature::Error& e) {
-      // Invalid signature
-      return -1;
-    }
-    catch (const tlv::Error& e) {
-      // Cannot decode signature related TLVs
-      return -1;
-    }
-  }
-
-private:
-  template<class Packet>
-  int8_t
-  check(const Packet& packet, const Signature& signature)
-  {
-    if (m_sigType != signature.getType()) {
-      // Signature type does not match
-      return -1;
-    }
-
-    if (signature.getType() == tlv::DigestSha256)
-      return 0;
-
-    try {
-      switch (signature.getType()) {
-        case tlv::SignatureSha256WithRsa:
-        case tlv::SignatureSha256WithEcdsa: {
-          if (!signature.hasKeyLocator()) {
-            // Missing KeyLocator in SignatureInfo
-            return -1;
-          }
-          break;
-        }
-        default: {
-          // Unsupported signature type
-          return -1;
-        }
-      }
-    }
-    catch (const KeyLocator::Error& e) {
-      // Cannot decode KeyLocator
-      return -1;
-    }
-    catch (const tlv::Error& e) {
-      // Cannot decode signature
-      return -1;
-    }
-
-    std::string failInfo;
-    if (m_keyLocatorChecker->check(packet, signature.getKeyLocator(), failInfo))
-      return 0;
-    else {
-      return -1;
-    }
-  }
-
-private:
-  uint32_t m_sigType;
-  shared_ptr<KeyLocatorChecker> m_keyLocatorChecker;
-};
-
-class HierarchicalChecker : public CustomizedChecker
-{
-public:
-  explicit
-  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
-{
-public:
-  FixedSignerChecker(uint32_t sigType,
-                     const std::vector<shared_ptr<v1::IdentityCertificate>>& signers)
-    : m_sigType(sigType)
-  {
-    for (std::vector<shared_ptr<v1::IdentityCertificate>>::const_iterator it = signers.begin();
-         it != signers.end(); it++)
-      m_signers[(*it)->getName().getPrefix(-1)] = (*it);
-
-    if (sigType != tlv::SignatureSha256WithRsa &&
-        sigType != tlv::SignatureSha256WithEcdsa) {
-      BOOST_THROW_EXCEPTION(Error("FixedSigner is only meaningful for strong signature type"));
-    }
-  }
-
-  int8_t
-  check(const Data& data) override
-  {
-    return check(data, data.getSignature());
-  }
-
-  int8_t
-  check(const Interest& interest) override
-  {
-    try {
-      const Name& interestName = interest.getName();
-      Signature signature(interestName[command_interest::POS_SIG_INFO].blockFromValue(),
-                          interestName[command_interest::POS_SIG_VALUE].blockFromValue());
-      return check(interest, signature);
-    }
-    catch (const Signature::Error& e) {
-      // Invalid signature
-      return -1;
-    }
-    catch (const tlv::Error& e) {
-      // Cannot decode signature related TLVs
-      return -1;
-    }
-  }
-
-private:
-  template<class Packet>
-  int8_t
-  check(const Packet& packet, const Signature& signature)
-  {
-    if (m_sigType != signature.getType()) {
-      // Signature type does not match
-      return -1;
-    }
-
-    if (signature.getType() == tlv::DigestSha256) {
-      // FixedSigner does not allow Sha256 signature type
-      return -1;
-    }
-
-    try {
-      switch (signature.getType()) {
-        case tlv::SignatureSha256WithRsa:
-        case tlv::SignatureSha256WithEcdsa: {
-          if (!signature.hasKeyLocator()) {
-            // Missing KeyLocator in SignatureInfo
-            return -1;
-          }
-          break;
-        }
-
-        default: {
-          // Unsupported signature type
-          return -1;
-        }
-      }
-
-      const Name& keyLocatorName = signature.getKeyLocator().getName();
-
-      if (m_signers.find(keyLocatorName) == m_signers.end()) {
-        // Signer is not in the fixed signer list
-        return -1;
-      }
-
-      if (Validator::verifySignature(packet, signature,
-                                     m_signers[keyLocatorName]->getPublicKeyInfo())) {
-        return 1;
-      }
-      else {
-        // Signature cannot be validated
-        return -1;
-      }
-    }
-    catch (const KeyLocator::Error& e) {
-      // KeyLocator does not have name
-      return -1;
-    }
-    catch (const tlv::Error& e) {
-      // Cannot decode signature
-      return -1;
-    }
-  }
-
-private:
-  typedef std::map<Name, shared_ptr<v1::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"))
-      BOOST_THROW_EXCEPTION(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
-      BOOST_THROW_EXCEPTION(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"))
-      BOOST_THROW_EXCEPTION(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"))
-      BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator>"));
-
-    shared_ptr<KeyLocatorChecker> keyLocatorChecker =
-      KeyLocatorCheckerFactory::create(propertyIt->second, configFilename);
-    propertyIt++;
-
-    if (propertyIt != configSection.end())
-      BOOST_THROW_EXCEPTION(Error("Expect the end of checker"));
-
-    return make_shared<CustomizedChecker>(getSigType(sigType), 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"))
-      BOOST_THROW_EXCEPTION(Error("Expect <checker.sig-type>"));
-
-    std::string sigType = propertyIt->second.data();
-    propertyIt++;
-
-    if (propertyIt != configSection.end())
-      BOOST_THROW_EXCEPTION(Error("Expect the end of checker"));
-
-    return make_shared<HierarchicalChecker>(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"))
-      BOOST_THROW_EXCEPTION(Error("Expect <checker.sig-type>"));
-
-    std::string sigType = propertyIt->second.data();
-    propertyIt++;
-
-    std::vector<shared_ptr<v1::IdentityCertificate>> signers;
-    for (; propertyIt != configSection.end(); propertyIt++) {
-      if (!boost::iequals(propertyIt->first, "signer"))
-        BOOST_THROW_EXCEPTION(Error("Expect <checker.signer> but get <checker." +
-                                    propertyIt->first + ">"));
-
-      signers.push_back(getSigner(propertyIt->second, configFilename));
-    }
-
-    if (propertyIt != configSection.end())
-      BOOST_THROW_EXCEPTION(Error("Expect the end of checker"));
-
-    return shared_ptr<FixedSignerChecker>(new FixedSignerChecker(getSigType(sigType),
-                                                                 signers));
-  }
-
-  static shared_ptr<v1::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"))
-      BOOST_THROW_EXCEPTION(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"))
-        BOOST_THROW_EXCEPTION(Error("Expect <checker.signer.file-name>"));
-
-      path certfilePath = absolute(propertyIt->second.data(),
-                                   path(configFilename).parent_path());
-      propertyIt++;
-
-      if (propertyIt != configSection.end())
-        BOOST_THROW_EXCEPTION(Error("Expect the end of checker.signer"));
-
-      shared_ptr<v1::IdentityCertificate> idCert
-        = io::load<v1::IdentityCertificate>(certfilePath.c_str());
-
-      if (static_cast<bool>(idCert))
-        return idCert;
-      else
-        BOOST_THROW_EXCEPTION(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"))
-        BOOST_THROW_EXCEPTION(Error("Expect <checker.signer.base64-string>"));
-
-      std::stringstream ss(propertyIt->second.data());
-      propertyIt++;
-
-      if (propertyIt != configSection.end())
-        BOOST_THROW_EXCEPTION(Error("Expect the end of checker.signer"));
-
-      shared_ptr<v1::IdentityCertificate> idCert = io::load<v1::IdentityCertificate>(ss);
-
-      if (static_cast<bool>(idCert))
-        return idCert;
-      else
-        BOOST_THROW_EXCEPTION(Error("Cannot decode certificate from string"));
-    }
-    else
-      BOOST_THROW_EXCEPTION(Error("Unsupported checker.signer type: " + type));
-  }
-
-  static uint32_t
-  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
-      BOOST_THROW_EXCEPTION(Error("Unsupported signature type"));
-  }
-};
-
-} // namespace conf
-} // namespace security
-} // namespace ndn
-
-#endif // NDN_SECURITY_CONF_CHECKER_HPP
diff --git a/src/security/conf/filter.hpp b/src/security/conf/filter.hpp
deleted file mode 100644
index 2ebc4e6..0000000
--- a/src/security/conf/filter.hpp
+++ /dev/null
@@ -1,238 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2017 Regents of the University of California.
- *
- * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
- *
- * ndn-cxx library is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * ndn-cxx library 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 Lesser General Public License for more details.
- *
- * You should have received copies of the GNU General Public License and GNU Lesser
- * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- *
- * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
- */
-
-#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 "../security-common.hpp"
-#include <boost/algorithm/string.hpp>
-
-#include "common.hpp"
-
-namespace ndn {
-namespace security {
-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)
-  {
-    return matchName(data.getName());
-  }
-
-  bool
-  match(const Interest& interest)
-  {
-    if (interest.getName().size() < command_interest::MIN_SIZE)
-      return false;
-
-    Name unsignedName = interest.getName().getPrefix(-command_interest::MIN_SIZE);
-    return matchName(unsignedName);
-  }
-
-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)
-    : m_name(name)
-    , m_relation(relation)
-  {
-  }
-
-  virtual
-  ~RelationNameFilter()
-  {
-  }
-
-protected:
-  virtual bool
-  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;
-      }
-  }
-
-private:
-  Name m_name;
-  Relation m_relation;
-};
-
-class RegexNameFilter : public Filter
-{
-public:
-  explicit
-  RegexNameFilter(const Regex& regex)
-    : m_regex(regex)
-  {
-  }
-
-  virtual
-  ~RegexNameFilter()
-  {
-  }
-
-protected:
-  virtual bool
-  matchName(const Name& name)
-  {
-    return m_regex.match(name);
-  }
-
-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"))
-      BOOST_THROW_EXCEPTION(Error("Expect <filter.type>!"));
-
-    std::string type = propertyIt->second.data();
-
-    if (boost::iequals(type, "name"))
-      return createNameFilter(configSection);
-    else
-      BOOST_THROW_EXCEPTION(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())
-      BOOST_THROW_EXCEPTION(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)
-          {
-            BOOST_THROW_EXCEPTION(Error("Wrong filter.name: " + propertyIt->second.data()));
-          }
-
-        propertyIt++;
-
-        // Get filter.relation
-        if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation"))
-          BOOST_THROW_EXCEPTION(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
-          BOOST_THROW_EXCEPTION(Error("Unsupported relation: " + relationString));
-
-
-        if (propertyIt != configSection.end())
-          BOOST_THROW_EXCEPTION(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())
-          BOOST_THROW_EXCEPTION(Error("Expect the end of filter!"));
-
-        try
-          {
-            return shared_ptr<RegexNameFilter>(new RegexNameFilter(regexString));
-          }
-        catch (Regex::Error& e)
-          {
-            BOOST_THROW_EXCEPTION(Error("Wrong filter.regex: " + regexString));
-          }
-      }
-    else
-      BOOST_THROW_EXCEPTION(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
deleted file mode 100644
index 04f43e0..0000000
--- a/src/security/conf/key-locator-checker.hpp
+++ /dev/null
@@ -1,389 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2017 Regents of the University of California.
- *
- * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
- *
- * ndn-cxx library is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * ndn-cxx library 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 Lesser General Public License for more details.
- *
- * You should have received copies of the GNU General Public License and GNU Lesser
- * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- *
- * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
- */
-
-#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 "../../util/regex.hpp"
-#include "../security-common.hpp"
-#include <boost/algorithm/string.hpp>
-
-#include "common.hpp"
-
-namespace ndn {
-namespace security {
-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)
-  {
-    return check(data.getName(), keyLocator, failInfo);
-  }
-
-  bool
-  check(const Interest& interest,
-        const KeyLocator& keyLocator,
-        std::string& failInfo)
-  {
-    if (interest.getName().size() < command_interest::MIN_SIZE)
-      {
-        failInfo = "No Signature";
-        return false;
-      }
-
-    Name signedName = interest.getName().getPrefix(-command_interest::MIN_SIZE);
-    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 (KeyLocator::Error& e)
-      {
-        failInfo = "KeyLocator does not have name";
-        return false;
-      }
-  }
-
-private:
-  Name m_name;
-  KeyLocatorChecker::Relation m_relation;
-};
-
-class RegexKeyLocatorNameChecker : public KeyLocatorChecker
-{
-public:
-  explicit
-  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 (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 (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"))
-      BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.type>!"));
-
-    std::string type = propertyIt->second.data();
-
-    if (boost::iequals(type, "name"))
-      return createKeyLocatorNameChecker(configSection, filename);
-    else
-      BOOST_THROW_EXCEPTION(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())
-      BOOST_THROW_EXCEPTION(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)
-          {
-            BOOST_THROW_EXCEPTION(Error("Invalid checker.key-locator.name: " +
-                                        propertyIt->second.data()));
-          }
-        propertyIt++;
-
-        if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation"))
-          BOOST_THROW_EXCEPTION(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
-          BOOST_THROW_EXCEPTION(Error("Unsupported relation: " + relationString));
-
-        if (propertyIt != configSection.end())
-          BOOST_THROW_EXCEPTION(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())
-          BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator!"));
-
-        try
-          {
-            return shared_ptr<RegexKeyLocatorNameChecker>
-              (new RegexKeyLocatorNameChecker(regexString));
-          }
-        catch (Regex::Error& e)
-          {
-            BOOST_THROW_EXCEPTION(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"))
-          BOOST_THROW_EXCEPTION(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"))
-          BOOST_THROW_EXCEPTION(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"))
-          BOOST_THROW_EXCEPTION(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"))
-          BOOST_THROW_EXCEPTION(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"))
-          BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.p-expand>!"));
-
-        std::string pExpand = hPropertyIt->second.data();
-        hPropertyIt++;
-
-        if (hPropertyIt != hSection.end())
-          BOOST_THROW_EXCEPTION(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
-          BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator.hyper-relation.h-relation: "
-                                      + hRelation));
-
-        try
-          {
-            return shared_ptr<HyperKeyLocatorNameChecker>
-              (new HyperKeyLocatorNameChecker(pRegex, pExpand,
-                                              kRegex, kExpand,
-                                              relation));
-          }
-        catch (Regex::Error& e)
-          {
-            BOOST_THROW_EXCEPTION(Error("Invalid regex for key-locator.hyper-relation"));
-          }
-      }
-    else
-      BOOST_THROW_EXCEPTION(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
deleted file mode 100644
index 03af661..0000000
--- a/src/security/conf/rule.hpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2016 Regents of the University of California.
- *
- * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
- *
- * ndn-cxx library is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * ndn-cxx library 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 Lesser General Public License for more details.
- *
- * You should have received copies of the GNU General Public License and GNU Lesser
- * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- *
- * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
- * @author Zhiyi Zhang <zhangzhiyi1919@gmail.com>
- */
-
-#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:
-  explicit
-  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)
-  {
-    bool hasPendingResult = false;
-    for (CheckerList::iterator it = m_checkers.begin(); it != m_checkers.end(); it++) {
-      int8_t result = (*it)->check(packet);
-      if (result > 0) {
-        onValidated(packet.shared_from_this());
-        return result;
-      }
-      else if (result == 0)
-        hasPendingResult = true;
-    }
-    if (hasPendingResult) {
-      return 0;
-    }
-    else {
-      onValidationFailed(packet.shared_from_this(), "Packet cannot pass any checkers.");
-      return -1;
-    }
-  }
-
-NDN_CXX_PUBLIC_WITH_TESTS_ELSE_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
diff --git a/src/security/v2/trust-anchor-group.cpp b/src/security/v2/trust-anchor-group.cpp
index 24f5b9e..6d702ab 100644
--- a/src/security/v2/trust-anchor-group.cpp
+++ b/src/security/v2/trust-anchor-group.cpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -96,6 +96,8 @@
     BOOST_THROW_EXCEPTION(std::runtime_error("Refresh period for the dynamic group must be positive"));
   }
 
+  NDN_LOG_TRACE("Create dynamic trust anchor group " << id << " for file/dir " << path
+                << " with refresh time " << refreshPeriod);
   refresh();
 }
 
diff --git a/src/security/v2/validation-policy-config.cpp b/src/security/v2/validation-policy-config.cpp
new file mode 100644
index 0000000..ba87a23
--- /dev/null
+++ b/src/security/v2/validation-policy-config.cpp
@@ -0,0 +1,314 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "validation-policy-config.hpp"
+#include "validator.hpp"
+#include "../../util/io.hpp"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/property_tree/info_parser.hpp>
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+
+ValidationPolicyConfig::ValidationPolicyConfig()
+  : m_shouldBypass(false)
+  , m_isConfigured(false)
+{
+}
+
+void
+ValidationPolicyConfig::load(const std::string& filename)
+{
+  std::ifstream inputFile;
+  inputFile.open(filename.c_str());
+  if (!inputFile.good() || !inputFile.is_open()) {
+    std::string msg = "Failed to read configuration file: ";
+    msg += filename;
+    BOOST_THROW_EXCEPTION(Error(msg));
+  }
+  load(inputFile, filename);
+  inputFile.close();
+}
+
+void
+ValidationPolicyConfig::load(const std::string& input, const std::string& filename)
+{
+  std::istringstream inputStream(input);
+  load(inputStream, filename);
+}
+
+void
+ValidationPolicyConfig::load(std::istream& input, const std::string& filename)
+{
+  ConfigSection tree;
+  try {
+    boost::property_tree::read_info(input, tree);
+  }
+  catch (const boost::property_tree::info_parser_error& error) {
+    std::stringstream msg;
+    msg << "Failed to parse configuration file";
+    msg << " " << filename;
+    msg << " " << error.message() << " line " << error.line();
+    BOOST_THROW_EXCEPTION(Error(msg.str()));
+  }
+
+  load(tree, filename);
+}
+
+void
+ValidationPolicyConfig::load(const ConfigSection& configSection,
+                             const std::string& filename)
+{
+  if (m_isConfigured) {
+    BOOST_THROW_EXCEPTION(std::logic_error("ValidationPolicyConfig can be configured only once"));
+  }
+  m_isConfigured = true;
+
+  BOOST_ASSERT(!filename.empty());
+
+  if (configSection.begin() == configSection.end()) {
+    std::string msg = "Error processing configuration file";
+    msg += ": ";
+    msg += filename;
+    msg += " no data";
+    BOOST_THROW_EXCEPTION(Error(msg));
+  }
+
+  for (const auto& subSection : configSection) {
+    const std::string& sectionName = subSection.first;
+    const ConfigSection& section = subSection.second;
+
+    if (boost::iequals(sectionName, "rule")) {
+      auto rule = Rule::create(section, filename);
+      if (rule->getPktType() == tlv::Data) {
+        m_dataRules.push_back(std::move(rule));
+      }
+      else if (rule->getPktType() == tlv::Interest) {
+        m_interestRules.push_back(std::move(rule));
+      }
+    }
+    else if (boost::iequals(sectionName, "trust-anchor")) {
+      processConfigTrustAnchor(section, filename);
+    }
+    else {
+      std::string msg = "Error processing configuration file";
+      msg += " ";
+      msg += filename;
+      msg += " unrecognized section: " + sectionName;
+      BOOST_THROW_EXCEPTION(Error(msg));
+    }
+  }
+}
+
+void
+ValidationPolicyConfig::processConfigTrustAnchor(const ConfigSection& configSection, const std::string& filename)
+{
+  using namespace boost::filesystem;
+
+  ConfigSection::const_iterator propertyIt = configSection.begin();
+
+  // Get trust-anchor.type
+  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
+    BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.type>"));
+  }
+
+  std::string type = propertyIt->second.data();
+  propertyIt++;
+
+  if (boost::iequals(type, "file")) {
+    // Get trust-anchor.file
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name")) {
+      BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.file-name>"));
+    }
+
+    std::string file = propertyIt->second.data();
+    propertyIt++;
+
+    time::nanoseconds refresh = getRefreshPeriod(propertyIt, configSection.end());
+    if (propertyIt != configSection.end()) {
+      BOOST_THROW_EXCEPTION(Error("Expect the end of trust-anchor!"));
+    }
+
+    m_validator->loadAnchor(filename, absolute(file, path(filename).parent_path()).string(),
+                            refresh, false);
+    return;
+  }
+  else if (boost::iequals(type, "base64")) {
+    // Get trust-anchor.base64-string
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "base64-string"))
+      BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.base64-string>"));
+
+    std::stringstream ss(propertyIt->second.data());
+    propertyIt++;
+
+    // Check other stuff
+    if (propertyIt != configSection.end())
+      BOOST_THROW_EXCEPTION(Error("Expecting the end of trust-anchor"));
+
+    auto idCert = io::load<Certificate>(ss);
+    if (idCert != nullptr) {
+      m_validator->loadAnchor("", std::move(*idCert));
+    }
+    else {
+      BOOST_THROW_EXCEPTION(Error("Cannot decode certificate from base64-string"));
+    }
+
+    return;
+  }
+  else if (boost::iequals(type, "dir")) {
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "dir"))
+      BOOST_THROW_EXCEPTION(Error("Expect <trust-anchor.dir>"));
+
+    std::string dirString(propertyIt->second.data());
+    propertyIt++;
+
+    time::nanoseconds refresh = getRefreshPeriod(propertyIt, configSection.end());
+    if (propertyIt != configSection.end()) {
+      BOOST_THROW_EXCEPTION(Error("Expecting the end of trust-anchor"));
+    }
+
+    path dirPath = absolute(dirString, path(filename).parent_path());
+    m_validator->loadAnchor(dirString, dirPath.string(), refresh, true);
+    return;
+  }
+  else if (boost::iequals(type, "any")) {
+    m_shouldBypass = true;
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("Unsupported trust-anchor.type: " + type));
+  }
+}
+
+time::nanoseconds
+ValidationPolicyConfig::getRefreshPeriod(ConfigSection::const_iterator& it,
+                                         const ConfigSection::const_iterator& end)
+{
+  time::nanoseconds refresh = time::nanoseconds::max();
+  if (it == end) {
+    return refresh;
+  }
+
+  if (!boost::iequals(it->first, "refresh")) {
+    BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.refresh>"));
+  }
+
+  std::string inputString = it->second.data();
+  ++it;
+
+  char unit = inputString[inputString.size() - 1];
+  std::string refreshString = inputString.substr(0, inputString.size() - 1);
+
+  uint32_t refreshPeriod = 0;
+
+  try {
+    refreshPeriod = boost::lexical_cast<uint32_t>(refreshString);
+  }
+  catch (const boost::bad_lexical_cast&) {
+    BOOST_THROW_EXCEPTION(Error("Bad number: " + refreshString));
+  }
+
+  if (refreshPeriod == 0) {
+    return getDefaultRefreshPeriod();
+  }
+
+  switch (unit) {
+    case 'h':
+      return time::duration_cast<time::nanoseconds>(time::hours(refreshPeriod));
+    case 'm':
+      return time::duration_cast<time::nanoseconds>(time::minutes(refreshPeriod));
+    case 's':
+      return time::duration_cast<time::nanoseconds>(time::seconds(refreshPeriod));
+    default:
+      BOOST_THROW_EXCEPTION(Error(std::string("Wrong time unit: ") + unit));
+  }
+}
+
+time::nanoseconds
+ValidationPolicyConfig::getDefaultRefreshPeriod()
+{
+  return time::duration_cast<time::nanoseconds>(time::seconds(3600));
+}
+
+void
+ValidationPolicyConfig::checkPolicy(const Data& data, const shared_ptr<ValidationState>& state,
+                                    const ValidationContinuation& continueValidation)
+{
+  BOOST_ASSERT_MSG(!hasInnerPolicy(), "ValidationPolicyConfig must be a terminal inner policy");
+
+  if (m_shouldBypass) {
+    return continueValidation(nullptr, state);
+  }
+
+  Name klName = getKeyLocatorName(data, *state);
+  if (!state->getOutcome()) { // already failed
+    return;
+  }
+
+  for (const auto& rule : m_dataRules) {
+    if (rule->match(tlv::Data, data.getName())) {
+      if (rule->check(tlv::Data, data.getName(), klName, state)) {
+        return continueValidation(make_shared<CertificateRequest>(Interest(klName)), state);
+      }
+      // rule->check calls state->fail(...) if the check fails
+      return;
+    }
+  }
+
+  return state->fail({ValidationError::POLICY_ERROR, "No rule matched for data `" + data.getName().toUri() + "`"});
+}
+
+void
+ValidationPolicyConfig::checkPolicy(const Interest& interest, const shared_ptr<ValidationState>& state,
+                                    const ValidationContinuation& continueValidation)
+{
+  BOOST_ASSERT_MSG(!hasInnerPolicy(), "ValidationPolicyConfig must be a terminal inner policy");
+
+  if (m_shouldBypass) {
+    return continueValidation(nullptr, state);
+  }
+
+  Name klName = getKeyLocatorName(interest, *state);
+  if (!state->getOutcome()) { // already failed
+    return;
+  }
+
+  for (const auto& rule : m_interestRules) {
+    if (rule->match(tlv::Interest, interest.getName())) {
+      if (rule->check(tlv::Interest, interest.getName(), klName, state)) {
+        return continueValidation(make_shared<CertificateRequest>(Interest(klName)), state);
+      }
+      // rule->check calls state->fail(...) if the check fails
+      return;
+    }
+  }
+
+  return state->fail({ValidationError::POLICY_ERROR, "No rule matched for interest `" + interest.getName().toUri() + "`"});
+}
+
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v2/validation-policy-config.hpp b/src/security/v2/validation-policy-config.hpp
new file mode 100644
index 0000000..7690cc1
--- /dev/null
+++ b/src/security/v2/validation-policy-config.hpp
@@ -0,0 +1,99 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_SECURITY_V2_VALIDATION_POLICY_CONFIG_HPP
+#define NDN_SECURITY_V2_VALIDATION_POLICY_CONFIG_HPP
+
+#include "validation-policy.hpp"
+#include "validator-config/rule.hpp"
+#include "validator-config/common.hpp"
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+
+/**
+ * @brief The validator which can be set up via a configuration file.
+ *
+ * @note For command Interest validation, this policy must be combined with
+ *       @p ValidationPolicyCommandInterest, in order to guard against replay attacks.
+ * @note This policy does not support inner policies (a sole policy or a terminal inner policy)
+ * @sa https://named-data.net/doc/ndn-cxx/current/tutorials/security-validator-config.html
+ */
+class ValidationPolicyConfig : public ValidationPolicy
+{
+public:
+  ValidationPolicyConfig();
+
+  void
+  load(const std::string& filename);
+
+  void
+  load(const std::string& input, const std::string& filename);
+
+  void
+  load(std::istream& input, const std::string& filename);
+
+  void
+  load(const ConfigSection& configSection, const std::string& filename);
+
+protected:
+  void
+  checkPolicy(const Data& data, const shared_ptr<ValidationState>& state,
+              const ValidationContinuation& continueValidation) override;
+
+  void
+  checkPolicy(const Interest& interest, const shared_ptr<ValidationState>& state,
+              const ValidationContinuation& continueValidation) override;
+
+private:
+  void
+  processConfigTrustAnchor(const ConfigSection& section, const std::string& filename);
+
+  time::nanoseconds
+  getRefreshPeriod(ConfigSection::const_iterator& it, const ConfigSection::const_iterator& end);
+
+  time::nanoseconds
+  getDefaultRefreshPeriod();
+
+NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  /** @brief whether to always bypass validation
+   *
+   *  This is set to true when 'any' is specified as a trust anchor.
+   *  It causes all packets to bypass validation.
+   */
+  bool m_shouldBypass;
+  bool m_isConfigured;
+
+  std::vector<unique_ptr<Rule>> m_dataRules;
+  std::vector<unique_ptr<Rule>> m_interestRules;
+};
+
+} // namespace validator_config
+
+using validator_config::ValidationPolicyConfig;
+
+} // namespace v2
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_V2_VALIDATION_POLICY_CONFIG_HPP
diff --git a/src/security/v2/validation-policy.hpp b/src/security/v2/validation-policy.hpp
index 351ffed..d7a261b 100644
--- a/src/security/v2/validation-policy.hpp
+++ b/src/security/v2/validation-policy.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -65,6 +65,20 @@
   void
   setInnerPolicy(unique_ptr<ValidationPolicy> innerPolicy);
 
+  /**
+   * @brief Check if inner policy is set
+   */
+  bool
+  hasInnerPolicy() const
+  {
+    return m_innerPolicy != nullptr;
+  }
+
+  /**
+   * @brief Return the inner policy
+   *
+   * If the inner policy was not set, behavior is undefined.
+   */
   ValidationPolicy&
   getInnerPolicy();
 
diff --git a/src/security/v2/validator-config/checker.cpp b/src/security/v2/validator-config/checker.cpp
new file mode 100644
index 0000000..47415af
--- /dev/null
+++ b/src/security/v2/validator-config/checker.cpp
@@ -0,0 +1,334 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "checker.hpp"
+#include "security/v2/validation-state.hpp"
+#include "security/verification-helpers.hpp"
+#include "security/pib/key.hpp"
+#include "util/logger.hpp"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+
+bool
+Checker::check(uint32_t pktType, const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
+{
+  BOOST_ASSERT(pktType == tlv::Interest || pktType == tlv::Data);
+
+  if (pktType == tlv::Interest) {
+    if (pktName.size() < signed_interest::MIN_SIZE)
+      return false;
+
+    return checkNames(pktName.getPrefix(-signed_interest::MIN_SIZE), klName, state);
+  }
+  else {
+    return checkNames(pktName, klName, state);
+  }
+}
+
+NameRelationChecker::NameRelationChecker(const Name& name, const NameRelation& relation)
+  : m_name(name)
+  , m_relation(relation)
+{
+}
+
+bool
+NameRelationChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
+{
+  // pktName not used in this check
+  Name identity = extractIdentityFromKeyName(klName);
+  bool result = checkNameRelation(m_relation, m_name, identity);
+  if (!result) {
+    std::ostringstream os;
+    os << "KeyLocator check failed: name relation " << m_name << " " << m_relation
+       << " for packet " << pktName << " is invalid"
+       << " (KeyLocator=" << klName << ", identity=" << identity << ")";
+    state->fail({ValidationError::POLICY_ERROR, os.str()});
+  }
+  return result;
+}
+
+RegexChecker::RegexChecker(const Regex& regex)
+  : m_regex(regex)
+{
+}
+
+bool
+RegexChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
+{
+  // pktName not used in this check
+  Name identity = extractIdentityFromKeyName(klName);
+  bool result = m_regex.match(identity);
+  if (!result) {
+    std::ostringstream os;
+    os << "KeyLocator check failed: regex " << m_regex << " for packet " << pktName << " is invalid"
+       << " (KeyLocator=" << klName << ", identity=" << identity << ")";
+    state->fail({ValidationError::POLICY_ERROR, os.str()});
+  }
+
+  return result;
+}
+
+HyperRelationChecker::HyperRelationChecker(const std::string& pktNameExpr, const std::string pktNameExpand,
+                                           const std::string& klNameExpr, const std::string klNameExpand,
+                                           const NameRelation& hyperRelation)
+  : m_hyperPRegex(pktNameExpr, pktNameExpand)
+  , m_hyperKRegex(klNameExpr, klNameExpand)
+  , m_hyperRelation(hyperRelation)
+{
+}
+
+bool
+HyperRelationChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
+{
+  if (!m_hyperPRegex.match(pktName) || !m_hyperKRegex.match(klName)) {
+    std::ostringstream os;
+    os << "Packet " << pktName << " (" << "KeyLocator=" << klName << ") does not match "
+       << "the hyper relation rule pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex;
+    state->fail({ValidationError::POLICY_ERROR, os.str()});
+    return false;
+  }
+
+  bool result = checkNameRelation(m_hyperRelation, m_hyperKRegex.expand(), m_hyperPRegex.expand());
+  if (!result) {
+    std::ostringstream os;
+    os << "KeyLocator check failed: hyper relation " << m_hyperRelation
+       << " pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex
+       << " of packet " << pktName << " (KeyLocator=" << klName << ") is invalid";
+    state->fail({ValidationError::POLICY_ERROR, os.str()});
+  }
+  return result;
+}
+
+unique_ptr<Checker>
+Checker::create(const ConfigSection& configSection, const std::string& configFilename)
+{
+  auto propertyIt = configSection.begin();
+
+  // Get checker.type
+  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
+    BOOST_THROW_EXCEPTION(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 {
+    BOOST_THROW_EXCEPTION(Error("Unsupported checker type: " + type));
+  }
+}
+
+unique_ptr<Checker>
+Checker::createCustomizedChecker(const ConfigSection& configSection,
+                                        const std::string& configFilename)
+{
+  auto propertyIt = configSection.begin();
+  propertyIt++;
+
+  // TODO implement restrictions based on signature type (outside this checker)
+
+  if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
+    // ignore sig-type
+    propertyIt++;
+  }
+
+  // Get checker.key-locator
+  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator")) {
+    BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator>"));
+  }
+
+  auto checker = createKeyLocatorChecker(propertyIt->second, configFilename);
+  propertyIt++;
+
+  if (propertyIt != configSection.end()) {
+    BOOST_THROW_EXCEPTION(Error("Expect the end of checker"));
+  }
+
+  return checker;
+}
+
+unique_ptr<Checker>
+Checker::createHierarchicalChecker(const ConfigSection& configSection,
+                                          const std::string& configFilename)
+{
+  auto propertyIt = configSection.begin();
+  propertyIt++;
+
+  // TODO implement restrictions based on signature type (outside this checker)
+
+  if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
+    // ignore sig-type
+    propertyIt++;
+  }
+
+  if (propertyIt != configSection.end()) {
+    BOOST_THROW_EXCEPTION(Error("Expect the end of checker"));
+  }
+
+  return make_unique<HyperRelationChecker>("^(<>*)$",        "\\1",
+                                           "^(<>*)<KEY><>$", "\\1",
+                                           NameRelation::IS_PREFIX_OF);
+}
+
+///
+
+unique_ptr<Checker>
+Checker::createKeyLocatorChecker(const ConfigSection& configSection, const std::string& configFilename)
+{
+  auto propertyIt = configSection.begin();
+
+  // Get checker.key-locator.type
+  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
+    BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.type>"));
+
+  std::string type = propertyIt->second.data();
+
+  if (boost::iequals(type, "name"))
+    return createKeyLocatorNameChecker(configSection, configFilename);
+  else
+    BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator.type: " + type));
+}
+
+unique_ptr<Checker>
+Checker::createKeyLocatorNameChecker(const ConfigSection& configSection, const std::string& configFilename)
+{
+  auto propertyIt = configSection.begin();
+  propertyIt++;
+
+  if (propertyIt == configSection.end())
+    BOOST_THROW_EXCEPTION(Error("Expect more checker.key-locator properties"));
+
+  if (boost::iequals(propertyIt->first, "name")) {
+    Name name;
+    try {
+      name = Name(propertyIt->second.data());
+    }
+    catch (const Name::Error& e) {
+      BOOST_THROW_EXCEPTION(Error("Invalid checker.key-locator.name: " + propertyIt->second.data()));
+    }
+    propertyIt++;
+
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) {
+      BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.relation>"));
+    }
+
+    std::string relationString = propertyIt->second.data();
+    propertyIt++;
+
+    NameRelation relation = getNameRelationFromString(relationString);
+
+    if (propertyIt != configSection.end()) {
+      BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator"));
+    }
+    return make_unique<NameRelationChecker>(name, relation);
+  }
+  else if (boost::iequals(propertyIt->first, "regex")) {
+    std::string regexString = propertyIt->second.data();
+    propertyIt++;
+
+    if (propertyIt != configSection.end()) {
+      BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator"));
+    }
+
+    try {
+      return make_unique<RegexChecker>(regexString);
+    }
+    catch (const Regex::Error& e) {
+      BOOST_THROW_EXCEPTION(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")) {
+      BOOST_THROW_EXCEPTION(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")) {
+      BOOST_THROW_EXCEPTION(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")) {
+      BOOST_THROW_EXCEPTION(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")) {
+      BOOST_THROW_EXCEPTION(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")) {
+      BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.p-expand>"));
+    }
+
+    std::string pExpand = hPropertyIt->second.data();
+    hPropertyIt++;
+
+    if (hPropertyIt != hSection.end()) {
+      BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator.hyper-relation"));
+    }
+
+    NameRelation relation = getNameRelationFromString(hRelation);
+    try {
+      return make_unique<HyperRelationChecker>(pRegex, pExpand, kRegex, kExpand, relation);
+    }
+    catch (const Regex::Error& e) {
+      BOOST_THROW_EXCEPTION(Error("Invalid regex for key-locator.hyper-relation"));
+    }
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator"));
+  }
+}
+
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v2/validator-config/checker.hpp b/src/security/v2/validator-config/checker.hpp
new file mode 100644
index 0000000..390dc08
--- /dev/null
+++ b/src/security/v2/validator-config/checker.hpp
@@ -0,0 +1,136 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_SECURITY_V2_VALIDATOR_CONFIG_CHECKER_HPP
+#define NDN_SECURITY_V2_VALIDATOR_CONFIG_CHECKER_HPP
+
+#include "common.hpp"
+#include "name-relation.hpp"
+#include "../../../name.hpp"
+#include "../../../util/regex.hpp"
+
+namespace ndn {
+namespace security {
+namespace v2 {
+
+class ValidationState;
+
+namespace validator_config {
+
+class Checker : noncopyable
+{
+public:
+  virtual
+  ~Checker() = default;
+
+  /**
+   * @brief Check if packet name ane KeyLocator satisfy the checker's conditions
+   *
+   * @param pktType tlv::Interest or tlv::Data
+   * @param pktName packet's name
+   * @param klName  KeyLocator's name
+   * @param state Validation state
+   *
+   * @retval false data is immediately invalid. Will call state::fail() with proper code and message.
+   * @retval true  further signature verification is needed.
+   */
+  bool
+  check(uint32_t pktType, const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state);
+
+  /**
+   * @brief create a checker from configuration section
+   *
+   * @param configSection The section containing the definition of checker.
+   * @param configFilename The configuration file name.
+   * @return a checker created from configuration
+   */
+  static unique_ptr<Checker>
+  create(const ConfigSection& configSection, const std::string& configFilename);
+
+private:
+  static unique_ptr<Checker>
+  createCustomizedChecker(const ConfigSection& configSection, const std::string& configFilename);
+
+  static unique_ptr<Checker>
+  createHierarchicalChecker(const ConfigSection& configSection, const std::string& configFilename);
+
+  static unique_ptr<Checker>
+  createKeyLocatorChecker(const ConfigSection& configSection, const std::string& configFilename);
+
+  static unique_ptr<Checker>
+  createKeyLocatorNameChecker(const ConfigSection& configSection, const std::string& configFilename);
+
+protected:
+  virtual bool
+  checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state) = 0;
+};
+
+class NameRelationChecker : public Checker
+{
+public:
+  NameRelationChecker(const Name& name, const NameRelation& relation);
+
+protected:
+  bool
+  checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state) override;
+
+private:
+  Name m_name;
+  NameRelation m_relation;
+};
+
+class RegexChecker : public Checker
+{
+public:
+  explicit
+  RegexChecker(const Regex& regex);
+
+protected:
+  bool
+  checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state) override;
+
+private:
+  Regex m_regex;
+};
+
+class HyperRelationChecker : public Checker
+{
+public:
+  HyperRelationChecker(const std::string& pktNameExpr, const std::string pktNameExpand,
+                       const std::string& klNameExpr, const std::string klNameExpand,
+                       const NameRelation& hyperRelation);
+
+protected:
+  bool
+  checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state) override;
+
+private:
+  Regex m_hyperPRegex;
+  Regex m_hyperKRegex;
+  NameRelation m_hyperRelation;
+};
+
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_V2_VALIDATOR_CONFIG_CHECKER_HPP
diff --git a/src/security/conf/common.hpp b/src/security/v2/validator-config/common.hpp
similarity index 75%
rename from src/security/conf/common.hpp
rename to src/security/v2/validator-config/common.hpp
index 3c79b7b..1663e5a 100644
--- a/src/security/conf/common.hpp
+++ b/src/security/v2/validator-config/common.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2014 Regents of the University of California.
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -21,31 +21,28 @@
  * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
  */
 
-#ifndef NDN_SECURITY_CONF_COMMON_HPP
-#define NDN_SECURITY_CONF_COMMON_HPP
+#ifndef NDN_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP
+#define NDN_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP
 
-#include "../../common.hpp"
-#include <string>
+#include "../../../common.hpp"
 #include <boost/property_tree/ptree.hpp>
 
 namespace ndn {
 namespace security {
-namespace conf {
+namespace v2 {
+namespace validator_config {
 
 typedef boost::property_tree::ptree ConfigSection;
 
 class Error : public std::runtime_error
 {
 public:
-  explicit
-  Error(const std::string& what)
-    : std::runtime_error(what)
-  {
-  }
+  using std::runtime_error::runtime_error;
 };
 
-} // namespace conf
+} // namespace validator_config
+} // namespace v2
 } // namespace security
 } // namespace ndn
 
-#endif // NDN_SECURITY_CONF_COMMON_HPP
+#endif // NDN_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP
diff --git a/src/security/v2/validator-config/filter.cpp b/src/security/v2/validator-config/filter.cpp
new file mode 100644
index 0000000..baeba1d
--- /dev/null
+++ b/src/security/v2/validator-config/filter.cpp
@@ -0,0 +1,149 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "filter.hpp"
+
+#include "data.hpp"
+#include "interest.hpp"
+#include "util/regex.hpp"
+#include "security/security-common.hpp"
+
+#include <boost/algorithm/string.hpp>
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+
+bool
+Filter::match(uint32_t pktType, const Name& pktName)
+{
+  BOOST_ASSERT(pktType == tlv::Interest || pktType == tlv::Data);
+
+  if (pktType == tlv::Interest) {
+    if (pktName.size() < signed_interest::MIN_SIZE)
+      return false;
+
+    return matchName(pktName.getPrefix(-signed_interest::MIN_SIZE));
+  }
+  else {
+    return matchName(pktName);
+  }
+}
+
+RelationNameFilter::RelationNameFilter(const Name& name, NameRelation relation)
+  : m_name(name)
+  , m_relation(relation)
+{
+}
+
+bool
+RelationNameFilter::matchName(const Name& name)
+{
+  return checkNameRelation(m_relation, m_name, name);
+}
+
+RegexNameFilter::RegexNameFilter(const Regex& regex)
+  : m_regex(regex)
+{
+}
+
+bool
+RegexNameFilter::matchName(const Name& name)
+{
+  return m_regex.match(name);
+}
+
+unique_ptr<Filter>
+Filter::create(const ConfigSection& configSection, const std::string& configFilename)
+{
+  auto propertyIt = configSection.begin();
+
+  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
+    BOOST_THROW_EXCEPTION(Error("Expect <filter.type>"));
+  }
+
+  std::string type = propertyIt->second.data();
+
+  if (boost::iequals(type, "name"))
+    return createNameFilter(configSection, configFilename);
+  else
+    BOOST_THROW_EXCEPTION(Error("Unsupported filter.type: " + type));
+}
+
+unique_ptr<Filter>
+Filter::createNameFilter(const ConfigSection& configSection, const std::string& configFilename)
+{
+  auto propertyIt = configSection.begin();
+  propertyIt++;
+
+  if (propertyIt == configSection.end()) {
+    BOOST_THROW_EXCEPTION(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 (const Name::Error& e) {
+      BOOST_THROW_EXCEPTION(Error("Wrong filter.name: " + propertyIt->second.data()));
+    }
+
+    propertyIt++;
+
+    // Get filter.relation
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) {
+      BOOST_THROW_EXCEPTION(Error("Expect <filter.relation>"));
+    }
+
+    NameRelation relation = getNameRelationFromString(propertyIt->second.data());
+    propertyIt++;
+
+    if (propertyIt != configSection.end())
+      BOOST_THROW_EXCEPTION(Error("Expect the end of filter"));
+
+    return make_unique<RelationNameFilter>(name, relation);
+  }
+  else if (boost::iequals(propertyIt->first, "regex")) {
+    std::string regexString = propertyIt->second.data();
+    propertyIt++;
+
+    if (propertyIt != configSection.end())
+      BOOST_THROW_EXCEPTION(Error("Expect the end of filter"));
+
+    try {
+      return make_unique<RegexNameFilter>(regexString);
+    }
+    catch (const Regex::Error& e) {
+      BOOST_THROW_EXCEPTION(Error("Wrong filter.regex: " + regexString));
+    }
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("Wrong filter(name) properties"));
+  }
+}
+
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v2/validator-config/filter.hpp b/src/security/v2/validator-config/filter.hpp
new file mode 100644
index 0000000..cbd5275
--- /dev/null
+++ b/src/security/v2/validator-config/filter.hpp
@@ -0,0 +1,142 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_SECURITY_V2_VALIDATOR_CONFIG_FILTER_HPP
+#define NDN_SECURITY_V2_VALIDATOR_CONFIG_FILTER_HPP
+
+#include "common.hpp"
+#include "name-relation.hpp"
+#include "../../../interest.hpp"
+#include "../../../data.hpp"
+#include "../../../util/regex.hpp"
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+
+/**
+ * @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 : noncopyable
+{
+public:
+  virtual
+  ~Filter() = default;
+
+  bool
+  match(uint32_t pktType, const Name& pktName);
+
+public:
+  /**
+   * @brief Create a filter from the configuration section
+   *
+   * @param configSection The section containing the definition of filter.
+   * @param configFilename The configuration file name.
+   * @return a filter created from configuration
+   */
+  static unique_ptr<Filter>
+  create(const ConfigSection& configSection, const std::string& configFilename);
+
+private:
+  static unique_ptr<Filter>
+  createNameFilter(const ConfigSection& configSection, const std::string& configFilename);
+
+private:
+  virtual bool
+  matchName(const Name& pktName) = 0;
+};
+
+/**
+ * @brief Check that name is in relation to the packet name
+ *
+ * The following configuration
+ * @code
+ * filter
+ * {
+ *   type name
+ *   name /example
+ *   relation is-prefix-of
+ * }
+ * @endcode
+ *
+ * creates
+ * @code
+ * RelationNameFilter("/example", RelationNameFilter::RELATION_IS_PREFIX_OF);
+ * @endcode
+ */
+class RelationNameFilter : public Filter
+{
+public:
+  RelationNameFilter(const Name& name, NameRelation relation);
+
+private:
+  bool
+  matchName(const Name& pktName) override;
+
+private:
+  Name m_name;
+  NameRelation m_relation;
+};
+
+/**
+ * @brief Filter to check that packet name matches the specified regular expression
+ *
+ * The following configuration
+ * @code
+ * filter
+ * {
+ *   type name
+ *   regex ^[^<KEY>]*<KEY><>*<ksk-.*>$
+ * }
+ * @endcode
+ *
+ * creates
+ * @code
+ * RegexNameFilter("^[^<KEY>]*<KEY><>*<ksk-.*>$");
+ * @endcode
+ *
+ * @sa Regex
+ */
+class RegexNameFilter : public Filter
+{
+public:
+  explicit
+  RegexNameFilter(const Regex& regex);
+
+private:
+  bool
+  matchName(const Name& pktName) override;
+
+private:
+  Regex m_regex;
+};
+
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_V2_VALIDATOR_CONFIG_FILTER_HPP
diff --git a/src/security/v2/validator-config/name-relation.cpp b/src/security/v2/validator-config/name-relation.cpp
new file mode 100644
index 0000000..ad65e9a
--- /dev/null
+++ b/src/security/v2/validator-config/name-relation.cpp
@@ -0,0 +1,79 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "name-relation.hpp"
+
+#include <boost/algorithm/string.hpp>
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+
+std::ostream&
+operator<<(std::ostream& os, NameRelation relation)
+{
+  switch (relation)  {
+    case NameRelation::EQUAL:
+      return os << "equal";
+    case NameRelation::IS_PREFIX_OF:
+      return os << "is-prefix-of";
+    case NameRelation::IS_STRICT_PREFIX_OF:
+      return os << "is-strict-prefix-of";
+  }
+  return os;
+}
+
+bool
+checkNameRelation(NameRelation relation, const Name& name1, const Name& name2)
+{
+  switch (relation)  {
+    case NameRelation::EQUAL:
+      return name1 == name2;
+    case NameRelation::IS_PREFIX_OF:
+      return name1.isPrefixOf(name2);
+    case NameRelation::IS_STRICT_PREFIX_OF:
+      return name1.isPrefixOf(name2) && name1.size() < name2.size();
+  }
+  return false;
+}
+
+NameRelation
+getNameRelationFromString(const std::string& relationString)
+{
+  if (boost::iequals(relationString, "equal")) {
+    return NameRelation::EQUAL;
+  }
+  else if (boost::iequals(relationString, "is-prefix-of")) {
+    return NameRelation::IS_PREFIX_OF;
+  }
+  else if (boost::iequals(relationString, "is-strict-prefix-of")) {
+    return NameRelation::IS_STRICT_PREFIX_OF;
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("Unsupported relation: " + relationString));
+  }
+}
+
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v2/validator-config/name-relation.hpp b/src/security/v2/validator-config/name-relation.hpp
new file mode 100644
index 0000000..5aa0dcf
--- /dev/null
+++ b/src/security/v2/validator-config/name-relation.hpp
@@ -0,0 +1,60 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_SECURITY_V2_VALIDATOR_CONFIG_NAME_RELATION_HPP
+#define NDN_SECURITY_V2_VALIDATOR_CONFIG_NAME_RELATION_HPP
+
+#include "common.hpp"
+#include "../../../name.hpp"
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+
+enum class NameRelation {
+  EQUAL,
+  IS_PREFIX_OF,
+  IS_STRICT_PREFIX_OF
+};
+
+std::ostream&
+operator<<(std::ostream& os, NameRelation relation);
+
+/**
+ * @brief check whether @p name1 and @p name2 satisfies @p relation
+ */
+bool
+checkNameRelation(NameRelation relation, const Name& name1, const Name& name2);
+
+/**
+ * @brief convert @p relationString to NameRelation
+ * @throw Error if @p relationString cannot be converted
+ */
+NameRelation
+getNameRelationFromString(const std::string& relationString);
+
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_V2_VALIDATOR_CONFIG_NAME_RELATION_HPP
diff --git a/src/security/v2/validator-config/rule.cpp b/src/security/v2/validator-config/rule.cpp
new file mode 100644
index 0000000..93b8df4
--- /dev/null
+++ b/src/security/v2/validator-config/rule.cpp
@@ -0,0 +1,169 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "rule.hpp"
+#include "util/logger.hpp"
+
+#include <boost/algorithm/string/predicate.hpp>
+
+NDN_LOG_INIT(ndn.security.validator_config.Rule);
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+
+Rule::Rule(const std::string& id, uint32_t pktType)
+  : m_id(id)
+  , m_pktType(pktType)
+{
+}
+
+void
+Rule::addFilter(unique_ptr<Filter> filter)
+{
+  m_filters.push_back(std::move(filter));
+}
+
+void
+Rule::addChecker(unique_ptr<Checker> checker)
+{
+  m_checkers.push_back(std::move(checker));
+}
+
+bool
+Rule::match(uint32_t pktType, const Name& pktName) const
+{
+  NDN_LOG_TRACE("Trying to match " << pktName);
+  if (pktType != m_pktType) {
+    BOOST_THROW_EXCEPTION(Error("Invalid packet type supplied (" +
+                                to_string(pktType) + " != " + to_string(m_pktType) + ")"));
+  }
+
+  if (m_filters.empty()) {
+    return true;
+  }
+
+  bool retval = false;
+  for (const auto& filter : m_filters) {
+    retval |= filter->match(pktType, pktName);
+    if (retval) {
+      break;
+    }
+  }
+  return retval;
+}
+
+bool
+Rule::check(uint32_t pktType, const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state) const
+{
+  NDN_LOG_TRACE("Trying to check " << pktName << " with keyLocator " << klName);
+
+  if (pktType != m_pktType) {
+    BOOST_THROW_EXCEPTION(Error("Invalid packet type supplied (" +
+                                to_string(pktType) + " != " + to_string(m_pktType) + ")"));
+  }
+
+  bool hasPendingResult = false;
+  for (const auto& checker : m_checkers) {
+    bool result = checker->check(pktType, pktName, klName, state);
+    if (!result) {
+      return result;
+    }
+    hasPendingResult = true;
+  }
+
+  return hasPendingResult;
+}
+
+unique_ptr<Rule>
+Rule::create(const ConfigSection& configSection, const std::string& configFilename)
+{
+  auto propertyIt = configSection.begin();
+
+  // Get rule.id
+  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "id")) {
+    BOOST_THROW_EXCEPTION(Error("Expecting <rule.id>"));
+  }
+
+  std::string ruleId = propertyIt->second.data();
+  propertyIt++;
+
+  // Get rule.for
+  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "for")) {
+    BOOST_THROW_EXCEPTION(Error("Expecting <rule.for> in rule: " + ruleId));
+  }
+
+  std::string usage = propertyIt->second.data();
+  propertyIt++;
+
+  bool isForData = false;
+  if (boost::iequals(usage, "data")) {
+    isForData = true;
+  }
+  else if (boost::iequals(usage, "interest")) {
+    isForData = false;
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("Unrecognized <rule.for>: " + usage + " in rule: " + ruleId));
+  }
+
+  auto rule = make_unique<Rule>(ruleId, isForData ? tlv::Data : tlv::Interest);
+
+  // Get rule.filter(s)
+  for (; propertyIt != configSection.end(); propertyIt++) {
+    if (!boost::iequals(propertyIt->first, "filter")) {
+      if (boost::iequals(propertyIt->first, "checker")) {
+        break;
+      }
+      BOOST_THROW_EXCEPTION(Error("Expecting <rule.filter> in rule: " + ruleId));
+    }
+
+    rule->addFilter(Filter::create(propertyIt->second, configFilename));
+  }
+
+  // Get rule.checker(s)
+  bool hasCheckers = false;
+  for (; propertyIt != configSection.end(); propertyIt++) {
+    if (!boost::iequals(propertyIt->first, "checker")) {
+      BOOST_THROW_EXCEPTION(Error("Expecting <rule.checker> in rule: " + ruleId));
+    }
+
+    rule->addChecker(Checker::create(propertyIt->second, configFilename));
+    hasCheckers = true;
+  }
+
+  // Check other stuff
+  if (propertyIt != configSection.end()) {
+    BOOST_THROW_EXCEPTION(Error("Expecting the end of rule: " + ruleId));
+  }
+
+  if (!hasCheckers) {
+    BOOST_THROW_EXCEPTION(Error("No <rule.checker> is specified in rule: " + ruleId));
+  }
+
+  return rule;
+}
+
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v2/validator-config/rule.hpp b/src/security/v2/validator-config/rule.hpp
new file mode 100644
index 0000000..66d6d6a
--- /dev/null
+++ b/src/security/v2/validator-config/rule.hpp
@@ -0,0 +1,113 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_SECURITY_V2_VALIDATOR_CONFIG_RULE_HPP
+#define NDN_SECURITY_V2_VALIDATOR_CONFIG_RULE_HPP
+
+#include "filter.hpp"
+#include "checker.hpp"
+
+namespace ndn {
+namespace security {
+namespace v2 {
+
+class ValidationState;
+
+namespace validator_config {
+
+class Rule : noncopyable
+{
+public:
+  Rule(const std::string& id, uint32_t pktType);
+
+  const std::string&
+  getId() const
+  {
+    return m_id;
+  }
+
+  uint32_t
+  getPktType() const
+  {
+    return m_pktType;
+  }
+
+  void
+  addFilter(unique_ptr<Filter> filter);
+
+  void
+  addChecker(unique_ptr<Checker> checker);
+
+  /**
+   * @brief check if the packet name matches rule's filter
+   *
+   * If no filters were added, the rule matches everything.
+   *
+   * @param pktType tlv::Interest or tlv::Data
+   * @param pktName packet name, for signed Interests the last two components are not removed
+   * @retval true  If at least one filter matches @p pktName
+   * @retval false If none of the filters match @p pktName
+   *
+   * @throw Error the supplied pktType doesn't match one for which the rule is designed
+   */
+  bool
+  match(uint32_t pktType, const Name& pktName) const;
+
+  /**
+   * @brief check if packet satisfies rule's condition
+   *
+   * @param pktType tlv::Interest or tlv::Data
+   * @param pktName packet name, for signed Interests the last two components are not removed
+   * @param klName KeyLocator name
+   * @param state Validation state
+   *
+   * @retval false packet violates at least one checker. Will call state::fail() with proper code and message.
+   * @retval true  packet satisfies all checkers, further validation is needed
+   *
+   * @throw Error the supplied pktType doesn't match one for which the rule is designed
+   */
+  bool
+  check(uint32_t pktType, const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state) const;
+
+public:
+  /**
+   * @brief create a rule from configuration section
+   *
+   * @param configSection The section containing the definition of checker.
+   * @param configFilename The configuration file name.
+   * @return a rule created from configuration
+   */
+  static unique_ptr<Rule>
+  create(const ConfigSection& configSection, const std::string& configFilename);
+
+NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  std::string m_id;
+  uint32_t m_pktType;
+  std::vector<unique_ptr<Filter>> m_filters;
+  std::vector<unique_ptr<Checker>> m_checkers;
+};
+
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_V2_VALIDATOR_CONFIG_RULE_HPP
diff --git a/src/security/validator-config.cpp b/src/security/validator-config.cpp
index f267377..a8c5abc 100644
--- a/src/security/validator-config.cpp
+++ b/src/security/validator-config.cpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -20,770 +20,47 @@
  */
 
 #include "validator-config.hpp"
-#include "certificate-cache-ttl.hpp"
-#include "../util/io.hpp"
-#include "../lp/tags.hpp"
-
-#include <boost/filesystem.hpp>
-#include <boost/property_tree/info_parser.hpp>
-#include <boost/algorithm/string.hpp>
+#include "v2/certificate-fetcher-from-network.hpp"
 
 namespace ndn {
 namespace security {
 
-const shared_ptr<CertificateCache> ValidatorConfig::DEFAULT_CERTIFICATE_CACHE;
-const time::milliseconds ValidatorConfig::DEFAULT_GRACE_INTERVAL(3000);
-const time::system_clock::Duration ValidatorConfig::DEFAULT_KEY_TIMESTAMP_TTL = time::hours(1);
-
-ValidatorConfig::ValidatorConfig(Face* face,
-                                 const shared_ptr<CertificateCache>& certificateCache,
-                                 const time::milliseconds& graceInterval,
-                                 const size_t stepLimit,
-                                 const size_t maxTrackedKeys,
-                                 const time::system_clock::Duration& keyTimestampTtl)
-  : Validator(face)
-  , m_shouldValidate(true)
-  , m_stepLimit(stepLimit)
-  , m_certificateCache(certificateCache)
-  , m_graceInterval(graceInterval < time::milliseconds::zero() ?
-                    DEFAULT_GRACE_INTERVAL : graceInterval)
-  , m_maxTrackedKeys(maxTrackedKeys)
-  , m_keyTimestampTtl(keyTimestampTtl)
+ValidatorConfig::ValidatorConfig(std::unique_ptr<v2::CertificateFetcher> fetcher, const Options& options)
+  : v2::Validator(make_unique<v2::ValidationPolicyCommandInterest>(make_unique<v2::ValidationPolicyConfig>(),
+                                                                   options),
+                  std::move(fetcher))
+  , m_policyConfig(static_cast<v2::ValidationPolicyConfig&>(getPolicy().getInnerPolicy()))
 {
-  if (m_certificateCache == nullptr && face != nullptr)
-    m_certificateCache = make_shared<CertificateCacheTtl>(ref(face->getIoService()));
 }
 
-ValidatorConfig::ValidatorConfig(Face& face,
-                                 const shared_ptr<CertificateCache>& certificateCache,
-                                 const time::milliseconds& graceInterval,
-                                 const size_t stepLimit,
-                                 const size_t maxTrackedKeys,
-                                 const time::system_clock::Duration& keyTimestampTtl)
-  : Validator(face)
-  , m_shouldValidate(true)
-  , m_stepLimit(stepLimit)
-  , m_certificateCache(certificateCache)
-  , m_graceInterval(graceInterval < time::milliseconds::zero() ?
-                    DEFAULT_GRACE_INTERVAL : graceInterval)
-  , m_maxTrackedKeys(maxTrackedKeys)
-  , m_keyTimestampTtl(keyTimestampTtl)
+ValidatorConfig::ValidatorConfig(Face& face, const Options& options)
+  : ValidatorConfig(make_unique<v2::CertificateFetcherFromNetwork>(face), options)
 {
-  if (m_certificateCache == nullptr)
-    m_certificateCache = make_shared<CertificateCacheTtl>(ref(face.getIoService()));
 }
 
 void
 ValidatorConfig::load(const std::string& filename)
 {
-  std::ifstream inputFile;
-  inputFile.open(filename.c_str());
-  if (!inputFile.good() || !inputFile.is_open()) {
-    std::string msg = "Failed to read configuration file: ";
-    msg += filename;
-    BOOST_THROW_EXCEPTION(security::conf::Error(msg));
-  }
-  load(inputFile, filename);
-  inputFile.close();
+  m_policyConfig.load(filename);
 }
 
 void
 ValidatorConfig::load(const std::string& input, const std::string& filename)
 {
-  std::istringstream inputStream(input);
-  load(inputStream, filename);
+  m_policyConfig.load(input, filename);
 }
 
-
 void
 ValidatorConfig::load(std::istream& input, const std::string& filename)
 {
-  security::conf::ConfigSection tree;
-  try {
-    boost::property_tree::read_info(input, tree);
-  }
-  catch (const boost::property_tree::info_parser_error& error) {
-    std::stringstream msg;
-    msg << "Failed to parse configuration file";
-    msg << " " << filename;
-    msg << " " << error.message() << " line " << error.line();
-    BOOST_THROW_EXCEPTION(security::conf::Error(msg.str()));
-  }
-
-  load(tree, filename);
+  m_policyConfig.load(input, filename);
 }
 
 void
-ValidatorConfig::load(const security::conf::ConfigSection& configSection,
+ValidatorConfig::load(const v2::validator_config::ConfigSection& configSection,
                       const std::string& filename)
 {
-  BOOST_ASSERT(!filename.empty());
-
-  reset();
-
-  if (configSection.begin() == configSection.end()) {
-    std::string msg = "Error processing configuration file";
-    msg += ": ";
-    msg += filename;
-    msg += " no data";
-    BOOST_THROW_EXCEPTION(security::conf::Error(msg));
-  }
-
-  for (security::conf::ConfigSection::const_iterator i = configSection.begin();
-       i != configSection.end(); ++i) {
-    const std::string& sectionName = i->first;
-    const security::conf::ConfigSection& section = i->second;
-
-    if (boost::iequals(sectionName, "rule")) {
-      onConfigRule(section, filename);
-    }
-    else if (boost::iequals(sectionName, "trust-anchor")) {
-      onConfigTrustAnchor(section, filename);
-    }
-    else {
-      std::string msg = "Error processing configuration file";
-      msg += " ";
-      msg += filename;
-      msg += " unrecognized section: " + sectionName;
-      BOOST_THROW_EXCEPTION(security::conf::Error(msg));
-    }
-  }
-}
-
-void
-ValidatorConfig::onConfigRule(const security::conf::ConfigSection& configSection,
-                              const std::string& filename)
-{
-  using namespace ndn::security::conf;
-
-  ConfigSection::const_iterator propertyIt = configSection.begin();
-
-  // Get rule.id
-  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "id"))
-    BOOST_THROW_EXCEPTION(Error("Expect <rule.id>!"));
-
-  std::string ruleId = propertyIt->second.data();
-  propertyIt++;
-
-  // Get rule.for
-  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,"for"))
-    BOOST_THROW_EXCEPTION(Error("Expect <rule.for> in rule: " + ruleId + "!"));
-
-  std::string usage = propertyIt->second.data();
-  propertyIt++;
-
-  bool isForData = false;
-  if (boost::iequals(usage, "data"))
-    isForData = true;
-  else if (boost::iequals(usage, "interest"))
-    isForData = false;
-  else
-    BOOST_THROW_EXCEPTION(Error("Unrecognized <rule.for>: " + usage
-                                + " in rule: " + ruleId));
-
-  // Get rule.filter(s)
-  std::vector<shared_ptr<Filter>> filters;
-  for (; propertyIt != configSection.end(); propertyIt++) {
-    if (!boost::iequals(propertyIt->first, "filter")) {
-      if (boost::iequals(propertyIt->first, "checker"))
-        break;
-      BOOST_THROW_EXCEPTION(Error("Expect <rule.filter> in rule: " + ruleId));
-    }
-
-    filters.push_back(FilterFactory::create(propertyIt->second));
-    continue;
-  }
-
-  // Get rule.checker(s)
-  std::vector<shared_ptr<Checker>> checkers;
-  for (; propertyIt != configSection.end(); propertyIt++) {
-    if (!boost::iequals(propertyIt->first, "checker"))
-      BOOST_THROW_EXCEPTION(Error("Expect <rule.checker> in rule: " + ruleId));
-
-    checkers.push_back(CheckerFactory::create(propertyIt->second, filename));
-    continue;
-  }
-
-  // Check other stuff
-  if (propertyIt != configSection.end())
-    BOOST_THROW_EXCEPTION(Error("Expect the end of rule: " + ruleId));
-
-  if (checkers.empty())
-    BOOST_THROW_EXCEPTION(Error("No <rule.checker> is specified in rule: " + ruleId));
-
-  if (isForData) {
-    shared_ptr<DataRule> rule = make_shared<DataRule>(ruleId);
-    for (const auto& filter : filters)
-      rule->addFilter(filter);
-    for (const auto& checker : checkers)
-      rule->addChecker(checker);
-
-    m_dataRules.push_back(rule);
-  }
-  else {
-    shared_ptr<InterestRule> rule = make_shared<InterestRule>(ruleId);;
-    for (const auto& filter : filters)
-      rule->addFilter(filter);
-    for (const auto& checker : checkers)
-      rule->addChecker(checker);
-
-    m_interestRules.push_back(rule);
-  }
-}
-
-void
-ValidatorConfig::onConfigTrustAnchor(const security::conf::ConfigSection& configSection,
-                                     const std::string& filename)
-{
-  using namespace ndn::security::conf;
-  using namespace boost::filesystem;
-
-  ConfigSection::const_iterator propertyIt = configSection.begin();
-
-  // Get trust-anchor.type
-  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
-    BOOST_THROW_EXCEPTION(Error("Expect <trust-anchor.type>!"));
-
-  std::string type = propertyIt->second.data();
-  propertyIt++;
-
-  if (boost::iequals(type, "file")) {
-    // Get trust-anchor.file
-    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name"))
-      BOOST_THROW_EXCEPTION(Error("Expect <trust-anchor.file-name>!"));
-
-    std::string file = propertyIt->second.data();
-    propertyIt++;
-
-    // Check other stuff
-    if (propertyIt != configSection.end())
-      BOOST_THROW_EXCEPTION(Error("Expect the end of trust-anchor!"));
-
-    path certfilePath = absolute(file, path(filename).parent_path());
-    auto idCert = io::load<v1::IdentityCertificate>(certfilePath.string());
-
-    if (idCert != nullptr) {
-      BOOST_ASSERT(idCert->getName().size() >= 1);
-      m_staticContainer.add(idCert);
-      m_anchors[idCert->getName().getPrefix(-1)] = idCert;
-    }
-    else
-      BOOST_THROW_EXCEPTION(Error("Cannot read certificate from file: " + certfilePath.native()));
-
-    return;
-  }
-  else if (boost::iequals(type, "base64")) {
-    // Get trust-anchor.base64-string
-    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "base64-string"))
-      BOOST_THROW_EXCEPTION(Error("Expect <trust-anchor.base64-string>!"));
-
-    std::stringstream ss(propertyIt->second.data());
-    propertyIt++;
-
-    // Check other stuff
-    if (propertyIt != configSection.end())
-      BOOST_THROW_EXCEPTION(Error("Expect the end of trust-anchor!"));
-
-    auto idCert = io::load<v1::IdentityCertificate>(ss);
-
-    if (idCert != nullptr) {
-      BOOST_ASSERT(idCert->getName().size() >= 1);
-      m_staticContainer.add(idCert);
-      m_anchors[idCert->getName().getPrefix(-1)] = idCert;
-    }
-    else
-      BOOST_THROW_EXCEPTION(Error("Cannot decode certificate from base64-string"));
-
-    return;
-  }
-  else if (boost::iequals(type, "dir")) {
-    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "dir"))
-      BOOST_THROW_EXCEPTION(Error("Expect <trust-anchor.dir>"));
-
-    std::string dirString(propertyIt->second.data());
-    propertyIt++;
-
-    if (propertyIt != configSection.end()) {
-      if (boost::iequals(propertyIt->first, "refresh")) {
-        using namespace boost::filesystem;
-
-        time::nanoseconds refresh = getRefreshPeriod(propertyIt->second.data());
-        propertyIt++;
-
-        if (propertyIt != configSection.end())
-          BOOST_THROW_EXCEPTION(Error("Expect the end of trust-anchor"));
-
-        path dirPath = absolute(dirString, path(filename).parent_path());
-
-        m_dynamicContainers.push_back(DynamicTrustAnchorContainer(dirPath, true, refresh));
-
-        m_dynamicContainers.rbegin()->setLastRefresh(time::system_clock::now() - refresh);
-
-        return;
-      }
-      else
-        BOOST_THROW_EXCEPTION(Error("Expect <trust-anchor.refresh>!"));
-    }
-    else {
-      using namespace boost::filesystem;
-
-      path dirPath = absolute(dirString, path(filename).parent_path());
-
-      directory_iterator end;
-
-      for (directory_iterator it(dirPath); it != end; it++) {
-        auto idCert = io::load<v1::IdentityCertificate>(it->path().string());
-
-        if (idCert != nullptr)
-          m_staticContainer.add(idCert);
-      }
-
-      return;
-    }
-  }
-  else if (boost::iequals(type, "any")) {
-    m_shouldValidate = false;
-  }
-  else
-    BOOST_THROW_EXCEPTION(Error("Unsupported trust-anchor.type: " + type));
-}
-
-void
-ValidatorConfig::reset()
-{
-  if (m_certificateCache != nullptr)
-    m_certificateCache->reset();
-  m_interestRules.clear();
-  m_dataRules.clear();
-
-  m_anchors.clear();
-
-  m_staticContainer = TrustAnchorContainer();
-
-  m_dynamicContainers.clear();
-}
-
-bool
-ValidatorConfig::isEmpty()
-{
-  return ((m_certificateCache == nullptr || m_certificateCache->isEmpty()) &&
-          m_interestRules.empty() && m_dataRules.empty() && m_anchors.empty());
-}
-
-time::nanoseconds
-ValidatorConfig::getRefreshPeriod(std::string inputString)
-{
-  char unit = inputString[inputString.size() - 1];
-  std::string refreshString = inputString.substr(0, inputString.size() - 1);
-
-  uint32_t refreshPeriod = 0;
-
-  try {
-    refreshPeriod = boost::lexical_cast<uint32_t>(refreshString);
-  }
-  catch (const boost::bad_lexical_cast&) {
-    BOOST_THROW_EXCEPTION(Error("Bad number: " + refreshString));
-  }
-
-  if (refreshPeriod == 0)
-    return getDefaultRefreshPeriod();
-
-  switch (unit) {
-  case 'h':
-    return time::duration_cast<time::nanoseconds>(time::hours(refreshPeriod));
-  case 'm':
-    return time::duration_cast<time::nanoseconds>(time::minutes(refreshPeriod));
-  case 's':
-    return time::duration_cast<time::nanoseconds>(time::seconds(refreshPeriod));
-  default:
-    BOOST_THROW_EXCEPTION(Error(std::string("Wrong time unit: ") + unit));
-  }
-}
-
-time::nanoseconds
-ValidatorConfig::getDefaultRefreshPeriod()
-{
-  return time::duration_cast<time::nanoseconds>(time::seconds(3600));
-}
-
-void
-ValidatorConfig::refreshAnchors()
-{
-  time::system_clock::TimePoint now = time::system_clock::now();
-
-  bool isRefreshed = false;
-
-  for (auto cIt = m_dynamicContainers.begin();
-       cIt != m_dynamicContainers.end() && cIt->getLastRefresh() + cIt->getRefreshPeriod() < now;
-       cIt++) {
-    isRefreshed = true;
-    cIt->refresh();
-    cIt->setLastRefresh(now);
-  }
-
-  if (isRefreshed) {
-    m_anchors.clear();
-
-    for (const auto& cert : m_staticContainer.getAll()) {
-      m_anchors[cert->getName().getPrefix(-1)] = cert;
-    }
-
-    for (const auto& container : m_dynamicContainers) {
-      const CertificateList& certList = container.getAll();
-
-      for (const auto& cert :certList) {
-        m_anchors[cert->getName().getPrefix(-1)] = cert;
-      }
-    }
-    m_dynamicContainers.sort(ValidatorConfig::compareDynamicContainer);
-  }
-}
-
-void
-ValidatorConfig::checkPolicy(const Data& data,
-                             int nSteps,
-                             const OnDataValidated& onValidated,
-                             const OnDataValidationFailed& onValidationFailed,
-                             std::vector<shared_ptr<ValidationRequest>>& nextSteps)
-{
-  if (!m_shouldValidate)
-    return onValidated(data.shared_from_this());
-
-  bool isMatched = false;
-  int8_t checkResult = -1;
-
-  for (const auto& dataRule : m_dataRules) {
-    if (dataRule->match(data)) {
-      isMatched = true;
-      checkResult = dataRule->check(data, onValidated, onValidationFailed);
-      break;
-    }
-  }
-
-  if (!isMatched)
-    return onValidationFailed(data.shared_from_this(), "No rule matched!");
-
-  if (checkResult == 0) {
-    const Signature& signature = data.getSignature();
-    checkSignature(data, signature, nSteps,
-                   onValidated, onValidationFailed, nextSteps);
-  }
-}
-
-void
-ValidatorConfig::checkPolicy(const Interest& interest,
-                             int nSteps,
-                             const OnInterestValidated& onValidated,
-                             const OnInterestValidationFailed& onValidationFailed,
-                             std::vector<shared_ptr<ValidationRequest>>& nextSteps)
-{
-  if (!m_shouldValidate)
-    return onValidated(interest.shared_from_this());
-
-  // If interestName has less than 4 name components,
-  // it is definitely not a signed interest.
-  if (interest.getName().size() < command_interest::MIN_SIZE)
-    return onValidationFailed(interest.shared_from_this(),
-                              "Interest is not signed: " + interest.getName().toUri());
-
-  try {
-    const Name& interestName = interest.getName();
-    Signature signature(interestName[command_interest::POS_SIG_INFO].blockFromValue(),
-                        interestName[command_interest::POS_SIG_VALUE].blockFromValue());
-
-    if (!signature.hasKeyLocator())
-      return onValidationFailed(interest.shared_from_this(), "No valid KeyLocator");
-
-    const KeyLocator& keyLocator = signature.getKeyLocator();
-
-    if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
-      return onValidationFailed(interest.shared_from_this(), "Key Locator is not a name");
-
-    Name keyName = v1::IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName());
-
-    bool isMatched = false;
-    int8_t checkResult = -1;
-
-    for (const auto& interestRule : m_interestRules) {
-      if (interestRule->match(interest)) {
-        isMatched = true;
-        checkResult = interestRule->check(interest,
-                                          bind(&ValidatorConfig::checkTimestamp, this, _1,
-                                               keyName, onValidated, onValidationFailed),
-                                          onValidationFailed);
-        break;
-      }
-    }
-
-    if (!isMatched)
-      return onValidationFailed(interest.shared_from_this(), "No rule matched!");
-
-    if (checkResult == 0) {
-      checkSignature<Interest, OnInterestValidated, OnInterestValidationFailed>
-        (interest, signature, nSteps,
-         bind(&ValidatorConfig::checkTimestamp, this, _1,
-              keyName, onValidated, onValidationFailed),
-         onValidationFailed,
-         nextSteps);
-    }
-  }
-  catch (const Signature::Error& e) {
-    return onValidationFailed(interest.shared_from_this(), "No valid signature");
-  }
-  catch (const KeyLocator::Error& e){
-    return onValidationFailed(interest.shared_from_this(), "No valid KeyLocator");
-  }
-  catch (const v1::IdentityCertificate::Error& e){
-    return onValidationFailed(interest.shared_from_this(), "Cannot determine the signing key");
-  }
-  catch (const tlv::Error& e){
-    return onValidationFailed(interest.shared_from_this(), "Cannot decode signature");
-  }
-}
-
-void
-ValidatorConfig::checkTimestamp(const shared_ptr<const Interest>& interest,
-                                const Name& keyName,
-                                const OnInterestValidated& onValidated,
-                                const OnInterestValidationFailed& onValidationFailed)
-{
-  const Name& interestName = interest->getName();
-  time::system_clock::TimePoint interestTime;
-
-  try {
-    interestTime =
-      time::fromUnixTimestamp(time::milliseconds(interestName.at(command_interest::POS_TIMESTAMP).toNumber()));
-  }
-  catch (const tlv::Error& e) {
-    return onValidationFailed(interest,
-                              "Cannot decode signature related TLVs");
-  }
-
-  time::system_clock::TimePoint currentTime = time::system_clock::now();
-
-  LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
-  if (timestampIt == m_lastTimestamp.end()) {
-    if (!(currentTime - m_graceInterval <= interestTime &&
-          interestTime <= currentTime + m_graceInterval))
-      return onValidationFailed(interest,
-                                "The command is not in grace interval: " + interest->getName().toUri());
-  }
-  else {
-    if (interestTime <= timestampIt->second)
-      return onValidationFailed(interest,
-                                "The command is outdated: " + interest->getName().toUri());
-  }
-
-  // Update timestamp
-  if (timestampIt == m_lastTimestamp.end()) {
-    cleanOldKeys();
-    m_lastTimestamp[keyName] = interestTime;
-  }
-  else {
-    timestampIt->second = interestTime;
-  }
-
-  return onValidated(interest);
-}
-
-void
-ValidatorConfig::cleanOldKeys()
-{
-  if (m_lastTimestamp.size() < m_maxTrackedKeys)
-    return;
-
-  LastTimestampMap::iterator timestampIt = m_lastTimestamp.begin();
-  LastTimestampMap::iterator end = m_lastTimestamp.end();
-
-  time::system_clock::TimePoint now = time::system_clock::now();
-  LastTimestampMap::iterator oldestKeyIt = m_lastTimestamp.begin();
-  time::system_clock::TimePoint oldestTimestamp = oldestKeyIt->second;
-
-  while (timestampIt != end) {
-    if (now - timestampIt->second > m_keyTimestampTtl) {
-      LastTimestampMap::iterator toDelete = timestampIt;
-      timestampIt++;
-      m_lastTimestamp.erase(toDelete);
-      continue;
-    }
-
-    if (timestampIt->second < oldestTimestamp) {
-      oldestTimestamp = timestampIt->second;
-      oldestKeyIt = timestampIt;
-    }
-
-    timestampIt++;
-  }
-
-  if (m_lastTimestamp.size() >= m_maxTrackedKeys)
-    m_lastTimestamp.erase(oldestKeyIt);
-}
-
-void
-ValidatorConfig::DynamicTrustAnchorContainer::refresh()
-{
-  using namespace boost::filesystem;
-
-  m_certificates.clear();
-
-  if (m_isDir) {
-    directory_iterator end;
-
-    for (directory_iterator it(m_path); it != end; it++) {
-      auto idCert = io::load<v1::IdentityCertificate>(it->path().string());
-
-      if (idCert != nullptr)
-        m_certificates.push_back(idCert);
-    }
-  }
-  else {
-    auto idCert = io::load<v1::IdentityCertificate>(m_path.string());
-
-    if (idCert != nullptr)
-      m_certificates.push_back(idCert);
-  }
-}
-
-template<class Packet, class OnValidated, class OnFailed>
-void
-ValidatorConfig::checkSignature(const Packet& packet,
-                                const Signature& signature,
-                                size_t nSteps,
-                                const OnValidated& onValidated,
-                                const OnFailed& onValidationFailed,
-                                std::vector<shared_ptr<ValidationRequest>>& nextSteps)
-{
-  if (signature.getType() == tlv::DigestSha256) {
-    DigestSha256 sigSha256(signature);
-
-    if (verifySignature(packet, sigSha256))
-      return onValidated(packet.shared_from_this());
-    else
-      return onValidationFailed(packet.shared_from_this(), "Sha256 Signature cannot be verified!");
-  }
-
-  try {
-    switch (signature.getType()) {
-      case tlv::SignatureSha256WithRsa:
-      case tlv::SignatureSha256WithEcdsa: {
-        if (!signature.hasKeyLocator()) {
-          return onValidationFailed(packet.shared_from_this(),
-                                    "Missing KeyLocator in SignatureInfo");
-        }
-        break;
-      }
-      default:
-        return onValidationFailed(packet.shared_from_this(), "Unsupported signature type");
-    }
-  }
-  catch (const KeyLocator::Error& e) {
-    return onValidationFailed(packet.shared_from_this(),
-                              "Cannot decode KeyLocator in public key signature");
-  }
-  catch (const tlv::Error& e) {
-    return onValidationFailed(packet.shared_from_this(), "Cannot decode public key signature");
-  }
-
-  if (signature.getKeyLocator().getType() != KeyLocator::KeyLocator_Name) {
-    return onValidationFailed(packet.shared_from_this(), "Unsupported KeyLocator type");
-  }
-
-  const Name& keyLocatorName = signature.getKeyLocator().getName();
-
-  shared_ptr<const v1::Certificate> trustedCert;
-
-  refreshAnchors();
-
-  AnchorList::const_iterator it = m_anchors.find(keyLocatorName);
-  if (m_anchors.end() == it && m_certificateCache != nullptr)
-    trustedCert = m_certificateCache->getCertificate(keyLocatorName);
-  else if (m_anchors.end() != it)
-    trustedCert = it->second;
-
-  if (trustedCert != nullptr) {
-    if (verifySignature(packet, signature, trustedCert->getPublicKeyInfo()))
-      return onValidated(packet.shared_from_this());
-    else
-      return onValidationFailed(packet.shared_from_this(), "Cannot verify signature");
-  }
-  else {
-    if (m_stepLimit == nSteps)
-      return onValidationFailed(packet.shared_from_this(), "Maximum steps of validation reached");
-
-    OnDataValidated onCertValidated =
-      bind(&ValidatorConfig::onCertValidated<Packet, OnValidated, OnFailed>,
-           this, _1, packet.shared_from_this(), onValidated, onValidationFailed);
-
-    OnDataValidationFailed onCertValidationFailed =
-      bind(&ValidatorConfig::onCertFailed<Packet, OnFailed>,
-           this, _1, _2, packet.shared_from_this(), onValidationFailed);
-
-    Interest certInterest(keyLocatorName);
-
-    uint64_t incomingFaceId = 0;
-    auto incomingFaceIdTag = packet.template getTag<lp::IncomingFaceIdTag>();
-    if (incomingFaceIdTag != nullptr) {
-      incomingFaceId = incomingFaceIdTag->get();
-    }
-    auto nextStep = make_shared<ValidationRequest>(certInterest,
-                                                   onCertValidated,
-                                                   onCertValidationFailed,
-                                                   1, nSteps + 1,
-                                                   incomingFaceId);
-
-    nextSteps.push_back(nextStep);
-    return;
-  }
-  return onValidationFailed(packet.shared_from_this(), "Unsupported Signature Type");
-}
-
-template<class Packet, class OnValidated, class OnFailed>
-void
-ValidatorConfig::onCertValidated(const shared_ptr<const Data>& signCertificate,
-                                 const shared_ptr<const Packet>& packet,
-                                 const OnValidated& onValidated,
-                                 const OnFailed& onValidationFailed)
-{
-  if (signCertificate->getContentType() != tlv::ContentType_Key)
-    return onValidationFailed(packet,
-                              "Cannot retrieve signer's cert: " +
-                              signCertificate->getName().toUri());
-
-  shared_ptr<v1::IdentityCertificate> certificate;
-  try {
-    certificate = make_shared<v1::IdentityCertificate>(*signCertificate);
-  }
-  catch (const tlv::Error&) {
-    return onValidationFailed(packet,
-                              "Cannot decode signer's cert: " +
-                              signCertificate->getName().toUri());
-  }
-
-  if (!certificate->isTooLate() && !certificate->isTooEarly()) {
-    if (m_certificateCache != nullptr)
-      m_certificateCache->insertCertificate(certificate);
-
-    if (verifySignature(*packet, certificate->getPublicKeyInfo()))
-      return onValidated(packet);
-    else
-      return onValidationFailed(packet,
-                                "Cannot verify signature: " + packet->getName().toUri());
-  }
-  else {
-    return onValidationFailed(packet,
-                              "Signing certificate " +
-                              signCertificate->getName().toUri() + " is no longer valid.");
-  }
-}
-
-template<class Packet, class OnFailed>
-void
-ValidatorConfig::onCertFailed(const shared_ptr<const Data>& signCertificate,
-                              const std::string& failureInfo,
-                              const shared_ptr<const Packet>& packet,
-                              const OnFailed& onValidationFailed)
-{
-  onValidationFailed(packet, failureInfo);
+  m_policyConfig.load(configSection, filename);
 }
 
 } // namespace security
diff --git a/src/security/validator-config.hpp b/src/security/validator-config.hpp
index 47d536e..bc42e52 100644
--- a/src/security/validator-config.hpp
+++ b/src/security/validator-config.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -22,51 +22,29 @@
 #ifndef NDN_SECURITY_VALIDATOR_CONFIG_HPP
 #define NDN_SECURITY_VALIDATOR_CONFIG_HPP
 
-#include "validator.hpp"
-#include "certificate-cache.hpp"
-#include "conf/rule.hpp"
-#include "conf/common.hpp"
+#include "v2/validator.hpp"
+#include "v2/validation-policy-command-interest.hpp"
+#include "v2/validation-policy-config.hpp"
 
 namespace ndn {
 namespace security {
 
 /**
- * @brief The validator which can be set up via a configuration file.
+ * @brief Helper for validator that uses CommandInterest + Config policy and NetworkFetcher
  */
-class ValidatorConfig : public Validator
+class ValidatorConfig : public v2::Validator
 {
 public:
-  class Error : public Validator::Error
-  {
-  public:
-    explicit
-    Error(const std::string& what)
-      : Validator::Error(what)
-    {
-    }
-  };
+  using v2::Validator::Validator;
+  using Options = v2::ValidationPolicyCommandInterest::Options;
 
-  /**
-   * @note  When both certificate cache and face are not supplied, no cache will be used.
-   *        However, if only face is supplied, a default cache will be created and used.
-   */
   explicit
-  ValidatorConfig(Face* face = nullptr,
-                  const shared_ptr<CertificateCache>& certificateCache = DEFAULT_CERTIFICATE_CACHE,
-                  const time::milliseconds& graceInterval = DEFAULT_GRACE_INTERVAL,
-                  const size_t stepLimit = 10,
-                  const size_t maxTrackedKeys = 1000,
-                  const time::system_clock::Duration& keyTimestampTtl = DEFAULT_KEY_TIMESTAMP_TTL);
+  ValidatorConfig(std::unique_ptr<v2::CertificateFetcher> fetcher, const Options& options = Options());
 
-  /// @deprecated Use the constructor taking Face* as parameter.
   explicit
-  ValidatorConfig(Face& face,
-                  const shared_ptr<CertificateCache>& certificateCache = DEFAULT_CERTIFICATE_CACHE,
-                  const time::milliseconds& graceInterval = DEFAULT_GRACE_INTERVAL,
-                  const size_t stepLimit = 10,
-                  const size_t maxTrackedKeys = 1000,
-                  const time::system_clock::Duration& keyTimestampTtl = DEFAULT_KEY_TIMESTAMP_TTL);
+  ValidatorConfig(Face& face, const Options& options = Options());
 
+public: // helpers for ValidationPolicyConfig
   void
   load(const std::string& filename);
 
@@ -77,182 +55,11 @@
   load(std::istream& input, const std::string& filename);
 
   void
-  load(const security::conf::ConfigSection& configSection,
+  load(const v2::validator_config::ConfigSection& configSection,
        const std::string& filename);
 
-  void
-  reset();
-
-  bool
-  isEmpty();
-
-protected:
-  void
-  checkPolicy(const Data& data,
-              int nSteps,
-              const OnDataValidated& onValidated,
-              const OnDataValidationFailed& onValidationFailed,
-              std::vector<shared_ptr<ValidationRequest>>& nextSteps) override;
-
-  void
-  checkPolicy(const Interest& interest,
-              int nSteps,
-              const OnInterestValidated& onValidated,
-              const OnInterestValidationFailed& onValidationFailed,
-              std::vector<shared_ptr<ValidationRequest>>& nextSteps) override;
-
-private:
-  template<class Packet, class OnValidated, class OnFailed>
-  void
-  checkSignature(const Packet& packet,
-                 const Signature& signature,
-                 size_t nSteps,
-                 const OnValidated& onValidated,
-                 const OnFailed& onValidationFailed,
-                 std::vector<shared_ptr<ValidationRequest>>& nextSteps);
-
-  void
-  checkTimestamp(const shared_ptr<const Interest>& interest,
-                 const Name& keyName,
-                 const OnInterestValidated& onValidated,
-                 const OnInterestValidationFailed& onValidationFailed);
-
-  template<class Packet, class OnValidated, class OnFailed>
-  void
-  onCertValidated(const shared_ptr<const Data>& signCertificate,
-                  const shared_ptr<const Packet>& packet,
-                  const OnValidated& onValidated,
-                  const OnFailed& onValidationFailed);
-
-  template<class Packet, class OnFailed>
-  void
-  onCertFailed(const shared_ptr<const Data>& signCertificate,
-               const std::string& failureInfo,
-               const shared_ptr<const Packet>& packet,
-               const OnFailed& onValidationFailed);
-
-  void
-  onConfigRule(const security::conf::ConfigSection& section,
-               const std::string& filename);
-
-  void
-  onConfigTrustAnchor(const security::conf::ConfigSection& section,
-                      const std::string& filename);
-
-  time::nanoseconds
-  getRefreshPeriod(std::string refreshString);
-
-  time::nanoseconds
-  getDefaultRefreshPeriod();
-
-  void
-  refreshAnchors();
-
-  void
-  cleanOldKeys();
-
-  class TrustAnchorContainer
-  {
-  public:
-    const std::list<shared_ptr<v1::IdentityCertificate>>&
-    getAll() const
-    {
-      return m_certificates;
-    }
-
-    void
-    add(shared_ptr<v1::IdentityCertificate> certificate)
-    {
-      m_certificates.push_back(certificate);
-    }
-
-  protected:
-    std::list<shared_ptr<v1::IdentityCertificate>> m_certificates;
-  };
-
-  class DynamicTrustAnchorContainer : public TrustAnchorContainer
-  {
-  public:
-    DynamicTrustAnchorContainer(const boost::filesystem::path& path, bool isDir,
-                                time::nanoseconds refreshPeriod)
-      : m_path(path)
-      , m_isDir(isDir)
-      , m_refreshPeriod(refreshPeriod)
-    {
-    }
-
-    void
-    setLastRefresh(const time::system_clock::TimePoint& lastRefresh)
-    {
-      m_lastRefresh = lastRefresh;
-    }
-
-    const time::system_clock::TimePoint&
-    getLastRefresh() const
-    {
-      return m_lastRefresh;
-    }
-
-    const time::nanoseconds&
-    getRefreshPeriod() const
-    {
-      return m_refreshPeriod;
-    }
-
-    void
-    refresh();
-
-  private:
-    boost::filesystem::path m_path;
-    bool m_isDir;
-
-    time::system_clock::TimePoint m_lastRefresh;
-    time::nanoseconds m_refreshPeriod;
-  };
-
-  static inline bool
-  compareDynamicContainer(const DynamicTrustAnchorContainer& containerA,
-                          const DynamicTrustAnchorContainer& containerB)
-  {
-    return (containerA.getLastRefresh() < containerB.getLastRefresh());
-  }
-
-public:
-  static const shared_ptr<CertificateCache> DEFAULT_CERTIFICATE_CACHE;
-  static const time::milliseconds DEFAULT_GRACE_INTERVAL;
-  static const time::system_clock::Duration DEFAULT_KEY_TIMESTAMP_TTL;
-
 NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
-  typedef security::conf::Rule<Interest> InterestRule;
-  typedef security::conf::Rule<Data>     DataRule;
-  typedef std::vector<shared_ptr<InterestRule>> InterestRuleList;
-  typedef std::vector<shared_ptr<DataRule>>     DataRuleList;
-  typedef std::map<Name, shared_ptr<v1::IdentityCertificate>> AnchorList;
-  typedef std::list<DynamicTrustAnchorContainer> DynamicContainers; // sorted by m_lastRefresh
-  typedef std::list<shared_ptr<v1::IdentityCertificate>> CertificateList;
-
-  /**
-   * @brief gives whether validation should be preformed
-   *
-   * If false, no validation occurs, and any packet is considered validated immediately.
-   */
-  bool m_shouldValidate;
-
-  size_t m_stepLimit;
-  shared_ptr<CertificateCache> m_certificateCache;
-
-  InterestRuleList m_interestRules;
-  DataRuleList m_dataRules;
-
-  AnchorList m_anchors;
-  TrustAnchorContainer m_staticContainer;
-  DynamicContainers m_dynamicContainers;
-
-  time::milliseconds m_graceInterval;
-  size_t m_maxTrackedKeys;
-  typedef std::map<Name, time::system_clock::TimePoint> LastTimestampMap;
-  LastTimestampMap m_lastTimestamp;
-  const time::system_clock::Duration& m_keyTimestampTtl;
+  v2::ValidationPolicyConfig& m_policyConfig;
 };
 
 } // namespace security
diff --git a/tests/identity-management-fixture.cpp b/tests/identity-management-fixture.cpp
index b924024..486cc9c 100644
--- a/tests/identity-management-fixture.cpp
+++ b/tests/identity-management-fixture.cpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -120,8 +120,7 @@
 }
 
 bool
-IdentityManagementV2Fixture::saveIdentityCertificate(const security::Identity& identity,
-                                                     const std::string& filename)
+IdentityManagementV2Fixture::saveCertificate(const security::Identity& identity, const std::string& filename)
 {
   try {
     auto cert = identity.getDefaultKey().getDefaultCertificate();
diff --git a/tests/identity-management-fixture.hpp b/tests/identity-management-fixture.hpp
index a6b348f..82545f9 100644
--- a/tests/identity-management-fixture.hpp
+++ b/tests/identity-management-fixture.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -25,11 +25,12 @@
 #include "security/v1/key-chain.hpp"
 #include "security/v2/key-chain.hpp"
 #include "security/signing-helpers.hpp"
-#include <vector>
 
 #include "boost-test.hpp"
 #include "test-home-fixture.hpp"
 
+#include <vector>
+
 namespace ndn {
 namespace tests {
 
@@ -117,7 +118,7 @@
    *  @return whether successful
    */
   bool
-  saveIdentityCertificate(const security::Identity& identity, const std::string& filename);
+  saveCertificate(const security::Identity& identity, const std::string& filename);
 
   /**
    * @brief Issue a certificate for \p subIdentityName signed by \p issuer
diff --git a/tests/unit-tests/security/conf/checker.t.cpp b/tests/unit-tests/security/conf/checker.t.cpp
deleted file mode 100644
index be2f9ea..0000000
--- a/tests/unit-tests/security/conf/checker.t.cpp
+++ /dev/null
@@ -1,439 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2017 Regents of the University of California.
- *
- * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
- *
- * ndn-cxx library is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * ndn-cxx library 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 Lesser General Public License for more details.
- *
- * You should have received copies of the GNU General Public License and GNU Lesser
- * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- */
-
-#include "security/conf/checker.hpp"
-
-#include "boost-test.hpp"
-#include "identity-management-fixture.hpp"
-
-namespace ndn {
-namespace security {
-namespace conf {
-namespace tests {
-
-using namespace ndn::tests;
-
-BOOST_AUTO_TEST_SUITE(Security)
-BOOST_AUTO_TEST_SUITE(Conf)
-BOOST_FIXTURE_TEST_SUITE(TestChecker, IdentityManagementV1Fixture)
-
-BOOST_AUTO_TEST_CASE(CustomizedCheckerTest1)
-{
-  using security::conf::CustomizedChecker;
-  using security::conf::KeyLocatorChecker;
-  using security::conf::RelationKeyLocatorNameChecker;
-
-  Name identity("/SecurityTestConfChecker/CustomizedCheckerTest1");
-  addIdentity(identity, RsaKeyParams());
-  Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
-
-  Name identity2("/SecurityTestConfChecker/CustomizedCheckerTest1Wrong");
-  addIdentity(identity2, RsaKeyParams());
-  Name certName2 = m_keyChain.getDefaultCertificateNameForIdentity(identity2);
-
-  Name packetName("/SecurityTestConfChecker/CustomizedCheckerTest1/Data");
-  shared_ptr<Data> data1 = make_shared<Data>(packetName);
-  m_keyChain.sign(*data1,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity));
-
-  shared_ptr<Data> data2 = make_shared<Data>(packetName);
-  m_keyChain.sign(*data2,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity2));
-
-  shared_ptr<Interest> interest1 = make_shared<Interest>(packetName);
-  m_keyChain.sign(*interest1,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity));
-
-  shared_ptr<Interest> interest2 = make_shared<Interest>(packetName);
-  m_keyChain.sign(*interest2,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity2));
-
-  int8_t result = 0;
-
-
-  shared_ptr<RelationKeyLocatorNameChecker> keyLocatorCheckerEqual1 =
-    make_shared<RelationKeyLocatorNameChecker>(certName.getPrefix(-1),
-                                               KeyLocatorChecker::RELATION_EQUAL);
-  CustomizedChecker checker1(tlv::SignatureSha256WithRsa, keyLocatorCheckerEqual1);
-
-  result = checker1.check(*data1);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker1.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker1.check(*interest1);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker1.check(*interest2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-
-  shared_ptr<RelationKeyLocatorNameChecker> keyLocatorCheckerEqual2 =
-    make_shared<RelationKeyLocatorNameChecker>(identity,
-                                               KeyLocatorChecker::RELATION_EQUAL);
-  CustomizedChecker checker2(tlv::SignatureSha256WithRsa, keyLocatorCheckerEqual2);
-
-  result = checker2.check(*data1);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker2.check(*interest1);
-  BOOST_CHECK_EQUAL(result, -1);
-
-
-  shared_ptr<RelationKeyLocatorNameChecker> keyLocatorCheckerPrefix1 =
-    make_shared<RelationKeyLocatorNameChecker>(certName.getPrefix(-1),
-                                               KeyLocatorChecker::RELATION_IS_PREFIX_OF);
-  CustomizedChecker checker3(tlv::SignatureSha256WithRsa, keyLocatorCheckerPrefix1);
-
-  result = checker3.check(*data1);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker3.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-
-  shared_ptr<RelationKeyLocatorNameChecker> keyLocatorCheckerPrefix2 =
-    make_shared<RelationKeyLocatorNameChecker>(identity,
-                                               KeyLocatorChecker::RELATION_IS_PREFIX_OF);
-  CustomizedChecker checker4(tlv::SignatureSha256WithRsa, keyLocatorCheckerPrefix2);
-
-  result = checker4.check(*data1);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker4.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-
-  shared_ptr<RelationKeyLocatorNameChecker> keyLocatorCheckerStrict1 =
-    make_shared<RelationKeyLocatorNameChecker>(certName.getPrefix(-1),
-                                               KeyLocatorChecker::RELATION_IS_STRICT_PREFIX_OF);
-  CustomizedChecker checker5(tlv::SignatureSha256WithRsa, keyLocatorCheckerStrict1);
-
-  result = checker5.check(*data1);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker5.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  shared_ptr<RelationKeyLocatorNameChecker> keyLocatorCheckerStrict2 =
-    make_shared<RelationKeyLocatorNameChecker>(identity,
-                                               KeyLocatorChecker::RELATION_IS_STRICT_PREFIX_OF);
-  CustomizedChecker checker6(tlv::SignatureSha256WithRsa, keyLocatorCheckerStrict2);
-
-  result = checker6.check(*data1);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker6.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-}
-
-BOOST_AUTO_TEST_CASE(CustomizedCheckerTest2)
-{
-  using security::conf::CustomizedChecker;
-  using security::conf::KeyLocatorChecker;
-  using security::conf::RegexKeyLocatorNameChecker;
-
-  Name identity("/SecurityTestConfChecker/CustomizedCheckerTest2");
-  addIdentity(identity, RsaKeyParams());
-  Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
-
-  Name identity2("/SecurityTestConfChecker/CustomizedCheckerTest2Wrong");
-  addIdentity(identity2, RsaKeyParams());
-  Name certName2 = m_keyChain.getDefaultCertificateNameForIdentity(identity2);
-
-  Name packetName("/SecurityTestConfChecker/CustomizedCheckerTest2/Data");
-  shared_ptr<Data> data1 = make_shared<Data>(packetName);
-  m_keyChain.sign(*data1,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity));
-
-  shared_ptr<Data> data2 = make_shared<Data>(packetName);
-  m_keyChain.sign(*data2,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity2));
-
-  shared_ptr<Interest> interest1 = make_shared<Interest>(packetName);
-  m_keyChain.sign(*interest1,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity));
-
-  shared_ptr<Interest> interest2 = make_shared<Interest>(packetName);
-  m_keyChain.sign(*interest2,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity2));
-
-  int8_t result = 0;
-
-
-  shared_ptr<RegexKeyLocatorNameChecker> keyLocatorCheckerRegex1 =
-    make_shared<RegexKeyLocatorNameChecker>(
-      Regex("^<SecurityTestConfChecker><CustomizedCheckerTest2>"));
-  CustomizedChecker checker1(tlv::SignatureSha256WithRsa, keyLocatorCheckerRegex1);
-
-  result = checker1.check(*data1);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker1.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker1.check(*interest1);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker1.check(*interest2);
-  BOOST_CHECK_EQUAL(result, -1);
-}
-
-BOOST_AUTO_TEST_CASE(CustomizedCheckerTest3)
-{
-  using security::conf::CustomizedChecker;
-  using security::conf::KeyLocatorChecker;
-  using security::conf::RegexKeyLocatorNameChecker;
-
-  Name identity("/SecurityTestConfChecker/CustomizedCheckerTest3");
-  addIdentity(identity, EcKeyParams());
-  Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
-
-  Name identity2("/SecurityTestConfChecker/CustomizedCheckerTest3Wrong");
-  addIdentity(identity2, EcKeyParams());
-  Name certName2 = m_keyChain.getDefaultCertificateNameForIdentity(identity2);
-
-  Name packetName("/SecurityTestConfChecker/CustomizedCheckerTest3/Data");
-  shared_ptr<Data> data1 = make_shared<Data>(packetName);
-  m_keyChain.sign(*data1,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity));
-
-  shared_ptr<Data> data2 = make_shared<Data>(packetName);
-  m_keyChain.sign(*data2,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity2));
-
-  shared_ptr<Interest> interest1 = make_shared<Interest>(packetName);
-  m_keyChain.sign(*interest1,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity));
-
-  shared_ptr<Interest> interest2 = make_shared<Interest>(packetName);
-  m_keyChain.sign(*interest2,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity2));
-
-  int8_t result = 0;
-
-
-  shared_ptr<RegexKeyLocatorNameChecker> keyLocatorCheckerRegex1 =
-    make_shared<RegexKeyLocatorNameChecker>(
-      Regex("^<SecurityTestConfChecker><CustomizedCheckerTest3>"));
-  CustomizedChecker checker1(tlv::SignatureSha256WithEcdsa, keyLocatorCheckerRegex1);
-
-  result = checker1.check(*data1);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker1.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker1.check(*interest1);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker1.check(*interest2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-
-  CustomizedChecker checker2(tlv::SignatureSha256WithRsa, keyLocatorCheckerRegex1);
-
-  result = checker2.check(*data1);
-  BOOST_CHECK_EQUAL(result, -1);
-}
-
-BOOST_AUTO_TEST_CASE(HierarchicalCheckerTest1)
-{
-  using security::conf::HierarchicalChecker;
-
-  Name identity("/SecurityTestConfChecker/HierarchicalCheckerTest1");
-  addIdentity(identity, EcKeyParams());
-  Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
-
-  Name identity2("/SecurityTestConfChecker/HierarchicalCheckerTest1/Data");
-  addIdentity(identity2, RsaKeyParams());
-  Name certName2 = m_keyChain.getDefaultCertificateNameForIdentity(identity2);
-
-  Name packetName("/SecurityTestConfChecker/HierarchicalCheckerTest1/Data");
-  Name packetName2("/SecurityTestConfChecker");
-  Name packetName3("/SecurityTestConfChecker/HierarchicalCheckerTest1");
-
-  shared_ptr<Data> data1 = make_shared<Data>(packetName);
-  m_keyChain.sign(*data1,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity));
-
-  shared_ptr<Data> data2 = make_shared<Data>(packetName2);
-  m_keyChain.sign(*data2,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity));
-
-  shared_ptr<Data> data3 = make_shared<Data>(packetName3);
-  m_keyChain.sign(*data3,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity));
-
-  shared_ptr<Data> data4 = make_shared<Data>(packetName);
-  m_keyChain.sign(*data4,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity2));
-
-  shared_ptr<Data> data5 = make_shared<Data>(packetName2);
-  m_keyChain.sign(*data5,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity2));
-
-  shared_ptr<Data> data6 = make_shared<Data>(packetName3);
-  m_keyChain.sign(*data6,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity2));
-
-  int8_t result = 0;
-
-  HierarchicalChecker checker1(tlv::SignatureSha256WithEcdsa);
-
-  result = checker1.check(*data1);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker1.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker1.check(*data3);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker1.check(*data4);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker1.check(*data5);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker1.check(*data6);
-  BOOST_CHECK_EQUAL(result, -1);
-
-
-  HierarchicalChecker checker2(tlv::SignatureSha256WithRsa);
-
-  result = checker2.check(*data1);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker2.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker2.check(*data3);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker2.check(*data4);
-  BOOST_CHECK_EQUAL(result, 0);
-
-  result = checker2.check(*data5);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker2.check(*data6);
-  BOOST_CHECK_EQUAL(result, -1);
-}
-
-BOOST_AUTO_TEST_CASE(FixedSignerCheckerTest1)
-{
-  using security::conf::FixedSignerChecker;
-
-  Name identity("/SecurityTestConfChecker/FixedSignerCheckerTest1");
-  addIdentity(identity, EcKeyParams());
-  Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
-  shared_ptr<v1::IdentityCertificate> cert1 = m_keyChain.getCertificate(certName);
-
-  Name identity2("/SecurityTestConfChecker/FixedSignerCheckerTest1Wrong");
-  addIdentity(identity2, RsaKeyParams());
-  Name certName2 = m_keyChain.getDefaultCertificateNameForIdentity(identity2);
-  shared_ptr<v1::IdentityCertificate> cert2 = m_keyChain.getCertificate(certName2);
-
-  Name packetName("/Test/Data");
-
-  shared_ptr<Data> data1 = make_shared<Data>(packetName);
-  m_keyChain.sign(*data1,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity));
-
-  shared_ptr<Data> data2 = make_shared<Data>(packetName);
-  m_keyChain.sign(*data2,
-                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
-                                        identity2));
-
-  std::vector<shared_ptr<v1::IdentityCertificate> > certSet1;
-  certSet1.push_back(cert1);
-
-  std::vector<shared_ptr<v1::IdentityCertificate> > certSet2;
-  certSet2.push_back(cert2);
-
-
-  int8_t result = 0;
-
-  FixedSignerChecker checker1(tlv::SignatureSha256WithEcdsa, certSet1);
-
-  result = checker1.check(*data1);
-  BOOST_CHECK_EQUAL(result, 1);
-
-  result = checker1.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-
-  FixedSignerChecker checker2(tlv::SignatureSha256WithRsa, certSet1);
-
-  result = checker2.check(*data1);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker2.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-
-  FixedSignerChecker checker3(tlv::SignatureSha256WithEcdsa, certSet2);
-
-  result = checker3.check(*data1);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker3.check(*data2);
-  BOOST_CHECK_EQUAL(result, -1);
-
-
-  FixedSignerChecker checker4(tlv::SignatureSha256WithRsa, certSet2);
-
-  result = checker4.check(*data1);
-  BOOST_CHECK_EQUAL(result, -1);
-
-  result = checker4.check(*data2);
-  BOOST_CHECK_EQUAL(result, 1);
-}
-
-BOOST_AUTO_TEST_SUITE_END() // TestChecker
-BOOST_AUTO_TEST_SUITE_END() // Conf
-BOOST_AUTO_TEST_SUITE_END() // Security
-
-} // namespace tests
-} // namespace conf
-} // namespace security
-} // namespace ndn
diff --git a/tests/unit-tests/security/v2/validation-policy-config.t.cpp b/tests/unit-tests/security/v2/validation-policy-config.t.cpp
new file mode 100644
index 0000000..308b0fe
--- /dev/null
+++ b/tests/unit-tests/security/v2/validation-policy-config.t.cpp
@@ -0,0 +1,456 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/v2/validation-policy-config.hpp"
+#include "security/transform/base64-encode.hpp"
+#include "security/transform/buffer-source.hpp"
+#include "security/transform/stream-sink.hpp"
+#include "util/logger.hpp"
+#include "util/io.hpp"
+
+#include "boost-test.hpp"
+#include "validator-config/common.hpp"
+#include "validator-fixture.hpp"
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+namespace tests {
+
+using namespace ndn::tests;
+using namespace ndn::security::v2::tests;
+
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(V2)
+BOOST_AUTO_TEST_SUITE(TestValidationPolicyConfig)
+
+template<typename Packet>
+class PacketName;
+
+template<>
+class PacketName<Interest>
+{
+public:
+  static std::string
+  getName()
+  {
+    return "interest";
+  }
+};
+
+template<>
+class PacketName<Data>
+{
+public:
+  static std::string
+  getName()
+  {
+    return "data";
+  }
+};
+
+template<typename PacketType>
+class ValidationPolicyConfigFixture : public HierarchicalValidatorFixture<ValidationPolicyConfig>
+{
+public:
+  ValidationPolicyConfigFixture()
+    : path(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) / "security" / "v2" / "validation-policy-config")
+  {
+    boost::filesystem::create_directories(path);
+    baseConfig = R"CONF(
+        rule
+        {
+          id test-rule-id
+          for )CONF" + PacketName<Packet>::getName() + R"CONF(
+          filter
+          {
+            type name
+            name )CONF" + identity.getName().toUri() + R"CONF(
+            relation is-prefix-of
+          }
+          checker
+          {
+            type hierarchical
+            sig-type rsa-sha256
+          }
+        }
+      )CONF";
+  }
+
+  ~ValidationPolicyConfigFixture()
+  {
+    boost::filesystem::remove_all(path);
+  }
+
+public:
+  using Packet = PacketType;
+
+  const boost::filesystem::path path;
+  std::string baseConfig;
+};
+
+template<typename PacketType>
+class LoadStringWithFileAnchor : public ValidationPolicyConfigFixture<PacketType>
+{
+public:
+  LoadStringWithFileAnchor()
+  {
+    BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false);
+
+    this->saveCertificate(this->identity, (this->path / "identity.ndncert").string());
+    this->policy.load(this->baseConfig + R"CONF(
+        trust-anchor
+        {
+          type file
+          file-name "trust-anchor.ndncert"
+        }
+      )CONF", (this->path / "test-config").string());
+
+    BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true);
+    BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false);
+  }
+};
+
+template<typename PacketType>
+class LoadFileWithFileAnchor : public ValidationPolicyConfigFixture<PacketType>
+{
+public:
+  LoadFileWithFileAnchor()
+  {
+    std::string configFile = (this->path / "config.conf").string();
+    {
+      std::ofstream config(configFile.c_str());
+      config << this->baseConfig << R"CONF(
+        trust-anchor
+        {
+          type file
+          file-name "trust-anchor.ndncert"
+        }
+      )CONF";
+    }
+    this->saveCertificate(this->identity, (this->path / "identity.ndncert").string());
+
+    BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false);
+
+    this->policy.load(configFile);
+
+    BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true);
+    BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false);
+  }
+};
+
+template<typename PacketType>
+class LoadSectionWithFileAnchor : public ValidationPolicyConfigFixture<PacketType>
+{
+public:
+  LoadSectionWithFileAnchor()
+  {
+    auto section = makeSection(this->baseConfig + R"CONF(
+        trust-anchor
+        {
+          type file
+          file-name "trust-anchor.ndncert"
+        }
+      )CONF");
+
+    this->saveCertificate(this->identity, (this->path / "identity.ndncert").string());
+
+    BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false);
+
+    this->policy.load(section, (this->path / "test-config").string());
+
+    BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true);
+    BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false);
+  }
+};
+
+template<typename PacketType>
+class LoadStringWithBase64Anchor : public ValidationPolicyConfigFixture<PacketType>
+{
+public:
+  LoadStringWithBase64Anchor()
+  {
+    BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false);
+
+    std::ostringstream os;
+    using namespace ndn::security::transform;
+    const auto& cert = this->identity.getDefaultKey().getDefaultCertificate();
+    bufferSource(cert.wireEncode().wire(), cert.wireEncode().size()) >> base64Encode(false) >> streamSink(os);
+
+    this->policy.load(this->baseConfig + R"CONF(
+        trust-anchor
+        {
+          type base64
+          base64-string ")CONF" + os.str() + R"CONF("
+        }
+      )CONF", (this->path / "test-config").string());
+
+    BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true);
+    BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false);
+  }
+};
+
+class NoRefresh
+{
+public:
+  static std::string
+  getRefreshString()
+  {
+    return "";
+  }
+};
+
+class Refresh1h
+{
+public:
+  static std::string
+  getRefreshString()
+  {
+    return "refresh 1h";
+  }
+
+  static time::milliseconds
+  getRefreshTime()
+  {
+    return time::hours(1);
+  }
+};
+
+class Refresh1m
+{
+public:
+  static std::string
+  getRefreshString()
+  {
+    return "refresh 1m";
+  }
+
+  static time::milliseconds
+  getRefreshTime()
+  {
+    return time::minutes(1);
+  }
+};
+
+class Refresh1s
+{
+public:
+  static std::string
+  getRefreshString()
+  {
+    return "refresh 1s";
+  }
+
+  static time::milliseconds
+  getRefreshTime()
+  {
+    return time::seconds(1);
+  }
+};
+
+template<typename PacketType, typename Refresh = NoRefresh>
+class LoadStringWithDirAnchor : public ValidationPolicyConfigFixture<PacketType>
+{
+public:
+  LoadStringWithDirAnchor()
+  {
+    BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false);
+
+    boost::filesystem::create_directories(this->path / "keys");
+    this->saveCertificate(this->identity, (this->path / "keys" / "identity.ndncert").string());
+
+    this->policy.load(this->baseConfig + R"CONF(
+        trust-anchor
+        {
+          type dir
+          dir keys
+          )CONF" + Refresh::getRefreshString() + R"CONF(
+        }
+      )CONF", (this->path / "test-config").string());
+
+    BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true);
+    BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false);
+  }
+};
+
+using DataPolicies = boost::mpl::vector<LoadStringWithFileAnchor<Data>,
+                                        LoadFileWithFileAnchor<Data>,
+                                        LoadSectionWithFileAnchor<Data>,
+                                        LoadStringWithBase64Anchor<Data>,
+                                        LoadStringWithDirAnchor<Data>,
+                                        LoadStringWithDirAnchor<Data, Refresh1h>,
+                                        LoadStringWithDirAnchor<Data, Refresh1m>,
+                                        LoadStringWithDirAnchor<Data, Refresh1s>
+                                        >;
+
+using InterestPolicies = boost::mpl::vector<LoadStringWithFileAnchor<Interest>,
+                                            LoadFileWithFileAnchor<Interest>,
+                                            LoadSectionWithFileAnchor<Interest>,
+                                            LoadStringWithBase64Anchor<Interest>,
+                                            LoadStringWithDirAnchor<Interest>,
+                                            LoadStringWithDirAnchor<Interest, Refresh1h>,
+                                            LoadStringWithDirAnchor<Interest, Refresh1m>,
+                                            LoadStringWithDirAnchor<Interest, Refresh1s>
+                                            >;
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateData, Policy, DataPolicies, Policy)
+{
+  BOOST_CHECK_EQUAL(this->policy.m_dataRules.size(), 1);
+  BOOST_CHECK_EQUAL(this->policy.m_interestRules.size(), 0);
+
+  using Packet = typename Policy::Packet;
+  Packet unsignedPacket("/Security/V2/ValidatorFixture/Sub1/Sub2/Packet");
+
+  Packet packet = unsignedPacket;
+  VALIDATE_FAILURE(packet, "Unsigned");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingWithSha256());
+  VALIDATE_FAILURE(packet, "Policy doesn't accept Sha256Digest signature");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->identity));
+  VALIDATE_SUCCESS(packet, "Should get accepted, as signed by the anchor");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->subIdentity));
+  VALIDATE_SUCCESS(packet, "Should get accepted, as signed by the policy-compliant cert");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->otherIdentity));
+  VALIDATE_FAILURE(packet, "Should fail, as signed by the policy-violating cert");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->subSelfSignedIdentity));
+  VALIDATE_FAILURE(packet, "Should fail, because subSelfSignedIdentity is not a trust anchor");
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateInterest, Policy, InterestPolicies, Policy)
+{
+  BOOST_CHECK_EQUAL(this->policy.m_dataRules.size(), 0);
+  BOOST_CHECK_EQUAL(this->policy.m_interestRules.size(), 1);
+
+  using Packet = typename Policy::Packet;
+  Packet unsignedPacket("/Security/V2/ValidatorFixture/Sub1/Sub2/Packet");
+
+  Packet packet = unsignedPacket;
+  VALIDATE_FAILURE(packet, "Unsigned");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingWithSha256());
+  VALIDATE_FAILURE(packet, "Policy doesn't accept Sha256Digest signature");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->identity));
+  VALIDATE_SUCCESS(packet, "Should get accepted, as signed by the anchor");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->subIdentity));
+  VALIDATE_FAILURE(packet, "Should fail, as there is no matching rule for data");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->otherIdentity));
+  VALIDATE_FAILURE(packet, "Should fail, as signed by the policy-violating cert");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->subSelfSignedIdentity));
+  VALIDATE_FAILURE(packet, "Should fail, because subSelfSignedIdentity is not a trust anchor");
+}
+
+using Packets = boost::mpl::vector<Interest, Data>;
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(TrustAnchorWildcard, Packet, Packets, ValidationPolicyConfigFixture<Packet>)
+{
+  this->policy.load(R"CONF(
+      trust-anchor
+      {
+        type any
+      }
+    )CONF", "test-config");
+
+  BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true);
+  BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, true);
+  BOOST_CHECK_EQUAL(this->policy.m_dataRules.size(), 0);
+  BOOST_CHECK_EQUAL(this->policy.m_interestRules.size(), 0);
+
+  Packet unsignedPacket("/Security/V2/ValidatorFixture/Sub1/Sub2/Packet");
+
+  Packet packet = unsignedPacket;
+  VALIDATE_SUCCESS(packet, "Policy should accept everything");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingWithSha256());
+  VALIDATE_SUCCESS(packet, "Policy should accept everything");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->identity));
+  VALIDATE_SUCCESS(packet, "Policy should accept everything");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->subIdentity));
+  VALIDATE_SUCCESS(packet, "Policy should accept everything");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->otherIdentity));
+  VALIDATE_SUCCESS(packet, "Policy should accept everything");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->subSelfSignedIdentity));
+  VALIDATE_SUCCESS(packet, "Policy should accept everything");
+}
+
+using ReloadedPolicies = boost::mpl::vector<Refresh1h, Refresh1m, Refresh1s>;
+
+// Somehow, didn't work without this wrapper
+template<typename ReloadPolicy>
+class ReloadPolicyFixture : public LoadStringWithDirAnchor<Data, ReloadPolicy>
+{
+public:
+};
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateReload, Reload, ReloadedPolicies, ReloadPolicyFixture<Reload>)
+{
+  using Packet = Data;
+  Packet unsignedPacket("/Security/V2/ValidatorFixture/Sub1/Sub2/Packet");
+
+  boost::filesystem::remove(this->path / "keys" / "identity.ndncert");
+  this->advanceClocks(Reload::getRefreshTime(), 3);
+
+  Packet packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->identity));
+  VALIDATE_FAILURE(packet, "Should fail, as the trust anchor should no longer exist");
+
+  packet = unsignedPacket;
+  this->m_keyChain.sign(packet, signingByIdentity(this->subIdentity));
+  VALIDATE_FAILURE(packet, "Should fail, as the trust anchor should no longer exist");
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestValidationPolicyConfig
+BOOST_AUTO_TEST_SUITE_END() // V2
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
diff --git a/tests/unit-tests/security/v2/validator-config/checker.t.cpp b/tests/unit-tests/security/v2/validator-config/checker.t.cpp
new file mode 100644
index 0000000..12af61b
--- /dev/null
+++ b/tests/unit-tests/security/v2/validator-config/checker.t.cpp
@@ -0,0 +1,374 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/v2/validator-config/checker.hpp"
+#include "security/command-interest-signer.hpp"
+#include "security/v2/validation-policy.hpp"
+#include "security/v2/validation-state.hpp"
+
+#include "boost-test.hpp"
+#include "common.hpp"
+#include "identity-management-fixture.hpp"
+#include "../validator-fixture.hpp"
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+namespace tests {
+
+using namespace ndn::tests;
+using namespace ndn::security::v2::tests;
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(V2)
+BOOST_AUTO_TEST_SUITE(ValidatorConfig)
+
+class CheckerFixture : public IdentityManagementFixture
+{
+public:
+  CheckerFixture()
+  {
+    names.push_back("/foo/bar");
+    names.push_back("/foo/bar/bar");
+    names.push_back("/foo");
+    names.push_back("/other/prefix");
+  }
+
+  Name
+  makeSignedInterestName(const Name& name)
+  {
+    return Name(name).append("SignatureInfo").append("SignatureValue");
+  }
+
+  Name
+  makeKeyLocatorName(const Name& name)
+  {
+    return Name(name).append("KEY").append("v=1");
+  }
+
+public:
+  std::vector<Name> names;
+};
+
+BOOST_FIXTURE_TEST_SUITE(TestChecker, CheckerFixture)
+
+class NameRelationEqual : public CheckerFixture
+{
+public:
+  NameRelationEqual()
+    : checker("/foo/bar", NameRelation::EQUAL)
+  {
+  }
+
+public:
+  NameRelationChecker checker;
+  std::vector<std::vector<bool>> outcomes = {{true, false, false, false},
+                                             {true, false, false, false},
+                                             {true, false, false, false},
+                                             {true, false, false, false}};
+};
+
+class NameRelationIsPrefixOf : public CheckerFixture
+{
+public:
+  NameRelationIsPrefixOf()
+    : checker("/foo/bar", NameRelation::IS_PREFIX_OF)
+  {
+  }
+
+public:
+  NameRelationChecker checker;
+  std::vector<std::vector<bool>> outcomes = {{true, true, false, false},
+                                             {true, true, false, false},
+                                             {true, true, false, false},
+                                             {true, true, false, false}};
+};
+
+class NameRelationIsStrictPrefixOf : public CheckerFixture
+{
+public:
+  NameRelationIsStrictPrefixOf()
+    : checker("/foo/bar", NameRelation::IS_STRICT_PREFIX_OF)
+  {
+  }
+
+public:
+  NameRelationChecker checker;
+  std::vector<std::vector<bool>> outcomes = {{false, true, false, false},
+                                             {false, true, false, false},
+                                             {false, true, false, false},
+                                             {false, true, false, false}};
+};
+
+class RegexEqual : public CheckerFixture
+{
+public:
+  RegexEqual()
+    : checker(Regex("^<foo><bar>$"))
+  {
+  }
+
+public:
+  RegexChecker checker;
+  std::vector<std::vector<bool>> outcomes = {{true, false, false, false},
+                                             {true, false, false, false},
+                                             {true, false, false, false},
+                                             {true, false, false, false}};
+};
+
+class RegexIsPrefixOf : public CheckerFixture
+{
+public:
+  RegexIsPrefixOf()
+    : checker(Regex("^<foo><bar><>*$"))
+  {
+  }
+
+public:
+  RegexChecker checker;
+  std::vector<std::vector<bool>> outcomes = {{true, true, false, false},
+                                             {true, true, false, false},
+                                             {true, true, false, false},
+                                             {true, true, false, false}};
+};
+
+class RegexIsStrictPrefixOf : public CheckerFixture
+{
+public:
+  RegexIsStrictPrefixOf()
+    : checker(Regex("^<foo><bar><>+$"))
+  {
+  }
+
+public:
+  RegexChecker checker;
+  std::vector<std::vector<bool>> outcomes = {{false, true, false, false},
+                                             {false, true, false, false},
+                                             {false, true, false, false},
+                                             {false, true, false, false}};
+};
+
+class HyperRelationEqual : public CheckerFixture
+{
+public:
+  HyperRelationEqual()
+    : checker("^(<>+)$", "\\1", "^(<>+)<KEY><>$", "\\1", NameRelation::EQUAL)
+  {
+  }
+
+public:
+  HyperRelationChecker checker;
+  std::vector<std::vector<bool>> outcomes = {{true,  false, false, false},
+                                             {false, true,  false, false},
+                                             {false, false, true,  false},
+                                             {false, false, false, true}};
+};
+
+class HyperRelationIsPrefixOf : public CheckerFixture
+{
+public:
+  HyperRelationIsPrefixOf()
+    : checker("^(<>+)$", "\\1", "^(<>+)<KEY><>$", "\\1", NameRelation::IS_PREFIX_OF)
+  {
+  }
+
+public:
+  HyperRelationChecker checker;
+  std::vector<std::vector<bool>> outcomes = {{true,  false, true,  false},
+                                             {true,  true,  true,  false},
+                                             {false, false, true,  false},
+                                             {false, false, false, true}};
+};
+
+class HyperRelationIsStrictPrefixOf : public CheckerFixture
+{
+public:
+  HyperRelationIsStrictPrefixOf()
+    : checker("^(<>+)$", "\\1", "^(<>+)<KEY><>$", "\\1", NameRelation::IS_STRICT_PREFIX_OF)
+  {
+  }
+
+public:
+  HyperRelationChecker checker;
+  std::vector<std::vector<bool>> outcomes = {{false, false, true,  false},
+                                             {true,  false, true,  false},
+                                             {false, false, false, false},
+                                             {false, false, false, false}};
+};
+
+class Hierarchical : public CheckerFixture
+{
+public:
+  Hierarchical()
+    : checkerPtr(Checker::create(makeSection(R"CONF(
+          type hierarchical
+          sig-type rsa-sha256
+        )CONF"), "test-config"))
+    , checker(*checkerPtr)
+  {
+  }
+
+public:
+  std::unique_ptr<Checker> checkerPtr;
+  Checker& checker;
+
+  std::vector<std::vector<bool>> outcomes = {{true,  false, true,  false},
+                                             {true,  true,  true,  false},
+                                             {false, false, true,  false},
+                                             {false, false, false, true}};
+};
+
+class CustomizedNameRelation : public CheckerFixture
+{
+public:
+  CustomizedNameRelation()
+    : checkerPtr(Checker::create(makeSection(R"CONF(
+          type customized
+          sig-type rsa-sha256
+          key-locator
+          {
+            type name
+            name /foo/bar
+            relation equal
+          }
+        )CONF"), "test-config"))
+    , checker(*checkerPtr)
+  {
+  }
+
+public:
+  std::unique_ptr<Checker> checkerPtr;
+  Checker& checker;
+
+  std::vector<std::vector<bool>> outcomes = {{true, false, false, false},
+                                             {true, false, false, false},
+                                             {true, false, false, false},
+                                             {true, false, false, false}};
+};
+
+class CustomizedRegex : public CheckerFixture
+{
+public:
+  CustomizedRegex()
+    : checkerPtr(Checker::create(makeSection(R"CONF(
+          type customized
+          sig-type rsa-sha256
+          key-locator
+          {
+            type name
+            regex ^<foo><bar>$
+          }
+        )CONF"), "test-config"))
+    , checker(*checkerPtr)
+  {
+  }
+
+public:
+  std::unique_ptr<Checker> checkerPtr;
+  Checker& checker;
+
+  std::vector<std::vector<bool>> outcomes = {{true, false, false, false},
+                                             {true, false, false, false},
+                                             {true, false, false, false},
+                                             {true, false, false, false}};
+};
+
+class CustomizedHyperRelation : public CheckerFixture
+{
+public:
+  CustomizedHyperRelation()
+    : checkerPtr(Checker::create(makeSection(R"CONF(
+          type customized
+          sig-type rsa-sha256
+          key-locator
+          {
+            type name
+            hyper-relation
+            {
+              k-regex ^(<>+)<KEY><>$
+              k-expand \\1
+              h-relation is-prefix-of
+              p-regex ^(<>+)$
+              p-expand \\1
+            }
+          }
+        )CONF"), "test-config"))
+    , checker(*checkerPtr)
+  {
+  }
+
+public:
+  std::unique_ptr<Checker> checkerPtr;
+  Checker& checker;
+
+  std::vector<std::vector<bool>> outcomes = {{true,  false, true,  false},
+                                             {true,  true,  true,  false},
+                                             {false, false, true,  false},
+                                             {false, false, false, true}};
+};
+
+
+using Tests = boost::mpl::vector<NameRelationEqual, NameRelationIsPrefixOf, NameRelationIsStrictPrefixOf,
+                                 RegexEqual, RegexIsPrefixOf, RegexIsStrictPrefixOf,
+                                 HyperRelationEqual, HyperRelationIsPrefixOf, HyperRelationIsStrictPrefixOf,
+                                 Hierarchical,
+                                 CustomizedNameRelation, CustomizedRegex, CustomizedHyperRelation>;
+
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(Checks, T, Tests, T)
+{
+  BOOST_ASSERT(this->outcomes.size() == this->names.size());
+  for (size_t i = 0; i < this->names.size(); ++i) {
+    BOOST_ASSERT(this->outcomes[i].size() == this->names.size());
+    for (size_t j = 0; j < this->names.size(); ++j) {
+      const Name& pktName = this->names[i];
+      Name klName = this->makeKeyLocatorName(this->names[j]);
+      bool expectedOutcome = this->outcomes[i][j];
+
+      auto dataState = make_shared<DummyValidationState>();
+      BOOST_CHECK_EQUAL(this->checker.check(tlv::Data, pktName, klName, dataState), expectedOutcome);
+      BOOST_CHECK_EQUAL(boost::logic::indeterminate(dataState->getOutcome()), expectedOutcome);
+      if (boost::logic::indeterminate(dataState->getOutcome()) == !expectedOutcome) {
+        BOOST_CHECK_EQUAL(dataState->getOutcome(), !expectedOutcome);
+      }
+
+      auto interestState = make_shared<DummyValidationState>();
+      BOOST_CHECK_EQUAL(this->checker.check(tlv::Interest, this->makeSignedInterestName(pktName),
+                                            klName, interestState), expectedOutcome);
+      BOOST_CHECK_EQUAL(boost::logic::indeterminate(interestState->getOutcome()), expectedOutcome);
+      if (boost::logic::indeterminate(interestState->getOutcome()) == !expectedOutcome) {
+        BOOST_CHECK_EQUAL(interestState->getOutcome(), !expectedOutcome);
+      }
+    }
+  }
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestChecker
+BOOST_AUTO_TEST_SUITE_END() // ValidatorConfig
+BOOST_AUTO_TEST_SUITE_END() // V2
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
diff --git a/src/security/conf/common.hpp b/tests/unit-tests/security/v2/validator-config/common.hpp
similarity index 62%
copy from src/security/conf/common.hpp
copy to tests/unit-tests/security/v2/validator-config/common.hpp
index 3c79b7b..4250718 100644
--- a/src/security/conf/common.hpp
+++ b/tests/unit-tests/security/v2/validator-config/common.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2014 Regents of the University of California.
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -17,35 +17,32 @@
  * <http://www.gnu.org/licenses/>.
  *
  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- *
- * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
  */
 
-#ifndef NDN_SECURITY_CONF_COMMON_HPP
-#define NDN_SECURITY_CONF_COMMON_HPP
+#ifndef NDN_TESTS_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP
+#define NDN_TESTS_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP
 
-#include "../../common.hpp"
-#include <string>
-#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/info_parser.hpp>
 
 namespace ndn {
 namespace security {
-namespace conf {
+namespace v2 {
+namespace validator_config {
+namespace tests {
 
-typedef boost::property_tree::ptree ConfigSection;
-
-class Error : public std::runtime_error
+inline ConfigSection
+makeSection(const std::string& config)
 {
-public:
-  explicit
-  Error(const std::string& what)
-    : std::runtime_error(what)
-  {
-  }
-};
+  std::istringstream inputStream(config);
+  ConfigSection section;
+  boost::property_tree::read_info(inputStream, section);
+  return section;
+}
 
-} // namespace conf
+} // namespace tests
+} // namespace validator_config
+} // namespace v2
 } // namespace security
 } // namespace ndn
 
-#endif // NDN_SECURITY_CONF_COMMON_HPP
+#endif // NDN_TESTS_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP
diff --git a/tests/unit-tests/security/v2/validator-config/filter.t.cpp b/tests/unit-tests/security/v2/validator-config/filter.t.cpp
new file mode 100644
index 0000000..054b99a
--- /dev/null
+++ b/tests/unit-tests/security/v2/validator-config/filter.t.cpp
@@ -0,0 +1,201 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/v2/validator-config/filter.hpp"
+#include "security/command-interest-signer.hpp"
+
+#include "boost-test.hpp"
+#include "common.hpp"
+#include "identity-management-fixture.hpp"
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+namespace tests {
+
+using namespace ndn::tests;
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(V2)
+BOOST_AUTO_TEST_SUITE(ValidatorConfig)
+
+class FilterFixture : public IdentityManagementFixture
+{
+public:
+  Interest
+  makeSignedInterest(const Name& name)
+  {
+    Interest interest(name);
+    m_keyChain.sign(interest);
+    return interest;
+  }
+};
+
+BOOST_FIXTURE_TEST_SUITE(TestFilter, FilterFixture)
+
+#define CHECK_FOR_MATCHES(filter, same, longer, shorter, different)     \
+  BOOST_CHECK_EQUAL(filter.match(tlv::Interest, makeSignedInterest("/foo/bar").getName()), same); \
+  BOOST_CHECK_EQUAL(filter.match(tlv::Data, Data("/foo/bar").getName()), same);   \
+  BOOST_CHECK_EQUAL(filter.match(tlv::Interest, makeSignedInterest("/foo/bar/bar").getName()), longer); \
+  BOOST_CHECK_EQUAL(filter.match(tlv::Data, Data("/foo/bar/bar").getName()), longer);       \
+  BOOST_CHECK_EQUAL(filter.match(tlv::Interest, makeSignedInterest("/foo").getName()), shorter); \
+  BOOST_CHECK_EQUAL(filter.match(tlv::Data, Data("/foo").getName()), shorter);              \
+  BOOST_CHECK_EQUAL(filter.match(tlv::Interest, makeSignedInterest("/other/prefix").getName()), different); \
+  BOOST_CHECK_EQUAL(filter.match(tlv::Data, Data("/other/prefix").getName()), different);
+
+BOOST_AUTO_TEST_CASE(RelationName)
+{
+  RelationNameFilter f1("/foo/bar", NameRelation::EQUAL);
+  CHECK_FOR_MATCHES(f1, true, false, false, false);
+
+  RelationNameFilter f2("/foo/bar", NameRelation::IS_PREFIX_OF);
+  CHECK_FOR_MATCHES(f2, true, true, false, false);
+
+  RelationNameFilter f3("/foo/bar", NameRelation::IS_STRICT_PREFIX_OF);
+  CHECK_FOR_MATCHES(f3, false, true, false, false);
+}
+
+BOOST_AUTO_TEST_CASE(RegexName)
+{
+  RegexNameFilter f1(Regex("^<foo><bar>$"));
+  CHECK_FOR_MATCHES(f1, true, false, false, false);
+
+  RegexNameFilter f2(Regex("^<foo><bar><>*$"));
+  CHECK_FOR_MATCHES(f2, true, true, false, false);
+
+  RegexNameFilter f3(Regex("^<foo><bar><>+$"));
+  CHECK_FOR_MATCHES(f3, false, true, false, false);
+}
+
+BOOST_FIXTURE_TEST_SUITE(Create, FilterFixture)
+
+BOOST_AUTO_TEST_CASE(Errors)
+{
+  BOOST_CHECK_THROW(Filter::create(makeSection(""), "test-config"), Error);
+  BOOST_CHECK_THROW(Filter::create(makeSection("type unknown"), "test-config"), Error);
+  BOOST_CHECK_THROW(Filter::create(makeSection("type name"), "test-config"), Error);
+
+  std::string config = R"CONF(
+      type name
+      not-name-or-regex stuff
+    )CONF";
+  BOOST_CHECK_THROW(Filter::create(makeSection(config), "test-config"), Error);
+
+  config = R"CONF(
+      type name
+      name /foo/bar
+    )CONF";
+  BOOST_CHECK_THROW(Filter::create(makeSection(config), "test-config"), Error);
+
+  config = R"CONF(
+      type name
+      name /foo/bar
+      not-relation stuff
+    )CONF";
+  BOOST_CHECK_THROW(Filter::create(makeSection(config), "test-config"), Error);
+
+  config = R"CONF(
+      type name
+      name /foo/bar
+      relation equal
+      not-end stuff
+    )CONF";
+  BOOST_CHECK_THROW(Filter::create(makeSection(config), "test-config"), Error);
+
+  config = R"CONF(
+      type name
+      regex ^<foo><bar>$
+      not-end stuff
+    )CONF";
+  BOOST_CHECK_THROW(Filter::create(makeSection(config), "test-config"), Error);
+}
+
+BOOST_AUTO_TEST_CASE(NameFilter)
+{
+  std::string config = R"CONF(
+      type name
+      name /foo/bar
+      relation equal
+    )CONF";
+  auto f1 = Filter::create(makeSection(config), "test-config");
+  CHECK_FOR_MATCHES((*f1), true, false, false, false);
+
+  config = R"CONF(
+      type name
+      name /foo/bar
+      relation is-prefix-of
+    )CONF";
+  auto f2 = Filter::create(makeSection(config), "test-config");
+  CHECK_FOR_MATCHES((*f2), true, true, false, false);
+
+  config = R"CONF(
+      type name
+      name /foo/bar
+      relation is-strict-prefix-of
+    )CONF";
+  auto f3 = Filter::create(makeSection(config), "test-config");
+  CHECK_FOR_MATCHES((*f3), false, true, false, false);
+}
+
+BOOST_AUTO_TEST_CASE(RegexFilter)
+{
+  std::string config = R"CONF(
+      type name
+      regex ^<foo><bar>$
+    )CONF";
+  auto f1 = Filter::create(makeSection(config), "test-config");
+  CHECK_FOR_MATCHES((*f1), true, false, false, false);
+
+  config = R"CONF(
+      type name
+      regex ^<foo><bar><>*$
+    )CONF";
+  auto f2 = Filter::create(makeSection(config), "test-config");
+  CHECK_FOR_MATCHES((*f2), true, true, false, false);
+
+  config = R"CONF(
+      type name
+      regex ^<foo><bar><>+$
+    )CONF";
+  auto f3 = Filter::create(makeSection(config), "test-config");
+  CHECK_FOR_MATCHES((*f3), false, true, false, false);
+
+  config = R"CONF(
+      type name
+      regex ^<>*$
+    )CONF";
+  auto f4 = Filter::create(makeSection(config), "test-config");
+  CHECK_FOR_MATCHES((*f4), true, true, true, true);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // Create
+
+BOOST_AUTO_TEST_SUITE_END() // TestFilter
+BOOST_AUTO_TEST_SUITE_END() // ValidatorConfig
+BOOST_AUTO_TEST_SUITE_END() // V2
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
diff --git a/tests/unit-tests/security/v2/validator-config/name-relation.t.cpp b/tests/unit-tests/security/v2/validator-config/name-relation.t.cpp
new file mode 100644
index 0000000..cbe7084
--- /dev/null
+++ b/tests/unit-tests/security/v2/validator-config/name-relation.t.cpp
@@ -0,0 +1,79 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/v2/validator-config/name-relation.hpp"
+
+#include "boost-test.hpp"
+
+#include <boost/lexical_cast.hpp>
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(V2)
+BOOST_AUTO_TEST_SUITE(ValidatorConfig)
+BOOST_AUTO_TEST_SUITE(TestNameRelation)
+
+BOOST_AUTO_TEST_CASE(ToString)
+{
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(NameRelation::EQUAL), "equal");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(NameRelation::IS_PREFIX_OF),
+                    "is-prefix-of");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(NameRelation::IS_STRICT_PREFIX_OF),
+                    "is-strict-prefix-of");
+}
+
+BOOST_AUTO_TEST_CASE(FromString)
+{
+  BOOST_CHECK_EQUAL(getNameRelationFromString("equal"), NameRelation::EQUAL);
+  BOOST_CHECK_EQUAL(getNameRelationFromString("is-prefix-of"), NameRelation::IS_PREFIX_OF);
+  BOOST_CHECK_EQUAL(getNameRelationFromString("is-strict-prefix-of"), NameRelation::IS_STRICT_PREFIX_OF);
+  BOOST_CHECK_THROW(getNameRelationFromString("unknown"), validator_config::Error);
+}
+
+BOOST_AUTO_TEST_CASE(CheckRelation)
+{
+  BOOST_CHECK(checkNameRelation(NameRelation::EQUAL, "/prefix", "/prefix"));
+  BOOST_CHECK(!checkNameRelation(NameRelation::EQUAL, "/prefix", "/prefix/other"));
+
+  BOOST_CHECK(checkNameRelation(NameRelation::IS_PREFIX_OF, "/prefix", "/prefix"));
+  BOOST_CHECK(checkNameRelation(NameRelation::IS_PREFIX_OF, "/prefix", "/prefix/other"));
+  BOOST_CHECK(!checkNameRelation(NameRelation::IS_PREFIX_OF, "/prefix/other", "/prefix"));
+
+  BOOST_CHECK(!checkNameRelation(NameRelation::IS_STRICT_PREFIX_OF, "/prefix", "/prefix"));
+  BOOST_CHECK(checkNameRelation(NameRelation::IS_STRICT_PREFIX_OF, "/prefix", "/prefix/other"));
+  BOOST_CHECK(!checkNameRelation(NameRelation::IS_STRICT_PREFIX_OF, "/prefix/other", "/prefix"));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestNameRelation
+BOOST_AUTO_TEST_SUITE_END() // ValidatorConfig
+BOOST_AUTO_TEST_SUITE_END() // V2
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
diff --git a/tests/unit-tests/security/v2/validator-config/rule.t.cpp b/tests/unit-tests/security/v2/validator-config/rule.t.cpp
new file mode 100644
index 0000000..6c2e631
--- /dev/null
+++ b/tests/unit-tests/security/v2/validator-config/rule.t.cpp
@@ -0,0 +1,209 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/v2/validator-config/rule.hpp"
+
+#include "boost-test.hpp"
+#include "common.hpp"
+#include "identity-management-fixture.hpp"
+#include "../validator-fixture.hpp"
+
+#include <boost/mpl/vector_c.hpp>
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+namespace tests {
+
+using namespace ndn::tests;
+using namespace ndn::security::v2::tests;
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(V2)
+BOOST_AUTO_TEST_SUITE(ValidatorConfig)
+
+template<uint32_t PktType>
+class RuleFixture : public IdentityManagementFixture
+{
+public:
+  RuleFixture()
+    : rule(ruleId, PktType)
+    , pktName("/foo/bar")
+  {
+    if (PktType == tlv::Interest) {
+      pktName = Name("/foo/bar/SigInfo/SigValue");
+    }
+  }
+
+public:
+  const std::string ruleId = "rule-id";
+  Rule rule;
+  Name pktName;
+};
+
+using PktTypes = boost::mpl::vector_c<uint32_t, tlv::Data, tlv::Interest>;
+
+BOOST_AUTO_TEST_SUITE(TestRule)
+
+BOOST_FIXTURE_TEST_CASE(Errors, RuleFixture<tlv::Data>)
+{
+  BOOST_CHECK_THROW(rule.match(tlv::Interest, this->pktName), Error);
+
+  auto state = make_shared<DummyValidationState>();
+  BOOST_CHECK_THROW(rule.check(tlv::Interest, this->pktName, "/foo/bar", state), Error);
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(Constructor, PktType, PktTypes, RuleFixture<PktType::value>)
+{
+  BOOST_CHECK_EQUAL(this->rule.getId(), this->ruleId);
+  BOOST_CHECK_EQUAL(this->rule.getPktType(), PktType::value);
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(EmptyRule, PktType, PktTypes, RuleFixture<PktType::value>)
+{
+  BOOST_CHECK_EQUAL(this->rule.match(PktType::value, this->pktName), true);
+
+  auto state = make_shared<DummyValidationState>();
+  BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/foo/bar", state), false);
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(Filters, PktType, PktTypes, RuleFixture<PktType::value>)
+{
+  this->rule.addFilter(make_unique<RegexNameFilter>(Regex("^<foo><bar>$")));
+
+  BOOST_CHECK_EQUAL(this->rule.match(PktType::value, this->pktName), true);
+  BOOST_CHECK_EQUAL(this->rule.match(PktType::value, "/not" + this->pktName.toUri()), false);
+
+  this->rule.addFilter(make_unique<RegexNameFilter>(Regex("^<not><foo><bar>$")));
+
+  BOOST_CHECK_EQUAL(this->rule.match(PktType::value, this->pktName), true);
+  BOOST_CHECK_EQUAL(this->rule.match(PktType::value, "/not" + this->pktName.toUri()), true);
+
+  auto state = make_shared<DummyValidationState>();
+  BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/foo/bar", state), false);
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(Checkers, PktType, PktTypes, RuleFixture<PktType::value>)
+{
+  this->rule.addChecker(make_unique<HyperRelationChecker>("^(<>+)$", "\\1",
+                                                        "^<not>?(<>+)$", "\\1",
+                                                        NameRelation::EQUAL));
+
+  auto state = make_shared<DummyValidationState>();
+  BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/foo/bar", state), true);
+
+  state = make_shared<DummyValidationState>();
+  BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/not/foo/bar", state), true);
+
+  this->rule.addChecker(make_unique<HyperRelationChecker>("^(<>+)$", "\\1",
+                                                        "^(<>+)$", "\\1",
+                                                        NameRelation::EQUAL));
+  state = make_shared<DummyValidationState>();
+  BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/foo/bar", state), true);
+
+  state = make_shared<DummyValidationState>();
+  BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/not/foo/bar", state), false);
+}
+
+BOOST_AUTO_TEST_SUITE(Create)
+
+BOOST_AUTO_TEST_CASE(Errors)
+{
+  BOOST_CHECK_THROW(Rule::create(makeSection(""), "test-config"), Error);
+
+  std::string config = R"CONF(
+      id rule-id
+      for something
+    )CONF";
+  BOOST_CHECK_THROW(Rule::create(makeSection(config), "test-config"), Error);
+
+  config = R"CONF(
+      id rule-id
+      for data
+    )CONF";
+  BOOST_CHECK_THROW(Rule::create(makeSection(config), "test-config"), Error); // at least one checker required
+
+  config = R"CONF(
+      id rule-id
+      for data
+      checker
+      {
+        type hierarchical
+        sig-type rsa-sha256
+      }
+      other stuff
+    )CONF";
+  BOOST_CHECK_THROW(Rule::create(makeSection(config), "test-config"), Error);
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(FilterAndChecker, PktType, PktTypes, RuleFixture<PktType::value>)
+{
+  std::string config = std::string("") + R"CONF(
+      id rule-id
+      for )CONF" + (PktType::value == tlv::Data ? "data" : "interest") + R"CONF(
+      filter
+      {
+        type name
+        regex ^<foo><bar>$
+      }
+      checker
+      {
+        type customized
+        sig-type rsa-sha256
+        key-locator
+        {
+          type name
+          hyper-relation
+          {
+            k-regex ^(<>+)$
+            k-expand \\1
+            h-relation equal
+            p-regex ^(<>+)$
+            p-expand \\1
+          }
+        }
+      }
+    )CONF";
+  auto rule = Rule::create(makeSection(config), "test-config");
+
+  BOOST_CHECK_EQUAL(rule->match(PktType::value, this->pktName), true);
+  BOOST_CHECK_EQUAL(rule->match(PktType::value, "/not" + this->pktName.toUri()), false);
+
+  auto state = make_shared<DummyValidationState>();
+  BOOST_CHECK_EQUAL(rule->check(PktType::value, this->pktName, "/foo/bar", state), true);
+
+  state = make_shared<DummyValidationState>();
+  BOOST_CHECK_EQUAL(rule->check(PktType::value, this->pktName, "/not/foo/bar", state), false);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // Create
+
+BOOST_AUTO_TEST_SUITE_END() // TestRule
+BOOST_AUTO_TEST_SUITE_END() // ValidatorConfig
+BOOST_AUTO_TEST_SUITE_END() // V2
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn
diff --git a/tests/unit-tests/security/v2/validator-fixture.hpp b/tests/unit-tests/security/v2/validator-fixture.hpp
index fb7edda..7f52048 100644
--- a/tests/unit-tests/security/v2/validator-fixture.hpp
+++ b/tests/unit-tests/security/v2/validator-fixture.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -42,6 +42,7 @@
   ValidatorFixture()
     : face(io, {true, true})
     , validator(make_unique<ValidationPolicy>(), make_unique<CertificateFetcher>(face))
+    , policy(static_cast<ValidationPolicy&>(validator.getPolicy()))
     , cache(time::days(100))
   {
     processInterest = [this] (const Interest& interest) {
@@ -101,6 +102,7 @@
   util::DummyClientFace face;
   std::function<void(const Interest& interest)> processInterest;
   Validator validator;
+  ValidationPolicy& policy;
 
   CertificateCache cache;
 
@@ -144,6 +146,35 @@
 #define VALIDATE_SUCCESS(packet, message) this->template validate(packet, message, true, __LINE__)
 #define VALIDATE_FAILURE(packet, message) this->template validate(packet, message, false, __LINE__)
 
+class DummyValidationState : public ValidationState
+{
+public:
+  ~DummyValidationState()
+  {
+    m_outcome = false;
+  }
+
+  void
+  fail(const ValidationError& error) override
+  {
+    // BOOST_TEST_MESSAGE(error);
+    m_outcome = false;
+  }
+
+private:
+  void
+  verifyOriginalPacket(const Certificate& trustedCert) override
+  {
+    // do nothing
+  }
+
+  void
+  bypassValidation() override
+  {
+    // do nothing
+  }
+};
+
 } // namespace tests
 } // namespace v2
 } // namespace security
diff --git a/tests/unit-tests/security/validator-config.t.cpp b/tests/unit-tests/security/validator-config.t.cpp
index e2fbda1..37f2cff 100644
--- a/tests/unit-tests/security/validator-config.t.cpp
+++ b/tests/unit-tests/security/validator-config.t.cpp
@@ -20,18 +20,12 @@
  */
 
 #include "security/validator-config.hpp"
-#include "security/signing-helpers.hpp"
+#include "security/v2/certificate-fetcher-offline.hpp"
 #include "util/dummy-client-face.hpp"
-#include "util/io.hpp"
-#include "util/scheduler.hpp"
-#include "lp/nack.hpp"
-#include "lp/tags.hpp"
 
 #include "boost-test.hpp"
-#include "make-interest-data.hpp"
-#include "../identity-management-time-fixture.hpp"
-
-#include <boost/logic/tribool.hpp>
+#include "identity-management-fixture.hpp"
+#include "v2/validator-config/common.hpp"
 
 namespace ndn {
 namespace security {
@@ -40,1597 +34,85 @@
 using namespace ndn::tests;
 
 BOOST_AUTO_TEST_SUITE(Security)
+BOOST_FIXTURE_TEST_SUITE(TestValidatorConfig, IdentityManagementFixture)
 
-// Needed to create Face instance
-class ValidatorConfigFixture : public IdentityManagementV1TimeFixture
+// This test only for API, actual tests are in ValidationPolicyConfig and corresponding CertificateFetchers
+
+BOOST_AUTO_TEST_CASE(Construct)
+{
+  util::DummyClientFace face;
+
+  ValidatorConfig v1(face);
+  BOOST_CHECK_EQUAL(v1.m_policyConfig.m_isConfigured, false);
+
+  ValidatorConfig v2(make_unique<v2::CertificateFetcherOffline>());
+  BOOST_CHECK_EQUAL(v2.m_policyConfig.m_isConfigured, false);
+}
+
+class ValidatorConfigFixture : public IdentityManagementFixture
 {
 public:
   ValidatorConfigFixture()
-    : m_v2KeyChain("pib-memory:", "tpm-memory:")
-    , face(nullptr, m_v2KeyChain)
-    , validator(face)
+    : path(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) / "security" / "validator-config")
+    , validator(make_unique<v2::CertificateFetcherOffline>())
   {
+    boost::filesystem::create_directories(path);
+    config = R"CONF(
+        trust-anchor
+        {
+          type any
+        }
+      )CONF";
+    configFile = (this->path / "config.conf").string();
+    std::ofstream f(configFile.c_str());
+    f << config;
+  }
+
+  ~ValidatorConfigFixture()
+  {
+    boost::filesystem::remove_all(path);
   }
 
 public:
-  v2::KeyChain m_v2KeyChain;
-  Face face;
+  const boost::filesystem::path path;
+  std::string config;
+  std::string configFile;
   ValidatorConfig validator;
 };
 
-BOOST_FIXTURE_TEST_SUITE(TestValidatorConfig, ValidatorConfigFixture)
+BOOST_FIXTURE_TEST_SUITE(Loads, ValidatorConfigFixture)
 
-BOOST_AUTO_TEST_CASE(NameFilter)
+BOOST_AUTO_TEST_CASE(FromFile)
 {
-  Name identity("/TestValidatorConfig/NameFilter");
-  identity.appendVersion();
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity), "trust-anchor-1.cert"));
-  Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
-
-  Name dataName1("/simple/equal");
-  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity)));
-
-  Name dataName2("/simple/different");
-  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity)));
-
-  std::string CONFIG_1 =
-    "rule\n"
-    "{\n"
-    "  id \"Simple Rule\"\n"
-    "  for data\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    name /simple/equal\n"
-    "    relation equal\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type customized\n"
-    "    sig-type rsa-sha256\n"
-    "    key-locator\n"
-    "    {\n"
-    "      type name\n"
-    "      name ";
-
-  std::string CONFIG_2 =
-    "\n"
-    "      relation equal\n"
-    "    }\n"
-    "  }\n"
-    "}\n"
-    "trust-anchor\n"
-    "{\n"
-    "  type file\n"
-    "  file-name \"trust-anchor-1.cert\"\n"
-    "}\n";
-  const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2;
-
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  validator.validate(*data1,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
-
-  validator.validate(*data2,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(true); });
+  validator.load(configFile);
+  BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
+  BOOST_CHECK_THROW(validator.load(configFile), std::logic_error);
 }
 
-BOOST_AUTO_TEST_CASE(NameFilter2)
+BOOST_AUTO_TEST_CASE(FromString)
 {
-  Name identity("/TestValidatorConfig/NameFilter2");
-  identity.appendVersion();
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity), "trust-anchor-2.cert"));
-  Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
-
-  Name dataName1("/simple/isPrefixOf");
-  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity)));
-
-  Name dataName2("/simple/notPrefixOf");
-  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity)));
-
-  Name dataName3("/simple/isPrefixOf/anotherLevel");
-  shared_ptr<Data> data3 = make_shared<Data>(dataName3);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data3, security::signingByIdentity(identity)));
-
-  std::string CONFIG_1 =
-    "rule\n"
-    "{\n"
-    "  id \"Simple2 Rule\"\n"
-    "  for data\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    name /simple/isPrefixOf\n"
-    "    relation is-prefix-of\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type customized\n"
-    "    sig-type rsa-sha256\n"
-    "    key-locator\n"
-    "    {\n"
-    "      type name\n"
-    "      name ";
-
-  std::string CONFIG_2 =
-    "\n"
-    "      relation equal\n"
-    "    }\n"
-    "  }\n"
-    "}\n"
-    "trust-anchor\n"
-    "{\n"
-    "  type file\n"
-    "  file-name \"trust-anchor-2.cert\"\n"
-    "}\n";
-  const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2;
-
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  validator.validate(*data1,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
-
-  validator.validate(*data2,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(true); });
-
-  validator.validate(*data3,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
+  validator.load(config, "config-file-from-string");
+  BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
+  BOOST_CHECK_THROW(validator.load(configFile), std::logic_error);
 }
 
-BOOST_AUTO_TEST_CASE(NameFilter3)
+BOOST_AUTO_TEST_CASE(FromIstream)
 {
-  Name identity("/TestValidatorConfig/NameFilter3");
-  identity.appendVersion();
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity), "trust-anchor-3.cert"));
-  Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
-
-  Name dataName1("/simple/isStrictPrefixOf");
-  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity)));
-
-  Name dataName2("/simple");
-  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity)));
-
-  Name dataName3("/simple/isStrictPrefixOf/anotherLevel");
-  shared_ptr<Data> data3 = make_shared<Data>(dataName3);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data3, security::signingByIdentity(identity)));
-
-  std::string CONFIG_1 =
-    "rule\n"
-    "{\n"
-    "  id \"Simple3 Rule\"\n"
-    "  for data\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    name /simple/isStrictPrefixOf\n"
-    "    relation is-strict-prefix-of\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type customized\n"
-    "    sig-type rsa-sha256\n"
-    "    key-locator\n"
-    "    {\n"
-    "      type name\n"
-    "      name ";
-
-  std::string CONFIG_2 =
-    "\n"
-    "      relation equal\n"
-    "    }\n"
-    "  }\n"
-    "}\n"
-    "trust-anchor\n"
-    "{\n"
-    "  type file\n"
-    "  file-name \"trust-anchor-3.cert\"\n"
-    "}\n";
-  const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2;
-
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  validator.validate(*data1,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(true); });
-
-  validator.validate(*data2,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(true); });
-
-  validator.validate(*data3,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
+  std::istringstream is(config);
+  validator.load(is, "config-file-from-istream");
+  BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
+  BOOST_CHECK_THROW(validator.load(configFile), std::logic_error);
 }
 
-BOOST_AUTO_TEST_CASE(NameFilter4)
+BOOST_AUTO_TEST_CASE(FromSection)
 {
-  Name identity("/TestValidatorConfig/NameFilter4");
-  identity.appendVersion();
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity), "trust-anchor-4.cert"));
-  Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
-
-  Name dataName1("/simple/regex");
-  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity)));
-
-  Name dataName2("/simple/regex-wrong");
-  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity)));
-
-  Name dataName3("/simple/regex/correct");
-  shared_ptr<Data> data3 = make_shared<Data>(dataName3);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data3, security::signingByIdentity(identity)));
-
-  std::string CONFIG_1 =
-    "rule\n"
-    "{\n"
-    "  id \"Simple3 Rule\"\n"
-    "  for data\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    regex ^<simple><regex>\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type customized\n"
-    "    sig-type rsa-sha256\n"
-    "    key-locator\n"
-    "    {\n"
-    "      type name\n"
-    "      name ";
-
-  std::string CONFIG_2 =
-    "\n"
-    "      relation equal\n"
-    "    }\n"
-    "  }\n"
-    "}\n"
-    "trust-anchor\n"
-    "{\n"
-    "  type file\n"
-    "  file-name \"trust-anchor-4.cert\"\n"
-    "}\n";
-  const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2;
-
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  validator.validate(*data1,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
-
-  validator.validate(*data2,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(true); });
-
-  validator.validate(*data3,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
+  validator.load(v2::validator_config::tests::makeSection(config), "config-file-from-section");
+  BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
+  BOOST_CHECK_THROW(validator.load(configFile), std::logic_error);
 }
 
-BOOST_AUTO_TEST_CASE(KeyLocatorNameChecker1)
-{
-  Name identity("/TestValidatorConfig/KeyLocatorNameChecker1");
-  identity.appendVersion();
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity), "trust-anchor-5.cert"));
-
-  Name dataName1 = identity;
-  dataName1.append("1");
-  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity)));
-
-  Name dataName2 = identity;
-  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity)));
-
-  Name dataName3("/TestValidatorConfig/KeyLocatorNameChecker1");
-  shared_ptr<Data> data3 = make_shared<Data>(dataName3);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data3, security::signingByIdentity(identity)));
-
-  const std::string CONFIG =
-    "rule\n"
-    "{\n"
-    "  id \"Simple3 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"
-    "trust-anchor\n"
-    "{\n"
-    "  type file\n"
-    "  file-name \"trust-anchor-5.cert\"\n"
-    "}\n";
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  validator.validate(*data1,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
-
-  validator.validate(*data2,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(true); });
-
-  validator.validate(*data3,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(true); });
-}
-
-BOOST_AUTO_TEST_CASE(FixedSignerChecker)
-{
-  Name identity("/TestValidatorConfig/FixedSignerChecker");
-
-  Name identity1 = identity;
-  identity1.append("1").appendVersion();
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity1), "trust-anchor-7.cert"));
-
-  Name identity2 = identity;
-  identity2.append("2").appendVersion();
-  addIdentity(identity2);
-
-  Name dataName1 = identity;
-  dataName1.append("data").appendVersion();
-  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity1)));
-
-  Name dataName2 = identity;
-  dataName2.append("data").appendVersion();
-  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity2)));
-
-  Name interestName("/TestValidatorConfig/FixedSignerChecker/fakeSigInfo/fakeSigValue");
-  shared_ptr<Interest> interest = make_shared<Interest>(interestName);
-
-  const std::string CONFIG =
-    "rule\n"
-    "{\n"
-    "  id \"FixedSignerChecker Data Rule\"\n"
-    "  for data\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    name /TestValidatorConfig/FixedSignerChecker\n"
-    "    relation is-strict-prefix-of\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type fixed-signer\n"
-    "    sig-type rsa-sha256\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-7.cert\"\n"
-    "    }\n"
-    "  }\n"
-    "}\n"
-    "rule\n"
-    "{\n"
-    "  id \"FixedSignerChecker Interest Rule\"\n"
-    "  for interest\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    name /TestValidatorConfig/FixedSignerChecker\n"
-    "    relation is-strict-prefix-of\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type fixed-signer\n"
-    "    sig-type rsa-sha256\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-7.cert\"\n"
-    "    }\n"
-    "  }\n"
-    "}\n";
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  validator.validate(*data1,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
-
-  validator.validate(*data2,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(true); });
-
-  validator.validate(*interest,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(true); });
-}
-
-BOOST_AUTO_TEST_CASE(MultiCheckers)
-{
-  Name identity1("/TestValidatorConfig/MultiCheckers/");
-  identity1.appendVersion();
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity1), "trust-anchor-multi-1.cert"));
-
-  Name identity2("/TestValidatorConfig/");
-  identity2.appendVersion();
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity2), "trust-anchor-multi-2.cert"));
-
-  const std::string CONFIG =
-    "rule\n"
-    "{\n"
-    "  id \"Simple Rule01\"\n"
-    "  for data\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    name /\n"
-    "    relation is-prefix-of\n"
-    "  }\n"
-    "  checker\n" // checker 1, signer should have prefix /TestValidatorConfig/MultiCheckers
-    "  {\n"
-    "    type customized\n"
-    "    sig-type rsa-sha256\n"
-    "    key-locator\n"
-    "    {\n"
-    "      type name\n"
-    "      name /TestValidatorConfig/MultiCheckers/\n"
-    "      relation is-prefix-of\n"
-    "    }\n"
-    "  }\n"
-    "  checker\n" // checker 2, data should have same prefix of its signer
-    "  {\n"
-    "    type hierarchical\n"
-    "    sig-type rsa-sha256\n"
-    "  }\n"
-    "  checker\n" // checker 3, the signer should be identity1
-    "  {\n"
-    "    type fixed-signer\n"
-    "    sig-type rsa-sha256\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-multi-1.cert\"\n"
-    "    }\n"
-    "  }\n"
-    "}\n";
-
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-multicheckers.conf"));
-
-  ValidatorConfig validator;
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-  conf::Checker& checker0 = *validator.m_dataRules.front()->m_checkers[0];
-  conf::Checker& checker1 = *validator.m_dataRules.front()->m_checkers[1];
-  conf::Checker& checker2 = *validator.m_dataRules.front()->m_checkers[2];
-
-  auto data1 = makeData(Name(identity1).append("Test"));
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity1)));
-  BOOST_CHECK_EQUAL(checker0.check(*data1), 0);
-  BOOST_CHECK_EQUAL(checker1.check(*data1), 0);
-  BOOST_CHECK_EQUAL(checker2.check(*data1), 1);
-
-  auto data2 = makeData(Name(identity2).append("Data2"));
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity2)));
-  BOOST_CHECK_EQUAL(checker0.check(*data2), -1);
-  BOOST_CHECK_EQUAL(checker1.check(*data2), 0);
-  BOOST_CHECK_EQUAL(checker2.check(*data2), -1);
-
-  auto data3 = makeData(Name(identity2).append("Data3"));
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data3, security::signingByIdentity(identity1)));
-  BOOST_CHECK_EQUAL(checker0.check(*data3), 0);
-  BOOST_CHECK_EQUAL(checker1.check(*data3), -1);
-  BOOST_CHECK_EQUAL(checker2.check(*data3), 1);
-
-  auto data4 = makeData("/Data4");
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data4, security::signingByIdentity(identity2)));
-  BOOST_CHECK_EQUAL(checker0.check(*data4), -1);
-  BOOST_CHECK_EQUAL(checker1.check(*data4), -1);
-  BOOST_CHECK_EQUAL(checker2.check(*data4), -1);
-
-  int count = 0;
-  validator.validate(*data1,
-    [&] (const shared_ptr<const Data>&) {
-      BOOST_CHECK(true);
-      count++;
-    },
-    [] (const shared_ptr<const Data>&, const std::string& str) { BOOST_CHECK(false); });
-
-  validator.validate(*data2,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [&] (const shared_ptr<const Data>&, const std::string& str) {
-      BOOST_CHECK(true);
-      count++;
-    });
-
-  validator.validate(*data3,
-    [&] (const shared_ptr<const Data>&) {
-      BOOST_CHECK(true);
-      count++;
-    },
-    [] (const shared_ptr<const Data>&, const std::string& str) { BOOST_CHECK(false); });
-
-  validator.validate(*data4,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [&] (const shared_ptr<const Data>&, const std::string& str) {
-      BOOST_CHECK(true);
-      count++;
-    });
-
-  BOOST_CHECK_EQUAL(count, 4);
-}
-
-BOOST_AUTO_TEST_CASE(Reset)
-{
-  Name root("/TestValidatorConfig/Reload");
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(root), "trust-anchor-8.cert"));
-
-  const std::string CONFIG =
-    "rule\n"
-    "{\n"
-    "  id \"NRD Prefix Registration Command Rule\"\n"
-    "  for interest\n"
-    "  filter\n"
-    "  {\n"
-    "    type name\n"
-    "    regex ^<localhost><nrd>[<register><unregister><advertise><withdraw>]<>$\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type customized\n"
-    "    sig-type rsa-sha256\n"
-    "    key-locator\n"
-    "    {\n"
-    "      type name\n"
-    "      regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT>$\n"
-    "    }\n"
-    "  }\n"
-    "}\n"
-    "rule\n"
-    "{\n"
-    "  id \"Testbed Hierarchy Rule\"\n"
-    "  for data\n"
-    "  filter\n"
-    "  {\n"
-    "    type name\n"
-    "    regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT><>$\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type hierarchical\n"
-    "    sig-type rsa-sha256\n"
-    "  }\n"
-    "}\n"
-    "trust-anchor\n"
-    "{\n"
-    "  type file\n"
-    "  file-name \"trust-anchor-8.cert\"\n"
-    "}\n";
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-  BOOST_CHECK_EQUAL(validator.isEmpty(), false);
-
-  validator.reset();
-  BOOST_CHECK(validator.isEmpty());
-}
-
-BOOST_AUTO_TEST_CASE(TrustAnchorWildcard)
-{
-  Name identity("/TestValidatorConfig/Wildcard");
-  identity.appendVersion();
-  addIdentity(identity);
-
-  Name dataName1("/any/data");
-  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity)));
-
-  std::string CONFIG =
-    "trust-anchor\n"
-    "{\n"
-    "  type any\n"
-    "}\n";
-
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  validator.validate(*data1,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
-}
-
-BOOST_AUTO_TEST_CASE(SignedInterestTest)
-{
-  Name certName = addIdentity("/TestValidatorConfig/SignedInterestTest");
-  BOOST_REQUIRE(saveIdentityCertificate(certName, "trust-anchor-9.cert"));
-
-  Name interestName("/TestValidatorConfig/SignedInterestTest");
-  Name interestName1 = interestName;
-  interestName1.append("1");
-  shared_ptr<Interest> interest1 = make_shared<Interest>(interestName1);
-  Name interestName2 = interestName;
-  interestName2.append("2");
-  shared_ptr<Interest> interest2 = make_shared<Interest>(interestName2);
-
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest1, security::signingByCertificate(certName)));
-  advanceClocks(time::milliseconds(10));
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest2, security::signingByCertificate(certName)));
-
-  const std::string CONFIG =
-    "rule\n"
-    "{\n"
-    "  id \"FixedSignerChecker Interest Rule\"\n"
-    "  for interest\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    name /TestValidatorConfig/SignedInterestTest\n"
-    "    relation is-strict-prefix-of\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type fixed-signer\n"
-    "    sig-type rsa-sha256\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-9.cert\"\n"
-    "    }\n"
-    "  }\n"
-    "}\n";
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  validator.validate(*interest1,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest2,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest1,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(true); });
-  advanceClocks(time::milliseconds(10));
-}
-
-BOOST_AUTO_TEST_CASE(MaxKeyTest)
-{
-  Name identity("/TestValidatorConfig/MaxKeyTest");
-
-  Name identity1 = identity;
-  identity1.append("Key1");
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity1), "trust-anchor-10-1.cert"));
-
-  Name identity2 = identity;
-  identity2.append("Key2");
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity2), "trust-anchor-10-2.cert"));
-
-  Name identity3 = identity;
-  identity3.append("Key3");
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity3), "trust-anchor-10-3.cert"));
-
-
-  Name interestName("/TestValidatorConfig/MaxKeyTest");
-  Name interestName1 = interestName;
-  interestName1.append("1");
-  shared_ptr<Interest> interest1 = make_shared<Interest>(interestName1);
-  Name interestName2 = interestName;
-  interestName2.append("2");
-  shared_ptr<Interest> interest2 = make_shared<Interest>(interestName2);
-  Name interestName3 = interestName;
-  interestName3.append("3");
-  shared_ptr<Interest> interest3 = make_shared<Interest>(interestName3);
-
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest1, security::signingByIdentity(identity1)));
-  advanceClocks(time::milliseconds(10));
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest2, security::signingByIdentity(identity2)));
-  advanceClocks(time::milliseconds(10));
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest3, security::signingByIdentity(identity3)));
-  advanceClocks(time::milliseconds(10));
-
-  const std::string CONFIG =
-    "rule\n"
-    "{\n"
-    "  id \"FixedSignerChecker Interest Rule\"\n"
-    "  for interest\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    name /TestValidatorConfig/MaxKeyTest\n"
-    "    relation is-strict-prefix-of\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type fixed-signer\n"
-    "    sig-type rsa-sha256\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-10-1.cert\"\n"
-    "    }\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-10-2.cert\"\n"
-    "    }\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-10-3.cert\"\n"
-    "    }\n"
-    "  }\n"
-    "}\n";
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  ValidatorConfig validator(face,
-                            ValidatorConfig::DEFAULT_CERTIFICATE_CACHE,
-                            ValidatorConfig::DEFAULT_GRACE_INTERVAL,
-                            10,
-                            2,                 // Two keys can be tracked
-                            time::seconds(1)); // TTL is set to 1 sec
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  validator.validate(*interest1,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest2,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest1,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(true); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest3,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-
-  // Should succeed because identity1's key has been cleaned up due to space limit.
-  validator.validate(*interest1,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-}
-
-BOOST_AUTO_TEST_CASE(MaxKeyTest2)
-{
-  Name identity("/TestValidatorConfig/MaxKeyTest");
-
-  Name identity1 = identity;
-  identity1.append("Key1");
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity1), "trust-anchor-10-1.cert"));
-
-  Name identity2 = identity;
-  identity2.append("Key2");
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity2), "trust-anchor-10-2.cert"));
-
-  Name identity3 = identity;
-  identity3.append("Key3");
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity3), "trust-anchor-10-3.cert"));
-
-  Name identity4 = identity;
-  identity4.append("Key4");
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(identity4), "trust-anchor-10-4.cert"));
-
-
-  Name interestName("/TestValidatorConfig/MaxKeyTest");
-  Name interestName1 = interestName;
-  interestName1.append("1");
-  shared_ptr<Interest> interest1 = make_shared<Interest>(interestName1);
-  Name interestName2 = interestName;
-  interestName2.append("2");
-  shared_ptr<Interest> interest2 = make_shared<Interest>(interestName2);
-  Name interestName3 = interestName;
-  interestName3.append("3");
-  shared_ptr<Interest> interest3 = make_shared<Interest>(interestName3);
-  Name interestName4 = interestName;
-  interestName4.append("4");
-  shared_ptr<Interest> interest4 = make_shared<Interest>(interestName4);
-
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest1, security::signingByIdentity(identity1)));
-  advanceClocks(time::milliseconds(10));
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest2, security::signingByIdentity(identity2)));
-  advanceClocks(time::milliseconds(10));
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest3, security::signingByIdentity(identity3)));
-  advanceClocks(time::milliseconds(10));
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest4, security::signingByIdentity(identity4)));
-  advanceClocks(time::milliseconds(10));
-
-  const std::string CONFIG =
-    "rule\n"
-    "{\n"
-    "  id \"FixedSignerChecker Interest Rule\"\n"
-    "  for interest\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    name /TestValidatorConfig/MaxKeyTest\n"
-    "    relation is-strict-prefix-of\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type fixed-signer\n"
-    "    sig-type rsa-sha256\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-10-1.cert\"\n"
-    "    }\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-10-2.cert\"\n"
-    "    }\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-10-3.cert\"\n"
-    "    }\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-10-4.cert\"\n"
-    "    }\n"
-    "  }\n"
-    "}\n";
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  ValidatorConfig validator(face,
-                            ValidatorConfig::DEFAULT_CERTIFICATE_CACHE,
-                            ValidatorConfig::DEFAULT_GRACE_INTERVAL,
-                            10,
-                            3,                 // Three keys can be tracked
-                            time::seconds(1)); // TTL is set to 1 sec
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  validator.validate(*interest1,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest2,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest3,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest1,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(true); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest2,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(true); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest3,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(true); });
-
-  advanceClocks(time::seconds(2));
-
-  validator.validate(*interest4,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-
-  // Should succeed because identity1 and identity2's key has been cleaned up due to ttl limit.
-  validator.validate(*interest1,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest2,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-
-  validator.validate(*interest3,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10));
-}
-
-BOOST_AUTO_TEST_CASE(FixedSignerChecker2)
-{
-  Name rsaIdentity("/TestValidatorConfig/FixedSignerChecker2/Rsa");
-  addIdentity(rsaIdentity, RsaKeyParams());
-
-  Name ecIdentity("/TestValidatorConfig/FixedSignerChecker2/Ec");
-  auto identity = addIdentity(ecIdentity, EcKeyParams());
-  BOOST_REQUIRE(saveIdentityCertificate(identity, "trust-anchor-11.cert"));
-
-  Name dataName("/TestValidatorConfig/FixedSignerChecker2");
-  shared_ptr<Data> dataRsa = make_shared<Data>(dataName);
-  m_keyChain.sign(*dataRsa, security::signingByIdentity(rsaIdentity));
-  shared_ptr<Data> dataEc = make_shared<Data>(dataName);
-  m_keyChain.sign(*dataEc, security::signingByIdentity(ecIdentity));
-
-  shared_ptr<Interest> interestRsa = make_shared<Interest>(dataName);
-  m_keyChain.sign(*interestRsa, security::signingByIdentity(rsaIdentity));
-  shared_ptr<Interest> interestEc = make_shared<Interest>(dataName);
-  m_keyChain.sign(*interestEc, security::signingByIdentity(ecIdentity));
-
-  const std::string CONFIG =
-    "rule\n"
-    "{\n"
-    "  id \"FixedSignerChecker Data Rule\"\n"
-    "  for data\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    name /TestValidatorConfig/FixedSignerChecker2\n"
-    "    relation equal\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type fixed-signer\n"
-    "    sig-type ecdsa-sha256\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-11.cert\"\n"
-    "    }\n"
-    "  }\n"
-    "}\n"
-    "rule\n"
-    "{\n"
-    "  id \"FixedSignerChecker Interest Rule\"\n"
-    "  for interest\n"
-    "  filter"
-    "  {\n"
-    "    type name\n"
-    "    name /TestValidatorConfig/FixedSignerChecker2\n"
-    "    relation equal\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type fixed-signer\n"
-    "    sig-type ecdsa-sha256\n"
-    "    signer\n"
-    "    {\n"
-    "      type file\n"
-    "      file-name \"trust-anchor-11.cert\"\n"
-    "    }\n"
-    "  }\n"
-    "}\n";
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test.conf"));
-
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  validator.validate(*dataEc,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
-
-  validator.validate(*dataRsa,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(true); });
-
-  validator.validate(*interestEc,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-
-  validator.validate(*interestRsa,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(true); });
-}
-
-
-struct FacesFixture : public ValidatorConfigFixture
-{
-  FacesFixture()
-    : face1(io, m_v2KeyChain, {true, true})
-    , face2(io, m_v2KeyChain, {true, true})
-    , readInterestOffset1(0)
-    , readDataOffset1(0)
-    , readInterestOffset2(0)
-    , readDataOffset2(0)
-  {
-  }
-
-  bool
-  passPacket()
-  {
-    bool hasPassed = false;
-
-    checkFace(face1.sentInterests, readInterestOffset1, face2, hasPassed);
-    checkFace(face1.sentData, readDataOffset1, face2, hasPassed);
-    checkFace(face2.sentInterests, readInterestOffset2, face1, hasPassed);
-    checkFace(face2.sentData, readDataOffset2, face1, hasPassed);
-
-    return hasPassed;
-  }
-
-  template<typename Packet>
-  void
-  checkFace(std::vector<Packet>& receivedPackets,
-            size_t& readPacketOffset,
-            util::DummyClientFace& receiver,
-            bool& hasPassed)
-  {
-    while (receivedPackets.size() > readPacketOffset) {
-      receiver.receive(receivedPackets[readPacketOffset]);
-      readPacketOffset++;
-      hasPassed = true;
-    }
-  }
-
-public:
-  util::DummyClientFace face1;
-  util::DummyClientFace face2;
-
-  size_t readInterestOffset1;
-  size_t readDataOffset1;
-  size_t readInterestOffset2;
-  size_t readDataOffset2;
-};
-
-BOOST_FIXTURE_TEST_CASE(HierarchicalChecker, FacesFixture)
-{
-  std::vector<v1::CertificateSubjectDescription> subjectDescription;
-
-  Name root("/TestValidatorConfig");
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(root), "trust-anchor-6.cert"));
-
-
-  Name sld("/TestValidatorConfig/HierarchicalChecker");
-  addIdentity(sld);
-  advanceClocks(time::milliseconds(100));
-  Name sldKeyName = m_keyChain.generateRsaKeyPairAsDefault(sld, true);
-  shared_ptr<v1::IdentityCertificate> sldCert =
-    m_keyChain.prepareUnsignedIdentityCertificate(sldKeyName,
-                                                  root,
-                                                  time::system_clock::now(),
-                                                  time::system_clock::now() + time::days(7300),
-                                                  subjectDescription);
-  m_keyChain.sign(*sldCert, security::signingByIdentity(root));
-  m_keyChain.addCertificateAsIdentityDefault(*sldCert);
-
-  Name nld("/TestValidatorConfig/HierarchicalChecker/NextLevel");
-  addIdentity(nld);
-  advanceClocks(time::milliseconds(100));
-  Name nldKeyName = m_keyChain.generateRsaKeyPairAsDefault(nld, true);
-  shared_ptr<v1::IdentityCertificate> nldCert =
-    m_keyChain.prepareUnsignedIdentityCertificate(nldKeyName,
-                                                  sld,
-                                                  time::system_clock::now(),
-                                                  time::system_clock::now() + time::days(7300),
-                                                  subjectDescription);
-  m_keyChain.sign(*nldCert, security::signingByIdentity(sld));
-  m_keyChain.addCertificateAsIdentityDefault(*nldCert);
-
-  face1.setInterestFilter(sldCert->getName().getPrefix(-1),
-    [&] (const InterestFilter&, const Interest&) { face1.put(*sldCert); },
-    RegisterPrefixSuccessCallback(),
-    [] (const Name&, const std::string&) {});
-
-  face1.setInterestFilter(nldCert->getName().getPrefix(-1),
-    [&] (const InterestFilter&, const Interest&) { face1.put(*nldCert); },
-    RegisterPrefixSuccessCallback(),
-    [] (const Name&, const std::string&) {});
-
-  Name dataName1 = nld;
-  dataName1.append("data1");
-  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(nld)));
-
-  Name dataName2("/ConfValidatorTest");
-  dataName2.append("data1");
-  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(nld)));
-
-  const std::string CONFIG =
-    "rule\n"
-    "{\n"
-    "  id \"Simple3 Rule\"\n"
-    "  for data\n"
-    "  checker\n"
-    "  {\n"
-    "    type hierarchical\n"
-    "    sig-type rsa-sha256\n"
-    "  }\n"
-    "}\n"
-    "trust-anchor\n"
-    "{\n"
-    "  type file\n"
-    "  file-name \"trust-anchor-6.cert\"\n"
-    "}\n";
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  auto validator = make_shared<ValidatorConfig>(&face2);
-  validator->load(CONFIG, CONFIG_PATH.c_str());
-
-  advanceClocks(time::milliseconds(2), 100);
-  validator->validate(*data1,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
-
-  do {
-    advanceClocks(time::milliseconds(2), 10);
-  } while (passPacket());
-
-  validator->validate(*data2,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(true); });
-
-  do {
-    advanceClocks(time::milliseconds(2), 10);
-  } while (passPacket());
-}
-
-BOOST_FIXTURE_TEST_CASE(Nrd, FacesFixture)
-{
-  advanceClocks(time::nanoseconds(1));
-
-  std::vector<v1::CertificateSubjectDescription> subjectDescription;
-
-  Name root("/TestValidatorConfig");
-  BOOST_REQUIRE(saveIdentityCertificate(addIdentity(root), "trust-anchor-8.cert"));
-
-  Name sld("/TestValidatorConfig/Nrd-1");
-  addIdentity(sld);
-  advanceClocks(time::milliseconds(100));
-  Name sldKeyName = m_keyChain.generateRsaKeyPairAsDefault(sld, true);
-  shared_ptr<v1::IdentityCertificate> sldCert =
-    m_keyChain.prepareUnsignedIdentityCertificate(sldKeyName,
-                                                  root,
-                                                  time::system_clock::now(),
-                                                  time::system_clock::now() + time::days(7300),
-                                                  subjectDescription);
-  m_keyChain.sign(*sldCert, security::signingByIdentity(root));
-  m_keyChain.addCertificateAsIdentityDefault(*sldCert);
-
-  Name nld("/TestValidatorConfig/Nrd-1/Nrd-2");
-  addIdentity(nld);
-  advanceClocks(time::milliseconds(100));
-  Name nldKeyName = m_keyChain.generateRsaKeyPairAsDefault(nld, true);
-  shared_ptr<v1::IdentityCertificate> nldCert =
-    m_keyChain.prepareUnsignedIdentityCertificate(nldKeyName,
-                                                  sld,
-                                                  time::system_clock::now(),
-                                                  time::system_clock::now() + time::days(7300),
-                                                  subjectDescription);
-  m_keyChain.sign(*nldCert, security::signingByIdentity(sld));
-  m_keyChain.addCertificateAsIdentityDefault(*nldCert);
-
-  face1.setInterestFilter(sldCert->getName().getPrefix(-1),
-    [&] (const InterestFilter&, const Interest&) { face1.put(*sldCert); },
-    RegisterPrefixSuccessCallback(),
-    [] (const Name&, const std::string&) {});
-
-  face1.setInterestFilter(nldCert->getName().getPrefix(-1),
-    [&] (const InterestFilter&, const Interest&) { face1.put(*nldCert); },
-    RegisterPrefixSuccessCallback(),
-    [] (const Name&, const std::string&) {});
-
-  advanceClocks(time::milliseconds(10));
-  Name interestName1("/localhost/nrd/register/option");
-  shared_ptr<Interest> interest1 = make_shared<Interest>(interestName1);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest1, security::signingByIdentity(nld)));
-
-  advanceClocks(time::milliseconds(10));
-  Name interestName2("/localhost/nrd/non-register");
-  shared_ptr<Interest> interest2 = make_shared<Interest>(interestName2);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest2, security::signingByIdentity(nld)));
-
-  advanceClocks(time::milliseconds(10));
-  Name interestName3("/localhost/nrd/register/option");
-  shared_ptr<Interest> interest3 = make_shared<Interest>(interestName3);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest3, security::signingByIdentity(root)));
-
-  advanceClocks(time::milliseconds(10));
-  Name interestName4("/localhost/nrd/register/option/timestamp/nonce/fakeSigInfo/fakeSigValue");
-  shared_ptr<Interest> interest4 = make_shared<Interest>(interestName4);
-
-  const std::string CONFIG =
-    "rule\n"
-    "{\n"
-    "  id \"NRD Prefix Registration Command Rule\"\n"
-    "  for interest\n"
-    "  filter\n"
-    "  {\n"
-    "    type name\n"
-    "    regex ^<localhost><nrd>[<register><unregister><advertise><withdraw>]<>$\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type customized\n"
-    "    sig-type rsa-sha256\n"
-    "    key-locator\n"
-    "    {\n"
-    "      type name\n"
-    "      regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT>$\n"
-    "    }\n"
-    "  }\n"
-    "}\n"
-    "rule\n"
-    "{\n"
-    "  id \"Testbed Hierarchy Rule\"\n"
-    "  for data\n"
-    "  filter\n"
-    "  {\n"
-    "    type name\n"
-    "    regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT><>$\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type hierarchical\n"
-    "    sig-type rsa-sha256\n"
-    "  }\n"
-    "}\n"
-    "trust-anchor\n"
-    "{\n"
-    "  type file\n"
-    "  file-name \"trust-anchor-8.cert\"\n"
-    "}\n";
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  auto validator = make_shared<ValidatorConfig>(&face2);
-  validator->load(CONFIG, CONFIG_PATH.c_str());
-
-  advanceClocks(time::milliseconds(2), 100);
-
-  // should succeed
-  validator->validate(*interest1,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-
-  do {
-    advanceClocks(time::milliseconds(2), 10);
-  } while (passPacket());
-
-  // should fail
-  validator->validate(*interest2,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(true); });
-
-  do {
-    advanceClocks(time::milliseconds(2), 10);
-  } while (passPacket());
-
-  // should succeed
-  validator->validate(*interest3,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(false); });
-
-  do {
-    advanceClocks(time::milliseconds(2), 10);
-  } while (passPacket());
-
-  // should fail
-  validator->validate(*interest4,
-    [] (const shared_ptr<const Interest>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Interest>&, const std::string&) { BOOST_CHECK(true); });
-
-  do {
-    advanceClocks(time::milliseconds(2), 10);
-  } while (passPacket());
-}
-
-struct DirTestFixture : public ValidatorConfigFixture
-{
-  DirTestFixture()
-    : validator(&face, ValidatorConfig::DEFAULT_CERTIFICATE_CACHE,
-                ValidatorConfig::DEFAULT_GRACE_INTERVAL, 0)
-  {
-    certDirPath = (boost::filesystem::current_path() / std::string("test-cert-dir"));
-    boost::filesystem::create_directory(certDirPath);
-
-    firstCertPath = (boost::filesystem::current_path() /
-                     std::string("test-cert-dir") /
-                     std::string("trust-anchor-1.cert"));
-
-    secondCertPath = (boost::filesystem::current_path() /
-                      std::string("test-cert-dir") /
-                      std::string("trust-anchor-2.cert"));
-
-    firstIdentity = Name("/TestValidatorConfig/Dir/First");
-    addIdentity(firstIdentity);
-    Name firstCertName = m_keyChain.getDefaultCertificateNameForIdentity(firstIdentity);
-    firstCert = m_keyChain.getCertificate(firstCertName);
-    io::save(*firstCert, firstCertPath.string());
-
-    secondIdentity = Name("/TestValidatorConfig/Dir/Second");
-    addIdentity(secondIdentity);
-    Name secondCertName = m_keyChain.getDefaultCertificateNameForIdentity(secondIdentity);
-    secondCert = m_keyChain.getCertificate(secondCertName);
-  }
-
-  ~DirTestFixture()
-  {
-    boost::filesystem::remove_all(certDirPath);
-  }
-
-public:
-  boost::filesystem::path certDirPath;
-  boost::filesystem::path firstCertPath;
-  boost::filesystem::path secondCertPath;
-
-  Name firstIdentity;
-  Name secondIdentity;
-
-  shared_ptr<v1::IdentityCertificate> firstCert;
-  shared_ptr<v1::IdentityCertificate> secondCert;
-
-  ValidatorConfig validator;
-};
-
-BOOST_FIXTURE_TEST_CASE(TrustAnchorDir, DirTestFixture)
-{
-  advanceClocks(time::milliseconds(10));
-
-  Name dataName1("/any/data/1");
-  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(firstIdentity)));
-
-  Name dataName2("/any/data/2");
-  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
-  BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(secondIdentity)));
-
-  std::string CONFIG =
-    "rule\n"
-    "{\n"
-    "  id \"Any Rule\"\n"
-    "  for data\n"
-    "  filter\n"
-    "  {\n"
-    "    type name\n"
-    "    regex ^<>*$\n"
-    "  }\n"
-    "  checker\n"
-    "  {\n"
-    "    type customized\n"
-    "    sig-type rsa-sha256\n"
-    "    key-locator\n"
-    "    {\n"
-    "      type name\n"
-    "      regex ^<>*$\n"
-    "    }\n"
-    "  }\n"
-    "}\n"
-    "trust-anchor\n"
-    "{\n"
-    "  type dir\n"
-    "  dir test-cert-dir\n"
-    "  refresh 1s\n"
-    "}\n";
-
-  const boost::filesystem::path CONFIG_PATH =
-    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
-
-  validator.load(CONFIG, CONFIG_PATH.c_str());
-
-  advanceClocks(time::milliseconds(10), 20);
-  validator.validate(*data1,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10), 20);
-
-  validator.validate(*data2,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(false); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(true); });
-  advanceClocks(time::milliseconds(10), 20);
-
-  io::save(*secondCert, secondCertPath.string());
-  advanceClocks(time::milliseconds(10), 200);
-
-  validator.validate(*data1,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10), 20);
-
-  validator.validate(*data2,
-    [] (const shared_ptr<const Data>&) { BOOST_CHECK(true); },
-    [] (const shared_ptr<const Data>&, const std::string&) { BOOST_CHECK(false); });
-  advanceClocks(time::milliseconds(10), 20);
-}
-
-class DirectCertFetchFixture : public ValidatorConfigFixture
-{
-public:
-  DirectCertFetchFixture()
-    : clientFace(io, m_v2KeyChain, {true, true})
-    , validationResult(boost::logic::indeterminate)
-  {
-    auto certName = addIdentity(ca);
-    saveIdentityCertificate(certName, "trust-anchor-1.cert");
-    addSubCertificate(user, ca);
-
-    userCertName = m_keyChain.getDefaultCertificateNameForIdentity(user);
-    userCert = m_keyChain.getCertificate(userCertName);
-  }
-
-protected:
-  void
-  runTest(const std::function<void(const Interest&, const Interest&)> respond)
-  {
-    optional<Interest> directInterest;
-    optional<Interest> infrastructureInterest;
-    clientFace.onSendInterest.connect([&] (const Interest& interest) {
-      const Name& interestName = interest.getName();
-      if (interestName == userCert->getName().getPrefix(-1)) {
-        auto nextHopFaceIdTag = interest.getTag<lp::NextHopFaceIdTag>();
-        if (nextHopFaceIdTag != nullptr) {
-          BOOST_CHECK(!directInterest);
-          directInterest = interest;
-        }
-        else {
-          BOOST_CHECK(!infrastructureInterest);
-          infrastructureInterest = interest;
-        }
-        if (static_cast<bool>(directInterest) && static_cast<bool>(infrastructureInterest)) {
-          io.post([directInterest, infrastructureInterest, respond] {
-              respond(directInterest.value(), infrastructureInterest.value());
-            });
-          directInterest = nullopt;
-          infrastructureInterest = nullopt;
-        }
-      }
-    });
-
-    const boost::filesystem::path CONFIG_PATH =
-      (boost::filesystem::current_path() / std::string("unit-test-direct.conf"));
-    ValidatorConfig validator(&clientFace);
-    validator.load(CONFIG, CONFIG_PATH.c_str());
-    validator.setDirectCertFetchEnabled(true);
-
-    shared_ptr<Interest> interest = make_shared<Interest>(interestName);
-    interest->setTag(make_shared<lp::IncomingFaceIdTag>(123));
-    BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest, security::signingByIdentity(user)));
-
-    validator.validate(*interest,
-                       [&] (const shared_ptr<const Interest>&) {
-                         BOOST_CHECK(boost::logic::indeterminate(validationResult));
-                         validationResult = true;
-                       },
-                       [&] (const shared_ptr<const Interest>&, const std::string& s) {
-                         BOOST_CHECK(boost::logic::indeterminate(validationResult));
-                         validationResult = false;
-                       });
-
-    advanceClocks(time::milliseconds(200), 60);
-
-    BOOST_CHECK(!boost::logic::indeterminate(validationResult));
-  }
-
-public:
-  util::DummyClientFace clientFace;
-  const Name ca = Name("/DirectCertFetch");
-  const Name user = Name("/DirectCertFetch/user");
-  const Name interestName = Name("/DirectCertFetch/user/tag-interest");
-  const std::string CONFIG = R"_TEXT_(
-      rule
-      {
-        id "RuleForInterest"
-        for interest
-        checker
-        {
-          type hierarchical
-          sig-type rsa-sha256
-        }
-      }
-      rule
-      {
-        id "RuleForData"
-        for data
-        filter
-        {
-          type name
-          regex ^<>*$
-        }
-        checker
-        {
-          type customized
-          sig-type rsa-sha256
-          key-locator
-        {
-          type name
-           regex ^<>*$
-          }
-        }
-      }
-      trust-anchor
-      {
-        type file
-        file-name "trust-anchor-1.cert"
-      }
-      )_TEXT_";
-  boost::logic::tribool validationResult;
-  Name userCertName;
-  shared_ptr<v1::IdentityCertificate> userCert;
-};
-
-BOOST_FIXTURE_TEST_SUITE(DirectCertFetch, DirectCertFetchFixture)
-
-BOOST_AUTO_TEST_CASE(CertFetchSuccess)
-{
-  runTest([this] (const Interest& directInterest, const Interest& infrastructureInterest) {
-      this->clientFace.receive(*userCert);
-    });
-
-  BOOST_CHECK_EQUAL(validationResult, true);
-}
-
-BOOST_AUTO_TEST_CASE(CertFetchTimeout)
-{
-  // In this test case, certificate request would time out
-  runTest([this] (const Interest& directInterest, const Interest& infrastructureInterest) { });
-
-  BOOST_CHECK_EQUAL(validationResult, false);
-}
-
-BOOST_AUTO_TEST_CASE(CertFetchNack)
-{
-  runTest([this] (const Interest& directInterest, const Interest& infrastructureInterest) {
-      lp::Nack nackInfrastructureInterest(infrastructureInterest);
-      nackInfrastructureInterest.setHeader(lp::NackHeader().setReason(lp::NackReason::NO_ROUTE));
-      this->clientFace.receive(nackInfrastructureInterest);
-    });
-
-  BOOST_CHECK_EQUAL(validationResult, false);
-}
+BOOST_AUTO_TEST_SUITE_END() // Loads
 
-BOOST_AUTO_TEST_SUITE_END() // DirectCertFetch
 BOOST_AUTO_TEST_SUITE_END() // TestValidatorConfig
 BOOST_AUTO_TEST_SUITE_END() // Security
 
diff --git a/tests/unit-tests/util/placeholders.t.cpp b/tests/unit-tests/util/placeholders.t.cpp
index 032b088..64c1dbf 100644
--- a/tests/unit-tests/util/placeholders.t.cpp
+++ b/tests/unit-tests/util/placeholders.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2015 Regents of the University of California.
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -24,9 +24,9 @@
 // interest.hpp includes common.hpp; common.hpp shouldn't be used from external program
 #include "interest.hpp"
 
-// validator-config.hpp indirectly includes <boost/property_tree/ptree.hpp>
+// util/config-file.hpp indirectly includes <boost/property_tree/ptree.hpp>
 // which in turn imports Boost placeholders
-#include "security/validator-config.hpp"
+#include "util/config-file.hpp"
 
 // It's intentional to write "using namespace",
 // to simulate an external program linked against ndn-cxx.