security: Make Face optional in Validator

Change-Id: I75760e358878d8031439dd33a8200e21c69db3f8
Refs: #2124
diff --git a/src/security/validator-config.cpp b/src/security/validator-config.cpp
index 5891ff1..b55cf69 100644
--- a/src/security/validator-config.cpp
+++ b/src/security/validator-config.cpp
@@ -35,6 +35,25 @@
 const time::milliseconds ValidatorConfig::DEFAULT_GRACE_INTERVAL(3000);
 const time::system_clock::Duration ValidatorConfig::DEFAULT_KEY_TIMESTAMP_TTL = time::hours(1);
 
+ValidatorConfig::ValidatorConfig(Face* face,
+                                 const shared_ptr<CertificateCache>& certificateCache,
+                                 const time::milliseconds& graceInterval,
+                                 const size_t stepLimit,
+                                 const size_t maxTrackedKeys,
+                                 const time::system_clock::Duration& keyTimestampTtl)
+  : Validator(face)
+  , m_shouldValidate(true)
+  , m_stepLimit(stepLimit)
+  , m_certificateCache(certificateCache)
+  , m_graceInterval(graceInterval < time::milliseconds::zero() ?
+                    DEFAULT_GRACE_INTERVAL : graceInterval)
+  , m_maxTrackedKeys(maxTrackedKeys)
+  , m_keyTimestampTtl(keyTimestampTtl)
+{
+  if (!static_cast<bool>(m_certificateCache) && face != nullptr)
+    m_certificateCache = make_shared<CertificateCacheTtl>(ref(face->getIoService()));
+}
+
 ValidatorConfig::ValidatorConfig(Face& face,
                                  const shared_ptr<CertificateCache>& certificateCache,
                                  const time::milliseconds& graceInterval,
@@ -51,7 +70,7 @@
   , m_keyTimestampTtl(keyTimestampTtl)
 {
   if (!static_cast<bool>(m_certificateCache))
-    m_certificateCache = make_shared<CertificateCacheTtl>(ref(m_face.getIoService()));
+    m_certificateCache = make_shared<CertificateCacheTtl>(ref(face.getIoService()));
 }
 
 void
@@ -355,6 +374,32 @@
     throw Error("Unsupported trust-anchor.type: " + type);
 }
 
+void
+ValidatorConfig::reset()
+{
+  if (static_cast<bool>(m_certificateCache))
+    m_certificateCache->reset();
+  m_interestRules.clear();
+  m_dataRules.clear();
+
+  m_anchors.clear();
+
+  m_staticContainer = TrustAnchorContainer();
+
+  m_dynamicContainers.clear();
+}
+
+bool
+ValidatorConfig::isEmpty()
+{
+  if ((!static_cast<bool>(m_certificateCache) || m_certificateCache->isEmpty()) &&
+      m_interestRules.empty() &&
+      m_dataRules.empty() &&
+      m_anchors.empty())
+    return true;
+  return false;
+}
+
 time::nanoseconds
 ValidatorConfig::getRefreshPeriod(std::string inputString)
 {
@@ -388,6 +433,12 @@
     }
 }
 
+time::nanoseconds
+ValidatorConfig::getDefaultRefreshPeriod()
+{
+  return time::duration_cast<time::nanoseconds>(time::seconds(3600));
+}
+
 void
 ValidatorConfig::refreshAnchors()
 {
@@ -674,5 +725,144 @@
     }
 }
 
