mgmt: add certificate generation/export instructions to nfd.conf.sample.in and README.md

rename configuration file's "keyfile" field to "certfile" to reflect usage of
  an NDN certificate
nfd.conf certfile paths are now interpreted as relative to nfd.conf's location

refs: #1332

Change-Id: Ib91cffd3d113ef084bf19e87a85172ddfd16b7eb
diff --git a/README.md b/README.md
index 2678ed0..de446f2 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,89 @@
 NFD - Named Data Networking Forwarding Daemon
-=============================================
+==============================================================
 
+## Default Paths
 
+This README uses `SYSCONFDIR` when referring to the default locations of
+various NFD configuration files.  By default, `SYSCONFDIR` is set to
+`/usr/local/etc`.  If you override `PREFIX`, then `SYSCONFDIR` will
+default to `PREFIX/etc`.
+
+You may override `SYSCONFDIR` and `PREFIX` by specifying their
+corresponding options during installation:
+
+    ./waf install --prefix <path/for/prefix> --sysconfdir <some/other/path>
+
+## Running and Configuring NFD
+
+NFD's runtime settings may be modified via configuration file.  After
+installation, a working sample configuration is provided at
+`SYSCONFDIR/ndn/nfd.conf.sample`.  At startup, NFD will attempt to
+read the default configuration file location:
+`SYSCONFDIR/ndn/nfd.conf`.
+
+You may also specify an alternative configuration file location
+by running NFD with:
+
+    nfd --config </path/to/nfd.conf>
+
+Once again, note that you may simply copy or rename the provided
+sample configuration and have an **almost** fully configured NFD.
+However, this NFD will be unable to add FIB entries or perform
+other typical operation tasks until you authorize an NDN certificate
+with the appropriate privileges.
+
+## Installing an NDN Certificate for Command Authentication
+
+Many NFD management protocols require signed commands to be processed
+(e.g. FIB modification, Face creation/destructions, etc.). You will
+need an NDN certificate to use any application that issues signed
+commands.
+
+If you do not already have NDN certificate, you can generate one with
+the following commands:
+
+**Generate and install a self-signed identity certificate**:
+
+    ndnsec-keygen /`whoami` | ndnsec-install-cert -
+
+Note that the argument to ndnsec-key will be the identity name of the
+new key (in this case, `/your-username`). Identity names are
+hierarchical NDN names and may have multiple components
+(e.g. `/ndn/ucla/edu/alice`).  You may create additional keys and
+identities as you see fit.
+
+**Dump the NDN certificate to a file**:
+
+The following commands assume that you have not modified
+`PREFIX` or `SYSCONFDIR` If you have, please substitute
+`/usr/local/etc` for the appropriate value (the overriden
+`SYSCONFDIR` or `PREFIX/etc` if you changed `PREFIX`).
+
+    sudo mkdir -p /usr/local/etc/ndn/keys
+    ndnsec-cert-dump -i /`whoami` > default.ndncert
+    sudo mv default.ndncert /usr/local/etc/ndn/keys/default.ndncert
+
+## Running NFD with Ethernet Face Support
+
+The ether configuration file section contains settings for Ethernet
+faces and channels.  These settings will **NOT** work without root or
+setting the appropriate permissions:
+
+    sudo setcap cap_net_raw,cap_net_admin=eip /full/path/nfd
+
+You may need to install a package to use setcap:
+
+**Ubuntu:**
+
+    sudo apt-get install libcap2-bin
+
+**Mac OS X:**
+
+    curl https://bugs.wireshark.org/bugzilla/attachment.cgi?id=3373 -o ChmodBPF.tar.gz
+    tar zxvf ChmodBPF.tar.gz
+    open ChmodBPF/Install\ ChmodBPF.app
+
+or manually:
+
+    sudo chgrp admin /dev/bpf*
+    sudo chmod g+rw /dev/bpf*
diff --git a/daemon/mgmt/command-validator.cpp b/daemon/mgmt/command-validator.cpp
index 9028ba2..fd8a124 100644
--- a/daemon/mgmt/command-validator.cpp
+++ b/daemon/mgmt/command-validator.cpp
@@ -8,6 +8,8 @@
 #include <ndn-cpp-dev/util/io.hpp>
 #include <ndn-cpp-dev/security/identity-certificate.hpp>
 
