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