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)
60 const shared_ptr<CertificateCache>& certificateCache,
61 const time::milliseconds& graceInterval,
62 const size_t stepLimit,
63 const size_t maxTrackedKeys,
81 std::ifstream inputFile;
82 inputFile.open(filename.c_str());
83 if (!inputFile.good() || !inputFile.is_open()) {
84 std::string msg =
"Failed to read configuration file: ";
88 load(inputFile, filename);
95 std::istringstream inputStream(input);
96 load(inputStream, filename);
105 boost::property_tree::read_info(input, tree);
107 catch (
const boost::property_tree::info_parser_error& error) {
108 std::stringstream msg;
109 msg <<
"Failed to parse configuration file";
110 msg <<
" " << filename;
111 msg <<
" " << error.message() <<
" line " << error.line();
115 load(tree, filename);
120 const std::string& filename)
122 BOOST_ASSERT(!filename.empty());
126 if (configSection.begin() == configSection.end()) {
127 std::string msg =
"Error processing configuration file";
134 for (security::conf::ConfigSection::const_iterator i = configSection.begin();
135 i != configSection.end(); ++i) {
136 const std::string& sectionName = i->first;
139 if (boost::iequals(sectionName,
"rule")) {
140 onConfigRule(section, filename);
142 else if (boost::iequals(sectionName,
"trust-anchor")) {
143 onConfigTrustAnchor(section, filename);
146 std::string msg =
"Error processing configuration file";
149 msg +=
" unrecognized section: " + sectionName;
157 const std::string& filename)
161 ConfigSection::const_iterator propertyIt = configSection.begin();
164 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"id"))
165 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.id>!"));
167 std::string ruleId = propertyIt->second.data();
171 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"for"))
172 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.for> in rule: " + ruleId +
"!"));
174 std::string usage = propertyIt->second.data();
177 bool isForData =
false;
178 if (boost::iequals(usage,
"data"))
180 else if (boost::iequals(usage,
"interest"))
183 BOOST_THROW_EXCEPTION(
Error(
"Unrecognized <rule.for>: " + usage
184 +
" in rule: " + ruleId));
187 std::vector<shared_ptr<Filter>> filters;
188 for (; propertyIt != configSection.end(); propertyIt++) {
189 if (!boost::iequals(propertyIt->first,
"filter")) {
190 if (boost::iequals(propertyIt->first,
"checker"))
192 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.filter> in rule: " + ruleId));
195 filters.push_back(FilterFactory::create(propertyIt->second));
200 std::vector<shared_ptr<Checker>> checkers;
201 for (; propertyIt != configSection.end(); propertyIt++) {
202 if (!boost::iequals(propertyIt->first,
"checker"))
203 BOOST_THROW_EXCEPTION(
Error(
"Expect <rule.checker> in rule: " + ruleId));
205 checkers.push_back(CheckerFactory::create(propertyIt->second, filename));
210 if (propertyIt != configSection.end())
211 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of rule: " + ruleId));
213 if (checkers.empty())
214 BOOST_THROW_EXCEPTION(
Error(
"No <rule.checker> is specified in rule: " + ruleId));
217 shared_ptr<DataRule> rule = make_shared<DataRule>(ruleId);
218 for (
const auto& filter : filters)
219 rule->addFilter(filter);
220 for (
const auto& checker : checkers)
221 rule->addChecker(checker);
226 shared_ptr<InterestRule> rule = make_shared<InterestRule>(ruleId);;
227 for (
const auto& filter : filters)
228 rule->addFilter(filter);
229 for (
const auto& checker : checkers)
230 rule->addChecker(checker);
238 const std::string& filename)
241 using namespace boost::filesystem;
243 ConfigSection::const_iterator propertyIt = configSection.begin();
246 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"type"))
247 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.type>!"));
249 std::string type = propertyIt->second.data();
252 if (boost::iequals(type,
"file")) {
254 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"file-name"))
255 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.file-name>!"));
257 std::string
file = propertyIt->second.data();
261 if (propertyIt != configSection.end())
262 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of trust-anchor!"));
264 path certfilePath = absolute(file, path(filename).parent_path());
265 auto idCert = io::load<v1::IdentityCertificate>(certfilePath.string());
267 if (idCert !=
nullptr) {
268 BOOST_ASSERT(idCert->getName().size() >= 1);
270 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
273 BOOST_THROW_EXCEPTION(
Error(
"Cannot read certificate from file: " + certfilePath.native()));
277 else if (boost::iequals(type,
"base64")) {
279 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"base64-string"))
280 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.base64-string>!"));
282 std::stringstream ss(propertyIt->second.data());
286 if (propertyIt != configSection.end())
287 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of trust-anchor!"));
289 auto idCert = io::load<v1::IdentityCertificate>(ss);
291 if (idCert !=
nullptr) {
292 BOOST_ASSERT(idCert->getName().size() >= 1);
294 m_anchors[idCert->getName().getPrefix(-1)] = idCert;
297 BOOST_THROW_EXCEPTION(
Error(
"Cannot decode certificate from base64-string"));
301 else if (boost::iequals(type,
"dir")) {
302 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,
"dir"))
303 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.dir>"));
305 std::string dirString(propertyIt->second.data());
308 if (propertyIt != configSection.end()) {
309 if (boost::iequals(propertyIt->first,
"refresh")) {
310 using namespace boost::filesystem;
312 time::nanoseconds refresh = getRefreshPeriod(propertyIt->second.data());
315 if (propertyIt != configSection.end())
316 BOOST_THROW_EXCEPTION(
Error(
"Expect the end of trust-anchor"));
318 path dirPath = absolute(dirString, path(filename).parent_path());
327 BOOST_THROW_EXCEPTION(
Error(
"Expect <trust-anchor.refresh>!"));
330 using namespace boost::filesystem;
332 path dirPath = absolute(dirString, path(filename).parent_path());
334 directory_iterator end;
336 for (directory_iterator it(dirPath); it != end; it++) {
337 auto idCert = io::load<v1::IdentityCertificate>(it->path().string());
339 if (idCert !=
nullptr)
346 else if (boost::iequals(type,
"any")) {
350 BOOST_THROW_EXCEPTION(
Error(
"Unsupported trust-anchor.type: " + type));
376 ValidatorConfig::getRefreshPeriod(std::string inputString)
378 char unit = inputString[inputString.size() - 1];
379 std::string refreshString = inputString.substr(0, inputString.size() - 1);
381 uint32_t refreshPeriod = 0;
384 refreshPeriod = boost::lexical_cast<uint32_t>(refreshString);
386 catch (
const boost::bad_lexical_cast&) {
387 BOOST_THROW_EXCEPTION(
Error(
"Bad number: " + refreshString));
390 if (refreshPeriod == 0)
391 return getDefaultRefreshPeriod();
395 return time::duration_cast<time::nanoseconds>(time::hours(refreshPeriod));
397 return time::duration_cast<time::nanoseconds>(time::minutes(refreshPeriod));
399 return time::duration_cast<time::nanoseconds>(time::seconds(refreshPeriod));
401 BOOST_THROW_EXCEPTION(
Error(std::string(
"Wrong time unit: ") + unit));
406 ValidatorConfig::getDefaultRefreshPeriod()
408 return time::duration_cast<time::nanoseconds>(time::seconds(3600));
412 ValidatorConfig::refreshAnchors()
416 bool isRefreshed =
false;
423 cIt->setLastRefresh(now);
430 m_anchors[cert->getName().getPrefix(-1)] = cert;
436 for (
const auto& cert :certList) {
437 m_anchors[cert->getName().getPrefix(-1)] = cert;
440 m_dynamicContainers.sort(ValidatorConfig::compareDynamicContainer);
449 std::vector<shared_ptr<ValidationRequest>>& nextSteps)
452 return onValidated(data.shared_from_this());
454 bool isMatched =
false;
455 int8_t checkResult = -1;
458 if (dataRule->match(data)) {
460 checkResult = dataRule->check(data, onValidated, onValidationFailed);
466 return onValidationFailed(data.shared_from_this(),
"No rule matched!");
468 if (checkResult == 0) {
470 checkSignature(data, signature, nSteps,
471 onValidated, onValidationFailed, nextSteps);
480 std::vector<shared_ptr<ValidationRequest>>& nextSteps)
483 return onValidated(interest.shared_from_this());
488 return onValidationFailed(interest.shared_from_this(),
489 "Interest is not signed: " + interest.
getName().
toUri());
497 return onValidationFailed(interest.shared_from_this(),
"No valid KeyLocator");
502 return onValidationFailed(interest.shared_from_this(),
"Key Locator is not a name");
506 bool isMatched =
false;
507 int8_t checkResult = -1;
510 if (interestRule->match(interest)) {
512 checkResult = interestRule->check(interest,
513 bind(&ValidatorConfig::checkTimestamp,
this, _1,
514 keyName, onValidated, onValidationFailed),
521 return onValidationFailed(interest.shared_from_this(),
"No rule matched!");
523 if (checkResult == 0) {
524 checkSignature<Interest, OnInterestValidated, OnInterestValidationFailed>
525 (interest, signature, nSteps,
526 bind(&ValidatorConfig::checkTimestamp,
this, _1,
527 keyName, onValidated, onValidationFailed),
533 return onValidationFailed(interest.shared_from_this(),
"No valid signature");
536 return onValidationFailed(interest.shared_from_this(),
"No valid KeyLocator");
539 return onValidationFailed(interest.shared_from_this(),
"Cannot determine the signing key");
542 return onValidationFailed(interest.shared_from_this(),
"Cannot decode signature");
547 ValidatorConfig::checkTimestamp(
const shared_ptr<const Interest>& interest,
552 const Name& interestName = interest->getName();
560 return onValidationFailed(interest,
561 "Cannot decode signature related TLVs");
570 return onValidationFailed(interest,
571 "The command is not in grace interval: " + interest->getName().toUri());
574 if (interestTime <= timestampIt->second)
575 return onValidationFailed(interest,
576 "The command is outdated: " + interest->getName().toUri());
585 timestampIt->second = interestTime;
588 return onValidated(interest);
592 ValidatorConfig::cleanOldKeys()
604 while (timestampIt != end) {
612 if (timestampIt->second < oldestTimestamp) {
613 oldestTimestamp = timestampIt->second;
614 oldestKeyIt = timestampIt;
625 ValidatorConfig::DynamicTrustAnchorContainer::refresh()
627 using namespace boost::filesystem;
629 m_certificates.clear();
632 directory_iterator end;
634 for (directory_iterator it(m_path); it != end; it++) {
635 auto idCert = io::load<v1::IdentityCertificate>(it->path().string());
637 if (idCert !=
nullptr)
638 m_certificates.push_back(idCert);
642 auto idCert = io::load<v1::IdentityCertificate>(m_path.string());
644 if (idCert !=
nullptr)
645 m_certificates.push_back(idCert);
649 template<
class Packet,
class OnVal
idated,
class OnFailed>
651 ValidatorConfig::checkSignature(
const Packet& packet,
654 const OnValidated& onValidated,
655 const OnFailed& onValidationFailed,
656 std::vector<shared_ptr<ValidationRequest>>& nextSteps)
662 return onValidated(packet.shared_from_this());
664 return onValidationFailed(packet.shared_from_this(),
"Sha256 Signature cannot be verified!");
672 return onValidationFailed(packet.shared_from_this(),
673 "Missing KeyLocator in SignatureInfo");
678 return onValidationFailed(packet.shared_from_this(),
"Unsupported signature type");
682 return onValidationFailed(packet.shared_from_this(),
683 "Cannot decode KeyLocator in public key signature");
686 return onValidationFailed(packet.shared_from_this(),
"Cannot decode public key signature");
690 return onValidationFailed(packet.shared_from_this(),
"Unsupported KeyLocator type");
695 shared_ptr<const v1::Certificate> trustedCert;
699 AnchorList::const_iterator it =
m_anchors.find(keyLocatorName);
703 trustedCert = it->second;
705 if (trustedCert !=
nullptr) {
706 if (
verifySignature(packet, signature, trustedCert->getPublicKeyInfo()))
707 return onValidated(packet.shared_from_this());
709 return onValidationFailed(packet.shared_from_this(),
"Cannot verify signature");
713 return onValidationFailed(packet.shared_from_this(),
"Maximum steps of validation reached");
716 bind(&ValidatorConfig::onCertValidated<Packet, OnValidated, OnFailed>,
717 this, _1, packet.shared_from_this(), onValidated, onValidationFailed);
720 bind(&ValidatorConfig::onCertFailed<Packet, OnFailed>,
721 this, _1, _2, packet.shared_from_this(), onValidationFailed);
723 Interest certInterest(keyLocatorName);
725 auto nextStep = make_shared<ValidationRequest>(certInterest,
727 onCertValidationFailed,
730 nextSteps.push_back(nextStep);
733 return onValidationFailed(packet.shared_from_this(),
"Unsupported Signature Type");
736 template<
class Packet,
class OnVal
idated,
class OnFailed>
738 ValidatorConfig::onCertValidated(
const shared_ptr<const Data>& signCertificate,
739 const shared_ptr<const Packet>& packet,
740 const OnValidated& onValidated,
741 const OnFailed& onValidationFailed)
744 return onValidationFailed(packet,
745 "Cannot retrieve signer's cert: " +
746 signCertificate->getName().toUri());
748 shared_ptr<v1::IdentityCertificate> certificate;
750 certificate = make_shared<v1::IdentityCertificate>(*signCertificate);
753 return onValidationFailed(packet,
754 "Cannot decode signer's cert: " +
755 signCertificate->getName().toUri());
758 if (!certificate->isTooLate() && !certificate->isTooEarly()) {
763 return onValidated(packet);
765 return onValidationFailed(packet,
766 "Cannot verify signature: " + packet->getName().toUri());
769 return onValidationFailed(packet,
770 "Signing certificate " +
771 signCertificate->getName().toUri() +
" is no longer valid.");
775 template<
class Packet,
class OnFailed>
777 ValidatorConfig::onCertFailed(
const shared_ptr<const Data>& signCertificate,
778 const std::string& failureInfo,
779 const shared_ptr<const Packet>& packet,
780 const OnFailed& onValidationFailed)
782 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.
Copyright (c) 2011-2015 Regents of the University of California.
std::string toUri() const
Encode this name as a URI.
InterestRuleList m_interestRules
void load(const std::string &filename)
time::milliseconds m_graceInterval
const Component & get(ssize_t i) const
Get the component at the given index.
Represent a SHA256 digest.
const Name & getName() const
get Name element
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
bool hasKeyLocator() const
Check if SignatureInfo block has a KeyLocator.
function< void(const shared_ptr< const Data > &)> OnDataValidated
Callback to report a successful Data validation.
Table::const_iterator iterator
TrustAnchorContainer m_staticContainer
function< void(const shared_ptr< const Interest > &)> OnInterestValidated
Callback to report a successful Interest validation.
DynamicContainers m_dynamicContainers
const size_t MIN_LENGTH
minimal number of components for Command Interest
static const shared_ptr< CertificateCache > DEFAULT_CERTIFICATE_CACHE
shared_ptr< CertificateCache > m_certificateCache
std::list< shared_ptr< v1::IdentityCertificate > > CertificateList
provides the interfaces for packet validation.
Provide a communication channel with local or remote NDN forwarder.
Name abstraction to represent an absolute name.
virtual void checkPolicy(const Data &data, int nSteps, const OnDataValidated &onValidated, const OnDataValidationFailed &onValidationFailed, std::vector< shared_ptr< ValidationRequest >> &nextSteps) override
Check the Data against policy and return the next validation step if necessary.
const ssize_t POS_SIG_VALUE
boost::asio::io_service & getIoService()
Return nullptr (cannot use IoService in simulations), preserved for API compatibility.
const time::system_clock::Duration & m_keyTimestampTtl
size_t size() const
Get the number of components.
uint64_t toNumber() const
Interpret this name component as nonNegativeInteger.
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
uint32_t getType() const
Get signature type.
static bool verifySignature(const Data &data, const v1::PublicKey &publicKey)
Verify the data using the publicKey.
const Signature & getSignature() const
bool m_shouldValidate
gives whether validation should be preformed
const KeyLocator & getKeyLocator() const
Get KeyLocator.
LastTimestampMap m_lastTimestamp
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...