validator.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2023 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later version.
10  *
11  * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14  *
15  * You should have received copies of the GNU General Public License and GNU Lesser
16  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20  */
21 
23 #include "ndn-cxx/util/logger.hpp"
24 
25 #include <boost/lexical_cast.hpp>
26 
27 namespace ndn::security {
28 
30 
31 #define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(state->getDepth() + 1, '>') << " " << x)
32 #define NDN_LOG_TRACE_DEPTH(x) NDN_LOG_TRACE(std::string(state->getDepth() + 1, '>') << " " << x)
33 
34 Validator::Validator(unique_ptr<ValidationPolicy> policy, unique_ptr<CertificateFetcher> certFetcher)
35  : m_policy(std::move(policy))
36  , m_certFetcher(std::move(certFetcher))
37 {
38  BOOST_ASSERT(m_policy != nullptr);
39  BOOST_ASSERT(m_certFetcher != nullptr);
40  m_policy->setValidator(*this);
41  m_certFetcher->setCertificateStorage(*this);
42 }
43 
44 Validator::~Validator() noexcept = default;
45 
46 void
47 Validator::validate(const Data& data,
48  const DataValidationSuccessCallback& successCb,
49  const DataValidationFailureCallback& failureCb)
50 {
51  auto state = make_shared<DataValidationState>(data, successCb, failureCb);
52  NDN_LOG_DEBUG_DEPTH("Start validating data " << data.getName());
53 
54  m_policy->checkPolicy(data, state, [this] (auto&&... args) {
55  continueValidation(std::forward<decltype(args)>(args)...);
56  });
57 }
58 
59 void
60 Validator::validate(const Interest& interest,
61  const InterestValidationSuccessCallback& successCb,
62  const InterestValidationFailureCallback& failureCb)
63 {
64  auto state = make_shared<InterestValidationState>(interest, successCb, failureCb);
65  NDN_LOG_DEBUG_DEPTH("Start validating interest " << interest.getName());
66 
67  try {
69  state->setTag(make_shared<SignedInterestFormatTag>(fmt));
70  }
71  catch (const tlv::Error& e) {
72  return state->fail({ValidationError::MALFORMED_SIGNATURE, "Malformed InterestSignatureInfo in `" +
73  interest.getName().toUri() + "`: " + e.what()});
74  }
75 
76  m_policy->checkPolicy(interest, state, [this] (auto&&... args) {
77  continueValidation(std::forward<decltype(args)>(args)...);
78  });
79 }
80 
81 void
82 Validator::validate(const Certificate& cert, const shared_ptr<ValidationState>& state)
83 {
84  NDN_LOG_DEBUG_DEPTH("Start validating certificate " << cert.getName());
85 
86  if (!cert.isValid()) {
87  return state->fail({ValidationError::EXPIRED_CERT, "`" + cert.getName().toUri() + "` is valid "
88  "between " + boost::lexical_cast<std::string>(cert.getValidityPeriod())});
89  }
90 
91  m_policy->checkPolicy(cert, state,
92  [this, cert] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
93  if (certRequest == nullptr) {
94  state->fail({ValidationError::POLICY_ERROR, "Validation policy is not allowed to designate `" +
95  cert.getName().toUri() + "` as a trust anchor"});
96  }
97  else {
98  // need to fetch key and validate it
99  state->addCertificate(cert);
100  requestCertificate(certRequest, state);
101  }
102  });
103 }
104 
105 void
106 Validator::continueValidation(const shared_ptr<CertificateRequest>& certRequest,
107  const shared_ptr<ValidationState>& state)
108 {
109  BOOST_ASSERT(state);
110 
111  if (certRequest == nullptr) {
112  state->bypassValidation();
113  }
114  else {
115  // need to fetch key and validate it
116  requestCertificate(certRequest, state);
117  }
118 }
119 
120 void
121 Validator::requestCertificate(const shared_ptr<CertificateRequest>& certRequest,
122  const shared_ptr<ValidationState>& state)
123 {
124  if (state->getDepth() >= m_maxDepth) {
125  state->fail({ValidationError::EXCEEDED_DEPTH_LIMIT, to_string(m_maxDepth)});
126  return;
127  }
128 
129  if (certRequest->interest.getName() == SigningInfo::getDigestSha256Identity()) {
130  state->verifyOriginalPacket(std::nullopt);
131  return;
132  }
133 
134  if (state->hasSeenCertificateName(certRequest->interest.getName())) {
135  state->fail({ValidationError::LOOP_DETECTED, certRequest->interest.getName().toUri()});
136  return;
137  }
138 
139  NDN_LOG_DEBUG_DEPTH("Retrieving " << certRequest->interest.getName());
140 
141  auto cert = findTrustedCert(certRequest->interest);
142  if (cert != nullptr) {
143  NDN_LOG_TRACE_DEPTH("Found trusted certificate " << cert->getName());
144 
145  cert = state->verifyCertificateChain(*cert);
146  if (cert != nullptr) {
147  state->verifyOriginalPacket(*cert);
148  }
149  for (auto trustedCert = std::make_move_iterator(state->m_certificateChain.begin());
150  trustedCert != std::make_move_iterator(state->m_certificateChain.end());
151  ++trustedCert) {
152  cacheVerifiedCertificate(*trustedCert);
153  }
154  return;
155  }
156 
157  m_certFetcher->fetch(certRequest, state, [this] (auto&&... args) {
158  validate(std::forward<decltype(args)>(args)...);
159  });
160 }
161 
163 // Trust anchor management
165 
166 // to change visibility from protected to public
167 
168 void
169 Validator::loadAnchor(const std::string& groupId, Certificate&& cert)
170 {
171  CertificateStorage::loadAnchor(groupId, std::move(cert));
172 }
173 
174 void
175 Validator::loadAnchor(const std::string& groupId, const std::string& certfilePath,
176  time::nanoseconds refreshPeriod, bool isDir)
177 {
178  CertificateStorage::loadAnchor(groupId, certfilePath, refreshPeriod, isDir);
179 }
180 
181 void
183 {
185 }
186 
187 void
189 {
190  CertificateStorage::cacheVerifiedCert(std::move(cert));
191 }
192 
193 void
195 {
197 }
198 
199 } // namespace ndn::security
Represents a Data packet.
Definition: data.hpp:39
Represents an Interest packet.
Definition: interest.hpp:50
std::optional< SignatureInfo > getSignatureInfo() const
Get the InterestSignatureInfo element.
Definition: interest.cpp:552
const Name & getName() const noexcept
Get the Interest name.
Definition: interest.hpp:179
const Certificate * findTrustedCert(const Interest &interestForCert) const
Find a trusted certificate in trust anchor container or in verified cache.
void resetAnchors()
Remove any previously loaded static or dynamic trust anchor.
void cacheVerifiedCert(Certificate &&cert)
Cache verified certificate a period of time (1 hour).
void loadAnchor(const std::string &groupId, Certificate &&cert)
Load static trust anchor.
void resetVerifiedCerts()
Remove any cached verified certificates.
Represents an NDN certificate.
Definition: certificate.hpp:58
static const Name & getDigestSha256Identity()
A localhost identity to indicate that the signature is generated using SHA-256.
@ EXCEEDED_DEPTH_LIMIT
Exceeded validation depth limit.
@ EXPIRED_CERT
The certificate expired or is not yet valid.
@ POLICY_ERROR
The packet violates the validation rules enforced by the policy.
@ LOOP_DETECTED
Loop detected in the certification chain.
@ MALFORMED_SIGNATURE
The signature (e.g., SignatureInfo element) is missing or malformed.
Interface for validating data and interest packets.
Definition: validator.hpp:61
void cacheVerifiedCertificate(Certificate &&cert)
Cache verified cert a period of time (1 hour).
Definition: validator.cpp:188
void loadAnchor(const std::string &groupId, Certificate &&cert)
Load static trust anchor.
Definition: validator.cpp:169
void validate(const Data &data, const DataValidationSuccessCallback &successCb, const DataValidationFailureCallback &failureCb)
Asynchronously validate data.
Definition: validator.cpp:47
void resetVerifiedCertificates()
Remove any cached verified certificates.
Definition: validator.cpp:194
void resetAnchors()
Remove any previously loaded static or dynamic trust anchor.
Definition: validator.cpp:182
Validator(unique_ptr< ValidationPolicy > policy, unique_ptr< CertificateFetcher > certFetcher)
Validator constructor.
Definition: validator.cpp:34
Represents an error in TLV encoding or decoding.
Definition: tlv.hpp:54
#define NDN_LOG_INIT(name)
Define a non-member log module.
Definition: logger.hpp:169
std::string to_string(const errinfo_stacktrace &x)
Definition: exception.cpp:30
Contains the ndn-cxx security framework.
std::function< void(const Interest &)> InterestValidationSuccessCallback
Callback to report a successful Interest validation.
std::function< void(const Interest &, const ValidationError &)> InterestValidationFailureCallback
Callback to report a failed Interest validation.
std::function< void(const Data &)> DataValidationSuccessCallback
Callback to report a successful Data validation.
@ V03
Sign Interest using Packet Specification v0.3 semantics.
@ V02
Sign Interest using Packet Specification v0.2 semantics.
std::function< void(const Data &, const ValidationError &)> DataValidationFailureCallback
Callback to report a failed Data validation.
::boost::chrono::nanoseconds nanoseconds
Definition: time.hpp:54
Definition: data.cpp:25
#define NDN_LOG_DEBUG_DEPTH(x)
Definition: validator.cpp:31
#define NDN_LOG_TRACE_DEPTH(x)
Definition: validator.cpp:32