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-2019 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 
38 void
39 ValidationPolicyConfig::load(const std::string& filename)
40 {
41  std::ifstream inputFile(filename);
42  if (!inputFile) {
43  NDN_THROW(Error("Failed to read configuration file: " + filename));
44  }
45  load(inputFile, filename);
46 }
47 
48 void
49 ValidationPolicyConfig::load(const std::string& input, const std::string& filename)
50 {
51  std::istringstream inputStream(input);
52  load(inputStream, filename);
53 }
54 
55 void
56 ValidationPolicyConfig::load(std::istream& input, const std::string& filename)
57 {
58  ConfigSection tree;
59  try {
60  boost::property_tree::read_info(input, tree);
61  }
62  catch (const boost::property_tree::info_parser_error& e) {
63  NDN_THROW(Error("Failed to parse configuration file " + filename +
64  " line " + to_string(e.line()) + ": " + e.message()));
65  }
66  load(tree, filename);
67 }
68 
69 void
70 ValidationPolicyConfig::load(const ConfigSection& configSection, const std::string& filename)
71 {
72  BOOST_ASSERT(!filename.empty());
73 
74  if (m_validator == nullptr) {
75  NDN_THROW(Error("Validator instance not assigned on the policy"));
76  }
77  if (m_isConfigured) {
78  m_shouldBypass = false;
79  m_dataRules.clear();
80  m_interestRules.clear();
81  m_validator->resetAnchors();
82  m_validator->resetVerifiedCertificates();
83  }
84  m_isConfigured = true;
85 
86  for (const auto& subSection : configSection) {
87  const std::string& sectionName = subSection.first;
88  const ConfigSection& section = subSection.second;
89 
90  if (boost::iequals(sectionName, "rule")) {
91  auto rule = Rule::create(section, filename);
92  if (rule->getPktType() == tlv::Data) {
93  m_dataRules.push_back(std::move(rule));
94  }
95  else if (rule->getPktType() == tlv::Interest) {
96  m_interestRules.push_back(std::move(rule));
97  }
98  }
99  else if (boost::iequals(sectionName, "trust-anchor")) {
100  processConfigTrustAnchor(section, filename);
101  }
102  else {
103  NDN_THROW(Error("Error processing configuration file " + filename +
104  ": unrecognized section " + sectionName));
105  }
106  }
107 }
108 
109 void
110 ValidationPolicyConfig::processConfigTrustAnchor(const ConfigSection& configSection,
111  const std::string& filename)
112 {
113  using namespace boost::filesystem;
114 
115  auto propertyIt = configSection.begin();
116 
117  // Get trust-anchor.type
118  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
119  NDN_THROW(Error("Expecting <trust-anchor.type>"));
120  }
121 
122  std::string type = propertyIt->second.data();
123  propertyIt++;
124 
125  if (boost::iequals(type, "file")) {
126  // Get trust-anchor.file
127  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name")) {
128  NDN_THROW(Error("Expecting <trust-anchor.file-name>"));
129  }
130 
131  std::string file = propertyIt->second.data();
132  propertyIt++;
133 
134  time::nanoseconds refresh = getRefreshPeriod(propertyIt, configSection.end());
135  if (propertyIt != configSection.end())
136  NDN_THROW(Error("Expecting end of <trust-anchor>"));
137 
138  m_validator->loadAnchor(filename, absolute(file, path(filename).parent_path()).string(),
139  refresh, false);
140  }
141  else if (boost::iequals(type, "base64")) {
142  // Get trust-anchor.base64-string
143  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "base64-string"))
144  NDN_THROW(Error("Expecting <trust-anchor.base64-string>"));
145 
146  std::stringstream ss(propertyIt->second.data());
147  propertyIt++;
148 
149  if (propertyIt != configSection.end())
150  NDN_THROW(Error("Expecting end of <trust-anchor>"));
151 
152  auto idCert = io::load<Certificate>(ss);
153  if (idCert != nullptr) {
154  m_validator->loadAnchor("", std::move(*idCert));
155  }
156  else {
157  NDN_THROW(Error("Cannot decode certificate from base64-string"));
158  }
159  }
160  else if (boost::iequals(type, "dir")) {
161  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "dir"))
162  NDN_THROW(Error("Expecting <trust-anchor.dir>"));
163 
164  std::string dirString(propertyIt->second.data());
165  propertyIt++;
166 
167  time::nanoseconds refresh = getRefreshPeriod(propertyIt, configSection.end());
168  if (propertyIt != configSection.end())
169  NDN_THROW(Error("Expecting end of <trust-anchor>"));
170 
171  path dirPath = absolute(dirString, path(filename).parent_path());
172  m_validator->loadAnchor(dirString, dirPath.string(), refresh, true);
173  }
174  else if (boost::iequals(type, "any")) {
175  m_shouldBypass = true;
176  }
177  else {
178  NDN_THROW(Error("Unrecognized <trust-anchor.type>: " + type));
179  }
180 }
181 
182 time::nanoseconds
183 ValidationPolicyConfig::getRefreshPeriod(ConfigSection::const_iterator& it,
184  const ConfigSection::const_iterator& end)
185 {
186  auto refresh = time::nanoseconds::max();
187  if (it == end) {
188  return refresh;
189  }
190 
191  if (!boost::iequals(it->first, "refresh")) {
192  NDN_THROW(Error("Expecting <trust-anchor.refresh>"));
193  }
194 
195  std::string inputString = it->second.data();
196  ++it;
197  char unit = inputString[inputString.size() - 1];
198  std::string refreshString = inputString.substr(0, inputString.size() - 1);
199 
200  int32_t refreshPeriod = -1;
201  try {
202  refreshPeriod = boost::lexical_cast<int32_t>(refreshString);
203  }
204  catch (const boost::bad_lexical_cast&) {
205  // pass
206  }
207  if (refreshPeriod < 0) {
208  NDN_THROW(Error("Bad refresh value: " + refreshString));
209  }
210 
211  if (refreshPeriod == 0) {
212  return getDefaultRefreshPeriod();
213  }
214 
215  switch (unit) {
216  case 'h':
217  return time::hours(refreshPeriod);
218  case 'm':
219  return time::minutes(refreshPeriod);
220  case 's':
221  return time::seconds(refreshPeriod);
222  default:
223  NDN_THROW(Error("Bad refresh time unit: "s + unit));
224  }
225 }
226 
227 time::nanoseconds
228 ValidationPolicyConfig::getDefaultRefreshPeriod()
229 {
230  return 1_h;
231 }
232 
233 void
234 ValidationPolicyConfig::checkPolicy(const Data& data, const shared_ptr<ValidationState>& state,
235  const ValidationContinuation& continueValidation)
236 {
237  BOOST_ASSERT_MSG(!hasInnerPolicy(), "ValidationPolicyConfig must be a terminal inner policy");
238 
239  if (m_shouldBypass) {
240  return continueValidation(nullptr, state);
241  }
242 
243  Name klName = getKeyLocatorName(data, *state);
244  if (!state->getOutcome()) { // already failed
245  return;
246  }
247 
248  for (const auto& rule : m_dataRules) {
249  if (rule->match(tlv::Data, data.getName())) {
250  if (rule->check(tlv::Data, data.getName(), klName, state)) {
251  return continueValidation(make_shared<CertificateRequest>(klName), state);
252  }
253  // rule->check calls state->fail(...) if the check fails
254  return;
255  }
256  }
257 
258  return state->fail({ValidationError::POLICY_ERROR,
259  "No rule matched for data `" + data.getName().toUri() + "`"});
260 }
261 
262 void
263 ValidationPolicyConfig::checkPolicy(const Interest& interest, const shared_ptr<ValidationState>& state,
264  const ValidationContinuation& continueValidation)
265 {
266  BOOST_ASSERT_MSG(!hasInnerPolicy(), "ValidationPolicyConfig must be a terminal inner policy");
267 
268  if (m_shouldBypass) {
269  return continueValidation(nullptr, state);
270  }
271 
272  Name klName = getKeyLocatorName(interest, *state);
273  if (!state->getOutcome()) { // already failed
274  return;
275  }
276 
277  for (const auto& rule : m_interestRules) {
278  if (rule->match(tlv::Interest, interest.getName())) {
279  if (rule->check(tlv::Interest, interest.getName(), klName, state)) {
280  return continueValidation(make_shared<CertificateRequest>(klName), state);
281  }
282  // rule->check calls state->fail(...) if the check fails
283  return;
284  }
285  }
286 
287  return state->fail({ValidationError::POLICY_ERROR,
288  "No rule matched for interest `" + interest.getName().toUri() + "`"});
289 }
290 
291 } // namespace validator_config
292 } // namespace v2
293 } // namespace security
294 } // namespace ndn
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:421
ndn::tlv::Interest
@ Interest
Definition: tlv.hpp:65
validator.hpp
ndn::security::v2::ValidationError::POLICY_ERROR
@ POLICY_ERROR
Definition: validation-error.hpp:51
ndn::security::v2::validator_config::ValidationPolicyConfig::checkPolicy
void checkPolicy(const Data &data, const shared_ptr< ValidationState > &state, const ValidationContinuation &continueValidation) override
Check data against the policy.
Definition: validation-policy-config.cpp:234
ndn::security::v2::ValidationPolicy::hasInnerPolicy
bool hasInnerPolicy() const
Check if inner policy is set.
Definition: validation-policy.hpp:67
ndn::Data::getName
const Name & getName() const
Get name.
Definition: data.hpp:124
ndn::security::v2::ValidationPolicy::ValidationContinuation
std::function< void(const shared_ptr< CertificateRequest > &certRequest, const shared_ptr< ValidationState > &state)> ValidationContinuation
Definition: validation-policy.hpp:41
ndn::Name
Represents an absolute name.
Definition: name.hpp:44
io.hpp
ndn::security::v2::validator_config::ValidationPolicyConfig::load
void load(const std::string &filename)
Load policy from file filename.
Definition: validation-policy-config.cpp:39
NDN_THROW
#define NDN_THROW(e)
Definition: exception.hpp:61
ndn::security::v2::validator_config::Rule::create
static unique_ptr< Rule > create(const ConfigSection &configSection, const std::string &configFilename)
create a rule from configuration section
Definition: rule.cpp:99
ndn::Interest
Represents an Interest packet.
Definition: interest.hpp:44
ndn::Data
Represents a Data packet.
Definition: data.hpp:36
ndn::tlv::Data
@ Data
Definition: tlv.hpp:66
ndn::to_string
std::string to_string(const T &val)
Definition: backports.hpp:102
ndn::Interest::getName
const Name & getName() const noexcept
Definition: interest.hpp:121
validation-policy-config.hpp
ndn::security::v2::getKeyLocatorName
static Name getKeyLocatorName(const SignatureInfo &si, ValidationState &state)
Definition: validation-policy.cpp:64
ndn::security::v2::validator_config::Error
Definition: common.hpp:39
ndn::security::v2::validator_config::ConfigSection
boost::property_tree::ptree ConfigSection
Definition: common.hpp:36
ndn
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-strategy-choice-helper.hpp:34