security: Abstract certificate fetching from v2::Validator

Change-Id: Ia98d11ac67b0095f632818ac37a19a1e5a7656a8
Refs: #3921
diff --git a/src/security/v2/validator.cpp b/src/security/v2/validator.cpp
index b18fc75..4928c67 100644
--- a/src/security/v2/validator.cpp
+++ b/src/security/v2/validator.cpp
@@ -34,13 +34,14 @@
 #define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(state->getDepth() + 1, '>') << " " << x)
 #define NDN_LOG_TRACE_DEPTH(x) NDN_LOG_TRACE(std::string(state->getDepth() + 1, '>') << " " << x)
 
-Validator::Validator(unique_ptr<ValidationPolicy> policy, Face* face)
+Validator::Validator(unique_ptr<ValidationPolicy> policy, unique_ptr<CertificateFetcher> certFetcher)
   : m_policy(std::move(policy))
-  , m_face(face)
-  , m_verifiedCertificateCache(time::hours(1))
-  , m_unverifiedCertificateCache(time::minutes(5))
+  , m_certFetcher(std::move(certFetcher))
   , m_maxDepth(25)
 {
+  BOOST_ASSERT(m_policy != nullptr);
+  BOOST_ASSERT(m_certFetcher != nullptr);
+  m_certFetcher->setCertificateStorage(*this);
 }
 
 Validator::~Validator() = default;
@@ -101,6 +102,12 @@
 Validator::validate(const Certificate& cert, const shared_ptr<ValidationState>& state)
 {
   NDN_LOG_DEBUG_DEPTH("Start validating certificate " << cert.getName());
+
+  if (!cert.isValid()) {
+    return state->fail({ValidationError::Code::EXPIRED_CERT, "Retrieved certificate is not yet valid or expired "
+          "`" + cert.getName().toUri() + "`"});
+  }
+
   m_policy->checkPolicy(cert, state,
       [this, cert] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
       if (certRequest == nullptr) {
@@ -115,23 +122,6 @@
     });
 }
 
-const Certificate*
-Validator::findTrustedCert(const Interest& interestForCertificate, const shared_ptr<ValidationState>& state)
-{
-  auto anchor = m_trustAnchors.find(interestForCertificate);
-  if (anchor != nullptr) {
-    NDN_LOG_TRACE_DEPTH("Found certificate in anchor cache " << anchor->getName());
-    return anchor;
-  }
-
-  auto key = m_verifiedCertificateCache.find(interestForCertificate);
-  if (key != nullptr) {
-    NDN_LOG_TRACE_DEPTH("Found certificate in verified key cache " << key->getName());
-    return key;
-  }
-  return nullptr;
-}
-
 void
 Validator::requestCertificate(const shared_ptr<CertificateRequest>& certRequest,
                               const shared_ptr<ValidationState>& state)
@@ -145,9 +135,10 @@
 
   NDN_LOG_DEBUG_DEPTH("Retrieving " << certRequest->m_interest.getName());
 
