ndn-cxx: NDN C++ Library 0.9.0-33-g832ea91d
Loading...
Searching...
No Matches
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-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_byKeyName(m_container.get<0>())
30 , m_byLastRefreshed(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.timestampGracePeriod = std::max(m_options.timestampGracePeriod, 0_ns);
38}
39
40void
42 const shared_ptr<ValidationState>& state,
43 const ValidationContinuation& continueValidation)
44{
45 getInnerPolicy().checkPolicy(data, state, continueValidation);
46}
47
48void
50 const shared_ptr<ValidationState>& state,
51 const ValidationContinuation& continueValidation)
52{
53 if (!state->getOutcome()) {
54 return;
55 }
56
57 auto fmt = state->getTag<SignedInterestFormatTag>();
58 BOOST_ASSERT(fmt);
59 if (*fmt == SignedInterestFormat::V03 && !checkIncomingInterest(state, interest)) {
60 return;
61 }
62
63 getInnerPolicy().checkPolicy(interest, state, continueValidation);
64}
65
66bool
67ValidationPolicySignedInterest::checkIncomingInterest(const shared_ptr<ValidationState>& state,
68 const Interest& interest)
69{
70 auto sigInfo = getSignatureInfo(interest, *state);
71 if (!state->getOutcome()) {
72 return false;
73 }
74 Name keyName = getKeyLocatorName(sigInfo, *state);
75 if (!state->getOutcome()) {
76 return false;
77 }
78 auto timestamp = sigInfo.getTime();
79 auto seqNum = sigInfo.getSeqNum();
80 auto nonce = sigInfo.getNonce();
81
82 auto record = m_byKeyName.find(keyName);
83
84 if (m_options.shouldValidateTimestamps) {
85 if (!timestamp.has_value()) {
86 state->fail({ValidationError::POLICY_ERROR, "Timestamp is required by policy but is not present"});
87 return false;
88 }
89
90 auto now = time::system_clock::now();
91 if (time::abs(now - *timestamp) > m_options.timestampGracePeriod) {
93 "Timestamp is outside the grace period for key " + keyName.toUri()});
94 return false;
95 }
96
97 if (record != m_byKeyName.end() && record->timestamp.has_value() && timestamp <= record->timestamp) {
99 "Timestamp is reordered for key " + keyName.toUri()});
100 return false;
101 }
102 }
103
104 if (m_options.shouldValidateSeqNums) {
105 if (!seqNum.has_value()) {
107 "Sequence number is required by policy but is not present"});
108 return false;
109 }
110
111 if (record != m_byKeyName.end() && record->seqNum.has_value() && seqNum <= record->seqNum) {
113 "Sequence number is reordered for key " + keyName.toUri()});
114 return false;
115 }
116 }
117
118 if (m_options.shouldValidateNonces) {
119 if (!nonce.has_value()) {
120 state->fail({ValidationError::POLICY_ERROR, "Nonce is required by policy but is not present"});
121 return false;
122 }
123
124 if (record != m_byKeyName.end() && record->observedNonces.get<NonceSet>().count(*nonce) > 0) {
126 "Nonce matches previously-seen nonce for key " + keyName.toUri()});
127 return false;
128 }
129 }
130
131 if (m_options.maxRecordCount != 0) {
132 auto interestState = std::dynamic_pointer_cast<InterestValidationState>(state);
133 BOOST_ASSERT(interestState != nullptr);
134 interestState->afterSuccess.connect([=] (const Interest&) {
135 insertRecord(keyName, timestamp, seqNum, nonce);
136 });
137 }
138 return true;
139}
140
141void
142ValidationPolicySignedInterest::insertRecord(const Name& keyName,
143 std::optional<time::system_clock::time_point> timestamp,
144 std::optional<uint64_t> seqNum,
145 std::optional<SigNonce> nonce)
146{
147 // If key record exists, update last refreshed time. Otherwise, create new record.
148 auto [it, isOk] = m_byKeyName.emplace(keyName, timestamp, seqNum);
149 if (!isOk) {
150 // There was already a record for this key, we just need to update it
151 isOk = m_byKeyName.modify(it, [&] (LastInterestRecord& record) {
152 record.lastRefreshed = time::steady_clock::now();
153 if (timestamp.has_value()) {
154 record.timestamp = timestamp;
155 }
156 if (seqNum.has_value()) {
157 record.seqNum = seqNum;
158 }
159 });
160 BOOST_VERIFY(isOk);
161 }
162
163 // If has nonce and max nonce list size > 0 (or unlimited), append to observed nonce list
164 if (m_options.shouldValidateNonces && m_options.maxNonceRecordCount != 0 && nonce.has_value()) {
165 isOk = m_byKeyName.modify(it, [this, &nonce] (LastInterestRecord& record) {
166 auto& sigNonceList = record.observedNonces.get<NonceList>();
167 sigNonceList.push_back(*nonce);
168 // Ensure observed nonce list is at or below max nonce list size
169 if (m_options.maxNonceRecordCount >= 0 &&
170 sigNonceList.size() > static_cast<size_t>(m_options.maxNonceRecordCount)) {
171 BOOST_ASSERT(sigNonceList.size() == static_cast<size_t>(m_options.maxNonceRecordCount) + 1);
172 sigNonceList.pop_front();
173 }
174 });
175 BOOST_VERIFY(isOk);
176 }
177
178 // Ensure record count is at or below max
179 if (m_options.maxRecordCount >= 0 &&
180 m_byLastRefreshed.size() > static_cast<size_t>(m_options.maxRecordCount)) {
181 BOOST_ASSERT(m_byLastRefreshed.size() == static_cast<size_t>(m_options.maxRecordCount) + 1);
182 m_byLastRefreshed.erase(m_byLastRefreshed.begin());
183 }
184}
185
186} // namespace ndn::security
Represents a Data packet.
Definition data.hpp:39
Represents an Interest packet.
Definition interest.hpp:50
Represents an absolute name.
Definition name.hpp:45
void toUri(std::ostream &os, name::UriFormat format=name::UriFormat::DEFAULT) const
Write URI representation of the name to the output stream.
Definition name.cpp:324
Provides a tag type for simple types.
Definition tag.hpp:56
@ POLICY_ERROR
The packet violates the validation rules enforced by the policy.
bool shouldValidateSeqNums
Whether to validate sequence numbers in signed Interests by ensuring they are present and are strictl...
ssize_t maxNonceRecordCount
Number of previous nonces to track for each public key.
time::nanoseconds timestampGracePeriod
Tolerance of timestamp differences from the current time.
ssize_t maxRecordCount
Max number of distinct public keys to track.
bool shouldValidateNonces
Whether to validate nonces by ensuring that they are present and do not overlap with one of the last ...
bool shouldValidateTimestamps
Whether to validate timestamps in signed Interests by ensuring they are not reordered for a given pub...
ValidationPolicySignedInterest(unique_ptr< ValidationPolicy > inner, const Options &options={})
Constructor.
void checkPolicy(const Data &data, const shared_ptr< ValidationState > &state, const ValidationContinuation &continueValidation) override
Check data against the policy.
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
#define NDN_THROW(e)
Definition exception.hpp:56
Contains the ndn-cxx security framework.
@ 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 duration< Rep, Period > abs(duration< Rep, Period > d)
Returns the absolute value of the duration d.
Definition time.hpp:63