blob: aa8ec27475428ae9a33c23cd45000b70af1fdb30 [file] [log] [blame]
Yingdi Yu48e8c0c2014-03-19 12:01:55 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07003 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
11 *
12 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070013 */
14
15#include "validator-config.hpp"
16#include "certificate-cache-ttl.hpp"
17#include "../util/io.hpp"
18
19#include <boost/filesystem.hpp>
20#include <boost/property_tree/info_parser.hpp>
21#include <boost/algorithm/string.hpp>
22
23namespace ndn {
24
25const shared_ptr<CertificateCache> ValidatorConfig::DEFAULT_CERTIFICATE_CACHE;
26
Yingdi Yu96e64062014-04-15 19:57:33 -070027ValidatorConfig::ValidatorConfig(Face& face,
28 const shared_ptr<CertificateCache>& certificateCache,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070029 const int stepLimit)
30 : Validator(face)
31 , m_stepLimit(stepLimit)
32 , m_certificateCache(certificateCache)
33{
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070034 if (!static_cast<bool>(m_certificateCache))
Yingdi Yu96e64062014-04-15 19:57:33 -070035 m_certificateCache = make_shared<CertificateCacheTtl>(m_face.ioService());
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070036}
37
38void
39ValidatorConfig::load(const std::string& filename)
40{
41 std::ifstream inputFile;
42 inputFile.open(filename.c_str());
43 if (!inputFile.good() || !inputFile.is_open())
44 {
45 std::string msg = "Failed to read configuration file: ";
46 msg += filename;
47 throw security::conf::Error(msg);
48 }
49 load(inputFile, filename);
50 inputFile.close();
51}
52
53void
54ValidatorConfig::load(const std::string& input, const std::string& filename)
55{
56 std::istringstream inputStream(input);
57 load(inputStream, filename);
58}
59
60
61void
62ValidatorConfig::load(std::istream& input, const std::string& filename)
63{
64 security::conf::ConfigSection tree;
65 try
66 {
67 boost::property_tree::read_info(input, tree);
68 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070069 catch (boost::property_tree::info_parser_error& error)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070070 {
71 std::stringstream msg;
72 msg << "Failed to parse configuration file";
73 msg << " " << filename;
74 msg << " " << error.message() << " line " << error.line();
75 throw security::conf::Error(msg.str());
76 }
77
Yingdi Yudfa9d732014-04-09 09:53:01 -070078 load(tree, filename);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070079}
80
81void
Yingdi Yudfa9d732014-04-09 09:53:01 -070082ValidatorConfig::load(const security::conf::ConfigSection& configSection,
83 const std::string& filename)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070084{
85 BOOST_ASSERT(!filename.empty());
86
87 if (configSection.begin() == configSection.end())
88 {
89 std::string msg = "Error processing configuration file";
90 msg += ": ";
91 msg += filename;
92 msg += " no data";
93 throw security::conf::Error(msg);
94 }
95
96 for (security::conf::ConfigSection::const_iterator i = configSection.begin();
97 i != configSection.end(); ++i)
98 {
99 const std::string& sectionName = i->first;
100 const security::conf::ConfigSection& section = i->second;
101
102 if (boost::iequals(sectionName, "rule"))
103 {
104 onConfigRule(section, filename);
105 }
106 else if (boost::iequals(sectionName, "trust-anchor"))
107 {
108 onConfigTrustAnchor(section, filename);
109 }
110 else
111 {
112 std::string msg = "Error processing configuration file";
113 msg += " ";
114 msg += filename;
115 msg += " unrecognized section: " + sectionName;
116 throw security::conf::Error(msg);
117 }
118 }
119}
120
121void
122ValidatorConfig::onConfigRule(const security::conf::ConfigSection& configSection,
123 const std::string& filename)
124{
125 using namespace ndn::security::conf;
126
127 ConfigSection::const_iterator propertyIt = configSection.begin();
128
129 // Get rule.id
130 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "id"))
131 throw Error("Expect <rule.id>!");
132
133 std::string ruleId = propertyIt->second.data();
134 propertyIt++;
135
136 // Get rule.for
137 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,"for"))
138 throw Error("Expect <rule.for> in rule: " + ruleId + "!");
139
140 std::string usage = propertyIt->second.data();
141 propertyIt++;
142
143 bool isForData;
144 if (boost::iequals(usage, "data"))
145 isForData = true;
146 else if (boost::iequals(usage, "interest"))
147 isForData = false;
148 else
149 throw Error("Unrecognized <rule.for>: " + usage
150 + " in rule: " + ruleId);
151
152 // Get rule.filter(s)
153 std::vector<shared_ptr<Filter> > filters;
154 for (; propertyIt != configSection.end(); propertyIt++)
155 {
156 if (!boost::iequals(propertyIt->first, "filter"))
157 {
158 if (boost::iequals(propertyIt->first, "checker"))
159 break;
160 throw Error("Expect <rule.filter> in rule: " + ruleId);
161 }
162
163 filters.push_back(FilterFactory::create(propertyIt->second));
164 continue;
165 }
166
167 // Get rule.checker(s)
168 std::vector<shared_ptr<Checker> > checkers;
169 for (; propertyIt != configSection.end(); propertyIt++)
170 {
171 if (!boost::iequals(propertyIt->first, "checker"))
172 throw Error("Expect <rule.checker> in rule: " + ruleId);
173
174 checkers.push_back(CheckerFactory::create(propertyIt->second, filename));
175 continue;
176 }
177
178 // Check other stuff
179 if (propertyIt != configSection.end())
180 throw Error("Expect the end of rule: " + ruleId);
181
182 if (checkers.size() == 0)
183 throw Error("No <rule.checker> is specified in rule: " + ruleId);
184
185 if (isForData)
186 {
187 shared_ptr<DataRule> rule(new DataRule(ruleId));
188 for (size_t i = 0; i < filters.size(); i++)
189 rule->addFilter(filters[i]);
190 for (size_t i = 0; i < checkers.size(); i++)
191 rule->addChecker(checkers[i]);
192
193 m_dataRules.push_back(rule);
194 }
195 else
196 {
197 shared_ptr<InterestRule> rule(new InterestRule(ruleId));
198 for (size_t i = 0; i < filters.size(); i++)
199 rule->addFilter(filters[i]);
200 for (size_t i = 0; i < checkers.size(); i++)
201 rule->addChecker(checkers[i]);
202
203 m_interestRules.push_back(rule);
204 }
205}
206
207void
208ValidatorConfig::onConfigTrustAnchor(const security::conf::ConfigSection& configSection,
209 const std::string& filename)
210{
211 using namespace ndn::security::conf;
212 using namespace boost::filesystem;
213
214 ConfigSection::const_iterator propertyIt = configSection.begin();
215
216 // Get trust-anchor.type
217 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
218 throw Error("Expect <trust-anchor.type>!");
219
220 std::string type = propertyIt->second.data();
221 propertyIt++;
222
223 if (boost::iequals(type, "file"))
224 {
225 // Get trust-anchor.file
226 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,"file-name"))
227 throw Error("Expect <trust-anchor.file-name>!");
228
229 std::string file = propertyIt->second.data();
230 propertyIt++;
231
232 // Check other stuff
233 if (propertyIt != configSection.end())
234 throw Error("Expect the end of trust-anchor!");
235
236 path certfilePath = absolute(file, path(filename).parent_path());
237 shared_ptr<IdentityCertificate> idCert =
238 io::load<IdentityCertificate>(certfilePath.string());
239
240 if (static_cast<bool>(idCert))
241 {
242 BOOST_ASSERT(idCert->getName().size() >= 1);
243 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
244 }
245 else
246 throw Error("Cannot read certificate from file: " +
247 certfilePath.native());
248
249 return;
250 }
251 else if (boost::iequals(type, "base64"))
252 {
253 // Get trust-anchor.base64-string
254 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "base64-string"))
255 throw Error("Expect <trust-anchor.base64-string>!");
256
257 std::stringstream ss(propertyIt->second.data());
258 propertyIt++;
259
260 // Check other stuff
261 if (propertyIt != configSection.end())
262 throw Error("Expect the end of trust-anchor!");
263
264 shared_ptr<IdentityCertificate> idCert = io::load<IdentityCertificate>(ss);
265
266 if (static_cast<bool>(idCert))
267 {
268 BOOST_ASSERT(idCert->getName().size() >= 1);
269 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
270 }
271 else
272 throw Error("Cannot decode certificate from base64-string");
273
274 return;
275 }
276 else
277 throw Error("Unsupported trust-anchor.type: " + type);
278}
279
280void
281ValidatorConfig::checkPolicy(const Data& data,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700282 int nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700283 const OnDataValidated& onValidated,
284 const OnDataValidationFailed& onValidationFailed,
285 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
286{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700287 if (m_stepLimit == nSteps)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700288 return onValidationFailed(data.shared_from_this(),
289 "Maximum steps of validation reached");
290
291 bool isMatched = false;
292 int8_t checkResult = -1;
293
294 for (DataRuleList::iterator it = m_dataRules.begin();
295 it != m_dataRules.end(); it++)
296 {
297 if ((*it)->match(data))
298 {
299 isMatched = true;
300 checkResult = (*it)->check(data, onValidated, onValidationFailed);
301 break;
302 }
303 }
304
305 if (!isMatched)
306 return onValidationFailed(data.shared_from_this(), "No rule matched!");
307
308 if (checkResult == 0)
309 {
310 const Signature& signature = data.getSignature();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700311 checkSignature(data, signature, nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700312 onValidated, onValidationFailed, nextSteps);
313 }
314}
315
316void
317ValidatorConfig::checkPolicy(const Interest& interest,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700318 int nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700319 const OnInterestValidated& onValidated,
320 const OnInterestValidationFailed& onValidationFailed,
321 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
322{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700323 if (m_stepLimit == nSteps)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700324 return onValidationFailed(interest.shared_from_this(),
325 "Maximum steps of validation reached");
326
327 bool isMatched = false;
328 int8_t checkResult = -1;
329
330 for (InterestRuleList::iterator it = m_interestRules.begin();
331 it != m_interestRules.end(); it++)
332 {
333 if ((*it)->match(interest))
334 {
335 isMatched = true;
336 checkResult = (*it)->check(interest, onValidated, onValidationFailed);
337 break;
338 }
339 }
340
341 if (!isMatched)
342 return onValidationFailed(interest.shared_from_this(), "No rule matched!");
343
344 if (checkResult == 0)
345 {
346 const Name& interestName = interest.getName();
347 Name signedName = interestName.getPrefix(-2);
348 Signature signature(interestName[-2].blockFromValue(),
349 interestName[-1].blockFromValue());
350
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700351 checkSignature(interest, signature, nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700352 onValidated, onValidationFailed, nextSteps);
353 }
354}
355
356
357} // namespace ndn