blob: 908e126ebb4a4cec2ef4a3b7d6468bce9da3e3b4 [file] [log] [blame]
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
Davide Pesavento5df42a82018-03-08 20:06:51 -05003 * Copyright (c) 2013-2018 Regents of the University of California.
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -08004 *
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
22#include "checker.hpp"
23#include "security/v2/validation-state.hpp"
24#include "security/verification-helpers.hpp"
25#include "security/pib/key.hpp"
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -080026
Davide Pesavento5df42a82018-03-08 20:06:51 -050027#include <boost/algorithm/string/predicate.hpp>
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -080028
29namespace ndn {
30namespace security {
31namespace v2 {
32namespace validator_config {
33
34bool
Davide Pesavento5df42a82018-03-08 20:06:51 -050035Checker::check(uint32_t pktType, const Name& pktName, const Name& klName,
36 const shared_ptr<ValidationState>& state)
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -080037{
38 BOOST_ASSERT(pktType == tlv::Interest || pktType == tlv::Data);
39
40 if (pktType == tlv::Interest) {
41 if (pktName.size() < signed_interest::MIN_SIZE)
42 return false;
43
44 return checkNames(pktName.getPrefix(-signed_interest::MIN_SIZE), klName, state);
45 }
46 else {
47 return checkNames(pktName, klName, state);
48 }
49}
50
51NameRelationChecker::NameRelationChecker(const Name& name, const NameRelation& relation)
52 : m_name(name)
53 , m_relation(relation)
54{
55}
56
57bool
Davide Pesavento5df42a82018-03-08 20:06:51 -050058NameRelationChecker::checkNames(const Name& pktName, const Name& klName,
59 const shared_ptr<ValidationState>& state)
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -080060{
61 // pktName not used in this check
62 Name identity = extractIdentityFromKeyName(klName);
63 bool result = checkNameRelation(m_relation, m_name, identity);
64 if (!result) {
65 std::ostringstream os;
66 os << "KeyLocator check failed: name relation " << m_name << " " << m_relation
67 << " for packet " << pktName << " is invalid"
68 << " (KeyLocator=" << klName << ", identity=" << identity << ")";
69 state->fail({ValidationError::POLICY_ERROR, os.str()});
70 }
71 return result;
72}
73
74RegexChecker::RegexChecker(const Regex& regex)
75 : m_regex(regex)
76{
77}
78
79bool
80RegexChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
81{
Zhiyi Zhangc4a01762017-10-11 12:07:25 -070082 bool result = m_regex.match(klName);
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -080083 if (!result) {
84 std::ostringstream os;
85 os << "KeyLocator check failed: regex " << m_regex << " for packet " << pktName << " is invalid"
Zhiyi Zhangc4a01762017-10-11 12:07:25 -070086 << " (KeyLocator=" << klName << ")";
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -080087 state->fail({ValidationError::POLICY_ERROR, os.str()});
88 }
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -080089 return result;
90}
91
92HyperRelationChecker::HyperRelationChecker(const std::string& pktNameExpr, const std::string pktNameExpand,
93 const std::string& klNameExpr, const std::string klNameExpand,
94 const NameRelation& hyperRelation)
95 : m_hyperPRegex(pktNameExpr, pktNameExpand)
96 , m_hyperKRegex(klNameExpr, klNameExpand)
97 , m_hyperRelation(hyperRelation)
98{
99}
100
101bool
Davide Pesavento5df42a82018-03-08 20:06:51 -0500102HyperRelationChecker::checkNames(const Name& pktName, const Name& klName,
103 const shared_ptr<ValidationState>& state)
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800104{
105 if (!m_hyperPRegex.match(pktName) || !m_hyperKRegex.match(klName)) {
106 std::ostringstream os;
107 os << "Packet " << pktName << " (" << "KeyLocator=" << klName << ") does not match "
108 << "the hyper relation rule pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex;
109 state->fail({ValidationError::POLICY_ERROR, os.str()});
110 return false;
111 }
112
113 bool result = checkNameRelation(m_hyperRelation, m_hyperKRegex.expand(), m_hyperPRegex.expand());
114 if (!result) {
115 std::ostringstream os;
116 os << "KeyLocator check failed: hyper relation " << m_hyperRelation
117 << " pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex
118 << " of packet " << pktName << " (KeyLocator=" << klName << ") is invalid";
119 state->fail({ValidationError::POLICY_ERROR, os.str()});
120 }
121 return result;
122}
123
124unique_ptr<Checker>
125Checker::create(const ConfigSection& configSection, const std::string& configFilename)
126{
127 auto propertyIt = configSection.begin();
128
129 // Get checker.type
130 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500131 BOOST_THROW_EXCEPTION(Error("Expecting <checker.type>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800132 }
133
134 std::string type = propertyIt->second.data();
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800135 if (boost::iequals(type, "customized")) {
136 return createCustomizedChecker(configSection, configFilename);
137 }
138 else if (boost::iequals(type, "hierarchical")) {
139 return createHierarchicalChecker(configSection, configFilename);
140 }
141 else {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500142 BOOST_THROW_EXCEPTION(Error("Unrecognized <checker.type>: " + type));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800143 }
144}
145
146unique_ptr<Checker>
147Checker::createCustomizedChecker(const ConfigSection& configSection,
Davide Pesavento5df42a82018-03-08 20:06:51 -0500148 const std::string& configFilename)
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800149{
150 auto propertyIt = configSection.begin();
151 propertyIt++;
152
153 // TODO implement restrictions based on signature type (outside this checker)
154
155 if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
156 // ignore sig-type
157 propertyIt++;
158 }
159
160 // Get checker.key-locator
161 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator")) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500162 BOOST_THROW_EXCEPTION(Error("Expecting <checker.key-locator>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800163 }
164
165 auto checker = createKeyLocatorChecker(propertyIt->second, configFilename);
166 propertyIt++;
167
168 if (propertyIt != configSection.end()) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500169 BOOST_THROW_EXCEPTION(Error("Expecting end of <checker>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800170 }
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800171 return checker;
172}
173
174unique_ptr<Checker>
175Checker::createHierarchicalChecker(const ConfigSection& configSection,
Davide Pesavento5df42a82018-03-08 20:06:51 -0500176 const std::string& configFilename)
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800177{
178 auto propertyIt = configSection.begin();
179 propertyIt++;
180
181 // TODO implement restrictions based on signature type (outside this checker)
182
183 if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
184 // ignore sig-type
185 propertyIt++;
186 }
187
188 if (propertyIt != configSection.end()) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500189 BOOST_THROW_EXCEPTION(Error("Expecting end of <checker>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800190 }
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800191 return make_unique<HyperRelationChecker>("^(<>*)$", "\\1",
192 "^(<>*)<KEY><>$", "\\1",
193 NameRelation::IS_PREFIX_OF);
194}
195
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800196unique_ptr<Checker>
Davide Pesavento5df42a82018-03-08 20:06:51 -0500197Checker::createKeyLocatorChecker(const ConfigSection& configSection,
198 const std::string& configFilename)
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800199{
200 auto propertyIt = configSection.begin();
201
202 // Get checker.key-locator.type
203 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
Davide Pesavento5df42a82018-03-08 20:06:51 -0500204 BOOST_THROW_EXCEPTION(Error("Expecting <checker.key-locator.type>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800205
206 std::string type = propertyIt->second.data();
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800207 if (boost::iequals(type, "name"))
208 return createKeyLocatorNameChecker(configSection, configFilename);
209 else
Davide Pesavento5df42a82018-03-08 20:06:51 -0500210 BOOST_THROW_EXCEPTION(Error("Unrecognized <checker.key-locator.type>: " + type));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800211}
212
213unique_ptr<Checker>
Davide Pesavento5df42a82018-03-08 20:06:51 -0500214Checker::createKeyLocatorNameChecker(const ConfigSection& configSection,
215 const std::string& configFilename)
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800216{
217 auto propertyIt = configSection.begin();
218 propertyIt++;
219
220 if (propertyIt == configSection.end())
Davide Pesavento5df42a82018-03-08 20:06:51 -0500221 BOOST_THROW_EXCEPTION(Error("Unexpected end of <checker.key-locator>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800222
223 if (boost::iequals(propertyIt->first, "name")) {
224 Name name;
225 try {
226 name = Name(propertyIt->second.data());
227 }
Davide Pesavento5df42a82018-03-08 20:06:51 -0500228 catch (const Name::Error&) {
229 BOOST_THROW_EXCEPTION(Error("Invalid <checker.key-locator.name>: " + propertyIt->second.data()));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800230 }
231 propertyIt++;
232
233 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500234 BOOST_THROW_EXCEPTION(Error("Expecting <checker.key-locator.relation>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800235 }
236
237 std::string relationString = propertyIt->second.data();
238 propertyIt++;
239
240 NameRelation relation = getNameRelationFromString(relationString);
241
242 if (propertyIt != configSection.end()) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500243 BOOST_THROW_EXCEPTION(Error("Expecting end of <checker.key-locator>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800244 }
245 return make_unique<NameRelationChecker>(name, relation);
246 }
247 else if (boost::iequals(propertyIt->first, "regex")) {
248 std::string regexString = propertyIt->second.data();
249 propertyIt++;
250
251 if (propertyIt != configSection.end()) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500252 BOOST_THROW_EXCEPTION(Error("Expecting end of <checker.key-locator>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800253 }
254
255 try {
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500256 return make_unique<RegexChecker>(Regex(regexString));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800257 }
Davide Pesavento5df42a82018-03-08 20:06:51 -0500258 catch (const Regex::Error&) {
259 BOOST_THROW_EXCEPTION(Error("Invalid <checker.key-locator.regex>: " + regexString));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800260 }
261 }
262 else if (boost::iequals(propertyIt->first, "hyper-relation")) {
263 const ConfigSection& hSection = propertyIt->second;
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800264 ConfigSection::const_iterator hPropertyIt = hSection.begin();
265
266 // Get k-regex
267 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-regex")) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500268 BOOST_THROW_EXCEPTION(Error("Expecting <checker.key-locator.hyper-relation.k-regex>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800269 }
270
271 std::string kRegex = hPropertyIt->second.data();
272 hPropertyIt++;
273
274 // Get k-expand
275 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-expand")) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500276 BOOST_THROW_EXCEPTION(Error("Expecting <checker.key-locator.hyper-relation.k-expand>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800277 }
278
279 std::string kExpand = hPropertyIt->second.data();
280 hPropertyIt++;
281
282 // Get h-relation
283 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "h-relation")) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500284 BOOST_THROW_EXCEPTION(Error("Expecting <checker.key-locator.hyper-relation.h-relation>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800285 }
286
287 std::string hRelation = hPropertyIt->second.data();
288 hPropertyIt++;
289
290 // Get p-regex
291 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-regex")) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500292 BOOST_THROW_EXCEPTION(Error("Expecting <checker.key-locator.hyper-relation.p-regex>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800293 }
294
295 std::string pRegex = hPropertyIt->second.data();
296 hPropertyIt++;
297
298 // Get p-expand
299 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-expand")) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500300 BOOST_THROW_EXCEPTION(Error("Expecting <checker.key-locator.hyper-relation.p-expand>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800301 }
302
303 std::string pExpand = hPropertyIt->second.data();
304 hPropertyIt++;
305
306 if (hPropertyIt != hSection.end()) {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500307 BOOST_THROW_EXCEPTION(Error("Expecting end of <checker.key-locator.hyper-relation>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800308 }
309
310 NameRelation relation = getNameRelationFromString(hRelation);
311 try {
312 return make_unique<HyperRelationChecker>(pRegex, pExpand, kRegex, kExpand, relation);
313 }
Davide Pesavento5df42a82018-03-08 20:06:51 -0500314 catch (const Regex::Error&) {
315 BOOST_THROW_EXCEPTION(Error("Invalid regex for <key-locator.hyper-relation>"));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800316 }
317 }
318 else {
Davide Pesavento5df42a82018-03-08 20:06:51 -0500319 BOOST_THROW_EXCEPTION(Error("Unrecognized <checker.key-locator>: " + propertyIt->first));
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -0800320 }
321}
322
323} // namespace validator_config
324} // namespace v2
325} // namespace security
326} // namespace ndn