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