security: refactor CertificateStore class

Refs: #5075

Change-Id: I8ab92012b3acf405503ab33c9320463accc682a9
diff --git a/src/security/certificate-store.cpp b/src/security/certificate-store.cpp
new file mode 100644
index 0000000..aa3ae32
--- /dev/null
+++ b/src/security/certificate-store.cpp
@@ -0,0 +1,179 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2020,  The University of Memphis,
+ *                           Regents of the University of California,
+ *                           Arizona Board of Regents.
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR 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.
+ *
+ * NLSR 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
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "certificate-store.hpp"
+#include "conf-parameter.hpp"
+#include "logger.hpp"
+
+#include <ndn-cxx/util/io.hpp>
+
+namespace nlsr {
+namespace security {
+
+INIT_LOGGER(CertificateStore);
+
+CertificateStore::CertificateStore(ndn::Face& face, ConfParameter& confParam, Lsdb& lsdb)
+  : m_face(face)
+  , m_confParam(confParam)
+  , m_lsdb(lsdb)
+  , m_validator(m_confParam.getValidator())
+  , m_afterSegmentValidatedConnection(m_lsdb.afterSegmentValidatedSignal.connect(
+                                      std::bind(&CertificateStore::afterFetcherSignalEmitted,
+                                                this, _1)))
+{
+  for (const auto& x: confParam.getIdCerts()) {
+    auto idCert = ndn::io::load<ndn::security::v2::Certificate>(x);
+    insert(*idCert);
+  }
+
+  registerKeyPrefixes();
+}
+
+void
+CertificateStore::insert(const ndn::security::v2::Certificate& certificate)
+{
+  m_certificates[certificate.getKeyName()] = certificate;
+  NLSR_LOG_TRACE("Certificate inserted successfully");
+}
+
+const ndn::security::v2::Certificate*
+CertificateStore::find(const ndn::Name& keyName) const
+{
+  auto it = m_certificates.find(keyName);
+  return it != m_certificates.end() ? &it->second : nullptr;
+}
+
+void
+CertificateStore::clear()
+{
+  m_certificates.clear();
+}
+
+void
+CertificateStore::setInterestFilter(const ndn::Name& prefix, bool loopback)
+{
+  m_face.setInterestFilter(ndn::InterestFilter(prefix).allowLoopback(loopback),
+                           std::bind(&CertificateStore::onKeyInterest, this, _1, _2),
+                           std::bind(&CertificateStore::onKeyPrefixRegSuccess, this, _1),
+                           std::bind(&CertificateStore::registrationFailed, this, _1),
+                           m_confParam.getSigningInfo(), ndn::nfd::ROUTE_FLAG_CAPTURE);
+}
+
+void
+CertificateStore::registerKeyPrefixes()
+{
+  std::vector<ndn::Name> prefixes;
+
+  // Router's NLSR certificate
+  ndn::Name nlsrKeyPrefix = m_confParam.getRouterPrefix();
+  nlsrKeyPrefix.append("nlsr");
+  nlsrKeyPrefix.append("KEY");
+  prefixes.push_back(nlsrKeyPrefix);
+
+  // Router's certificate
+  ndn::Name routerKeyPrefix = m_confParam.getRouterPrefix();
+  routerKeyPrefix.append("KEY");
+  prefixes.push_back(routerKeyPrefix);
+
+  // Router's operator's certificate
+  ndn::Name operatorKeyPrefix = m_confParam.getNetwork();
+  operatorKeyPrefix.append(m_confParam.getSiteName());
+  operatorKeyPrefix.append(std::string("%C1.Operator"));
+  prefixes.push_back(operatorKeyPrefix);
+
+  // Router's site's certificate
+  ndn::Name siteKeyPrefix = m_confParam.getNetwork();
+  siteKeyPrefix.append(m_confParam.getSiteName());
+  siteKeyPrefix.append("KEY");
+  prefixes.push_back(siteKeyPrefix);
+
+  // Start listening for interest of this router's NLSR certificate,
+  // router's certificate and site's certificate
+  for (const auto& i : prefixes) {
+    setInterestFilter(i);
+  }
+}
+
+void
+CertificateStore::onKeyInterest(const ndn::Name& name, const ndn::Interest& interest)
+{
+  NLSR_LOG_DEBUG("Got interest for certificate. Interest: " << interest.getName());
+
+  const auto* cert = find(interest.getName());
+
+  if (!cert) {
+    NLSR_LOG_TRACE("Certificate is not found for: " << interest);
+    return;
+  }
+  m_face.put(*cert);
+}
+
+void
+CertificateStore::onKeyPrefixRegSuccess(const ndn::Name& name)
+{
+  NLSR_LOG_DEBUG("KEY prefix: " << name << " registration is successful.");
+}
+
+void
+CertificateStore::registrationFailed(const ndn::Name& name)
+{
+  NLSR_LOG_ERROR("ERROR: Failed to register prefix " << name);
+  BOOST_THROW_EXCEPTION(std::runtime_error("Prefix registration failed"));
+}
+
+void
+CertificateStore::publishCertFromCache(const ndn::Name& keyName)
+{
+  const auto* cert = m_validator.getUnverifiedCertCache().find(keyName);
+
+  if (cert) {
+    insert(*cert);
+    NLSR_LOG_TRACE(*cert);
+    ndn::Name certName = ndn::security::v2::extractKeyNameFromCertName(cert->getName());
+    NLSR_LOG_TRACE("Setting interest filter for: " << certName);
+
+    setInterestFilter(certName);
+
+    if (cert->getKeyName() != cert->getSignature().getKeyLocator().getName()) {
+      publishCertFromCache(cert->getSignature().getKeyLocator().getName());
+    }
+  }
+  else {
+    // Happens for root cert
+    NLSR_LOG_TRACE("Cert for " << keyName << " was not found in the Validator's cache. ");
+  }
+}
+
+void
+CertificateStore::afterFetcherSignalEmitted(const ndn::Data& lsaSegment)
+{
+  const auto keyName = lsaSegment.getSignature().getKeyLocator().getName();
+  if (!find(keyName)) {
+    NLSR_LOG_TRACE("Publishing certificate for: " << keyName);
+    publishCertFromCache(keyName);
+  }
+  else {
+    NLSR_LOG_TRACE("Certificate is already in the store: " << keyName);
+  }
+}
+
+} // namespace security
+} // namespace nlsr
diff --git a/src/security/certificate-store.hpp b/src/security/certificate-store.hpp
index 0445318..99b88bf 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-2017,  The University of Memphis,
+ * Copyright (c) 2014-2020,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -22,13 +22,17 @@
 #ifndef NLSR_CERTIFICATE_STORE_HPP
 #define NLSR_CERTIFICATE_STORE_HPP
 
