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
diff --git a/src/security/validator-config.hpp b/src/security/validator-config.hpp
index 6b70a3c..e1ae5fd 100644
--- a/src/security/validator-config.hpp
+++ b/src/security/validator-config.hpp
@@ -33,7 +33,6 @@
 
 class ValidatorConfig : public Validator
 {
-
 public:
   class Error : public Validator::Error
   {
@@ -45,10 +44,19 @@
     }
   };
 
-  static const shared_ptr<CertificateCache> DEFAULT_CERTIFICATE_CACHE;
-  static const time::milliseconds DEFAULT_GRACE_INTERVAL;
-  static const time::system_clock::Duration DEFAULT_KEY_TIMESTAMP_TTL;
+  /**
+   * @note  When both certificate cache and face are not supplied, no cache will be used.
+   *        However, if only face is supplied, a default cache will be created and used.
+   */
+  explicit
+  ValidatorConfig(Face* face = nullptr,
+                  const shared_ptr<CertificateCache>& certificateCache = DEFAULT_CERTIFICATE_CACHE,
+                  const time::milliseconds& graceInterval = DEFAULT_GRACE_INTERVAL,
+                  const size_t stepLimit = 10,
+                  const size_t maxTrackedKeys = 1000,
+                  const time::system_clock::Duration& keyTimestampTtl = DEFAULT_KEY_TIMESTAMP_TTL);
 
+  /// @deprecated Use the constructor taking Face* as parameter.
   explicit
   ValidatorConfig(Face& face,
                   const shared_ptr<CertificateCache>& certificateCache = DEFAULT_CERTIFICATE_CACHE,
@@ -75,10 +83,10 @@
   load(const security::conf::ConfigSection& configSection,
        const std::string& filename);
 
-  inline void
+  void
   reset();
 
-  inline bool
+  bool
   isEmpty();
 
 protected:
@@ -137,7 +145,7 @@
   time::nanoseconds
   getRefreshPeriod(std::string refreshString);
 
-  inline time::nanoseconds
+  time::nanoseconds
   getDefaultRefreshPeriod();
 
   void
@@ -154,9 +162,6 @@
   }
 #endif
 
-
-private:
-
   class TrustAnchorContainer
   {
   public:
@@ -220,6 +225,19 @@
     time::nanoseconds m_refreshPeriod;
   };
 
+  static inline bool
+  compareDynamicContainer(const DynamicTrustAnchorContainer& containerA,
+                          const DynamicTrustAnchorContainer& containerB)
+  {
+    return (containerA.getLastRefresh() < containerB.getLastRefresh());
+  }
+
+public:
+  static const shared_ptr<CertificateCache> DEFAULT_CERTIFICATE_CACHE;
+  static const time::milliseconds DEFAULT_GRACE_INTERVAL;
+  static const time::system_clock::Duration DEFAULT_KEY_TIMESTAMP_TTL;
+
+private:
   typedef security::conf::Rule<Interest> InterestRule;
   typedef security::conf::Rule<Data>     DataRule;
   typedef std::vector<shared_ptr<InterestRule> > InterestRuleList;
@@ -228,12 +246,6 @@
   typedef std::list<DynamicTrustAnchorContainer> DynamicContainers; // sorted by m_lastRefresh
   typedef std::list<shared_ptr<IdentityCertificate> > CertificateList;
 
