security: Convert ValidatorConfig to ValidationPolicyConfig
The security API also provides a convenience ValidatorConfig helper.
Change-Id: Ic86dec4904b917361cb4740204de4b6710d2a386
Refs: #3920
diff --git a/src/security/v2/validator-config/checker.cpp b/src/security/v2/validator-config/checker.cpp
new file mode 100644
index 0000000..47415af
--- /dev/null
+++ b/src/security/v2/validator-config/checker.cpp
@@ -0,0 +1,334 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "checker.hpp"
+#include "security/v2/validation-state.hpp"
+#include "security/verification-helpers.hpp"
+#include "security/pib/key.hpp"
+#include "util/logger.hpp"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace validator_config {
+
+bool
+Checker::check(uint32_t pktType, const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
+{
+ BOOST_ASSERT(pktType == tlv::Interest || pktType == tlv::Data);
+
+ if (pktType == tlv::Interest) {
+ if (pktName.size() < signed_interest::MIN_SIZE)
+ return false;
+
+ return checkNames(pktName.getPrefix(-signed_interest::MIN_SIZE), klName, state);
+ }
+ else {
+ return checkNames(pktName, klName, state);
+ }
+}
+
+NameRelationChecker::NameRelationChecker(const Name& name, const NameRelation& relation)
+ : m_name(name)
+ , m_relation(relation)
+{
+}
+
+bool
+NameRelationChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
+{
+ // pktName not used in this check
+ Name identity = extractIdentityFromKeyName(klName);
+ bool result = checkNameRelation(m_relation, m_name, identity);
+ if (!result) {
+ std::ostringstream os;
+ os << "KeyLocator check failed: name relation " << m_name << " " << m_relation
+ << " for packet " << pktName << " is invalid"
+ << " (KeyLocator=" << klName << ", identity=" << identity << ")";
+ state->fail({ValidationError::POLICY_ERROR, os.str()});
+ }
+ return result;
+}
+
+RegexChecker::RegexChecker(const Regex& regex)
+ : m_regex(regex)
+{
+}
+
+bool
+RegexChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
+{
+ // pktName not used in this check
+ Name identity = extractIdentityFromKeyName(klName);
+ bool result = m_regex.match(identity);
+ if (!result) {
+ std::ostringstream os;
+ os << "KeyLocator check failed: regex " << m_regex << " for packet " << pktName << " is invalid"
+ << " (KeyLocator=" << klName << ", identity=" << identity << ")";
+ state->fail({ValidationError::POLICY_ERROR, os.str()});
+ }
+
+ return result;
+}
+
+HyperRelationChecker::HyperRelationChecker(const std::string& pktNameExpr, const std::string pktNameExpand,
+ const std::string& klNameExpr, const std::string klNameExpand,
+ const NameRelation& hyperRelation)
+ : m_hyperPRegex(pktNameExpr, pktNameExpand)
+ , m_hyperKRegex(klNameExpr, klNameExpand)
+ , m_hyperRelation(hyperRelation)
+{
+}
+
+bool
+HyperRelationChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr<ValidationState>& state)
+{
+ if (!m_hyperPRegex.match(pktName) || !m_hyperKRegex.match(klName)) {
+ std::ostringstream os;
+ os << "Packet " << pktName << " (" << "KeyLocator=" << klName << ") does not match "
+ << "the hyper relation rule pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex;
+ state->fail({ValidationError::POLICY_ERROR, os.str()});
+ return false;
+ }
+
+ bool result = checkNameRelation(m_hyperRelation, m_hyperKRegex.expand(), m_hyperPRegex.expand());
+ if (!result) {
+ std::ostringstream os;
+ os << "KeyLocator check failed: hyper relation " << m_hyperRelation
+ << " pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex
+ << " of packet " << pktName << " (KeyLocator=" << klName << ") is invalid";
+ state->fail({ValidationError::POLICY_ERROR, os.str()});
+ }
+ return result;
+}
+
+unique_ptr<Checker>
+Checker::create(const ConfigSection& configSection, const std::string& configFilename)
+{
+ auto propertyIt = configSection.begin();
+
+ // Get checker.type
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) {
+ BOOST_THROW_EXCEPTION(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 {
+ BOOST_THROW_EXCEPTION(Error("Unsupported checker type: " + type));
+ }
+}
+
+unique_ptr<Checker>
+Checker::createCustomizedChecker(const ConfigSection& configSection,
+ const std::string& configFilename)
+{
+ auto propertyIt = configSection.begin();
+ propertyIt++;
+
+ // TODO implement restrictions based on signature type (outside this checker)
+
+ if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
+ // ignore sig-type
+ propertyIt++;
+ }
+
+ // Get checker.key-locator
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator")) {
+ BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator>"));
+ }
+
+ auto checker = createKeyLocatorChecker(propertyIt->second, configFilename);
+ propertyIt++;
+
+ if (propertyIt != configSection.end()) {
+ BOOST_THROW_EXCEPTION(Error("Expect the end of checker"));
+ }
+
+ return checker;
+}
+
+unique_ptr<Checker>
+Checker::createHierarchicalChecker(const ConfigSection& configSection,
+ const std::string& configFilename)
+{
+ auto propertyIt = configSection.begin();
+ propertyIt++;
+
+ // TODO implement restrictions based on signature type (outside this checker)
+
+ if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) {
+ // ignore sig-type
+ propertyIt++;
+ }
+
+ if (propertyIt != configSection.end()) {
+ BOOST_THROW_EXCEPTION(Error("Expect the end of checker"));
+ }
+
+ return make_unique<HyperRelationChecker>("^(<>*)$", "\\1",
+ "^(<>*)<KEY><>$", "\\1",
+ NameRelation::IS_PREFIX_OF);
+}
+
+///
+
+unique_ptr<Checker>
+Checker::createKeyLocatorChecker(const ConfigSection& configSection, const std::string& configFilename)
+{
+ auto propertyIt = configSection.begin();
+
+ // Get checker.key-locator.type
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
+ BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.type>"));
+
+ std::string type = propertyIt->second.data();
+
+ if (boost::iequals(type, "name"))
+ return createKeyLocatorNameChecker(configSection, configFilename);
+ else
+ BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator.type: " + type));
+}
+
+unique_ptr<Checker>
+Checker::createKeyLocatorNameChecker(const ConfigSection& configSection, const std::string& configFilename)
+{
+ auto propertyIt = configSection.begin();
+ propertyIt++;
+
+ if (propertyIt == configSection.end())
+ BOOST_THROW_EXCEPTION(Error("Expect more checker.key-locator properties"));
+
+ if (boost::iequals(propertyIt->first, "name")) {
+ Name name;
+ try {
+ name = Name(propertyIt->second.data());
+ }
+ catch (const Name::Error& e) {
+ BOOST_THROW_EXCEPTION(Error("Invalid checker.key-locator.name: " + propertyIt->second.data()));
+ }
+ propertyIt++;
+
+ if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) {
+ BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.relation>"));
+ }
+
+ std::string relationString = propertyIt->second.data();
+ propertyIt++;
+
+ NameRelation relation = getNameRelationFromString(relationString);
+
+ if (propertyIt != configSection.end()) {
+ BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator"));
+ }
+ return make_unique<NameRelationChecker>(name, relation);
+ }
+ else if (boost::iequals(propertyIt->first, "regex")) {
+ std::string regexString = propertyIt->second.data();
+ propertyIt++;
+
+ if (propertyIt != configSection.end()) {
+ BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator"));
+ }
+
+ try {
+ return make_unique<RegexChecker>(regexString);
+ }
+ catch (const Regex::Error& e) {
+ BOOST_THROW_EXCEPTION(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")) {
+ BOOST_THROW_EXCEPTION(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")) {
+ BOOST_THROW_EXCEPTION(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")) {
+ BOOST_THROW_EXCEPTION(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")) {
+ BOOST_THROW_EXCEPTION(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")) {
+ BOOST_THROW_EXCEPTION(Error("Expect <checker.key-locator.hyper-relation.p-expand>"));
+ }
+
+ std::string pExpand = hPropertyIt->second.data();
+ hPropertyIt++;
+
+ if (hPropertyIt != hSection.end()) {
+ BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator.hyper-relation"));
+ }
+
+ NameRelation relation = getNameRelationFromString(hRelation);
+ try {
+ return make_unique<HyperRelationChecker>(pRegex, pExpand, kRegex, kExpand, relation);
+ }
+ catch (const Regex::Error& e) {
+ BOOST_THROW_EXCEPTION(Error("Invalid regex for key-locator.hyper-relation"));
+ }
+ }
+ else {
+ BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator"));
+ }
+}
+
+} // namespace validator_config
+} // namespace v2
+} // namespace security
+} // namespace ndn