blob: fdff8d2569bb826eccedd73962ae398a7e24666d [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{
Zhiyi Zhangc4a01762017-10-11 12:07:25 -070083 bool result = m_regex.match(klName);
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -080084 if (!result) {
85 std::ostringstream os;
86 os << "KeyLocator check failed: regex " << m_regex << " for packet " << pktName << " is invalid"
Zhiyi Zhangc4a01762017-10-11 12:07:25 -070087 << " (KeyLocator=" << klName << ")";
Alexander Afanasyeve5a19b82017-01-30 22:30:46 -080088 state->fail({ValidationError::POLICY_ERROR, os.str()});
89 }
90
91 return result;
92}
93
94HyperRelationChecker::HyperRelationChecker(const std::string& pktNameExpr, const std::string pktNameExpand,
95 const std::string& klNameExpr, const std::string klNameExpand,
96 const NameRelation& hyperRelation)
97 : m_hyperPRegex(pktNameExpr, pktNameExpand)
98 , m_hyperKRegex(klNameExpr, klNameExpand)
99 , m_hyperRelation(hyperRelation)
100{
101}
102
103bool
104HyperRelationChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
105{
106 if (!m_hyperPRegex.match(pktName) || !m_hyperKRegex.match(klName)) {
107 std::ostringstream os;
108 os << "Packet " << pktName << " (" << "KeyLocator=" << klName << ") does not match "
109 << "the hyper relation rule pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex;
110 state->fail({ValidationError::POLICY_ERROR, os.str()});
111 return false;
112 }
113
114 bool result = checkNameRelation(m_hyperRelation, m_hyperKRegex.expand(), m_hyperPRegex.expand());
115 if (!result) {
116 std::ostringstream os;
117 os << "KeyLocator check failed: hyper relation " << m_hyperRelation
118 << " pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex
119 << " of packet " << pktName << " (KeyLocator=" << klName << ") is invalid";
120 state->fail({ValidationError::POLICY_ERROR, os.str()});
121 }
122 return result;
123}
124
125unique_ptr<Checker>
126Checker::create(const ConfigSection& configSection, const std::string& configFilename)
127{
128 auto propertyIt = configSection.begin();
129
130 // Get checker.type
131 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
132 BOOST_THROW_EXCEPTION(Error("Expect <checker.type>"));
133 }
134
135 std::string type = propertyIt->second.data();
136
137 if (boost::iequals(type, "customized")) {
138 return createCustomizedChecker(configSection, configFilename);
139 }
140 else if (boost::iequals(type, "hierarchical")) {
141 return createHierarchicalChecker(configSection, configFilename);
142 }
143 else {
144 BOOST_THROW_EXCEPTION(Error("Unsupported checker type: " + type));
145 }
146}
147
148unique_ptr<Checker>
149Checker::createCustomizedChecker(const ConfigSection& configSection,
150 const std::string& configFilename)
151{
152 auto propertyIt = configSection.begin();
153 propertyIt++;
154
155 // TODO implement restrictions based on signature type (outside this checker)
156
157 if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
158 // ignore sig-type
159 propertyIt++;
160 }
161
162 // Get checker.key-locator
163 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator")) {
164 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator>"));
165 }
166
167 auto checker = createKeyLocatorChecker(propertyIt->second, configFilename);
168 propertyIt++;
169
170 if (propertyIt != configSection.end()) {
171 BOOST_THROW_EXCEPTION(Error("Expect the end of checker"));
172 }
173
174 return checker;
175}
176
177unique_ptr<Checker>
178Checker::createHierarchicalChecker(const ConfigSection& configSection,
179 const std::string& configFilename)
180{
181 auto propertyIt = configSection.begin();
182 propertyIt++;
183
184 // TODO implement restrictions based on signature type (outside this checker)
185
186 if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
187 // ignore sig-type
188 propertyIt++;
189 }
190
191 if (propertyIt != configSection.end()) {
192 BOOST_THROW_EXCEPTION(Error("Expect the end of checker"));
193 }
194
195 return make_unique<HyperRelationChecker>("^(<>*)$", "\\1",
196 "^(<>*)<KEY><>$", "\\1",
197 NameRelation::IS_PREFIX_OF);
198}
199
200///
201
202unique_ptr<Checker>
203Checker::createKeyLocatorChecker(const ConfigSection& configSection, const std::string& configFilename)
204{
205 auto propertyIt = configSection.begin();
206
207 // Get checker.key-locator.type
208 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
209 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.type>"));
210
211 std::string type = propertyIt->second.data();
212
213 if (boost::iequals(type, "name"))
214 return createKeyLocatorNameChecker(configSection, configFilename);
215 else
216 BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator.type: " + type));
217}
218
219unique_ptr<Checker>
220Checker::createKeyLocatorNameChecker(const ConfigSection& configSection, const std::string& configFilename)
221{
222 auto propertyIt = configSection.begin();
223 propertyIt++;
224
225 if (propertyIt == configSection.end())
226 BOOST_THROW_EXCEPTION(Error("Expect more checker.key-locator properties"));
227
228 if (boost::iequals(propertyIt->first, "name")) {
229 Name name;
230 try {
231 name = Name(propertyIt->second.data());
232 }
233 catch (const Name::Error& e) {
234 BOOST_THROW_EXCEPTION(Error("Invalid checker.key-locator.name: " + propertyIt->second.data()));
235 }
236 propertyIt++;
237
238 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) {
239 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.relation>"));
240 }
241
242 std::string relationString = propertyIt->second.data();
243 propertyIt++;
244
245 NameRelation relation = getNameRelationFromString(relationString);
246
247 if (propertyIt != configSection.end()) {
248 BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator"));
249 }
250 return make_unique<NameRelationChecker>(name, relation);
251 }
252 else if (boost::iequals(propertyIt->first, "regex")) {
253 std::string regexString = propertyIt->second.data();
254 propertyIt++;
255
256 if (propertyIt != configSection.end()) {
257 BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator"));
258 }
259
260 try {
261 return make_unique<RegexChecker>(regexString);
262 }
263 catch (const Regex::Error& e) {
264 BOOST_THROW_EXCEPTION(Error("Invalid checker.key-locator.regex: " + regexString));
265 }
266 }
267 else if (boost::iequals(propertyIt->first, "hyper-relation")) {
268 const ConfigSection& hSection = propertyIt->second;
269
270 ConfigSection::const_iterator hPropertyIt = hSection.begin();
271
272 // Get k-regex
273 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-regex")) {
274 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.k-regex>"));
275 }
276
277 std::string kRegex = hPropertyIt->second.data();
278 hPropertyIt++;
279
280 // Get k-expand
281 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-expand")) {
282 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.k-expand>"));
283 }
284
285 std::string kExpand = hPropertyIt->second.data();
286 hPropertyIt++;
287
288 // Get h-relation
289 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "h-relation")) {
290 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.h-relation>"));
291 }
292
293 std::string hRelation = hPropertyIt->second.data();
294 hPropertyIt++;
295
296 // Get p-regex
297 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-regex")) {
298 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.p-regex>"));
299 }
300
301 std::string pRegex = hPropertyIt->second.data();
302 hPropertyIt++;
303
304 // Get p-expand
305 if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-expand")) {
306 BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.p-expand>"));
307 }
308
309 std::string pExpand = hPropertyIt->second.data();
310 hPropertyIt++;
311
312 if (hPropertyIt != hSection.end()) {
313 BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator.hyper-relation"));
314 }
315
316 NameRelation relation = getNameRelationFromString(hRelation);
317 try {
318 return make_unique<HyperRelationChecker>(pRegex, pExpand, kRegex, kExpand, relation);
319 }
320 catch (const Regex::Error& e) {
321 BOOST_THROW_EXCEPTION(Error("Invalid regex for key-locator.hyper-relation"));
322 }
323 }
324 else {
325 BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator"));
326 }
327}
328
329} // namespace validator_config
330} // namespace v2
331} // namespace security
332} // namespace ndn