conf+security: accommodate certificate name in KeyLocator

refs #5195

Change-Id: I88709f891fe78fc9f2699bc021d35ca72ebc6850
diff --git a/nlsr.conf b/nlsr.conf
index fd2ad23..bfed00b 100644
--- a/nlsr.conf
+++ b/nlsr.conf
@@ -4,7 +4,7 @@
 {
   ; mandatory configuration command section network, site and router
 
-  network /ndn/         ; name of the network the router belongs to in ndn URI format
+  network /ndn         ; name of the network the router belongs to in ndn URI format
   site /edu/memphis    ; name of the site the router belongs to in ndn URI format
   router /%C1.Router/cs/pollux    ; name of the router in ndn URI format
 
@@ -150,7 +150,7 @@
           type name
           hyper-relation
           {
-            k-regex ^([^<KEY><nlsr>]*)<nlsr><KEY><>$
+            k-regex ^([^<KEY><nlsr>]*)<nlsr><KEY><>{1,3}$
             k-expand \\1
             h-relation equal
             p-regex ^([^<nlsr><INFO>]*)<nlsr><INFO><><>$
@@ -178,7 +178,7 @@
           type name
           hyper-relation
           {
-            k-regex ^([^<KEY><nlsr>]*)<nlsr><KEY><>$
+            k-regex ^([^<KEY><nlsr>]*)<nlsr><KEY><>{1,3}$
             k-expand \\1
             h-relation equal
             ; the last four components in the prefix should be <lsaType><seqNo><version><segmentNo>
@@ -235,7 +235,7 @@
           type name
           hyper-relation
           {
-            k-regex ^([^<KEY><%C1.Operator>]*)<%C1.Operator>[^<KEY>]*<KEY><>$
+            k-regex ^([^<KEY><%C1.Operator>]*)<%C1.Operator>[^<KEY>]*<KEY><>{1,3}$
             k-expand \\1
             h-relation equal
             p-regex ^([^<KEY><%C1.Router>]*)<%C1.Router>[^<KEY>]*<KEY><><><>$
@@ -288,7 +288,7 @@
         key-locator
         {
           type name
-          regex ^([^<KEY><%C1.Operator>]*)<%C1.Operator>[^<KEY>]*<KEY><>$
+          regex ^([^<KEY><%C1.Operator>]*)<%C1.Operator>[^<KEY>]*<KEY><>{1,3}$
         }
       }
     }
diff --git a/src/conf-parameter.cpp b/src/conf-parameter.cpp
index e313b1f..205c67c 100644
--- a/src/conf-parameter.cpp
+++ b/src/conf-parameter.cpp
@@ -20,6 +20,7 @@
 
 #include "conf-parameter.hpp"
 #include "logger.hpp"
+#include <ndn-cxx/security/signing-helpers.hpp>
 
 namespace nlsr {
 
@@ -118,69 +119,38 @@
   m_prefixUpdateValidator.loadAnchor("Authoritative-Certificate", ndn::security::Certificate(cert));
 }
 
-std::shared_ptr<ndn::security::Certificate>
+ndn::optional<ndn::security::Certificate>
 ConfParameter::initializeKey()
 {
+  using namespace ndn::security;
   NLSR_LOG_DEBUG("Initializing Key ...");
 
-  ndn::Name nlsrInstanceName(m_routerPrefix);
-  nlsrInstanceName.append("nlsr");
-
+  Identity routerIdentity;
   try {
-    m_keyChain.deleteIdentity(m_keyChain.getPib().getIdentity(nlsrInstanceName));
+    routerIdentity = m_keyChain.getPib().getIdentity(m_routerPrefix);
   }
-  catch (const std::exception& e) {
-    NLSR_LOG_WARN(e.what());
-  }
-
-  ndn::security::Identity nlsrInstanceIdentity;
-  try {
-    nlsrInstanceIdentity = m_keyChain.createIdentity(nlsrInstanceName);
-  }
-  catch (const std::exception& e) {
-    NLSR_LOG_ERROR(e.what());
-    NLSR_LOG_ERROR("Unable to create identity, NLSR will run without security!");
-    NLSR_LOG_ERROR("Can be ignored if running in non-production environments.");
-    return nullptr;
-  }
-  auto certificate = std::make_shared<ndn::security::Certificate>();
-  auto nlsrInstanceKey = nlsrInstanceIdentity.getDefaultKey();
-  ndn::Name certificateName = nlsrInstanceKey.getName();
-  certificateName.append("NA");
-  certificateName.appendVersion();
-
-  certificate->setName(certificateName);
-
-  // set metainfo
-  certificate->setContentType(ndn::tlv::ContentType_Key);
-  certificate->setFreshnessPeriod(365_days);
-
-  // set content
-  certificate->setContent(nlsrInstanceKey.getPublicKey());
-
-  // set signature-info
-  ndn::SignatureInfo signatureInfo;
-  signatureInfo.setValidityPeriod(ndn::security::ValidityPeriod(ndn::time::system_clock::TimePoint(),
-                                                                ndn::time::system_clock::now()
-                                                                + 365_days));
-
-  try {
-    m_keyChain.sign(*certificate,
-                    ndn::security::SigningInfo(m_keyChain.getPib().getIdentity(m_routerPrefix))
-                                               .setSignatureInfo(signatureInfo));
-  }
-  catch (const std::exception& e) {
-    NLSR_LOG_ERROR("Router's " << e.what() << ", NLSR is running without security. " <<
+  catch (const Pib::Error&) {
+    NLSR_LOG_ERROR("Router identity " << m_routerPrefix << " not found. "
+                   "NLSR is running without security. "
                    "If security is enabled in the configuration, NLSR will not converge.");
-
+    return ndn::nullopt;
   }
 
-  m_signingInfo = ndn::security::SigningInfo(ndn::security::SigningInfo::SIGNER_TYPE_ID,
-                                             nlsrInstanceName);
+  auto instanceName = ndn::Name(m_routerPrefix).append("nlsr");
+  try {
+    m_keyChain.deleteIdentity(m_keyChain.getPib().getIdentity(instanceName));
+  }
+  catch (const Pib::Error&) {
+    // old instance identity does not exist
+  }
 
-  loadCertToValidator(*certificate);
+  auto key = m_keyChain.createIdentity(instanceName).getDefaultKey();
+  auto cert = m_keyChain.makeCertificate(key, signingByIdentity(routerIdentity));
+  m_keyChain.setDefaultCertificate(key, cert);
 
-  return certificate;
+  m_signingInfo = signingByCertificate(cert);
+  loadCertToValidator(cert);
+  return cert;
 }
 
 } // namespace nlsr
diff --git a/src/conf-parameter.hpp b/src/conf-parameter.hpp
index 57dd2c2..9989803 100644
--- a/src/conf-parameter.hpp
+++ b/src/conf-parameter.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2021,  The University of Memphis,
+ * Copyright (c) 2014-2022,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -475,7 +475,7 @@
     return m_keyChain;
   }
 
-  std::shared_ptr<ndn::security::Certificate>
+  ndn::optional<ndn::security::Certificate>
   initializeKey();
 
   void
diff --git a/src/security/certificate-store.cpp b/src/security/certificate-store.cpp
index 9fcaf84..f679fb1 100644
--- a/src/security/certificate-store.cpp
+++ b/src/security/certificate-store.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2021,  The University of Memphis,
+ * Copyright (c) 2014-2022,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -55,12 +55,31 @@
 }
 
 const ndn::security::Certificate*
-CertificateStore::find(const ndn::Name& keyName) const
+CertificateStore::find(const ndn::Name& name) const
+{
+  if (ndn::security::Certificate::isValidName(name)) {
+    return findByCertName(name);
+  }
+  return findByKeyName(name);
+}
+
+const ndn::security::Certificate*
+CertificateStore::findByKeyName(const ndn::Name& keyName) const
 {
   auto it = m_certificates.find(keyName);
   return it != m_certificates.end() ? &it->second : nullptr;
 }
 
+const ndn::security::Certificate*
+CertificateStore::findByCertName(const ndn::Name& certName) const
+{
+  auto found = findByKeyName(ndn::security::extractKeyNameFromCertName(certName));
+  if (found == nullptr || found->getName() != certName) {
+    return nullptr;
+  }
+  return found;
+}
+
 void
 CertificateStore::clear()
 {
@@ -113,7 +132,7 @@
 }
 
 void
-CertificateStore::onKeyInterest(const ndn::Name& name, const ndn::Interest& interest)
+CertificateStore::onKeyInterest(const ndn::Name&, const ndn::Interest& interest)
 {
   NLSR_LOG_DEBUG("Got interest for certificate. Interest: " << interest.getName());
 
diff --git a/src/security/certificate-store.hpp b/src/security/certificate-store.hpp
index 79a0cf7..2a47caa 100644
--- a/src/security/certificate-store.hpp
+++ b/src/security/certificate-store.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2021,  The University of Memphis,
+ * Copyright (c) 2014-2022,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -44,23 +44,24 @@
  */
 class CertificateStore
 {
-
 public:
   CertificateStore(ndn::Face& face, ConfParameter& confParam, Lsdb& lsdb);
 
   void
   insert(const ndn::security::Certificate& certificate);
 
-  /*! \brief Find a certificate
+  /*!
+   * \brief Find a certificate
+   * \param name Either key name or certificate name.
    *
    * Find a certificate that NLSR has. First it checks against the
    * certificates this NLSR claims to be authoritative for, usually
    * something like this specific router's certificate, and then
    * checks the cache of certificates it has already fetched. If none
    * can be found, it will return an null pointer.
- */
+   */
   const ndn::security::Certificate*
-  find(const ndn::Name& keyName) const;
+  find(const ndn::Name& name) const;
 
   /*! \brief Retrieves the chain of certificates from Validator's cache and
    *   store them in Nlsr's own CertificateStore.
@@ -73,6 +74,12 @@
   afterFetcherSignalEmitted(const ndn::Data& lsaSegment);
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  const ndn::security::Certificate*
+  findByKeyName(const ndn::Name& keyName) const;
+
+  const ndn::security::Certificate*
+  findByCertName(const ndn::Name& certName) const;
+
   void
   clear();
 
diff --git a/tests/security/test-certificate-store.cpp b/tests/security/test-certificate-store.cpp
index ffb94d1..216aba5 100644
--- a/tests/security/test-certificate-store.cpp
+++ b/tests/security/test-certificate-store.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2021,  The University of Memphis,
+ * Copyright (c) 2014-2022,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -59,26 +59,21 @@
     opIdentity = addSubCertificate(opIdentityName, siteIdentity);
     routerId = addSubCertificate(routerIdName, opIdentity);
 
-    auto certificate = conf.initializeKey();
-    if (certificate) {
-      certStore.insert(*certificate);
-    };
+    auto instanceCert = conf.initializeKey();
+    BOOST_REQUIRE(!!instanceCert);
+    certStore.insert(*instanceCert);
+    instanceCertName = instanceCert->getName();
 
     // Create certificate and load it to the validator
     // previously this was done by in nlsr ctor
-    conf.loadCertToValidator(rootId.getDefaultKey().getDefaultCertificate());
-    conf.loadCertToValidator(siteIdentity.getDefaultKey().getDefaultCertificate());
-    conf.loadCertToValidator(opIdentity.getDefaultKey().getDefaultCertificate());
-    conf.loadCertToValidator(routerId.getDefaultKey().getDefaultCertificate());
-
-    std::ifstream inputFile;
-    inputFile.open(std::string("nlsr.conf"));
-
-    BOOST_REQUIRE(inputFile.is_open());
+    for (const auto& id : {rootId, siteIdentity, opIdentity, routerId}) {
+      const auto& cert = id.getDefaultKey().getDefaultCertificate();
+      conf.loadCertToValidator(cert);
+      certStore.insert(cert);
+    }
 
     boost::property_tree::ptree pt;
-
-    boost::property_tree::read_info(inputFile, pt);
+    boost::property_tree::read_info("nlsr.conf", pt);
 
     // Load security section and file name
     for (const auto& tn : pt) {
@@ -88,9 +83,8 @@
         break;
       }
     }
-    inputFile.close();
 
-    this->advanceClocks(ndn::time::milliseconds(20));
+    advanceClocks(20_ms);
   }
 
 public:
@@ -114,6 +108,7 @@
 
   ndn::Name rootIdName, siteIdentityName, opIdentityName, routerIdName;
   ndn::security::pib::Identity rootId, siteIdentity, opIdentity, routerId;
+  ndn::Name instanceCertName;
 
   Nlsr nlsr;
   Lsdb& lsdb;
@@ -136,12 +131,14 @@
   ndn::Name certKey = certificate.getKeyName();
 
   BOOST_CHECK(certStore.find(certKey) == nullptr);
+  BOOST_CHECK(certStore.find(certificate.getName()) == nullptr);
 
   // Certificate should be retrievable from the CertificateStore
   certStore.insert(certificate);
   conf.loadCertToValidator(certificate);
 
   BOOST_CHECK(certStore.find(certKey) != nullptr);
+  BOOST_CHECK(certStore.find(certificate.getName()) != nullptr);
 
   lsdb.expressInterest(certKey, 0);
 
@@ -149,6 +146,41 @@
   checkForInterest(certKey);
 }
 
+BOOST_AUTO_TEST_CASE(RetrieveCert)
+{
+  ndn::util::DummyClientFace consumer(m_ioService);
+  consumer.linkTo(face);
+
+  auto checkRetrieve = [&] (const ndn::Name& interestName, bool canBePrefix, const ndn::Name& dataName) {
+    ndn::Interest interest(interestName);
+    interest.setCanBePrefix(canBePrefix);
+    BOOST_TEST_CONTEXT(interest) {
+      bool hasData = false;
+      consumer.expressInterest(interest,
+        [&] (const auto&, const auto& data) {
+          BOOST_CHECK(!hasData);
+          hasData = true;
+          BOOST_CHECK_EQUAL(data.getName(), dataName);
+        },
+        [&] (const auto&, const auto&) { BOOST_ERROR("unexpected Nack"); },
+        [&] (const auto&) { BOOST_ERROR("unexpected timeout"); }
+      );
+      advanceClocks(10_ms, 2);
+      BOOST_CHECK(hasData);
+    }
+  };
+
+  for (const auto& id : {siteIdentity, opIdentity, routerId}) {
+    auto key = id.getDefaultKey();
+    auto cert = key.getDefaultCertificate();
+    checkRetrieve(key.getName(), true, cert.getName());
+    checkRetrieve(cert.getName(), false, cert.getName());
+  }
+
+  checkRetrieve(ndn::security::extractKeyNameFromCertName(instanceCertName), true, instanceCertName);
+  checkRetrieve(instanceCertName, false, instanceCertName);
+}
+
 BOOST_AUTO_TEST_CASE(TestKeyPrefixRegistration)
 {
   // check if nlsrKeyPrefix is registered
@@ -202,12 +234,13 @@
   // Make NLSR validate data signed by its own key
   conf.getValidator().validate(data,
                                  [] (const ndn::Data&) { BOOST_CHECK(true); },
-                                 [] (const ndn::Data&, const ndn::security::ValidationError&) {
-                                   BOOST_CHECK(false);
+                                 [] (const ndn::Data&, const ndn::security::ValidationError& e) {
+                                   BOOST_ERROR(e);
                                  });
 
   lsdb.emitSegmentValidatedSignal(data);
-  const auto keyName = data.getSignatureInfo().getKeyLocator().getName();
+  auto certName = data.getSignatureInfo().getKeyLocator().getName();
+  auto keyName = ndn::security::extractKeyNameFromCertName(certName);
   BOOST_CHECK(certStore.find(keyName) != nullptr);
 
   // testing a callback after segment validation signal from lsdb
diff --git a/tests/test-lsa-rule.cpp b/tests/test-lsa-rule.cpp
index 2b6faf4..557b540 100644
--- a/tests/test-lsa-rule.cpp
+++ b/tests/test-lsa-rule.cpp
@@ -65,21 +65,15 @@
 
     saveCertificate(rootId, ROOT_CERT_PATH.string());
 
-    confParam.loadCertToValidator(rootId.getDefaultKey().getDefaultCertificate());
-    confParam.loadCertToValidator(siteIdentity.getDefaultKey().getDefaultCertificate());
-    confParam.loadCertToValidator(opIdentity.getDefaultKey().getDefaultCertificate());
-    confParam.loadCertToValidator(routerId.getDefaultKey().getDefaultCertificate());
+    for (const auto& id : {rootId, siteIdentity, opIdentity, routerId}) {
+      const auto& cert = id.getDefaultKey().getDefaultCertificate();
+      confParam.loadCertToValidator(cert);
+    }
 
     // Loading the security section's validator part into the validator
     // See conf file processor for more details
-    std::ifstream inputFile;
-    inputFile.open(std::string("nlsr.conf"));
-
-    BOOST_REQUIRE(inputFile.is_open());
-
     boost::property_tree::ptree pt;
-
-    boost::property_tree::read_info(inputFile, pt);
+    boost::property_tree::read_info("nlsr.conf", pt);
 
     // Loads section and file name
     for (const auto& tn : pt) {
@@ -89,10 +83,8 @@
         break;
       }
     }
-    inputFile.close();
 
-    this->advanceClocks(ndn::time::milliseconds(10));
-
+    this->advanceClocks(10_ms);
     face.sentInterests.clear();
    }
 
@@ -126,7 +118,7 @@
   lsaDataName.appendNumber(1).appendNumber(1);
 
   ndn::Data data(lsaDataName);
-  data.setFreshnessPeriod(ndn::time::seconds(10));
+  data.setFreshnessPeriod(10_s);
 
   // Sign data with NLSR's key
   m_keyChain.sign(data, confParam.getSigningInfo());
@@ -134,8 +126,8 @@
   // Make NLSR validate data signed by its own key
   confParam.getValidator().validate(data,
                                     [] (const Data&) { BOOST_CHECK(true); },
-                                    [] (const Data&, const ndn::security::ValidationError&) {
-                                      BOOST_CHECK(false);
+                                    [] (const Data&, const ndn::security::ValidationError& e) {
+                                      BOOST_ERROR(e);
                                     });
 }