+#include <boost/filesystem.hpp>
+
 namespace nfd {
 
 NFD_LOG_INIT("CommandValidator");
@@ -26,7 +28,7 @@
 CommandValidator::setConfigFile(ConfigFile& configFile)
 {
   configFile.addSectionHandler("authorizations",
-                               bind(&CommandValidator::onConfig, this, _1, _2));
+                               bind(&CommandValidator::onConfig, this, _1, _2, _3));
 }
 
 static inline void
@@ -41,8 +43,11 @@
 
 void
 CommandValidator::onConfig(const ConfigSection& section,
-                           bool isDryRun)
+                           bool isDryRun,
+                           const std::string& filename)
 {
+  using namespace boost::filesystem;
+
   const ConfigSection EMPTY_SECTION;
 
   if (section.begin() == section.end())
@@ -54,14 +59,14 @@
   ConfigSection::const_iterator authIt;
   for (authIt = section.begin(); authIt != section.end(); authIt++)
     {
-      std::string keyfile;
+      std::string certfile;
       try
         {
-          keyfile = authIt->second.get<std::string>("keyfile");
+          certfile = authIt->second.get<std::string>("certfile");
         }
       catch (const std::runtime_error& e)
         {
-          std::string msg = "No keyfile specified";
+          std::string msg = "No certfile specified";
           if (!isDryRun)
             {
               throw ConfigFile::Error(msg);
@@ -70,11 +75,14 @@
           continue;
         }
 
+      path certfilePath = absolute(certfile, path(filename).parent_path());
+      NFD_LOG_DEBUG("generated certfile path: " << certfilePath.native());
+
       std::ifstream in;
-      in.open(keyfile.c_str());
+      in.open(certfilePath.c_str());
       if (!in.is_open())
         {
-          std::string msg = "Unable to open key file " + keyfile;
+          std::string msg = "Unable to open certificate file " + certfilePath.native();
           if (!isDryRun)
             {
               throw ConfigFile::Error(msg);
@@ -90,7 +98,7 @@
         }
       catch(const std::runtime_error& error)
         {
-          std::string msg = "Malformed key file " + keyfile;
+          std::string msg = "Malformed certificate file " + certfilePath.native();
           if (!isDryRun)
             {
               throw ConfigFile::Error(msg);
@@ -109,8 +117,8 @@
         }
       catch (const std::runtime_error& error)
         {
-          std::string msg = "No privileges section found for key file " +
-            keyfile + " (" + id->getPublicKeyName().toUri() + ")";
+          std::string msg = "No privileges section found for certificate file " +
+            certfile + " (" + id->getPublicKeyName().toUri() + ")";
           if (!isDryRun)
             {
               throw ConfigFile::Error(msg);
@@ -121,7 +129,8 @@
 
       if (privileges->begin() == privileges->end())
         {
-          NFD_LOG_WARN("No privileges specified for key file " << keyfile + " (" << id->getPublicKeyName().toUri() << ")");
+          NFD_LOG_WARN("No privileges specified for certificate file " << certfile
+                       << " (" << id->getPublicKeyName().toUri() << ")");
         }
 
       ConfigSection::const_iterator privIt;
@@ -131,7 +140,7 @@
           if (m_supportedPrivileges.find(privilegeName) != m_supportedPrivileges.end())
             {
               NFD_LOG_INFO("Giving privilege \"" << privilegeName
-                           << "\" to key " << id->getPublicKeyName());
+                           << "\" to identity " << id->getPublicKeyName());
               if (!isDryRun)
                 {
                   const std::string regex = "^<localhost><nfd><" + privilegeName + ">";
@@ -141,8 +150,8 @@
           else
             {
               // Invalid configuration
-              std::string msg = "Invalid privilege \"" + privilegeName + "\" for key file " +
-                keyfile + " (" + id->getPublicKeyName().toUri() + ")";
+              std::string msg = "Invalid privilege \"" + privilegeName + "\" for certificate file " +
+                certfile + " (" + id->getPublicKeyName().toUri() + ")";
               if (!isDryRun)
                 {
                   throw ConfigFile::Error(msg);
@@ -163,7 +172,7 @@
 {
   if (m_supportedPrivileges.find(privilege) != m_supportedPrivileges.end())
     {
-      throw CommandValidator::Error("Duplicated privivilege: " + privilege);
+      throw CommandValidator::Error("Duplicated privilege: " + privilege);
     }
   m_supportedPrivileges.insert(privilege);
 }
diff --git a/daemon/mgmt/command-validator.hpp b/daemon/mgmt/command-validator.hpp
index 466bb70..97c7c18 100644
--- a/daemon/mgmt/command-validator.hpp
+++ b/daemon/mgmt/command-validator.hpp
@@ -39,7 +39,7 @@
    * \throws ConfigFile::Error on parse error
    */
   void
-  onConfig(const ConfigSection& section, bool isDryRun);
+  onConfig(const ConfigSection& section, bool isDryRun, const std::string& filename);
 
   /**
    * \param privilege name of privilege to add
diff --git a/daemon/mgmt/config-file.cpp b/daemon/mgmt/config-file.cpp
index e5bbb9d..d0eddd5 100644
--- a/daemon/mgmt/config-file.cpp
+++ b/daemon/mgmt/config-file.cpp
@@ -20,7 +20,7 @@
 
 void
 ConfigFile::addSectionHandler(const std::string& sectionName,
-                              OnConfig subscriber)
+                              ConfigSectionHandler subscriber)
 {
   m_subscriptions[sectionName] = subscriber;
 }
@@ -90,8 +90,8 @@
       SubscriptionTable::iterator subscriberIt = m_subscriptions.find(sectionName);
       if (subscriberIt != m_subscriptions.end())
         {
-          OnConfig subscriber = subscriberIt->second;
-          subscriber(section, isDryRun);
+          ConfigSectionHandler subscriber = subscriberIt->second;
+          subscriber(section, isDryRun, filename);
         }
       else
         {
diff --git a/daemon/mgmt/config-file.hpp b/daemon/mgmt/config-file.hpp
index 2a94fac..15eca05 100644
--- a/daemon/mgmt/config-file.hpp
+++ b/daemon/mgmt/config-file.hpp
@@ -16,9 +16,9 @@
 typedef boost::property_tree::ptree ConfigSection;
 
 /// \brief callback for config file sections
-typedef function<void(const ConfigSection&, bool)> OnConfig;
+typedef function<void(const ConfigSection&, bool, const std::string&)> ConfigSectionHandler;
 
-class ConfigFile
+class ConfigFile : noncopyable
 {
 public:
 
@@ -37,7 +37,7 @@
   /// \brief setup notification of configuration file sections
   void
   addSectionHandler(const std::string& sectionName,
-                    OnConfig subscriber);
+                    ConfigSectionHandler subscriber);
 
 
   /**
@@ -75,7 +75,7 @@
 
 private:
 
-  typedef std::map<std::string, OnConfig> SubscriptionTable;
+  typedef std::map<std::string, ConfigSectionHandler> SubscriptionTable;
 
   SubscriptionTable m_subscriptions;
 
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 6407237..237a914 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -87,12 +87,14 @@
 FaceManager::setConfigFile(ConfigFile& configFile)
 {
   configFile.addSectionHandler("face_system",
-                               bind(&FaceManager::onConfig, this, _1, _2));
+                               bind(&FaceManager::onConfig, this, _1, _2, _3));
 }
 
 
 void
-FaceManager::onConfig(const ConfigSection& configSection, bool isDryRun)
+FaceManager::onConfig(const ConfigSection& configSection,
+                      bool isDryRun,
+                      const std::string& filename)
 {
   bool hasSeenUnix = false;
   bool hasSeenTcp = false;
diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp
index 4139152..8efb509 100644
--- a/daemon/mgmt/face-manager.hpp
+++ b/daemon/mgmt/face-manager.hpp
@@ -83,7 +83,7 @@
 
 private:
   void
-  onConfig(const ConfigSection& configSection, bool isDryRun);
+  onConfig(const ConfigSection& configSection, bool isDryRun, const std::string& filename);
 
   void
   processSectionUnix(const ConfigSection& configSection, bool isDryRun);
diff --git a/daemon/mgmt/fib-manager.cpp b/daemon/mgmt/fib-manager.cpp
index 4e1dbe7..0ffe333 100644
--- a/daemon/mgmt/fib-manager.cpp
+++ b/daemon/mgmt/fib-manager.cpp
@@ -214,10 +214,4 @@
     }
 }
 
-// void
-// FibManager::onConfig(ConfigFile::Node section, bool isDryRun)
-// {
-
-// }
-
 } // namespace nfd
diff --git a/nfd.conf.sample.in b/nfd.conf.sample.in
index c7710a1..c915202 100644
--- a/nfd.conf.sample.in
+++ b/nfd.conf.sample.in
@@ -1,26 +1,26 @@
-; the general section contains settings of nfd process
+; The general section contains settings of nfd process.
 ; general
 ; {
 ; }
 
-; the face_system section defines what faces and channels are created
+; The face_system section defines what faces and channels are created.
 face_system
 {
-  ; the unix section contains settings of UNIX stream faces and channels
+  ; The unix section contains settings of UNIX stream faces and channels.
   unix
   {
     listen yes ; set to 'no' to disable UNIX stream listener, default 'yes'
     path /var/run/nfd.sock ; UNIX stream listener path
   }
 
-  ; the tcp section contains settings of TCP faces and channels
+  ; The tcp section contains settings of TCP faces and channels.
   tcp
   {
     listen yes ; set to 'no' to disable TCP listener, default 'yes'
     port 6363 ; TCP listener port number
   }
 
-  ; the udp section contains settings of UDP faces and channels
+  ; The udp section contains settings of UDP faces and channels.
   udp
   {
     port 6363 ; UDP unicast port number
@@ -31,36 +31,95 @@
 
     ; Example multicast settings
     ; NFD creates one UDP multicast face per NIC
+
     ; mcast yes ; set to 'no' to disable UDP multicast, default 'yes'
     ; mcast_port 56363 ; UDP multicast port number
     ; mcast_group 224.0.23.170 ; UDP multicast group (IPv4 only)
   }
 
-  ; the ether section contains settings of Ethernet faces and channels
+  ; The ether section contains settings of Ethernet faces and channels.
+  ; These settings will NOT work without root or setting the appropriate
+  ; permissions:
+  ;
+  ;    sudo setcap cap_net_raw,cap_net_admin=eip /full/path/nfd
+  ;
+  ; You may need to install a package to use setcap:
+  ;
+  ; **Ubuntu:**
+  ;
+  ;    sudo apt-get install libcap2-bin
+  ;
+  ; **Mac OS X:**
+  ;
+  ;    curl https://bugs.wireshark.org/bugzilla/attachment.cgi?id=3373 -o ChmodBPF.tar.gz
+  ;    tar zxvf ChmodBPF.tar.gz
+  ;    open ChmodBPF/Install\ ChmodBPF.app
+  ;
+  ; or manually:
+  ;
+  ;    sudo chgrp admin /dev/bpf*
+  ;    sudo chmod g+rw /dev/bpf*
+
   ether
   {
     mcast no
-    ; Example multicast settings
-    ; NFD creates one Ethernet multicast face per NIC
-    ; mcast yes ; set to 'no' to disable Ethernet multicast, default 'yes'
-    ; mcast_group 01:00:5E:00:17:AA ; Ethernet multicast group
+
+  ;    Example multicast settings
+  ;    NFD creates one Ethernet multicast face per NIC
+  ;
+  ;    mcast yes ; set to 'no' to disable Ethernet multicast, default 'yes'
+  ;    mcast_group 01:00:5E:00:17:AA ; Ethernet multicast group
   }
 }
 
-; the authorizations section grants privileges to authorized keys
+; The authorizations section grants privileges to authorized keys.
 authorizations
 {
-  ; an authorize section grants privileges to a key
+  ; An authorize section grants privileges to a NDN certificate.
   authorize
   {
-    keyfile @SYSCONFDIR@/ndn/keys/default.pub ; public key file
-    privileges ; set of privileges granted to this public key
+    ; If you do not already have NDN certificate, you can generate
+    ; one with the following commands.
+    ;
+    ; 1. Generate and install a self-signed identity certificate:
+    ;
+    ;      ndnsec-keygen /`whoami` | ndnsec-install-cert -
+    ;
+    ; Note that the argument to ndnsec-key will be the identity name of the
+    ; new key (in this case, /your-username). Identities are hierarchical NDN
+    ; names and may have multiple components (e.g. `/ndn/ucla/edu/alice`).
+    ; You may create additional keys and identities as you see fit.
+    ;
+    ; 2. Dump the NDN certificate to a file:
+    ;
+    ;      sudo mkdir -p @SYSCONFDIR@/ndn/keys/
+    ;      ndnsec-cert-dump -i /`whoami` >  default.ndncert
+    ;      sudo mv default.ndncert @SYSCONFDIR@/ndn/keys/default.ndncert
+    ;
+    ; The "certfile" field below specifies the default key directory for
+    ; your machine. You may move your newly created key to the location it
+    ; specifies or path.
+
+    certfile keys/default.ndncert ; NDN identity certificate file
+    privileges ; set of privileges granted to this identity
     {
       control-header
       faces
       fib
-      ; stats
       strategy-choice
     }
   }
+
+  ; You may have multiple authorize sections that specify additional
+  ; certificates and their privileges.
+
+;  authorize
+;  {
+;    certfile keys/this_cert_does_not_exist.ndncert
+;    authorize
+;    privileges
+;    {
+;      faces
+;    }
+;  }
 }
diff --git a/tests/mgmt/command-validator.cpp b/tests/mgmt/command-validator.cpp
index 4e53322..3dcae24 100644
--- a/tests/mgmt/command-validator.cpp
+++ b/tests/mgmt/command-validator.cpp
@@ -24,11 +24,10 @@
 
 // authorizations
 // {
-//   ; an authorize section grants privileges to a key
 //   authorize
 //   {
-//     keyfile "tests/mgmt/key1.pub" ; public key file
-//     privileges ; set of privileges granted to this public key
+//     certfile "tests/mgmt/cert1.ndncert"
+//     privileges
 //     {
 //       fib
 //       stats
@@ -37,8 +36,8 @@
 
 //   authorize
 //   {
-//     keyfile "tests/mgmt/key2.pub" ; public key file
-//     privileges ; set of privileges granted to this public key
+//     certfile "tests/mgmt/cert2.ndncert"
+//     privileges
 //     {
 //       faces
 //     }
@@ -50,7 +49,7 @@
 "{\n"
 "  authorize\n"
 "  {\n"
-"    keyfile \"tests/mgmt/key1.pub\"\n"
+"    certfile \"tests/mgmt/cert1.ndncert\"\n"
 "    privileges\n"
 "    {\n"
 "      fib\n"
@@ -59,7 +58,7 @@
 "  }\n"
 "  authorize\n"
 "  {\n"
-"    keyfile \"tests/mgmt/key2.pub\"\n"
+"    certfile \"tests/mgmt/cert2.ndncert\"\n"
 "    privileges\n"
 "    {\n"
 "      faces\n"
@@ -67,6 +66,9 @@
 "  }\n"
   "}\n";
 
+const boost::filesystem::path CONFIG_PATH =
+  boost::filesystem::current_path() /= std::string("unit-test-nfd.conf");
+
 class CommandValidatorTester
 {
 public:
@@ -170,17 +172,17 @@
   TwoValidatorFixture()
   {
     m_tester1.generateIdentity("/test/CommandValidator/TwoKeys/id1");
-    m_tester1.saveIdentityToFile("tests/mgmt/key1.pub");
+    m_tester1.saveIdentityToFile("tests/mgmt/cert1.ndncert");
 
     m_tester2.generateIdentity("/test/CommandValidator/TwoKeys/id2");
-    m_tester2.saveIdentityToFile("tests/mgmt/key2.pub");
+    m_tester2.saveIdentityToFile("tests/mgmt/cert2.ndncert");
   }
 
   ~TwoValidatorFixture()
   {
     boost::system::error_code error;
-    boost::filesystem::remove("tests/mgmt/key1.pub", error);
-    boost::filesystem::remove("tests/mgmt/key2.pub", error);
+    boost::filesystem::remove("tests/mgmt/cert1.ndncert", error);
+    boost::filesystem::remove("tests/mgmt/cert2.ndncert", error);
   }
 
 protected:
@@ -205,9 +207,9 @@
   validator.addSupportedPrivilege("fib");
   validator.addSupportedPrivilege("stats");
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
-  config.parse(CONFIG, false, "dummy-config");
+  validator.setConfigFile(config);
+
+  config.parse(CONFIG, false, CONFIG_PATH.native());
 
   validator.validate(*fibCommand,
                      bind(&CommandValidatorTester::onValidated, boost::ref(m_tester1), _1),
@@ -229,7 +231,7 @@
   BOOST_REQUIRE(m_tester2.commandValidated());
   m_tester2.resetValidation();
 
-  // use key2 for fib command (authorized for key1 only)
+  // use cert2 for fib command (authorized for cert1 only)
   shared_ptr<Interest> unauthorizedFibCommand = make_shared<Interest>("/localhost/nfd/fib/insert");
   generator.generateWithIdentity(*unauthorizedFibCommand, m_tester2.getIdentityName());
 
@@ -244,11 +246,11 @@
 {
   CommandValidatorTester tester1;
   tester1.generateIdentity("/test/CommandValidator/TwoKeys/id1");
-  tester1.saveIdentityToFile("tests/mgmt/key1.pub");
+  tester1.saveIdentityToFile("tests/mgmt/cert1.ndncert");
 
   CommandValidatorTester tester2;
   tester2.generateIdentity("/test/CommandValidator/TwoKeys/id2");
-  tester2.saveIdentityToFile("tests/mgmt/key2.pub");
+  tester2.saveIdentityToFile("tests/mgmt/cert2.ndncert");
 
   shared_ptr<Interest> fibCommand = make_shared<Interest>("/localhost/nfd/fib/insert");
   shared_ptr<Interest> statsCommand = make_shared<Interest>("/localhost/nfd/stats/dosomething");
@@ -265,9 +267,9 @@
   validator.addSupportedPrivilege("fib");
   validator.addSupportedPrivilege("stats");
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
-  config.parse(CONFIG, true, "dummy-config");
+  validator.setConfigFile(config);
+
+  config.parse(CONFIG, true, CONFIG_PATH.native());
 
   validator.validate(*fibCommand,
                      bind(&CommandValidatorTester::onValidated, boost::ref(m_tester1), _1),
@@ -289,7 +291,7 @@
   BOOST_REQUIRE(m_tester2.commandValidationFailed());
   m_tester2.resetValidation();
 
-  // use key2 for fib command (authorized for key1 only)
+  // use cert2 for fib command (authorized for cert1 only)
   shared_ptr<Interest> unauthorizedFibCommand = make_shared<Interest>("/localhost/nfd/fib/insert");
   generator.generateWithIdentity(*unauthorizedFibCommand, m_tester2.getIdentityName());
 
@@ -310,9 +312,8 @@
   ConfigFile config;
   CommandValidator validator;
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
-  BOOST_CHECK_THROW(config.parse(NO_AUTHORIZE_CONFIG, false, "dummy-config"), ConfigFile::Error);
+  validator.setConfigFile(config);
+  BOOST_CHECK_THROW(config.parse(NO_AUTHORIZE_CONFIG, false, CONFIG_PATH.native()), ConfigFile::Error);
 }
 
 BOOST_AUTO_TEST_CASE(NoPrivilegesSections)
@@ -322,26 +323,26 @@
     "{\n"
     "  authorize\n"
     "  {\n"
-    "    keyfile \"tests/mgmt/key1.pub\"\n"
+    "    certfile \"tests/mgmt/cert1.ndncert\"\n"
     "  }\n"
     "}\n";
 
   ConfigFile config;
   CommandValidator validator;
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
-  BOOST_CHECK_THROW(config.parse(NO_PRIVILEGES_CONFIG, false, "dummy-config"), ConfigFile::Error);
+  validator.setConfigFile(config);
+
+  BOOST_CHECK_THROW(config.parse(NO_PRIVILEGES_CONFIG, false, CONFIG_PATH.native()), ConfigFile::Error);
 }
 
-BOOST_AUTO_TEST_CASE(InvalidKeyFile)
+BOOST_AUTO_TEST_CASE(InvalidCertfile)
 {
-  const std::string INVALID_KEY_CONFIG =
+  const std::string INVALID_CERT_CONFIG =
     "authorizations\n"
     "{\n"
     "  authorize\n"
     "  {\n"
-    "    keyfile \"tests/mgmt/notakeyfile.pub\"\n"
+    "    certfile \"tests/mgmt/notacertfile.ndncert\"\n"
     "    privileges\n"
     "    {\n"
     "      fib\n"
@@ -353,14 +354,13 @@
   ConfigFile config;
   CommandValidator validator;
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
-  BOOST_CHECK_THROW(config.parse(INVALID_KEY_CONFIG, false, "dummy-config"), ConfigFile::Error);
+  validator.setConfigFile(config);
+  BOOST_CHECK_THROW(config.parse(INVALID_CERT_CONFIG, false, CONFIG_PATH.native()), ConfigFile::Error);
 }
 
-BOOST_AUTO_TEST_CASE(NoKeyFile)
+BOOST_AUTO_TEST_CASE(NoCertfile)
 {
-  const std::string NO_KEY_CONFIG =
+  const std::string NO_CERT_CONFIG =
     "authorizations\n"
     "{\n"
     "  authorize\n"
@@ -377,19 +377,18 @@
   ConfigFile config;
   CommandValidator validator;
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
-  BOOST_CHECK_THROW(config.parse(NO_KEY_CONFIG, false, "dummy-config"), ConfigFile::Error);
+  validator.setConfigFile(config);
+  BOOST_CHECK_THROW(config.parse(NO_CERT_CONFIG, false, CONFIG_PATH.native()), ConfigFile::Error);
 }
 
-BOOST_AUTO_TEST_CASE(MalformedKey)
+BOOST_AUTO_TEST_CASE(MalformedCert)
 {
-    const std::string MALFORMED_KEY_CONFIG =
+    const std::string MALFORMED_CERT_CONFIG =
     "authorizations\n"
     "{\n"
     "  authorize\n"
     "  {\n"
-    "    keyfile \"tests/mgmt/malformedkey.pub\"\n"
+    "    certfile \"tests/mgmt/malformed.ndncert\"\n"
     "    privileges\n"
     "    {\n"
     "      fib\n"
@@ -402,9 +401,8 @@
   ConfigFile config;
   CommandValidator validator;
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
-  BOOST_CHECK_THROW(config.parse(MALFORMED_KEY_CONFIG, false, "dummy-config"), ConfigFile::Error);
+  validator.setConfigFile(config);
+  BOOST_CHECK_THROW(config.parse(MALFORMED_CERT_CONFIG, false, CONFIG_PATH.native()), ConfigFile::Error);
 }
 
 bool
@@ -429,9 +427,8 @@
   ConfigFile config;
   CommandValidator validator;
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
-  BOOST_CHECK_EXCEPTION(config.parse(NO_AUTHORIZE_CONFIG, true, "dummy-config"),
+  validator.setConfigFile(config);
+  BOOST_CHECK_EXCEPTION(config.parse(NO_AUTHORIZE_CONFIG, true, CONFIG_PATH.native()),
                         ConfigFile::Error,
                         bind(&validateErrorMessage,
                              "No authorize sections found", _1));
@@ -444,47 +441,40 @@
     "{\n"
     "  authorize\n"
     "  {\n"
-    "    keyfile \"tests/mgmt/key1.pub\"\n"
+    "    certfile \"tests/mgmt/cert1.ndncert\"\n"
     "  }\n"
     "  authorize\n"
     "  {\n"
-    "    keyfile \"tests/mgmt/key2.pub\"\n"
+    "    certfile \"tests/mgmt/cert2.ndncert\"\n"
     "  }\n"
     "}\n";
 
-  // CommandValidatorTester tester1;
-  // tester1.generateIdentity("/tests/CommandValidator/TwoKeys/id1");
-  // tester1.saveIdentityToFile("tests/mgmt/key1.pub");
-
-  // CommandValidatorTester tester2;
-  // tester2.generateIdentity("/tests/CommandValidator/TwoKeys/id2");
-  // tester2.saveIdentityToFile("tests/mgmt/key2.pub");
-
   ConfigFile config;
   CommandValidator validator;
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
+  validator.setConfigFile(config);
 
   std::stringstream expectedError;
-  expectedError << "No privileges section found for key file tests/mgmt/key1.pub "
+  expectedError << "No privileges section found for certificate file tests/mgmt/cert1.ndncert "
                 << "(" << m_tester1.getPublicKeyName().toUri() << ")\n"
-                << "No privileges section found for key file tests/mgmt/key2.pub "
+                << "No privileges section found for certificate file tests/mgmt/cert2.ndncert "
                 << "(" << m_tester2.getPublicKeyName().toUri() << ")";
 
-  BOOST_CHECK_EXCEPTION(config.parse(NO_PRIVILEGES_CONFIG, true, "dummy-config"),
+  BOOST_CHECK_EXCEPTION(config.parse(NO_PRIVILEGES_CONFIG, true, CONFIG_PATH.native()),
                         ConfigFile::Error,
                         bind(&validateErrorMessage, expectedError.str(), _1));
 }
 
-BOOST_AUTO_TEST_CASE(InvalidKeyFileDryRun)
+BOOST_AUTO_TEST_CASE(InvalidCertfileDryRun)
 {
+  using namespace boost::filesystem;
+
   const std::string INVALID_KEY_CONFIG =
     "authorizations\n"
     "{\n"
     "  authorize\n"
     "  {\n"
-    "    keyfile \"tests/mgmt/notakeyfile.pub\"\n"
+    "    certfile \"tests/mgmt/notacertfile.ndncert\"\n"
     "    privileges\n"
     "    {\n"
     "      fib\n"
@@ -493,7 +483,7 @@
     "  }\n"
     "  authorize\n"
     "  {\n"
-    "    keyfile \"tests/mgmt/stillnotakeyfile.pub\"\n"
+    "    certfile \"tests/mgmt/stillnotacertfile.ndncert\"\n"
     "    privileges\n"
     "    {\n"
     "    }\n"
@@ -503,19 +493,22 @@
   ConfigFile config;
   CommandValidator validator;
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
+  validator.setConfigFile(config);
 
-  BOOST_CHECK_EXCEPTION(config.parse(INVALID_KEY_CONFIG, true, "dummy-config"),
+  std::stringstream error;
+  error << "Unable to open certificate file "
+        << absolute("tests/mgmt/notacertfile.ndncert").native() << "\n"
+        << "Unable to open certificate file "
+        << absolute("tests/mgmt/stillnotacertfile.ndncert").native();
+
+  BOOST_CHECK_EXCEPTION(config.parse(INVALID_KEY_CONFIG, true, CONFIG_PATH.native()),
                         ConfigFile::Error,
-                        bind(&validateErrorMessage,
-                             "Unable to open key file tests/mgmt/notakeyfile.pub\n"
-                             "Unable to open key file tests/mgmt/stillnotakeyfile.pub", _1));
+                        bind(&validateErrorMessage, error.str(), _1));
 }
 
-BOOST_AUTO_TEST_CASE(NoKeyFileDryRun)
+BOOST_AUTO_TEST_CASE(NoCertfileDryRun)
 {
-  const std::string NO_KEY_CONFIG =
+  const std::string NO_CERT_CONFIG =
     "authorizations\n"
     "{\n"
     "  authorize\n"
@@ -535,23 +528,24 @@
   ConfigFile config;
   CommandValidator validator;
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
-  BOOST_CHECK_EXCEPTION(config.parse(NO_KEY_CONFIG, true, "dummy-config"),
+  validator.setConfigFile(config);
+  BOOST_CHECK_EXCEPTION(config.parse(NO_CERT_CONFIG, true, CONFIG_PATH.native()),
                         ConfigFile::Error,
                         bind(&validateErrorMessage,
-                             "No keyfile specified\n"
-                             "No keyfile specified", _1));
+                             "No certfile specified\n"
+                             "No certfile specified", _1));
 }
 
-BOOST_AUTO_TEST_CASE(MalformedKeyDryRun)
+BOOST_AUTO_TEST_CASE(MalformedCertDryRun)
 {
-    const std::string MALFORMED_KEY_CONFIG =
+  using namespace boost::filesystem;
+
+  const std::string MALFORMED_CERT_CONFIG =
     "authorizations\n"
     "{\n"
     "  authorize\n"
     "  {\n"
-    "    keyfile \"tests/mgmt/malformedkey.pub\"\n"
+    "    certfile \"tests/mgmt/malformed.ndncert\"\n"
     "    privileges\n"
     "    {\n"
     "      fib\n"
@@ -560,7 +554,7 @@
     "  }\n"
     "  authorize\n"
     "  {\n"
-    "    keyfile \"tests/mgmt/malformedkey.pub\"\n"
+    "    certfile \"tests/mgmt/malformed.ndncert\"\n"
     "  }\n"
     "}\n";
 
@@ -568,13 +562,17 @@
   ConfigFile config;
   CommandValidator validator;
 
-  config.addSectionHandler("authorizations",
-                           bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2));
-  BOOST_CHECK_EXCEPTION(config.parse(MALFORMED_KEY_CONFIG, true, "dummy-config"),
+  validator.setConfigFile(config);
+
+  std::stringstream error;
+  error << "Malformed certificate file "
+        << absolute("tests/mgmt/malformed.ndncert").native() << "\n"
+        << "Malformed certificate file "
+        << absolute("tests/mgmt/malformed.ndncert").native();
+
+  BOOST_CHECK_EXCEPTION(config.parse(MALFORMED_CERT_CONFIG, true, CONFIG_PATH.native()),
                         ConfigFile::Error,
-                        bind(&validateErrorMessage,
-                             "Malformed key file tests/mgmt/malformedkey.pub\n"
-                             "Malformed key file tests/mgmt/malformedkey.pub", _1));
+                        bind(&validateErrorMessage, error.str(), _1));
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/mgmt/malformedkey.pub b/tests/mgmt/malformed.ndncert
similarity index 100%
rename from tests/mgmt/malformedkey.pub
rename to tests/mgmt/malformed.ndncert