validator-config.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
22 #include "validator-config.hpp"
24 #include "../util/io.hpp"
25 #include "../lp/tags.hpp"
26 
27 #include <boost/filesystem.hpp>
28 #include <boost/property_tree/info_parser.hpp>
29 #include <boost/algorithm/string.hpp>
30 
31 namespace ndn {
32 namespace security {
33 
34 const shared_ptr<CertificateCache> ValidatorConfig::DEFAULT_CERTIFICATE_CACHE;
35 const time::milliseconds ValidatorConfig::DEFAULT_GRACE_INTERVAL(3000);
37 
39  const shared_ptr<CertificateCache>& certificateCache,
40  const time::milliseconds& graceInterval,
41  const size_t stepLimit,
42  const size_t maxTrackedKeys,
43  const time::system_clock::Duration& keyTimestampTtl)
44  : Validator(face)
45  , m_shouldValidate(true)
46  , m_stepLimit(stepLimit)
47  , m_certificateCache(certificateCache)
48  , m_graceInterval(graceInterval < time::milliseconds::zero() ?
49  DEFAULT_GRACE_INTERVAL : graceInterval)
50  , m_maxTrackedKeys(maxTrackedKeys)
51  , m_keyTimestampTtl(keyTimestampTtl)
52 {
53  if (m_certificateCache == nullptr && face != nullptr)
54  m_certificateCache = make_shared<CertificateCacheTtl>(ref(face->getIoService()));
55 }
56 
58  const shared_ptr<CertificateCache>& certificateCache,
59  const time::milliseconds& graceInterval,
60  const size_t stepLimit,
61  const size_t maxTrackedKeys,
62  const time::system_clock::Duration& keyTimestampTtl)
63  : Validator(face)
64  , m_shouldValidate(true)
65  , m_stepLimit(stepLimit)
66  , m_certificateCache(certificateCache)
67  , m_graceInterval(graceInterval < time::milliseconds::zero() ?
68  DEFAULT_GRACE_INTERVAL : graceInterval)
69  , m_maxTrackedKeys(maxTrackedKeys)
70  , m_keyTimestampTtl(keyTimestampTtl)
71 {
72  if (m_certificateCache == nullptr)
73  m_certificateCache = make_shared<CertificateCacheTtl>(ref(face.getIoService()));
74 }
75 
76 void
77 ValidatorConfig::load(const std::string& filename)
78 {
79  std::ifstream inputFile;
80  inputFile.open(filename.c_str());
81  if (!inputFile.good() || !inputFile.is_open()) {
82  std::string msg = "Failed to read configuration file: ";
83  msg += filename;
84  BOOST_THROW_EXCEPTION(security::conf::Error(msg));
85  }
86  load(inputFile, filename);
87  inputFile.close();
88 }
89 
90 void
91 ValidatorConfig::load(const std::string& input, const std::string& filename)
92 {
93  std::istringstream inputStream(input);
94  load(inputStream, filename);
95 }
96 
97 
98 void
99 ValidatorConfig::load(std::istream& input, const std::string& filename)
100 {
102  try {
103  boost::property_tree::read_info(input, tree);
104  }
105  catch (const boost::property_tree::info_parser_error& error) {
106  std::stringstream msg;
107  msg << "Failed to parse configuration file";
108  msg << " " << filename;
109  msg << " " << error.message() << " line " << error.line();
110  BOOST_THROW_EXCEPTION(security::conf::Error(msg.str()));
111  }
112 
113  load(tree, filename);
114 }
115 
116 void
118  const std::string& filename)
119 {
120  BOOST_ASSERT(!filename.empty());
121 
122  reset();
123 
124  if (configSection.begin() == configSection.end()) {
125  std::string msg = "Error processing configuration file";
126  msg += ": ";
127  msg += filename;
128  msg += " no data";
129  BOOST_THROW_EXCEPTION(security::conf::Error(msg));
130  }
131 
132  for (security::conf::ConfigSection::const_iterator i = configSection.begin();
133  i != configSection.end(); ++i) {
134  const std::string& sectionName = i->first;
135  const security::conf::ConfigSection& section = i->second;
136 
137  if (boost::iequals(sectionName, "rule")) {
138  onConfigRule(section, filename);
139  }
140  else if (boost::iequals(sectionName, "trust-anchor")) {
141  onConfigTrustAnchor(section, filename);
142  }
143  else {
144  std::string msg = "Error processing configuration file";
145  msg += " ";
146  msg += filename;
147  msg += " unrecognized section: " + sectionName;
148  BOOST_THROW_EXCEPTION(security::conf::Error(msg));
149  }
150  }
151 }
152 
153 void
154 ValidatorConfig::onConfigRule(const security::conf::ConfigSection& configSection,
155  const std::string& filename)
156 {
157  using namespace ndn::security::conf;
158 
159  ConfigSection::const_iterator propertyIt = configSection.begin();
160 
161  // Get rule.id
162  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "id"))
163  BOOST_THROW_EXCEPTION(Error("Expect <rule.id>!"));
164 
165  std::string ruleId = propertyIt->second.data();
166  propertyIt++;
167 
168  // Get rule.for
169  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,"for"))
170  BOOST_THROW_EXCEPTION(Error("Expect <rule.for> in rule: " + ruleId + "!"));
171 
172  std::string usage = propertyIt->second.data();
173  propertyIt++;
174 
175  bool isForData = false;
176  if (boost::iequals(usage, "data"))
177  isForData = true;
178  else if (boost::iequals(usage, "interest"))
179  isForData = false;
180  else
181  BOOST_THROW_EXCEPTION(Error("Unrecognized <rule.for>: " + usage
182  + " in rule: " + ruleId));
183 
184  // Get rule.filter(s)
185  std::vector<shared_ptr<Filter>> filters;
186  for (; propertyIt != configSection.end(); propertyIt++) {
187  if (!boost::iequals(propertyIt->first, "filter")) {
188  if (boost::iequals(propertyIt->first, "checker"))
189  break;
190  BOOST_THROW_EXCEPTION(Error("Expect <rule.filter> in rule: " + ruleId));
191  }
192 
193  filters.push_back(FilterFactory::create(propertyIt->second));
194  continue;
195  }
196 
197  // Get rule.checker(s)
198  std::vector<shared_ptr<Checker>> checkers;
199  for (; propertyIt != configSection.end(); propertyIt++) {
200  if (!boost::iequals(propertyIt->first, "checker"))
201  BOOST_THROW_EXCEPTION(Error("Expect <rule.checker> in rule: " + ruleId));
202 
203  checkers.push_back(CheckerFactory::create(propertyIt->second, filename));
204  continue;
205  }
206 
207  // Check other stuff
208  if (propertyIt != configSection.end())
209  BOOST_THROW_EXCEPTION(Error("Expect the end of rule: " + ruleId));
210 
211  if (checkers.empty())
212  BOOST_THROW_EXCEPTION(Error("No <rule.checker> is specified in rule: " + ruleId));
213 
214  if (isForData) {
215  shared_ptr<DataRule> rule = make_shared<DataRule>(ruleId);
216  for (const auto& filter : filters)
217  rule->addFilter(filter);
218  for (const auto& checker : checkers)
219  rule->addChecker(checker);
220 
221  m_dataRules.push_back(rule);
222  }
223  else {
224  shared_ptr<InterestRule> rule = make_shared<InterestRule>(ruleId);;
225  for (const auto& filter : filters)
226  rule->addFilter(filter);
227  for (const auto& checker : checkers)
228  rule->addChecker(checker);
229 
230  m_interestRules.push_back(rule);
231  }
232 }
233 
234 void
235 ValidatorConfig::onConfigTrustAnchor(const security::conf::ConfigSection& configSection,
236  const std::string& filename)
237 {
238  using namespace ndn::security::conf;
239  using namespace boost::filesystem;
240 
241  ConfigSection::const_iterator propertyIt = configSection.begin();
242 
243  // Get trust-anchor.type
244  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
245  BOOST_THROW_EXCEPTION(Error("Expect <trust-anchor.type>!"));
246 
247  std::string type = propertyIt->second.data();
248  propertyIt++;
249 
250  if (boost::iequals(type, "file")) {
251  // Get trust-anchor.file
252  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name"))
253  BOOST_THROW_EXCEPTION(Error("Expect <trust-anchor.file-name>!"));
254 
255  std::string file = propertyIt->second.data();
256  propertyIt++;
257 
258  // Check other stuff
259  if (propertyIt != configSection.end())
260  BOOST_THROW_EXCEPTION(Error("Expect the end of trust-anchor!"));
261 
262  path certfilePath = absolute(file, path(filename).parent_path());
263  auto idCert = io::load<v1::IdentityCertificate>(certfilePath.string());
264 
265  if (idCert != nullptr) {
266  BOOST_ASSERT(idCert->getName().size() >= 1);
267  m_staticContainer.add(idCert);
268  m_anchors[idCert->getName().getPrefix(-1)] = idCert;
269  }
270  else
271  BOOST_THROW_EXCEPTION(Error("Cannot read certificate from file: " + certfilePath.native()));
272 
273  return;
274  }
275  else if (boost::iequals(type, "base64")) {
276  // Get trust-anchor.base64-string
277  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "base64-string"))
278  BOOST_THROW_EXCEPTION(Error("Expect <trust-anchor.base64-string>!"));
279 
280  std::stringstream ss(propertyIt->second.data());
281  propertyIt++;
282 
283  // Check other stuff
284  if (propertyIt != configSection.end())
285  BOOST_THROW_EXCEPTION(Error("Expect the end of trust-anchor!"));
286 
287  auto idCert = io::load<v1::IdentityCertificate>(ss);
288 
289  if (idCert != nullptr) {
290  BOOST_ASSERT(idCert->getName().size() >= 1);
291  m_staticContainer.add(idCert);
292  m_anchors[idCert->getName().getPrefix(-1)] = idCert;
293  }
294  else
295  BOOST_THROW_EXCEPTION(Error("Cannot decode certificate from base64-string"));
296 
297  return;
298  }
299  else if (boost::iequals(type, "dir")) {
300  if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "dir"))
301  BOOST_THROW_EXCEPTION(Error("Expect <trust-anchor.dir>"));
302 
303  std::string dirString(propertyIt->second.data());
304  propertyIt++;
305 
306  if (propertyIt != configSection.end()) {
307  if (boost::iequals(propertyIt->first, "refresh")) {
308  using namespace boost::filesystem;
309 
310  time::nanoseconds refresh = getRefreshPeriod(propertyIt->second.data());
311  propertyIt++;
312 
313  if (propertyIt != configSection.end())
314  BOOST_THROW_EXCEPTION(Error("Expect the end of trust-anchor"));
315 
316  path dirPath = absolute(dirString, path(filename).parent_path());
317 
318  m_dynamicContainers.push_back(DynamicTrustAnchorContainer(dirPath, true, refresh));
319 
320  m_dynamicContainers.rbegin()->setLastRefresh(time::system_clock::now() - refresh);
321 
322  return;
323  }
324  else
325  BOOST_THROW_EXCEPTION(Error("Expect <trust-anchor.refresh>!"));
326  }
327  else {
328  using namespace boost::filesystem;
329 
330  path dirPath = absolute(dirString, path(filename).parent_path());
331 
332  directory_iterator end;
333 
334  for (directory_iterator it(dirPath); it != end; it++) {
335  auto idCert = io::load<v1::IdentityCertificate>(it->path().string());
336 
337  if (idCert != nullptr)
338  m_staticContainer.add(idCert);
339  }
340 
341  return;
342  }
343  }
344  else if (boost::iequals(type, "any")) {
345  m_shouldValidate = false;
346  }
347  else
348  BOOST_THROW_EXCEPTION(Error("Unsupported trust-anchor.type: " + type));
349 }
350 
351 void
353 {
354  if (m_certificateCache != nullptr)
355  m_certificateCache->reset();
356  m_interestRules.clear();
357  m_dataRules.clear();
358 
359  m_anchors.clear();
360 
361  m_staticContainer = TrustAnchorContainer();
362 
363  m_dynamicContainers.clear();
364 }
365 
366 bool
368 {
369  return ((m_certificateCache == nullptr || m_certificateCache->isEmpty()) &&
370  m_interestRules.empty() && m_dataRules.empty() && m_anchors.empty());
371 }
372 
373 time::nanoseconds
374 ValidatorConfig::getRefreshPeriod(std::string inputString)
375 {
376  char unit = inputString[inputString.size() - 1];
377  std::string refreshString = inputString.substr(0, inputString.size() - 1);
378 
379  uint32_t refreshPeriod = 0;
380 
381  try {
382  refreshPeriod = boost::lexical_cast<uint32_t>(refreshString);
383  }
384  catch (const boost::bad_lexical_cast&) {
385  BOOST_THROW_EXCEPTION(Error("Bad number: " + refreshString));
386  }
387 
388  if (refreshPeriod == 0)
389  return getDefaultRefreshPeriod();
390 
391  switch (unit) {
392  case 'h':
393  return time::duration_cast<time::nanoseconds>(time::hours(refreshPeriod));
394  case 'm':
395  return time::duration_cast<time::nanoseconds>(time::minutes(refreshPeriod));
396  case 's':
397  return time::duration_cast<time::nanoseconds>(time::seconds(refreshPeriod));
398  default:
399  BOOST_THROW_EXCEPTION(Error(std::string("Wrong time unit: ") + unit));
400  }
401 }
402 
403 time::nanoseconds
404 ValidatorConfig::getDefaultRefreshPeriod()
405 {
406  return time::duration_cast<time::nanoseconds>(time::seconds(3600));
407 }
408 
409 void
410 ValidatorConfig::refreshAnchors()
411 {
413 
414  bool isRefreshed = false;
415 
416  for (auto cIt = m_dynamicContainers.begin();
417  cIt != m_dynamicContainers.end() && cIt->getLastRefresh() + cIt->getRefreshPeriod() < now;
418  cIt++) {
419  isRefreshed = true;
420  cIt->refresh();
421  cIt->setLastRefresh(now);
422  }
423 
424  if (isRefreshed) {
425  m_anchors.clear();
426 
427  for (const auto& cert : m_staticContainer.getAll()) {
428  m_anchors[cert->getName().getPrefix(-1)] = cert;
429  }
430 
431  for (const auto& container : m_dynamicContainers) {
432  const CertificateList& certList = container.getAll();
433 
434  for (const auto& cert :certList) {
435  m_anchors[cert->getName().getPrefix(-1)] = cert;
436  }
437  }
438  m_dynamicContainers.sort(ValidatorConfig::compareDynamicContainer);
439  }
440 }
441 
442 void
444  int nSteps,
445  const OnDataValidated& onValidated,
446  const OnDataValidationFailed& onValidationFailed,
447  std::vector<shared_ptr<ValidationRequest>>& nextSteps)
448 {
449  if (!m_shouldValidate)
450  return onValidated(data.shared_from_this());
451 
452  bool isMatched = false;
453  int8_t checkResult = -1;
454 
455  for (const auto& dataRule : m_dataRules) {
456  if (dataRule->match(data)) {
457  isMatched = true;
458  checkResult = dataRule->check(data, onValidated, onValidationFailed);
459  break;
460  }
461  }
462 
463  if (!isMatched)
464  return onValidationFailed(data.shared_from_this(), "No rule matched!");
465 
466  if (checkResult == 0) {
467  const Signature& signature = data.getSignature();
468  checkSignature(data, signature, nSteps,
469  onValidated, onValidationFailed, nextSteps);
470  }
471 }
472 
473 void
475  int nSteps,
476  const OnInterestValidated& onValidated,
477  const OnInterestValidationFailed& onValidationFailed,
478  std::vector<shared_ptr<ValidationRequest>>& nextSteps)
479 {
480  if (!m_shouldValidate)
481  return onValidated(interest.shared_from_this());
482 
483  // If interestName has less than 4 name components,
484  // it is definitely not a signed interest.
485  if (interest.getName().size() < command_interest::MIN_SIZE)
486  return onValidationFailed(interest.shared_from_this(),
487  "Interest is not signed: " + interest.getName().toUri());
488 
489  try {
490  const Name& interestName = interest.getName();
491  Signature signature(interestName[command_interest::POS_SIG_INFO].blockFromValue(),
492  interestName[command_interest::POS_SIG_VALUE].blockFromValue());
493 
494  if (!signature.hasKeyLocator())
495  return onValidationFailed(interest.shared_from_this(), "No valid KeyLocator");
496 
497  const KeyLocator& keyLocator = signature.getKeyLocator();
498 
499  if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
500  return onValidationFailed(interest.shared_from_this(), "Key Locator is not a name");
501 
503 
504  bool isMatched = false;
505  int8_t checkResult = -1;
506 
507  for (const auto& interestRule : m_interestRules) {
508  if (interestRule->match(interest)) {
509  isMatched = true;
510  checkResult = interestRule->check(interest,
511  bind(&ValidatorConfig::checkTimestamp, this, _1,
512  keyName, onValidated, onValidationFailed),
513  onValidationFailed);
514  break;
515  }
516  }
517 
518  if (!isMatched)
519  return onValidationFailed(interest.shared_from_this(), "No rule matched!");
520 
521  if (checkResult == 0) {
522  checkSignature<Interest, OnInterestValidated, OnInterestValidationFailed>
523  (interest, signature, nSteps,
524  bind(&ValidatorConfig::checkTimestamp, this, _1,
525  keyName, onValidated, onValidationFailed),
526  onValidationFailed,
527  nextSteps);
528  }
529  }
530  catch (const Signature::Error& e) {
531  return onValidationFailed(interest.shared_from_this(), "No valid signature");
532  }
533  catch (const KeyLocator::Error& e){
534  return onValidationFailed(interest.shared_from_this(), "No valid KeyLocator");
535  }
536  catch (const v1::IdentityCertificate::Error& e){
537  return onValidationFailed(interest.shared_from_this(), "Cannot determine the signing key");
538  }
539  catch (const tlv::Error& e){
540  return onValidationFailed(interest.shared_from_this(), "Cannot decode signature");
541  }
542 }
543 
544 void
545 ValidatorConfig::checkTimestamp(const shared_ptr<const Interest>& interest,
546  const Name& keyName,
547  const OnInterestValidated& onValidated,
548  const OnInterestValidationFailed& onValidationFailed)
549 {
550  const Name& interestName = interest->getName();
551  time::system_clock::TimePoint interestTime;
552 
553  try {
554  interestTime =
555  time::fromUnixTimestamp(time::milliseconds(interestName.at(command_interest::POS_TIMESTAMP).toNumber()));
556  }
557  catch (const tlv::Error& e) {
558  return onValidationFailed(interest,
559  "Cannot decode signature related TLVs");
560  }
561 
563 
564  LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
565  if (timestampIt == m_lastTimestamp.end()) {
566  if (!(currentTime - m_graceInterval <= interestTime &&
567  interestTime <= currentTime + m_graceInterval))
568  return onValidationFailed(interest,
569  "The command is not in grace interval: " + interest->getName().toUri());
570  }
571  else {
572  if (interestTime <= timestampIt->second)
573  return onValidationFailed(interest,
574  "The command is outdated: " + interest->getName().toUri());
575  }
576 
577  // Update timestamp
578  if (timestampIt == m_lastTimestamp.end()) {
579  cleanOldKeys();
580  m_lastTimestamp[keyName] = interestTime;
581  }
582  else {
583  timestampIt->second = interestTime;
584  }
585 
586  return onValidated(interest);
587 }
588 
589 void
590 ValidatorConfig::cleanOldKeys()
591 {
592  if (m_lastTimestamp.size() < m_maxTrackedKeys)
593  return;
594 
595  LastTimestampMap::iterator timestampIt = m_lastTimestamp.begin();
596  LastTimestampMap::iterator end = m_lastTimestamp.end();
597 
599  LastTimestampMap::iterator oldestKeyIt = m_lastTimestamp.begin();
600  time::system_clock::TimePoint oldestTimestamp = oldestKeyIt->second;
601 
602  while (timestampIt != end) {
603  if (now - timestampIt->second > m_keyTimestampTtl) {
604  LastTimestampMap::iterator toDelete = timestampIt;
605  timestampIt++;
606  m_lastTimestamp.erase(toDelete);
607  continue;
608  }
609 
610  if (timestampIt->second < oldestTimestamp) {
611  oldestTimestamp = timestampIt->second;
612  oldestKeyIt = timestampIt;
613  }
614 
615  timestampIt++;
616  }
617 
618  if (m_lastTimestamp.size() >= m_maxTrackedKeys)
619  m_lastTimestamp.erase(oldestKeyIt);
620 }
621 
622 void
623 ValidatorConfig::DynamicTrustAnchorContainer::refresh()
624 {
625  using namespace boost::filesystem;
626 
627  m_certificates.clear();
628 
629  if (m_isDir) {
630  directory_iterator end;
631 
632  for (directory_iterator it(m_path); it != end; it++) {
633  auto idCert = io::load<v1::IdentityCertificate>(it->path().string());
634 
635  if (idCert != nullptr)
636  m_certificates.push_back(idCert);
637  }
638  }
639  else {
640  auto idCert = io::load<v1::IdentityCertificate>(m_path.string());
641 
642  if (idCert != nullptr)
643  m_certificates.push_back(idCert);
644  }
645 }
646 
647 template<class Packet, class OnValidated, class OnFailed>
648 void
649 ValidatorConfig::checkSignature(const Packet& packet,
650  const Signature& signature,
651  size_t nSteps,
652  const OnValidated& onValidated,
653  const OnFailed& onValidationFailed,
654  std::vector<shared_ptr<ValidationRequest>>& nextSteps)
655 {
656  if (signature.getType() == tlv::DigestSha256) {
657  DigestSha256 sigSha256(signature);
658 
659  if (verifySignature(packet, sigSha256))
660  return onValidated(packet.shared_from_this());
661  else
662  return onValidationFailed(packet.shared_from_this(), "Sha256 Signature cannot be verified!");
663  }
664 
665  try {
666  switch (signature.getType()) {
669  if (!signature.hasKeyLocator()) {
670  return onValidationFailed(packet.shared_from_this(),
671  "Missing KeyLocator in SignatureInfo");
672  }
673  break;
674  }
675  default:
676  return onValidationFailed(packet.shared_from_this(), "Unsupported signature type");
677  }
678  }
679  catch (const KeyLocator::Error& e) {
680  return onValidationFailed(packet.shared_from_this(),
681  "Cannot decode KeyLocator in public key signature");
682  }
683  catch (const tlv::Error& e) {
684  return onValidationFailed(packet.shared_from_this(), "Cannot decode public key signature");
685  }
686 
687  if (signature.getKeyLocator().getType() != KeyLocator::KeyLocator_Name) {
688  return onValidationFailed(packet.shared_from_this(), "Unsupported KeyLocator type");
689  }
690 
691  const Name& keyLocatorName = signature.getKeyLocator().getName();
692 
693  shared_ptr<const v1::Certificate> trustedCert;
694 
695  refreshAnchors();
696 
697  AnchorList::const_iterator it = m_anchors.find(keyLocatorName);
698  if (m_anchors.end() == it && m_certificateCache != nullptr)
699  trustedCert = m_certificateCache->getCertificate(keyLocatorName);
700  else if (m_anchors.end() != it)
701  trustedCert = it->second;
702 
703  if (trustedCert != nullptr) {
704  if (verifySignature(packet, signature, trustedCert->getPublicKeyInfo()))
705  return onValidated(packet.shared_from_this());
706  else
707  return onValidationFailed(packet.shared_from_this(), "Cannot verify signature");
708  }
709  else {
710  if (m_stepLimit == nSteps)
711  return onValidationFailed(packet.shared_from_this(), "Maximum steps of validation reached");
712 
713  OnDataValidated onCertValidated =
714  bind(&ValidatorConfig::onCertValidated<Packet, OnValidated, OnFailed>,
715  this, _1, packet.shared_from_this(), onValidated, onValidationFailed);
716 
717  OnDataValidationFailed onCertValidationFailed =
718  bind(&ValidatorConfig::onCertFailed<Packet, OnFailed>,
719  this, _1, _2, packet.shared_from_this(), onValidationFailed);
720 
721  Interest certInterest(keyLocatorName);
722 
723  uint64_t incomingFaceId = 0;
724  auto incomingFaceIdTag = packet.template getTag<lp::IncomingFaceIdTag>();
725  if (incomingFaceIdTag != nullptr) {
726  incomingFaceId = incomingFaceIdTag->get();
727  }
728  auto nextStep = make_shared<ValidationRequest>(certInterest,
729  onCertValidated,
730  onCertValidationFailed,
731  1, nSteps + 1,
732  incomingFaceId);
733 
734  nextSteps.push_back(nextStep);
735  return;
736  }
737  return onValidationFailed(packet.shared_from_this(), "Unsupported Signature Type");
738 }
739 
740 template<class Packet, class OnValidated, class OnFailed>
741 void
742 ValidatorConfig::onCertValidated(const shared_ptr<const Data>& signCertificate,
743  const shared_ptr<const Packet>& packet,
744  const OnValidated& onValidated,
745  const OnFailed& onValidationFailed)
746 {
747  if (signCertificate->getContentType() != tlv::ContentType_Key)
748  return onValidationFailed(packet,
749  "Cannot retrieve signer's cert: " +
750  signCertificate->getName().toUri());
751 
752  shared_ptr<v1::IdentityCertificate> certificate;
753  try {
754  certificate = make_shared<v1::IdentityCertificate>(*signCertificate);
755  }
756  catch (const tlv::Error&) {
757  return onValidationFailed(packet,
758  "Cannot decode signer's cert: " +
759  signCertificate->getName().toUri());
760  }
761 
762  if (!certificate->isTooLate() && !certificate->isTooEarly()) {
763  if (m_certificateCache != nullptr)
764  m_certificateCache->insertCertificate(certificate);
765 
766  if (verifySignature(*packet, certificate->getPublicKeyInfo()))
767  return onValidated(packet);
768  else
769  return onValidationFailed(packet,
770  "Cannot verify signature: " + packet->getName().toUri());
771  }
772  else {
773  return onValidationFailed(packet,
774  "Signing certificate " +
775  signCertificate->getName().toUri() + " is no longer valid.");
776  }
777 }
778 
779 template<class Packet, class OnFailed>
780 void
781 ValidatorConfig::onCertFailed(const shared_ptr<const Data>& signCertificate,
782  const std::string& failureInfo,
783  const shared_ptr<const Packet>& packet,
784  const OnFailed& onValidationFailed)
785 {
786  onValidationFailed(packet, failureInfo);
787 }
788 
789 } // namespace security
790 } // namespace ndn
function< void(const shared_ptr< const Interest > &, const std::string &)> OnInterestValidationFailed
Callback to report a failed Interest validation.
static Name certificateNameToPublicKeyName(const Name &certificateName)
Get the public key name from the full certificate name.
const Name & getName() const
Definition: interest.hpp:226
Copyright (c) 2013-2016 Regents of the University of California.
Definition: common.hpp:74
void load(const std::string &filename)
bool hasKeyLocator() const
Check if SignatureInfo block has a KeyLocator.
Definition: signature.hpp:132
const KeyLocator & getKeyLocator() const
Get KeyLocator.
Definition: signature.hpp:143
represents an Interest packet
Definition: interest.hpp:42
indicates KeyLocator contains a Name
Definition: key-locator.hpp:49
static time_point now() noexcept
Definition: time.cpp:45
ValidatorConfig(Face *face=nullptr, const shared_ptr< CertificateCache > &certificateCache=DEFAULT_CERTIFICATE_CACHE, const time::milliseconds &graceInterval=DEFAULT_GRACE_INTERVAL, const size_t stepLimit=10, const size_t maxTrackedKeys=1000, const time::system_clock::Duration &keyTimestampTtl=DEFAULT_KEY_TIMESTAMP_TTL)
function< void(const shared_ptr< const Data > &, const std::string &)> OnDataValidationFailed
Callback to report a failed Data validation.
static const time::milliseconds DEFAULT_GRACE_INTERVAL
function< void(const shared_ptr< const Data > &)> OnDataValidated
Callback to report a successful Data validation.
function< void(const shared_ptr< const Interest > &)> OnInterestValidated
Callback to report a successful Interest validation.
std::string toUri() const
Encode this name as a URI.
Definition: name.cpp:171
const Name & getName() const
get Name element
Type getType() const
static const shared_ptr< CertificateCache > DEFAULT_CERTIFICATE_CACHE
provides the interfaces for packet validation.
Definition: validator.hpp:39
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:121
size_t size() const
Get the number of components.
Definition: name.hpp:400
const size_t MIN_SIZE
minimal number of components for Command Interest
Name abstraction to represent an absolute name.
Definition: name.hpp:46
void checkPolicy(const Data &data, int nSteps, const OnDataValidated &onValidated, const OnDataValidationFailed &onValidationFailed, std::vector< shared_ptr< ValidationRequest >> &nextSteps) override
Check the Data against policy and return the next validation step if necessary.
const ssize_t POS_SIG_VALUE
boost::asio::io_service & getIoService()
Definition: face.hpp:696
time_point TimePoint
Definition: time.hpp:90
const Signature & getSignature() const
Definition: data.hpp:348
boost::property_tree::ptree ConfigSection
const ssize_t POS_TIMESTAMP
system_clock::TimePoint fromUnixTimestamp(const milliseconds &duration)
Convert UNIX timestamp to system_clock::TimePoint.
Definition: time.cpp:124
const ssize_t POS_SIG_INFO
static const time::system_clock::Duration DEFAULT_KEY_TIMESTAMP_TTL
indicates content is a public key
static bool verifySignature(const Data &data, const v1::PublicKey &publicKey)
Verify the data using the publicKey.
Definition: validator.cpp:104
represents a Data packet
Definition: data.hpp:37
uint64_t toNumber() const
Interpret this name component as nonNegativeInteger.
const Component & at(ssize_t i) const
Get component at the specified index.
Definition: name.hpp:434
represents an error in TLV encoding or decoding
A Signature is storage for the signature-related information (info and value) in a Data packet...
Definition: signature.hpp:33