ndn-cxx: NDN C++ Library 0.9.0-33-g832ea91d
Loading...
Searching...
No Matches
validation-policy-command-interest.cpp
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2013-2023 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
24namespace ndn::security {
25
27 const Options& options)
28 : m_options(options)
29 , m_index(m_container.get<0>())
30 , m_queue(m_container.get<1>())
31{
32 if (inner == nullptr) {
33 NDN_THROW(std::invalid_argument("inner policy is missing"));
34 }
35 setInnerPolicy(std::move(inner));
36
37 m_options.gracePeriod = std::max(m_options.gracePeriod, 0_ns);
38}
39
40void
41ValidationPolicyCommandInterest::checkPolicy(const Data& data, const shared_ptr<ValidationState>& state,
42 const ValidationContinuation& continueValidation)
43{
44 getInnerPolicy().checkPolicy(data, state, continueValidation);
45}
46
47void
48ValidationPolicyCommandInterest::checkPolicy(const Interest& interest, const shared_ptr<ValidationState>& state,
49 const ValidationContinuation& continueValidation)
50{
51 auto [isOk, keyName, timestamp] = parseCommandInterest(interest, state);
52 if (!isOk) {
53 return;
54 }
55
56 if (!checkTimestamp(state, keyName, timestamp)) {
57 return;
58 }
59
60 getInnerPolicy().checkPolicy(interest, state, continueValidation);
61}
62
63std::tuple<bool, Name, time::system_clock::time_point>
64ValidationPolicyCommandInterest::parseCommandInterest(const Interest& interest,
65 const shared_ptr<ValidationState>& state)
66{
67 auto sigInfo = getSignatureInfo(interest, *state);
68 if (!state->getOutcome()) { // already failed
69 return {false, {}, {}};
70 }
71
73
74 auto fmt = state->getTag<SignedInterestFormatTag>();
75 BOOST_ASSERT(fmt);
76 if (*fmt == SignedInterestFormat::V03) {
77 // SignatureTime is a hard requirement of this policy
78 // New apps should use the more flexible ValidationPolicySignedInterest (v0.3 only)
79 auto optionalTimestamp = sigInfo.getTime();
80 if (!optionalTimestamp) {
81 state->fail({ValidationError::POLICY_ERROR, "Signed Interest `" +
82 interest.getName().toUri() + "` lacks required SignatureTime element"});
83 return {false, {}, {}};
84 }
85
86 timestamp = *optionalTimestamp;
87 }
88 else {
89 const Name& name = interest.getName();
90 if (name.size() < command_interest::MIN_SIZE) {
92 "Command Interest name too short `" + interest.getName().toUri() + "`"});
93 return {false, {}, {}};
94 }
95
96 const auto& timestampComp = name.at(command_interest::POS_TIMESTAMP);
97 if (!timestampComp.isNumber()) {
98 state->fail({ValidationError::POLICY_ERROR, "Command Interest `" +
99 interest.getName().toUri() + "` lacks required timestamp component"});
100 return {false, {}, {}};
101 }
102
103 timestamp = time::fromUnixTimestamp(time::milliseconds(timestampComp.toNumber()));
104 }
105
106 Name klName = getKeyLocatorName(sigInfo, *state);
107 if (!state->getOutcome()) { // already failed
108 return {false, {}, {}};
109 }
110
111 return {true, klName, timestamp};
112}
113
114void
115ValidationPolicyCommandInterest::cleanup()
116{
117 auto expiring = time::steady_clock::now() - m_options.recordLifetime;
118
119 while ((!m_queue.empty() && m_queue.front().lastRefreshed <= expiring) ||
120 (m_options.maxRecords >= 0 &&
121 m_queue.size() > static_cast<size_t>(m_options.maxRecords))) {
122 m_queue.pop_front();
123 }
124}
125
126bool
127ValidationPolicyCommandInterest::checkTimestamp(const shared_ptr<ValidationState>& state,
128 const Name& keyName, time::system_clock::time_point timestamp)
129{
130 this->cleanup();
131
132 auto now = time::system_clock::now();
133
134 if (timestamp < now - m_options.gracePeriod || timestamp > now + m_options.gracePeriod) {
136 "Timestamp is outside the grace period for key " + keyName.toUri()});
137 return false;
138 }
139
140 auto it = m_index.find(keyName);
141 if (it != m_index.end()) {
142 if (timestamp <= it->timestamp) {
144 "Timestamp is reordered for key " + keyName.toUri()});
145 return false;
146 }
147 }
148
149 auto interestState = std::dynamic_pointer_cast<InterestValidationState>(state);
150 BOOST_ASSERT(interestState != nullptr);
151 interestState->afterSuccess.connect([=] (const Interest&) { insertNewRecord(keyName, timestamp); });
152 return true;
153}
154
155void
156ValidationPolicyCommandInterest::insertNewRecord(const Name& keyName, time::system_clock::time_point timestamp)
157{
158 // try to insert new record
159 LastTimestampRecord newRecord{keyName, timestamp, time::steady_clock::now()};
160 auto [i, isNew] = m_queue.push_back(newRecord);
161
162 if (!isNew) {
163 BOOST_ASSERT(i->keyName == keyName);
164
165 // set lastRefreshed field, and move to queue tail
166 m_queue.erase(i);
167 isNew = m_queue.push_back(newRecord).second;
168 BOOST_VERIFY(isNew);
169 }
170}
171
172} // namespace ndn::security
Represents a Data packet.
Definition data.hpp:39
Represents an Interest packet.
Definition interest.hpp:50
const Name & getName() const noexcept
Get the Interest name.
Definition interest.hpp:179
const Component & at(ssize_t i) const
Returns an immutable reference to the component at the specified index, with bounds checking.
Definition name.cpp:146
@ POLICY_ERROR
The packet violates the validation rules enforced by the policy.
ssize_t maxRecords
Max number of distinct public keys of which to record the last timestamp.
time::nanoseconds recordLifetime
Max lifetime of a last timestamp record.
void checkPolicy(const Data &data, const shared_ptr< ValidationState > &state, const ValidationContinuation &continueValidation) override
Check data against the policy.
ValidationPolicyCommandInterest(unique_ptr< ValidationPolicy > inner, const Options &options={})
Constructor.
std::function< void(const shared_ptr< CertificateRequest > &certRequest, const shared_ptr< ValidationState > &state)> ValidationContinuation
ValidationPolicy & getInnerPolicy()
Return the inner policy.
virtual void checkPolicy(const Data &data, const shared_ptr< ValidationState > &state, const ValidationContinuation &continueValidation)=0
Check data against the policy.
void setInnerPolicy(unique_ptr< ValidationPolicy > innerPolicy)
Set inner policy.
static time_point now() noexcept
Definition time.cpp:79
static time_point now() noexcept
Definition time.cpp:45
::boost::chrono::time_point< system_clock > time_point
Definition time.hpp:205
#define NDN_THROW(e)
Definition exception.hpp:56
constexpr size_t MIN_SIZE
Minimum number of name components for a Command Interest.
constexpr ssize_t POS_TIMESTAMP
Contains the ndn-cxx security framework.
SimpleTag< SignedInterestFormat, 1002 > SignedInterestFormatTag
@ V03
Sign Interest using Packet Specification v0.3 semantics.
SignatureInfo getSignatureInfo(const Interest &interest, ValidationState &state)
Extract SignatureInfo from a signed Interest.
Name getKeyLocatorName(const SignatureInfo &si, ValidationState &state)
Extract the KeyLocator name from a SignatureInfo element.
constexpr system_clock::time_point fromUnixTimestamp(system_clock::duration d)
Convert UNIX timestamp to system_clock::time_point.
Definition time.hpp:274
::boost::chrono::milliseconds milliseconds
Definition time.hpp:52
@ Name
Definition tlv.hpp:71