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 
23 #include "validator.hpp"
24 #include "../../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_isConfigured) {
79  m_shouldBypass = false;
80  m_dataRules.clear();
81  m_interestRules.clear();
82  m_validator->resetAnchors();
83  m_validator->resetVerifiedCertificates();
84  }
85  m_isConfigured = true;
86 
87  BOOST_ASSERT(!filename.empty());
88 
89  if (configSection.begin() == configSection.end()) {
90  BOOST_THROW_EXCEPTION(Error("Error processing configuration file " + filename + ": no data"));
91  }
92 
93  for (const auto& subSection : configSection) {
94  const std::string& sectionName = subSection.first;
95  const ConfigSection& section = subSection.second;
96 
97  if (boost::iequals(sectionName, "rule")) {
98  auto rule = Rule::create(section, filename);
99  if (rule->getPktType() == tlv::Data) {
100  m_dataRules.push_back(std::move(rule));
101  }
102  else if (rule->getPktType() == tlv::Interest) {
103  m_interestRules.push_back(std::move(rule));
104  }
105  }
106  else if (boost::iequals(sectionName, "trust-anchor")) {
107  processConfigTrustAnchor(section, filename);
108  }
109  else {
110  BOOST_THROW_EXCEPTION(Error("Error processing configuration file " + filename +
111  ": unrecognized section " + sectionName));
112  }
113  }
114 }
115 
116 void
117 ValidationPolicyConfig::processConfigTrustAnchor(const ConfigSection& configSection,
118  const std::string& filename)
119 {
120  using namespace boost::filesystem;
121 
122  auto propertyIt = configSection.begin();
123 
124  // Get trust-anchor.type
125  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
126  BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.type>"));
127  }
128 
129  std::string type = propertyIt->second.data();
130  propertyIt++;
131 
132  if (boost::iequals(type, "file")) {
133  // Get trust-anchor.file
134  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name")) {
135  BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.file-name>"));
136  }
137 
138  std::string file = propertyIt->second.data();
139  propertyIt++;
140 
141  time::nanoseconds refresh = getRefreshPeriod(propertyIt, configSection.end());
142  if (propertyIt != configSection.end())
143  BOOST_THROW_EXCEPTION(Error("Expecting end of <trust-anchor>"));
144 
145  m_validator->loadAnchor(filename, absolute(file, path(filename).parent_path()).string(),
146  refresh, false);
147  }
148  else if (boost::iequals(type, "base64")) {
149  // Get trust-anchor.base64-string
150  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "base64-string"))
151  BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.base64-string>"));
152 
153  std::stringstream ss(propertyIt->second.data());
154  propertyIt++;
155 
156  if (propertyIt != configSection.end())
157  BOOST_THROW_EXCEPTION(Error("Expecting end of <trust-anchor>"));
158 
159  auto idCert = io::load<Certificate>(ss);
160  if (idCert != nullptr) {
161  m_validator->loadAnchor("", std::move(*idCert));
162  }
163  else {
164  BOOST_THROW_EXCEPTION(Error("Cannot decode certificate from base64-string"));
165  }
166  }
167  else if (boost::iequals(type, "dir")) {
168  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "dir"))
169  BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.dir>"));
170 
171  std::string dirString(propertyIt->second.data());
172  propertyIt++;
173 
174  time::nanoseconds refresh = getRefreshPeriod(propertyIt, configSection.end());
175  if (propertyIt != configSection.end())
176  BOOST_THROW_EXCEPTION(Error("Expecting end of <trust-anchor>"));
177 
178  path dirPath = absolute(dirString, path(filename).parent_path());
179  m_validator->loadAnchor(dirString, dirPath.string(), refresh, true);
180  }
181  else if (boost::iequals(type, "any")) {
182  m_shouldBypass = true;
183  }
184  else {
185  BOOST_THROW_EXCEPTION(Error("Unrecognized <trust-anchor.type>: " + type));
186  }
187 }
188 
189 time::nanoseconds
190 ValidationPolicyConfig::getRefreshPeriod(ConfigSection::const_iterator& it,
191  const ConfigSection::const_iterator& end)
192 {
193  auto refresh = time::nanoseconds::max();
194  if (it == end) {
195  return refresh;
196  }
197 
198  if (!boost::iequals(it->first, "refresh")) {
199  BOOST_THROW_EXCEPTION(Error("Expecting <trust-anchor.refresh>"));
200  }
201 
202  std::string inputString = it->second.data();
203  ++it;
204  char unit = inputString[inputString.size() - 1];
205  std::string refreshString = inputString.substr(0, inputString.size() - 1);
206 
207  int32_t refreshPeriod = -1;
208  try {
209  refreshPeriod = boost::lexical_cast<int32_t>(refreshString);
210  }
211  catch (const boost::bad_lexical_cast&) {
212  // pass
213  }
214  if (refreshPeriod < 0) {
215  BOOST_THROW_EXCEPTION(Error("Bad refresh value: " + refreshString));
216  }
217 
218  if (refreshPeriod == 0) {
219  return getDefaultRefreshPeriod();
220  }
221 
222  switch (unit) {
223  case 'h':
224  return time::hours(refreshPeriod);
225  case 'm':
226  return time::minutes(refreshPeriod);
227  case 's':
228  return time::seconds(refreshPeriod);
229  default:
230  BOOST_THROW_EXCEPTION(Error(std::string("Bad refresh time unit: ") + unit));
231  }
232 }
233 
234 time::nanoseconds
235 ValidationPolicyConfig::getDefaultRefreshPeriod()
236 {
237  return 1_h;
238 }
239 
240 void
241 ValidationPolicyConfig::checkPolicy(const Data& data, const shared_ptr<ValidationState>& state,
242  const ValidationContinuation& continueValidation)
243 {
244  BOOST_ASSERT_MSG(!hasInnerPolicy(), "ValidationPolicyConfig must be a terminal inner policy");
245 
246  if (m_shouldBypass) {
247  return continueValidation(nullptr, state);
248  }
249 
250  Name klName = getKeyLocatorName(data, *state);
251  if (!state->getOutcome()) { // already failed
252  return;
253  }
254 
255  for (const auto& rule : m_dataRules) {
256  if (rule->match(tlv::Data, data.getName())) {
257  if (rule->check(tlv::Data, data.getName(), klName, state)) {
258  return continueValidation(make_shared<CertificateRequest>(Interest(klName)), state);
259  }
260  // rule->check calls state->fail(...) if the check fails
261  return;
262  }
263  }
264 
265  return state->fail({ValidationError::POLICY_ERROR,
266  "No rule matched for data `" + data.getName().toUri() + "`"});
267 }
268 
269 void
270 ValidationPolicyConfig::checkPolicy(const Interest& interest, const shared_ptr<ValidationState>& state,
271  const ValidationContinuation& continueValidation)
272 {
273  BOOST_ASSERT_MSG(!hasInnerPolicy(), "ValidationPolicyConfig must be a terminal inner policy");
274 
275  if (m_shouldBypass) {
276  return continueValidation(nullptr, state);
277  }
278 
279  Name klName = getKeyLocatorName(interest, *state);
280  if (!state->getOutcome()) { // already failed
281  return;
282  }
283 
284  for (const auto& rule : m_interestRules) {
285  if (rule->match(tlv::Interest, interest.getName())) {
286  if (rule->check(tlv::Interest, interest.getName(), klName, state)) {
287  return continueValidation(make_shared<CertificateRequest>(Interest(klName)), state);
288  }
289  // rule->check calls state->fail(...) if the check fails
290  return;
291  }
292  }
293 
294  return state->fail({ValidationError::POLICY_ERROR,
295  "No rule matched for interest `" + interest.getName().toUri() + "`"});
296 }
297 
298 } // namespace validator_config
299 } // namespace v2
300 } // namespace security
301 } // 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:117
const Name & getName() const
Get name.
Definition: data.hpp:128
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:42
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:42
boost::property_tree::ptree ConfigSection
Definition: common.hpp:35
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:107
Represents a Data packet.
Definition: data.hpp:35
const Name & getName() const
Definition: interest.hpp:137