mgmt: management tools

refs #2034

Change-Id: I43ff11e0aa7e67f6207e75f139b7417779590efc
diff --git a/AUTHORS.md b/AUTHORS.md
index d1af3b8..02ce1d8 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -5,7 +5,7 @@
 
 * Xiaoke Jiang          <http://netarchlab.tsinghua.edu.cn/~shock/>
 * Alexander Afanasyev   <http://lasr.cs.ucla.edu/afanasyev/index.html>
-
+* Jiewen Tan            <alanwake@ucla.edu>
 
 ## All project authors and contributors
 
diff --git a/src/daemon/db-mgr.cpp b/src/daemon/db-mgr.cpp
index 35af5de..53d3822 100644
--- a/src/daemon/db-mgr.cpp
+++ b/src/daemon/db-mgr.cpp
@@ -174,6 +174,31 @@
   return zone.getId() != 0;
 }
 
+std::vector<Zone>
+DbMgr::listZones()
+{
+  sqlite3_stmt* stmt;
+  const char* sql = "SELECT id, name, ttl FROM zones";
+  int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, 0);
+  if (rc != SQLITE_OK) {
+    throw PrepareError(sql);
+  }
+
+  std::vector<Zone> vec;
+
+  while (sqlite3_step(stmt) == SQLITE_ROW) {
+    vec.emplace_back();
+    Zone& zone = vec.back();
+    zone.setId(sqlite3_column_int64(stmt, 0));
+    zone.setTtl(time::seconds(sqlite3_column_int(stmt, 2)));
+    zone.setName(Name(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 1)),
+                            sqlite3_column_bytes(stmt, 1))));
+  }
+  sqlite3_finalize(stmt);
+
+  return vec;
+}
+
 void
 DbMgr::remove(Zone& zone)
 {
diff --git a/src/daemon/db-mgr.hpp b/src/daemon/db-mgr.hpp
index ca83691..336b330 100644
--- a/src/daemon/db-mgr.hpp
+++ b/src/daemon/db-mgr.hpp
@@ -113,6 +113,12 @@
   find(Zone& zone);
 
   /**
+   * @brief get all zones in the database
+   */
+  std::vector<Zone>
+  listZones();
+
+  /**
    * @brief remove the zone
    * @pre m_zone.getId() > 0
    * @post m_zone.getId() == 0
diff --git a/src/mgmt/management-tool.cpp b/src/mgmt/management-tool.cpp
new file mode 100644
index 0000000..619d1c0
--- /dev/null
+++ b/src/mgmt/management-tool.cpp
@@ -0,0 +1,642 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "management-tool.hpp"
+#include "logger.hpp"
+#include "ndns-label.hpp"
+#include "ndns-tlv.hpp"
+
+#include <string>
+#include <iomanip>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/algorithm/string/replace.hpp>
+
+#include <ndn-cxx/util/io.hpp>
+#include <ndn-cxx/util/regex.hpp>
+#include <ndn-cxx/encoding/oid.hpp>
+#include <ndn-cxx/security/cryptopp.hpp>
+
+namespace ndn {
+namespace ndns {
+
+NDNS_LOG_INIT("ManagementTool");
+
+ManagementTool::ManagementTool(const std::string& dbFile)
+  : m_dbMgr(dbFile)
+{
+}
+
+void
+ManagementTool::createZone(const Name &zoneName,
+                           const Name& parentZoneName,
+                           const time::seconds& cacheTtl,
+                           const time::seconds& certTtl,
+                           const Name& kskCertName,
+                           const Name& dskCertName)
+{
+  bool isRoot = zoneName == ROOT_ZONE;
+
+  //check preconditions
+  Zone zone(zoneName, cacheTtl);
+  if (m_dbMgr.find(zone)) {
+    throw Error(zoneName.toUri() + " is already presented in the NDNS db");
+  }
+
+  if (!isRoot && parentZoneName.equals(zoneName)) {
+    throw Error("Parent zone name can not be the zone itself");
+  }
+
+  if (!isRoot && !parentZoneName.isPrefixOf(zoneName)) {
+    throw Error(parentZoneName.toUri() + " is not a prefix of " + zoneName.toUri());
+  }
+
+  if (kskCertName != DEFAULT_CERT) {
+    if (!matchCertificate(kskCertName, zoneName)) {
+      throw Error("Cannot verify KSK certificate");
+    }
+  }
+
+  if (dskCertName != DEFAULT_CERT) {
+    if (!matchCertificate(dskCertName, zoneName)) {
+      throw Error("Cannot verify DSK certificate");
+    }
+  }
+
+  if (kskCertName == DEFAULT_CERT && isRoot) {
+    throw Error("Cannot generate KSK for root zone");
+  }
+
+  //first generate KSK and DSK to the keyChain system, and add DSK as default
+  NDNS_LOG_INFO("Start generating KSK and DSK and their corresponding certificates");
+  time::system_clock::TimePoint notBefore = time::system_clock::now();
+  time::system_clock::TimePoint notAfter = notBefore + certTtl;
+  shared_ptr<IdentityCertificate> kskCert;
+
+  if (kskCertName == DEFAULT_CERT) {
+    //create KSK's certificate
+    Name kskName = m_keyChain.generateRsaKeyPair(zoneName, true);
+    std::vector<CertificateSubjectDescription> kskDesc;
+    kskCert = m_keyChain.prepareUnsignedIdentityCertificate(kskName, zoneName, notBefore, notAfter,
+                                                            kskDesc);
+    //prepare the correct name for the ksk certificate
+    Name newScertName = parentZoneName;
+    newScertName.append(label::NDNS_CERT_QUERY);
+    newScertName.append(zoneName.getSubName(parentZoneName.size()));
+    //remove the zone prefix and KEY
+    newScertName.append(kskCert->getName().getSubName(zoneName.size()+1));
+    kskCert->setName(newScertName);
+
+    m_keyChain.selfSign(*kskCert);
+    m_keyChain.addCertificate(*kskCert);
+    NDNS_LOG_INFO("Generated KSK: " << kskCert->getName().toUri());
+  }
+  else {
+    kskCert = m_keyChain.getCertificate(kskCertName);
+  }
+
+  Name dskName;
+  shared_ptr<IdentityCertificate> dskCert;
+  if (dskCertName == DEFAULT_CERT) {
+    dskName = m_keyChain.generateRsaKeyPairAsDefault(zoneName, false);
+    //create DSK's certificate
+    std::vector<CertificateSubjectDescription> dskDesc;
+    dskCert = m_keyChain.prepareUnsignedIdentityCertificate(dskName, zoneName, notBefore, notAfter,
+                                                            dskDesc);
+    m_keyChain.sign(*dskCert, kskCert->getName());
+    m_keyChain.addCertificateAsKeyDefault(*dskCert);
+    NDNS_LOG_INFO("Generated DSK: " << dskCert->getName().toUri());
+  }
+  else {
+    dskCert = m_keyChain.getCertificate(dskCertName);
+    dskName = dskCert->getPublicKeyName();
+    m_keyChain.setDefaultKeyNameForIdentity(dskName);
+    m_keyChain.setDefaultCertificateNameForKey(dskCert->getName());
+  }
+
+  //second add zone to the database
+  NDNS_LOG_INFO("Start adding new zone to data base");
+  addZone(zone);
+
+  //third create ID-cert
+  NDNS_LOG_INFO("Start creating DSK's ID-CERT");
+  addIdCert(zone, dskCert, cacheTtl);
+}
+
+void
+ManagementTool::deleteZone(const Name& zoneName)
+{
+  //check pre-conditions
+  Zone zone(zoneName);
+  if (!m_dbMgr.find(zone)) {
+    throw Error(zoneName.toUri() + " is not presented in the NDNS db");
+  }
+
+  //first remove all rrsets of this zone from local ndns database
+  std::vector<Rrset> rrsets = m_dbMgr.findRrsets(zone);
+  for (Rrset& rrset : rrsets) {
+    m_dbMgr.remove(rrset);
+  }
+
+  //second remove zone from local ndns database
+  removeZone(zone);
+
+  //third remove identity
+  m_keyChain.deleteIdentity(zoneName);
+}
+
+void
+ManagementTool::exportCertificate(const Name& certName, const std::string& outFile)
+{
+  //search for the certificate, start from KeyChain then local NDNS database
+  shared_ptr<IdentityCertificate> cert;
+  if (m_keyChain.doesCertificateExist(certName)) {
+    cert = m_keyChain.getCertificate(certName);
+  }
+  else {
+    shared_ptr<Regex> regex = make_shared<Regex>("(<>*)<KEY>(<>+)<ID-CERT><>");
+    if (regex->match(certName) != true) {
+      throw Error("Certificate name is illegal");
+    }
+    Name zoneName = regex->expand("\\1");
+    Name label = regex->expand("\\2");
+
+    Zone zone(zoneName);
+    Rrset rrset(&zone);
+    rrset.setLabel(label);
+    rrset.setType(label::CERT_RR_TYPE);
+    if (m_dbMgr.find(rrset)) {
+      Data data(rrset.getData());
+      cert = make_shared<IdentityCertificate>(data);
+    }
+    else {
+      throw Error("Cannot find the cert: " + certName.toUri());
+    }
+  }
+
+  if (outFile == DEFAULT_IO) {
+    ndn::io::save(*cert, std::cout);
+  }
+  else {
+    ndn::io::save(*cert, outFile);
+    NDNS_LOG_INFO("save cert to file: " << outFile);
+  }
+}
+
+void
+ManagementTool::addRrSet(const Name& zoneName,
+                         const Name& label,
+                         const name::Component& type,
+                         NdnsType ndnsType,
+                         const uint64_t version,
+                         const std::vector<std::string>& contents,
+                         const Name& inputDskCertName,
+                         const time::seconds& ttl)
+{
+  // check pre-condition
+  Zone zone(zoneName);
+  if (!m_dbMgr.find(zone)) {
+    throw Error(zoneName.toUri() + " is not presented in the NDNS db");
+  }
+
+  if (ndnsType == NDNS_UNKNOWN) {
+    throw Error("The ndns type is unknown");
+  }
+
+  if (type == label::CERT_RR_TYPE) {
+    throw Error("It cannot handle ID-CERT rrset type");
+  }
+
+  // check strange rr type and ndns type combination
+  if (type == label::NS_RR_TYPE && ndnsType == NDNS_RAW) {
+    throw Error("NS cannot be of the type NDNS_RAW");
+  }
+
+  if (type == label::TXT_RR_TYPE && ndnsType != NDNS_RESP) {
+    throw Error("TXT cannot be of the type NDNS_RAW or NDNS_AUTH");
+  }
+
+  if (ndnsType == NDNS_RAW && contents.size() != 1) {
+    throw Error("NDNS_RAW must contain a single content element");
+  }
+
+  Name dskName;
+  Name dskCertName = inputDskCertName;
+  if (dskCertName == DEFAULT_CERT) {
+    dskName = m_keyChain.getDefaultKeyNameForIdentity(zoneName);
+    dskCertName = m_keyChain.getDefaultCertificateNameForKey(dskName);
+  }
+  else {
+    if (!matchCertificate(dskCertName, zoneName)) {
+      throw Error("Cannot verify certificate");
+    }
+  }
+
+  // set rrset
+  Rrset rrset(&zone);
+  rrset.setLabel(label);
+  rrset.setType(type);
+  if (ttl == DEFAULT_RR_TTL)
+    rrset.setTtl(zone.getTtl());
+  else
+    rrset.setTtl(ttl);
+
+  // set response
+  Response re;
+  re.setZone(zoneName);
+  re.setQueryType(label::NDNS_ITERATIVE_QUERY);
+  re.setRrLabel(label);
+  re.setRrType(type);
+  re.setNdnsType(ndnsType);
+
+  //set content according to ndns type
+  if (ndnsType == NDNS_RAW) {
+    Block tmp = ndn::dataBlock(ndn::tlv::Content, contents[0].c_str(), contents[0].length());
+    re.setAppContent(tmp);
+  }
+  else if (ndnsType != NDNS_AUTH) {
+    if (contents.empty()) {
+      re.addRr("");
+    }
+    else {
+      for (const auto& item : contents) {
+        re.addRr(item);
+      }
+    }
+  }
+
+  shared_ptr<Data> data = re.toData();
+  if (version != VERSION_USE_UNIX_TIMESTAMP) {
+    name::Component tmp = name::Component::fromVersion(version);
+    re.setVersion(tmp);
+  }
+  m_keyChain.sign(*data, dskCertName);
+
+  rrset.setVersion(re.getVersion());
+  rrset.setData(data->wireEncode());
+
+  if (m_dbMgr.find(rrset)) {
+    throw Error("Rrset with label=" + label.toUri() + " is already in local NDNS databse");
+  }
+  NDNS_LOG_INFO("Add rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
+                << type);
+  m_dbMgr.insert(rrset);
+}
+
+void
+ManagementTool::addRrSet(const Name& zoneName,
+                         const std::string& inFile,
+                         const time::seconds& ttl,
+                         const Name& inputDskCertName)
+{
+  //check precondition
+  Zone zone(zoneName);
+  if (!m_dbMgr.find(zone)) {
+    throw Error(zoneName.toUri() + " is not presented in the NDNS db");
+  }
+
+  Name dskName;
+  Name dskCertName = inputDskCertName;
+  if (dskCertName == DEFAULT_CERT) {
+    dskName = m_keyChain.getDefaultKeyNameForIdentity(zoneName);
+    dskCertName = m_keyChain.getDefaultCertificateNameForKey(dskName);
+  }
+  else {
+    if (!matchCertificate(dskCertName, zoneName)) {
+      throw Error("Cannot verify certificate");
+    }
+  }
+
+  if (inFile != DEFAULT_IO) {
+    boost::filesystem::path dir = boost::filesystem::path(inFile);
+    if (!boost::filesystem::exists(dir) || boost::filesystem::is_directory(dir)) {
+      throw Error("Data: " + inFile + " does not exist");
+    }
+  }
+
+  //first load the data
+  shared_ptr<Data> data;
+  if (inFile == DEFAULT_IO)
+    data = ndn::io::load<ndn::Data>(std::cin);
+  else
+    data = ndn::io::load<ndn::Data>(inFile);
+
+  //determine whether the data is a self-signed certificate
+  shared_ptr<Regex> regex1 = make_shared<Regex>("(<>*)<KEY>(<>+)<ID-CERT><>");
+  if (regex1->match(data->getName())) {
+    IdentityCertificate scert(*data);
+    Name keyName = scert.getPublicKeyName();
+    Name keyLocator = scert.getSignature().getKeyLocator().getName();
+
+    //if it is, extract the content and name from the data, and resign it using the dsk.
+    shared_ptr<Regex> regex2 = make_shared<Regex>("(<>*)<KEY>(<>+)<ID-CERT>");
+    BOOST_VERIFY(regex2->match(keyLocator) == true);
+    if (keyName == regex2->expand("\\1\\2")) {
+      shared_ptr<Data> pre = data;
+      Name name = pre->getName();
+      //check whether the name is legal or not. if not converting it to a legal name
+      if (zoneName != regex1->expand("\\1")) {
+        Name comp1 = regex1->expand("\\1").getSubName(zoneName.size());
+        Name comp2 = regex1->expand("\\2");
+        name = zoneName;
+        name.append("KEY");
+        name.append(comp1);
+        name.append(comp2);
+        name.append("ID-CERT");
+        name.append(pre->getName().get(-1));
+      }
+
+      data = make_shared<Data>();
+      data->setName(name);
+      data->setContent(pre->getContent());
+
+      m_keyChain.sign(*data, dskCertName);
+    }
+  }
+
+  // create response for the input data
+  Response re;
+  Name hint;
+  re.fromData(hint, zoneName, *data);
+  Name label = re.getRrLabel();
+  name::Component type = re.getRrType();
+
+  Rrset rrset(&zone);
+  rrset.setLabel(label);
+  rrset.setType(type);
+  if (ttl == DEFAULT_RR_TTL)
+    rrset.setTtl(zone.getTtl());
+  else
+    rrset.setTtl(ttl);
+  rrset.setVersion(re.getVersion());
+  rrset.setData(data->wireEncode());
+
+  if (m_dbMgr.find(rrset)) {
+    throw Error("Rrset with label=" + label.toUri() + " is already in local NDNS databse");
+  }
+  NDNS_LOG_INFO("Add rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
+                << type);
+  m_dbMgr.insert(rrset);
+}
+
+void
+ManagementTool::listZone(const Name& zoneName, std::ostream& os, const bool printRaw) {
+  Zone zone(zoneName);
+  if (!m_dbMgr.find(zone)) {
+    os << "No record is found" << std::endl;
+    return;
+  }
+
+  //first output the zone name
+  os << "; Zone " << zoneName.toUri() << std::endl << std::endl;
+
+  //second output all rrsets
+  std::vector<Rrset> rrsets = m_dbMgr.findRrsets(zone);
+
+  //set width for different columns
+  size_t labelWidth = 0;
+  size_t ttlWidth = 0;
+  size_t typeWidth = 0;
+  for (Rrset& rrset : rrsets) {
+    Data data(rrset.getData());
+    Response re;
+    Name hint;
+    re.fromData(hint, zoneName, data);
+
+    if (rrset.getLabel().toUri().size() > labelWidth)
+      labelWidth = rrset.getLabel().toUri().size();
+
+    std::stringstream seconds;
+    seconds << rrset.getTtl().count();
+    if (seconds.str().size() > ttlWidth)
+      ttlWidth = seconds.str().size();
+
+    if (rrset.getType().toUri().size() > typeWidth)
+      typeWidth = rrset.getType().toUri().size();
+  }
+
+  //output
+  for (Rrset& rrset : rrsets) {
+    Data data(rrset.getData());
+    Response re;
+    Name hint;
+    re.fromData(hint, zoneName, data);
+    int iteration = re.getNdnsType() == NDNS_RAW || re.getNdnsType() == NDNS_AUTH ?
+                      1 : re.getRrs().size();
+    const std::vector<Block> &rrs = re.getRrs();
+
+    if (re.getNdnsType() != NDNS_RAW && re.getNdnsType() != NDNS_AUTH) {
+      os << "; rrset=" << rrset.getLabel().toUri()
+         << " type=" << rrset.getType().toUri()
+         << " version=" << rrset.getVersion().toUri()
+         << " signed-by=" << data.getSignature().getKeyLocator().getName().toUri()
+         << std::endl;
+    }
+
+    for (int i = 0; i < iteration; i++) {
+      os.setf(os.left);
+      os.width(labelWidth + 2);
+      os << rrset.getLabel().toUri();
+
+      os.width(ttlWidth + 2);
+      os << rrset.getTtl().count();
+
+      os.width(typeWidth + 2);
+      os << rrset.getType().toUri();
+
+      if (re.getNdnsType() != NDNS_RAW && re.getNdnsType() != NDNS_AUTH) {
+        using namespace CryptoPP;
+        if (rrset.getType() == label::TXT_RR_TYPE) {
+          os.write(reinterpret_cast<const char*>(rrs[i].value()), rrs[i].value_size());
+          os << std::endl;
+        }
+        else if (rrset.getType() == label::NS_RR_TYPE) {
+          //TODO output the NS data once we have it
+          os << std::endl;
+        }
+        else {
+          StringSource ss(rrs[i].wire(), rrs[i].size(), true,
+                          new Base64Encoder(new FileSink(os), true, 64));
+        }
+      }
+    }
+
+    if (re.getNdnsType() == NDNS_RAW || re.getNdnsType() == NDNS_AUTH) {
+      os.width();
+      os << "; content-type=" << re.getNdnsType()
+         << " version=" << rrset.getVersion().toUri()
+         << " signed-by=" << data.getSignature().getKeyLocator().getName().toUri();
+      os << std::endl;
+
+      if (printRaw && re.getNdnsType() == NDNS_RAW) {
+        using namespace CryptoPP;
+        std::stringstream sstream;
+        StringSource ss(re.getAppContent().wire(), re.getAppContent().size(), true,
+                        new Base64Encoder(new FileSink(sstream), true, 64));
+
+        std::string content = sstream.str();
+        std::string delimiter = "\n";
+        size_t pos = 0;
+        std::string token;
+        while ((pos = content.find(delimiter)) != std::string::npos) {
+            token = content.substr(0, pos);
+            os << "; " << token << std::endl;
+            content.erase(0, pos + delimiter.length());
+        }
+
+        os << std::endl;
+      }
+    }
+    else {
+      os << std::endl;
+    }
+  }
+}
+
+void
+ManagementTool::listAllZones(std::ostream& os) {
+  std::vector<Zone> zones = m_dbMgr.listZones();
+
+  size_t nameWidth = 0;
+  for (const Zone& zone : zones) {
+    if (zone.getName().toUri().size() > nameWidth)
+      nameWidth = zone.getName().toUri().size();
+  }
+
+  for (const Zone& zone : zones) {
+    os.setf(os.left);
+    os.width(nameWidth + 2);
+    os << zone.getName().toUri();
+
+    os << "; default-ttl=" << zone.getTtl().count();
+    os << " default-key=" << m_keyChain.getDefaultKeyNameForIdentity(zone.getName());
+    os << " default-certificate="
+       << m_keyChain.getDefaultCertificateNameForIdentity(zone.getName());
+    os << std::endl;
+  }
+}
+
+void
+ManagementTool::removeRrSet(const Name& zoneName, const Name& label, const name::Component& type)
+{
+  Zone zone(zoneName);
+  Rrset rrset(&zone);
+  rrset.setLabel(label);
+  rrset.setType(type);
+
+  if (!m_dbMgr.find(rrset)) {
+    return;
+  }
+  NDNS_LOG_INFO("Remove rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
+                << type);
+  m_dbMgr.remove(rrset);
+}
+
+void
+ManagementTool::getRrSet(const Name& zoneName,
+                         const Name& label,
+                         const name::Component& type,
+                         std::ostream& os)
+{
+  Zone zone(zoneName);
+  Rrset rrset(&zone);
+  rrset.setLabel(label);
+  rrset.setType(type);
+
+  if (!m_dbMgr.find(rrset)) {
+    os << "No record is found" << std::endl;
+    return;
+  }
+
+  using namespace CryptoPP;
+  StringSource ss(rrset.getData().wire(), rrset.getData().size(), true,
+                  new Base64Encoder(new FileSink(os), true, 64));
+}
+
+void
+ManagementTool::addIdCert(Zone& zone, shared_ptr<IdentityCertificate> cert,
+                          const time::seconds& ttl)
+{
+  Rrset rrset(&zone);
+  size_t size = zone.getName().size();
+  Name label = cert->getName().getSubName(size + 1, cert->getName().size() - size - 3);
+  rrset.setLabel(label);
+  rrset.setType(label::CERT_RR_TYPE);
+  rrset.setTtl(ttl);
+  rrset.setVersion(cert->getName().get(-1));
+  rrset.setData(cert->wireEncode());
+
+  if (m_dbMgr.find(rrset)) {
+    throw Error("ID-CERT with label=" + label.toUri() +
+                " is already presented in local NDNS databse");
+  }
+  NDNS_LOG_INFO("Add rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
+                << label::CERT_RR_TYPE);
+  m_dbMgr.insert(rrset);
+}
+
+void
+ManagementTool::addZone(Zone& zone)
+{
+  if (m_dbMgr.find(zone)) {
+    throw Error("Zone with Name=" + zone.getName().toUri() +
+                " is already presented in local NDNS databse");
+  }
+  NDNS_LOG_INFO("Add zone with Name: " << zone.getName().toUri());
+  m_dbMgr.insert(zone);
+}
+
+void
+ManagementTool::removeZone(Zone& zone)
+{
+  if (!m_dbMgr.find(zone)) {
+    return;
+  }
+  NDNS_LOG_INFO("Remove zone with Name: " << zone.getName().toUri());
+  m_dbMgr.remove(zone);
+}
+
+bool
+ManagementTool::matchCertificate(const Name& certName, const Name& identity)
+{
+  if (!m_keyChain.doesCertificateExist(certName)) {
+    NDNS_LOG_WARN(certName.toUri() << " is not presented in KeyChain");
+    return false;
+  }
+
+  //check its public key information
+  shared_ptr<IdentityCertificate> cert = m_keyChain.getCertificate(certName);
+  Name keyName = cert->getPublicKeyName();
+
+  if (!identity.isPrefixOf(keyName) || identity.size()!=keyName.size()-1) {
+    NDNS_LOG_WARN(keyName.toUri() << " is not a key of " << identity.toUri());
+    return false;
+  }
+
+  if (!m_keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE)) {
+    NDNS_LOG_WARN("Private key: " << keyName.toUri() << " is not presented in KeyChain");
+    return false;
+  }
+
+  return true;
+}
+
+} // namespace ndns
+} // namespace ndn
diff --git a/src/mgmt/management-tool.hpp b/src/mgmt/management-tool.hpp
new file mode 100644
index 0000000..f962b11
--- /dev/null
+++ b/src/mgmt/management-tool.hpp
@@ -0,0 +1,233 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NDNS_MGMT_MANAGEMENT_TOOL_HPP
+#define NDNS_MGMT_MANAGEMENT_TOOL_HPP
+
+#include "config.hpp"
+#include "ndns-enum.hpp"
+#include "./daemon/zone.hpp"
+#include "./daemon/db-mgr.hpp"
+#include "./daemon/rrset.hpp"
+#include "./clients/response.hpp"
+
+#include <stdexcept>
+#include <ndn-cxx/common.hpp>
+#include <ndn-cxx/security/identity-certificate.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+
+namespace ndn {
+namespace ndns {
+
+static const Name DEFAULT_CERT;
+static const Name ROOT_ZONE;
+static const time::seconds DEFAULT_CACHE_TTL = time::seconds(3600);
+static const time::seconds DEFAULT_CERT_TTL = time::days(365);
+static const std::vector<std::string> DEFAULT_CONTENTS;
+static const std::string DEFAULT_IO = "-";
+static const time::seconds DEFAULT_RR_TTL = time::seconds(0);
+static constexpr uint64_t VERSION_USE_UNIX_TIMESTAMP = std::numeric_limits<uint64_t>::max();
+
+/**
+ * @brief provides management tools to the NDNS system, such as zone creation, zone delegation, DSK
+ * generation and root zone creation.
+ */
+class ManagementTool : noncopyable
+{
+public:
+  /** @brief Represents an error might be thrown during runtime
+   */
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what) : std::runtime_error(what)
+    {
+    }
+  };
+
+  /** @param certDir Path to the directory to store certificates
+   *  @param dbFile Path to the local database
+   */
+  explicit
+  ManagementTool(const std::string& dbFile);
+
+  /** @brief Create a Zone according to a given name.
+   *
+   *  Specifically, It will generate a KSK and a DSK (and their certificates) to the following
+   *  places:
+   *  1) Local NDNS database: a new zone is added.
+   *  2) Local NDNS database: an ID-CERT of the DSK is added.
+   *  3) KeyChain: an identity named with zone name is added.
+   *  4) KeyChain: a KSK and its self-signed certificate is added. The ownership of the KSK is the
+   *  parent zone.
+   *  5) KeyChain: a DSK and its KSK signed certificate is added.
+   *
+   *  -SS.cert (self-signed)
+   *  -SKS.cert (self's Key signed)
+   *  -PKS.cert (parent's Key Signed)
+   *
+   *  @attention
+   *  1) to create root zone, supply zoneName and parentZoneName both with ROOT_ZONE
+   *
+   *  @param zoneName zone's name
+   *  @param parentZoneName parent zone's name
+   *  @param ttl ttl for the created zone
+   *  @param kskCertName if given, a zone will be created with this ksk certificate and its key
+   *  @param kskCertName if given, a zone will be created with this dsk certificate and its key
+   */
+  void
+  createZone(const Name& zoneName,
+             const Name& parentZoneName,
+             const time::seconds& cacheTtl = DEFAULT_CACHE_TTL,
+             const time::seconds& certTtl = DEFAULT_CERT_TTL,
+             const Name& kskCertName = DEFAULT_CERT,
+             const Name& dskCertName = DEFAULT_CERT);
+
+  /** @brief Delete a Zone according to a given name.
+   *
+   *  Specifically, It will do the following things:
+   *  1) KeyChain System: delete the Identity with zone name and all its keys/certificates
+   *  2) Local NDNS database: delete the zone record
+   *  3) Local NDNS database: delete the ID-CERT of the zone's DSK
+   */
+  void
+  deleteZone(const Name& zoneName);
+
+  /** @brief Export the certificate to file system
+   *
+   *  @param certName the name of the certificate to be exported
+   *  @param output the path to output to-be exported file, including the file name
+   */
+  void
+  exportCertificate(const Name& certName, const std::string& outFile = DEFAULT_IO);
+
+  /** @brief add rrset to the NDNS local database
+   *
+   *  This one is only capable of adding NS type including NDNS_RESP and NDNS_AUTH and user defined
+   *  type with string content.
+   *  Other complicated situations can be handled by the other addRrSet() overload function.
+   *
+   *  @param zoneName the name of the zone to hold the rrset
+   *  @param label the rrset label
+   *  @param type the rrset type
+   *  @param ndnsType the ndnsType of the response, for user-defined type, just set it NDNS_RAW
+   *  @param version the version of the response and rrset, default is Unix Timestamp
+   *  @param content the content of the response
+   *  @param dskName the DSK to signed the response, default is the zone's DSK
+   *  @param ttl the ttl of the rrset
+    */
+  void
+  addRrSet(const Name& zoneName,
+           const Name& label,
+           const name::Component& type,
+           NdnsType ndnsType,
+           const uint64_t version = VERSION_USE_UNIX_TIMESTAMP,
+           const std::vector<std::string>& contents = DEFAULT_CONTENTS,
+           const Name& dskCertName = DEFAULT_CERT,
+           const time::seconds& ttl = DEFAULT_RR_TTL);
+
+  /** @brief add rrset to the NDNS local database
+   *
+   *  This overload is capable of adding any data to the rrset as long as the supplied data is
+   *  valid.
+   *  A special case is to add the ID-CERT of KSK to the parent zone. At this case, the SS cert
+   *  should be supplied, and therefore it will use the parent zone's DSK to resign the certificate.
+   *  For other cases, the data will be added directly without any modification.
+   *
+   *  @param zoneName the name of the zone to hold the rrset
+   *  @param dataPath the path to the supplied data
+   *  @param ttl the ttl of the rrset
+   *  @param dskName the DSK to signed the special case, default is the zone's DSK
+    */
+  void
+  addRrSet(const Name& zoneName,
+           const std::string& inFile = DEFAULT_IO,
+           const time::seconds& ttl = DEFAULT_RR_TTL,
+           const Name& dskCertName = DEFAULT_CERT);
+
+  /** @brief remove rrset from the NDNS local database
+   *
+   *  @param zonName the name of the zone holding the rrset
+   *  @param label rrset's label
+   *  @param type rrset's type
+    */
+  void
+  removeRrSet(const Name& zoneName, const Name& label, const name::Component& type);
+
+  /** @brief output the raw data of the selected rrset
+   *
+   *  @param zonName the name of the zone holding the rrset
+   *  @param label rrset's label
+   *  @param type rrset's type
+   *  @param os the ostream to print information to
+   *  @param isPP indicate pretty print
+    */
+  void
+  getRrSet(const Name& zoneName,
+           const Name& label,
+           const name::Component& type,
+           std::ostream& os);
+
+  /** @brief generates an output like DNS zone file. Reference:
+   *  http://en.wikipedia.org/wiki/Zone_file
+   *
+   *  @param zoneName the name of the zone to investigate
+   *  @param os the ostream to print information to
+   *  @param printRaw set to print content of ndns-raw rrset
+    */
+  void
+  listZone(const Name& zoneName, std::ostream& os, const bool printRaw = false);
+
+  /** @brief lists all existing zones within this name server.
+   *
+   *  @param os the ostream to print information to
+    */
+  void
+  listAllZones(std::ostream& os);
+
+private:
+  /** @brief add ID-CERT to the NDNS local database
+    */
+  void
+  addIdCert(Zone& zone, shared_ptr<IdentityCertificate> cert, const time::seconds& ttl);
+
+  /** @brief add zone to the NDNS local database
+    */
+  void
+  addZone(Zone& zone);
+
+  /** @brief remove zone from the NDNS local database
+    */
+  void
+  removeZone(Zone& zone);
+
+  /** @brief determine whether a certificate matches with both the identity and key type
+   */
+  bool
+  matchCertificate(const Name& certName, const Name& identity);
+
+private:
+  KeyChain m_keyChain;
+  DbMgr m_dbMgr;
+};
+
+} // namespace ndns
+} // namespace ndn
+#endif // NDNS_MGMT_MANAGEMENT_TOOL_HPP
diff --git a/tests/unit/daemon/db-mgr.cpp b/tests/unit/daemon/db-mgr.cpp
index fb621d2..be728d6 100644
--- a/tests/unit/daemon/db-mgr.cpp
+++ b/tests/unit/daemon/db-mgr.cpp
@@ -179,6 +179,33 @@
   BOOST_CHECK_NO_THROW(session.remove(rrset1));
 }
 