-#include "../common.hpp"
-#include "../test-access-control.hpp"
+#include "common.hpp"
+#include "test-access-control.hpp"
+#include "lsdb.hpp"
 
 #include <ndn-cxx/interest.hpp>
+#include <ndn-cxx/mgmt/nfd/controller.hpp>
 #include <ndn-cxx/security/v2/certificate.hpp>
+#include <ndn-cxx/security/validator-config.hpp>
 
 namespace nlsr {
+class ConfParameter;
 namespace security {
 
 /*! \brief Store certificates for names
@@ -40,35 +44,61 @@
  */
 class CertificateStore
 {
+
 public:
+  CertificateStore(ndn::Face& face, ConfParameter& confParam, Lsdb& lsdb);
+
   void
-  insert(const ndn::security::v2::Certificate& certificate)
-  {
-    m_certificates[certificate.getKeyName()] = certificate;
-  }
+  insert(const ndn::security::v2::Certificate& certificate);
 
+  /*! \brief Find a certificate
+   *
+   * 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::v2::Certificate*
-  find(const ndn::Name keyName)
-  {
-    CertMap::iterator it = m_certificates.find(keyName);
+  find(const ndn::Name& keyName) const;
 
-    if (it != m_certificates.end()) {
-      return &it->second;
-    }
+  /*! \brief Retrieves the chain of certificates from Validator's cache and
+   *   store them in Nlsr's own CertificateStore.
+   * \param keyName Name of the first key in the certificate chain.
+  */
+  void
+  publishCertFromCache(const ndn::Name& keyName);
 
-    return nullptr;
-  }
+  void
+  afterFetcherSignalEmitted(const ndn::Data& lsaSegment);
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   void
-  clear()
-  {
-    m_certificates.clear();
-  }
+  clear();
+
+  void
+  setInterestFilter(const ndn::Name& prefix, const bool loopback = false);
+
+  void
+  registerKeyPrefixes();
+
+  void
+  onKeyInterest(const ndn::Name& name, const ndn::Interest& interest);
+
+  void
+  onKeyPrefixRegSuccess(const ndn::Name& name);
+
+  void
+  registrationFailed(const ndn::Name& name);
 
 private:
   typedef std::map<ndn::Name, ndn::security::v2::Certificate> CertMap;
   CertMap m_certificates;
+  ndn::Face& m_face;
+  ConfParameter& m_confParam;
+  Lsdb& m_lsdb;
+  ndn::security::ValidatorConfig& m_validator;
+  ndn::util::signal::ScopedConnection m_afterSegmentValidatedConnection;
 };
 
 } // namespace security