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