security: Add configuration based validator
configuration file format can be found at: http://redmine.named-data.net/projects/ndn-cpp-dev/wiki/CommandValidatorConf
Change-Id: Icc2725f349aed7513f35f2cccdcd4463fadeef31
diff --git a/src/security/conf/checker.hpp b/src/security/conf/checker.hpp
new file mode 100644
index 0000000..1ec2323
--- /dev/null
+++ b/src/security/conf/checker.hpp
@@ -0,0 +1,481 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SECURITY_CONF_CHECKER_HPP
+#define NDN_SECURITY_CONF_CHECKER_HPP
+
+#include "key-locator-checker.hpp"
+#include "../../util/io.hpp"
+#include <boost/algorithm/string.hpp>
+
+#include "common.hpp"
+
+namespace ndn {
+namespace security {
+namespace conf {
+
+class Checker
+{
+public:
+ typedef function<void(const shared_ptr<const Interest>&)> OnInterestChecked;
+ typedef function<void(const shared_ptr<const Interest>&, const std::string&)> OnInterestCheckFailed;
+ typedef function<void(const shared_ptr<const Data>&)> OnDataChecked;
+ typedef function<void(const shared_ptr<const Data>&, const std::string&)> OnDataCheckFailed;
+
+
+ virtual
+ ~Checker()
+ {
+ }
+
+ /**
+ * @brief check if data satisfies condition defined in the specific checker implementation
+ *
+ * @param data Data packet
+ * @param onValidated Callback function which is called when data is immediately valid
+ * @param onValidationFailed Call function which is called when data is immediately invalid
+ * @return -1 if data is immediately invalid (onValidationFailed has been called)
+ * 1 if data is immediately valid (onValidated has been called)
+ * 0 if further signature verification is needed.
+ */
+ virtual int8_t
+ check(const Data& data,
+ const OnDataChecked& onValidated,
+ const OnDataCheckFailed& onValidationFailed) = 0;
+
+ /**
+ * @brief check if interest satisfies condition defined in the specific checker implementation
+ *
+ * @param interest Interest packet
+ * @param onValidated Callback function which is called when interest is immediately valid
+ * @param onValidationFailed Call function which is called when interest is immediately invalid
+ * @return -1 if interest is immediately invalid (onValidationFailed has been called)
+ * 1 if interest is immediately valid (onValidated has been called)
+ * 0 if further signature verification is needed.
+ */
+ virtual int8_t
+ check(const Interest& interest,
+ const OnInterestChecked& onValidated,
+ const OnInterestCheckFailed& onValidationFailed) = 0;
+};
+
+class CustomizedChecker : public Checker
+{
+ enum
+ {
+ INTEREST_SIG_VALUE = -1,
+ INTEREST_SIG_INFO = -2,
+ };
+
+public:
+ CustomizedChecker(uint32_t sigType,
+ shared_ptr<KeyLocatorChecker> keyLocatorChecker)
+ : m_sigType(sigType)
+ , m_keyLocatorChecker(keyLocatorChecker)
+ {
+ if (m_sigType == Signature::Sha256WithRsa && !static_cast<bool>(m_keyLocatorChecker))
+ throw Error("Strong signature requires KeyLocatorChecker");
+ }
+
+ virtual int8_t
+ check(const Data& data,
+ const OnDataChecked& onValidated,
+ const OnDataCheckFailed& onValidationFailed)
+ {
+ return check(data, data.getSignature(), onValidated, onValidationFailed);
+ }
+
+ virtual int8_t
+ check(const Interest& interest,
+ const OnInterestChecked& onValidated,
+ const OnInterestCheckFailed& onValidationFailed)
+ {
+ const Name& interestName = interest.getName();
+ Signature signature(interestName[INTEREST_SIG_INFO].blockFromValue(),
+ interestName[INTEREST_SIG_VALUE].blockFromValue());
+ return check(interest, signature, onValidated, onValidationFailed);
+ }
+
+private:
+ template<class Packet, class OnValidated, class OnFailed>
+ int8_t
+ check(const Packet& packet, const Signature& signature,
+ const OnValidated& onValidated,
+ const OnFailed& onValidationFailed)
+ {
+ if (m_sigType != signature.getType())
+ {
+ onValidationFailed(packet.shared_from_this(),
+ "Signature type does not match: " +
+ boost::lexical_cast<std::string>(m_sigType) +
+ "!=" +
+ boost::lexical_cast<std::string>(signature.getType()));
+ return -1;
+ }
+
+ switch (signature.getType())
+ {
+ case Signature::Sha256WithRsa:
+ {
+ try
+ {
+ SignatureSha256WithRsa sig(signature);
+
+ std::string failInfo;
+ if (m_keyLocatorChecker->check(packet, sig.getKeyLocator(), failInfo))
+ return 0;
+ else
+ {
+ onValidationFailed(packet.shared_from_this(), failInfo);
+ return -1;
+ }
+ }
+ catch (const SignatureSha256WithRsa::Error& e)
+ {
+ onValidationFailed(packet.shared_from_this(),
+ "Cannot decode Sha256WithRsa signature!");
+ return -1;
+ }
+ }
+ case Signature::Sha256:
+ return 0;
+ default:
+ {
+ onValidationFailed(packet.shared_from_this(),
+ "Unsupported signature type: " +
+ boost::lexical_cast<std::string>(signature.getType()));
+ return -1;
+ }
+ }
+ }
+
+private:
+ uint32_t m_sigType;
+ shared_ptr<KeyLocatorChecker> m_keyLocatorChecker;
+};
+
+class HierarchicalChecker : public CustomizedChecker
+{
+public:
+ HierarchicalChecker(uint32_t sigType)
+ : CustomizedChecker(sigType,
+ make_shared<HyperKeyLocatorNameChecker>("^(<>*)$", "\\1",
+ "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
+ "\\1\\2",
+ KeyLocatorChecker::RELATION_IS_PREFIX_OF))
+ {
+ }
+};
+
+class FixedSignerChecker : public Checker
+{
+ enum
+ {
+ INTEREST_SIG_VALUE = -1,
+ INTEREST_SIG_INFO = -2,
+ };
+public:
+ FixedSignerChecker(uint32_t sigType,
+ const std::vector<shared_ptr<IdentityCertificate> >& signers)
+ : m_sigType(sigType)
+ {
+ for (std::vector<shared_ptr<IdentityCertificate> >::const_iterator it = signers.begin();
+ it != signers.end(); it++)
+ m_signers[(*it)->getName().getPrefix(-1)] = (*it);
+ }
+
+ virtual int8_t
+ check(const Data& data,
+ const OnDataChecked& onValidated,
+ const OnDataCheckFailed& onValidationFailed)
+ {
+ return check(data, data.getSignature(), onValidated, onValidationFailed);
+ }
+
+ virtual int8_t
+ check(const Interest& interest,
+ const OnInterestChecked& onValidated,
+ const OnInterestCheckFailed& onValidationFailed)
+ {
+ const Name& interestName = interest.getName();
+ Signature signature(interestName[INTEREST_SIG_INFO].blockFromValue(),
+ interestName[INTEREST_SIG_VALUE].blockFromValue());
+ return check(interest, signature, onValidated, onValidationFailed);
+ }
+
+private:
+ template<class Packet, class OnValidated, class OnFailed>
+ int8_t
+ check(const Packet& packet, const Signature& signature,
+ const OnValidated& onValidated,
+ const OnFailed& onValidationFailed)
+ {
+ if (m_sigType != signature.getType())
+ {
+ onValidationFailed(packet.shared_from_this(),
+ "Signature type does not match: "
+ + boost::lexical_cast<std::string>(m_sigType)
+ + "!="
+ + boost::lexical_cast<std::string>(signature.getType()));
+ return -1;
+ }
+
+ switch(signature.getType())
+ {
+ case Signature::Sha256WithRsa:
+ {
+ try
+ {
+ SignatureSha256WithRsa sig(signature);
+
+ const Name& keyLocatorName = sig.getKeyLocator().getName();
+ if (m_signers.find(keyLocatorName) == m_signers.end())
+ {
+ onValidationFailed(packet.shared_from_this(),
+ "Signer is not in the fixed signer list: "
+ + keyLocatorName.toUri());
+ return -1;
+ }
+
+ if (Validator::verifySignature(packet, sig,
+ m_signers[keyLocatorName]->getPublicKeyInfo()))
+ {
+ onValidated(packet.shared_from_this());
+ return 1;
+ }
+ else
+ {
+ onValidationFailed(packet.shared_from_this(),
+ "Signature cannot be validated!");
+ return -1;
+ }
+ }
+ catch (const KeyLocator::Error& e)
+ {
+ onValidationFailed(packet.shared_from_this(),
+ "KeyLocator does not have name!");
+ return -1;
+ }
+ catch (const SignatureSha256WithRsa::Error& e)
+ {
+ onValidationFailed(packet.shared_from_this(),
+ "Cannot decode signature!");
+ return -1;
+ }
+ }
+ case Signature::Sha256:
+ {
+ onValidationFailed(packet.shared_from_this(),
+ "FixedSigner does not allow Sha256 signature type!");
+ return -1;
+ }
+ default:
+ {
+ onValidationFailed(packet.shared_from_this(),
+ "Unsupported signature type: "
+ + boost::lexical_cast<std::string>(signature.getType()));
+ return -1;
+ }
+ }
+ }
+
+private:
+ typedef std::map<Name, shared_ptr<IdentityCertificate> > SignerList;
+
+ uint32_t m_sigType;
+ SignerList m_signers;
+};
+
+class CheckerFactory
+{
+public:
+ /**
+ * @brief create a checker from configuration file.
+ *
+ * @param configSection The section containing the definition of checker.
+ * @param configFilename The configuration file name.
+ * @return a shared pointer to the created checker.
+ */
+ static shared_ptr<Checker>
+ create(const ConfigSection& configSection, const std::string& configFilename)
+ {
+ ConfigSection::const_iterator propertyIt = configSection.begin();
+
+ // Get checker.type
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
+ throw Error("Expect <checker.type>!");
+
+ std::string type = propertyIt->second.data();
+
+ if (boost::iequals(type, "customized"))
+ return createCustomizedChecker(configSection, configFilename);
+ else if (boost::iequals(type, "hierarchical"))
+ return createHierarchicalChecker(configSection, configFilename);
+ else if (boost::iequals(type, "fixed-signer"))
+ return createFixedSignerChecker(configSection, configFilename);
+ else
+ throw Error("Unsupported checker type: " + type);
+ }
+
+private:
+ static shared_ptr<Checker>
+ createCustomizedChecker(const ConfigSection& configSection,
+ const std::string& configFilename)
+ {
+ ConfigSection::const_iterator propertyIt = configSection.begin();
+ propertyIt++;
+
+ // Get checker.sig-type
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type"))
+ throw Error("Expect <checker.sig-type>!");
+
+ std::string sigType = propertyIt->second.data();
+ propertyIt++;
+
+ // Get checker.key-locator
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator"))
+ throw Error("Expect <checker.key-locator>!");
+
+ shared_ptr<KeyLocatorChecker> keyLocatorChecker =
+ KeyLocatorCheckerFactory::create(propertyIt->second, configFilename);
+ propertyIt++;
+
+ if (propertyIt != configSection.end())
+ throw Error("Expect the end of checker!");
+
+ return make_shared<CustomizedChecker>(boost::cref(getSigType(sigType)),
+ boost::cref(keyLocatorChecker));
+ }
+
+ static shared_ptr<Checker>
+ createHierarchicalChecker(const ConfigSection& configSection,
+ const std::string& configFilename)
+ {
+ ConfigSection::const_iterator propertyIt = configSection.begin();
+ propertyIt++;
+
+ // Get checker.sig-type
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type"))
+ throw Error("Expect <checker.sig-type>!");
+
+ std::string sigType = propertyIt->second.data();
+ propertyIt++;
+
+ if (propertyIt != configSection.end())
+ throw Error("Expect the end of checker!");
+
+ return make_shared<HierarchicalChecker>(boost::cref(getSigType(sigType)));
+ }
+
+ static shared_ptr<Checker>
+ createFixedSignerChecker(const ConfigSection& configSection,
+ const std::string& configFilename)
+ {
+ ConfigSection::const_iterator propertyIt = configSection.begin();
+ propertyIt++;
+
+ // Get checker.sig-type
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type"))
+ throw Error("Expect <checker.sig-type>!");
+
+ std::string sigType = propertyIt->second.data();
+ propertyIt++;
+
+ std::vector<shared_ptr<IdentityCertificate> > signers;
+ for (; propertyIt != configSection.end(); propertyIt++)
+ {
+ if (!boost::iequals(propertyIt->first, "signer"))
+ throw Error("Expect <checker.signer> but get <checker."
+ + propertyIt->first + ">");
+
+ signers.push_back(getSigner(propertyIt->second, configFilename));
+ }
+
+ if (propertyIt != configSection.end())
+ throw Error("Expect the end of checker!");
+
+ return shared_ptr<FixedSignerChecker>(new FixedSignerChecker(getSigType(sigType),
+ signers));
+ }
+
+ static shared_ptr<IdentityCertificate>
+ getSigner(const ConfigSection& configSection, const std::string& configFilename)
+ {
+ using namespace boost::filesystem;
+
+ ConfigSection::const_iterator propertyIt = configSection.begin();
+
+ // Get checker.signer.type
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
+ throw Error("Expect <checker.signer.type>!");
+
+ std::string type = propertyIt->second.data();
+ propertyIt++;
+
+ if (boost::iequals(type, "file"))
+ {
+ // Get checker.signer.file-name
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name"))
+ throw Error("Expect <checker.signer.file-name>!");
+
+ path certfilePath = absolute(propertyIt->second.data(),
+ path(configFilename).parent_path());
+ propertyIt++;
+
+ if (propertyIt != configSection.end())
+ throw Error("Expect the end of checker.signer");
+
+ shared_ptr<IdentityCertificate> idCert
+ = io::load<IdentityCertificate>(certfilePath.c_str());
+
+ if (static_cast<bool>(idCert))
+ return idCert;
+ else
+ throw Error("Cannot read certificate from file: "
+ + certfilePath.native());
+ }
+ else if (boost::iequals(type, "base64"))
+ {
+ // Get checker.signer.base64-string
+ if (propertyIt == configSection.end() ||
+ !boost::iequals(propertyIt->first, "base64-string"))
+ throw Error("Expect <checker.signer.base64-string>!");
+
+ std::stringstream ss(propertyIt->second.data());
+ propertyIt++;
+
+ if (propertyIt != configSection.end())
+ throw Error("Expect the end of checker.signer");
+
+ shared_ptr<IdentityCertificate> idCert = io::load<IdentityCertificate>(ss);
+
+ if (static_cast<bool>(idCert))
+ return idCert;
+ else
+ throw Error("Cannot decode certificate from string");
+ }
+ else
+ throw Error("Unsupported checker.signer type: " + type);
+ }
+
+ static int32_t
+ getSigType(const std::string& sigType)
+ {
+ if (boost::iequals(sigType, "rsa-sha256"))
+ return Signature::Sha256WithRsa;
+ else if (boost::iequals(sigType, "sha256"))
+ return Signature::Sha256;
+ else
+ return -1;
+ }
+};
+
+} // namespace conf
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_SEC_CONF_RULE_SIGNER_HPP
diff --git a/src/security/conf/common.hpp b/src/security/conf/common.hpp
new file mode 100644
index 0000000..ba68e2a
--- /dev/null
+++ b/src/security/conf/common.hpp
@@ -0,0 +1,34 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SECURITY_CONF_COMMON_HPP
+#define NDN_SECURITY_CONF_COMMON_HPP
+
+#include <string>
+#include <boost/property_tree/ptree.hpp>
+
+namespace ndn {
+namespace security {
+namespace conf {
+
+typedef boost::property_tree::ptree ConfigSection;
+
+class Error : public std::runtime_error
+{
+public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+};
+
+} // namespace conf
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_CONF_COMMON_HPP
diff --git a/src/security/conf/filter.hpp b/src/security/conf/filter.hpp
new file mode 100644
index 0000000..1db7498
--- /dev/null
+++ b/src/security/conf/filter.hpp
@@ -0,0 +1,224 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SECURITY_CONF_FILTER_HPP
+#define NDN_SECURITY_CONF_FILTER_HPP
+
+#include "../../common.hpp"
+#include "../../data.hpp"
+#include "../../interest.hpp"
+#include "../../util/regex.hpp"
+#include <boost/algorithm/string.hpp>
+
+#include "common.hpp"
+
+namespace ndn {
+namespace security {
+namespace conf {
+
+class Filter
+{
+public:
+ virtual
+ ~Filter()
+ {
+ }
+
+ virtual bool
+ match(const Data& data) = 0;
+
+ virtual bool
+ match(const Interest& interest) = 0;
+};
+
+class RelationNameFilter : public Filter
+{
+public:
+ enum Relation
+ {
+ RELATION_EQUAL,
+ RELATION_IS_PREFIX_OF,
+ RELATION_IS_STRICT_PREFIX_OF,
+ };
+
+ RelationNameFilter(const Name& name, Relation relation)
+ : m_name(name)
+ , m_relation(relation)
+ {
+ }
+
+ virtual
+ ~RelationNameFilter()
+ {
+ }
+
+ virtual bool
+ match(const Data& data)
+ {
+ return match(data.getName());
+ }
+
+ virtual bool
+ match(const Interest& interest)
+ {
+ if (interest.getName().size() < 2)
+ return false;
+
+ Name signedName = interest.getName().getPrefix(-2);
+ return match(signedName);
+ }
+
+private:
+ bool
+ match(const Name& name)
+ {
+ switch (m_relation)
+ {
+ case RELATION_EQUAL:
+ return (name == m_name);
+ case RELATION_IS_PREFIX_OF:
+ return m_name.isPrefixOf(name);
+ case RELATION_IS_STRICT_PREFIX_OF:
+ return (m_name.isPrefixOf(name) && m_name != name);
+ default:
+ return false;
+ }
+ }
+
+private:
+ Name m_name;
+ Relation m_relation;
+};
+
+class RegexNameFilter : public Filter
+{
+public:
+ explicit
+ RegexNameFilter(const Regex& regex)
+ : m_regex(regex)
+ {
+ }
+
+ virtual
+ ~RegexNameFilter()
+ {
+ }
+
+ virtual bool
+ match(const Data& data)
+ {
+ return m_regex.match(data.getName());
+ }
+
+ virtual bool
+ match(const Interest& interest)
+ {
+ if (interest.getName().size() < 2)
+ return false;
+
+ Name signedName = interest.getName().getPrefix(-2);
+ return m_regex.match(signedName);
+ }
+
+private:
+ Regex m_regex;
+};
+
+class FilterFactory
+{
+public:
+ static shared_ptr<Filter>
+ create(const ConfigSection& configSection)
+ {
+ ConfigSection::const_iterator propertyIt = configSection.begin();
+
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
+ throw Error("Expect <filter.type>!");
+
+ std::string type = propertyIt->second.data();
+
+ if (boost::iequals(type, "name"))
+ return createNameFilter(configSection);
+ else
+ throw Error("Unsupported filter.type: " + type);
+ }
+private:
+ static shared_ptr<Filter>
+ createNameFilter(const ConfigSection& configSection)
+ {
+ ConfigSection::const_iterator propertyIt = configSection.begin();
+ propertyIt++;
+
+ if (propertyIt == configSection.end())
+ throw Error("Expect more properties for filter(name)");
+
+ if (boost::iequals(propertyIt->first, "name"))
+ {
+ // Get filter.name
+ Name name;
+ try
+ {
+ name = Name(propertyIt->second.data());
+ }
+ catch (Name::Error& e)
+ {
+ throw Error("Wrong filter.name: " + propertyIt->second.data());
+ }
+
+ propertyIt++;
+
+ // Get filter.relation
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation"))
+ throw Error("Expect <filter.relation>!");
+
+ std::string relationString = propertyIt->second.data();
+ propertyIt++;
+
+ RelationNameFilter::Relation relation;
+ if (boost::iequals(relationString, "equal"))
+ relation = RelationNameFilter::RELATION_EQUAL;
+ else if (boost::iequals(relationString, "is-prefix-of"))
+ relation = RelationNameFilter::RELATION_IS_PREFIX_OF;
+ else if (boost::iequals(relationString, "is-strict-prefix-of"))
+ relation = RelationNameFilter::RELATION_IS_STRICT_PREFIX_OF;
+ else
+ throw Error("Unsupported relation: " + relationString);
+
+
+ if (propertyIt != configSection.end())
+ throw Error("Expect the end of filter!");
+
+ return make_shared<RelationNameFilter>(boost::cref(name),
+ boost::cref(relation));
+ }
+ else if (boost::iequals(propertyIt->first, "regex"))
+ {
+ std::string regexString = propertyIt->second.data();
+ propertyIt++;
+
+ if (propertyIt != configSection.end())
+ throw Error("Expect the end of filter!");
+
+ try
+ {
+ return shared_ptr<RegexNameFilter>(new RegexNameFilter(regexString));
+ }
+ catch (const Regex::Error& e)
+ {
+ throw Error("Wrong filter.regex: " + regexString);
+ }
+ }
+ else
+ throw Error("Wrong filter(name) properties");
+ }
+};
+
+} // namespace conf
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_CONF_FILTER_HPP
diff --git a/src/security/conf/key-locator-checker.hpp b/src/security/conf/key-locator-checker.hpp
new file mode 100644
index 0000000..0f667f7
--- /dev/null
+++ b/src/security/conf/key-locator-checker.hpp
@@ -0,0 +1,362 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SECURITY_CONF_KEY_LOCATOR_CHECKER_HPP
+#define NDN_SECURITY_CONF_KEY_LOCATOR_CHECKER_HPP
+
+#include "../../common.hpp"
+#include "../../data.hpp"
+#include "../../interest.hpp"
+#include <boost/algorithm/string.hpp>
+
+#include "common.hpp"
+
+namespace ndn {
+namespace security {
+namespace conf {
+
+class KeyLocatorCheckerFactory;
+
+class KeyLocatorChecker
+{
+public:
+ enum Relation
+ {
+ RELATION_EQUAL,
+ RELATION_IS_PREFIX_OF,
+ RELATION_IS_STRICT_PREFIX_OF,
+ };
+
+ virtual
+ ~KeyLocatorChecker()
+ {
+ }
+
+ bool
+ check(const Data& data,
+ const KeyLocator& keyLocator,
+ std::string& failInfo)
+ {
+ return check(data.getName(), keyLocator, failInfo);
+ }
+
+ bool
+ check(const Interest& interest,
+ const KeyLocator& keyLocator,
+ std::string& failInfo)
+ {
+ if (interest.getName().size() < 2)
+ {
+ failInfo = "No Signature";
+ return false;
+ }
+
+ Name signedName = interest.getName().getPrefix(-2);
+ return check(signedName, keyLocator, failInfo);
+ }
+
+protected:
+
+ virtual bool
+ check(const Name& packetName,
+ const KeyLocator& keyLocator,
+ std::string& failInfo) = 0;
+
+ bool
+ checkRelation(const Relation& relation, const Name& name1, const Name& name2)
+ {
+ switch (relation)
+ {
+ case RELATION_EQUAL:
+ return (name1 == name2);
+ case RELATION_IS_PREFIX_OF:
+ return name1.isPrefixOf(name2);
+ case RELATION_IS_STRICT_PREFIX_OF:
+ return (name1.isPrefixOf(name2) && name1 != name2);
+ default:
+ return false;
+ }
+ }
+};
+
+class RelationKeyLocatorNameChecker : public KeyLocatorChecker
+{
+public:
+ RelationKeyLocatorNameChecker(const Name& name,
+ const KeyLocatorChecker::Relation& relation)
+ : m_name(name)
+ , m_relation(relation)
+ {
+ }
+
+protected:
+ virtual bool
+ check(const Name& packetName,
+ const KeyLocator& keyLocator,
+ std::string& failInfo)
+ {
+ try
+ {
+ if (checkRelation(m_relation, m_name, keyLocator.getName()))
+ return true;
+
+ failInfo = "KeyLocatorChecker failed!";
+ return false;
+ }
+ catch (const KeyLocator::Error& e)
+ {
+ failInfo = "KeyLocator does not have name";
+ return false;
+ }
+ }
+
+private:
+ Name m_name;
+ KeyLocatorChecker::Relation m_relation;
+};
+
+class RegexKeyLocatorNameChecker : public KeyLocatorChecker
+{
+public:
+ RegexKeyLocatorNameChecker(const Regex& regex)
+ : m_regex(regex)
+ {
+ }
+
+protected:
+ virtual bool
+ check(const Name& packetName,
+ const KeyLocator& keyLocator,
+ std::string& failInfo)
+ {
+ try
+ {
+ if (m_regex.match(keyLocator.getName()))
+ return true;
+
+ failInfo = "KeyLocatorChecker failed!";
+ return false;
+ }
+ catch (const KeyLocator::Error& e)
+ {
+ failInfo = "KeyLocator does not have name";
+ return false;
+ }
+ }
+
+private:
+ Regex m_regex;
+};
+
+class HyperKeyLocatorNameChecker : public KeyLocatorChecker
+{
+public:
+ HyperKeyLocatorNameChecker(const std::string& pExpr, const std::string pExpand,
+ const std::string& kExpr, const std::string kExpand,
+ const Relation& hyperRelation)
+ : m_hyperPRegex(new Regex(pExpr, pExpand))
+ , m_hyperKRegex(new Regex(kExpr, kExpand))
+ , m_hyperRelation(hyperRelation)
+ {
+ }
+
+protected:
+ virtual bool
+ check(const Name& packetName,
+ const KeyLocator& keyLocator,
+ std::string& failInfo)
+ {
+ try
+ {
+ if (m_hyperPRegex->match(packetName) &&
+ m_hyperKRegex->match(keyLocator.getName()) &&
+ checkRelation(m_hyperRelation,
+ m_hyperKRegex->expand(),
+ m_hyperPRegex->expand()))
+ return true;
+
+ failInfo = "KeyLocatorChecker failed!";
+ return false;
+ }
+ catch (const KeyLocator::Error& e)
+ {
+ failInfo = "KeyLocator does not have name";
+ return false;
+ }
+
+ }
+
+private:
+ shared_ptr<Regex> m_hyperPRegex;
+ shared_ptr<Regex> m_hyperKRegex;
+ Relation m_hyperRelation;
+};
+
+
+class KeyLocatorCheckerFactory
+{
+public:
+ static shared_ptr<KeyLocatorChecker>
+ create(const ConfigSection& configSection, const std::string& filename)
+ {
+ ConfigSection::const_iterator propertyIt = configSection.begin();
+
+ // Get checker.key-locator.type
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
+ throw Error("Expect <checker.key-locator.type>!");
+
+ std::string type = propertyIt->second.data();
+
+ if (boost::iequals(type, "name"))
+ return createKeyLocatorNameChecker(configSection, filename);
+ else
+ throw Error("Unsupported checker.key-locator.type: " + type);
+ }
+
+private:
+ static shared_ptr<KeyLocatorChecker>
+ createKeyLocatorNameChecker(const ConfigSection& configSection,
+ const std::string& filename)
+ {
+ ConfigSection::const_iterator propertyIt = configSection.begin();
+ propertyIt++;
+
+ if (propertyIt == configSection.end())
+ throw Error("Expect more checker.key-locator properties");
+
+ if (boost::iequals(propertyIt->first, "name"))
+ {
+ Name name;
+ try
+ {
+ name = Name(propertyIt->second.data());
+ }
+ catch (Name::Error& e)
+ {
+ throw Error("Invalid checker.key-locator.name: "
+ + propertyIt->second.data());
+ }
+ propertyIt++;
+
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation"))
+ throw Error("Expect <checker.key-locator.relation>!");
+
+ std::string relationString = propertyIt->second.data();
+ propertyIt++;
+
+ KeyLocatorChecker::Relation relation;
+ if (boost::iequals(relationString, "equal"))
+ relation = KeyLocatorChecker::RELATION_EQUAL;
+ else if (boost::iequals(relationString, "is-prefix-of"))
+ relation = KeyLocatorChecker::RELATION_IS_PREFIX_OF;
+ else if (boost::iequals(relationString, "is-strict-prefix-of"))
+ relation = KeyLocatorChecker::RELATION_IS_STRICT_PREFIX_OF;
+ else
+ throw Error("Unsupported relation: " + relationString);
+
+ if (propertyIt != configSection.end())
+ throw Error("Expect the end of checker.key-locator!");
+
+ return shared_ptr<RelationKeyLocatorNameChecker>
+ (new RelationKeyLocatorNameChecker(name, relation));
+ }
+ else if (boost::iequals(propertyIt->first, "regex"))
+ {
+ std::string regexString = propertyIt->second.data();
+ propertyIt++;
+
+ if (propertyIt != configSection.end())
+ throw Error("Expect the end of checker.key-locator!");
+
+ try
+ {
+ return shared_ptr<RegexKeyLocatorNameChecker>
+ (new RegexKeyLocatorNameChecker(regexString));
+ }
+ catch (const Regex::Error& e)
+ {
+ throw Error("Invalid checker.key-locator.regex: " + regexString);
+ }
+ }
+ else if (boost::iequals(propertyIt->first, "hyper-relation"))
+ {
+ const ConfigSection& hSection = propertyIt->second;
+
+ ConfigSection::const_iterator hPropertyIt = hSection.begin();
+
+ // Get k-regex
+ if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-regex"))
+ throw Error("Expect <checker.key-locator.hyper-relation.k-regex>!");
+
+ std::string kRegex = hPropertyIt->second.data();
+ hPropertyIt++;
+
+ // Get k-expand
+ if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-expand"))
+ throw Error("Expect <checker.key-locator.hyper-relation.k-expand>!");
+
+ std::string kExpand = hPropertyIt->second.data();
+ hPropertyIt++;
+
+ // Get h-relation
+ if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "h-relation"))
+ throw Error("Expect <checker.key-locator.hyper-relation.h-relation>!");
+
+ std::string hRelation = hPropertyIt->second.data();
+ hPropertyIt++;
+
+ // Get p-regex
+ if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-regex"))
+ throw Error("Expect <checker.key-locator.hyper-relation.p-regex>!");
+
+ std::string pRegex = hPropertyIt->second.data();
+ hPropertyIt++;
+
+ // Get p-expand
+ if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-expand"))
+ throw Error("Expect <checker.key-locator.hyper-relation.p-expand>!");
+
+ std::string pExpand = hPropertyIt->second.data();
+ hPropertyIt++;
+
+ if (hPropertyIt != hSection.end())
+ throw Error("Expect the end of checker.key-locator.hyper-relation!");
+
+ KeyLocatorChecker::Relation relation;
+ if (boost::iequals(hRelation, "equal"))
+ relation = KeyLocatorChecker::RELATION_EQUAL;
+ else if (boost::iequals(hRelation, "is-prefix-of"))
+ relation = KeyLocatorChecker::RELATION_IS_PREFIX_OF;
+ else if (boost::iequals(hRelation, "is-strict-prefix-of"))
+ relation = KeyLocatorChecker::RELATION_IS_STRICT_PREFIX_OF;
+ else
+ throw Error("Unsupported checker.key-locator.hyper-relation.h-relation: "
+ + hRelation);
+
+ try
+ {
+ return shared_ptr<HyperKeyLocatorNameChecker>
+ (new HyperKeyLocatorNameChecker(pRegex, pExpand,
+ kRegex, kExpand,
+ relation));
+ }
+ catch (const Regex::Error& e)
+ {
+ throw Error("Invalid regex for key-locator.hyper-relation");
+ }
+ }
+ else
+ throw Error("Unsupported checker.key-locator");
+ }
+};
+
+
+} // namespace conf
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_CONF_KEY_LOCATOR_CHECKER_HPP
diff --git a/src/security/conf/rule.hpp b/src/security/conf/rule.hpp
new file mode 100644
index 0000000..560c440
--- /dev/null
+++ b/src/security/conf/rule.hpp
@@ -0,0 +1,106 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SECURITY_CONF_RULE_HPP
+#define NDN_SECURITY_CONF_RULE_HPP
+
+#include "filter.hpp"
+#include "checker.hpp"
+
+
+namespace ndn {
+namespace security {
+namespace conf {
+
+template<class Packet>
+class Rule
+{
+public:
+ Rule(const std::string& id)
+ : m_id(id)
+ {
+ }
+
+ virtual
+ ~Rule()
+ {
+ }
+
+ const std::string&
+ getId()
+ {
+ return m_id;
+ }
+
+ void
+ addFilter(const shared_ptr<Filter>& filter)
+ {
+ m_filters.push_back(filter);
+ }
+
+ void
+ addChecker(const shared_ptr<Checker>& checker)
+ {
+ m_checkers.push_back(checker);
+ }
+
+ bool
+ match(const Packet& packet)
+ {
+ if (m_filters.empty())
+ return true;
+
+ for (FilterList::iterator it = m_filters.begin();
+ it != m_filters.end(); it++)
+ {
+ if (!(*it)->match(packet))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @brief check if packet satisfies certain condition
+ *
+ * @param packet The packet
+ * @param onValidated Callback function which is called when packet is immediately valid
+ * @param onValidationFailed Call function which is called when packet is immediately invalid
+ * @return -1 if packet is immediately invalid (onValidationFailed has been called)
+ * 1 if packet is immediately valid (onValidated has been called)
+ * 0 if further signature verification is needed.
+ */
+ template<class ValidatedCallback, class ValidationFailureCallback>
+ int8_t
+ check(const Packet& packet,
+ const ValidatedCallback& onValidated,
+ const ValidationFailureCallback& onValidationFailed)
+ {
+ for (CheckerList::iterator it = m_checkers.begin();
+ it != m_checkers.end(); it++)
+ {
+ int8_t result = (*it)->check(packet, onValidated, onValidationFailed);
+ if (result >= 0)
+ return result;
+ }
+ return -1;
+ }
+
+private:
+ typedef std::vector<shared_ptr<Filter> > FilterList;
+ typedef std::vector<shared_ptr<Checker> > CheckerList;
+
+ std::string m_id;
+ FilterList m_filters;
+ CheckerList m_checkers;
+};
+
+} // namespace conf
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_CONF_RULE_HPP