NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
validation-policy-config.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2018 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later version.
10  *
11  * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14  *
15  * You should have received copies of the GNU General Public License and GNU Lesser
16  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20  */
21 
24 #include "ndn-cxx/util/io.hpp"
25 
26 #include <boost/algorithm/string/predicate.hpp>
27 #include <boost/filesystem.hpp>
28 #include <boost/lexical_cast.hpp>
29 #include <boost/property_tree/info_parser.hpp>
30 
31 #include <fstream>
32 
33 namespace ndn {
34 namespace security {
35 namespace v2 {
36 namespace validator_config {
37 
39  : m_shouldBypass(false)
40  , m_isConfigured(false)
41 {
42 }
43 
44 void
45 ValidationPolicyConfig::load(const std::string& filename)
46 {
47  std::ifstream inputFile(filename);
48  if (!inputFile) {
49  BOOST_THROW_EXCEPTION(Error("Failed to read configuration file: " + filename));
50  }
51  load(inputFile, filename);
52 }
53 
54 void
55 ValidationPolicyConfig::load(const std::string& input, const std::string& filename)
56 {
57  std::istringstream inputStream(input);
58  load(inputStream, filename);
59 }
60 
61 void
62 ValidationPolicyConfig::load(std::istream& input, const std::string& filename)
63 {
64  ConfigSection tree;
65  try {
66  boost::property_tree::read_info(input, tree);
67  }
68  catch (const boost::property_tree::info_parser_error& e) {
69  BOOST_THROW_EXCEPTION(Error("Failed to parse configuration file " + filename +
70  " line " + to_string(e.line()) + ": " + e.message()));
71  }
72  load(tree, filename);
73 }
74 
75 void
76 ValidationPolicyConfig::load(const ConfigSection& configSection, const std::string& filename)
77 {
78  if (m_validator == nullptr) {
79  BOOST_THROW_EXCEPTION(Error("Validator instance not assigned on the policy"));
80  }
81  if (m_isConfigured) {
82  m_shouldBypass = false;
83  m_dataRules.clear();
84  m_interestRules.clear();
85  m_validator->resetAnchors();
86  m_validator->resetVerifiedCertificates();
87  }
88  m_isConfigured = true;
89 
90  BOOST_ASSERT(!filename.empty());
91 
92  if (configSection.begin() == configSection.end()) {
93  BOOST_THROW_EXCEPTION(Error("Error processing configuration file " + filename + ": no data"));
94  }
95 
96  for (const auto& subSection : configSection) {
97  const std::string& sectionName = subSection.first;
98  const ConfigSection& section = subSection.second;
99 
100  if (boost::iequals(sectionName, "rule")) {
101  auto rule = Rule::create(section, filename);
102  if (rule->getPktType() == tlv::Data) {
103  m_dataRules.push_back(std::move(rule));
104  }
105  else if (rule->getPktType() == tlv::Interest) {
106  m_interestRules.push_back(std::move(rule));
107  }
108  }
109  else if (boost::iequals(sectionName, "trust-anchor")) {
110  processConfigTrustAnchor(section, filename);
111  }
112  else {
113  BOOST_THROW_EXCEPTION(Error("Error processing configuration file " + filename +
114  ": unrecognized section " + sectionName));
115  }
116  }
117 }
118 
119 void
120 ValidationPolicyConfig::processConfigTrustAnchor(const ConfigSection& configSection,
121  const std::string& filename)
122 {
123  using namespace boost::filesystem;
124 
125  auto propertyIt = configSection.begin();
126 
127  // Get trust-anchor.type
128  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
129  BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.type>"));
130  }
131 
132  std::string type = propertyIt->second.data();
133  propertyIt++;
134 
135  if (boost::iequals(type, "file")) {
136  // Get trust-anchor.file
137  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name")) {
138  BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.file-name>"));
139  }
140 
141  std::string file = propertyIt->second.data();
142  propertyIt++;
143 
144  time::nanoseconds refresh = getRefreshPeriod(propertyIt, configSection.end());
145  if (propertyIt != configSection.end())
146  BOOST_THROW_EXCEPTION(Error("Expecting end of <trust-anchor>"));
147 
148  m_validator->loadAnchor(filename, absolute(file, path(filename).parent_path()).string(),
149  refresh, false);
150  }
151  else if (boost::iequals(type, "base64")) {
152  // Get trust-anchor.base64-string
153  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "base64-string"))
154  BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.base64-string>"));
155 
156  std::stringstream ss(propertyIt->second.data());
157  propertyIt++;
158 
159  if (propertyIt != configSection.end())
160  BOOST_THROW_EXCEPTION(Error("Expecting end of <trust-anchor>"));
161 
162  auto idCert = io::load<Certificate>(ss);
163  if (idCert != nullptr) {
164  m_validator->loadAnchor("", std::move(*idCert));
165  }
166  else {
167  BOOST_THROW_EXCEPTION(Error("Cannot decode certificate from base64-string"));
168  }
169  }
170  else if (boost::iequals(type, "dir")) {
171  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "dir"))
172  BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.dir>"));
173 
174  std::string dirString(propertyIt->second.data());
175  propertyIt++;
176 
177  time::nanoseconds refresh = getRefreshPeriod(propertyIt, configSection.end());
178  if (propertyIt != configSection.end())
179  BOOST_THROW_EXCEPTION(Error("Expecting end of <trust-anchor>"));
180 
181  path dirPath = absolute(dirString, path(filename).parent_path());
182  m_validator->loadAnchor(dirString, dirPath.string(), refresh, true);
183  }
184  else if (boost::iequals(type, "any")) {
185  m_shouldBypass = true;
186  }
187  else {
188  BOOST_THROW_EXCEPTION(Error("Unrecognized <trust-anchor.type>: " + type));
189  }
190 }
191 
192 time::nanoseconds
193 ValidationPolicyConfig::getRefreshPeriod(ConfigSection::const_iterator& it,
194  const ConfigSection::const_iterator& end)
195 {
196  auto refresh = time::nanoseconds::max();
197  if (it == end) {
198  return refresh;
199  }
200 
201  if (!boost::iequals(it->first, "refresh")) {
202  BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.refresh>"));
203  }
204 
205  std::string inputString = it->second.data();
206  ++it;
207  char unit = inputString[inputString.size() - 1];
208  std::string refreshString = inputString.substr(0, inputString.size() - 1);
209 
210  int32_t refreshPeriod = -1;
211  try {
212  refreshPeriod = boost::lexical_cast<int32_t>(refreshString);
213  }
214  catch (const boost::bad_lexical_cast&) {
215  // pass
216  }
217  if (refreshPeriod < 0) {
218  BOOST_THROW_EXCEPTION(Error("Bad refresh value: " + refreshString));
219  }
220 
221  if (refreshPeriod == 0) {
222  return getDefaultRefreshPeriod();
223  }
224 
225  switch (unit) {
226  case 'h':
227  return time::hours(refreshPeriod);
228  case 'm':
229  return time::minutes(refreshPeriod);
230  case 's':
231  return time::seconds(refreshPeriod);
232  default:
233  BOOST_THROW_EXCEPTION(Error("Bad refresh time unit: "s + unit));
234  }
235 }
236 
237 time::nanoseconds
238 ValidationPolicyConfig::getDefaultRefreshPeriod()
239 {
240  return 1_h;
241 }
242 
243 void
244 ValidationPolicyConfig::checkPolicy(const Data& data, const shared_ptr<ValidationState>& state,
245  const ValidationContinuation& continueValidation)
246 {
247  BOOST_ASSERT_MSG(!hasInnerPolicy(), "ValidationPolicyConfig must be a terminal inner policy");
248 
249  if (m_shouldBypass) {
250  return continueValidation(nullptr, state);
251  }
252 
253  Name klName = getKeyLocatorName(data, *state);
254  if (!state->getOutcome()) { // already failed
255  return;
256  }
257 
258  for (const auto& rule : m_dataRules) {
259  if (rule->match(tlv::Data, data.getName())) {
260  if (rule->check(tlv::Data, data.getName(), klName, state)) {
261  return continueValidation(make_shared<CertificateRequest>(klName), state);
262  }
263  // rule->check calls state->fail(...) if the check fails
264  return;
265  }
266  }
267 
268  return state->fail({ValidationError::POLICY_ERROR,
269  "No rule matched for data `" + data.getName().toUri() + "`"});
270 }
271 
272 void
273 ValidationPolicyConfig::checkPolicy(const Interest& interest, const shared_ptr<ValidationState>& state,
274  const ValidationContinuation& continueValidation)
275 {
276  BOOST_ASSERT_MSG(!hasInnerPolicy(), "ValidationPolicyConfig must be a terminal inner policy");
277 
278  if (m_shouldBypass) {
279  return continueValidation(nullptr, state);
280  }
281 
282  Name klName = getKeyLocatorName(interest, *state);
283  if (!state->getOutcome()) { // already failed
284  return;
285  }
286 
287  for (const auto& rule : m_interestRules) {
288  if (rule->match(tlv::Interest, interest.getName())) {
289  if (rule->check(tlv::Interest, interest.getName(), klName, state)) {
290  return continueValidation(make_shared<CertificateRequest>(klName), state);
291  }
292  // rule->check calls state->fail(...) if the check fails
293  return;
294  }
295  }
296 
297  return state->fail({ValidationError::POLICY_ERROR,
298  "No rule matched for interest `" + interest.getName().toUri() + "`"});
299 }
300 
301 } // namespace validator_config
302 } // namespace v2
303 } // namespace security
304 } // namespace ndn
Copyright (c) 2011-2015 Regents of the University of California.
std::string toUri() const
Get URI representation of the name.
Definition: name.cpp:116
const Name & getName() const
Get name.
Definition: data.hpp:124
static unique_ptr< Rule > create(const ConfigSection &configSection, const std::string &configFilename)
create a rule from configuration section
Definition: rule.cpp:99
Represents an Interest packet.
Definition: interest.hpp:44
std::function< void(const shared_ptr< CertificateRequest > &certRequest, const shared_ptr< ValidationState > &state)> ValidationContinuation
static Name getKeyLocatorName(const SignatureInfo &si, ValidationState &state)
Represents an absolute name.
Definition: name.hpp:43
boost::property_tree::ptree ConfigSection
Definition: common.hpp:36
bool hasInnerPolicy() const
Check if inner policy is set.
void checkPolicy(const Data &data, const shared_ptr< ValidationState > &state, const ValidationContinuation &continueValidation) override
Check data against the policy.
std::string to_string(const V &v)
Definition: backports.hpp:67
Represents a Data packet.
Definition: data.hpp:35
void load(const std::string &filename)
Load policy from file filename.
const Name & getName() const
Definition: interest.hpp:134