27 #include "../util/io.hpp"
29 #include <boost/filesystem.hpp>
30 #include <boost/property_tree/info_parser.hpp>
31 #include <boost/algorithm/string.hpp>
41 const shared_ptr<CertificateCache>& certificateCache,
42 const time::milliseconds& graceInterval,
43 const size_t stepLimit,
44 const size_t maxTrackedKeys,
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)
55 if (!static_cast<bool>(m_certificateCache) && face !=
nullptr)
56 m_certificateCache = make_shared<CertificateCacheTtl>(ref(face->
getIoService()));
60 const shared_ptr<CertificateCache>& certificateCache,
61 const time::milliseconds& graceInterval,
62 const size_t stepLimit,
63 const size_t maxTrackedKeys,
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)
74 if (!static_cast<bool>(m_certificateCache))
75 m_certificateCache = make_shared<CertificateCacheTtl>(ref(face.
getIoService()));
81 std::ifstream inputFile;
82 inputFile.open(filename.c_str());
83 if (!inputFile.good() || !inputFile.is_open())
85 std::string msg =
"Failed to read configuration file: ";
89 load(inputFile, filename);
96 std::istringstream inputStream(input);
97 load(inputStream, filename);
107 boost::property_tree::read_info(input, tree);
109 catch (boost::property_tree::info_parser_error& error)
111 std::stringstream msg;
112 msg <<
"Failed to parse configuration file";
113 msg <<
" " << filename;
114 msg <<
" " << error.message() <<
" line " << error.line();
118 load(tree, filename);
123 const std::string& filename)
125 BOOST_ASSERT(!filename.empty());
129 if (configSection.begin() == configSection.end())
131 std::string msg =
"Error processing configuration file";
138 for (security::conf::ConfigSection::const_iterator i = configSection.begin();
139 i != configSection.end(); ++i)
141 const std::string& sectionName = i->first;
144 if (boost::iequals(sectionName,
"rule"))
146 onConfigRule(section, filename);
148 else if (boost::iequals(sectionName,
"trust-anchor"))
150 onConfigTrustAnchor(section, filename);
154 std::string msg =
"Error processing configuration file";
157 msg +=
" unrecognized section: " + sectionName;
165 const std::string& filename)
169 ConfigSection::const_iterator propertyIt = configSection.begin();
172 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"id"))
173 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.id>!"));
175 std::string ruleId = propertyIt->second.data();
179 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"for"))
180 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.for> in rule: " + ruleId +
"!"));
182 std::string usage = propertyIt->second.data();
186 if (boost::iequals(usage,
"data"))
188 else if (boost::iequals(usage,
"interest"))
191 BOOST_THROW_EXCEPTION(
Error(
"Unrecognized <rule.for>: " + usage
192 +
" in rule: " + ruleId));
195 std::vector<shared_ptr<Filter>> filters;
196 for (; propertyIt != configSection.end(); propertyIt++)
198 if (!boost::iequals(propertyIt->first,
"filter"))
200 if (boost::iequals(propertyIt->first,
"checker"))
202 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.filter> in rule: " + ruleId));
205 filters.push_back(FilterFactory::create(propertyIt->second));
210 std::vector<shared_ptr<Checker>> checkers;
211 for (; propertyIt != configSection.end(); propertyIt++)
213 if (!boost::iequals(propertyIt->first,
"checker"))
214 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.checker> in rule: " + ruleId));
216 checkers.push_back(CheckerFactory::create(propertyIt->second, filename));
221 if (propertyIt != configSection.end())
222 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of rule: " + ruleId));
224 if (checkers.size() == 0)
225 BOOST_THROW_EXCEPTION(
Error(
"No <rule.checker> is specified in rule: " + ruleId));
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]);
235 m_dataRules.push_back(rule);
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]);
245 m_interestRules.push_back(rule);
251 const std::string& filename)
254 using namespace boost::filesystem;
256 ConfigSection::const_iterator propertyIt = configSection.begin();
259 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"type"))
260 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.type>!"));
262 std::string type = propertyIt->second.data();
265 if (boost::iequals(type,
"file"))
268 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"file-name"))
269 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.file-name>!"));
271 std::string
file = propertyIt->second.data();
275 if (propertyIt != configSection.end())
276 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of trust-anchor!"));
278 path certfilePath = absolute(file, path(filename).parent_path());
279 shared_ptr<v1::IdentityCertificate> idCert =
280 io::load<v1::IdentityCertificate>(certfilePath.string());
282 if (static_cast<bool>(idCert))
284 BOOST_ASSERT(idCert->getName().size() >= 1);
285 m_staticContainer.add(idCert);
286 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
289 BOOST_THROW_EXCEPTION(
Error(
"Cannot read certificate from file: " +
290 certfilePath.native()));
294 else if (boost::iequals(type,
"base64"))
297 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"base64-string"))
298 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.base64-string>!"));
300 std::stringstream ss(propertyIt->second.data());
304 if (propertyIt != configSection.end())
305 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of trust-anchor!"));
307 shared_ptr<v1::IdentityCertificate> idCert = io::load<v1::IdentityCertificate>(ss);
309 if (static_cast<bool>(idCert))
311 BOOST_ASSERT(idCert->getName().size() >= 1);
312 m_staticContainer.add(idCert);
313 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
316 BOOST_THROW_EXCEPTION(
Error(
"Cannot decode certificate from base64-string"));
320 else if (boost::iequals(type,
"dir"))
322 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"dir"))
323 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.dir>"));
325 std::string dirString(propertyIt->second.data());
328 if (propertyIt != configSection.end())
330 if (boost::iequals(propertyIt->first,
"refresh"))
332 using namespace boost::filesystem;
334 time::nanoseconds refresh = getRefreshPeriod(propertyIt->second.data());
337 if (propertyIt != configSection.end())
338 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of trust-anchor"));
340 path dirPath = absolute(dirString, path(filename).parent_path());
342 m_dynamicContainers.push_back(DynamicTrustAnchorContainer(dirPath,
true, refresh));
349 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.refresh>!"));
353 using namespace boost::filesystem;
355 path dirPath = absolute(dirString, path(filename).parent_path());
357 directory_iterator end;
359 for (directory_iterator it(dirPath); it != end; it++)
361 shared_ptr<v1::IdentityCertificate> idCert =
362 io::load<v1::IdentityCertificate>(it->path().string());
364 if (static_cast<bool>(idCert))
365 m_staticContainer.add(idCert);
371 else if (boost::iequals(type,
"any"))
373 m_shouldValidate =
false;
376 BOOST_THROW_EXCEPTION(
Error(
"Unsupported trust-anchor.type: " + type));
382 if (static_cast<bool>(m_certificateCache))
383 m_certificateCache->reset();
384 m_interestRules.clear();
389 m_staticContainer = TrustAnchorContainer();
391 m_dynamicContainers.clear();
397 if ((!static_cast<bool>(m_certificateCache) || m_certificateCache->isEmpty()) &&
398 m_interestRules.empty() &&
399 m_dataRules.empty() &&
406 ValidatorConfig::getRefreshPeriod(std::string inputString)
408 char unit = inputString[inputString.size() - 1];
409 std::string refreshString = inputString.substr(0, inputString.size() - 1);
415 number = boost::lexical_cast<uint32_t>(refreshString);
417 catch (boost::bad_lexical_cast&)
419 BOOST_THROW_EXCEPTION(
Error(
"Bad number: " + refreshString));
423 return getDefaultRefreshPeriod();
428 return time::duration_cast<time::nanoseconds>(time::hours(number));
430 return time::duration_cast<time::nanoseconds>(time::minutes(number));
432 return time::duration_cast<time::nanoseconds>(time::seconds(number));
434 BOOST_THROW_EXCEPTION(
Error(std::string(
"Wrong time unit: ") + unit));
439 ValidatorConfig::getDefaultRefreshPeriod()
441 return time::duration_cast<time::nanoseconds>(time::seconds(3600));
445 ValidatorConfig::refreshAnchors()
449 bool isRefreshed =
false;
451 for (DynamicContainers::iterator cIt = m_dynamicContainers.begin();
452 cIt != m_dynamicContainers.end(); cIt++)
454 if (cIt->getLastRefresh() + cIt->getRefreshPeriod() < now)
458 cIt->setLastRefresh(now);
468 for (CertificateList::const_iterator it = m_staticContainer.getAll().begin();
469 it != m_staticContainer.getAll().end(); it++)
471 m_anchors[(*it)->getName().getPrefix(-1)] = (*it);
474 for (DynamicContainers::iterator cIt = m_dynamicContainers.begin();
475 cIt != m_dynamicContainers.end(); cIt++)
477 const CertificateList& certList = cIt->getAll();
479 for (CertificateList::const_iterator it = certList.begin();
480 it != certList.end(); it++)
482 m_anchors[(*it)->getName().getPrefix(-1)] = (*it);
485 m_dynamicContainers.sort(ValidatorConfig::compareDynamicContainer);
494 std::vector<shared_ptr<ValidationRequest>>& nextSteps)
496 if (!m_shouldValidate)
497 return onValidated(data.shared_from_this());
499 bool isMatched =
false;
500 int8_t checkResult = -1;
502 for (DataRuleList::iterator it = m_dataRules.begin();
503 it != m_dataRules.end(); it++)
505 if ((*it)->match(data))
508 checkResult = (*it)->check(data, onValidated, onValidationFailed);
514 return onValidationFailed(data.shared_from_this(),
"No rule matched!");
516 if (checkResult == 0)
519 checkSignature(data, signature, nSteps,
520 onValidated, onValidationFailed, nextSteps);
529 std::vector<shared_ptr<ValidationRequest>>& nextSteps)
531 if (!m_shouldValidate)
532 return onValidated(interest.shared_from_this());
537 return onValidationFailed(interest.shared_from_this(),
538 "Interest is not signed: " + interest.
getName().
toUri());
547 return onValidationFailed(interest.shared_from_this(),
548 "No valid KeyLocator");
553 return onValidationFailed(interest.shared_from_this(),
554 "Key Locator is not a name");
558 bool isMatched =
false;
559 int8_t checkResult = -1;
561 for (InterestRuleList::iterator it = m_interestRules.begin();
562 it != m_interestRules.end(); it++)
564 if ((*it)->match(interest))
567 checkResult = (*it)->check(interest,
568 bind(&ValidatorConfig::checkTimestamp,
this, _1,
569 keyName, onValidated, onValidationFailed),
576 return onValidationFailed(interest.shared_from_this(),
"No rule matched!");
578 if (checkResult == 0)
580 checkSignature<Interest, OnInterestValidated, OnInterestValidationFailed>
581 (interest, signature, nSteps,
582 bind(&ValidatorConfig::checkTimestamp,
this, _1,
583 keyName, onValidated, onValidationFailed),
590 return onValidationFailed(interest.shared_from_this(),
591 "No valid signature");
595 return onValidationFailed(interest.shared_from_this(),
596 "No valid KeyLocator");
600 return onValidationFailed(interest.shared_from_this(),
601 "Cannot determine the signing key");
606 return onValidationFailed(interest.shared_from_this(),
607 "Cannot decode signature");
612 ValidatorConfig::checkTimestamp(
const shared_ptr<const Interest>& interest,
617 const Name& interestName = interest->getName();
628 return onValidationFailed(interest,
629 "Cannot decode signature related TLVs");
634 LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
635 if (timestampIt == m_lastTimestamp.end())
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());
645 if (interestTime <= timestampIt->second)
646 return onValidationFailed(interest,
647 "The command is outdated: " +
648 interest->getName().toUri());
652 if (timestampIt == m_lastTimestamp.end())
655 m_lastTimestamp[keyName] = interestTime;
659 timestampIt->second = interestTime;
662 return onValidated(interest);
666 ValidatorConfig::cleanOldKeys()
668 if (m_lastTimestamp.size() < m_maxTrackedKeys)
671 LastTimestampMap::iterator timestampIt = m_lastTimestamp.begin();
672 LastTimestampMap::iterator end = m_lastTimestamp.end();
675 LastTimestampMap::iterator oldestKeyIt = m_lastTimestamp.begin();
678 while (timestampIt != end)
680 if (now - timestampIt->second > m_keyTimestampTtl)
682 LastTimestampMap::iterator toDelete = timestampIt;
684 m_lastTimestamp.erase(toDelete);
688 if (timestampIt->second < oldestTimestamp)
690 oldestTimestamp = timestampIt->second;
691 oldestKeyIt = timestampIt;
697 if (m_lastTimestamp.size() >= m_maxTrackedKeys)
698 m_lastTimestamp.erase(oldestKeyIt);
702 ValidatorConfig::DynamicTrustAnchorContainer::refresh()
704 using namespace boost::filesystem;
706 m_certificates.clear();
710 directory_iterator end;
712 for (directory_iterator it(m_path); it != end; it++)
714 shared_ptr<v1::IdentityCertificate> idCert =
715 io::load<v1::IdentityCertificate>(it->path().string());
717 if (static_cast<bool>(idCert))
718 m_certificates.push_back(idCert);
723 shared_ptr<v1::IdentityCertificate> idCert =
724 io::load<v1::IdentityCertificate>(m_path.string());
726 if (static_cast<bool>(idCert))
727 m_certificates.push_back(idCert);
731 template<
class Packet,
class OnVal
idated,
class OnFailed>
733 ValidatorConfig::checkSignature(
const Packet& packet,
734 const Signature& signature,
736 const OnValidated& onValidated,
737 const OnFailed& onValidationFailed,
738 std::vector<shared_ptr<ValidationRequest>>& nextSteps)
745 return onValidated(packet.shared_from_this());
747 return onValidationFailed(packet.shared_from_this(),
748 "Sha256 Signature cannot be verified!");
752 switch (signature.getType()) {
756 if (!signature.hasKeyLocator()) {
757 return onValidationFailed(packet.shared_from_this(),
758 "Missing KeyLocator in SignatureInfo");
763 return onValidationFailed(packet.shared_from_this(),
764 "Unsupported signature type");
767 catch (KeyLocator::Error& e) {
768 return onValidationFailed(packet.shared_from_this(),
769 "Cannot decode KeyLocator in public key signature");
771 catch (tlv::Error& e) {
772 return onValidationFailed(packet.shared_from_this(),
773 "Cannot decode public key signature");
778 return onValidationFailed(packet.shared_from_this(),
"Unsupported KeyLocator type");
781 const Name& keyLocatorName = signature.getKeyLocator().getName();
783 shared_ptr<const v1::Certificate> trustedCert;
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;
793 if (static_cast<bool>(trustedCert))
795 if (
verifySignature(packet, signature, trustedCert->getPublicKeyInfo()))
796 return onValidated(packet.shared_from_this());
798 return onValidationFailed(packet.shared_from_this(),
799 "Cannot verify signature");
803 if (m_stepLimit == nSteps)
804 return onValidationFailed(packet.shared_from_this(),
805 "Maximum steps of validation reached");
808 bind(&ValidatorConfig::onCertValidated<Packet, OnValidated, OnFailed>,
809 this, _1, packet.shared_from_this(), onValidated, onValidationFailed);
812 bind(&ValidatorConfig::onCertFailed<Packet, OnFailed>,
813 this, _1, _2, packet.shared_from_this(), onValidationFailed);
815 Interest certInterest(keyLocatorName);
817 shared_ptr<ValidationRequest> nextStep =
818 make_shared<ValidationRequest>(certInterest,
820 onCertValidationFailed,
823 nextSteps.push_back(nextStep);
827 return onValidationFailed(packet.shared_from_this(),
"Unsupported Signature Type");
830 template<
class Packet,
class OnVal
idated,
class OnFailed>
832 ValidatorConfig::onCertValidated(
const shared_ptr<const Data>& signCertificate,
833 const shared_ptr<const Packet>& packet,
834 const OnValidated& onValidated,
835 const OnFailed& onValidationFailed)
838 return onValidationFailed(packet,
839 "Cannot retrieve signer's cert: " +
840 signCertificate->getName().toUri());
842 shared_ptr<v1::IdentityCertificate> certificate;
844 certificate = make_shared<v1::IdentityCertificate>(*signCertificate);
846 catch (tlv::Error&) {
847 return onValidationFailed(packet,
848 "Cannot decode signer's cert: " +
849 signCertificate->getName().toUri());
852 if (!certificate->isTooLate() && !certificate->isTooEarly())
854 if (static_cast<bool>(m_certificateCache))
855 m_certificateCache->insertCertificate(certificate);
858 return onValidated(packet);
860 return onValidationFailed(packet,
861 "Cannot verify signature: " +
862 packet->getName().toUri());
866 return onValidationFailed(packet,
867 "Signing certificate " +
868 signCertificate->getName().toUri() +
869 " is no longer valid.");
873 template<
class Packet,
class OnFailed>
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)
880 onValidationFailed(packet, failureInfo);
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
Copyright (c) 2013-2016 Regents of the University of California.
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.
const KeyLocator & getKeyLocator() const
Get KeyLocator.
represents an Interest packet
indicates KeyLocator contains a Name
static time_point now() noexcept
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.
const Name & getName() const
get Name element
const size_t MIN_LENGTH
minimal number of components for Command Interest
static const shared_ptr< CertificateCache > DEFAULT_CERTIFICATE_CACHE
provides the interfaces for packet validation.
Provide a communication channel with local or remote NDN forwarder.
size_t size() const
Get the number of components.
Name abstraction to represent an absolute name.
const ssize_t POS_SIG_VALUE
boost::asio::io_service & getIoService()
const Signature & getSignature() const
boost::property_tree::ptree ConfigSection
system_clock::TimePoint fromUnixTimestamp(const milliseconds &duration)
Convert UNIX timestamp to system_clock::TimePoint.
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.
uint64_t toNumber() const
Interpret this name component as nonNegativeInteger.
const Component & get(ssize_t i) const
Get the component at the given index.
represents an error in TLV encoding or decoding
A Signature is storage for the signature-related information (info and value) in a Data packet...