-  static inline bool
-  compareDynamicContainer(const DynamicTrustAnchorContainer& containerA,
-                          const DynamicTrustAnchorContainer& containerB)
-  {
-    return (containerA.getLastRefresh() < containerB.getLastRefresh());
-  }
 
   /**
    * @brief gives whether validation should be preformed
@@ -259,175 +271,6 @@
   const time::system_clock::Duration& m_keyTimestampTtl;
 };
 
-inline void
-ValidatorConfig::reset()
-{
-  m_certificateCache->reset();
-  m_interestRules.clear();
-  m_dataRules.clear();
-
-  m_anchors.clear();
-
-  m_staticContainer = TrustAnchorContainer();
-
-  m_dynamicContainers.clear();
-}
-
-inline bool
-ValidatorConfig::isEmpty()
-{
-  if (m_certificateCache->isEmpty() &&
-      m_interestRules.empty() &&
-      m_dataRules.empty() &&
-      m_anchors.empty())
-    return true;
-  return false;
-}
-
-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)
-    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())
-    {
-      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);
-}
-
-inline time::nanoseconds
-ValidatorConfig::getDefaultRefreshPeriod()
-{
-  return time::duration_cast<time::nanoseconds>(time::seconds(3600));
-}
-
 } // namespace ndn
 
 #endif // NDN_SECURITY_VALIDATOR_CONFIG_HPP
diff --git a/src/security/validator-regex.cpp b/src/security/validator-regex.cpp
index 0539abd..08f4c73 100644
--- a/src/security/validator-regex.cpp
+++ b/src/security/validator-regex.cpp
@@ -31,6 +31,17 @@
 
 const shared_ptr<CertificateCache> ValidatorRegex::DEFAULT_CERTIFICATE_CACHE;
 
+ValidatorRegex::ValidatorRegex(Face* face,
+                               shared_ptr<CertificateCache> certificateCache,
+                               const int stepLimit)
+  : Validator(face)
+  , m_stepLimit(stepLimit)
+  , m_certificateCache(certificateCache)
+{
+  if (!static_cast<bool>(m_certificateCache) && face != nullptr)
+    m_certificateCache = make_shared<CertificateCacheTtl>(ref(face->getIoService()));
+}
+
 ValidatorRegex::ValidatorRegex(Face& face,
                                shared_ptr<CertificateCache> certificateCache,
                                const int stepLimit)
@@ -39,7 +50,19 @@
   , m_certificateCache(certificateCache)
 {
   if (!static_cast<bool>(m_certificateCache))
-    m_certificateCache = make_shared<CertificateCacheTtl>(ref(m_face.getIoService()));
+    m_certificateCache = make_shared<CertificateCacheTtl>(ref(face.getIoService()));
+}
+
+void
+ValidatorRegex::addDataVerificationRule(shared_ptr<SecRuleRelative> rule)
+{
+  rule->isPositive() ? m_verifyPolicies.push_back(rule) : m_mustFailVerify.push_back(rule);
+}
+
+void
+ValidatorRegex::addTrustAnchor(shared_ptr<IdentityCertificate> certificate)
+{
+  m_trustAnchors[certificate->getName().getPrefix(-1)] = certificate;
 }
 
 void
@@ -53,7 +76,8 @@
 
   if (!certificate->isTooLate() && !certificate->isTooEarly())
     {
-      m_certificateCache->insertCertificate(certificate);
+      if (static_cast<bool>(m_certificateCache))
+        m_certificateCache->insertCertificate(certificate);
 
       if (verifySignature(*data, certificate->getPublicKeyInfo()))
         return onValidated(data);
@@ -122,7 +146,8 @@
 
               const Name& keyLocatorName = keyLocator.getName();
               shared_ptr<const Certificate> trustedCert;
-              if (m_trustAnchors.end() == m_trustAnchors.find(keyLocatorName))
+              if (m_trustAnchors.end() == m_trustAnchors.find(keyLocatorName) &&
+                  static_cast<bool>(m_certificateCache))
                 trustedCert = m_certificateCache->getCertificate(keyLocatorName);
               else
                 trustedCert = m_trustAnchors[keyLocatorName];
diff --git a/src/security/validator-regex.hpp b/src/security/validator-regex.hpp
index 0490b77..b207bbc 100644
--- a/src/security/validator-regex.hpp
+++ b/src/security/validator-regex.hpp
@@ -45,8 +45,16 @@
     }
   };
 
-  static const shared_ptr<CertificateCache> DEFAULT_CERTIFICATE_CACHE;
+  /**
+   * @note  When both certificate cache and face are not supplied, no cache will be used.
+   *        However, if only face is supplied, a default cache will be created and used.
+   */
+  explicit
+  ValidatorRegex(Face* face = nullptr,
+                 shared_ptr<CertificateCache> certificateCache = DEFAULT_CERTIFICATE_CACHE,
+                 const int stepLimit = 3);
 
+  /// @deprecated Use the constructor taking Face* as parameter.
   explicit
   ValidatorRegex(Face& face,
                  shared_ptr<CertificateCache> certificateCache = DEFAULT_CERTIFICATE_CACHE,
@@ -62,7 +70,7 @@
    *
    * @param rule The verification rule
    */
-  inline void
+  void
   addDataVerificationRule(shared_ptr<SecRuleRelative> rule);
 
   /**
@@ -70,7 +78,7 @@
    *
    * @param certificate The trust anchor
    */
-  inline void
+  void
   addTrustAnchor(shared_ptr<IdentityCertificate> certificate);
 
 protected:
@@ -103,6 +111,9 @@
                                 const shared_ptr<const Data>& data,
                                 const OnDataValidationFailed& onValidationFailed);
 
+public:
+  static const shared_ptr<CertificateCache> DEFAULT_CERTIFICATE_CACHE;
+
 protected:
   typedef std::vector< shared_ptr<SecRuleRelative> > RuleList;
   typedef std::vector< shared_ptr<Regex> > RegexList;
@@ -114,18 +125,6 @@
   std::map<Name, shared_ptr<IdentityCertificate> > m_trustAnchors;
 };
 
