blob: fbe19d25a36131c63199b1842ffa8ba5f336c400 [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
Yingdi Yu96e64062014-04-15 19:57:33 -070038ValidatorConfig::ValidatorConfig(const shared_ptr<Face>& face,
39 const shared_ptr<CertificateCache>& certificateCache,
40 const int stepLimit)
41 : Validator(*face)
42 , m_stepLimit(stepLimit)
43 , m_certificateCache(certificateCache)
44{
45 if (!static_cast<bool>(m_certificateCache))
46 m_certificateCache = make_shared<CertificateCacheTtl>(m_face.ioService());
47}
48
49
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070050void
51ValidatorConfig::load(const std::string& filename)
52{
53 std::ifstream inputFile;
54 inputFile.open(filename.c_str());
55 if (!inputFile.good() || !inputFile.is_open())
56 {
57 std::string msg = "Failed to read configuration file: ";
58 msg += filename;
59 throw security::conf::Error(msg);
60 }
61 load(inputFile, filename);
62 inputFile.close();
63}
64
65void
66ValidatorConfig::load(const std::string& input, const std::string& filename)
67{
68 std::istringstream inputStream(input);
69 load(inputStream, filename);
70}
71
72
73void
74ValidatorConfig::load(std::istream& input, const std::string& filename)
75{
76 security::conf::ConfigSection tree;
77 try
78 {
79 boost::property_tree::read_info(input, tree);
80 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070081 catch (boost::property_tree::info_parser_error& error)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070082 {
83 std::stringstream msg;
84 msg << "Failed to parse configuration file";
85 msg << " " << filename;
86 msg << " " << error.message() << " line " << error.line();
87 throw security::conf::Error(msg.str());
88 }
89
Yingdi Yudfa9d732014-04-09 09:53:01 -070090 load(tree, filename);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070091}
92
93void
Yingdi Yudfa9d732014-04-09 09:53:01 -070094ValidatorConfig::load(const security::conf::ConfigSection& configSection,
95 const std::string& filename)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070096{
97 BOOST_ASSERT(!filename.empty());
98
99 if (configSection.begin() == configSection.end())
100 {
101 std::string msg = "Error processing configuration file";
102 msg += ": ";
103 msg += filename;
104 msg += " no data";
105 throw security::conf::Error(msg);
106 }
107
108 for (security::conf::ConfigSection::const_iterator i = configSection.begin();
109 i != configSection.end(); ++i)
110 {
111 const std::string& sectionName = i->first;
112 const security::conf::ConfigSection& section = i->second;
113
114 if (boost::iequals(sectionName, "rule"))
115 {
116 onConfigRule(section, filename);
117 }
118 else if (boost::iequals(sectionName, "trust-anchor"))
119 {
120 onConfigTrustAnchor(section, filename);
121 }
122 else
123 {
124 std::string msg = "Error processing configuration file";
125 msg += " ";
126 msg += filename;
127 msg += " unrecognized section: " + sectionName;
128 throw security::conf::Error(msg);
129 }
130 }
131}
132
133void
134ValidatorConfig::onConfigRule(const security::conf::ConfigSection& configSection,
135 const std::string& filename)
136{
137 using namespace ndn::security::conf;
138
139 ConfigSection::const_iterator propertyIt = configSection.begin();
140
141 // Get rule.id
142 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "id"))
143 throw Error("Expect <rule.id>!");
144
145 std::string ruleId = propertyIt->second.data();
146 propertyIt++;
147
148 // Get rule.for
149 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,"for"))
150 throw Error("Expect <rule.for> in rule: " + ruleId + "!");
151
152 std::string usage = propertyIt->second.data();
153 propertyIt++;
154
155 bool isForData;
156 if (boost::iequals(usage, "data"))
157 isForData = true;
158 else if (boost::iequals(usage, "interest"))
159 isForData = false;
160 else
161 throw Error("Unrecognized <rule.for>: " + usage
162 + " in rule: " + ruleId);
163
164 // Get rule.filter(s)
165 std::vector<shared_ptr<Filter> > filters;
166 for (; propertyIt != configSection.end(); propertyIt++)
167 {
168 if (!boost::iequals(propertyIt->first, "filter"))
169 {
170 if (boost::iequals(propertyIt->first, "checker"))
171 break;
172 throw Error("Expect <rule.filter> in rule: " + ruleId);
173 }
174
175 filters.push_back(FilterFactory::create(propertyIt->second));
176 continue;
177 }
178
179 // Get rule.checker(s)
180 std::vector<shared_ptr<Checker> > checkers;
181 for (; propertyIt != configSection.end(); propertyIt++)
182 {
183 if (!boost::iequals(propertyIt->first, "checker"))
184 throw Error("Expect <rule.checker> in rule: " + ruleId);
185
186 checkers.push_back(CheckerFactory::create(propertyIt->second, filename));
187 continue;
188 }
189
190 // Check other stuff
191 if (propertyIt != configSection.end())
192 throw Error("Expect the end of rule: " + ruleId);
193
194 if (checkers.size() == 0)
195 throw Error("No <rule.checker> is specified in rule: " + ruleId);
196
197 if (isForData)
198 {
199 shared_ptr<DataRule> rule(new DataRule(ruleId));
200 for (size_t i = 0; i < filters.size(); i++)
201 rule->addFilter(filters[i]);
202 for (size_t i = 0; i < checkers.size(); i++)
203 rule->addChecker(checkers[i]);
204
205 m_dataRules.push_back(rule);
206 }
207 else
208 {
209 shared_ptr<InterestRule> rule(new InterestRule(ruleId));
210 for (size_t i = 0; i < filters.size(); i++)
211 rule->addFilter(filters[i]);
212 for (size_t i = 0; i < checkers.size(); i++)
213 rule->addChecker(checkers[i]);
214
215 m_interestRules.push_back(rule);
216 }
217}
218
219void
220ValidatorConfig::onConfigTrustAnchor(const security::conf::ConfigSection& configSection,
221 const std::string& filename)
222{
223 using namespace ndn::security::conf;
224 using namespace boost::filesystem;
225
226 ConfigSection::const_iterator propertyIt = configSection.begin();
227
228 // Get trust-anchor.type
229 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
230 throw Error("Expect <trust-anchor.type>!");
231
232 std::string type = propertyIt->second.data();
233 propertyIt++;
234
235 if (boost::iequals(type, "file"))
236 {
237 // Get trust-anchor.file
238 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,"file-name"))
239 throw Error("Expect <trust-anchor.file-name>!");
240
241 std::string file = propertyIt->second.data();
242 propertyIt++;
243
244 // Check other stuff
245 if (propertyIt != configSection.end())
246 throw Error("Expect the end of trust-anchor!");
247
248 path certfilePath = absolute(file, path(filename).parent_path());
249 shared_ptr<IdentityCertificate> idCert =
250 io::load<IdentityCertificate>(certfilePath.string());
251
252 if (static_cast<bool>(idCert))
253 {
254 BOOST_ASSERT(idCert->getName().size() >= 1);
255 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
256 }
257 else
258 throw Error("Cannot read certificate from file: " +
259 certfilePath.native());
260
261 return;
262 }
263 else if (boost::iequals(type, "base64"))
264 {
265 // Get trust-anchor.base64-string
266 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "base64-string"))
267 throw Error("Expect <trust-anchor.base64-string>!");
268
269 std::stringstream ss(propertyIt->second.data());
270 propertyIt++;
271
272 // Check other stuff
273 if (propertyIt != configSection.end())
274 throw Error("Expect the end of trust-anchor!");
275
276 shared_ptr<IdentityCertificate> idCert = io::load<IdentityCertificate>(ss);
277
278 if (static_cast<bool>(idCert))
279 {
280 BOOST_ASSERT(idCert->getName().size() >= 1);
281 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
282 }
283 else
284 throw Error("Cannot decode certificate from base64-string");
285
286 return;
287 }
288 else
289 throw Error("Unsupported trust-anchor.type: " + type);
290}
291
292void
293ValidatorConfig::checkPolicy(const Data& data,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700294 int nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700295 const OnDataValidated& onValidated,
296 const OnDataValidationFailed& onValidationFailed,
297 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
298{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700299 if (m_stepLimit == nSteps)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700300 return onValidationFailed(data.shared_from_this(),
301 "Maximum steps of validation reached");
302
303 bool isMatched = false;
304 int8_t checkResult = -1;
305
306 for (DataRuleList::iterator it = m_dataRules.begin();
307 it != m_dataRules.end(); it++)
308 {
309 if ((*it)->match(data))
310 {
311 isMatched = true;
312 checkResult = (*it)->check(data, onValidated, onValidationFailed);
313 break;
314 }
315 }
316
317 if (!isMatched)
318 return onValidationFailed(data.shared_from_this(), "No rule matched!");
319
320 if (checkResult == 0)
321 {
322 const Signature& signature = data.getSignature();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700323 checkSignature(data, signature, nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700324 onValidated, onValidationFailed, nextSteps);
325 }
326}
327
328void
329ValidatorConfig::checkPolicy(const Interest& interest,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700330 int nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700331 const OnInterestValidated& onValidated,
332 const OnInterestValidationFailed& onValidationFailed,
333 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
334{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700335 if (m_stepLimit == nSteps)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700336 return onValidationFailed(interest.shared_from_this(),
337 "Maximum steps of validation reached");
338
339 bool isMatched = false;
340 int8_t checkResult = -1;
341
342 for (InterestRuleList::iterator it = m_interestRules.begin();
343 it != m_interestRules.end(); it++)
344 {
345 if ((*it)->match(interest))
346 {
347 isMatched = true;
348 checkResult = (*it)->check(interest, onValidated, onValidationFailed);
349 break;
350 }
351 }
352
353 if (!isMatched)
354 return onValidationFailed(interest.shared_from_this(), "No rule matched!");
355
356 if (checkResult == 0)
357 {
358 const Name& interestName = interest.getName();
359 Name signedName = interestName.getPrefix(-2);
360 Signature signature(interestName[-2].blockFromValue(),
361 interestName[-1].blockFromValue());
362
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700363 checkSignature(interest, signature, nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700364 onValidated, onValidationFailed, nextSteps);
365 }
366}
367
368
369} // namespace ndn