+template<class Packet, class OnValidated, class OnFailed>
+void
+ValidatorConfig::checkSignature(const Packet& packet,
+                                const Signature& signature,
+                                size_t nSteps,
+                                const OnValidated& onValidated,
+                                const OnFailed& onValidationFailed,
+                                std::vector<shared_ptr<ValidationRequest> >& nextSteps)
+{
+  if (signature.getType() == tlv::DigestSha256)
+    {
+      DigestSha256 sigSha256(signature);
+
+      if (verifySignature(packet, sigSha256))
+        return onValidated(packet.shared_from_this());
+      else
+        return onValidationFailed(packet.shared_from_this(),
+                                  "Sha256 Signature cannot be verified!");
+    }
+
+  try {
+    switch (signature.getType()) {
+    case tlv::SignatureSha256WithRsa:
+    case tlv::SignatureSha256WithEcdsa:
+      {
+        if (!signature.hasKeyLocator()) {
+          return onValidationFailed(packet.shared_from_this(),
+                                    "Missing KeyLocator in SignatureInfo");
+        }
+        break;
+      }
+    default:
+      return onValidationFailed(packet.shared_from_this(),
+                              "Unsupported signature type");
+    }
+  }
+  catch (KeyLocator::Error& e) {
+    return onValidationFailed(packet.shared_from_this(),
+                              "Cannot decode KeyLocator in public key signature");
+  }
+  catch (tlv::Error& e) {
+    return onValidationFailed(packet.shared_from_this(),
+                              "Cannot decode public key signature");
+  }
+
+
+  if (signature.getKeyLocator().getType() != KeyLocator::KeyLocator_Name) {
+    return onValidationFailed(packet.shared_from_this(), "Unsupported KeyLocator type");
+  }
+
+  const Name& keyLocatorName = signature.getKeyLocator().getName();
+
+  shared_ptr<const Certificate> trustedCert;
+
+  refreshAnchors();
+
+  AnchorList::const_iterator it = m_anchors.find(keyLocatorName);
+  if (m_anchors.end() == it && static_cast<bool>(m_certificateCache))
+    trustedCert = m_certificateCache->getCertificate(keyLocatorName);
+  else
+    trustedCert = it->second;
+
+  if (static_cast<bool>(trustedCert))
+    {
+      if (verifySignature(packet, signature, trustedCert->getPublicKeyInfo()))
+        return onValidated(packet.shared_from_this());
+      else
+        return onValidationFailed(packet.shared_from_this(),
+                                  "Cannot verify signature");
+    }
+  else
+    {
+      if (m_stepLimit == nSteps)
+        return onValidationFailed(packet.shared_from_this(),
+                                  "Maximum steps of validation reached");
+
+      OnDataValidated onCertValidated =
+        bind(&ValidatorConfig::onCertValidated<Packet, OnValidated, OnFailed>,
+             this, _1, packet.shared_from_this(), onValidated, onValidationFailed);
+
+      OnDataValidationFailed onCertValidationFailed =
+        bind(&ValidatorConfig::onCertFailed<Packet, OnFailed>,
+             this, _1, _2, packet.shared_from_this(), onValidationFailed);
+
+      Interest certInterest(keyLocatorName);
+
+      shared_ptr<ValidationRequest> nextStep =
+        make_shared<ValidationRequest>(certInterest,
+                                       onCertValidated,
+                                       onCertValidationFailed,
+                                       1, nSteps + 1);
+
+      nextSteps.push_back(nextStep);
+      return;
+    }
+
+  return onValidationFailed(packet.shared_from_this(), "Unsupported Signature Type");
+}
+
+template<class Packet, class OnValidated, class OnFailed>
+void
+ValidatorConfig::onCertValidated(const shared_ptr<const Data>& signCertificate,
+                                 const shared_ptr<const Packet>& packet,
+                                 const OnValidated& onValidated,
+                                 const OnFailed& onValidationFailed)
+{
+  shared_ptr<IdentityCertificate> certificate =
+    make_shared<IdentityCertificate>(*signCertificate);
+
+  if (!certificate->isTooLate() && !certificate->isTooEarly())
+    {
+      if (static_cast<bool>(m_certificateCache))
+        m_certificateCache->insertCertificate(certificate);
+
+      if (verifySignature(*packet, certificate->getPublicKeyInfo()))
+        return onValidated(packet);
+      else
+        return onValidationFailed(packet,
+                                  "Cannot verify signature: " +
+                                  packet->getName().toUri());
+    }
+  else
+    {
+      return onValidationFailed(packet,
+                                "Signing certificate " +
+                                signCertificate->getName().toUri() +
+                                " is no longer valid.");
+    }
+}
+
+template<class Packet, class OnFailed>
+void
+ValidatorConfig::onCertFailed(const shared_ptr<const Data>& signCertificate,
+                              const std::string& failureInfo,
+                              const shared_ptr<const Packet>& packet,
+                              const OnFailed& onValidationFailed)
+{
+  onValidationFailed(packet, failureInfo);
+}
 
 } // namespace ndn