+BOOST_FIXTURE_TEST_CASE(FindAllZones, DbMgrFixture)
+{
+  Zone zone("/ndn");
+  zone.setTtl(time::seconds(1600));
+  session.insert(zone);
+
+  Zone zone2("/ndn/ucla");
+  zone2.setTtl(time::seconds(2600));
+  session.insert(zone2);
+
+  std::vector<Zone> vec = session.listZones();
+  BOOST_CHECK_EQUAL(vec.size(), 2);
+
+  std::sort(vec.begin(),
+            vec.end(),
+            [] (const Zone& n1, const Zone& n2) {
+              return n1.getName().size() < n2.getName().size();
+            });
+  BOOST_CHECK_EQUAL(vec[0].getId(), zone.getId());
+  BOOST_CHECK_EQUAL(vec[0].getName(), "/ndn");
+  BOOST_CHECK_EQUAL(vec[0].getTtl(), time::seconds(1600));
+
+  BOOST_CHECK_EQUAL(vec[1].getId(), zone2.getId());
+  BOOST_CHECK_EQUAL(vec[1].getName(), "/ndn/ucla");
+  BOOST_CHECK_EQUAL(vec[1].getTtl(), time::seconds(2600));
+
+}
 
 BOOST_FIXTURE_TEST_CASE(FindRrsets, DbMgrFixture)
 {
diff --git a/tests/unit/daemon/name-server.cpp b/tests/unit/daemon/name-server.cpp
index f721a5e..09d192f 100644
--- a/tests/unit/daemon/name-server.cpp
+++ b/tests/unit/daemon/name-server.cpp
@@ -167,7 +167,6 @@
     Response resp;
 
     BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
-    std::cout << resp << std::endl;
     BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RESP); // by default NDNS_RAW is enough
     BOOST_CHECK_GT(resp.getRrs().size(), 0);
     Block block = resp.getRrs()[0];
