blob: 45a0c38c64e1bdc65fc99314cd46e035ff67901f [file] [log] [blame]
Manika Mittal95c80702017-01-27 09:54:41 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shiebfe4a22018-04-01 23:53:40 +00002/*
3 * Copyright (c) 2013-2018 Regents of the University of California.
Manika Mittal95c80702017-01-27 09:54:41 -08004 *
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
22#include "certificate-bundle-fetcher.hpp"
23#include "face.hpp"
24#include "util/logger.hpp"
25
26namespace ndn {
27namespace security {
28namespace v2 {
29
30NDN_LOG_INIT(ndn.security.v2.CertificateBundleFetcher);
31
32#define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(state->getDepth() + 1, '>') << " " << x)
33#define NDN_LOG_TRACE_DEPTH(x) NDN_LOG_TRACE(std::string(state->getDepth() + 1, '>') << " " << x)
34
35CertificateBundleFetcher::CertificateBundleFetcher(unique_ptr<CertificateFetcher> inner,
36 Face& face)
37 : m_inner(std::move(inner))
38 , m_face(face)
39 , m_bundleInterestLifetime(1000)
40{
41 BOOST_ASSERT(m_inner != nullptr);
42}
43
44void
45CertificateBundleFetcher::setBundleInterestLifetime(time::milliseconds time)
46{
47 m_bundleInterestLifetime = time;
48}
49
50time::milliseconds
51CertificateBundleFetcher::getBundleInterestLifetime() const
52{
53 return m_bundleInterestLifetime;
54}
55
56void
57CertificateBundleFetcher::setCertificateStorage(CertificateStorage& certStorage)
58{
59 m_certStorage = &certStorage;
60 m_inner->setCertificateStorage(certStorage);
61}
62
63void
64CertificateBundleFetcher::doFetch(const shared_ptr<CertificateRequest>& certRequest,
65 const shared_ptr<ValidationState>& state,
66 const ValidationContinuation& continueValidation)
67{
68 auto dataValidationState = dynamic_pointer_cast<DataValidationState>(state);
69 if (dataValidationState == nullptr) {
70 return m_inner->fetch(certRequest, state, continueValidation);
71 }
72
73 // check if a bundle segment was fetched before
74 shared_ptr<BundleNameTag> bundleNameTag = state->getTag<BundleNameTag>();
75 if (bundleNameTag == nullptr) {
76 const Name& originalDataName = dataValidationState->getOriginalData().getName();
77 if (originalDataName.empty()) {
78 return m_inner->fetch(certRequest, state, continueValidation);
79 }
80 // derive certificate bundle name from original data name
81 Name bundleNamePrefix = deriveBundleName(originalDataName);
82 fetchFirstBundleSegment(bundleNamePrefix, certRequest, state, continueValidation);
83 }
84 else {
85 Name fullBundleName = bundleNameTag->get();
86 fetchNextBundleSegment(fullBundleName, fullBundleName.get(-1).getSuccessor(),
87 certRequest, state, continueValidation);
88 }
89}
90
91void
92CertificateBundleFetcher::fetchFirstBundleSegment(const Name& bundleNamePrefix,
93 const shared_ptr<CertificateRequest>& certRequest,
94 const shared_ptr<ValidationState>& state,
95 const ValidationContinuation& continueValidation)
96{
97 Interest bundleInterest = Interest(bundleNamePrefix);
98 bundleInterest.setInterestLifetime(m_bundleInterestLifetime);
99 bundleInterest.setMustBeFresh(true);
100 bundleInterest.setChildSelector(1);
101
102 m_face.expressInterest(bundleInterest,
103 [=] (const Interest& interest, const Data& data) {
104 dataCallback(data, true, certRequest, state, continueValidation);
105 },
106 [=] (const Interest& interest, const lp::Nack& nack) {
107 nackCallback(nack, certRequest, state, continueValidation, bundleNamePrefix);
108 },
109 [=] (const Interest& interest) {
110 timeoutCallback(certRequest, state, continueValidation, bundleNamePrefix);
111 });
112}
113
114void
115CertificateBundleFetcher::fetchNextBundleSegment(const Name& fullBundleName, const name::Component& segmentNo,
116 const shared_ptr<CertificateRequest>& certRequest,
117 const shared_ptr<ValidationState>& state,
118 const ValidationContinuation& continueValidation)
119{
120 shared_ptr<FinalBlockIdTag> finalBlockId = state->getTag<FinalBlockIdTag>();
121 if (finalBlockId != nullptr && segmentNo > finalBlockId->get()) {
122 return m_inner->fetch(certRequest, state, continueValidation);
123 }
124
125 Interest bundleInterest(fullBundleName.getPrefix(-1).append(segmentNo));
126 bundleInterest.setInterestLifetime(m_bundleInterestLifetime);
127 bundleInterest.setMustBeFresh(false);
128
129 m_face.expressInterest(bundleInterest,
130 [=] (const Interest& interest, const Data& data) {
131 dataCallback(data, false, certRequest, state, continueValidation);
132 },
133 [=] (const Interest& interest, const lp::Nack& nack) {
134 nackCallback(nack, certRequest, state, continueValidation, fullBundleName);
135 },
136 [=] (const Interest& interest) {
137 timeoutCallback(certRequest, state, continueValidation, fullBundleName);
138 });
139}
140
141void
142CertificateBundleFetcher::dataCallback(const Data& bundleData,
143 bool isSegmentZeroExpected,
144 const shared_ptr<CertificateRequest>& certRequest,
145 const shared_ptr<ValidationState>& state,
146 const ValidationContinuation& continueValidation)
147{
148 NDN_LOG_DEBUG_DEPTH("Fetched certificate bundle from network " << bundleData.getName());
149
150 name::Component currentSegment = bundleData.getName().get(-1);
151 if (!currentSegment.isSegment()) {
152 return m_inner->fetch(certRequest, state, continueValidation);
153 }
154
155 if (isSegmentZeroExpected && currentSegment.toSegment() != 0) {
156 // fetch segment zero
157 fetchNextBundleSegment(bundleData.getName(), name::Component::fromSegment(0),
158 certRequest, state, continueValidation);
159 }
160 else {
161 state->setTag(make_shared<BundleNameTag>(bundleData.getName()));
162
Junxiao Shiebfe4a22018-04-01 23:53:40 +0000163 const auto& finalBlockId = bundleData.getFinalBlock();
164 if (!finalBlockId) {
165 state->setTag(make_shared<FinalBlockIdTag>(*finalBlockId));
Manika Mittal95c80702017-01-27 09:54:41 -0800166 }
167
168 Block bundleContent = bundleData.getContent();
169 bundleContent.parse();
170
171 // store all the certificates in unverified cache
172 for (const auto& block : bundleContent.elements()) {
173 m_certStorage->cacheUnverifiedCert(Certificate(block));
174 }
175
176 auto cert = m_certStorage->getUnverifiedCertCache().find(certRequest->m_interest);
177 continueValidation(*cert, state);
178 }
179}
180
181void
182CertificateBundleFetcher::nackCallback(const lp::Nack& nack,
183 const shared_ptr<CertificateRequest>& certRequest,
184 const shared_ptr<ValidationState>& state,
185 const ValidationContinuation& continueValidation,
186 const Name& bundleName)
187{
188 NDN_LOG_DEBUG_DEPTH("NACK (" << nack.getReason() << ") while fetching certificate bundle"
189 << bundleName);
190
191 m_inner->fetch(certRequest, state, continueValidation);
192}
193
194void
195CertificateBundleFetcher::timeoutCallback(const shared_ptr<CertificateRequest>& certRequest,
196 const shared_ptr<ValidationState>& state,
197 const ValidationContinuation& continueValidation,
198 const Name& bundleName)
199{
200 NDN_LOG_DEBUG_DEPTH("Timeout while fetching certificate bundle" << bundleName);
201
202 m_inner->fetch(certRequest, state, continueValidation);
203}
204
205Name
206CertificateBundleFetcher::deriveBundleName(const Name& name)
207{
208 name::Component lastComponent = name.at(-1);
209
210 Name bundleName = name;
211 if (lastComponent.isImplicitSha256Digest()) {
212 if (name.size() >= 2 && name.get(-2).isSegment()) {
213 bundleName = name.getPrefix(-2);
214 }
215 else {
216 bundleName = name.getPrefix(-1);
217 }
218 }
219 else if (lastComponent.isSegment()) {
220 bundleName = name.getPrefix(-1);
221 }
222 bundleName.append("_BUNDLE");
223 bundleName.appendNumber(00);
224
225 return bundleName;
226}
227
228} // namespace v2
229} // namespace security
230} // namespace ndn