-  // Check the trusted cache
-  auto cert = findTrustedCert(certRequest->m_interest, state);
+  auto cert = findTrustedCert(certRequest->m_interest);
   if (cert != nullptr) {
+    NDN_LOG_TRACE_DEPTH("Found trusted certificate " << cert->getName());
+
     cert = state->verifyCertificateChain(*cert);
     if (cert != nullptr) {
       state->verifyOriginalPacket(*cert);
@@ -160,159 +151,34 @@
     return;
   }
 
-  if (state->hasSeenCertificateName(certRequest->m_interest.getName())) {
-    state->fail({ValidationError::Code::LOOP_DETECTED,
-                 "Loop detected at " + certRequest->m_interest.getName().toUri()});
-    return;
-  }
-
-  // Check untrusted cache
-  cert = m_unverifiedCertificateCache.find(certRequest->m_interest);
-  if (cert != nullptr) {
-    NDN_LOG_DEBUG_DEPTH("Found certificate in **un**verified key cache " << cert->getName());
-    return dataCallback(*cert, certRequest, state, false); // to avoid caching the cached key
-  }
-
-  // Attempt to retrieve certificate from the network
-  fetchCertificateFromNetwork(certRequest, state);
-}
-
-void
-Validator::fetchCertificateFromNetwork(const shared_ptr<CertificateRequest>& certRequest,
-                                       const shared_ptr<ValidationState>& state)
-{
-  if (m_face == nullptr) {
-    state->fail({ValidationError::Code::CANNOT_RETRIEVE_CERT, "Cannot fetch certificate in offline mode "
-                 "`" + certRequest->m_interest.getName().toUri() + "`"});
-    return;
-  }
-
-  m_face->expressInterest(certRequest->m_interest,
-                          [=] (const Interest& interest, const Data& data) {
-                            dataCallback(data, certRequest, state);
-                          },
-                          [=] (const Interest& interest, const lp::Nack& nack) {
-                            nackCallback(nack, certRequest, state);
-                          },
-                          [=] (const Interest& interest) {
-                            timeoutCallback(certRequest, state);
-                          });
-}
-
-void
-Validator::dataCallback(const Data& data,
-                        const shared_ptr<CertificateRequest>& certRequest,
-                        const shared_ptr<ValidationState>& state,
-                        bool isFromNetwork)
-{
-  NDN_LOG_DEBUG_DEPTH("Retrieved certificate " << (isFromNetwork ? "from network " : "from cache ") << data.getName());
-
-  Certificate cert;
-  try {
-    cert = Certificate(data);
-  }
-  catch (const tlv::Error& e) {
-    return state->fail({ValidationError::Code::MALFORMED_CERT, "Retrieved a malformed certificate "
-                        "`" + data.getName().toUri() + "` (" + e.what() + ")"});
-  }
-
-  if (!cert.isValid()) {
-    return state->fail({ValidationError::Code::EXPIRED_CERT, "Retrieved certificate is not yet "
-                        "valid or has expired `" + cert.getName().toUri() + "`"});
-  }
-  if (isFromNetwork) {
-    cacheUnverifiedCertificate(Certificate(cert));
-  }
-  return validate(cert, state); // recursion step
-}
-
-void
-Validator::nackCallback(const lp::Nack& nack, const shared_ptr<CertificateRequest>& certRequest,
-                        const shared_ptr<ValidationState>& state)
-{
-  NDN_LOG_DEBUG_DEPTH("NACK (" << nack.getReason() <<  ") while retrieving certificate "
-                      << certRequest->m_interest.getName());
-
-  --certRequest->m_nRetriesLeft;
-  if (certRequest->m_nRetriesLeft > 0) {
-    // TODO implement delay for the the next fetch
-    fetchCertificateFromNetwork(certRequest, state);
-  }
-  else {
-    state->fail({ValidationError::Code::CANNOT_RETRIEVE_CERT, "Cannot fetch certificate after all "
-                 "retries `" + certRequest->m_interest.getName().toUri() + "`"});
-  }
-}
-
-void
-Validator::timeoutCallback(const shared_ptr<CertificateRequest>& certRequest,
-                           const shared_ptr<ValidationState>& state)
-{
-  NDN_LOG_DEBUG_DEPTH("Timeout while retrieving certificate "
-                      << certRequest->m_interest.getName() << ", retrying");
-
-  --certRequest->m_nRetriesLeft;
-  if (certRequest->m_nRetriesLeft > 0) {
-    fetchCertificateFromNetwork(certRequest, state);
-  }
-  else {
-    state->fail({ValidationError::Code::CANNOT_RETRIEVE_CERT, "Cannot fetch certificate after all "
-                 "retries `" + certRequest->m_interest.getName().toUri() + "`"});
-  }
+  m_certFetcher->fetch(certRequest, state, [this] (const Certificate& cert, const shared_ptr<ValidationState>& state) {
+      validate(cert, state);
+    });
 }
 
 ////////////////////////////////////////////////////////////////////////
 // Trust anchor management
 ////////////////////////////////////////////////////////////////////////
 
+// to change visibility from protected to public
+
 void
 Validator::loadAnchor(const std::string& groupId, Certificate&& cert)
 {
-  m_trustAnchors.insert(groupId, std::move(cert));
+  CertificateStorage::loadAnchor(groupId, std::move(cert));
 }
 
 void
 Validator::loadAnchor(const std::string& groupId, const std::string& certfilePath,
                       time::nanoseconds refreshPeriod, bool isDir)
 {
-  m_trustAnchors.insert(groupId, certfilePath, refreshPeriod, isDir);
+  CertificateStorage::loadAnchor(groupId, certfilePath, refreshPeriod, isDir);
 }
 
 void
 Validator::cacheVerifiedCertificate(Certificate&& cert)
 {
-  m_verifiedCertificateCache.insert(std::move(cert));
-}
-
-void
-Validator::cacheUnverifiedCertificate(Certificate&& cert)
-{
-  m_unverifiedCertificateCache.insert(std::move(cert));
-}
-
-const TrustAnchorContainer&
-Validator::getTrustAnchors() const
-{
-  return m_trustAnchors;
-}
-
-const CertificateCache&
-Validator::getVerifiedCertificateCache() const
-{
-  return m_verifiedCertificateCache;
-}
-
-const CertificateCache&
-Validator::getUnverifiedCertificateCache() const
-{
-  return m_unverifiedCertificateCache;
-}
-
-bool
-Validator::isCertificateCached(const Name& certName) const
-{
-  return (getVerifiedCertificateCache().find(certName) != nullptr ||
-          getVerifiedCertificateCache().find(certName) != nullptr);
+  CertificateStorage::cacheVerifiedCert(std::move(cert));
 }
 
 } // namespace v2