add Validator
Change-Id: Ib8ce9023aad0782f934e8e6e559840b559d68208
diff --git a/log4cxx.properties.sample.in b/log4cxx.properties.sample.in
new file mode 100644
index 0000000..15a36d7
--- /dev/null
+++ b/log4cxx.properties.sample.in
@@ -0,0 +1,9 @@
+log4j.rootLogger=TRACE, A1
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+
+# Print the date in ISO 8601 format
+log4j.appender.A1.layout.ConversionPattern=%-5p %-15c - %m%n
+
+# Print only messages of level WARN or above in the package com.foo.
+#log4j.logger.com.foo=WARN
\ No newline at end of file
diff --git a/src/validator.cpp b/src/validator.cpp
new file mode 100644
index 0000000..721b311
--- /dev/null
+++ b/src/validator.cpp
@@ -0,0 +1,125 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "logger.hpp"
+#include "config.hpp"
+#include "validator.hpp"
+
+#include "ndn-cxx/data.hpp"
+#include <ndn-cxx/security/validator-config.hpp>
+
+
+namespace ndn {
+namespace ndns {
+NDNS_LOG_INIT("validator");
+
+std::string Validator::VALIDATOR_CONF_FILE = DEFAULT_CONFIG_PATH "/" "validator.conf";
+
+Validator::Validator(Face& face, const std::string& confFile /* = VALIDATOR_CONF_FILE */)
+ : ValidatorConfig(face)
+{
+ try {
+ this->load(confFile);
+ NDNS_LOG_TRACE("Validator loads configuration: " << confFile);
+ }
+ catch (std::exception&) {
+ std::string config =
+ "rule \n"
+ "{ \n"
+ " id \"NDNS Validator\" \n"
+ " for data \n"
+ " checker \n"
+ " { \n"
+ " type customized \n"
+ " sig-type rsa-sha256 \n"
+ " key-locator \n"
+ " { \n"
+ " type name \n"
+ " hyper-relation \n"
+ " { \n"
+ " k-regex ^(<>*)<KEY>(<>*)<><ID-CERT>$ \n"
+ " k-expand \\\\1\\\\2 \n"
+ " h-relation is-prefix-of \n"
+ " p-regex ^(<>*)[<KEY><NDNS>](<>*)<><>$ \n"
+ " p-expand \\\\1\\\\2 \n"
+ " } \n"
+ " } \n"
+ " } \n"
+ "} \n"
+ " \n"
+ " \n"
+ "trust-anchor \n"
+ "{ \n"
+ " type file \n"
+ " file-name \""
+ ;
+
+ config += "anchors/root.cert";
+
+ config +=
+ "\" \n"
+ "} \n"
+ " \n"
+ ;
+
+ this->load(config, "embededConf");
+ NDNS_LOG_TRACE("Validator loads embedded configuration with anchors path: anchors/root.cert");
+ }
+
+}
+
+void
+Validator::validate(const Data& data,
+ const OnDataValidated& onValidated,
+ const OnDataValidationFailed& onValidationFailed)
+{
+ NDNS_LOG_TRACE("[* ?? *] verify data: " << data.getName() << ". KeyLocator: "
+ << data.getSignature().getKeyLocator().getName());
+ ValidatorConfig::validate(data,
+ [this, onValidated](const shared_ptr<const Data>& data)
+ // onValidated here cannot use reference, since this is non-block
+ {
+ onValidated(data);
+ this->onDataValidated(data);
+ },
+ [this, onValidationFailed](const shared_ptr<const Data>& data,
+ const std::string& str)
+ {
+ onValidationFailed(data, str);
+ this->onDataValidationFailed(data, str);
+ }
+ );
+}
+
+void
+Validator::onDataValidated(const shared_ptr<const Data>& data)
+{
+ NDNS_LOG_TRACE("[* VV *] pass validation: " << data->getName() << ". KeyLocator = "
+ << data->getSignature().getKeyLocator().getName());
+}
+
+void
+Validator::onDataValidationFailed(const shared_ptr<const Data>& data, const std::string& str)
+{
+ NDNS_LOG_WARN("[* XX *] fail validation: " << data->getName() << ". due to: " << str
+ << ". KeyLocator = " << data->getSignature().getKeyLocator().getName());
+}
+
+} // namespace ndns
+} // namespace ndn
diff --git a/src/validator.hpp b/src/validator.hpp
new file mode 100644
index 0000000..dc7f656
--- /dev/null
+++ b/src/validator.hpp
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NDNS_VALIDATOR_HPP
+#define NDNS_VALIDATOR_HPP
+
+#include "config.hpp"
+
+#include "ndn-cxx/data.hpp"
+#include <ndn-cxx/security/validator-config.hpp>
+
+
+namespace ndn {
+namespace ndns {
+
+/**
+ * @brief NDNS validator, which validates Data with hierarchical way. Validator is used in three
+ * scenarios:
+ * 1) Dig client gets the final response Data;
+ * 2) Authoritative name server receives update request;
+ * 3) Update client gets the result of update request.
+ *
+ * @note Compared to its parent class, ValidatorConfig, the class provides is customized according
+ * to config file and the above working scenarios:
+ * 1) give the default path of config file;
+ * 2) default rule is the given path if not valid or the content is wrong.
+ * Validator rule is must for NDNS, the daemon/dig/update must work even without manually edit
+ * 3) some wrapper provides default behavior when verification succeeds or fails
+ */
+class Validator : public ValidatorConfig
+{
+
+public:
+ static std::string VALIDATOR_CONF_FILE;
+
+ /**
+ * @brief the callback function which is called after validation finishes
+ * @param[in] callback The function is called after validation finishes, no matter validation
+ * succeeds or fails
+ */
+ explicit
+ Validator(Face& face, const std::string& confFile = VALIDATOR_CONF_FILE);
+
+ /**
+ * @brief validate the Data
+ */
+ virtual void
+ validate(const Data& data,
+ const OnDataValidated& onValidated,
+ const OnDataValidationFailed& onValidationFailed);
+
+private:
+ /**
+ * @brief the default callback function on data validated
+ */
+ void
+ onDataValidated(const shared_ptr<const Data>& data);
+
+ /**
+ * @brief the default callback function on data validation failed
+ */
+ void
+ onDataValidationFailed(const shared_ptr<const Data>& data, const std::string& str);
+
+};
+
+
+} // namespace ndns
+} // namespace ndn
+
+#endif // NDNS_VALIDATOR_HPP
diff --git a/tests/unit/dummy-client-face.hpp b/tests/unit/dummy-client-face.hpp
new file mode 100644
index 0000000..649e714
--- /dev/null
+++ b/tests/unit/dummy-client-face.hpp
@@ -0,0 +1,236 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Copyright (c) 2013-2014 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.
+ */
+
+#ifndef NDNS_TESTS_UNIT_DUMMY_CLIENT_FACE_HPP
+#define NDNS_TESTS_UNIT_DUMMY_CLIENT_FACE_HPP
+
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/transport/transport.hpp>
+#include <ndn-cxx/management/nfd-controller.hpp>
+#include <ndn-cxx/management/nfd-control-response.hpp>
+#include <ndn-cxx/util/event-emitter.hpp>
+
+
+namespace ndn {
+namespace tests {
+
+class DummyClientTransport : public ndn::Transport
+{
+public:
+ void
+ receive(const Block& block)
+ {
+ if (static_cast<bool>(m_receiveCallback))
+ m_receiveCallback(block);
+ }
+
+ virtual void
+ close()
+ {
+ }
+
+ virtual void
+ pause()
+ {
+ }
+
+ virtual void
+ resume()
+ {
+ }
+
+ virtual void
+ send(const Block& wire)
+ {
+ if (wire.type() == tlv::Interest) {
+ shared_ptr<Interest> interest = make_shared<Interest>(wire);
+ (*m_onInterest)(*interest, this);
+ }
+ else if (wire.type() == tlv::Data) {
+ shared_ptr<Data> data = make_shared<Data>(wire);
+ (*m_onData)(*data, this);
+ }
+ }
+
+ virtual void
+ send(const Block& header, const Block& payload)
+ {
+ this->send(payload);
+ }
+
+ boost::asio::io_service&
+ getIoService()
+ {
+ return *m_ioService;
+ }
+
+private:
+ friend class DummyClientFace;
+ util::EventEmitter<Interest, DummyClientTransport*>* m_onInterest;
+ util::EventEmitter<Data, DummyClientTransport*>* m_onData;
+};
+
+
+/** \brief Callback to connect
+ */
+inline void
+replyNfdRibCommands(const Interest& interest, DummyClientTransport* transport)
+{
+ static const Name localhostRegistration("/localhost/nfd/rib");
+ if (localhostRegistration.isPrefixOf(interest.getName())) {
+ shared_ptr<Data> okResponse = make_shared<Data>(interest.getName());
+ nfd::ControlParameters params(interest.getName().get(-5).blockFromValue());
+ params.setFaceId(1);
+ params.setOrigin(0);
+ if (interest.getName().get(3) == name::Component("register")) {
+ params.setCost(0);
+ }
+ nfd::ControlResponse resp;
+ resp.setCode(200);
+ resp.setBody(params.wireEncode());
+ okResponse->setContent(resp.wireEncode());
+ KeyChain keyChain;
+ keyChain.signWithSha256(*okResponse);
+
+ transport->getIoService().post(bind(&DummyClientTransport::receive, transport,
+ okResponse->wireEncode()));
+ }
+}
+
+/** \brief a client-side face for unit testing
+ */
+class DummyClientFace : public ndn::Face
+{
+public:
+ explicit
+ DummyClientFace(shared_ptr<DummyClientTransport> transport)
+ : Face(transport)
+ , m_transport(transport)
+ {
+ m_transport->m_onInterest = &onInterest;
+ m_transport->m_onData = &onData;
+
+ enablePacketLogging();
+ }
+
+ DummyClientFace(shared_ptr<DummyClientTransport> transport, boost::asio::io_service& ioService)
+ : Face(transport, ioService)
+ , m_transport(transport)
+ {
+ m_transport->m_onInterest = &onInterest;
+ m_transport->m_onData = &onData;
+
+ enablePacketLogging();
+ }
+
+ /** \brief cause the Face to receive a packet
+ */
+ template<typename Packet>
+ void
+ receive(const Packet& packet)
+ {
+ m_transport->receive(packet.wireEncode());
+ }
+
+ void
+ enablePacketLogging()
+ {
+ // @todo Replace with C++11 lambdas
+
+ onInterest += bind(static_cast<void(std::vector<Interest>::*)(const Interest&)>(
+ &std::vector<Interest>::push_back),
+ &m_sentInterests, _1);
+
+ onData += bind(static_cast<void(std::vector<Data>::*)(const Data&)>(
+ &std::vector<Data>::push_back),
+ &m_sentDatas, _1);
+ }
+
+ void
+ enableRegistrationReply()
+ {
+ onInterest += &replyNfdRibCommands;
+ }
+
+public:
+ /** \brief sent Interests
+ * \note After .expressInterest, .processEvents must be called before
+ * the Interest would show up here.
+ */
+ std::vector<Interest> m_sentInterests;
+ /** \brief sent Datas
+ * \note After .put, .processEvents must be called before
+ * the Interest would show up here.
+ */
+ std::vector<Data> m_sentDatas;
+
+public:
+ /** \brief Event to be called whenever an Interest is received
+ * \note After .expressInterest, .processEvents must be called before
+ * the Interest would show up here.
+ */
+ util::EventEmitter<Interest, DummyClientTransport*> onInterest;
+
+ /** \brief Event to be called whenever a Data packet is received
+ * \note After .put, .processEvents must be called before
+ * the Interest would show up here.
+ */
+ util::EventEmitter<Data, DummyClientTransport*> onData;
+
+private:
+ shared_ptr<DummyClientTransport> m_transport;
+};
+
+inline shared_ptr<DummyClientFace>
+makeDummyClientFace()
+{
+ return make_shared<DummyClientFace>(make_shared<DummyClientTransport>());
+}
+
+inline shared_ptr<DummyClientFace>
+makeDummyClientFace(boost::asio::io_service& ioService)
+{
+ return make_shared<DummyClientFace>(make_shared<DummyClientTransport>(), ref(ioService));
+}
+
+
+} // namespace tests
+} // namespace ndn
+
+#endif // NDNS_TESTS_UNIT_DUMMY_CLIENT_FACE_HPP
diff --git a/tests/unit/validator.cpp b/tests/unit/validator.cpp
new file mode 100644
index 0000000..26c25ac
--- /dev/null
+++ b/tests/unit/validator.cpp
@@ -0,0 +1,264 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NDNS 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NDNS, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "validator.hpp"
+#include "dummy-client-face.hpp"
+#include <ndn-cxx/security/key-chain.hpp>
+#include "../boost-test.hpp"
+
+namespace ndn {
+namespace ndns {
+namespace tests {
+NDNS_LOG_INIT("ValidatorTest");
+
+BOOST_AUTO_TEST_SUITE(Validator)
+
+class Fixture
+{
+public:
+ Fixture()
+ : m_testId1("/test02")
+ , m_testId2("/test02/ndn")
+ , m_testId3("/test02/ndn/edu")
+ , m_randomId("/test03")
+ , m_version(name::Component::fromVersion(0))
+ , m_face(::ndn::tests::makeDummyClientFace())
+ {
+ m_keyChain.deleteIdentity(m_testId1);
+ m_keyChain.deleteIdentity(m_testId2);
+ m_keyChain.deleteIdentity(m_testId3);
+ m_keyChain.deleteIdentity(m_randomId);
+
+ m_randomDsk = createRoot(m_randomId); // generate a root cert
+
+ m_dsk1 = createRoot(m_testId1); // replace to root cert
+ m_dsk2 = createIdentity(m_testId2, m_dsk1);
+ m_dsk3 = createIdentity(m_testId3, m_dsk2);
+
+ m_selfSignCert = m_keyChain.generateRsaKeyPair(m_testId3, false);
+ shared_ptr<IdentityCertificate> cert = m_keyChain.selfSign(m_selfSignCert);
+ m_selfSignCert = cert->getName();
+ m_keyChain.addCertificate(*cert);
+ NDNS_LOG_TRACE("add cert: " << cert->getName() << " to KeyChain");
+
+ m_face->onInterest += bind(&Fixture::respondInterest, this, _1, _2);
+ }
+
+ ~Fixture()
+ {
+ m_face->getIoService().stop();
+ m_face->shutdown();
+ m_keyChain.deleteIdentity(m_testId1);
+ m_keyChain.deleteIdentity(m_testId2);
+ m_keyChain.deleteIdentity(m_testId3);
+ m_keyChain.deleteIdentity(m_randomId);
+ }
+
+ const Name
+ createIdentity(const Name& id, const Name& parentCertName)
+ {
+ Name kskCertName = m_keyChain.createIdentity(id);
+ Name kskName = m_keyChain.getDefaultKeyNameForIdentity(id);
+ m_keyChain.deleteCertificate(kskCertName);
+ auto kskCert = createCertificate(kskName, parentCertName);
+
+ Name dskName = m_keyChain.generateRsaKeyPair(id, false);
+ auto dskCert = createCertificate(dskName, kskCert);
+ return dskCert;
+ }
+
+ const Name
+ createRoot(const Name& root)
+ {
+ m_rootCert = m_keyChain.createIdentity(root);
+ ndn::io::save(*(m_keyChain.getCertificate(m_rootCert)), TEST_CONFIG_PATH "/anchors/root.cert");
+ NDNS_LOG_TRACE("save root cert "<< m_rootCert <<
+ " to: " << TEST_CONFIG_PATH "/anchors/root.cert");
+ Name dsk = m_keyChain.generateRsaKeyPair(root, false);
+ auto cert = createCertificate(dsk, m_rootCert);
+ return cert;
+ }
+
+
+ const Name
+ createCertificate(const Name& keyName, const Name& parentCertName)
+ {
+ std::vector<CertificateSubjectDescription> desc;
+ time::system_clock::TimePoint notBefore = time::system_clock::now();
+ time::system_clock::TimePoint notAfter = notBefore + time::days(365);
+ desc.push_back(CertificateSubjectDescription(oid::ATTRIBUTE_NAME,
+ "Signer: " + parentCertName.toUri()));
+ shared_ptr<IdentityCertificate> cert =
+ m_keyChain.prepareUnsignedIdentityCertificate(keyName, parentCertName,
+ notBefore, notAfter, desc);
+
+ Name tmp = cert->getName().getPrefix(-1).append(m_version);
+ cert->setName(tmp);
+ m_keyChain.sign(*cert, parentCertName);
+ m_keyChain.addCertificateAsKeyDefault(*cert);
+ NDNS_LOG_TRACE("add cert: " << cert->getName() << " to KeyChain");
+ return cert->getName();
+ }
+
+
+ void
+ respondInterest(const Interest& interest, ndn::tests::DummyClientTransport* transport)
+ {
+ Name certName = interest.getName();
+ if (certName.isPrefixOf(m_selfSignCert)) {
+ // self-sign cert's version number is not m_version
+ certName = m_selfSignCert;
+ } else {
+ certName.append(m_version);
+ }
+ NDNS_LOG_TRACE("validator needs: " << certName);
+ BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName), true);
+ auto cert = m_keyChain.getCertificate(certName);
+ transport->receive(cert->wireEncode());
+ }
+
+public:
+ Name m_testId1;
+ Name m_testId2;
+ Name m_testId3;
+ Name m_randomId;
+
+ Name m_rootCert;
+
+ KeyChain m_keyChain;
+
+ Name m_dsk1;
+ Name m_dsk2;
+ Name m_dsk3;
+
+ Name m_selfSignCert;
+
+ Name m_randomDsk;
+
+ name::Component m_version;
+
+ shared_ptr<ndn::tests::DummyClientFace> m_face;
+};
+
+
+BOOST_FIXTURE_TEST_CASE(Basic, Fixture)
+{
+ // validator must be created after root key is saved to the target
+ ndns::Validator validator(*m_face, TEST_CONFIG_PATH "/" "validator.conf");
+
+ Name dataName(m_testId3);
+ dataName.append("NDNS")
+ .append("rrLabel")
+ .append("rrType")
+ .appendVersion();
+ shared_ptr<Data> data = make_shared<Data>(dataName);
+ m_keyChain.sign(*data, m_dsk3);
+
+ bool hasValidated = false;
+ validator.validate(*data,
+ [&] (const shared_ptr<const Data>& data) {
+ hasValidated = true;
+ BOOST_CHECK(true);
+ },
+ [&] (const shared_ptr<const Data>& data, const std::string& str) {
+ hasValidated = true;
+ BOOST_CHECK(false);
+ });
+
+ m_face->processEvents(time::milliseconds(-1));
+
+ BOOST_CHECK_EQUAL(hasValidated, true);
+
+
+ dataName = m_testId2;
+ dataName.append("KEY")
+ .append("rrLabel")
+ .append("ID-CERT")
+ .appendVersion();
+ data = make_shared<Data>(dataName);
+ m_keyChain.sign(*data, m_dsk3); // key's owner's name is longer than data owner's
+
+ hasValidated = false;
+ validator.validate(*data,
+ [&] (const shared_ptr<const Data>& data) {
+ hasValidated = true;
+ BOOST_CHECK(false);
+ },
+ [&] (const shared_ptr<const Data>& data, const std::string& str) {
+ hasValidated = true;
+ BOOST_CHECK(true);
+ });
+
+ m_face->processEvents(time::milliseconds(-1));
+ // cannot pass verification due to key's owner's name is longer than data owner's
+ BOOST_CHECK_EQUAL(hasValidated, true);
+
+
+ dataName = m_testId3;
+ dataName.append("KEY")
+ .append("rrLabel")
+ .append("ID-CERT")
+ .appendVersion();
+ data = make_shared<Data>(dataName);
+ m_keyChain.sign(*data, m_selfSignCert);
+
+ hasValidated = false;
+ validator.validate(*data,
+ [&] (const shared_ptr<const Data>& data) {
+ hasValidated = true;
+ BOOST_CHECK(false);
+ },
+ [&] (const shared_ptr<const Data>& data, const std::string& str) {
+ hasValidated = true;
+ BOOST_CHECK(true);
+ });
+
+ m_face->processEvents(time::milliseconds(-1));
+ // cannot pass due to self-sign cert is used
+ BOOST_CHECK_EQUAL(hasValidated, true);
+
+ dataName = m_testId2;
+ dataName.append("KEY")
+ .append("rrLabel")
+ .append("ID-CERT")
+ .appendVersion();
+ data = make_shared<Data>(dataName);
+ m_keyChain.sign(*data, m_randomDsk);
+
+ hasValidated = false;
+ validator.validate(*data,
+ [&] (const shared_ptr<const Data>& data) {
+ hasValidated = true;
+ BOOST_CHECK(false);
+ },
+ [&] (const shared_ptr<const Data>& data, const std::string& str) {
+ hasValidated = true;
+ BOOST_CHECK(true);
+ });
+
+ m_face->processEvents(time::milliseconds(-1));
+ // cannot pass due to a totally mismatched key
+ BOOST_CHECK_EQUAL(hasValidated, true);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace ndns
+} // namespace ndn
diff --git a/tests/wscript b/tests/wscript
index 0407962..fa36e78 100644
--- a/tests/wscript
+++ b/tests/wscript
@@ -5,12 +5,33 @@
top = '..'
def build(bld):
- if bld.env['WITH_TESTS']:
- unit_tests = bld.program(
- target='../unit-tests',
- features='cxx cxxprogram',
- source=bld.path.ant_glob(['**/*.cpp']),
- use='ndns-objects',
- install_path=None,
- defines="BUILDDIR=\"%s\"" % Context.out_dir,
- )
+ if not bld.env['WITH_TESTS']:
+ return
+ dst = bld.bldnode.make_node("conf-test/anchors")
+ dst.mkdir()
+
+ bld(features = "subst",
+ name = 'test-validator-conf',
+ source = '../validator.conf.sample.in',
+ target = '../conf-test/validator.conf',
+ use = 'validator-sample',
+ ANCHORPATH='\"anchors/root.cert\"',
+ RELATION='is-prefix-of',
+ )
+
+ bld(features = "subst",
+ name = 'test-logger-conf',
+ source = '../log4cxx.properties.sample.in',
+ target = '../conf-test/log4cxx.properties.sample',
+ is_copy = True,
+ use = 'log4cxx-sample',
+ )
+
+ unit_tests = bld.program(
+ target='../unit-tests',
+ features='cxx cxxprogram',
+ source=bld.path.ant_glob(['**/*.cpp']),
+ use='ndns-objects',
+ install_path=None,
+ defines='TEST_CONFIG_PATH=\"%s/conf-test\"' %(bld.bldnode)
+ )
diff --git a/tools/wscript b/tools/wscript
index 78b50ca..bea6079 100644
--- a/tools/wscript
+++ b/tools/wscript
@@ -1,9 +1,11 @@
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+import os.path
+
top = '..'
def build(bld):
- for app in bld.path.ant_glob('tools/*', dir=True):
+ for app in bld.path.ant_glob('**/*', dir=True):
if os.path.isdir(app.abspath()):
bld(features=['cxx', 'cxxprogram'],
target = '../bin/%s' % (str(app)),
@@ -11,9 +13,9 @@
use = 'ndns-objects',
)
- for app in bld.path.ant_glob('tools/*.cpp'):
- bld(features=['cxxprogram'],
- target = 'bin/%s' % (str(app.change_ext('','.cpp'))),
+ for app in bld.path.ant_glob('**/*.cpp'):
+ bld(features=['cxx', 'cxxprogram'],
+ target = '../bin/%s' % (str(app.change_ext('','.cpp'))),
source = app,
use = 'ndns-objects',
)
diff --git a/validator.conf.sample.in b/validator.conf.sample.in
new file mode 100644
index 0000000..8aaf58c
--- /dev/null
+++ b/validator.conf.sample.in
@@ -0,0 +1,28 @@
+rule
+{
+ id "NDNS Validator"
+ for data
+ checker
+ {
+ type customized
+ sig-type rsa-sha256
+ key-locator
+ {
+ type name
+ hyper-relation
+ {
+ k-regex ^(<>*)<KEY>(<>*)<><ID-CERT>$
+ k-expand \\1\\2
+ h-relation @RELATION@ ; data is only allowed to be signed by the zone key
+ p-regex ^(<>*)[<KEY><NDNS>](<>*)<><>$
+ p-expand \\1\\2
+ }
+ }
+ }
+}
+
+trust-anchor
+{
+ type file
+ file-name @ANCHORPATH@
+}
diff --git a/wscript b/wscript
index 8963265..6a3c29b 100644
--- a/wscript
+++ b/wscript
@@ -32,8 +32,10 @@
conf.check_sqlite3(mandatory=True)
+
if conf.options.with_tests:
conf.env['WITH_TESTS'] = True
+ conf.define('NDNS_HAVE_TESTS', 1)
USED_BOOST_LIBS = ['system', 'filesystem']
if conf.env['WITH_TESTS']:
@@ -43,8 +45,8 @@
if not conf.options.with_sqlite_locking:
conf.define('DISABLE_SQLITE3_FS_LOCKING', 1)
- conf.define("DEFAULT_CONFIG_PATH", "%s/ndn" % conf.env['SYSCONFDIR'])
- conf.define("DEFAULT_DATABASE_PATH", "%s/ndn/ndns" % conf.env['LOCALSTATEDIR'])
+ conf.define("DEFAULT_CONFIG_PATH", "%s/ndns" % conf.env['SYSCONFDIR'])
+ conf.define("DEFAULT_DATABASE_PATH", "%s/ndns" % conf.env['LOCALSTATEDIR'])
conf.write_config_header('src/config.hpp')
@@ -70,7 +72,7 @@
features='cxx',
name='ndns-objects',
source=bld.path.ant_glob(['src/**/*.cpp'],
- excl=['src/main.cpp']),
+ excl=['src/main.cpp',]),
use='version NDN_CXX LOG4CXX BOOST',
includes='src',
export_includes='src',
@@ -88,7 +90,25 @@
bld.recurse('tests')
bld.recurse('tools')
- # bld.install_files('${SYSCONFDIR}/ndn', 'ndns.conf.sample')
+
+ bld(features='subst',
+ source='validator.conf.sample.in',
+ target='validator.conf',
+ install_path='${SYSCONFDIR}/ndns',
+ name='validator-sample',
+ ANCHORPATH='anchors/root.cert',
+ RELATION='is-prefix-of',
+ help='the validator configuration of ndns',
+ )
+
+ bld(features='subst',
+ source='log4cxx.properties.sample.in',
+ target='log4cxx.properties.sample',
+ install_path='${SYSCONFDIR}/ndns',
+ is_copy = True,
+ name='log4cxx-sample',
+ help='the log4cxx configration file',
+ )
def docs(bld):
from waflib import Options