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-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 
26 
27 #include <boost/algorithm/string/predicate.hpp>
28 
29 namespace ndn {
30 namespace security {
31 inline namespace v2 {
32 namespace validator_config {
33 
34 bool
35 Checker::check(uint32_t pktType, const Name& pktName, const Name& klName,
36  const shared_ptr<ValidationState>& state)
37 {
38  BOOST_ASSERT(pktType == tlv::Interest || pktType == tlv::Data);
39 
40  if (pktType == tlv::Interest) {
41  auto fmt = state->getTag<SignedInterestFormatTag>();
42  BOOST_ASSERT(fmt);
43 
44  if (*fmt == SignedInterestFormat::V03) {
45  // This check is redundant if parameter digest checking is enabled. However, the parameter
46  // digest checking can be disabled in API.
47  if (pktName.size() == 0 || pktName[-1].type() != tlv::ParametersSha256DigestComponent) {
48  return false;
49  }
50  return checkNames(pktName.getPrefix(-1), klName, state);
51  }
52  else {
53  if (pktName.size() < signed_interest::MIN_SIZE)
54  return false;
55 
56  return checkNames(pktName.getPrefix(-signed_interest::MIN_SIZE), klName, state);
57  }
58  }
59  else {
60  return checkNames(pktName, klName, state);
61  }
62 }
63 
65  : m_name(name)
66  , m_relation(relation)
67 {
68 }
69 
70 bool
71 NameRelationChecker::checkNames(const Name& pktName, const Name& klName,
72  const shared_ptr<ValidationState>& state)
73 {
74  // pktName not used in this check
75  Name identity = extractIdentityFromKeyName(klName);
76  bool result = checkNameRelation(m_relation, m_name, identity);
77  if (!result) {
78  std::ostringstream os;
79  os << "KeyLocator check failed: name relation " << m_name << " " << m_relation
80  << " for packet " << pktName << " is invalid"
81  << " (KeyLocator=" << klName << ", identity=" << identity << ")";
82  state->fail({ValidationError::POLICY_ERROR, os.str()});
83  }
84  return result;
85 }
86 
88  : m_regex(regex)
89 {
90 }
91 
92 bool
93 RegexChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
94 {
95  bool result = m_regex.match(klName);
96  if (!result) {
97  std::ostringstream os;
98  os << "KeyLocator check failed: regex " << m_regex << " for packet " << pktName << " is invalid"
99  << " (KeyLocator=" << klName << ")";
100  state->fail({ValidationError::POLICY_ERROR, os.str()});
101  }
102  return result;
103 }
104 
105 HyperRelationChecker::HyperRelationChecker(const std::string& pktNameExpr, const std::string pktNameExpand,
106  const std::string& klNameExpr, const std::string klNameExpand,
107  const NameRelation& hyperRelation)
108  : m_hyperPRegex(pktNameExpr, pktNameExpand)
109  , m_hyperKRegex(klNameExpr, klNameExpand)
110  , m_hyperRelation(hyperRelation)
111 {
112 }
113 
114 bool
115 HyperRelationChecker::checkNames(const Name& pktName, const Name& klName,
116  const shared_ptr<ValidationState>& state)
117 {
118  if (!m_hyperPRegex.match(pktName) || !m_hyperKRegex.match(klName)) {
119  std::ostringstream os;
120  os << "Packet " << pktName << " (" << "KeyLocator=" << klName << ") does not match "
121  << "the hyper relation rule pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex;
122  state->fail({ValidationError::POLICY_ERROR, os.str()});
123  return false;
124  }
125 
126  bool result = checkNameRelation(m_hyperRelation, m_hyperKRegex.expand(), m_hyperPRegex.expand());
127  if (!result) {
128  std::ostringstream os;
129  os << "KeyLocator check failed: hyper relation " << m_hyperRelation
130  << " pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex
131  << " of packet " << pktName << " (KeyLocator=" << klName << ") is invalid";
132  state->fail({ValidationError::POLICY_ERROR, os.str()});
133  }
134  return result;
135 }
136 
137 unique_ptr<Checker>
138 Checker::create(const ConfigSection& configSection, const std::string& configFilename)
139 {
140  auto propertyIt = configSection.begin();
141 
142  // Get checker.type
143  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
144  NDN_THROW(Error("Expecting <checker.type>"));
145  }
146 
147  std::string type = propertyIt->second.data();
148  if (boost::iequals(type, "customized")) {
149  return createCustomizedChecker(configSection, configFilename);
150  }
151  else if (boost::iequals(type, "hierarchical")) {
152  return createHierarchicalChecker(configSection, configFilename);
153  }
154  else {
155  NDN_THROW(Error("Unrecognized <checker.type>: " + type));
156  }
157 }
158 
159 unique_ptr<Checker>
160 Checker::createCustomizedChecker(const ConfigSection& configSection,
161  const std::string& configFilename)
162 {
163  auto propertyIt = configSection.begin();
164  propertyIt++;
165 
166  // TODO implement restrictions based on signature type (outside this checker)
167 
168  if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
169  // ignore sig-type
170  propertyIt++;
171  }
172 
173  // Get checker.key-locator
174  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator")) {
175  NDN_THROW(Error("Expecting <checker.key-locator>"));
176  }
177 
178  auto checker = createKeyLocatorChecker(propertyIt->second, configFilename);
179  propertyIt++;
180 
181  if (propertyIt != configSection.end()) {
182  NDN_THROW(Error("Expecting end of <checker>"));
183  }
184  return checker;
185 }
186 
187 unique_ptr<Checker>
188 Checker::createHierarchicalChecker(const ConfigSection& configSection,
189  const std::string& configFilename)
190 {
191  auto propertyIt = configSection.begin();
192  propertyIt++;
193 
194  // TODO implement restrictions based on signature type (outside this checker)
195 
196  if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
197  // ignore sig-type
198  propertyIt++;
199  }
200 
201  if (propertyIt != configSection.end()) {
202  NDN_THROW(Error("Expecting end of <checker>"));
203  }
204  return make_unique<HyperRelationChecker>("^(<>*)$", "\\1",
205  "^(<>*)<KEY><>$", "\\1",
207 }
208 
209 unique_ptr<Checker>
210 Checker::createKeyLocatorChecker(const ConfigSection& configSection,
211  const std::string& configFilename)
212 {
213  auto propertyIt = configSection.begin();
214 
215  // Get checker.key-locator.type
216  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
217  NDN_THROW(Error("Expecting <checker.key-locator.type>"));
218 
219  std::string type = propertyIt->second.data();
220  if (boost::iequals(type, "name"))
221  return createKeyLocatorNameChecker(configSection, configFilename);
222  else
223  NDN_THROW(Error("Unrecognized <checker.key-locator.type>: " + type));
224 }
225 
226 unique_ptr<Checker>
227 Checker::createKeyLocatorNameChecker(const ConfigSection& configSection,
228  const std::string& configFilename)
229 {
230  auto propertyIt = configSection.begin();
231  propertyIt++;
232 
233  if (propertyIt == configSection.end())
234  NDN_THROW(Error("Unexpected end of <checker.key-locator>"));
235 
236  if (boost::iequals(propertyIt->first, "name")) {
237  Name name;
238  try {
239  name = Name(propertyIt->second.data());
240  }
241  catch (const Name::Error&) {
242  NDN_THROW_NESTED(Error("Invalid <checker.key-locator.name>: " + propertyIt->second.data()));
243  }
244  propertyIt++;
245 
246  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) {
247  NDN_THROW(Error("Expecting <checker.key-locator.relation>"));
248  }
249 
250  std::string relationString = propertyIt->second.data();
251  propertyIt++;
252 
253  NameRelation relation = getNameRelationFromString(relationString);
254 
255  if (propertyIt != configSection.end()) {
256  NDN_THROW(Error("Expecting end of <checker.key-locator>"));
257  }
258  return make_unique<NameRelationChecker>(name, relation);
259  }
260  else if (boost::iequals(propertyIt->first, "regex")) {
261  std::string regexString = propertyIt->second.data();
262  propertyIt++;
263 
264  if (propertyIt != configSection.end()) {
265  NDN_THROW(Error("Expecting end of <checker.key-locator>"));
266  }
267 
268  try {
269  return make_unique<RegexChecker>(Regex(regexString));
270  }
271  catch (const Regex::Error&) {
272  NDN_THROW_NESTED(Error("Invalid <checker.key-locator.regex>: " + regexString));
273  }
274  }
275  else if (boost::iequals(propertyIt->first, "hyper-relation")) {
276  const ConfigSection& hSection = propertyIt->second;
277  auto hPropertyIt = hSection.begin();
278 
279  // Get k-regex
280  if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-regex")) {
281  NDN_THROW(Error("Expecting <checker.key-locator.hyper-relation.k-regex>"));
282  }
283 
284  std::string kRegex = hPropertyIt->second.data();
285  hPropertyIt++;
286 
287  // Get k-expand
288  if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-expand")) {
289  NDN_THROW(Error("Expecting <checker.key-locator.hyper-relation.k-expand>"));
290  }
291 
292  std::string kExpand = hPropertyIt->second.data();
293  hPropertyIt++;
294 
295  // Get h-relation
296  if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "h-relation")) {
297  NDN_THROW(Error("Expecting <checker.key-locator.hyper-relation.h-relation>"));
298  }
299 
300  std::string hRelation = hPropertyIt->second.data();
301  hPropertyIt++;
302 
303  // Get p-regex
304  if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-regex")) {
305  NDN_THROW(Error("Expecting <checker.key-locator.hyper-relation.p-regex>"));
306  }
307 
308  std::string pRegex = hPropertyIt->second.data();
309  hPropertyIt++;
310 
311  // Get p-expand
312  if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-expand")) {
313  NDN_THROW(Error("Expecting <checker.key-locator.hyper-relation.p-expand>"));
314  }
315 
316  std::string pExpand = hPropertyIt->second.data();
317  hPropertyIt++;
318 
319  if (hPropertyIt != hSection.end()) {
320  NDN_THROW(Error("Expecting end of <checker.key-locator.hyper-relation>"));
321  }
322 
323  NameRelation relation = getNameRelationFromString(hRelation);
324  try {
325  return make_unique<HyperRelationChecker>(pRegex, pExpand, kRegex, kExpand, relation);
326  }
327  catch (const Regex::Error&) {
328  NDN_THROW_NESTED(Error("Invalid regex for <key-locator.hyper-relation>"));
329  }
330  }
331  else {
332  NDN_THROW(Error("Unrecognized <checker.key-locator>: " + propertyIt->first));
333  }
334 }
335 
336 } // namespace validator_config
337 } // inline namespace v2
338 } // namespace security
339 } // namespace ndn
#define NDN_THROW_NESTED(e)
Definition: exception.hpp:71
Sign Interest using Packet Specification v0.3 semantics.
PartialName getPrefix(ssize_t nComponents) const
Returns a prefix of the name.
Definition: name.hpp:212
Definition: data.cpp:26
NameRelationChecker(const Name &name, const NameRelation &relation)
Definition: checker.cpp:64
bool checkNames(const Name &pktName, const Name &klName, const shared_ptr< ValidationState > &state) override
Definition: checker.cpp:115
const size_t MIN_SIZE
minimal number of components for Signed Interest
#define NDN_THROW(e)
Definition: exception.hpp:61
provides a tag type for simple types
Definition: tag.hpp:58
bool checkNameRelation(NameRelation relation, const Name &name1, const Name &name2)
check whether name1 and name2 satisfies relation
bool checkNames(const Name &pktName, const Name &klName, const shared_ptr< ValidationState > &state) override
Definition: checker.cpp:93
NameRelation getNameRelationFromString(const std::string &relationString)
convert relationString to NameRelation
Represents an absolute name.
Definition: name.hpp:44
size_t size() const
Returns the number of components.
Definition: name.hpp:154
boost::property_tree::ptree ConfigSection
Definition: common.hpp:36
virtual Name expand(const std::string &expand="")
bool checkNames(const Name &pktName, const Name &klName, const shared_ptr< ValidationState > &state) override
Definition: checker.cpp:71
bool match(const Name &name)
HyperRelationChecker(const std::string &pktNameExpr, const std::string pktNameExpand, const std::string &klNameExpr, const std::string klNameExpand, const NameRelation &hyperRelation)
Definition: checker.cpp:105
bool check(uint32_t pktType, const Name &pktName, const Name &klName, const shared_ptr< ValidationState > &state)
Check if packet name ane KeyLocator satisfy the checker&#39;s conditions.
Definition: checker.cpp:35
virtual bool checkNames(const Name &pktName, const Name &klName, const shared_ptr< ValidationState > &state)=0
RegexTopMatcher Regex
Definition: regex.hpp:31
Name extractIdentityFromKeyName(const Name &keyName)
Extract identity namespace from the key name keyName.
Definition: key.cpp:160
static unique_ptr< Checker > create(const ConfigSection &configSection, const std::string &configFilename)
create a checker from configuration section
Definition: checker.cpp:138