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-2022 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 {
28 namespace security {
29 inline namespace v2 {
30 
32 
33 #define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(state->getDepth() + 1, '>') << " " << x)
34 #define NDN_LOG_TRACE_DEPTH(x) NDN_LOG_TRACE(std::string(state->getDepth() + 1, '>') << " " << x)
35 
36 Validator::Validator(unique_ptr<ValidationPolicy> policy, unique_ptr<CertificateFetcher> certFetcher)
37  : m_policy(std::move(policy))
38  , m_certFetcher(std::move(certFetcher))
39 {
40  BOOST_ASSERT(m_policy != nullptr);
41  BOOST_ASSERT(m_certFetcher != nullptr);
42  m_policy->setValidator(*this);
43  m_certFetcher->setCertificateStorage(*this);
44 }
45 
46 Validator::~Validator() noexcept = default;
47 
48 void
49 Validator::validate(const Data& data,
50  const DataValidationSuccessCallback& successCb,
51  const DataValidationFailureCallback& failureCb)
52 {
53  auto state = make_shared<DataValidationState>(data, successCb, failureCb);
54  NDN_LOG_DEBUG_DEPTH("Start validating data " << data.getName());
55 
56  m_policy->checkPolicy(data, state, [this] (auto&&... args) {
57  continueValidation(std::forward<decltype(args)>(args)...);
58  });
59 }
60 
61 void
62 Validator::validate(const Interest& interest,
63  const InterestValidationSuccessCallback& successCb,
64  const InterestValidationFailureCallback& failureCb)
65 {
66  auto state = make_shared<InterestValidationState>(interest, successCb, failureCb);
67  NDN_LOG_DEBUG_DEPTH("Start validating interest " << interest.getName());
68 
69  try {
71  state->setTag(make_shared<SignedInterestFormatTag>(fmt));
72  }
73  catch (const tlv::Error& e) {
74  return state->fail({ValidationError::MALFORMED_SIGNATURE, "Malformed InterestSignatureInfo in `" +
75  interest.getName().toUri() + "`: " + e.what()});
76  }
77 
78  m_policy->checkPolicy(interest, state, [this] (auto&&... args) {
79  continueValidation(std::forward<decltype(args)>(args)...);
80  });
81 }
82 
83 void
84 Validator::validate(const Certificate& cert, const shared_ptr<ValidationState>& state)
85 {
86  NDN_LOG_DEBUG_DEPTH("Start validating certificate " << cert.getName());
87 
88  if (!cert.isValid()) {
89  return state->fail({ValidationError::EXPIRED_CERT, "`" + cert.getName().toUri() + "` is valid "
90  "between " + boost::lexical_cast<std::string>(cert.getValidityPeriod())});
91  }
92 
93  m_policy->checkPolicy(cert, state,
94  [this, cert] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
95  if (certRequest == nullptr) {
96  state->fail({ValidationError::POLICY_ERROR, "Validation policy is not allowed to designate `" +
97  cert.getName().toUri() + "` as a trust anchor"});
98  }
99  else {
100  // need to fetch key and validate it
101  state->addCertificate(cert);
102  requestCertificate(certRequest, state);
103  }
104  });
105 }
106 
107 void
108 Validator::continueValidation(const shared_ptr<CertificateRequest>& certRequest,
109  const shared_ptr<ValidationState>& state)
110 {
111  BOOST_ASSERT(state);
112 
113  if (certRequest == nullptr) {
114  state->bypassValidation();
115  }
116  else {
117  // need to fetch key and validate it
118  requestCertificate(certRequest, state);
119  }
120 }
121 
122 void
123 Validator::requestCertificate(const shared_ptr<CertificateRequest>& certRequest,
124  const shared_ptr<ValidationState>& state)
125 {
126  if (state->getDepth() >= m_maxDepth) {
127  state->fail({ValidationError::EXCEEDED_DEPTH_LIMIT, to_string(m_maxDepth)});
128  return;
129  }
130 
131  if (certRequest->interest.getName() == SigningInfo::getDigestSha256Identity()) {
132  state->verifyOriginalPacket(nullopt);
133  return;
134  }
135 
136  if (state->hasSeenCertificateName(certRequest->interest.getName())) {
137  state->fail({ValidationError::LOOP_DETECTED, certRequest->interest.getName().toUri()});
138  return;
139  }
140 
141  NDN_LOG_DEBUG_DEPTH("Retrieving " << certRequest->interest.getName());
142 
143  auto cert = findTrustedCert(certRequest->interest);
144  if (cert != nullptr) {
145  NDN_LOG_TRACE_DEPTH("Found trusted certificate " << cert->getName());
146 
147  cert = state->verifyCertificateChain(*cert);
148  if (cert != nullptr) {
149  state->verifyOriginalPacket(*cert);
150  }
151  for (auto trustedCert = std::make_move_iterator(state->m_certificateChain.begin());
152  trustedCert != std::make_move_iterator(state->m_certificateChain.end());
153  ++trustedCert) {
154  cacheVerifiedCertificate(*trustedCert);
155  }
156  return;
157  }
158 
159  m_certFetcher->fetch(certRequest, state, [this] (auto&&... args) {
160  validate(std::forward<decltype(args)>(args)...);
161  });
162 }
163 
165 // Trust anchor management
167 
168 // to change visibility from protected to public
169 
170 void
171 Validator::loadAnchor(const std::string& groupId, Certificate&& cert)
172 {
173  CertificateStorage::loadAnchor(groupId, std::move(cert));
174 }
175 
176 void
177 Validator::loadAnchor(const std::string& groupId, const std::string& certfilePath,
178  time::nanoseconds refreshPeriod, bool isDir)
179 {
180  CertificateStorage::loadAnchor(groupId, certfilePath, refreshPeriod, isDir);
181 }
182 
183 void
185 {
187 }
188 
189 void
191 {
192  CertificateStorage::cacheVerifiedCert(std::move(cert));
193 }
194 
195 void
197 {
199 }
200 
201 } // inline namespace v2
202 } // namespace security
203 } // namespace ndn
Represents a Data packet.
Definition: data.hpp:39
Represents an Interest packet.
Definition: interest.hpp:50
const Name & getName() const noexcept
Definition: interest.hpp:173
optional< SignatureInfo > getSignatureInfo() const
Get the InterestSignatureInfo element.
Definition: interest.cpp:531
static const Name & getDigestSha256Identity()
A localhost identity to indicate that the signature is generated using SHA-256.
const Certificate * findTrustedCert(const Interest &interestForCert) const
Find a trusted certificate in trust anchor container or in verified cache.
void loadAnchor(const std::string &groupId, Certificate &&cert)
Load static trust anchor.
void resetVerifiedCerts()
Remove any cached verified certificates.
void resetAnchors()
Remove any previously loaded static or dynamic trust anchor.
void cacheVerifiedCert(Certificate &&cert)
Cache verified certificate a period of time (1 hour).
Represents an NDN certificate.
Definition: certificate.hpp:60
@ LOOP_DETECTED
Loop detected in the certification chain.
@ EXCEEDED_DEPTH_LIMIT
Exceeded validation depth limit.
@ MALFORMED_SIGNATURE
The signature (e.g., SignatureInfo element) is missing or malformed.
@ POLICY_ERROR
The packet violates the validation rules enforced by the policy.
@ EXPIRED_CERT
The certificate expired or is not yet valid.
Interface for validating data and interest packets.
Definition: validator.hpp:62
void cacheVerifiedCertificate(Certificate &&cert)
Cache verified cert a period of time (1 hour).
Definition: validator.cpp:190
void resetAnchors()
Remove any previously loaded static or dynamic trust anchor.
Definition: validator.cpp:184
Validator(unique_ptr< ValidationPolicy > policy, unique_ptr< CertificateFetcher > certFetcher)
Validator constructor.
Definition: validator.cpp:36
void resetVerifiedCertificates()
Remove any cached verified certificates.
Definition: validator.cpp:196
void validate(const Data &data, const DataValidationSuccessCallback &successCb, const DataValidationFailureCallback &failureCb)
Asynchronously validate data.
Definition: validator.cpp:49
void loadAnchor(const std::string &groupId, Certificate &&cert)
Load static trust anchor.
Definition: validator.cpp:171
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:163
std::string to_string(const errinfo_stacktrace &x)
Definition: exception.cpp:31
std::function< void(const Data &)> DataValidationSuccessCallback
Callback to report a successful Data validation.
std::function< void(const Data &, const ValidationError &)> DataValidationFailureCallback
Callback to report a failed Data validation.
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.
@ V03
Sign Interest using Packet Specification v0.3 semantics.
@ V02
Sign Interest using Packet Specification v0.2 semantics.
boost::chrono::nanoseconds nanoseconds
Definition: time.hpp:50
Definition: data.cpp:25
#define NDN_LOG_DEBUG_DEPTH(x)
Definition: validator.cpp:33
#define NDN_LOG_TRACE_DEPTH(x)
Definition: validator.cpp:34