26 #include "../util/io.hpp" 28 #include <boost/filesystem.hpp> 29 #include <boost/property_tree/info_parser.hpp> 30 #include <boost/algorithm/string.hpp> 39 const shared_ptr<CertificateCache>& certificateCache,
40 const time::milliseconds& graceInterval,
41 const size_t stepLimit,
42 const size_t maxTrackedKeys,
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)
53 if (!static_cast<bool>(m_certificateCache) && face !=
nullptr)
54 m_certificateCache = make_shared<CertificateCacheTtl>(ref(face->
getIoService()));
58 const shared_ptr<CertificateCache>& certificateCache,
59 const time::milliseconds& graceInterval,
60 const size_t stepLimit,
61 const size_t maxTrackedKeys,
64 , m_shouldValidate(true)
65 , m_stepLimit(stepLimit)
66 , m_certificateCache(certificateCache)
67 , m_graceInterval(graceInterval <
time::milliseconds::zero() ?
69 , m_maxTrackedKeys(maxTrackedKeys)
70 , m_keyTimestampTtl(keyTimestampTtl)
72 if (!static_cast<bool>(m_certificateCache))
73 m_certificateCache = make_shared<CertificateCacheTtl>(ref(face.
getIoService()));
79 std::ifstream inputFile;
80 inputFile.open(filename.c_str());
81 if (!inputFile.good() || !inputFile.is_open())
83 std::string msg =
"Failed to read configuration file: ";
87 load(inputFile, filename);
94 std::istringstream inputStream(input);
95 load(inputStream, filename);
105 boost::property_tree::read_info(input, tree);
107 catch (boost::property_tree::info_parser_error& error)
109 std::stringstream msg;
110 msg <<
"Failed to parse configuration file";
111 msg <<
" " << filename;
112 msg <<
" " << error.message() <<
" line " << error.line();
116 load(tree, filename);
121 const std::string& filename)
123 BOOST_ASSERT(!filename.empty());
127 if (configSection.begin() == configSection.end())
129 std::string msg =
"Error processing configuration file";
136 for (security::conf::ConfigSection::const_iterator i = configSection.begin();
137 i != configSection.end(); ++i)
139 const std::string& sectionName = i->first;
142 if (boost::iequals(sectionName,
"rule"))
144 onConfigRule(section, filename);
146 else if (boost::iequals(sectionName,
"trust-anchor"))
148 onConfigTrustAnchor(section, filename);
152 std::string msg =
"Error processing configuration file";
155 msg +=
" unrecognized section: " + sectionName;
163 const std::string& filename)
167 ConfigSection::const_iterator propertyIt = configSection.begin();
170 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"id"))
171 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.id>!"));
173 std::string ruleId = propertyIt->second.data();
177 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"for"))
178 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.for> in rule: " + ruleId +
"!"));
180 std::string usage = propertyIt->second.data();
184 if (boost::iequals(usage,
"data"))
186 else if (boost::iequals(usage,
"interest"))
189 BOOST_THROW_EXCEPTION(
Error(
"Unrecognized <rule.for>: " + usage
190 +
" in rule: " + ruleId));
193 std::vector<shared_ptr<Filter> > filters;
194 for (; propertyIt != configSection.end(); propertyIt++)
196 if (!boost::iequals(propertyIt->first,
"filter"))
198 if (boost::iequals(propertyIt->first,
"checker"))
200 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.filter> in rule: " + ruleId));
203 filters.push_back(FilterFactory::create(propertyIt->second));
208 std::vector<shared_ptr<Checker> > checkers;
209 for (; propertyIt != configSection.end(); propertyIt++)
211 if (!boost::iequals(propertyIt->first,
"checker"))
212 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.checker> in rule: " + ruleId));
214 checkers.push_back(CheckerFactory::create(propertyIt->second, filename));
219 if (propertyIt != configSection.end())
220 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of rule: " + ruleId));
222 if (checkers.size() == 0)
223 BOOST_THROW_EXCEPTION(
Error(
"No <rule.checker> is specified in rule: " + ruleId));
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]);
233 m_dataRules.push_back(rule);
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]);
243 m_interestRules.push_back(rule);
249 const std::string& filename)
252 using namespace boost::filesystem;
254 ConfigSection::const_iterator propertyIt = configSection.begin();
257 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"type"))
258 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.type>!"));
260 std::string type = propertyIt->second.data();
263 if (boost::iequals(type,
"file"))
266 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"file-name"))
267 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.file-name>!"));
269 std::string
file = propertyIt->second.data();
273 if (propertyIt != configSection.end())
274 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of trust-anchor!"));
276 path certfilePath = absolute(file, path(filename).parent_path());
277 shared_ptr<IdentityCertificate> idCert =
278 io::load<IdentityCertificate>(certfilePath.string());
280 if (static_cast<bool>(idCert))
282 BOOST_ASSERT(idCert->getName().size() >= 1);
283 m_staticContainer.add(idCert);
284 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
287 BOOST_THROW_EXCEPTION(
Error(
"Cannot read certificate from file: " +
288 certfilePath.native()));
292 else if (boost::iequals(type,
"base64"))
295 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"base64-string"))
296 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.base64-string>!"));
298 std::stringstream ss(propertyIt->second.data());
302 if (propertyIt != configSection.end())
303 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of trust-anchor!"));
305 shared_ptr<IdentityCertificate> idCert = io::load<IdentityCertificate>(ss);
307 if (static_cast<bool>(idCert))
309 BOOST_ASSERT(idCert->getName().size() >= 1);
310 m_staticContainer.add(idCert);
311 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
314 BOOST_THROW_EXCEPTION(
Error(
"Cannot decode certificate from base64-string"));
318 else if (boost::iequals(type,
"dir"))
320 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"dir"))
321 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.dir>"));
323 std::string dirString(propertyIt->second.data());
326 if (propertyIt != configSection.end())
328 if (boost::iequals(propertyIt->first,
"refresh"))
330 using namespace boost::filesystem;
332 time::nanoseconds refresh = getRefreshPeriod(propertyIt->second.data());
335 if (propertyIt != configSection.end())
336 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of trust-anchor"));
338 path dirPath = absolute(dirString, path(filename).parent_path());
340 m_dynamicContainers.push_back(DynamicTrustAnchorContainer(dirPath,
true, refresh));
347 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.refresh>!"));
351 using namespace boost::filesystem;
353 path dirPath = absolute(dirString, path(filename).parent_path());
355 directory_iterator end;
357 for (directory_iterator it(dirPath); it != end; it++)
359 shared_ptr<IdentityCertificate> idCert =
360 io::load<IdentityCertificate>(it->path().string());
362 if (static_cast<bool>(idCert))
363 m_staticContainer.add(idCert);
369 else if (boost::iequals(type,
"any"))
371 m_shouldValidate =
false;
374 BOOST_THROW_EXCEPTION(
Error(
"Unsupported trust-anchor.type: " + type));
380 if (static_cast<bool>(m_certificateCache))
381 m_certificateCache->reset();
382 m_interestRules.clear();
387 m_staticContainer = TrustAnchorContainer();
389 m_dynamicContainers.clear();
395 if ((!static_cast<bool>(m_certificateCache) || m_certificateCache->isEmpty()) &&
396 m_interestRules.empty() &&
397 m_dataRules.empty() &&
404 ValidatorConfig::getRefreshPeriod(std::string inputString)
406 char unit = inputString[inputString.size() - 1];
407 std::string refreshString = inputString.substr(0, inputString.size() - 1);
413 number = boost::lexical_cast<uint32_t>(refreshString);
415 catch (boost::bad_lexical_cast&)
417 BOOST_THROW_EXCEPTION(
Error(
"Bad number: " + refreshString));
421 return getDefaultRefreshPeriod();
426 return time::duration_cast<time::nanoseconds>(time::hours(number));
428 return time::duration_cast<time::nanoseconds>(time::minutes(number));
430 return time::duration_cast<time::nanoseconds>(time::seconds(number));
432 BOOST_THROW_EXCEPTION(
Error(std::string(
"Wrong time unit: ") + unit));
437 ValidatorConfig::getDefaultRefreshPeriod()
439 return time::duration_cast<time::nanoseconds>(time::seconds(3600));
443 ValidatorConfig::refreshAnchors()
447 bool isRefreshed =
false;
450 cIt != m_dynamicContainers.end(); cIt++)
452 if (cIt->getLastRefresh() + cIt->getRefreshPeriod() < now)
456 cIt->setLastRefresh(now);
466 for (CertificateList::const_iterator it = m_staticContainer.getAll().begin();
467 it != m_staticContainer.getAll().end(); it++)
469 m_anchors[(*it)->getName().getPrefix(-1)] = (*it);
473 cIt != m_dynamicContainers.end(); cIt++)
475 const CertificateList& certList = cIt->getAll();
477 for (CertificateList::const_iterator it = certList.begin();
478 it != certList.end(); it++)
480 m_anchors[(*it)->getName().getPrefix(-1)] = (*it);
483 m_dynamicContainers.sort(ValidatorConfig::compareDynamicContainer);
492 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
494 if (!m_shouldValidate)
495 return onValidated(data.shared_from_this());
497 bool isMatched =
false;
498 int8_t checkResult = -1;
501 it != m_dataRules.end(); it++)
503 if ((*it)->match(data))
506 checkResult = (*it)->check(data, onValidated, onValidationFailed);
512 return onValidationFailed(data.shared_from_this(),
"No rule matched!");
514 if (checkResult == 0)
517 checkSignature(data, signature, nSteps,
518 onValidated, onValidationFailed, nextSteps);
527 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
529 if (!m_shouldValidate)
530 return onValidated(interest.shared_from_this());
535 return onValidationFailed(interest.shared_from_this(),
536 "Interest is not signed: " + interest.
getName().
toUri());
545 return onValidationFailed(interest.shared_from_this(),
546 "No valid KeyLocator");
551 return onValidationFailed(interest.shared_from_this(),
552 "Key Locator is not a name");
556 bool isMatched =
false;
557 int8_t checkResult = -1;
560 it != m_interestRules.end(); it++)
562 if ((*it)->match(interest))
565 checkResult = (*it)->check(interest,
566 bind(&ValidatorConfig::checkTimestamp,
this, _1,
567 keyName, onValidated, onValidationFailed),
574 return onValidationFailed(interest.shared_from_this(),
"No rule matched!");
576 if (checkResult == 0)
578 checkSignature<Interest, OnInterestValidated, OnInterestValidationFailed>
579 (interest, signature, nSteps,
580 bind(&ValidatorConfig::checkTimestamp,
this, _1,
581 keyName, onValidated, onValidationFailed),
588 return onValidationFailed(interest.shared_from_this(),
589 "No valid signature");
593 return onValidationFailed(interest.shared_from_this(),
594 "No valid KeyLocator");
598 return onValidationFailed(interest.shared_from_this(),
599 "Cannot determine the signing key");
604 return onValidationFailed(interest.shared_from_this(),
605 "Cannot decode signature");
610 ValidatorConfig::checkTimestamp(
const shared_ptr<const Interest>& interest,
615 const Name& interestName = interest->getName();
626 return onValidationFailed(interest,
627 "Cannot decode signature related TLVs");
633 if (timestampIt == m_lastTimestamp.end())
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());
643 if (interestTime <= timestampIt->second)
644 return onValidationFailed(interest,
645 "The command is outdated: " +
646 interest->getName().toUri());
650 if (timestampIt == m_lastTimestamp.end())
653 m_lastTimestamp[keyName] = interestTime;
657 timestampIt->second = interestTime;
660 return onValidated(interest);
664 ValidatorConfig::cleanOldKeys()
666 if (m_lastTimestamp.size() < m_maxTrackedKeys)
676 while (timestampIt != end)
678 if (now - timestampIt->second > m_keyTimestampTtl)
682 m_lastTimestamp.erase(toDelete);
686 if (timestampIt->second < oldestTimestamp)
688 oldestTimestamp = timestampIt->second;
689 oldestKeyIt = timestampIt;
695 if (m_lastTimestamp.size() >= m_maxTrackedKeys)
696 m_lastTimestamp.erase(oldestKeyIt);
700 ValidatorConfig::DynamicTrustAnchorContainer::refresh()
702 using namespace boost::filesystem;
704 m_certificates.clear();
708 directory_iterator end;
710 for (directory_iterator it(m_path); it != end; it++)
712 shared_ptr<IdentityCertificate> idCert =
713 io::load<IdentityCertificate>(it->path().string());
715 if (static_cast<bool>(idCert))
716 m_certificates.push_back(idCert);
721 shared_ptr<IdentityCertificate> idCert =
722 io::load<IdentityCertificate>(m_path.string());
724 if (static_cast<bool>(idCert))
725 m_certificates.push_back(idCert);
729 template<
class Packet,
class OnVal
idated,
class OnFailed>
731 ValidatorConfig::checkSignature(
const Packet& packet,
734 const OnValidated& onValidated,
735 const OnFailed& onValidationFailed,
736 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
743 return onValidated(packet.shared_from_this());
745 return onValidationFailed(packet.shared_from_this(),
746 "Sha256 Signature cannot be verified!");
755 return onValidationFailed(packet.shared_from_this(),
756 "Missing KeyLocator in SignatureInfo");
761 return onValidationFailed(packet.shared_from_this(),
762 "Unsupported signature type");
766 return onValidationFailed(packet.shared_from_this(),
767 "Cannot decode KeyLocator in public key signature");
770 return onValidationFailed(packet.shared_from_this(),
771 "Cannot decode public key signature");
776 return onValidationFailed(packet.shared_from_this(),
"Unsupported KeyLocator type");
781 shared_ptr<const Certificate> trustedCert;
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);
789 trustedCert = it->second;
791 if (static_cast<bool>(trustedCert))
793 if (
verifySignature(packet, signature, trustedCert->getPublicKeyInfo()))
794 return onValidated(packet.shared_from_this());
796 return onValidationFailed(packet.shared_from_this(),
797 "Cannot verify signature");
801 if (m_stepLimit == nSteps)
802 return onValidationFailed(packet.shared_from_this(),
803 "Maximum steps of validation reached");
806 bind(&ValidatorConfig::onCertValidated<Packet, OnValidated, OnFailed>,
807 this, _1, packet.shared_from_this(), onValidated, onValidationFailed);
810 bind(&ValidatorConfig::onCertFailed<Packet, OnFailed>,
811 this, _1, _2, packet.shared_from_this(), onValidationFailed);
813 Interest certInterest(keyLocatorName);
815 shared_ptr<ValidationRequest> nextStep =
816 make_shared<ValidationRequest>(certInterest,
818 onCertValidationFailed,
821 nextSteps.push_back(nextStep);
825 return onValidationFailed(packet.shared_from_this(),
"Unsupported Signature Type");
828 template<
class Packet,
class OnVal
idated,
class OnFailed>
830 ValidatorConfig::onCertValidated(
const shared_ptr<const Data>& signCertificate,
831 const shared_ptr<const Packet>& packet,
832 const OnValidated& onValidated,
833 const OnFailed& onValidationFailed)
836 return onValidationFailed(packet,
837 "Cannot retrieve signer's cert: " +
838 signCertificate->getName().toUri());
840 shared_ptr<IdentityCertificate> certificate;
842 certificate = make_shared<IdentityCertificate>(*signCertificate);
845 return onValidationFailed(packet,
846 "Cannot decode signer's cert: " +
847 signCertificate->getName().toUri());
850 if (!certificate->isTooLate() && !certificate->isTooEarly())
852 if (static_cast<bool>(m_certificateCache))
853 m_certificateCache->insertCertificate(certificate);
856 return onValidated(packet);
858 return onValidationFailed(packet,
859 "Cannot verify signature: " +
860 packet->getName().toUri());
864 return onValidationFailed(packet,
865 "Signing certificate " +
866 signCertificate->getName().toUri() +
867 " is no longer valid.");
871 template<
class Packet,
class OnFailed>
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)
878 onValidationFailed(packet, failureInfo);
Copyright (c) 2011-2015 Regents of the University of California.
std::string toUri() const
Encode this name as a URI.
void load(const std::string &filename)
const Component & get(ssize_t i) const
Get the component at the given index.
static const time::system_clock::Duration DEFAULT_KEY_TIMESTAMP_TTL
Represent a SHA256 digest.
const Name & getName() const
get Name element
static Name certificateNameToPublicKeyName(const Name &certificateName)
Get the public key name from the full certificate name.
represents an Interest packet
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
static time_point now() noexcept
bool hasKeyLocator() const
Check if SignatureInfo block has a KeyLocator.
Table::const_iterator iterator
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)
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.
static const shared_ptr< CertificateCache > DEFAULT_CERTIFICATE_CACHE
Name abstraction to represent an absolute name.
boost::asio::io_service & getIoService()
Return nullptr (cannot use IoService in simulations), preserved for API compatibility.
size_t size() const
Get the number of components.
uint64_t toNumber() const
Interpret this name component as nonNegativeInteger.
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
system_clock::TimePoint fromUnixTimestamp(const milliseconds &duration)
Convert UNIX timestamp to system_clock::TimePoint.
static bool verifySignature(const Data &data, const PublicKey &publicKey)
Verify the data using the publicKey.
indicates content is a public key
uint32_t getType() const
Get signature type.
const Signature & getSignature() const
const KeyLocator & getKeyLocator() const
Get KeyLocator.
Validator is one of the main classes of the security library.
function< void(const shared_ptr< const Interest > &)> OnInterestValidated
Callback to report a successful Interest validation.
represents an error in TLV encoding or decoding
const Name & getName() const
A Signature is storage for the signature-related information (info and value) in a Data packet...