blob: 054c843bba6e813d5b9b1a838415d557a5a643b8 [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 Yu58f33712014-04-16 16:57:47 -070035 m_certificateCache = make_shared<CertificateCacheTtl>(boost::ref(m_face.getIoService()));
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
Yingdi Yu58f33712014-04-16 16:57:47 -070087 reset();
88
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070089 if (configSection.begin() == configSection.end())
90 {
91 std::string msg = "Error processing configuration file";
92 msg += ": ";
93 msg += filename;
94 msg += " no data";
95 throw security::conf::Error(msg);
96 }
97
98 for (security::conf::ConfigSection::const_iterator i = configSection.begin();
99 i != configSection.end(); ++i)
100 {
101 const std::string& sectionName = i->first;
102 const security::conf::ConfigSection& section = i->second;
103
104 if (boost::iequals(sectionName, "rule"))
105 {
106 onConfigRule(section, filename);
107 }
108 else if (boost::iequals(sectionName, "trust-anchor"))
109 {
110 onConfigTrustAnchor(section, filename);
111 }
112 else
113 {
114 std::string msg = "Error processing configuration file";
115 msg += " ";
116 msg += filename;
117 msg += " unrecognized section: " + sectionName;
118 throw security::conf::Error(msg);
119 }
120 }
121}
122
123void
124ValidatorConfig::onConfigRule(const security::conf::ConfigSection& configSection,
125 const std::string& filename)
126{
127 using namespace ndn::security::conf;
128
129 ConfigSection::const_iterator propertyIt = configSection.begin();
130
131 // Get rule.id
132 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "id"))
133 throw Error("Expect <rule.id>!");
134
135 std::string ruleId = propertyIt->second.data();
136 propertyIt++;
137
138 // Get rule.for
139 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,"for"))
140 throw Error("Expect <rule.for> in rule: " + ruleId + "!");
141
142 std::string usage = propertyIt->second.data();
143 propertyIt++;
144
145 bool isForData;
146 if (boost::iequals(usage, "data"))
147 isForData = true;
148 else if (boost::iequals(usage, "interest"))
149 isForData = false;
150 else
151 throw Error("Unrecognized <rule.for>: " + usage
152 + " in rule: " + ruleId);
153
154 // Get rule.filter(s)
155 std::vector<shared_ptr<Filter> > filters;
156 for (; propertyIt != configSection.end(); propertyIt++)
157 {
158 if (!boost::iequals(propertyIt->first, "filter"))
159 {
160 if (boost::iequals(propertyIt->first, "checker"))
161 break;
162 throw Error("Expect <rule.filter> in rule: " + ruleId);
163 }
164
165 filters.push_back(FilterFactory::create(propertyIt->second));
166 continue;
167 }
168
169 // Get rule.checker(s)
170 std::vector<shared_ptr<Checker> > checkers;
171 for (; propertyIt != configSection.end(); propertyIt++)
172 {
173 if (!boost::iequals(propertyIt->first, "checker"))
174 throw Error("Expect <rule.checker> in rule: " + ruleId);
175
176 checkers.push_back(CheckerFactory::create(propertyIt->second, filename));
177 continue;
178 }
179
180 // Check other stuff
181 if (propertyIt != configSection.end())
182 throw Error("Expect the end of rule: " + ruleId);
183
184 if (checkers.size() == 0)
185 throw Error("No <rule.checker> is specified in rule: " + ruleId);
186
187 if (isForData)
188 {
189 shared_ptr<DataRule> rule(new DataRule(ruleId));
190 for (size_t i = 0; i < filters.size(); i++)
191 rule->addFilter(filters[i]);
192 for (size_t i = 0; i < checkers.size(); i++)
193 rule->addChecker(checkers[i]);
194
195 m_dataRules.push_back(rule);
196 }
197 else
198 {
199 shared_ptr<InterestRule> rule(new InterestRule(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_interestRules.push_back(rule);
206 }
207}
208
209void
210ValidatorConfig::onConfigTrustAnchor(const security::conf::ConfigSection& configSection,
211 const std::string& filename)
212{
213 using namespace ndn::security::conf;
214 using namespace boost::filesystem;
215
216 ConfigSection::const_iterator propertyIt = configSection.begin();
217
218 // Get trust-anchor.type
219 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
220 throw Error("Expect <trust-anchor.type>!");
221
222 std::string type = propertyIt->second.data();
223 propertyIt++;
224
225 if (boost::iequals(type, "file"))
226 {
227 // Get trust-anchor.file
228 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,"file-name"))
229 throw Error("Expect <trust-anchor.file-name>!");
230
231 std::string file = propertyIt->second.data();
232 propertyIt++;
233
234 // Check other stuff
235 if (propertyIt != configSection.end())
236 throw Error("Expect the end of trust-anchor!");
237
238 path certfilePath = absolute(file, path(filename).parent_path());
239 shared_ptr<IdentityCertificate> idCert =
240 io::load<IdentityCertificate>(certfilePath.string());
241
242 if (static_cast<bool>(idCert))
243 {
244 BOOST_ASSERT(idCert->getName().size() >= 1);
245 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
246 }
247 else
248 throw Error("Cannot read certificate from file: " +
249 certfilePath.native());
250
251 return;
252 }
253 else if (boost::iequals(type, "base64"))
254 {
255 // Get trust-anchor.base64-string
256 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "base64-string"))
257 throw Error("Expect <trust-anchor.base64-string>!");
258
259 std::stringstream ss(propertyIt->second.data());
260 propertyIt++;
261
262 // Check other stuff
263 if (propertyIt != configSection.end())
264 throw Error("Expect the end of trust-anchor!");
265
266 shared_ptr<IdentityCertificate> idCert = io::load<IdentityCertificate>(ss);
267
268 if (static_cast<bool>(idCert))
269 {
270 BOOST_ASSERT(idCert->getName().size() >= 1);
271 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
272 }
273 else
274 throw Error("Cannot decode certificate from base64-string");
275
276 return;
277 }
278 else
279 throw Error("Unsupported trust-anchor.type: " + type);
280}
281
282void
283ValidatorConfig::checkPolicy(const Data& data,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700284 int nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700285 const OnDataValidated& onValidated,
286 const OnDataValidationFailed& onValidationFailed,
287 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
288{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700289 if (m_stepLimit == nSteps)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700290 return onValidationFailed(data.shared_from_this(),
291 "Maximum steps of validation reached");
292
293 bool isMatched = false;
294 int8_t checkResult = -1;
295
296 for (DataRuleList::iterator it = m_dataRules.begin();
297 it != m_dataRules.end(); it++)
298 {
299 if ((*it)->match(data))
300 {
301 isMatched = true;
302 checkResult = (*it)->check(data, onValidated, onValidationFailed);
303 break;
304 }
305 }
306
307 if (!isMatched)
308 return onValidationFailed(data.shared_from_this(), "No rule matched!");
309
310 if (checkResult == 0)
311 {
312 const Signature& signature = data.getSignature();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700313 checkSignature(data, signature, nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700314 onValidated, onValidationFailed, nextSteps);
315 }
316}
317
318void
319ValidatorConfig::checkPolicy(const Interest& interest,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700320 int nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700321 const OnInterestValidated& onValidated,
322 const OnInterestValidationFailed& onValidationFailed,
323 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
324{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700325 if (m_stepLimit == nSteps)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700326 return onValidationFailed(interest.shared_from_this(),
327 "Maximum steps of validation reached");
328
329 bool isMatched = false;
330 int8_t checkResult = -1;
331
332 for (InterestRuleList::iterator it = m_interestRules.begin();
333 it != m_interestRules.end(); it++)
334 {
335 if ((*it)->match(interest))
336 {
337 isMatched = true;
338 checkResult = (*it)->check(interest, onValidated, onValidationFailed);
339 break;
340 }
341 }
342
343 if (!isMatched)
344 return onValidationFailed(interest.shared_from_this(), "No rule matched!");
345
346 if (checkResult == 0)
347 {
348 const Name& interestName = interest.getName();
349 Name signedName = interestName.getPrefix(-2);
350 Signature signature(interestName[-2].blockFromValue(),
351 interestName[-1].blockFromValue());
352
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700353 checkSignature(interest, signature, nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700354 onValidated, onValidationFailed, nextSteps);
355 }
356}
357
358
359} // namespace ndn