validation-policy-signed-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-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 namespace ndn {
25 namespace security {
26 inline namespace v2 {
27 
29  const Options& options)
30  : m_options(options)
31  , m_byKeyName(m_container.get<0>())
32  , m_byLastRefreshed(m_container.get<1>())
33 {
34  if (inner == nullptr) {
35  NDN_THROW(std::invalid_argument("Inner policy is missing"));
36  }
37  setInnerPolicy(std::move(inner));
38 
39  m_options.timestampGracePeriod = std::max(m_options.timestampGracePeriod, 0_ns);
40 }
41 
42 void
44  const shared_ptr<ValidationState>& state,
45  const ValidationContinuation& continueValidation)
46 {
47  getInnerPolicy().checkPolicy(data, state, continueValidation);
48 }
49 
50 void
52  const shared_ptr<ValidationState>& state,
53  const ValidationContinuation& continueValidation)
54 {
55  auto fmt = state->getTag<SignedInterestFormatTag>();
56  BOOST_ASSERT(fmt);
57 
58  if (!state->getOutcome()) {
59  return;
60  }
61 
62  if (*fmt == SignedInterestFormat::V03 && !checkIncomingInterest(state, interest)) {
63  return;
64  }
65 
66  getInnerPolicy().checkPolicy(interest, state, std::bind(continueValidation, _1, _2));
67 }
68 
69 bool
70 ValidationPolicySignedInterest::checkIncomingInterest(const shared_ptr<ValidationState>& state,
71  const Interest& interest)
72 {
73  // Extract information from Interest
74  BOOST_ASSERT(interest.getSignatureInfo());
75  Name keyName = getKeyLocatorName(interest, *state);
76  auto timestamp = interest.getSignatureInfo()->getTime();
77  auto seqNum = interest.getSignatureInfo()->getSeqNum();
78  auto nonce = interest.getSignatureInfo()->getNonce();
79 
80  auto record = m_byKeyName.find(keyName);
81 
82  if (m_options.shouldValidateTimestamps) {
83  if (!timestamp.has_value()) {
84  state->fail({ValidationError::POLICY_ERROR,
85  "Timestamp is required by policy but is not present"});
86  return false;
87  }
88 
89  auto now = time::system_clock::now();
90  if (time::abs(now - *timestamp) > m_options.timestampGracePeriod) {
91  state->fail({ValidationError::POLICY_ERROR,
92  "Timestamp is outside the grace period for key " + keyName.toUri()});
93  return false;
94  }
95 
96  if (record != m_byKeyName.end() && record->timestamp.has_value() && timestamp <= record->timestamp) {
97  state->fail({ValidationError::POLICY_ERROR,
98  "Timestamp is reordered for key " + keyName.toUri()});
99  return false;
100  }
101  }
102 
103  if (m_options.shouldValidateSeqNums) {
104  if (!seqNum.has_value()) {
105  state->fail({ValidationError::POLICY_ERROR,
106  "Sequence number is required by policy but is not present"});
107  return false;
108  }
109 
110  if (record != m_byKeyName.end() && record->seqNum.has_value() && seqNum <= record->seqNum) {
111  state->fail({ValidationError::POLICY_ERROR,
112  "Sequence number is reordered for key " + keyName.toUri()});
113  return false;
114  }
115  }
116 
117  if (m_options.shouldValidateNonces) {
118  if (!nonce.has_value()) {
119  state->fail({ValidationError::POLICY_ERROR, "Nonce is required by policy but is not present"});
120  return false;
121  }
122 
123  if (record != m_byKeyName.end() && record->observedNonces.get<NonceSet>().count(*nonce) > 0) {
124  state->fail({ValidationError::POLICY_ERROR,
125  "Nonce matches previously-seen nonce for key " + keyName.toUri()});
126  return false;
127  }
128  }
129 
130  if (m_options.maxRecordCount != 0) {
131  auto interestState = dynamic_pointer_cast<InterestValidationState>(state);
132  BOOST_ASSERT(interestState != nullptr);
133  interestState->afterSuccess.connect([=] (const Interest&) {
134  insertRecord(keyName, timestamp, seqNum, nonce);
135  });
136  }
137  return true;
138 }
139 
140 void
141 ValidationPolicySignedInterest::insertRecord(const Name& keyName,
142  optional<time::system_clock::TimePoint> timestamp,
143  optional<uint64_t> seqNum,
144  optional<SigNonce> nonce)
145 {
146  // If key record exists, update last refreshed time. Otherwise, create new record.
147  Container::nth_index<0>::type::iterator it;
148  bool isOk;
149  std::tie(it, isOk) = m_byKeyName.emplace(keyName, timestamp, seqNum);
150  if (!isOk) {
151  // There was already a record for this key, we just need to update it
152  isOk = m_byKeyName.modify(it, [&] (LastInterestRecord& record) {
153  record.lastRefreshed = time::steady_clock::now();
154  if (timestamp.has_value()) {
155  record.timestamp = timestamp;
156  }
157  if (seqNum.has_value()) {
158  record.seqNum = seqNum;
159  }
160  });
161  BOOST_VERIFY(isOk);
162  }
163 
164  // If has nonce and max nonce list size > 0 (or unlimited), append to observed nonce list
165  if (m_options.shouldValidateNonces && m_options.maxNonceRecordCount != 0 && nonce.has_value()) {
166  isOk = m_byKeyName.modify(it, [this, &nonce] (LastInterestRecord& record) {
167  auto& sigNonceList = record.observedNonces.get<NonceList>();
168  sigNonceList.push_back(*nonce);
169  // Ensure observed nonce list is at or below max nonce list size
170  if (m_options.maxNonceRecordCount >= 0 &&
171  sigNonceList.size() > static_cast<size_t>(m_options.maxNonceRecordCount)) {
172  BOOST_ASSERT(sigNonceList.size() == static_cast<size_t>(m_options.maxNonceRecordCount) + 1);
173  sigNonceList.pop_front();
174  }
175  });
176  BOOST_VERIFY(isOk);
177  }
178 
179  // Ensure record count is at or below max
180  if (m_options.maxRecordCount >= 0 &&
181  m_byLastRefreshed.size() > static_cast<size_t>(m_options.maxRecordCount)) {
182  BOOST_ASSERT(m_byLastRefreshed.size() == static_cast<size_t>(m_options.maxRecordCount) + 1);
183  m_byLastRefreshed.erase(m_byLastRefreshed.begin());
184  }
185 }
186 
187 } // inline namespace v2
188 } // namespace security
189 } // namespace ndn
void setInnerPolicy(unique_ptr< ValidationPolicy > innerPolicy)
Set inner policy.
Sign Interest using Packet Specification v0.3 semantics.
bool shouldValidateSeqNums
Whether to validate sequence numbers in signed Interests by ensuring they are present and are strictl...
Definition: data.cpp:26
static time_point now() noexcept
Definition: time.cpp:80
void checkPolicy(const Data &data, const shared_ptr< ValidationState > &state, const ValidationContinuation &continueValidation) override
Check data against the policy.
Represents an Interest packet.
Definition: interest.hpp:50
ValidationPolicy & getInnerPolicy()
Return the inner policy.
static time_point now() noexcept
Definition: time.cpp:46
time::nanoseconds timestampGracePeriod
Tolerance of timestamp differences from the current time.
constexpr duration< Rep, Period > abs(duration< Rep, Period > d)
Definition: time.hpp:50
optional< SignatureInfo > getSignatureInfo() const
Get the InterestSignatureInfo.
Definition: interest.cpp:546
#define NDN_THROW(e)
Definition: exception.hpp:61
provides a tag type for simple types
Definition: tag.hpp:58
ssize_t maxRecordCount
Max number of distinct public keys to track.
std::function< void(const shared_ptr< CertificateRequest > &certRequest, const shared_ptr< ValidationState > &state)> ValidationContinuation
bool shouldValidateNonces
Whether to validate nonces by ensuring that they are present and do not overlap with one of the last ...
static Name getKeyLocatorName(const SignatureInfo &si, ValidationState &state)
Validation state for an interest packet.
ValidationPolicySignedInterest(unique_ptr< ValidationPolicy > inner, const Options &options={})
Constructor.
Represents an absolute name.
Definition: name.hpp:44
ssize_t maxNonceRecordCount
Number of previous nonces to track for each public key.
bool shouldValidateTimestamps
Whether to validate timestamps in signed Interests by ensuring they are not reordered for a given pub...
virtual void checkPolicy(const Data &data, const shared_ptr< ValidationState > &state, const ValidationContinuation &continueValidation)=0
Check data against the policy.
Represents a Data packet.
Definition: data.hpp:39