ndn-cxx: NDN C++ Library 0.9.0-33-g832ea91d
Loading...
Searching...
No Matches
checker.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
25
26#include <boost/algorithm/string/predicate.hpp>
27
29
31 : m_sigType(sigType)
32{
33}
34
35Checker::Result::Result(std::string error)
36 : m_error(std::move(error))
37{
38}
39
40class Checker::NegativeResultBuilder
41{
42public:
43 template<typename T>
44 NegativeResultBuilder&
45 operator<<(const T& value)
46 {
47 m_ss << value;
48 return *this;
49 }
50
51 operator Checker::Result() const
52 {
53 auto error = m_ss.str();
54 return Checker::Result(error.empty() ? "checker failed" : std::move(error));
55 }
56
57private:
58 std::ostringstream m_ss;
59};
60
61Checker::NegativeResultBuilder
63{
64 return NegativeResultBuilder();
65}
66
68Checker::check(uint32_t pktType, tlv::SignatureTypeValue sigType, const Name& pktName, const Name& klName,
69 const ValidationState& state)
70{
71 BOOST_ASSERT(pktType == tlv::Interest || pktType == tlv::Data);
72
73 if (sigType != m_sigType) {
74 return reject() << "signature type does not match the checker "
75 << sigType << " != " << m_sigType;
76 }
77
78 if (pktType == tlv::Interest) {
79 auto fmt = state.getTag<SignedInterestFormatTag>();
80 BOOST_ASSERT(fmt);
81
82 if (*fmt == SignedInterestFormat::V03) {
83 // This check is redundant if parameter digest checking is enabled. However, the parameter
84 // digest checking can be disabled in API.
85 if (pktName.size() == 0 || pktName[-1].type() != tlv::ParametersSha256DigestComponent) {
86 return reject() << "ParametersSha256DigestComponent missing";
87 }
88 return checkNames(pktName.getPrefix(-1), klName);
89 }
90 else {
91 if (pktName.size() < signed_interest::MIN_SIZE)
92 return reject() << "name too short";
93
94 return checkNames(pktName.getPrefix(-signed_interest::MIN_SIZE), klName);
95 }
96 }
97 else {
98 return checkNames(pktName, klName);
99 }
100}
101
103Checker::checkNames(const Name& pktName, const Name& klName)
104{
105 return accept();
106}
107
109 : Checker(sigType)
110 , m_name(name)
111 , m_relation(relation)
112{
113}
114
116NameRelationChecker::checkNames(const Name& pktName, const Name& klName)
117{
118 // pktName not used in this check
119 Name identity = extractIdentityNameFromKeyLocator(klName);
120 if (checkNameRelation(m_relation, m_name, identity)) {
121 return accept();
122 }
123
124 return reject() << "identity " << identity << " and packet name do not satisfy "
125 << m_relation << " relation";
126}
127
129 : Checker(sigType)
130 , m_regex(regex)
131{
132}
133
135RegexChecker::checkNames(const Name& pktName, const Name& klName)
136{
137 if (m_regex.match(klName)) {
138 return accept();
139 }
140
141 return reject() << "KeyLocator does not match regex " << m_regex;
142}
143
145 const std::string& pktNameExpr, const std::string& pktNameExpand,
146 const std::string& klNameExpr, const std::string& klNameExpand,
147 const NameRelation& hyperRelation)
148 : Checker(sigType)
149 , m_hyperPRegex(pktNameExpr, pktNameExpand)
150 , m_hyperKRegex(klNameExpr, klNameExpand)
151 , m_hyperRelation(hyperRelation)
152{
153}
154
156HyperRelationChecker::checkNames(const Name& pktName, const Name& klName)
157{
158 if (!m_hyperPRegex.match(pktName)) {
159 return reject() << "packet name does not match p-regex " << m_hyperPRegex;
160 }
161
162 if (!m_hyperKRegex.match(klName)) {
163 return reject() << "KeyLocator does not match k-regex " << m_hyperKRegex;
164 }
165
166 auto kExpand = m_hyperKRegex.expand();
167 auto pExpand = m_hyperPRegex.expand();
168 if (checkNameRelation(m_hyperRelation, kExpand, pExpand)) {
169 return accept();
170 }
171
172 return reject() << "expanded names " << kExpand << " and " << pExpand
173 << " do not satisfy " << m_hyperRelation << " relation";
174}
175
176unique_ptr<Checker>
177Checker::create(const ConfigSection& configSection, const std::string& configFilename)
178{
179 auto propertyIt = configSection.begin();
180
181 // Get checker.type
182 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
183 NDN_THROW(Error("Expecting <checker.type>"));
184 }
185
186 std::string type = propertyIt->second.data();
187 if (boost::iequals(type, "customized")) {
188 return createCustomizedChecker(configSection, configFilename);
189 }
190 else if (boost::iequals(type, "hierarchical")) {
191 return createHierarchicalChecker(configSection, configFilename);
192 }
193 else {
194 NDN_THROW(Error("Unrecognized <checker.type>: " + type));
195 }
196}
197
199parseSigType(const std::string& value)
200{
201 if (boost::iequals(value, "rsa-sha256")) {
203 }
204 else if (boost::iequals(value, "ecdsa-sha256")) {
206 }
207 // TODO: uncomment when HMAC logic is defined/implemented
208 // else if (boost::iequals(value, "hmac-sha256")) {
209 // return tlv::SignatureHmacWithSha256;
210 // }
211 else if (boost::iequals(value, "sha256")) {
212 return tlv::DigestSha256;
213 }
214 else {
215 NDN_THROW(Error("Unrecognized value of <checker.sig-type>: " + value));
216 }
217}
218
219unique_ptr<Checker>
220Checker::createCustomizedChecker(const ConfigSection& configSection,
221 const std::string& configFilename)
222{
223 auto propertyIt = configSection.begin();
224 propertyIt++;
225
226 // assume that checker by default is for ecdsa-sha256, unless explicitly specified
227 auto sigType = tlv::SignatureSha256WithEcdsa;
228
229 if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
230 sigType = parseSigType(propertyIt->second.data());
231 propertyIt++;
232 }
233
234 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator")) {
235 if (sigType == tlv::DigestSha256) {
236 // for sha256, key-locator is optional
237 return make_unique<Checker>(sigType);
238 }
239 NDN_THROW(Error("Expecting <checker.key-locator>"));
240 }
241
242 auto checker = createKeyLocatorChecker(sigType, propertyIt->second, configFilename);
243 propertyIt++;
244
245 if (propertyIt != configSection.end()) {
246 NDN_THROW(Error("Expecting end of <checker>"));
247 }
248 return checker;
249}
250
251unique_ptr<Checker>
252Checker::createHierarchicalChecker(const ConfigSection& configSection,
253 const std::string& configFilename)
254{
255 auto propertyIt = configSection.begin();
256 propertyIt++;
257
258 // assume that checker by default is for ecdsa-sha256, unless explicitly specificied
259 auto sigType = tlv::SignatureSha256WithEcdsa;
260
261 if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
262 sigType = parseSigType(propertyIt->second.data());
263 propertyIt++;
264 }
265
266 if (propertyIt != configSection.end()) {
267 NDN_THROW(Error("Expecting end of <checker>"));
268 }
269 return make_unique<HyperRelationChecker>(sigType,
270 "^(<>*)$", "\\1",
271 "^(<>*)<KEY><>{1,3}$", "\\1",
273}
274
275unique_ptr<Checker>
276Checker::createKeyLocatorChecker(tlv::SignatureTypeValue sigType,
277 const ConfigSection& configSection, const std::string& configFilename)
278{
279 auto propertyIt = configSection.begin();
280
281 // Get checker.key-locator.type
282 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
283 NDN_THROW(Error("Expecting <checker.key-locator.type>"));
284
285 std::string type = propertyIt->second.data();
286 if (boost::iequals(type, "name"))
287 return createKeyLocatorNameChecker(sigType, configSection, configFilename);
288 else
289 NDN_THROW(Error("Unrecognized <checker.key-locator.type>: " + type));
290}
291
292unique_ptr<Checker>
293Checker::createKeyLocatorNameChecker(tlv::SignatureTypeValue sigType,
294 const ConfigSection& configSection, const std::string& configFilename)
295{
296 auto propertyIt = configSection.begin();
297 propertyIt++;
298
299 if (propertyIt == configSection.end())
300 NDN_THROW(Error("Unexpected end of <checker.key-locator>"));
301
302 if (boost::iequals(propertyIt->first, "name")) {
303 Name name;
304 try {
305 name = Name(propertyIt->second.data());
306 }
307 catch (const Name::Error&) {
308 NDN_THROW_NESTED(Error("Invalid <checker.key-locator.name>: " + propertyIt->second.data()));
309 }
310 propertyIt++;
311
312 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) {
313 NDN_THROW(Error("Expecting <checker.key-locator.relation>"));
314 }
315
316 std::string relationString = propertyIt->second.data();
317 propertyIt++;
318
319 NameRelation relation = getNameRelationFromString(relationString);
320
321 if (propertyIt != configSection.end()) {
322 NDN_THROW(Error("Expecting end of <checker.key-locator>"));
323 }
324 return make_unique<NameRelationChecker>(sigType, name, relation);
325 }
326 else if (boost::iequals(propertyIt->first, "regex")) {
327 std::string regexString = propertyIt->second.data();
328 propertyIt++;
329
330 if (propertyIt != configSection.end()) {
331 NDN_THROW(Error("Expecting end of <checker.key-locator>"));
332 }
333
334 try {
335 return make_unique<RegexChecker>(sigType, Regex(regexString));
336 }
337 catch (const Regex::Error&) {
338 NDN_THROW_NESTED(Error("Invalid <checker.key-locator.regex>: " + regexString));
339 }
340 }
341 else if (boost::iequals(propertyIt->first, "hyper-relation")) {
342 const ConfigSection& hSection = propertyIt->second;
343 auto hPropertyIt = hSection.begin();
344
345 // Get k-regex
346 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-regex")) {
347 NDN_THROW(Error("Expecting <checker.key-locator.hyper-relation.k-regex>"));
348 }
349
350 std::string kRegex = hPropertyIt->second.data();
351 hPropertyIt++;
352
353 // Get k-expand
354 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-expand")) {
355 NDN_THROW(Error("Expecting <checker.key-locator.hyper-relation.k-expand>"));
356 }
357
358 std::string kExpand = hPropertyIt->second.data();
359 hPropertyIt++;
360
361 // Get h-relation
362 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "h-relation")) {
363 NDN_THROW(Error("Expecting <checker.key-locator.hyper-relation.h-relation>"));
364 }
365
366 std::string hRelation = hPropertyIt->second.data();
367 hPropertyIt++;
368
369 // Get p-regex
370 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-regex")) {
371 NDN_THROW(Error("Expecting <checker.key-locator.hyper-relation.p-regex>"));
372 }
373
374 std::string pRegex = hPropertyIt->second.data();
375 hPropertyIt++;
376
377 // Get p-expand
378 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-expand")) {
379 NDN_THROW(Error("Expecting <checker.key-locator.hyper-relation.p-expand>"));
380 }
381
382 std::string pExpand = hPropertyIt->second.data();
383 hPropertyIt++;
384
385 if (hPropertyIt != hSection.end()) {
386 NDN_THROW(Error("Expecting end of <checker.key-locator.hyper-relation>"));
387 }
388
389 NameRelation relation = getNameRelationFromString(hRelation);
390 try {
391 return make_unique<HyperRelationChecker>(sigType, pRegex, pExpand, kRegex, kExpand, relation);
392 }
393 catch (const Regex::Error&) {
394 NDN_THROW_NESTED(Error("Invalid regex for <key-locator.hyper-relation>"));
395 }
396 }
397 else {
398 NDN_THROW(Error("Unrecognized <checker.key-locator>: " + propertyIt->first));
399 }
400}
401
402} // namespace ndn::security::validator_config
Represents an absolute name.
Definition name.hpp:45
PartialName getPrefix(ssize_t nComponents) const
Returns a prefix of the name.
Definition name.hpp:241
size_t size() const noexcept
Returns the number of components.
Definition name.hpp:180
Component::Error Error
Definition name.hpp:48
bool match(const Name &name)
virtual Name expand(const std::string &expand="")
Provides a tag type for simple types.
Definition tag.hpp:56
std::shared_ptr< T > getTag() const
Get a tag item.
Definition tag-host.hpp:72
tlv::SignatureTypeValue m_sigType
Definition checker.hpp:136
virtual Result checkNames(const Name &pktName, const Name &klName)
Base version of name checking.
Definition checker.cpp:103
static unique_ptr< Checker > create(const ConfigSection &configSection, const std::string &configFilename)
Create a checker from configuration section.
Definition checker.cpp:177
Result check(uint32_t pktType, tlv::SignatureTypeValue sigType, const Name &pktName, const Name &klName, const ValidationState &state)
Check if packet name and KeyLocator satisfy the checker's conditions.
Definition checker.cpp:68
Checker(tlv::SignatureTypeValue sigType)
Definition checker.cpp:30
static NegativeResultBuilder reject()
Definition checker.cpp:62
HyperRelationChecker(tlv::SignatureTypeValue sigType, const std::string &pktNameExpr, const std::string &pktNameExpand, const std::string &klNameExpr, const std::string &klNameExpand, const NameRelation &hyperRelation)
Definition checker.cpp:144
Result checkNames(const Name &pktName, const Name &klName) override
Base version of name checking.
Definition checker.cpp:156
Result checkNames(const Name &pktName, const Name &klName) override
Base version of name checking.
Definition checker.cpp:116
NameRelationChecker(tlv::SignatureTypeValue sigType, const Name &name, const NameRelation &relation)
Definition checker.cpp:108
Result checkNames(const Name &pktName, const Name &klName) override
Base version of name checking.
Definition checker.cpp:135
RegexChecker(tlv::SignatureTypeValue sigType, const Regex &regex)
Definition checker.cpp:128
#define NDN_THROW_NESTED(e)
Definition exception.hpp:65
#define NDN_THROW(e)
Definition exception.hpp:56
NameRelation getNameRelationFromString(const std::string &relationString)
Convert relationString to NameRelation.
boost::property_tree::ptree ConfigSection
Definition common.hpp:33
bool checkNameRelation(NameRelation relation, const Name &name1, const Name &name2)
Check whether name1 and name2 satisfies relation.
Name extractIdentityNameFromKeyLocator(const Name &keyLocator)
Extract identity name from key, version-less certificate, or certificate name.
@ V03
Sign Interest using Packet Specification v0.3 semantics.
constexpr size_t MIN_SIZE
Minimum number of name components for an old-style Signed Interest.
@ Name
Definition tlv.hpp:71
@ Data
Definition tlv.hpp:69
@ ParametersSha256DigestComponent
Definition tlv.hpp:74
@ Interest
Definition tlv.hpp:68
SignatureTypeValue
SignatureType values.
Definition tlv.hpp:127
@ SignatureSha256WithRsa
Definition tlv.hpp:129
@ DigestSha256
Definition tlv.hpp:128
@ SignatureSha256WithEcdsa
Definition tlv.hpp:130
std::ostream & operator<<(std::ostream &os, const Data &data)
Definition data.cpp:377
RegexTopMatcher Regex
Definition regex.hpp:31
STL namespace.