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