blob: 227a434bb1c64ed073fe131908b7e98a137043f5 [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);
Junxiao Shib55e5d32018-07-18 13:32:00 -060098 bundleInterest.setCanBePrefix(true);
Manika Mittal95c80702017-01-27 09:54:41 -080099 bundleInterest.setMustBeFresh(true);
100 bundleInterest.setChildSelector(1);
Junxiao Shib55e5d32018-07-18 13:32:00 -0600101 bundleInterest.setInterestLifetime(m_bundleInterestLifetime);
Manika Mittal95c80702017-01-27 09:54:41 -0800102
103 m_face.expressInterest(bundleInterest,
104 [=] (const Interest& interest, const Data& data) {
105 dataCallback(data, true, certRequest, state, continueValidation);
106 },
107 [=] (const Interest& interest, const lp::Nack& nack) {
108 nackCallback(nack, certRequest, state, continueValidation, bundleNamePrefix);
109 },
110 [=] (const Interest& interest) {
111 timeoutCallback(certRequest, state, continueValidation, bundleNamePrefix);
112 });
113}
114
115void
116CertificateBundleFetcher::fetchNextBundleSegment(const Name& fullBundleName, const name::Component& segmentNo,
117 const shared_ptr<CertificateRequest>& certRequest,
118 const shared_ptr<ValidationState>& state,
119 const ValidationContinuation& continueValidation)
120{
121 shared_ptr<FinalBlockIdTag> finalBlockId = state->getTag<FinalBlockIdTag>();
122 if (finalBlockId != nullptr && segmentNo > finalBlockId->get()) {
123 return m_inner->fetch(certRequest, state, continueValidation);
124 }
125
126 Interest bundleInterest(fullBundleName.getPrefix(-1).append(segmentNo));
Junxiao Shib55e5d32018-07-18 13:32:00 -0600127 bundleInterest.setCanBePrefix(false);
Manika Mittal95c80702017-01-27 09:54:41 -0800128 bundleInterest.setMustBeFresh(false);
Junxiao Shib55e5d32018-07-18 13:32:00 -0600129 bundleInterest.setInterestLifetime(m_bundleInterestLifetime);
Manika Mittal95c80702017-01-27 09:54:41 -0800130
131 m_face.expressInterest(bundleInterest,
132 [=] (const Interest& interest, const Data& data) {
133 dataCallback(data, false, certRequest, state, continueValidation);
134 },
135 [=] (const Interest& interest, const lp::Nack& nack) {
136 nackCallback(nack, certRequest, state, continueValidation, fullBundleName);
137 },
138 [=] (const Interest& interest) {
139 timeoutCallback(certRequest, state, continueValidation, fullBundleName);
140 });
141}
142
143void
144CertificateBundleFetcher::dataCallback(const Data& bundleData,
145 bool isSegmentZeroExpected,
146 const shared_ptr<CertificateRequest>& certRequest,
147 const shared_ptr<ValidationState>& state,
148 const ValidationContinuation& continueValidation)
149{
150 NDN_LOG_DEBUG_DEPTH("Fetched certificate bundle from network " << bundleData.getName());
151
152 name::Component currentSegment = bundleData.getName().get(-1);
153 if (!currentSegment.isSegment()) {
154 return m_inner->fetch(certRequest, state, continueValidation);
155 }
156
157 if (isSegmentZeroExpected && currentSegment.toSegment() != 0) {
158 // fetch segment zero
159 fetchNextBundleSegment(bundleData.getName(), name::Component::fromSegment(0),
160 certRequest, state, continueValidation);
161 }
162 else {
163 state->setTag(make_shared<BundleNameTag>(bundleData.getName()));
164
Junxiao Shiebfe4a22018-04-01 23:53:40 +0000165 const auto& finalBlockId = bundleData.getFinalBlock();
166 if (!finalBlockId) {
167 state->setTag(make_shared<FinalBlockIdTag>(*finalBlockId));
Manika Mittal95c80702017-01-27 09:54:41 -0800168 }
169
170 Block bundleContent = bundleData.getContent();
171 bundleContent.parse();
172
173 // store all the certificates in unverified cache
174 for (const auto& block : bundleContent.elements()) {
175 m_certStorage->cacheUnverifiedCert(Certificate(block));
176 }
177
178 auto cert = m_certStorage->getUnverifiedCertCache().find(certRequest->m_interest);
179 continueValidation(*cert, state);
180 }
181}
182
183void
184CertificateBundleFetcher::nackCallback(const lp::Nack& nack,
185 const shared_ptr<CertificateRequest>& certRequest,
186 const shared_ptr<ValidationState>& state,
187 const ValidationContinuation& continueValidation,
188 const Name& bundleName)
189{
190 NDN_LOG_DEBUG_DEPTH("NACK (" << nack.getReason() << ") while fetching certificate bundle"
191 << bundleName);
192
193 m_inner->fetch(certRequest, state, continueValidation);
194}
195
196void
197CertificateBundleFetcher::timeoutCallback(const shared_ptr<CertificateRequest>& certRequest,
198 const shared_ptr<ValidationState>& state,
199 const ValidationContinuation& continueValidation,
200 const Name& bundleName)
201{
202 NDN_LOG_DEBUG_DEPTH("Timeout while fetching certificate bundle" << bundleName);
203
204 m_inner->fetch(certRequest, state, continueValidation);
205}
206
207Name
208CertificateBundleFetcher::deriveBundleName(const Name& name)
209{
210 name::Component lastComponent = name.at(-1);
211
212 Name bundleName = name;
213 if (lastComponent.isImplicitSha256Digest()) {
214 if (name.size() >= 2 && name.get(-2).isSegment()) {
215 bundleName = name.getPrefix(-2);
216 }
217 else {
218 bundleName = name.getPrefix(-1);
219 }
220 }
221 else if (lastComponent.isSegment()) {
222 bundleName = name.getPrefix(-1);
223 }
224 bundleName.append("_BUNDLE");
225 bundleName.appendNumber(00);
226
227 return bundleName;
228}
229
230} // namespace v2
231} // namespace security
232} // namespace ndn