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