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 
24 namespace 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 
40 void
41 ValidationPolicyCommandInterest::checkPolicy(const Data& data, const shared_ptr<ValidationState>& state,
42  const ValidationContinuation& continueValidation)
43 {
44  getInnerPolicy().checkPolicy(data, state, continueValidation);
45 }
46 
47 void
48 ValidationPolicyCommandInterest::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 
63 std::tuple<bool, Name, time::system_clock::time_point>
64 ValidationPolicyCommandInterest::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) {
91  state->fail({ValidationError::POLICY_ERROR,
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 
114 void
115 ValidationPolicyCommandInterest::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 
126 bool
127 ValidationPolicyCommandInterest::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) {
135  state->fail({ValidationError::POLICY_ERROR,
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) {
143  state->fail({ValidationError::POLICY_ERROR,
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 
155 void
156 ValidationPolicyCommandInterest::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
@ Interest
Definition: tlv.hpp:68