@@ -220,7 +219,6 @@
     Response resp;
 
     BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
-    std::cout << resp << std::endl;
     BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RESP); // by default NDNS_RAW is enough
     BOOST_CHECK_GT(resp.getRrs().size(), 0);
     Block block = resp.getRrs()[0];
@@ -401,7 +399,6 @@
       Response resp;
 
       BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
-      std::cout << resp << std::endl;
       BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RESP); // by default NDNS_RAW is enough
       BOOST_CHECK_GT(resp.getRrs().size(), 0);
       Block block = resp.getRrs()[0];
diff --git a/tests/unit/mgmt/management-tool.cpp b/tests/unit/mgmt/management-tool.cpp
new file mode 100644
index 0000000..2eefe15
--- /dev/null
+++ b/tests/unit/mgmt/management-tool.cpp
@@ -0,0 +1,982 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "../../src/mgmt/management-tool.hpp"
+
+#include "../../boost-test.hpp"
+#include <boost/test/output_test_stream.hpp>
+using boost::test_tools::output_test_stream;
+
+#include "ndns-enum.hpp"
+#include "ndns-label.hpp"
+#include "ndns-tlv.hpp"
+
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string/replace.hpp>
+
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/security/validator.hpp>
+#include <ndn-cxx/util/io.hpp>
+#include <ndn-cxx/util/regex.hpp>
+
+namespace ndn {
+namespace ndns {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(ManagementTool)
+
+static const boost::filesystem::path TEST_DATABASE = TEST_CONFIG_PATH "/management_tool.db";
+static const boost::filesystem::path TEST_CERTDIR = TEST_CONFIG_PATH "/management_tool_certs";
+static const Name FAKE_ROOT("/fake-root/123456789");
+
+class ManagementToolFixture
+{
+public:
+  ManagementToolFixture()
+    : m_tool(TEST_DATABASE.string().c_str())
+    , m_keyChain("sqlite3", "file")
+    , m_dbMgr(TEST_DATABASE.string().c_str())
+  {
+    boost::filesystem::create_directory(TEST_CERTDIR);
+  }
+
+  ~ManagementToolFixture()
+  {
+    boost::filesystem::remove_all(TEST_CERTDIR);
+    boost::filesystem::remove(TEST_DATABASE);
+  }
+
+  void
+  getKeyList(const Name& identity, std::vector<Name>& keyList)
+  {
+    m_keyChain.getAllKeyNamesOfIdentity(identity, keyList, false);
+    m_keyChain.getAllKeyNamesOfIdentity(identity, keyList, true);
+  }
+
+  void
+  getCertList(const Name& identity, std::vector<Name>& certNameList)
+  {
+    std::vector<Name> keyList;
+    getKeyList(identity, keyList);
+    for (const Name& name : keyList) {
+      m_keyChain.getAllCertificateNamesOfKey(name, certNameList, false);
+      m_keyChain.getAllCertificateNamesOfKey(name, certNameList, true);
+    }
+  }
+
+  bool
+  checkIdCert(Zone& zone, const Name& certName)
+  {
+    Rrset rrset(&zone);
+    size_t size = zone.getName().size();
+    Name label = certName.getSubName(size+1, certName.size()-size-3);
+    rrset.setLabel(label);
+    rrset.setType(label::CERT_RR_TYPE);
+
+    if (!m_dbMgr.find(rrset))
+      return false;
+
+    Data data(rrset.getData());
+    IdentityCertificate cert(data);
+    return cert.getName() == certName;
+  }
+
+  bool
+  checkNs(Zone& zone, const Name& label, NdnsType ndnsType)
+  {
+    Rrset rrset(&zone);
+    rrset.setLabel(label);
+    rrset.setType(label::NS_RR_TYPE);
+
+    if (!m_dbMgr.find(rrset))
+      return false;
+
+    Data data(rrset.getData());
+    MetaInfo info = data.getMetaInfo();
+
+    const Block* block = info.findAppMetaInfo(tlv::NdnsType);
+    if (block == 0)
+      return false;
+
+    return static_cast<NdnsType>(readNonNegativeInteger(*block)) == ndnsType;
+  }
+
+  bool
+  checkVersion(Zone& zone, const Name& label, const name::Component& type, uint64_t version)
+  {
+    Rrset rrset(&zone);
+    rrset.setLabel(label);
+    rrset.setType(type);
+
+    if (!m_dbMgr.find(rrset))
+      return false;
+
+    name::Component tmp = name::Component::fromVersion(version);
+
+    return rrset.getVersion() == tmp;
+  }
+
+  bool
+  checkTtl(Zone& zone, const Name& label, const name::Component& type, time::seconds ttl)
+  {
+    Rrset rrset(&zone);
+    rrset.setLabel(label);
+    rrset.setType(type);
+
+    if (!m_dbMgr.find(rrset))
+      return false;
+
+    return rrset.getTtl() == ttl;
+  }
+
+  // function to get a verified public key of a given data
+  PublicKey
+  getPublicKeyOfData(const Data& data) {
+    // first extract certificate name of the signing key
+    Signature sig = data.getSignature();
+    KeyLocator kl = sig.getKeyLocator();
+    Name klName = kl.getName();
+
+    //base case, return root key to verify ROOT DSK certificate
+    shared_ptr<Regex> regex1 = make_shared<Regex>(
+                                 "<KEY><fake-root><123456789><ksk-[0-9]+><ID-CERT>");
+    if (regex1->match(klName)) {
+      std::vector<Name> keyList1;
+      m_keyChain.getAllKeyNamesOfIdentity(FAKE_ROOT, keyList1, false);
+      shared_ptr<PublicKey> rootKey = m_keyChain.getPublicKey(keyList1.front());
+
+      // return root key
+      return *rootKey;
+    }
+
+    // second extract the certificate from local NDNS database
+    // extract zone name and label
+    shared_ptr<Regex> regex2 = make_shared<Regex>("(<>*)<KEY>(<>+)<ID-CERT>");
+    BOOST_ASSERT(regex2->match(klName) == true);
+    Name zoneName = regex2->expand("\\1");
+    Name label = regex2->expand("\\2");
+
+    // get ID-CERT from local NDNS database
+    Zone zone(zoneName);
+    Rrset rrset(&zone);
+    rrset.setLabel(label);
+    rrset.setType(label::CERT_RR_TYPE);
+
+    BOOST_CHECK_EQUAL(m_dbMgr.find(rrset), true);
+
+    // get public key siging the ID-CERT
+    Data tmp(rrset.getData());
+    PublicKey pk = getPublicKeyOfData(tmp);
+
+    // verified the ID-CERT
+    BOOST_CHECK_EQUAL(Validator::verifySignature(tmp, pk), true);
+    IdentityCertificate cert(tmp);
+
+    // third return public key
+    return cert.getPublicKeyInfo();
+  }
+
+public:
+  ndns::ManagementTool m_tool;
+  ndn::KeyChain m_keyChain;
+  ndns::DbMgr m_dbMgr;
+};
+
+BOOST_FIXTURE_TEST_CASE(CreateZone1, ManagementToolFixture)
+{
+  //create root zone with supplied certificates
+  bool isRoot = m_keyChain.doesIdentityExist(ROOT_ZONE);
+  size_t iniKey = 0;
+  size_t iniCert = 0;
+  if (isRoot) {
+    std::vector<Name> keyList;
+    getKeyList(ROOT_ZONE, keyList);
+    iniKey = keyList.size();
+
+    std::vector<Name> certList;
+    getCertList(ROOT_ZONE, certList);
+    iniCert = certList.size();
+  }
+
+  time::system_clock::TimePoint notBefore = time::system_clock::now();
+  time::system_clock::TimePoint notAfter = notBefore + DEFAULT_CERT_TTL;
+
+  Name kskName = m_keyChain.generateRsaKeyPair(ROOT_ZONE, true);
+  std::vector<CertificateSubjectDescription> kskDesc;
+  shared_ptr<IdentityCertificate> kskCert = m_keyChain.prepareUnsignedIdentityCertificate(kskName,
+    ROOT_ZONE, notBefore, notAfter, kskDesc);
+  m_keyChain.selfSign(*kskCert);
+  m_keyChain.addCertificate(*kskCert);
+
+  Name dskName = m_keyChain.generateRsaKeyPair(ROOT_ZONE, false);
+  std::vector<CertificateSubjectDescription> dskDesc;
+  shared_ptr<IdentityCertificate> dskCert = m_keyChain.prepareUnsignedIdentityCertificate(
+    dskName, ROOT_ZONE, notBefore, notAfter, dskDesc);
+  m_keyChain.sign(*dskCert, kskCert->getName());
+  m_keyChain.addCertificate(*dskCert);
+
+  m_tool.createZone(ROOT_ZONE, ROOT_ZONE, time::seconds(4600), time::seconds(4600),
+                    kskCert->getName(), dskCert->getName());
+
+  BOOST_CHECK_EQUAL(m_keyChain.doesIdentityExist(ROOT_ZONE), true);
+
+  std::vector<Name> keyList;
+  getKeyList(ROOT_ZONE, keyList);
+  BOOST_CHECK_EQUAL(keyList.size(), 2 + iniKey);
+
+  std::vector<Name> certList;
+  getCertList(ROOT_ZONE, certList);
+  BOOST_CHECK_EQUAL(certList.size(), 2 + iniCert);
+
+  Zone zone(ROOT_ZONE);
+  BOOST_CHECK_EQUAL(m_dbMgr.find(zone), true);
+  BOOST_CHECK_EQUAL(checkIdCert(zone, dskCert->getName()), true);
+
+  if (isRoot) {
+    // will leave the identity in KeyChain
+    m_keyChain.deleteCertificate(kskCert->getName());
+    m_keyChain.deleteCertificate(dskCert->getName());
+
+    m_keyChain.deleteKey(kskName);
+    m_keyChain.deleteKey(dskName);
+  }
+  else {
+    m_tool.deleteZone(ROOT_ZONE);
+  }
+}
+
+BOOST_FIXTURE_TEST_CASE(CreateZone2, ManagementToolFixture)
+{
+  //create normal zone
+  Name parentZoneName("/ndns-test");
+  parentZoneName.appendVersion();
+  Name zoneName = parentZoneName;
+  zoneName.append("child-zone");
+
+
+  m_tool.createZone(zoneName, parentZoneName);
+
+  BOOST_CHECK_EQUAL(m_keyChain.doesIdentityExist(zoneName), true);
+
+  std::vector<Name> keyList;
+  getKeyList(zoneName, keyList);
+  BOOST_CHECK_EQUAL(keyList.size(), 2);
+
+  std::vector<Name> certList;
+  getCertList(zoneName, certList);
+  BOOST_CHECK_EQUAL(certList.size(), 2);
+
+  Name dskName;
+  Name kskName;
+  for (std::vector<Name>::iterator it = certList.begin();
+      it != certList.end();
+      it++) {
+    std::string temp = (*it).toUri();
+    size_t found = temp.find("dsk");
+    if (found != std::string::npos) {
+      dskName = *it;
+    }
+    else {
+      kskName = *it;
+    }
+  }
+
+  Zone zone(zoneName);
+  BOOST_CHECK_EQUAL(m_dbMgr.find(zone), true);
+  BOOST_CHECK_EQUAL(checkIdCert(zone, dskName), true);
+
+  m_tool.deleteZone(zoneName);
+}
+
+BOOST_FIXTURE_TEST_CASE(CreateZone3, ManagementToolFixture)
+{
+  //create normal zone with TTL
+  Name parentZoneName("/ndns-test");
+  parentZoneName.appendVersion();
+  Name zoneName = parentZoneName;
+  zoneName.append("child-zone");
+
+  time::seconds ttl = time::seconds(4200);
+  m_tool.createZone(zoneName, parentZoneName, ttl, ttl);
+
+  BOOST_CHECK_EQUAL(m_keyChain.doesIdentityExist(zoneName), true);
+
+  std::vector<Name> keyList;
+  getKeyList(zoneName, keyList);
+  BOOST_CHECK_EQUAL(keyList.size(), 2);
+
+  std::vector<Name> certList;
+  getCertList(zoneName, certList);
+  BOOST_CHECK_EQUAL(certList.size(), 2);
+
+  Name dskName;
+  for (std::vector<Name>::iterator it = certList.begin();
+      it != certList.end();
+      it++) {
+    std::string temp = (*it).toUri();
+    size_t found = temp.find("dsk");
+    if (found != std::string::npos) {
+      dskName = *it;
+    }
+  }
+
+  //check zone ttl
+  Zone zone(zoneName);
+  BOOST_CHECK_EQUAL(m_dbMgr.find(zone), true);
+  BOOST_CHECK_EQUAL(zone.getTtl(), ttl);
+
+  //check dsk rrset ttl
+  Rrset rrset(&zone);
+  size_t size = zone.getName().size();
+  Name label = dskName.getSubName(size+1, dskName.size()-size-3);
+  rrset.setLabel(label);
+  rrset.setType(label::CERT_RR_TYPE);
+  BOOST_CHECK_EQUAL(m_dbMgr.find(rrset), true);
+  BOOST_CHECK_EQUAL(rrset.getTtl(), ttl);
+
+  //check certificate ttl
+  shared_ptr<IdentityCertificate> dskCert = m_keyChain.getCertificate(dskName);
+  time::system_clock::Duration tmp = dskCert->getNotAfter() - dskCert->getNotBefore();
+  BOOST_CHECK_EQUAL(ttl, tmp);
+
+  m_tool.deleteZone(zoneName);
+}
+
+BOOST_FIXTURE_TEST_CASE(CreateZone4, ManagementToolFixture)
+{
+  //check pre-condition
+  Name zoneName("/net/ndnsim");
+  Name parentZoneName("/net");
+
+  Zone zone(zoneName);
+  m_dbMgr.insert(zone);
+  BOOST_CHECK_THROW(m_tool.createZone(zoneName, parentZoneName), ndns::ManagementTool::Error);
+  m_dbMgr.remove(zone);
+
+  time::seconds ttl = time::seconds(4200);
+  BOOST_CHECK_THROW(m_tool.createZone(zoneName, zoneName), ndns::ManagementTool::Error);
+
+  Name fake1("/com");
+  BOOST_CHECK_THROW(m_tool.createZone(zoneName, fake1), ndns::ManagementTool::Error);
+
+  Name fake2("/com/ndnsim");
+  BOOST_CHECK_THROW(m_tool.createZone(zoneName, parentZoneName, ttl, ttl, fake2),
+                    ndns::ManagementTool::Error);
+  Name cert2 = m_keyChain.createIdentity(fake2);
+  BOOST_CHECK_THROW(m_tool.createZone(zoneName, parentZoneName, ttl, ttl, cert2),
+                    ndns::ManagementTool::Error);
+  m_keyChain.deleteIdentity(fake2);
+
+  Name fake3("/net/ndnsim/www");
+  Name cert3 = m_keyChain.createIdentity(fake3);
+  BOOST_CHECK_THROW(m_tool.createZone(zoneName, parentZoneName, ttl, ttl, cert3),
+                    ndns::ManagementTool::Error);
+  m_keyChain.deleteIdentity(fake3);
+
+  Name cert4 = m_keyChain.createIdentity(zoneName);
+  shared_ptr<IdentityCertificate> cert = m_keyChain.getCertificate(cert4);
+  //delete keys in tpm
+  m_keyChain.deleteKeyPairInTpm(cert->getPublicKeyName());
+  BOOST_CHECK_THROW(m_tool.createZone(zoneName, parentZoneName, ttl, ttl, cert4),
+                    ndns::ManagementTool::Error);
+  m_keyChain.deleteIdentity(zoneName);
+
+  //for root zone special case
+  BOOST_CHECK_THROW(m_tool.createZone(ROOT_ZONE, ROOT_ZONE), ndns::ManagementTool::Error);
+}
+
+BOOST_FIXTURE_TEST_CASE(DeleteZone1, ManagementToolFixture)
+{
+  Name zoneName("/ndns-test");
+  zoneName.appendVersion();
+
+  m_tool.createZone(zoneName, ROOT_ZONE);
+
+  std::vector<Name> keyList;
+  getKeyList(zoneName, keyList);
+  std::vector<Name> certList;
+  getCertList(zoneName, certList);
+
+  m_tool.deleteZone(zoneName);
+
+  BOOST_CHECK_EQUAL(m_keyChain.doesIdentityExist(zoneName), false);
+
+  for (std::vector<Name>::iterator it = keyList.begin(); it != keyList.end(); it++) {
+    BOOST_CHECK_EQUAL(m_keyChain.doesKeyExistInTpm(*it, KEY_CLASS_PUBLIC), false);
+    BOOST_CHECK_EQUAL(m_keyChain.doesKeyExistInTpm(*it, KEY_CLASS_PRIVATE), false);
+  }
+
+  Name dskName;
+  for (std::vector<Name>::iterator it = certList.begin();
+      it != certList.end();
+      it++) {
+    BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(*it), false);
+    std::string temp = (*it).toUri();
+    size_t found = temp.find("dsk");
+    if (found != std::string::npos) {
+      dskName = *it;
+    }
+  }
+
+  Zone zone(zoneName);
+  BOOST_CHECK_EQUAL(m_dbMgr.find(zone), false);
+  BOOST_CHECK_EQUAL(checkIdCert(zone, dskName), false);
+}
+
+BOOST_FIXTURE_TEST_CASE(DeleteZone2, ManagementToolFixture)
+{
+  Name zoneName("/net/ndnsim");
+
+  BOOST_CHECK_THROW(m_tool.deleteZone(zoneName), ndns::ManagementTool::Error);
+}
+
+class OutputTester
+{
+public:
+  OutputTester()
+    : savedBuf(std::clog.rdbuf())
+  {
+    std::cout.rdbuf(buffer.rdbuf());
+  }
+
+  ~OutputTester()
+  {
+    std::cout.rdbuf(savedBuf);
+  }
+
+public:
+  std::stringstream buffer;
+  std::streambuf* savedBuf;
+};
+
+BOOST_FIXTURE_TEST_CASE(ExportCertificate, ManagementToolFixture)
+{
+  Name zoneName("/ndns-test");
+  zoneName.appendVersion();
+  std::string output = TEST_CERTDIR.string() + "/ss.cert";
+
+  /// @todo Do not generate anything in root zone. Use some prefix for testing, e.g. /test
+
+  //check precondition
+  Name certName("/net/KEY/ksk-123/ID-CERT/123");
+  BOOST_CHECK_THROW(m_tool.exportCertificate(certName, output), ndns::ManagementTool::Error);
+
+  //get certificate from KeyChain
+  m_tool.createZone(zoneName, ROOT_ZONE);
+  std::vector<Name> certList;
+  getCertList(zoneName, certList);
+  Name kskCertName;
+  Name dskCertName;
+  for (const auto& cert : certList) {
+    std::string temp = cert.toUri();
+    size_t found = temp.find("ksk");
+    if (found != std::string::npos) {
+      kskCertName = cert;
+    }
+    else {
+      dskCertName = cert;
+    }
+  }
+  m_tool.exportCertificate(kskCertName, output);
+  BOOST_CHECK_EQUAL(boost::filesystem::exists(output), true);
+
+  //get certificate from ndns database
+  boost::filesystem::remove(output);
+  m_keyChain.deleteCertificate(dskCertName);
+  m_tool.exportCertificate(dskCertName, output);
+  BOOST_CHECK_EQUAL(boost::filesystem::exists(output), true);
+
+  //output to std::cout
+  std::string acutalOutput;
+  {
+    OutputTester tester;
+    m_tool.exportCertificate(dskCertName, "-");
+    acutalOutput = tester.buffer.str();
+  }
+  // BOOST_CHECK_EQUAL(acutalOutput,
+  //                   "Bv0DDAdCCAluZG5zLXRlc3QICf0AAAFJ6RF8OggDS0VZCBFkc2stMTQxNjk1NDQ3\n"
+  //                   "NzcxNQgHSUQtQ0VSVAgJ/QAAAUnpEXzcFAMYAQIV/QF7MIIBdzAiGA8yMDE0MTEy\n"
+  //                   "NTIyMjc1N1oYDzIwMTUxMTI1MjIyNzU3WjAtMCsGA1UEKRMkL25kbnMtdGVzdC8l\n"
+  //                   "RkQlMDAlMDAlMDFJJUU5JTExJTdDJTNBMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0A\n"
+  //                   "MIIBCAKCAQEAvRAQ0iLGmoUCNFQjtD6ClA6BzmtViWywDRU7eDXHHqz1BmXNGS28\n"
+  //                   "dmVbk6C8ZiQxVh5IoN2psxU1avC2lLM7HXHnyUtmfu9/zkxdBSFq8B+8FchFpPWe\n"
+  //                   "9M/TSFmEemcFLdMgYEJOurF3osASZ70/kJJ7f1yiFRm1dtO2pl5eVUuiZPcgVwMU\n"
+  //                   "nCUDT/wZ6l2LDr4K7wo6p5F8PYiIddS6zT38gZsRNwCeR5JDwCPY3u5x21aVSSY7\n"
+  //                   "8PS/wdSG0vmjI/kQEWhjaV7ibyTc6ygrbq5RiLD+18CkEF+ECLKjvLnyIO8DkbbM\n"
+  //                   "iMVyc6QSiKnq7bLCyqbBVpZqNpBjdMvDuQIBERY+GwEBHDkHNwgDS0VZCAluZG5z\n"
+  //                   "LXRlc3QICf0AAAFJ6RF8OggRa3NrLTE0MTY5NTQ0Nzc2MjcIB0lELUNFUlQX/QEA\n"
+  //                   "BKchd4m2kpI7N376Z8yRAKA3epcUlGI5E1Xs7pKTFwA16ZQ+dTThBQSzzVaJcOC2\n"
+  //                   "UIc2WVRG5wCxcCLou4bxnbuPaQORyeRnmoodTPoIYsDrWVPxeVY1xJSKCbGoY8dh\n"
+  //                   "BuXmo9nl4X2wk/gZx6//afATgzQCliQK/J9PwigqirJqH6aD+3Ji209FbP57tv0g\n"
+  //                   "aL0Dy5IA6LrJI1Dxq0MXCRv3bNtdGNQZT0AfHIgCrhPe6MMLGn+C9UTDP2nzMqbX\n"
+  //                   "4MaAdshgUFj0mI2iPL3Bep9pYI6zxbU3hJ25UQegjJdC3qoFjz2sp/D6J8wAlCPX\n"
+  //                   "gGH3iewd94xFpPcdrhxtHQ==\n");
+
+  m_tool.deleteZone(zoneName);
+}
+
+BOOST_FIXTURE_TEST_CASE(AddRrSet1, ManagementToolFixture)
+{
+  // check pre-condition
+  BOOST_CHECK_THROW(m_tool.addRrSet(ROOT_ZONE, ROOT_ZONE, label::NS_RR_TYPE, NDNS_RESP),
+                    ndns::ManagementTool::Error);
+
+  Name zoneName("/ndns-test");
+  zoneName.appendVersion();
+  Zone zone(zoneName);
+  m_dbMgr.insert(zone);
+
+  BOOST_CHECK_THROW(m_tool.addRrSet(ROOT_ZONE, ROOT_ZONE, label::NS_RR_TYPE, NDNS_UNKNOWN),
+                    ndns::ManagementTool::Error);
+  BOOST_CHECK_THROW(m_tool.addRrSet(zoneName, zoneName, label::CERT_RR_TYPE, NDNS_RAW),
+                    ndns::ManagementTool::Error);
+  BOOST_CHECK_THROW(m_tool.addRrSet(ROOT_ZONE, ROOT_ZONE, label::NS_RR_TYPE, NDNS_RAW),
+                    ndns::ManagementTool::Error);
+  BOOST_CHECK_THROW(m_tool.addRrSet(ROOT_ZONE, ROOT_ZONE, label::TXT_RR_TYPE, NDNS_RAW),
+                    ndns::ManagementTool::Error);
+
+  m_dbMgr.remove(zone);
+}
+
+BOOST_FIXTURE_TEST_CASE(AddRrSet2, ManagementToolFixture)
+{
+  Name zoneName("/ndns-test");
+  zoneName.appendVersion();
+  Zone zone(zoneName);
+  uint64_t version = 1234;
+  time::seconds ttl1(4200);
+  time::seconds ttl2(4500);
+  m_tool.createZone(zoneName, ROOT_ZONE, ttl1);
+
+  //add NS NDNS_AUTH and check user-defined ttl
+  Name label1("/net/ndnsim1");
+  BOOST_CHECK_NO_THROW(m_tool.addRrSet(zoneName, label1, label::NS_RR_TYPE, NDNS_AUTH, version,
+                                       {}, DEFAULT_CERT, ttl2));
+  BOOST_CHECK_EQUAL(checkNs(zone, label1, NDNS_AUTH), true);
+  BOOST_CHECK_EQUAL(checkVersion(zone, label1, label::NS_RR_TYPE, version), true);
+  BOOST_CHECK_EQUAL(checkTtl(zone, label1, label::NS_RR_TYPE, ttl2), true);
+
+  //add NS NDNS_RESP and check default ttl
+  Name label2("/net/ndnsim2");
+  BOOST_CHECK_NO_THROW(m_tool.addRrSet(zoneName, label2, label::NS_RR_TYPE, NDNS_RESP, version));
+  BOOST_CHECK_EQUAL(checkNs(zone, label2, NDNS_RESP), true);
+  BOOST_CHECK_EQUAL(checkVersion(zone, label2, label::NS_RR_TYPE, version), true);
+  BOOST_CHECK_EQUAL(checkTtl(zone, label2, label::NS_RR_TYPE, ttl1), true);
+
+  //add TXT NDNS_RESP and check rr
+  std::string test = "oops";
+  BOOST_CHECK_NO_THROW(m_tool.addRrSet(zoneName, label2, label::TXT_RR_TYPE, NDNS_RESP, version,
+                                       {test}));
+  Rrset rrset1(&zone);
+  rrset1.setLabel(label2);
+  rrset1.setType(label::TXT_RR_TYPE);
+  BOOST_CHECK_EQUAL(m_dbMgr.find(rrset1), true);
+
+  Data data1(rrset1.getData());
+  Response re1;
+  Name hint1;
+  BOOST_CHECK_EQUAL(re1.fromData(hint1, zoneName, data1), true);
+  const Block &block = re1.getRrs().front();
+  std::string someString(reinterpret_cast<const char*>(block.value()), block.value_size());
+  BOOST_CHECK_EQUAL(test, someString);
+
+  //add user defined type
+  Name label3("/net/ndnsim3");
+  name::Component type("A");
+  std::string content = "10.10.0.1";
+  m_tool.addRrSet(zoneName, label3, type, NDNS_RAW, version, {content});
+  BOOST_CHECK_EQUAL(checkVersion(zone, label3, type, version), true);
+
+  Rrset rrset2(&zone);
+  rrset2.setLabel(label3);
+  rrset2.setType(type);
+  BOOST_CHECK_EQUAL(m_dbMgr.find(rrset2), true);
+
+  Data data2(rrset2.getData());
+  Response re2;
+  Name hint2;
+  BOOST_CHECK_EQUAL(re2.fromData(hint2, zoneName, data2), true);
+  Block tmp = ndn::dataBlock(ndn::tlv::Content, content.c_str(), content.length());
+  tmp.encode();
+  BOOST_REQUIRE(tmp == re2.getAppContent());
+
+  m_tool.deleteZone(zoneName);
+}
+
+BOOST_FIXTURE_TEST_CASE(AddRrSet3, ManagementToolFixture)
+{
+  // check pre-condition
+  Name zoneName("/ndns-test");
+  zoneName.appendVersion();
+  std::string certPath = TEST_CERTDIR.string();
+  BOOST_CHECK_THROW(m_tool.addRrSet(zoneName, certPath), ndns::ManagementTool::Error);
+
+  m_tool.createZone(zoneName, ROOT_ZONE);
+  BOOST_CHECK_THROW(m_tool.addRrSet(zoneName, certPath), ndns::ManagementTool::Error);
+  m_tool.deleteZone(zoneName);
+}
+
+BOOST_FIXTURE_TEST_CASE(AddRrSet4, ManagementToolFixture)
+{
+  Name parentZoneName("/ndns-test");
+  parentZoneName.appendVersion();
+  Name zoneName = parentZoneName;
+  zoneName.append("/child-zone");
+  Zone zone(parentZoneName);
+  time::seconds ttl1(4200);
+  time::seconds ttl2(4500);
+  m_tool.createZone(zoneName, parentZoneName);
+  m_tool.createZone(parentZoneName, ROOT_ZONE, ttl1);
+
+  //add KSK ID-CERT
+  std::string output = TEST_CERTDIR.string() + "/ss.cert";
+  std::vector<Name> certList;
+  getCertList(zoneName, certList);
+  Name kskCertName;
+  for (std::vector<Name>::iterator it = certList.begin();
+       it != certList.end();
+       it++) {
+    std::string temp = (*it).toUri();
+    size_t found = temp.find("ksk");
+    if (found != std::string::npos) {
+      kskCertName = *it;
+      break;
+    }
+  }
+  m_tool.exportCertificate(kskCertName, output);
+
+  BOOST_CHECK_NO_THROW(m_tool.addRrSet(parentZoneName, output, ttl2));
+  BOOST_CHECK_EQUAL(checkIdCert(zone, kskCertName), true);
+
+  //add data
+  Response re;
+  re.setZone(parentZoneName);
+  re.setQueryType(label::NDNS_ITERATIVE_QUERY);
+  re.setRrLabel(zoneName);
+  re.setRrType(label::NS_RR_TYPE);
+  re.setNdnsType(NDNS_RESP);
+  shared_ptr<Data> data1 = re.toData();
+  m_keyChain.sign(*data1, kskCertName);
+  ndn::io::save(*data1, output);
+
+  //check user-defined ttl and default ttl
+  BOOST_CHECK_NO_THROW(m_tool.addRrSet(parentZoneName, output));
+  BOOST_CHECK_EQUAL(checkTtl(zone, zoneName, label::NS_RR_TYPE, ttl1), true);
+  m_tool.removeRrSet(parentZoneName, zoneName, label::NS_RR_TYPE);
+  BOOST_CHECK_NO_THROW(m_tool.addRrSet(parentZoneName, output, ttl2));
+  BOOST_CHECK_EQUAL(checkTtl(zone, zoneName, label::NS_RR_TYPE, ttl2), true);
+
+  Rrset rrset(&zone);
+  rrset.setLabel(zoneName);
+  rrset.setType(label::NS_RR_TYPE);
+  BOOST_CHECK_EQUAL(m_dbMgr.find(rrset), true);
+
+  Data data2(rrset.getData());
+  BOOST_REQUIRE(*data1 == data2);
+
+  //add KSK ID-CERT with illegal name and convert it
+  Name iZoneName = parentZoneName;
+  iZoneName.append("illegal");
+  Name illegalCertName = m_keyChain.createIdentity(iZoneName);
+  m_tool.exportCertificate(illegalCertName, output);
+  BOOST_CHECK_NO_THROW(m_tool.addRrSet(parentZoneName, output, ttl2));
+
+  Name legalCertName = parentZoneName;
+  legalCertName.append("KEY");
+  legalCertName.append("illegal");
+  legalCertName.append(illegalCertName.getSubName(4));
+  BOOST_CHECK_EQUAL(checkIdCert(zone, legalCertName), true);
+  m_keyChain.deleteIdentity(iZoneName);
+
+  m_tool.deleteZone(zoneName);
+  m_tool.deleteZone(parentZoneName);
+}
+
+BOOST_FIXTURE_TEST_CASE(AddRrSet5, ManagementToolFixture)
+{
+  //check using user provided certificate
+  Name parentZoneName("/ndns-test");
+  parentZoneName.appendVersion();
+  Name zoneName = parentZoneName;
+  zoneName.append("child-zone");
+
+  Name dskName = m_keyChain.generateRsaKeyPair(parentZoneName, false);
+  shared_ptr<IdentityCertificate> dskCert = m_keyChain.selfSign(dskName);
+  m_keyChain.addCertificateAsKeyDefault(*dskCert);
+
+  //check addRrSet1
+  m_tool.createZone(zoneName, parentZoneName);
+  m_tool.createZone(parentZoneName, ROOT_ZONE);
+
+  //add KSK ID-CERT
+  std::string output =  TEST_CERTDIR.string() +  "/ss.cert";
+  std::vector<Name> certList;
+  getCertList(zoneName, certList);
+  Name kskCertName;
+  for (std::vector<Name>::iterator it = certList.begin();
+       it != certList.end();
+       it++) {
+    std::string temp = (*it).toUri();
+    size_t found = temp.find("ksk");
+    if (found != std::string::npos) {
+      kskCertName = *it;
+      break;
+    }
+  }
+  m_tool.exportCertificate(kskCertName, output);
+
+  BOOST_CHECK_NO_THROW(m_tool.addRrSet(parentZoneName, output, time::seconds(4600),
+                                       dskCert->getName()));
+
+  //check addRrSet2
+  Name label1("/net/ndnsim1");
+  BOOST_CHECK_NO_THROW(m_tool.addRrSet(parentZoneName, label1, label::NS_RR_TYPE, NDNS_AUTH, -1, {},
+                                       dskCert->getName()));
+
+  m_tool.deleteZone(zoneName);
+  m_tool.deleteZone(parentZoneName);
+}
+
+BOOST_FIXTURE_TEST_CASE(ListZone, ManagementToolFixture)
+{
+  Name zoneName("/ndns-test/mgmt/123456789");
+
+  m_tool.createZone(zoneName, ROOT_ZONE);
+  Name certName = m_keyChain.getDefaultCertificateNameForIdentity(zoneName);
+  shared_ptr<IdentityCertificate> cert = m_keyChain.getCertificate(certName);
+
+  //add NS with NDNS_RESP
+  Name label2("/ndnsim");
+  uint64_t version = 1234;
+  m_tool.addRrSet(zoneName, label2, label::NS_RR_TYPE, NDNS_RESP, version);
+
+  //add NS with NDNS_AUTH
+  Name label3("/ndnsim/oops");
+  m_tool.addRrSet(zoneName, label3, label::NS_RR_TYPE, NDNS_AUTH, version);
+
+  //add TXT
+  std::string output = TEST_CERTDIR.string() + "/a.rrset";
+  Response re1;
+  re1.setZone(zoneName);
+  re1.setQueryType(label::NDNS_ITERATIVE_QUERY);
+  re1.setRrLabel(label2);
+  re1.setRrType(label::TXT_RR_TYPE);
+  re1.setNdnsType(NDNS_RESP);
+  re1.setVersion(name::Component::fromVersion(version));
+  re1.addRr("First RR");
+  re1.addRr("Second RR");
+  re1.addRr("Last RR");
+  shared_ptr<Data> data1= re1.toData();
+  m_keyChain.sign(*data1, certName);
+  ndn::io::save(*data1, output);
+  m_tool.addRrSet(zoneName, output);
+
+  //add User-Defined
+  name::Component type("A");
+  Response re2;
+  re2.setZone(zoneName);
+  re2.setQueryType(label::NDNS_ITERATIVE_QUERY);
+  re2.setRrLabel(label2);
+  re2.setRrType(type);
+  re2.setNdnsType(NDNS_RESP);
+  re2.setVersion(name::Component::fromVersion(version));
+  re2.addRr("First RR");
+  re2.addRr("Second RR");
+  re2.addRr("Last RR");
+  shared_ptr<Data> data2= re2.toData();
+  m_keyChain.sign(*data2, certName);
+  ndn::io::save(*data2, output);
+  m_tool.addRrSet(zoneName, output);
+
+  output_test_stream testOutput;
+  m_tool.listZone(zoneName, testOutput, true);
+
+  /// @todo check the output
+
+  // BOOST_CHECK(testOutput.
+  //   is_equal(
+  //     "; Zone /ndns-test/mgmt/123456789\n"
+  //     "\n"
+  //     "; rrset=/ndnsim type=A version=%FD%04%D2 signed-by=*\n"
+  //     "/ndnsim             3600  A        vwhGaXJzdCBSUg==\n"
+  //     "/ndnsim             3600  A        vwlTZWNvbmQgUlI=\n"
+  //     "/ndnsim             3600  A        vwdMYXN0IFJS\n"
+  //     "\n"
+  //     "; rrset=/ndnsim type=NS version=%FD%04%D2 signed-by=*\n"
+  //     "/ndnsim             3600  NS\n"
+  //     "\n"
+  //     "; rrset=/ndnsim type=TXT version=%FD%04%D2 signed-by=*\n"
+  //     "/ndnsim             3600  TXT      First RR\n"
+  //     "/ndnsim             3600  TXT      Second RR\n"
+  //     "/ndnsim             3600  TXT      Last RR\n"
+  //     ""
+  //     "/ndnsim/oops        3600  NS       ; content-type=NDNS-Auth version=* signed-by=*\n"
+  //     "/dsk-1416888156106  3600  ID-CERT  ; content-type=NDNS-Raw version=* signed-by=*\n"
+  //     "; Ff0BcjCCAW4wIhgPMjAxNDExMjUwNDAyMzVaGA8yMDE1MTEyNTA0MDIzNVowIjAg\n"
+  //     "; BgNVBCkTGS9uZG5zLXRlc3QvbWdtdC8xMjM0NTY3ODkwggEiMA0GCSqGSIb3DQEB\n"
+  //     "; AQUAA4IBDwAwggEKAoIBAQD8Lsd/kKdcdXTKEhcJpy7M0cnZgpZ3lpQX2Nz8InXN\n"
+  //     "; BkF3b6TsuMSokmDQ78xXNTx0jGUM1g47kQNsk2WTjYgDZUOfpBWz5PZcaO35dUz8\n"
+  //     "; wNGc1lED9A/PbFB4t5NPbZsrThCPw+IvzTYN6A/Dxg9h69zLEEsLWD2PzCkyHQ+F\n"
+  //     "; JjRgzhJPsrl1CoVFSP/bu70xMJVqOwj3GMej6mm0gXXmMv4aEI22jot7+fO07jIy\n"
+  //     "; WUl0fhY33Cgo50YvDeeRsdo+At29OMN8Dd/s2z/6olH0P7IK1/cn++DWcO5zMd1x\n"
+  //     "; zWm+6IoZA6mV1J2O5U0AkbllRVZ+vZPI/lWGzCtXK6jfAgMBAAE=\n"
+  //     ));
+
+  m_tool.deleteZone(zoneName);
+}
+
+BOOST_FIXTURE_TEST_CASE(ListAllZones, ManagementToolFixture)
+{
+  Name zoneName1("/ndns-test1/mgmt/123456789");
+  m_tool.createZone(zoneName1, ROOT_ZONE);
+
+  Name zoneName2("/ndns-test2/mgmt/123456789");
+  m_tool.createZone(zoneName2, ROOT_ZONE);
+
+  Name zoneName3("/ndns-test3/mgmt/123456789");
+  m_tool.createZone(zoneName3, ROOT_ZONE);
+
+  //TODO Check the output
+  // a sample output is like this
+  //  /ndns-test1/mgmt/123456789  ; default-ttl=* default-key=* default-certificate=*
+  //  /ndns-test2/mgmt/123456789  ; default-ttl=* default-key=* default-certificate=*
+  //  /ndns-test3/mgmt/123456789  ; default-ttl=* default-key=* default-certificate=*
+  output_test_stream testOutput;
+  m_tool.listAllZones(testOutput);
+
+  m_tool.deleteZone(zoneName1);
+  m_tool.deleteZone(zoneName2);
+  m_tool.deleteZone(zoneName3);
+}
+
+BOOST_FIXTURE_TEST_CASE(GetRrSet, ManagementToolFixture)
+{
+  Name zoneName("/ndns-test");
+  zoneName.appendVersion();
+  m_tool.createZone(zoneName, ROOT_ZONE);
+
+  Name label("/net/ndnsim2");
+
+  m_tool.addRrSet(zoneName, label, label::NS_RR_TYPE, NDNS_RESP);
+
+  // a sample output is like this
+//  Bv0Bjgc5CAluZG5zLXRlc3QICf0AAAFJ5Sn8HwgETkROUwgDbmV0CAduZG5zaW0y
+//  CAJOUwgJ/QAAAUnlKgXYFAkZBAA27oC0AQEVAr8AFj4bAQEcOQc3CAluZG5zLXRl
+//  c3QICf0AAAFJ5Sn8HwgDS0VZCBFkc2stMTQxNjg4ODk3NTY0NAgHSUQtQ0VSVBf9
+//  AQBj8QOr3vPo1wzuTAwwdF6UEfHmHYxkMor5bw/5Lc6Wpt6SkTb7Ku92/MHedtRD
+//  2UsIhQV+JR7jUGzLVLUuktmrBTT7G9tSioTOVpbtJ7EEYYhcDCV0h1Kefz01AS1O
+//  bUuZbxAWboZCzW6OluTq9Db2c2xEmzE8EzmMQ5zflIL7vQxEigH1kBsvGoMZThOb
+//  aKrfcACfKU3kZQBzyPVbur5PER3dgBjVcdu5aIEXhO3Nf7b22OrPSP8AztZGvkz0
+//  5TSBf7wwxtB6V/aMlDPaKFPgI2mXan729e1JGYZ0OmKhvuPnhT9ApOh9UNSJuhO8
+//  puPJKCOSQHspQHOhnEy9Ee9U
+  output_test_stream testOutput;
+  m_tool.getRrSet(zoneName, label, label::NS_RR_TYPE, testOutput);
+
+  m_tool.deleteZone(zoneName);
+}
+
+BOOST_FIXTURE_TEST_CASE(RemoveRrSet, ManagementToolFixture)
+{
+  Name zoneName("/ndns-test");
+  zoneName.appendVersion();
+  m_tool.createZone(zoneName, ROOT_ZONE);
+  Name label2("/net/ndnsim2");
+  m_tool.addRrSet(zoneName, label2, label::NS_RR_TYPE, NDNS_RESP);
+
+  m_tool.removeRrSet(zoneName, label2, label::NS_RR_TYPE);
+  Zone zone(zoneName);
+  BOOST_CHECK_EQUAL(checkNs(zone, label2, NDNS_RESP), false);
+
+  m_tool.deleteZone(zoneName);
+}
+
+BOOST_FIXTURE_TEST_CASE(DataValidation, ManagementToolFixture)
+{
+  Name subZoneName1 = FAKE_ROOT;
+  subZoneName1.append("net");
+  Name subZoneName2 = subZoneName1;
+  subZoneName2.append("ndnsim");
+
+  // create fake-root zone
+  m_tool.createZone(FAKE_ROOT, ROOT_ZONE);
+
+  // create subZone1 by creating zone, delegating it to ROOT zone
+  m_tool.createZone(subZoneName1, FAKE_ROOT);
+
+  std::string output1 = TEST_CERTDIR.string() + "/ss1.cert";
+  std::vector<Name> certList1;
+  getCertList(subZoneName1, certList1);
+  Name kskCertName1;
+  for (std::vector<Name>::iterator it = certList1.begin();
+       it != certList1.end();
+       it++) {
+    std::string temp = (*it).toUri();
+    size_t found = temp.find("ksk");
+    if (found != std::string::npos) {
+      kskCertName1 = *it;
+      break;
+    }
+  }
+  m_tool.exportCertificate(kskCertName1, output1);
+  m_tool.addRrSet(FAKE_ROOT, output1, time::seconds(4600));
+
+  // create subZone2 by creating zone, delegating it to subZone1
+  m_tool.createZone(subZoneName2, subZoneName1);
+
+  std::string output2 = TEST_CERTDIR.string() + "/ss2.cert";
+  std::vector<Name> certList2;
+  getCertList(subZoneName2, certList2);
+  Name kskCertName2;
+  for (std::vector<Name>::iterator it = certList2.begin();
+       it != certList2.end();
+       it++) {
+    std::string temp = (*it).toUri();
+    size_t found = temp.find("ksk");
+    if (found != std::string::npos) {
+      kskCertName2 = *it;
+      break;
+    }
+  }
+  m_tool.exportCertificate(kskCertName2, output2);
+  m_tool.addRrSet(subZoneName1, output2, time::seconds(4600));
+
+  //simulate the trust chain
+  Data data("test");
+  Name certName = m_keyChain.getDefaultCertificateNameForIdentity(subZoneName2);
+  m_keyChain.sign(data, certName);
+
+  //details of the verification please see the getPublicKeyOfData() function
+  PublicKey pk = getPublicKeyOfData(data);
+  BOOST_CHECK_EQUAL(Validator::verifySignature(data, pk), true);
+
+  m_tool.deleteZone(subZoneName2);
+  m_tool.deleteZone(subZoneName1);
+  m_tool.deleteZone(FAKE_ROOT);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace ndns
+} // namespace ndn
diff --git a/tools/ndns-add-rr-from-file.cpp b/tools/ndns-add-rr-from-file.cpp
new file mode 100644
index 0000000..4fc2066
--- /dev/null
+++ b/tools/ndns-add-rr-from-file.cpp
@@ -0,0 +1,118 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mgmt/management-tool.hpp"
+#include "ndns-label.hpp"
+#include "logger.hpp"
+#include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+
+
+// @todo combine this command with ndns-add-rr
+int
+main(int argc, char* argv[])
+{
+  using std::string;
+  using namespace ndn;
+  using namespace ndns;
+
+  ndn::ndns::log::init();
+  int ttlInt = -1;
+  string zoneStr;
+  string dskStr;
+  string db;
+  string file = "-";
+  try {
+    namespace po = boost::program_options;
+    po::variables_map vm;
+
+    po::options_description options("Generic Options");
+    options.add_options()
+      ("help,h", "print help message")
+      ("db,b", po::value<std::string>(&db), "Set the path of NDNS server database. "
+        "Default: " DEFAULT_DATABASE_PATH "/ndns.db")
+      ;
+
+    po::options_description config("Record Options");
+    config.add_options()
+      ("file,f", po::value<string>(&file), "Path to the data. Default is stdin(-)")
+      ("dsk,d", po::value<std::string>(&dskStr), "Set the name of DSK's certificate. "
+        "Default: use default DSK and its default certificate")
+      ("ttl,a", po::value<int>(&ttlInt), "Set ttl of the rrset. Default: 3600 seconds")
+      ;
+
+    options.add(config);
+
+    po::options_description hidden("Hidden Options");
+    hidden.add_options()
+      ("zone", po::value<string>(&zoneStr), "host zone name")
+      ;
+
+    po::positional_options_description postion;
+    postion.add("zone", 1);
+    postion.add("file", 1);
+
+    po::options_description cmdlineOptions;
+    cmdlineOptions.add(options).add(hidden);
+
+    // po::options_description config_file_options;
+    // config_file_options.add(config).add(hidden);
+
+    po::parsed_options parsed =
+      po::command_line_parser(argc, argv).options(cmdlineOptions).positional(postion).run();
+
+    po::store(parsed, vm);
+    po::notify(vm);
+
+    if (vm.count("help")) {
+      std::cout << "Usage: ndns-add-rr-from-file [-b db] zone [-f file] [-d dskCert] [-a ttl]"
+        " [file]" << std::endl
+                << std::endl;
+      std::cout << options << std::endl;
+      return 0;
+    }
+
+    if (vm.count("zone") == 0) {
+      std::cerr << "Error: zone must be specified" << std::endl;
+      return 1;
+    }
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Parameter Error: " << ex.what() << std::endl;
+    return 1;
+  }
+
+  try {
+    Name zoneName(zoneStr);
+    Name dskName(dskStr);
+    time::seconds ttl;
+    if (ttlInt == -1)
+      ttl = ndns::DEFAULT_CACHE_TTL;
+    else
+      ttl = time::seconds(ttlInt);
+
+    ndn::ndns::ManagementTool tool(db);
+    tool.addRrSet(zoneName, file, ttl, dskName);
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Error: " << ex.what() << std::endl;
+    return 1;
+  }
+}
diff --git a/tools/ndns-add-rr.cpp b/tools/ndns-add-rr.cpp
new file mode 100644
index 0000000..47e7121
--- /dev/null
+++ b/tools/ndns-add-rr.cpp
@@ -0,0 +1,161 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mgmt/management-tool.hpp"
+#include "ndns-label.hpp"
+#include "logger.hpp"
+#include "util/util.hpp"
+
+#include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+
+#include <string>
+
+int
+main(int argc, char* argv[])
+{
+  using std::string;
+  using namespace ndn;
+  using namespace ndns;
+
+  ndn::ndns::log::init();
+  int ttlInt = -1;
+  int versionInt = -1;
+  string zoneStr;
+  Name dsk;
+  string db;
+  string rrLabelStr;
+  string rrTypeStr;
+  string ndnsTypeStr;
+  std::vector<std::string> content;
+  try {
+    namespace po = boost::program_options;
+    po::variables_map vm;
+
+    po::options_description options("Generic Options");
+    options.add_options()
+      ("help,h", "print help message")
+      ("db,b", po::value<std::string>(&db), "Set the path of NDNS server database. "
+        "Default: " DEFAULT_DATABASE_PATH "/ndns.db")
+      ;
+
+    po::options_description config("Record Options");
+    config.add_options()
+      ("content-type,t", po::value<string>(&ndnsTypeStr), "Set the ndnsType of the resource record."
+        "Options: resp|nack|auth|raw (will try guess type by default)")
+      ("dsk,d", po::value<Name>(&dsk), "Set the name of DSK's certificate. "
+        "Default: use default DSK and its default certificate")
+      ("content,c", po::value<std::vector<std::string>>(&content),
+       "Set the content of resource record. Default: empty string")
+      ("ttl,a", po::value<int>(&ttlInt), "Set ttl of the rrset. Default: 3600 seconds")
+      ("version,v", po::value<int>(&ttlInt), "Set version of the rrset. Default: Unix Timestamp")
+      ;
+
+    // add "Record Options" as a separate section
+    options.add(config);
+
+    po::options_description hidden("Hidden Options");
+    hidden.add_options()
+      ("zone", po::value<string>(&zoneStr), "host zone name")
+      ("label", po::value<string>(&rrLabelStr), "label of resource record.")
+      ("type", po::value<string>(&rrTypeStr), "Set the type of resource record.")
+      ;
+
+    po::positional_options_description positional;
+    positional.add("zone", 1);
+    positional.add("label", 1);
+    positional.add("type", 1);
+    positional.add("content", -1);
+
+    po::options_description cmdlineOptions;
+    cmdlineOptions.add(options).add(hidden);
+
+    // po::options_description configFileOptions;
+    // configFileOptions.add(config).add(hidden);
+
+    po::parsed_options parsed =
+      po::command_line_parser(argc, argv).options(cmdlineOptions).positional(positional).run();
+
+    po::store(parsed, vm);
+    po::notify(vm);
+
+
+    if (vm.count("help")) {
+      std::cout << "Usage: ndns-add-rr [options] zone label type [content ...]" << std::endl
+                << std::endl;
+      std::cout << options << std::endl;
+      return 0;
+    }
+
+    if (vm.count("zone") == 0) {
+      std::cerr << "Error: zone, label, and type must be specified" << std::endl;
+      return 1;
+    }
+
+    if (vm.count("label") == 0) {
+      std::cerr << "Error: label and type must be specified" << std::endl;
+      return 1;
+    }
+
+    if (vm.count("type") == 0) {
+      std::cerr << "Error: type must be specified" << std::endl;
+      return 1;
+    }
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Parameter Error: " << ex.what() << std::endl;
+    return 1;
+  }
+
+  try {
+    Name zoneName(zoneStr);
+    Name label(rrLabelStr);
+    name::Component type(rrTypeStr);
+
+    if (ndnsTypeStr.empty()) {
+      if (rrTypeStr == "NS" || rrTypeStr == "TXT")
+        ndnsTypeStr = "resp";
+      else if (rrTypeStr == "ID-CERT") {
+        ndnsTypeStr = "raw";
+      }
+      else {
+        std::cerr << "Error: content type needs to be explicitly set using --content-type option"
+                  << std::endl;
+        return 1;
+      }
+    }
+    NdnsType ndnsType = ndns::toNdnsType(ndnsTypeStr);
+    time::seconds ttl;
+    if (ttlInt == -1)
+      ttl = ndns::DEFAULT_CACHE_TTL;
+    else
+      ttl = time::seconds(ttlInt);
+    uint64_t version = static_cast<uint64_t>(versionInt);
+
+    ndn::ndns::ManagementTool tool(db);
+    tool.addRrSet(zoneName, label, type, ndnsType, version, content, dsk, ttl);
+
+    /// @todo Report success or failure
+    //        May be also show the inserted record in ndns-list-zone format
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Error: " << ex.what() << std::endl;
+    return 1;
+  }
+}
diff --git a/tools/ndns-create-zone.cpp b/tools/ndns-create-zone.cpp
new file mode 100644
index 0000000..0893bc7
--- /dev/null
+++ b/tools/ndns-create-zone.cpp
@@ -0,0 +1,133 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mgmt/management-tool.hpp"
+#include "ndns-label.hpp"
+#include "logger.hpp"
+#include "config.hpp"
+
+#include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+
+int
+main(int argc, char* argv[])
+{
+  using std::string;
+  using namespace ndn;
+  ndn::ndns::log::init();
+  int cacheTtlInt = -1;
+  int certTtlInt = -1;
+  string zoneStr;
+  string parentStr;
+  string dskStr;
+  string kskStr;
+  string db;
+  try {
+    namespace po = boost::program_options;
+    po::variables_map vm;
+
+    po::options_description options("Generic Options");
+    options.add_options()
+      ("help,h", "print help message")
+      ("db,b", po::value<std::string>(&db), "Set the path of NDNS server database. "
+        "Default: " DEFAULT_DATABASE_PATH "/ndns.db")
+      ;
+
+    po::options_description config("Zone Options");
+    config.add_options()
+      ("cacheTtl,a", po::value<int>(&cacheTtlInt), "Set ttl of records of the zone and its "
+        "DSK ID-CERT. Default: 3600 seconds")
+      ("certTtl,e", po::value<int>(&certTtlInt), "Set ttl of DSK and KSK certificates. "
+        "Default: 365 days")
+      ("parent,p", po::value<std::string>(&parentStr), "Set the parent zone of the zone to be "
+        "created. Default: the zone's direct parent")
+      ("dsk,d", po::value<std::string>(&dskStr), "Set the name of DSK's certificate, "
+        "Default: generate new key and certificate")
+      ("ksk,k", po::value<std::string>(&kskStr), "Set the name of KSK's certificate, "
+        "Default: generate new key and certificate")
+      ;
+
+    options.add(config);
+
+    po::options_description hidden("Hidden Options");
+    hidden.add_options()
+      ("zone", po::value<string>(&zoneStr), "name of the zone to be created")
+      ;
+    po::positional_options_description postion;
+    postion.add("zone", 1);
+
+    po::options_description cmdline_options;
+    cmdline_options.add(options).add(hidden);
+
+    // po::options_description config_file_options;
+    // config_file_options.add(config).add(hidden);
+
+    po::parsed_options parsed =
+      po::command_line_parser(argc, argv).options(cmdline_options).positional(postion).run();
+
+    po::store(parsed, vm);
+    po::notify(vm);
+
+    if (vm.count("help")) {
+      std::cout << "Usage: ndns-create-zone [-b db] zone [-a cacheTtl] [-e certTtl] [-p parent] "
+        "[-d dskCert] [-k kskCert]" << std::endl;
+      std::cout << options << std::endl;
+      return 0;
+    }
+
+    if (vm.count("zone") == 0) {
+      std::cerr << "Error: zone must be specified" << std::endl;
+      return 1;
+    }
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Parameter Error: " << ex.what() << std::endl;
+    return 1;
+  }
+
+  try {
+    Name zone(zoneStr);
+    Name parent(parentStr);
+    if (!zone.empty() && parentStr.empty())
+      parent = zone.getPrefix(-1);
+
+    Name ksk(kskStr);
+    Name dsk(dskStr);
+
+    time::seconds cacheTtl;
+    time::seconds certTtl;
+    if (cacheTtlInt == -1)
+      cacheTtl = ndns::DEFAULT_CACHE_TTL;
+    else
+      cacheTtl = time::seconds(cacheTtlInt);
+
+    if (certTtlInt == -1)
+      certTtl = ndns::DEFAULT_CERT_TTL;
+    else
+      certTtl = time::seconds(certTtlInt);
+
+    ndn::ndns::ManagementTool tool(db);
+    tool.createZone(zone, parent, cacheTtl, certTtl, ksk, dsk);
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Error: " << ex.what() << std::endl;
+    return 1;
+  }
+}
diff --git a/tools/ndns-delete-zone.cpp b/tools/ndns-delete-zone.cpp
new file mode 100644
index 0000000..12bc7f3
--- /dev/null
+++ b/tools/ndns-delete-zone.cpp
@@ -0,0 +1,88 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mgmt/management-tool.hpp"
+#include "ndns-label.hpp"
+#include "logger.hpp"
+#include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+
+int
+main(int argc, char* argv[])
+{
+  using std::string;
+  using namespace ndn;
+  ndn::ndns::log::init();
+  string zoneStr;
+  string db;
+  try {
+    namespace po = boost::program_options;
+    po::variables_map vm;
+
+    po::options_description options("Generic Options");
+    options.add_options()
+      ("help,h", "print help message")
+      ("db,b", po::value<std::string>(&db), "Set the path of NDNS server database."
+        "Default: " DEFAULT_DATABASE_PATH "/ndns.db")
+      ;
+
+    po::options_description hidden("Hidden Options");
+    hidden.add_options()
+      ("zone", po::value<string>(&zoneStr), "name of the zone to be deleted")
+      ;
+    po::positional_options_description postion;
+    postion.add("zone", 1);
+
+    po::options_description cmdline_options;
+    cmdline_options.add(options).add(hidden);
+
+    po::parsed_options parsed =
+      po::command_line_parser(argc, argv).options(cmdline_options).positional(postion).run();
+
+    po::store(parsed, vm);
+    po::notify(vm);
+
+    if (vm.count("help")) {
+      std::cout << "Usage: ndns-delete-zone zone [-b db]" << std::endl;
+      std::cout << options << std::endl;
+      return 0;
+    }
+
+    if (vm.count("zone") == 0) {
+      std::cerr << "Error: zone must be specified" << std::endl;
+      return 1;
+    }
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Parameter Error: " << ex.what() << std::endl;
+    return 1;
+  }
+
+  try {
+    Name zone(zoneStr);
+
+    ndn::ndns::ManagementTool tool(db);
+    tool.deleteZone(zone);
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Error: " << ex.what() << std::endl;
+    return 1;
+  }
+}
diff --git a/tools/ndns-export-certificate.cpp b/tools/ndns-export-certificate.cpp
new file mode 100644
index 0000000..701aa20
--- /dev/null
+++ b/tools/ndns-export-certificate.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mgmt/management-tool.hpp"
+#include "ndns-label.hpp"
+#include "logger.hpp"
+#include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+
+int
+main(int argc, char* argv[])
+{
+  using std::string;
+  using namespace ndn;
+  using namespace ndns;
+
+  ndn::ndns::log::init();
+  string certStr;
+  string db;
+  string output = "-";
+  try {
+    namespace po = boost::program_options;
+    po::variables_map vm;
+
+    po::options_description options("Generic Options");
+    options.add_options()
+      ("help,h", "print help message")
+      ("db,b", po::value<std::string>(&db), "Set the path of NDNS server database. "
+        "Default: " DEFAULT_DATABASE_PATH "/ndns.db");
+
+    po::options_description config("Output Options");
+    config.add_options()
+      ("output,o", po::value<string>(&output), "Set the output path of the to be export cert. "
+        "Default: stdout(-)")
+      ;
+
+    options.add(config);
+
+    po::options_description hidden("Hidden Options");
+    hidden.add_options()
+      ("certName", po::value<string>(&certStr), "the name of the certificate")
+      ;
+
+    po::positional_options_description postion;
+    postion.add("certName", 1);
+
+    po::options_description cmdline_options;
+    cmdline_options.add(options).add(hidden);
+
+    // po::options_description config_file_options;
+    // config_file_options.add(config).add(hidden);
+
+    po::parsed_options parsed =
+      po::command_line_parser(argc, argv).options(cmdline_options).positional(postion).run();
+
+    po::store(parsed, vm);
+    po::notify(vm);
+
+    if (vm.count("help")) {
+      std::cout << "Usage: ndns-export-certificate [-b db] certificateName [-o output] "
+                << std::endl;
+      std::cout << options << std::endl;
+      return 0;
+    }
+
+    if (vm.count("certName") == 0) {
+      std::cerr << "Error: certificate name must be specified" << std::endl;
+      return 1;
+    }
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Parameter Error: " << ex.what() << std::endl;
+    return 1;
+  }
+
+  try {
+    Name certName(certStr);
+
+    ndn::ndns::ManagementTool tool(db);
+    tool.exportCertificate(certName, output);
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Error: " << ex.what() << std::endl;
+    return 1;
+  }
+}
diff --git a/tools/ndns-get-rr.cpp b/tools/ndns-get-rr.cpp
new file mode 100644
index 0000000..bdf86e0
--- /dev/null
+++ b/tools/ndns-get-rr.cpp
@@ -0,0 +1,109 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mgmt/management-tool.hpp"
+#include "ndns-label.hpp"
+#include "logger.hpp"
+#include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+
+int
+main(int argc, char* argv[])
+{
+  using std::string;
+  using namespace ndn;
+  using namespace ndns;
+
+  ndn::ndns::log::init();
+  string zoneStr;
+  string db;
+  string rrLabelStr;
+  string rrTypeStr;
+  try {
+    namespace po = boost::program_options;
+    po::variables_map vm;
+
+    po::options_description options("Generic Options");
+    options.add_options()
+      ("help,h", "print help message")
+      ("db,b", po::value<std::string>(&db), "Set the path of NDNS server database. "
+        "Default: " DEFAULT_DATABASE_PATH "/ndns.db")
+      ;
+
+    po::options_description hidden("Hidden Options");
+    hidden.add_options()
+      ("zone", po::value<string>(&zoneStr), "host zone name")
+      ("label", po::value<string>(&rrLabelStr), "label of the resource record.")
+      ("type", po::value<string>(&rrTypeStr), "type of the resource record.")
+      ;
+
+    po::positional_options_description postion;
+    postion.add("zone", 1);
+    postion.add("label", 1);
+    postion.add("type", 1);
+
+    po::options_description cmdline_options;
+    cmdline_options.add(options).add(hidden);
+
+    po::parsed_options parsed =
+      po::command_line_parser(argc, argv).options(cmdline_options).positional(postion).run();
+
+    po::store(parsed, vm);
+    po::notify(vm);
+
+    if (vm.count("help")) {
+      std::cout << "Usage: ndns-get-rr zone label type [-b db]" << std::endl;
+      std::cout << options << std::endl;
+      return 0;
+    }
+
+    if (vm.count("zone") == 0) {
+      std::cerr << "Error: zone must be specified" << std::endl;
+      return 1;
+    }
+
+    if (vm.count("label") == 0) {
+      std::cerr << "Error: label must be specified" << std::endl;
+      return 1;
+    }
+
+    if (vm.count("type") == 0) {
+      std::cerr << "Error: type must be specified" << std::endl;
+      return 1;
+    }
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Parameter Error: " << ex.what() << std::endl;
+    return 1;
+  }
+
+  try {
+    Name zoneName(zoneStr);
+    Name label(rrLabelStr);
+    name::Component type(rrTypeStr);
+
+    ndn::ndns::ManagementTool tool(db);
+    tool.getRrSet(zoneName, label, type, std::cout);
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Error: " << ex.what() << std::endl;
+    return 1;
+  }
+}
diff --git a/tools/ndns-list-all-zones.cpp b/tools/ndns-list-all-zones.cpp
new file mode 100644
index 0000000..98c33f3
--- /dev/null
+++ b/tools/ndns-list-all-zones.cpp
@@ -0,0 +1,80 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mgmt/management-tool.hpp"
+#include "ndns-label.hpp"
+#include "logger.hpp"
+#include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+#include <iostream>
+
+int
+main(int argc, char* argv[])
+{
+  using std::string;
+  using namespace ndn;
+  using namespace ndns;
+
+  ndn::ndns::log::init();
+  string zoneStr;
+  string db;
+  try {
+    namespace po = boost::program_options;
+    po::variables_map vm;
+
+    po::options_description options("Generic Options");
+    options.add_options()
+      ("help,h", "print help message")
+      ("db,b", po::value<std::string>(&db), "Set the path of NDNS server database. "
+        "Default: " DEFAULT_DATABASE_PATH "/ndns.db")
+      ;
+
+    po::positional_options_description postion;
+    postion.add("zone", 1);
+
+    po::options_description cmdline_options;
+    cmdline_options.add(options);
+
+    po::parsed_options parsed =
+      po::command_line_parser(argc, argv).options(cmdline_options).positional(postion).run();
+
+    po::store(parsed, vm);
+    po::notify(vm);
+
+    if (vm.count("help")) {
+      std::cout << "Usage: ndns-list-all-zones [-b db]" << std::endl;
+      std::cout << options << std::endl;
+      return 0;
+    }
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Parameter Error: " << ex.what() << std::endl;
+    return 1;
+  }
+
+  try {
+    ndn::ndns::ManagementTool tool(db);
+    tool.listAllZones(std::cout);
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Error: " << ex.what() << std::endl;
+    return 1;
+  }
+}
diff --git a/tools/ndns-list-zone.cpp b/tools/ndns-list-zone.cpp
new file mode 100644
index 0000000..f1a85a2
--- /dev/null
+++ b/tools/ndns-list-zone.cpp
@@ -0,0 +1,107 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mgmt/management-tool.hpp"
+#include "ndns-label.hpp"
+#include "logger.hpp"
+#include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+#include <iostream>
+
+int
+main(int argc, char* argv[])
+{
+  using std::string;
+  using namespace ndn;
+  using namespace ndns;
+
+  ndn::ndns::log::init();
+  string zoneStr;
+  string db;
+  bool printRaw = false;
+  try {
+    namespace po = boost::program_options;
+    po::variables_map vm;
+
+    po::options_description options("Generic Options");
+    options.add_options()
+      ("help,h", "print help message")
+      ("db,b", po::value<std::string>(&db), "Set the path of NDNS server database. "
+        "Default: " DEFAULT_DATABASE_PATH "/ndns.db");
+
+    po::options_description config("Output Options");
+    config.add_options()
+      ("printRaw,p", "Set to print raw data")
+      ;
+
+    options.add(config);
+
+    po::options_description hidden("Hidden Options");
+    hidden.add_options()
+      ("zone", po::value<string>(&zoneStr), "zone name to investigate")
+      ;
+
+    po::positional_options_description positional;
+    positional.add("zone", 1);
+
+    po::options_description cmdlineOptions;
+    cmdlineOptions.add(options).add(hidden);
+
+    // po::options_description config_file_options;
+    // config_file_options.add(config).add(hidden);
+
+    po::parsed_options parsed =
+      po::command_line_parser(argc, argv).options(cmdlineOptions).positional(positional).run();
+
+    po::store(parsed, vm);
+    po::notify(vm);
+
+    if (vm.count("help")) {
+      std::cout << "Usage: ndns-list-zone zone [-b db] [-p printRaw]" << std::endl
+                << std::endl;
+      std::cout << options << std::endl;
+      return 0;
+    }
+
+    if (vm.count("zone") == 0) {
+      std::cerr << "Error: zone must be specified" << std::endl;
+      return 1;
+    }
+
+    if (vm.count("printRaw") != 0) {
+      printRaw = true;
+    }
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Parameter Error: " << ex.what() << std::endl;
+    return 1;
+  }
+
+  try {
+    Name zoneName(zoneStr);
+
+    ndn::ndns::ManagementTool tool(db);
+    tool.listZone(zoneName, std::cout, printRaw);
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Error: " << ex.what() << std::endl;
+    return 1;
+  }
+}
diff --git a/tools/ndns-remove-rr.cpp b/tools/ndns-remove-rr.cpp
new file mode 100644
index 0000000..a3fdf89
--- /dev/null
+++ b/tools/ndns-remove-rr.cpp
@@ -0,0 +1,115 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mgmt/management-tool.hpp"
+#include "ndns-label.hpp"
+#include "logger.hpp"
+#include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+
+int
+main(int argc, char* argv[])
+{
+  using std::string;
+  using namespace ndn;
+  using namespace ndns;
+
+  ndn::ndns::log::init();
+  string zoneStr;
+  string db;
+  string rrLabelStr;
+  string rrTypeStr;
+  try {
+    namespace po = boost::program_options;
+    po::variables_map vm;
+
+    po::options_description options("Generic Options");
+    options.add_options()
+      ("help,h", "print help message")
+      ("db,b", po::value<std::string>(&db), "Set the path of NDNS server database. "
+        "Default: " DEFAULT_DATABASE_PATH "/ndns.db");
+
+    po::options_description hidden("Hidden Options");
+    hidden.add_options()
+      ("zone", po::value<string>(&zoneStr), "host zone name")
+      ("label", po::value<string>(&rrLabelStr), "label of the resource record.")
+      ("type", po::value<string>(&rrTypeStr), "type of the resource record.")
+      ;
+
+    po::positional_options_description positional;
+    positional.add("zone", 1);
+    positional.add("label", 1);
+    positional.add("type", 1);
+
+    po::options_description cmdlineOptions;
+    cmdlineOptions.add(options).add(hidden);
+
+    // po::options_description configFileOptions;
+    // config_file_options.add(config).add(hidden);
+
+    po::parsed_options parsed =
+      po::command_line_parser(argc, argv).options(cmdlineOptions).positional(positional).run();
+
+    po::store(parsed, vm);
+    po::notify(vm);
+
+    if (vm.count("help")) {
+      std::cout << "Usage: ndns-remove-rr [-b db] zone label type" << std::endl
+                << std::endl;
+      std::cout << options << std::endl;
+      return 0;
+    }
+
+    if (vm.count("zone") == 0) {
+      std::cerr << "Error: zone, label, and type must be specified" << std::endl;
+      return 1;
+    }
+
+    if (vm.count("label") == 0) {
+      std::cerr << "Error: label and type must be specified" << std::endl;
+      return 1;
+    }
+
+    if (vm.count("type") == 0) {
+      std::cerr << "Error: type must be specified" << std::endl;
+      return 1;
+    }
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Parameter Error: " << ex.what() << std::endl;
+    return 1;
+  }
+
+  try {
+    Name zoneName(zoneStr);
+    Name label(rrLabelStr);
+    name::Component type(rrTypeStr);
+
+    ndn::ndns::ManagementTool tool(db);
+    tool.removeRrSet(zoneName, label, type);
+
+    /// @todo Report how many records have been removed
+    //        (or that the record was removed or record wasn't found)
+  }
+  catch (const std::exception& ex) {
+    std::cerr << "Error: " << ex.what() << std::endl;
+    return 1;
+  }
+}