-inline void
-ValidatorRegex::addDataVerificationRule(shared_ptr<SecRuleRelative> rule)
-{
-  rule->isPositive() ? m_verifyPolicies.push_back(rule) : m_mustFailVerify.push_back(rule);
-}
-
-inline void
-ValidatorRegex::addTrustAnchor(shared_ptr<IdentityCertificate> certificate)
-{
-  m_trustAnchors[certificate->getName().getPrefix(-1)] = certificate;
-}
-
 } // namespace ndn
 
-#endif //NDN_SECURITY_VALIDATOR_REGEX_HPP
+#endif // NDN_SECURITY_VALIDATOR_REGEX_HPP
diff --git a/src/security/validator.cpp b/src/security/validator.cpp
index de8c311..2e1e637 100644
--- a/src/security/validator.cpp
+++ b/src/security/validator.cpp
@@ -34,15 +34,13 @@
 static OID SECP256R1("1.2.840.10045.3.1.7");
 static OID SECP384R1("1.3.132.0.34");
 
-Validator::Validator()
-  : m_hasFace(false)
-  , m_face(*static_cast<Face*>(0))
+Validator::Validator(Face* face)
+  : m_face(face)
 {
 }
 
 Validator::Validator(Face& face)
-  : m_hasFace(true)
-  , m_face(face)
+  : m_face(&face)
 {
 }
 
@@ -63,13 +61,6 @@
       return;
     }
 
-  if (!m_hasFace)
-    {
-      onValidationFailed(interest.shared_from_this(),
-                         "Require more information to validate the interest!");
-      return;
-    }
-
   OnFailure onFailure = bind(onValidationFailed, interest.shared_from_this(), _1);
   afterCheckPolicy(nextSteps, onFailure);
 }
@@ -91,13 +82,6 @@
       return;
     }
 
-  if (!m_hasFace)
-    {
-      onValidationFailed(data.shared_from_this(),
-                         "Require more information to validate the data!");
-      return;
-    }
-
   OnFailure onFailure = bind(onValidationFailed, data.shared_from_this(), _1);
   afterCheckPolicy(nextSteps, onFailure);
 }
@@ -289,10 +273,10 @@
 {
   if (remainingRetries > 0)
     // Issue the same expressInterest except decrement nRetrials.
-    m_face.expressInterest(interest,
-                           bind(&Validator::onData, this, _1, _2, validationRequest),
-                           bind(&Validator::onTimeout, this, _1,
-                                remainingRetries - 1, onFailure, validationRequest));
+    m_face->expressInterest(interest,
+                            bind(&Validator::onData, this, _1, _2, validationRequest),
+                            bind(&Validator::onTimeout, this, _1,
+                                 remainingRetries - 1, onFailure, validationRequest));
   else
     onFailure("Cannot fetch cert: " + interest.getName().toUri());
 }
@@ -302,15 +286,21 @@
 Validator::afterCheckPolicy(const std::vector<shared_ptr<ValidationRequest> >& nextSteps,
                             const OnFailure& onFailure)
 {
+  if (m_face == nullptr)
+    {
+      onFailure("Require more information to validate the packet!");
+      return;
+    }
+
   for (std::vector<shared_ptr<ValidationRequest> >::const_iterator it = nextSteps.begin();
        it != nextSteps.end(); it++)
     {
-      m_face.expressInterest((*it)->m_interest,
-                             bind(&Validator::onData, this, _1, _2, *it),
-                             bind(&Validator::onTimeout,
-                                  this, _1, (*it)->m_nRetries,
-                                  onFailure,
-                                  *it));
+      m_face->expressInterest((*it)->m_interest,
+                              bind(&Validator::onData, this, _1, _2, *it),
+                              bind(&Validator::onTimeout,
+                                   this, _1, (*it)->m_nRetries,
+                                   onFailure,
+                                   *it));
     }
 }
 
diff --git a/src/security/validator.hpp b/src/security/validator.hpp
index 9a3b4a3..3fe58f3 100644
--- a/src/security/validator.hpp
+++ b/src/security/validator.hpp
@@ -54,8 +54,18 @@
     }
   };
 
-  Validator();
+  /**
+   * @brief Validator constructor
+   *
+   * @param face Pointer to face through which validator may retrieve certificates.
+   *             Passing a null pointer implies the validator is in offline mode.
+   *
+   * @note Make sure the lifetime of the passed Face is longer than validator.
+   */
+  explicit
+  Validator(Face* face = nullptr);
 
+  /// @deprecated Use the constructor taking Face* as parameter.
   explicit
   Validator(Face& face);
 
@@ -300,10 +310,9 @@
                    const OnFailure& onFailure);
 
 protected:
-  bool m_hasFace;
-  Face& m_face;
+  Face* m_face;
 };
 
 } // namespace ndn
 
-#endif //NDN_SECURITY_VALIDATOR_HPP
+#endif // NDN_SECURITY_VALIDATOR_HPP