blob: 47415af8778cd0f547ac3333f0db9db171c69076 [file] [log] [blame]
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2013-2017 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
22#include "checker.hpp"
23#include "security/v2/validation-state.hpp"
24#include "security/verification-helpers.hpp"
25#include "security/pib/key.hpp"
26#include "util/logger.hpp"
27
28#include <boost/algorithm/string.hpp>
29#include <boost/filesystem.hpp>
30#include <boost/lexical_cast.hpp>
31
32namespace ndn {
33namespace security {
34namespace v2 {
35namespace validator_config {
36
37bool
38Checker::check(uint32_t pktType, const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
39{
40 BOOST_ASSERT(pktType == tlv::Interest || pktType == tlv::Data);
41
42 if (pktType == tlv::Interest) {
43 if (pktName.size() < signed_interest::MIN_SIZE)
44 return false;
45
46 return checkNames(pktName.getPrefix(-signed_interest::MIN_SIZE), klName, state);
47 }
48 else {
49 return checkNames(pktName, klName, state);
50 }
51}
52
53NameRelationChecker::NameRelationChecker(const Name& name, const NameRelation& relation)
54 : m_name(name)
55 , m_relation(relation)
56{
57}
58
59bool
60NameRelationChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
61{
62 // pktName not used in this check
63 Name identity = extractIdentityFromKeyName(klName);
64 bool result = checkNameRelation(m_relation, m_name, identity);
65 if (!result) {
66 std::ostringstream os;
67 os << "KeyLocator check failed: name relation " << m_name << " " << m_relation
68 << " for packet " << pktName << " is invalid"
69 << " (KeyLocator=" << klName << ", identity=" << identity << ")";
70 state->fail({ValidationError::POLICY_ERROR, os.str()});
71 }
72 return result;
73}
74
75RegexChecker::RegexChecker(const Regex& regex)
76 : m_regex(regex)
77{
78}
79
80bool
81RegexChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
82{
83 // pktName not used in this check
84 Name identity = extractIdentityFromKeyName(klName);
85 bool result = m_regex.match(identity);
86 if (!result) {
87 std::ostringstream os;
88 os << "KeyLocator check failed: regex " << m_regex << " for packet " << pktName << " is invalid"
89 << " (KeyLocator=" << klName << ", identity=" << identity << ")";
90 state->fail({ValidationError::POLICY_ERROR, os.str()});
91 }
92
93 return result;
94}
95
96HyperRelationChecker::HyperRelationChecker(const std::string& pktNameExpr, const std::string pktNameExpand,
97 const std::string& klNameExpr, const std::string klNameExpand,
98 const NameRelation& hyperRelation)
99 : m_hyperPRegex(pktNameExpr, pktNameExpand)
100 , m_hyperKRegex(klNameExpr, klNameExpand)
101 , m_hyperRelation(hyperRelation)
102{
103}
104
105bool
106HyperRelationChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
107{
108 if (!m_hyperPRegex.match(pktName) || !m_hyperKRegex.match(klName)) {
109 std::ostringstream os;
110 os << "Packet " << pktName << " (" << "KeyLocator=" << klName << ") does not match "
111 << "the hyper relation rule pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex;
112 state->fail({ValidationError::POLICY_ERROR, os.str()});
113 return false;
114 }
115
116 bool result = checkNameRelation(m_hyperRelation, m_hyperKRegex.expand(), m_hyperPRegex.expand());
117 if (!result) {
118 std::ostringstream os;
119 os << "KeyLocator check failed: hyper relation " << m_hyperRelation
120 << " pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex
121 << " of packet " << pktName << " (KeyLocator=" << klName << ") is invalid";
122 state->fail({ValidationError::POLICY_ERROR, os.str()});
123 }
124 return result;
125}
126
127unique_ptr<Checker>
128Checker::create(const ConfigSection& configSection, const std::string& configFilename)
129{
130 auto propertyIt = configSection.begin();
131
132 // Get checker.type
133 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
134 BOOST_THROW_EXCEPTION(Error("Expect <checker.type>"));
135 }
136
137 std::string type = propertyIt->second.data();
138
139 if (boost::iequals(type, "customized")) {
140 return createCustomizedChecker(configSection, configFilename);
141 }
142 else if (boost::iequals(type, "hierarchical")) {
143 return createHierarchicalChecker(configSection, configFilename);
144 }
145 else {
146 BOOST_THROW_EXCEPTION(Error("Unsupported checker type: " + type));
147 }
148}
149
150unique_ptr<Checker>
151Checker::createCustomizedChecker(const ConfigSection& configSection,
152 const std::string& configFilename)
153{
154 auto propertyIt = configSection.begin();
155 propertyIt++;
156
157 // TODO implement restrictions based on signature type (outside this checker)
158
159 if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
160 // ignore sig-type
161 propertyIt++;
162 }
163
164 // Get checker.key-locator
165 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator")) {
166 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator>"));
167 }
168
169 auto checker = createKeyLocatorChecker(propertyIt->second, configFilename);
170 propertyIt++;
171
172 if (propertyIt != configSection.end()) {
173 BOOST_THROW_EXCEPTION(Error("Expect the end of checker"));
174 }
175
176 return checker;
177}
178
179unique_ptr<Checker>
180Checker::createHierarchicalChecker(const ConfigSection& configSection,
181 const std::string& configFilename)
182{
183 auto propertyIt = configSection.begin();
184 propertyIt++;
185
186 // TODO implement restrictions based on signature type (outside this checker)
187
188 if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
189 // ignore sig-type
190 propertyIt++;
191 }
192
193 if (propertyIt != configSection.end()) {
194 BOOST_THROW_EXCEPTION(Error("Expect the end of checker"));
195 }
196
197 return make_unique<HyperRelationChecker>("^(<>*)$", "\\1",
198 "^(<>*)<KEY><>$", "\\1",
199 NameRelation::IS_PREFIX_OF);
200}
201
202///
203
204unique_ptr<Checker>
205Checker::createKeyLocatorChecker(const ConfigSection& configSection, const std::string& configFilename)
206{
207 auto propertyIt = configSection.begin();
208
209 // Get checker.key-locator.type
210 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
211 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.type>"));
212
213 std::string type = propertyIt->second.data();
214
215 if (boost::iequals(type, "name"))
216 return createKeyLocatorNameChecker(configSection, configFilename);
217 else
218 BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator.type: " + type));
219}
220
221unique_ptr<Checker>
222Checker::createKeyLocatorNameChecker(const ConfigSection& configSection, const std::string& configFilename)
223{
224 auto propertyIt = configSection.begin();
225 propertyIt++;
226
227 if (propertyIt == configSection.end())
228 BOOST_THROW_EXCEPTION(Error("Expect more checker.key-locator properties"));
229
230 if (boost::iequals(propertyIt->first, "name")) {
231 Name name;
232 try {
233 name = Name(propertyIt->second.data());
234 }
235 catch (const Name::Error& e) {
236 BOOST_THROW_EXCEPTION(Error("Invalid checker.key-locator.name: " + propertyIt->second.data()));
237 }
238 propertyIt++;
239
240 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) {
241 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.relation>"));
242 }
243
244 std::string relationString = propertyIt->second.data();
245 propertyIt++;
246
247 NameRelation relation = getNameRelationFromString(relationString);
248
249 if (propertyIt != configSection.end()) {
250 BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator"));
251 }
252 return make_unique<NameRelationChecker>(name, relation);
253 }
254 else if (boost::iequals(propertyIt->first, "regex")) {
255 std::string regexString = propertyIt->second.data();
256 propertyIt++;
257
258 if (propertyIt != configSection.end()) {
259 BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator"));
260 }
261
262 try {
263 return make_unique<RegexChecker>(regexString);
264 }
265 catch (const Regex::Error& e) {
266 BOOST_THROW_EXCEPTION(Error("Invalid checker.key-locator.regex: " + regexString));
267 }
268 }
269 else if (boost::iequals(propertyIt->first, "hyper-relation")) {
270 const ConfigSection& hSection = propertyIt->second;
271
272 ConfigSection::const_iterator hPropertyIt = hSection.begin();
273
274 // Get k-regex
275 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-regex")) {
276 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.k-regex>"));
277 }
278
279 std::string kRegex = hPropertyIt->second.data();
280 hPropertyIt++;
281
282 // Get k-expand
283 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-expand")) {
284 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.k-expand>"));
285 }
286
287 std::string kExpand = hPropertyIt->second.data();
288 hPropertyIt++;
289
290 // Get h-relation
291 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "h-relation")) {
292 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.h-relation>"));
293 }
294
295 std::string hRelation = hPropertyIt->second.data();
296 hPropertyIt++;
297
298 // Get p-regex
299 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-regex")) {
300 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.p-regex>"));
301 }
302
303 std::string pRegex = hPropertyIt->second.data();
304 hPropertyIt++;
305
306 // Get p-expand
307 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-expand")) {
308 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.p-expand>"));
309 }
310
311 std::string pExpand = hPropertyIt->second.data();
312 hPropertyIt++;
313
314 if (hPropertyIt != hSection.end()) {
315 BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator.hyper-relation"));
316 }
317
318 NameRelation relation = getNameRelationFromString(hRelation);
319 try {
320 return make_unique<HyperRelationChecker>(pRegex, pExpand, kRegex, kExpand, relation);
321 }
322 catch (const Regex::Error& e) {
323 BOOST_THROW_EXCEPTION(Error("Invalid regex for key-locator.hyper-relation"));
324 }
325 }
326 else {
327 BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator"));
328 }
329}
330
331} // namespace validator_config
332} // namespace v2
333} // namespace security
334} // namespace ndn