certificate-bundle-fetcher.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2024 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 
27 #include "ndn-cxx/tag.hpp"
28 #include "ndn-cxx/util/logger.hpp"
29 
30 #define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(state->getDepth() + 1, '>') << ' ' << x)
31 
32 namespace ndn::security {
33 
35 
38 
39 CertificateBundleFetcher::CertificateBundleFetcher(unique_ptr<CertificateFetcher> inner, Face& face)
40  : m_inner(std::move(inner))
41  , m_face(face)
42 {
43  BOOST_ASSERT(m_inner != nullptr);
44 }
45 
46 void
48 {
49  m_certStorage = &certStorage;
50  m_inner->setCertificateStorage(certStorage);
51 }
52 
53 void
54 CertificateBundleFetcher::doFetch(const shared_ptr<CertificateRequest>& certRequest,
55  const shared_ptr<ValidationState>& state,
56  const ValidationContinuation& continueValidation)
57 {
58  auto dataValidationState = std::dynamic_pointer_cast<DataValidationState>(state);
59  if (dataValidationState == nullptr) {
60  return m_inner->fetch(certRequest, state, continueValidation);
61  }
62 
63  // check if a bundle segment was fetched before
64  shared_ptr<BundleNameTag> bundleNameTag = state->getTag<BundleNameTag>();
65  if (bundleNameTag == nullptr) {
66  const Name& originalDataName = dataValidationState->getOriginalData().getName();
67  if (originalDataName.empty()) {
68  return m_inner->fetch(certRequest, state, continueValidation);
69  }
70  // derive certificate bundle name from original data name
71  Name bundleNamePrefix = deriveBundleName(originalDataName);
72  fetchFirstBundleSegment(bundleNamePrefix, certRequest, state, continueValidation);
73  }
74  else {
75  Name fullBundleName = bundleNameTag->get();
76  fetchNextBundleSegment(fullBundleName, fullBundleName.get(-1).getSuccessor(),
77  certRequest, state, continueValidation);
78  }
79 }
80 
81 void
82 CertificateBundleFetcher::fetchFirstBundleSegment(const Name& bundleNamePrefix,
83  const shared_ptr<CertificateRequest>& certRequest,
84  const shared_ptr<ValidationState>& state,
85  const ValidationContinuation& continueValidation)
86 {
87  Interest bundleInterest = Interest(bundleNamePrefix);
88  bundleInterest.setCanBePrefix(true);
89  bundleInterest.setMustBeFresh(true);
90  bundleInterest.setInterestLifetime(m_bundleInterestLifetime);
91 
92  m_face.expressInterest(bundleInterest,
93  [=] (const Interest&, const Data& data) {
94  dataCallback(data, true, certRequest, state, continueValidation);
95  },
96  [=] (const Interest&, const lp::Nack& nack) {
97  nackCallback(nack, certRequest, state, continueValidation, bundleNamePrefix);
98  },
99  [=] (const Interest&) {
100  timeoutCallback(certRequest, state, continueValidation, bundleNamePrefix);
101  });
102 }
103 
104 void
105 CertificateBundleFetcher::fetchNextBundleSegment(const Name& fullBundleName, const name::Component& segmentNo,
106  const shared_ptr<CertificateRequest>& certRequest,
107  const shared_ptr<ValidationState>& state,
108  const ValidationContinuation& continueValidation)
109 {
110  shared_ptr<FinalBlockIdTag> finalBlockId = state->getTag<FinalBlockIdTag>();
111  if (finalBlockId != nullptr && segmentNo > finalBlockId->get()) {
112  return m_inner->fetch(certRequest, state, continueValidation);
113  }
114 
115  Interest bundleInterest(fullBundleName.getPrefix(-1).append(segmentNo));
116  bundleInterest.setCanBePrefix(false);
117  bundleInterest.setMustBeFresh(false);
118  bundleInterest.setInterestLifetime(m_bundleInterestLifetime);
119 
120  m_face.expressInterest(bundleInterest,
121  [=] (const Interest&, const Data& data) {
122  dataCallback(data, false, certRequest, state, continueValidation);
123  },
124  [=] (const Interest&, const lp::Nack& nack) {
125  nackCallback(nack, certRequest, state, continueValidation, fullBundleName);
126  },
127  [=] (const Interest&) {
128  timeoutCallback(certRequest, state, continueValidation, fullBundleName);
129  });
130 }
131 
132 void
133 CertificateBundleFetcher::dataCallback(const Data& bundleData,
134  bool isSegmentZeroExpected,
135  const shared_ptr<CertificateRequest>& certRequest,
136  const shared_ptr<ValidationState>& state,
137  const ValidationContinuation& continueValidation)
138 {
139  NDN_LOG_DEBUG_DEPTH("Fetched certificate bundle " << bundleData.getName());
140 
141  name::Component currentSegment = bundleData.getName().get(-1);
142  if (!currentSegment.isSegment()) {
143  return m_inner->fetch(certRequest, state, continueValidation);
144  }
145 
146  if (isSegmentZeroExpected && currentSegment.toSegment() != 0) {
147  // fetch segment zero
148  fetchNextBundleSegment(bundleData.getName(), name::Component::fromSegment(0),
149  certRequest, state, continueValidation);
150  }
151  else {
152  state->setTag(make_shared<BundleNameTag>(bundleData.getName()));
153 
154  const auto& finalBlockId = bundleData.getFinalBlock();
155  if (finalBlockId) {
156  state->setTag(make_shared<FinalBlockIdTag>(*finalBlockId));
157  }
158 
159  Block bundleContent = bundleData.getContent();
160  bundleContent.parse();
161 
162  // store all the certificates in unverified cache
163  for (const auto& block : bundleContent.elements()) {
164  m_certStorage->cacheUnverifiedCert(Certificate(block));
165  }
166 
167  auto cert = m_certStorage->getUnverifiedCertCache().find(certRequest->interest);
168  continueValidation(*cert, state);
169  }
170 }
171 
172 void
173 CertificateBundleFetcher::nackCallback(const lp::Nack& nack,
174  const shared_ptr<CertificateRequest>& certRequest,
175  const shared_ptr<ValidationState>& state,
176  const ValidationContinuation& continueValidation,
177  const Name& bundleName)
178 {
179  NDN_LOG_DEBUG_DEPTH("NACK (" << nack.getReason() << ") while fetching certificate bundle "
180  << bundleName);
181 
182  m_inner->fetch(certRequest, state, continueValidation);
183 }
184 
185 void
186 CertificateBundleFetcher::timeoutCallback(const shared_ptr<CertificateRequest>& certRequest,
187  const shared_ptr<ValidationState>& state,
188  const ValidationContinuation& continueValidation,
189  const Name& bundleName)
190 {
191  NDN_LOG_DEBUG_DEPTH("Timeout while fetching certificate bundle " << bundleName);
192 
193  m_inner->fetch(certRequest, state, continueValidation);
194 }
195 
196 Name
197 CertificateBundleFetcher::deriveBundleName(const Name& name)
198 {
199  Name bundleName = name;
200  const auto& lastComponent = name.at(-1);
201 
202  if (lastComponent.isImplicitSha256Digest()) {
203  if (name.size() >= 2 && name.get(-2).isSegment()) {
204  bundleName = name.getPrefix(-2);
205  }
206  else {
207  bundleName = name.getPrefix(-1);
208  }
209  }
210  else if (lastComponent.isSegment()) {
211  bundleName = name.getPrefix(-1);
212  }
213 
214  bundleName.append("_BUNDLE");
215  bundleName.appendNumber(0);
216  return bundleName;
217 }
218 
219 } // namespace ndn::security
#define NDN_LOG_DEBUG_DEPTH(x)
Represents a Data packet.
Definition: data.hpp:39
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:91
PendingInterestHandle expressInterest(const Interest &interest, const DataCallback &afterSatisfied, const NackCallback &afterNacked, const TimeoutCallback &afterTimeout)
Express an Interest.
Definition: face.cpp:151
Represents an Interest packet.
Definition: interest.hpp:50
Interest & setCanBePrefix(bool canBePrefix)
Add or remove CanBePrefix element.
Definition: interest.cpp:372
Interest & setMustBeFresh(bool mustBeFresh)
Add or remove MustBeFresh element.
Definition: interest.cpp:382
Interest & setInterestLifetime(time::milliseconds lifetime)
Set the Interest's lifetime.
Definition: interest.cpp:451
Represents an absolute name.
Definition: name.hpp:45
bool empty() const noexcept
Checks if the name is empty, i.e., has no components.
Definition: name.hpp:171
const Component & get(ssize_t i) const noexcept
Returns an immutable reference to the component at the specified index.
Definition: name.hpp:192
Provides a tag type for simple types.
Definition: tag.hpp:56
Represents a Network Nack.
Definition: nack.hpp:39
static Component fromSegment(uint64_t segmentNo)
Create a segment number component using NDN naming conventions.
Component getSuccessor() const
Get the successor of this name component.
Fetch certificate bundle from the network.
CertificateBundleFetcher(unique_ptr< CertificateFetcher > inner, Face &face)
void doFetch(const shared_ptr< CertificateRequest > &certRequest, const shared_ptr< ValidationState > &state, const ValidationContinuation &continueValidation) override
Asynchronous certificate fetching implementation.
void setCertificateStorage(CertificateStorage &certStorage) override
Set the storage for this and inner certificate fetcher.
const Certificate * find(const Name &certPrefix) const
Get certificate given key name.
std::function< void(const Certificate &cert, const shared_ptr< ValidationState > &state)> ValidationContinuation
Storage for trusted anchors, verified certificate cache, and unverified certificate cache.
void cacheUnverifiedCert(Certificate &&cert)
Cache unverified certificate for a period of time (5 minutes).
const CertificateCache & getUnverifiedCertCache() const
#define NDN_LOG_INIT(name)
Define a non-member log module.
Definition: logger.hpp:169
Contains the ndn-cxx security framework.
SimpleTag< name::Component, 1001 > FinalBlockIdTag
@ Name
Definition: tlv.hpp:71
@ Data
Definition: tlv.hpp:69
@ Interest
Definition: tlv.hpp:68
Definition: data.cpp:25