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