diff --git a/AUTHORS.md b/AUTHORS.md index 3d40a6f..0915877 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -12,3 +12,4 @@ in ndn-tools: * Junxiao Shi * Eric Newberry * Xiaoke Jiang +* Yingdi Yu diff --git a/manpages/conf.py b/manpages/conf.py index 3c0f6bb..d86777a 100644 --- a/manpages/conf.py +++ b/manpages/conf.py @@ -12,4 +12,5 @@ man_pages = [ ('ndnpingserver', 'ndnpingserver', 'reachability testing server', None, 1), ('ndndump', 'ndndump', 'traffic analysis tool', None, 8), ('ndn-dissect', 'ndn-dissect', 'NDN packet format inspector', None, 1), + ('ndn-pib', 'ndn-pib', 'NDN PIB service', None, 1), ] diff --git a/manpages/ndn-pib.rst b/manpages/ndn-pib.rst new file mode 100644 index 0000000..e94a7d2 --- /dev/null +++ b/manpages/ndn-pib.rst @@ -0,0 +1,35 @@ +ndn-pib +======== + +``ndn-pib`` is a public key and certificate management and publishing service. + +Usage +----- + +:: + + ndn-pib [-h] -o owner -d database_dir -t tpm_locator + +Description +----------- + +This command will start a PIB service process which serves signing key lookup/management for local +applications and also public the public key certificate of signing keys. The lookup/management +interface listens on a prefix "/localhost/pib/[OwnerName]" and accept five types of command (get, +default, list, update, delete). More details can be found at `Public key Info Base (PIB) Service +`__ + +Since PIB service is queried through Interest/Data exchange, NFD is required to run before this +command is executed. + +This command requires three arguments: ``owner`` specify the owner of the pib service, which is also +the third name component in the local lookup/management prefix; ``database_dir`` is the path to the +database where all the public key, certificate, identity are stored and managed; ``tpm_locator`` is +locator of a TPM which stores the corresponding private key of the public keys in PIB. + +Example +------- + +:: + + $ ndn-pib -o alice -d /var/pib -t tpm-file:/var/ndn/tpm diff --git a/tests/pib/cert-publicher.t.cpp b/tests/pib/cert-publicher.t.cpp new file mode 100644 index 0000000..f33f325 --- /dev/null +++ b/tests/pib/cert-publicher.t.cpp @@ -0,0 +1,132 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "tools/pib/cert-publisher.hpp" +#include "identity-management-time-fixture.hpp" +#include + +#include + +#include "tests/test-common.hpp" + +namespace ndn { +namespace pib { +namespace tests { + +class CertPublisherFixture : public ndn::security::IdentityManagementTimeFixture +{ +public: + CertPublisherFixture() + : tmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "DbTest") + , db(tmpPath.c_str()) + , face(util::makeDummyClientFace(io, {true, true})) + { + } + + ~CertPublisherFixture() + { + boost::filesystem::remove_all(tmpPath); + } + + boost::asio::io_service io; + boost::filesystem::path tmpPath; + PibDb db; + shared_ptr face; +}; + +BOOST_FIXTURE_TEST_SUITE(TestCertPublisher, CertPublisherFixture) + +BOOST_AUTO_TEST_CASE(Basic) +{ + // Initialize id1 + Name id1("/test/identity"); + addIdentity(id1); + Name certName111 = m_keyChain.getDefaultCertificateNameForIdentity(id1); + shared_ptr cert111 = m_keyChain.getCertificate(certName111); + Name keyName11 = cert111->getPublicKeyName(); + + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert112 = m_keyChain.selfSign(keyName11); + Name certName112 = cert112->getName(); + + CertPublisher certPublisher(*face, db); + + // Add a certificate + db.addCertificate(*cert111); + advanceClocks(io, time::milliseconds(2), 50); + + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0); + auto interest111 = make_shared(cert111->getName().getPrefix(-1)); + face->receive(*interest111); + advanceClocks(io, time::milliseconds(2), 50); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + BOOST_CHECK(face->sentDatas[0].wireEncode() == cert111->wireEncode()); + face->sentDatas.clear(); + + // Add another certificate + db.addCertificate(*cert112); + advanceClocks(io, time::milliseconds(2), 50); + + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0); + auto interest112 = make_shared(cert112->getName().getPrefix(-1)); + face->receive(*interest112); + advanceClocks(io, time::milliseconds(2), 50); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + BOOST_CHECK(face->sentDatas[0].wireEncode() == cert111->wireEncode()); + face->sentDatas.clear(); + + Exclude exclude; + exclude.excludeOne(cert111->getName().get(-1)); + interest112->setExclude(exclude); + face->receive(*interest112); + advanceClocks(io, time::milliseconds(2), 50); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + BOOST_CHECK(face->sentDatas[0].wireEncode() == cert112->wireEncode()); + face->sentDatas.clear(); + + // delete a certificate + db.deleteCertificate(certName112); + face->receive(*interest112); + advanceClocks(io, time::milliseconds(2), 50); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0); + + face->receive(*interest111); + advanceClocks(io, time::milliseconds(2), 50); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + BOOST_CHECK(face->sentDatas[0].wireEncode() == cert111->wireEncode()); + face->sentDatas.clear(); + + // delete another certificate + db.deleteCertificate(certName111); + face->receive(*interest112); + advanceClocks(io, time::milliseconds(2), 50); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0); + + face->receive(*interest111); + advanceClocks(io, time::milliseconds(2), 50); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace tests +} // namespace pib +} // namespace ndn diff --git a/tests/pib/identity-management-time-fixture.cpp b/tests/pib/identity-management-time-fixture.cpp new file mode 100644 index 0000000..526a2e6 --- /dev/null +++ b/tests/pib/identity-management-time-fixture.cpp @@ -0,0 +1,58 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "identity-management-time-fixture.hpp" + +namespace ndn { +namespace security { + +IdentityManagementTimeFixture::IdentityManagementTimeFixture() + : m_keyChainTmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "PibIdMgmtTimeTest") + , m_keyChain(std::string("pib-sqlite3:").append(m_keyChainTmpPath.string()), + std::string("tpm-file:").append(m_keyChainTmpPath.string())) +{ +} + +IdentityManagementTimeFixture::~IdentityManagementTimeFixture() +{ + for (const auto& identity : m_identities) { + m_keyChain.deleteIdentity(identity); + } + + boost::filesystem::remove_all(m_keyChainTmpPath); +} + +bool +IdentityManagementTimeFixture::addIdentity(const Name& identity, const KeyParams& params) +{ + try { + m_keyChain.createIdentity(identity, params); + m_identities.push_back(identity); + return true; + } + catch (std::runtime_error&) { + return false; + } +} + + +} // namespace security +} // namespace ndn diff --git a/tests/pib/identity-management-time-fixture.hpp b/tests/pib/identity-management-time-fixture.hpp new file mode 100644 index 0000000..4ac2e63 --- /dev/null +++ b/tests/pib/identity-management-time-fixture.hpp @@ -0,0 +1,61 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP +#define NDN_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP + +#include +#include +#include + +#include "tests/test-common.hpp" + +namespace ndn { +namespace security { + +/** + * @brief IdentityManagementTimeFixture is a test suite level fixture. + * Test cases in the suite can use this fixture to create identities. + * Identities added via addIdentity method are automatically deleted + * during test teardown. + */ +class IdentityManagementTimeFixture : public tests::UnitTestTimeFixture +{ +public: + IdentityManagementTimeFixture(); + + ~IdentityManagementTimeFixture(); + + /// @brief add identity, return true if succeed. + bool + addIdentity(const Name& identity, const KeyParams& params = KeyChain::DEFAULT_KEY_PARAMS); + +protected: + boost::filesystem::path m_keyChainTmpPath; + + KeyChain m_keyChain; + std::vector m_identities; +}; + +} // namespace security +} // namespace ndn + +#endif // NDN_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP diff --git a/tests/pib/key-cache.t.cpp b/tests/pib/key-cache.t.cpp new file mode 100644 index 0000000..936c132 --- /dev/null +++ b/tests/pib/key-cache.t.cpp @@ -0,0 +1,75 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "tools/pib/key-cache.hpp" + +#include "tests/test-common.hpp" + +namespace ndn { +namespace pib { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestKeyCache) + +BOOST_AUTO_TEST_CASE(Basic) +{ + KeyCache keyCache(3); + + Name name1("/1"); + Name name2("/2"); + Name name3("/3"); + Name name4("/4"); + + auto key1 = make_shared(); + auto key2 = make_shared(); + auto key3 = make_shared(); + auto key4 = make_shared(); + + keyCache.insert(name1, key1); + keyCache.insert(name2, key2); + keyCache.insert(name3, key3); + + BOOST_CHECK_EQUAL(keyCache.size(), 3); + BOOST_CHECK(static_cast(keyCache.find(name1))); + BOOST_CHECK(static_cast(keyCache.find(name2))); + BOOST_CHECK(static_cast(keyCache.find(name3))); + BOOST_CHECK(!static_cast(keyCache.find(name4))); + + keyCache.insert(name1, key1); + keyCache.insert(name4, key4); + BOOST_CHECK_EQUAL(keyCache.size(), 3); + BOOST_CHECK(static_cast(keyCache.find(name1))); + BOOST_CHECK(!static_cast(keyCache.find(name2))); + BOOST_CHECK(static_cast(keyCache.find(name3))); + BOOST_CHECK(static_cast(keyCache.find(name4))); + + keyCache.erase(name1); + BOOST_CHECK_EQUAL(keyCache.size(), 2); + BOOST_CHECK(!static_cast(keyCache.find(name1))); + BOOST_CHECK(static_cast(keyCache.find(name3))); + BOOST_CHECK(static_cast(keyCache.find(name4))); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace tests +} // namespace pib +} // namespace ndn diff --git a/tests/pib/pib-db.t.cpp b/tests/pib/pib-db.t.cpp new file mode 100644 index 0000000..6d826d2 --- /dev/null +++ b/tests/pib/pib-db.t.cpp @@ -0,0 +1,474 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "tools/pib/pib-db.hpp" +#include "identity-management-time-fixture.hpp" + +#include + +#include "tests/test-common.hpp" + +namespace ndn { +namespace pib { +namespace tests { + +class PibDbTestFixture : public ndn::security::IdentityManagementTimeFixture +{ +public: + PibDbTestFixture() + : tmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "DbTest") + , db(tmpPath.c_str()) + { + } + + ~PibDbTestFixture() + { + boost::filesystem::remove_all(tmpPath); + } + + boost::asio::io_service io; + boost::filesystem::path tmpPath; + PibDb db; + std::vector deletedIds; + std::vector deletedKeys; + std::vector deletedCerts; + std::vector insertedCerts; +}; + + +BOOST_FIXTURE_TEST_SUITE(TestPibDb, PibDbTestFixture) + +BOOST_AUTO_TEST_CASE(MgmtTest) +{ + Name testUser("/localhost/pib/test/mgmt"); + addIdentity(testUser); + Name testUserCertName = m_keyChain.getDefaultCertificateNameForIdentity(testUser); + shared_ptr testUserCert = m_keyChain.getCertificate(testUserCertName); + + + BOOST_CHECK_EQUAL(db.getOwnerName(), ""); + BOOST_CHECK(db.getMgmtCertificate() == nullptr); + + db.updateMgmtCertificate(*testUserCert); + BOOST_CHECK_EQUAL(db.getOwnerName(), "test"); + BOOST_REQUIRE(db.getMgmtCertificate() != nullptr); + BOOST_CHECK_EQUAL(db.getMgmtCertificate()->getName(), testUserCertName); + + db.setTpmLocator("tpmLocator"); + BOOST_CHECK_EQUAL(db.getTpmLocator(), "tpmLocator"); + + Name testUser2("/localhost/pib/test2/mgmt"); + addIdentity(testUser2); + Name testUser2CertName = m_keyChain.getDefaultCertificateNameForIdentity(testUser2); + shared_ptr testUser2Cert = m_keyChain.getCertificate(testUser2CertName); + + BOOST_CHECK_THROW(db.updateMgmtCertificate(*testUser2Cert), PibDb::Error); + + Name testUserKeyName2 = m_keyChain.generateRsaKeyPairAsDefault(testUser); + shared_ptr testUserCert2 = m_keyChain.selfSign(testUserKeyName2); + + BOOST_CHECK_NO_THROW(db.updateMgmtCertificate(*testUserCert2)); + BOOST_REQUIRE(db.getMgmtCertificate() != nullptr); + BOOST_CHECK_EQUAL(db.getMgmtCertificate()->getName(), + testUserCert2->getName()); +} + +BOOST_AUTO_TEST_CASE(IdentityTest) +{ + db.identityDeleted.connect([this] (const Name& id) { + this->deletedIds.push_back(id); + }); + + Name identity("/test/identity"); + Name identity2("/test/identity2"); + + // Add an identity: /test/identity + // Since there is no default identity, + // the new added identity will be set as the default identity. + BOOST_CHECK_EQUAL(db.getDefaultIdentity(), PibDb::NON_EXISTING_IDENTITY); + db.addIdentity(identity); + BOOST_CHECK(db.hasIdentity(identity)); + BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity); + + // Add the second identity: /test/identity2 + // Since the default identity exists, + // the new added identity will not be set as the default identity. + db.addIdentity(identity2); + BOOST_CHECK_EQUAL(db.hasIdentity(identity2), true); + BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity); + + // Set the second identity: /test/identity2 as default explicitly + db.setDefaultIdentity(identity2); + BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity2); + + // Delete identity /test/identity2, which is also the default one + // This will trigger the identityDeleted signal + // and also causes no default identity. + db.deleteIdentity(identity2); + BOOST_CHECK_EQUAL(db.hasIdentity(identity2), false); + BOOST_CHECK_EQUAL(db.hasIdentity(identity), true); + BOOST_CHECK_EQUAL(deletedIds.size(), 1); + BOOST_CHECK_EQUAL(deletedIds[0], identity2); + BOOST_CHECK_EQUAL(db.getDefaultIdentity(), PibDb::NON_EXISTING_IDENTITY); + deletedIds.clear(); + + // Add the second identity back + // Since there is no default identity (though another identity still exists), + // the second identity will be set as default. + db.addIdentity(identity2); + BOOST_CHECK_EQUAL(db.hasIdentity(identity2), true); + BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity2); + + // Delete identity /test/identity + db.deleteIdentity(identity); + BOOST_CHECK_EQUAL(db.hasIdentity(identity), false); + BOOST_CHECK_EQUAL(db.hasIdentity(identity2), true); + BOOST_CHECK_EQUAL(deletedIds.size(), 1); + BOOST_CHECK_EQUAL(deletedIds[0], identity); + deletedIds.clear(); + + // Delete identity /test/identity2 + db.deleteIdentity(identity2); + BOOST_CHECK_EQUAL(db.hasIdentity(identity), false); + BOOST_CHECK_EQUAL(db.hasIdentity(identity2), false); + BOOST_CHECK_EQUAL(deletedIds.size(), 1); + BOOST_CHECK_EQUAL(deletedIds[0], identity2); + deletedIds.clear(); +} + + +BOOST_AUTO_TEST_CASE(KeyTest) +{ + db.identityDeleted.connect([this] (const Name& id) { + this->deletedIds.push_back(id); + }); + + db.keyDeleted.connect([this] (const Name& key) { + this->deletedKeys.push_back(key); + }); + + // Initialize id1 + Name id1("/test/identity"); + addIdentity(id1); + Name certName111 = m_keyChain.getDefaultCertificateNameForIdentity(id1); + shared_ptr cert111 = m_keyChain.getCertificate(certName111); + Name keyName11 = cert111->getPublicKeyName(); + PublicKey& key11 = cert111->getPublicKeyInfo(); + + advanceClocks(io, time::milliseconds(100)); + Name keyName12 = m_keyChain.generateRsaKeyPairAsDefault(id1); + shared_ptr cert121 = m_keyChain.selfSign(keyName12); + PublicKey& key12 = cert121->getPublicKeyInfo(); + + // Initialize id2 + advanceClocks(io, time::milliseconds(100)); + Name id2("/test/identity2"); + addIdentity(id2); + Name certName211 = m_keyChain.getDefaultCertificateNameForIdentity(id2); + shared_ptr cert211 = m_keyChain.getCertificate(certName211); + Name keyName21 = cert211->getPublicKeyName(); + PublicKey& key21 = cert211->getPublicKeyInfo(); + + advanceClocks(io, time::milliseconds(100)); + Name keyName22 = m_keyChain.generateRsaKeyPairAsDefault(id2); + shared_ptr cert221 = m_keyChain.selfSign(keyName22); + PublicKey& key22 = cert221->getPublicKeyInfo(); + + // Add a key, the corresponding identity should be added as well + // Since the PIB does not have any default identity set before, + // the added identity will be set as default. + // Since there is no default key for the identity, + // the added key will be set as default. + BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), PibDb::NON_EXISTING_KEY); + BOOST_CHECK(db.getKey(keyName11) == nullptr); + db.addKey(keyName11, key11); + BOOST_CHECK(db.hasIdentity(id1)); + BOOST_CHECK(db.getKey(keyName11) != nullptr); + BOOST_CHECK_EQUAL(db.getDefaultIdentity(), id1); + BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName11); + + // Add the second key of /test/identity. + // Since the default key of /test/identity has been set, + // The new added key will not be set as default. + db.addKey(keyName12, key12); + BOOST_CHECK(db.getKey(keyName12) != nullptr); + BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName11); + + // Explicitly set the second key as the default key of /test/identity + db.setDefaultKeyNameOfIdentity(keyName12); + BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName12); + + // Delete the second key which is also the default key. + // This will trigger the keyDeleted signal. + // This will also cause no default key for /test/identity + db.deleteKey(keyName12); + BOOST_CHECK_EQUAL(db.hasKey(keyName12), false); + BOOST_CHECK_EQUAL(db.hasKey(keyName11), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName22), false); + BOOST_CHECK_EQUAL(db.hasKey(keyName21), false); + BOOST_CHECK_EQUAL(deletedKeys.size(), 1); + BOOST_CHECK_EQUAL(deletedKeys[0], keyName12); + deletedKeys.clear(); + + // Add the second key back. + // Since there is no default key of /test/identity (although another key still exists) + // The second key will be set as the default key of /test/identity + BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), PibDb::NON_EXISTING_KEY); + db.addKey(keyName12, key12); + BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName12); + + // Prepare test for identity deletion + db.addKey(keyName21, key21); + db.addKey(keyName22, key22); + BOOST_CHECK_EQUAL(db.hasKey(keyName12), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName22), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName21), true); + BOOST_CHECK_EQUAL(db.hasIdentity(id2), true); + + // Delete the identity. + // All keys of the identity should also be deleted, + // and the keyDeleted signal should be triggered twice. + db.deleteIdentity(id1); + BOOST_CHECK_EQUAL(db.hasIdentity(id1), false); + BOOST_CHECK_EQUAL(db.hasIdentity(id2), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName11), false); + BOOST_CHECK_EQUAL(db.hasKey(keyName12), false); + BOOST_CHECK_EQUAL(db.hasKey(keyName21), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName22), true); + BOOST_CHECK_EQUAL(deletedKeys.size(), 2); + BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName11) != + deletedKeys.end()); + BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName12) != + deletedKeys.end()); + BOOST_CHECK_EQUAL(deletedIds.size(), 1); + BOOST_CHECK_EQUAL(deletedIds[0], id1); +} + +BOOST_AUTO_TEST_CASE(CertTest) +{ + db.identityDeleted.connect([this] (const Name& id) { + this->deletedIds.push_back(id); + }); + + db.keyDeleted.connect([this] (const Name& key) { + this->deletedKeys.push_back(key); + }); + + db.certificateDeleted.connect([this] (const Name& certificate) { + this->deletedCerts.push_back(certificate); + }); + + db.certificateInserted.connect([this] (const Name& certificate) { + this->insertedCerts.push_back(certificate); + }); + + // Initialize id1 + Name id1("/test/identity"); + addIdentity(id1); + Name certName111 = m_keyChain.getDefaultCertificateNameForIdentity(id1); + shared_ptr cert111 = m_keyChain.getCertificate(certName111); + Name keyName11 = cert111->getPublicKeyName(); + + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert112 = m_keyChain.selfSign(keyName11); + Name certName112 = cert112->getName(); + + advanceClocks(io, time::milliseconds(100)); + Name keyName12 = m_keyChain.generateRsaKeyPairAsDefault(id1); + shared_ptr cert121 = m_keyChain.selfSign(keyName12); + Name certName121 = cert121->getName(); + + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert122 = m_keyChain.selfSign(keyName12); + Name certName122 = cert122->getName(); + + // Initialize id2 + advanceClocks(io, time::milliseconds(100)); + Name id2("/test/identity2"); + addIdentity(id2); + Name certName211 = m_keyChain.getDefaultCertificateNameForIdentity(id2); + shared_ptr cert211 = m_keyChain.getCertificate(certName211); + Name keyName21 = cert211->getPublicKeyName(); + + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert212 = m_keyChain.selfSign(keyName21); + Name certName212 = cert212->getName(); + + advanceClocks(io, time::milliseconds(100)); + Name keyName22 = m_keyChain.generateRsaKeyPairAsDefault(id2); + shared_ptr cert221 = m_keyChain.selfSign(keyName22); + Name certName221 = cert221->getName(); + + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert222 = m_keyChain.selfSign(keyName22); + Name certName222 = cert222->getName(); + + // Add a certificate + // This will also add the corresponding key and identity. + // Since there is no default setting before, + // The certificate will be set as the default one of the key, and so be the key and identity + BOOST_CHECK_EQUAL(db.hasCertificate(certName111), false); + BOOST_CHECK_EQUAL(db.hasKey(keyName11), false); + BOOST_CHECK_EQUAL(db.hasIdentity(id1), false); + BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), PibDb::NON_EXISTING_CERTIFICATE); + db.addCertificate(*cert111); + BOOST_CHECK_EQUAL(db.hasCertificate(certName111), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName11), true); + BOOST_CHECK_EQUAL(db.hasIdentity(id1), true); + BOOST_CHECK_EQUAL(db.getDefaultIdentity(), id1); + BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName11); + BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName111); + BOOST_CHECK_EQUAL(insertedCerts.size(), 1); + BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName111) != + insertedCerts.end()); + insertedCerts.clear(); + + // Add the second certificate of the same key + // Since default certificate already exists, no default setting changes. + BOOST_CHECK(db.getCertificate(certName112) == nullptr); + db.addCertificate(*cert112); + BOOST_CHECK(db.getCertificate(certName112) != nullptr); + BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName111); + BOOST_CHECK_EQUAL(insertedCerts.size(), 1); + BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName112) != + insertedCerts.end()); + insertedCerts.clear(); + + // Explicitly set the second certificate as the default one of the key. + db.setDefaultCertNameOfKey(certName112); + BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName112); + + // Delete the default certificate + // This will trigger certificateDeleted signal + // and also causes no default certificate for the key. + db.deleteCertificate(certName112); + BOOST_CHECK_EQUAL(db.hasCertificate(certName112), false); + BOOST_CHECK_EQUAL(db.hasCertificate(certName111), true); + BOOST_CHECK_EQUAL(deletedCerts.size(), 1); + BOOST_CHECK_EQUAL(deletedCerts[0], certName112); + BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), PibDb::NON_EXISTING_CERTIFICATE); + deletedCerts.clear(); + + // Add the second certificate back + // Since there is no default certificate of the key (though another certificate still exists), + // the new added certificate will be set as default + db.addCertificate(*cert112); + BOOST_CHECK(db.getCertificate(certName112) != nullptr); + BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName112); + insertedCerts.clear(); + + // Add entries for delete tests + db.addCertificate(*cert111); // already exists no certInserted signal emitted + db.addCertificate(*cert112); // already exists no certInserted signal emitted + db.addCertificate(*cert121); + db.addCertificate(*cert122); + db.addCertificate(*cert211); + db.addCertificate(*cert212); + db.addCertificate(*cert221); + db.addCertificate(*cert222); + BOOST_CHECK_EQUAL(insertedCerts.size(), 6); + BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName121) != + insertedCerts.end()); + BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName122) != + insertedCerts.end()); + BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName211) != + insertedCerts.end()); + BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName212) != + insertedCerts.end()); + BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName221) != + insertedCerts.end()); + BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName222) != + insertedCerts.end()); + insertedCerts.clear(); + + // Delete the key. + // All the related certificates will be deleted as well. + db.deleteKey(keyName11); + BOOST_CHECK_EQUAL(db.hasCertificate(certName112), false); + BOOST_CHECK_EQUAL(db.hasCertificate(certName111), false); + BOOST_CHECK_EQUAL(db.hasCertificate(certName122), true); + BOOST_CHECK_EQUAL(db.hasCertificate(certName121), true); + BOOST_CHECK_EQUAL(db.hasCertificate(certName212), true); + BOOST_CHECK_EQUAL(db.hasCertificate(certName211), true); + BOOST_CHECK_EQUAL(db.hasCertificate(certName222), true); + BOOST_CHECK_EQUAL(db.hasCertificate(certName221), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName11), false); + BOOST_CHECK_EQUAL(db.hasKey(keyName12), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName21), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName22), true); + BOOST_CHECK_EQUAL(deletedCerts.size(), 2); + BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName111) != + deletedCerts.end()); + BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName112) != + deletedCerts.end()); + BOOST_CHECK_EQUAL(deletedKeys.size(), 1); + BOOST_CHECK_EQUAL(deletedKeys[0], keyName11); + deletedCerts.clear(); + deletedKeys.clear(); + + // Recover deleted entries + db.addCertificate(*cert111); + db.addCertificate(*cert112); + + // Delete the identity + // All the related certificates and keys will be deleted as well. + BOOST_CHECK_EQUAL(db.hasCertificate(certName111), true); + BOOST_CHECK_EQUAL(db.hasCertificate(certName112), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName11), true); + BOOST_CHECK_EQUAL(db.hasIdentity(id1), true); + db.deleteIdentity(id1); + BOOST_CHECK_EQUAL(db.hasCertificate(certName112), false); + BOOST_CHECK_EQUAL(db.hasCertificate(certName111), false); + BOOST_CHECK_EQUAL(db.hasCertificate(certName122), false); + BOOST_CHECK_EQUAL(db.hasCertificate(certName121), false); + BOOST_CHECK_EQUAL(db.hasCertificate(certName212), true); + BOOST_CHECK_EQUAL(db.hasCertificate(certName211), true); + BOOST_CHECK_EQUAL(db.hasCertificate(certName222), true); + BOOST_CHECK_EQUAL(db.hasCertificate(certName221), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName11), false); + BOOST_CHECK_EQUAL(db.hasKey(keyName12), false); + BOOST_CHECK_EQUAL(db.hasKey(keyName21), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName22), true); + BOOST_CHECK_EQUAL(db.hasIdentity(id1), false); + BOOST_CHECK_EQUAL(db.hasIdentity(id2), true); + BOOST_CHECK_EQUAL(deletedCerts.size(), 4); + BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName111) != + deletedCerts.end()); + BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName112) != + deletedCerts.end()); + BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName121) != + deletedCerts.end()); + BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName122) != + deletedCerts.end()); + BOOST_CHECK_EQUAL(deletedKeys.size(), 2); + BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName11) != + deletedKeys.end()); + BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName12) != + deletedCerts.end()); + BOOST_CHECK_EQUAL(deletedIds.size(), 1); + BOOST_CHECK_EQUAL(deletedIds[0], id1); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace tests +} // namespace pib +} // namespace ndn diff --git a/tests/pib/pib-validator.t.cpp b/tests/pib/pib-validator.t.cpp new file mode 100644 index 0000000..06fd373 --- /dev/null +++ b/tests/pib/pib-validator.t.cpp @@ -0,0 +1,137 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "tools/pib/pib-validator.hpp" +#include "tools/pib/encoding/update-param.hpp" +#include "tools/pib/encoding/delete-param.hpp" +#include + +#include "identity-management-time-fixture.hpp" +#include +#include "tests/test-common.hpp" + +namespace ndn { +namespace pib { +namespace tests { + +class PibValidatorFixture : public ndn::security::IdentityManagementTimeFixture +{ +public: + PibValidatorFixture() + : tmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "DbTest") + , db(tmpPath.c_str()) + { + } + + ~PibValidatorFixture() + { + boost::filesystem::remove_all(tmpPath); + } + + boost::asio::io_service io; + boost::filesystem::path tmpPath; + PibDb db; + bool isProcessed; +}; + +BOOST_FIXTURE_TEST_SUITE(TestPibValidator, PibValidatorFixture) + +BOOST_AUTO_TEST_CASE(Basic) +{ + PibValidator validator(db); + + Name testUser("/localhost/pib/test/mgmt"); + BOOST_REQUIRE(addIdentity(testUser, RsaKeyParams())); + Name testUserCertName = m_keyChain.getDefaultCertificateNameForIdentity(testUser); + shared_ptr testUserCert = m_keyChain.getCertificate(testUserCertName); + + advanceClocks(io, time::milliseconds(100)); + Name testUser2("/localhost/pib/test2/mgmt"); + BOOST_REQUIRE(addIdentity(testUser2, RsaKeyParams())); + + db.updateMgmtCertificate(*testUserCert); + + advanceClocks(io, time::milliseconds(100)); + Name normalId("/normal/id"); + BOOST_REQUIRE(addIdentity(normalId, RsaKeyParams())); + Name normalIdCertName = m_keyChain.getDefaultCertificateNameForIdentity(normalId); + shared_ptr normalIdCert = m_keyChain.getCertificate(normalIdCertName); + + db.addIdentity(normalId); + db.addKey(normalIdCert->getPublicKeyName(), normalIdCert->getPublicKeyInfo()); + db.addCertificate(*normalIdCert); + + Name command1("/localhost/pib/test/verb/param"); + shared_ptr interest1 = make_shared(command1); + m_keyChain.signByIdentity(*interest1, testUser); + // "test" user is trusted for any command about itself, OK. + isProcessed = false; + validator.validate(*interest1, + [this] (const shared_ptr&) { + isProcessed = true; + BOOST_CHECK(true); + }, + [this] (const shared_ptr&, const std::string&) { + isProcessed = true; + BOOST_CHECK(false); + }); + BOOST_CHECK(isProcessed); + + Name command2("/localhost/pib/test/verb/param"); + shared_ptr interest2 = make_shared(command2); + m_keyChain.signByIdentity(*interest2, testUser2); + // "test2" user is NOT trusted for any command about other user, MUST fail + isProcessed = false; + validator.validate(*interest2, + [this] (const shared_ptr&) { + isProcessed = true; + BOOST_CHECK(false); + }, + [this] (const shared_ptr&, const std::string&) { + isProcessed = true; + BOOST_CHECK(true); + }); + BOOST_CHECK(isProcessed); + + Name command3("/localhost/pib/test/verb/param"); + shared_ptr interest3 = make_shared(command3); + m_keyChain.signByIdentity(*interest3, normalId); + // "normalId" is in "test" pib, can be trusted for some commands about "test". + // Detail checking is needed, but it is not the job of Validator, OK. + isProcessed = false; + validator.validate(*interest3, + [this] (const shared_ptr&) { + isProcessed = true; + BOOST_CHECK(true); + }, + [this] (const shared_ptr&, const std::string&) { + isProcessed = true; + BOOST_CHECK(false); + }); + BOOST_CHECK(isProcessed); + +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace tests +} // namespace pib +} // namespace ndn diff --git a/tests/pib/pib.t.cpp b/tests/pib/pib.t.cpp new file mode 100644 index 0000000..f4c4e6f --- /dev/null +++ b/tests/pib/pib.t.cpp @@ -0,0 +1,1389 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "tools/pib/pib.hpp" +#include "identity-management-time-fixture.hpp" +#include +#include "tools/pib/encoding/pib-encoding.hpp" +#include +#include + +#include + +#include "tests/test-common.hpp" + +namespace ndn { +namespace pib { +namespace tests { + +class PibTestFixture : public ndn::security::IdentityManagementTimeFixture +{ +public: + PibTestFixture() + : tmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "PibTest") + , face(util::makeDummyClientFace(io, {true, true})) + { + } + + ~PibTestFixture() + { + boost::filesystem::remove_all(tmpPath); + } + + template + shared_ptr + generateUnsignedInterest(Param& param, const std::string& user) + { + Name command("/localhost/pib"); + command.append(user).append(Param::VERB).append(param.wireEncode()); + shared_ptr interest = make_shared(command); + + return interest; + } + + template + shared_ptr + generateSignedInterest(Param& param, const std::string& user, const Name& certName) + { + shared_ptr interest = generateUnsignedInterest(param, user); + m_keyChain.sign(*interest, certName); + + return interest; + } + + boost::asio::io_service io; + std::string owner; + boost::filesystem::path tmpPath; + shared_ptr face; +}; + +BOOST_FIXTURE_TEST_SUITE(TestPib, PibTestFixture) + +BOOST_AUTO_TEST_CASE(InitCertTest1) +{ + // Create a PIB with full parameters + owner = "testUser"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK_EQUAL(pib.getOwner(), owner); + BOOST_CHECK_EQUAL(pib.getDb().getOwnerName(), owner); + + auto mgmtCert = pib.getMgmtCert(); + BOOST_CHECK_EQUAL(mgmtCert.getName().getPrefix(-3), + Name("/localhost/pib/testUser/mgmt/KEY")); + BOOST_CHECK_EQUAL(mgmtCert.getName().get(5).toUri().substr(0, 4), "dsk-"); + + auto mgmtCert2 = pib.getDb().getMgmtCertificate(); + BOOST_REQUIRE(mgmtCert2 != nullptr); + BOOST_CHECK(mgmtCert.wireEncode() == mgmtCert2->wireEncode()); + + BOOST_CHECK_EQUAL(pib.getDb().getTpmLocator(), m_keyChain.getTpm().getTpmLocator()); + + GetParam param01; + shared_ptr interest01 = generateUnsignedInterest(param01, owner); + + face->receive(*interest01); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibUser result01; + BOOST_REQUIRE_NO_THROW(result01.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK(result01.getMgmtCert().wireEncode() == mgmtCert.wireEncode()); + BOOST_CHECK_EQUAL(result01.getTpmLocator(), m_keyChain.getTpm().getTpmLocator()); +} + +BOOST_AUTO_TEST_CASE(InitCertTest2) +{ + // Create a PIB from a database (assume that the database is configured) + std::string dbDir = tmpPath.string(); + std::string tpmLocator = m_keyChain.getTpm().getTpmLocator(); + owner = "testUser"; + + Name testUser("/localhost/pib/testUser/mgmt"); + + addIdentity(testUser); + Name testUserCertName = m_keyChain.getDefaultCertificateNameForIdentity(testUser); + shared_ptr testUserCert = m_keyChain.getCertificate(testUserCertName); + + PibDb db(tmpPath.string()); + BOOST_CHECK_NO_THROW(Pib(*face, dbDir, tpmLocator, owner)); + + db.updateMgmtCertificate(*testUserCert); + BOOST_CHECK_NO_THROW(Pib(*face, dbDir, tpmLocator, owner)); + BOOST_CHECK_THROW(Pib(*face, dbDir, tpmLocator, "wrongUser"), Pib::Error); + + db.setTpmLocator(m_keyChain.getTpm().getTpmLocator()); + BOOST_CHECK_NO_THROW(Pib(*face, dbDir, tpmLocator, owner)); + BOOST_CHECK_THROW(Pib(*face, dbDir, "tpm-file:wrong", owner), Pib::Error); + + advanceClocks(io, time::milliseconds(10)); + m_keyChain.deleteIdentity(testUser); + BOOST_CHECK_NO_THROW(Pib(*face, dbDir, tpmLocator, owner)); +} + +BOOST_AUTO_TEST_CASE(InitCertTest3) +{ + std::string dbDir = tmpPath.string(); + std::string tpmLocator = m_keyChain.getTpm().getTpmLocator(); + owner = "testUser"; + + Name testUser("/localhost/pib/testUser/mgmt"); + addIdentity(testUser); + Name testUserCertName = m_keyChain.getDefaultCertificateNameForIdentity(testUser); + shared_ptr testUserCert = m_keyChain.getCertificate(testUserCertName); + + Pib pib1(*face, dbDir, tpmLocator, owner); + BOOST_CHECK_EQUAL(pib1.getMgmtCert().getName().getPrefix(-3), + Name("/localhost/pib/testUser/mgmt/KEY")); + + PibDb db(tmpPath.string()); + db.updateMgmtCertificate(*testUserCert); + Pib pib2(*face, dbDir, tpmLocator, owner); + BOOST_CHECK_EQUAL(pib2.getMgmtCert().getName(), testUserCertName); + + advanceClocks(io, time::milliseconds(10)); + m_keyChain.deleteIdentity(testUser); + Pib pib3(*face, dbDir, tpmLocator, owner); + BOOST_CHECK(pib3.getMgmtCert().getName() != testUserCertName); + BOOST_CHECK_EQUAL(pib3.getMgmtCert().getName().getPrefix(-3), + Name("/localhost/pib/testUser/mgmt/KEY")); +} + +BOOST_AUTO_TEST_CASE(GetCommandTest) +{ + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + advanceClocks(io, time::milliseconds(10), 10); + util::InMemoryStoragePersistent& cache = pib.getResponseCache(); + auto ownerMgmtCert = pib.getMgmtCert(); + m_keyChain.addCertificate(ownerMgmtCert); + + PibDb db(tmpPath.string()); + + Name testId("/test/identity"); + Name testIdCertName00 = m_keyChain.createIdentity(testId); + shared_ptr cert00 = m_keyChain.getCertificate(testIdCertName00); + Name testIdKeyName0 = cert00->getPublicKeyName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert01 = m_keyChain.selfSign(testIdKeyName0); + Name testIdCertName01 = cert01->getName(); + + advanceClocks(io, time::milliseconds(100)); + Name testIdKeyName1 = m_keyChain.generateRsaKeyPair(testId); + shared_ptr cert10 = m_keyChain.selfSign(testIdKeyName1); + Name testIdCertName10 = cert10->getName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert11 = m_keyChain.selfSign(testIdKeyName1); + Name testIdCertName11 = cert11->getName(); + + BOOST_CHECK_EQUAL(db.hasIdentity(testId), false); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName0), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName00), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName01), false); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName1), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName10), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName11), false); + + db.addCertificate(*cert00); + db.addCertificate(*cert01); + db.addCertificate(*cert10); + db.addCertificate(*cert11); + db.setDefaultIdentity(testId); + db.setDefaultKeyNameOfIdentity(testIdKeyName0); + db.setDefaultCertNameOfKey(testIdCertName00); + + BOOST_CHECK_EQUAL(db.hasIdentity(testId), true); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName0), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName00), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName01), true); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName1), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName10), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName11), true); + + // Get Param + GetParam param01; + shared_ptr interest01 = generateUnsignedInterest(param01, owner); + + face->sentDatas.clear(); + face->receive(*interest01); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest01->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibUser result01; + BOOST_REQUIRE_NO_THROW(result01.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK(result01.getMgmtCert().wireEncode() == ownerMgmtCert.wireEncode()); + + + GetParam param02; + shared_ptr interest02 = generateUnsignedInterest(param02, "non-existing"); + + face->sentDatas.clear(); + face->receive(*interest02); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest02->getName()) == nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0); + + + GetParam param03(TYPE_ID, testId); + shared_ptr interest03 = generateUnsignedInterest(param03, owner); + + face->sentDatas.clear(); + face->receive(*interest03); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest03->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibIdentity result03; + BOOST_REQUIRE_NO_THROW(result03.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result03.getIdentity(), testId); + + + Name wrongId("/wrong/id"); + GetParam param04(TYPE_ID, wrongId); + shared_ptr interest04 = generateUnsignedInterest(param04, owner); + + face->sentDatas.clear(); + face->receive(*interest04); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest04->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result04; + BOOST_REQUIRE_NO_THROW(result04.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result04.getErrorCode(), ERR_NON_EXISTING_ID); + + + GetParam param05(TYPE_KEY, testIdKeyName1); + shared_ptr interest05 = generateUnsignedInterest(param05, owner); + + face->sentDatas.clear(); + face->receive(*interest05); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest05->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibPublicKey result05; + BOOST_REQUIRE_NO_THROW(result05.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result05.getKeyName(), testIdKeyName1); + + + Name wrongKeyName1("/wrong/key/name1"); + GetParam param06(TYPE_KEY, wrongKeyName1); + shared_ptr interest06 = generateUnsignedInterest(param06, owner); + + face->sentDatas.clear(); + face->receive(*interest06); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest06->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result06; + BOOST_REQUIRE_NO_THROW(result06.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result06.getErrorCode(), ERR_NON_EXISTING_KEY); + + + GetParam param07(TYPE_CERT, testIdCertName00); + shared_ptr interest07 = generateUnsignedInterest(param07, owner); + + face->sentDatas.clear(); + face->receive(*interest07); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest07->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibCertificate result07; + BOOST_REQUIRE_NO_THROW(result07.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result07.getCertificate().getName(), testIdCertName00); + + + Name wrongCertName1("/wrong/cert/name1"); + GetParam param08(TYPE_CERT, wrongCertName1); + shared_ptr interest08 = generateUnsignedInterest(param08, owner); + + face->sentDatas.clear(); + face->receive(*interest08); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest08->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result08; + BOOST_REQUIRE_NO_THROW(result08.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result08.getErrorCode(), ERR_NON_EXISTING_CERT); + + + Name wrongKeyName2; + GetParam param09(TYPE_KEY, wrongKeyName2); + shared_ptr interest09 = generateUnsignedInterest(param09, owner); + + face->sentDatas.clear(); + face->receive(*interest09); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest09->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result09; + BOOST_REQUIRE_NO_THROW(result09.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result09.getErrorCode(), ERR_WRONG_PARAM); +} + +BOOST_AUTO_TEST_CASE(DefaultCommandTest) +{ + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + advanceClocks(io, time::milliseconds(10), 10); + util::InMemoryStoragePersistent& cache = pib.getResponseCache(); + auto ownerMgmtCert = pib.getMgmtCert(); + m_keyChain.addCertificate(ownerMgmtCert); + + PibDb db(tmpPath.string()); + + Name testId("/test/identity"); + Name testIdCertName00 = m_keyChain.createIdentity(testId); + shared_ptr cert00 = m_keyChain.getCertificate(testIdCertName00); + Name testIdKeyName0 = cert00->getPublicKeyName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert01 = m_keyChain.selfSign(testIdKeyName0); + Name testIdCertName01 = cert01->getName(); + + advanceClocks(io, time::milliseconds(100)); + Name testIdKeyName1 = m_keyChain.generateRsaKeyPair(testId); + shared_ptr cert10 = m_keyChain.selfSign(testIdKeyName1); + Name testIdCertName10 = cert10->getName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert11 = m_keyChain.selfSign(testIdKeyName1); + Name testIdCertName11 = cert11->getName(); + + BOOST_CHECK_EQUAL(db.hasIdentity(testId), false); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName0), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName00), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName01), false); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName1), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName10), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName11), false); + + db.addCertificate(*cert00); + db.addCertificate(*cert01); + db.addCertificate(*cert10); + db.addCertificate(*cert11); + db.setDefaultIdentity(testId); + db.setDefaultKeyNameOfIdentity(testIdKeyName0); + db.setDefaultCertNameOfKey(testIdCertName00); + + BOOST_CHECK_EQUAL(db.hasIdentity(testId), true); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName0), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName00), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName01), true); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName1), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName10), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName11), true); + + // Default Param + DefaultParam param11(TYPE_ID, TYPE_USER); + shared_ptr interest11 = generateUnsignedInterest(param11, owner); + + face->sentDatas.clear(); + face->receive(*interest11); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest11->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibIdentity result11; + BOOST_REQUIRE_NO_THROW(result11.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result11.getIdentity(), testId); + + + DefaultParam param13(TYPE_ID, TYPE_ID); + shared_ptr interest13 = generateUnsignedInterest(param13, owner); + + face->sentDatas.clear(); + face->receive(*interest13); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest13->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result13; + BOOST_REQUIRE_NO_THROW(result13.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result13.getErrorCode(), ERR_WRONG_PARAM); + + + DefaultParam param14(TYPE_KEY, TYPE_ID, testId); + shared_ptr interest14 = generateUnsignedInterest(param14, owner); + + face->sentDatas.clear(); + face->receive(*interest14); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest14->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibPublicKey result14; + BOOST_REQUIRE_NO_THROW(result14.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result14.getKeyName(), testIdKeyName0); + + + DefaultParam param15(TYPE_CERT, TYPE_ID, testId); + shared_ptr interest15 = generateUnsignedInterest(param15, owner); + + face->sentDatas.clear(); + face->receive(*interest15); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest15->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibCertificate result15; + BOOST_REQUIRE_NO_THROW(result15.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result15.getCertificate().getName(), testIdCertName00); + + + DefaultParam param16(TYPE_CERT, TYPE_USER); + shared_ptr interest16 = generateUnsignedInterest(param16, owner); + + face->sentDatas.clear(); + face->receive(*interest16); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest16->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibCertificate result16; + BOOST_REQUIRE_NO_THROW(result16.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result16.getCertificate().getName(), testIdCertName00); + + + DefaultParam param17(TYPE_CERT, TYPE_KEY, testIdKeyName1); + shared_ptr interest17 = generateUnsignedInterest(param17, owner); + + face->sentDatas.clear(); + face->receive(*interest17); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest17->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibCertificate result17; + BOOST_REQUIRE_NO_THROW(result17.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result17.getCertificate().getName(), testIdCertName10); +} + +BOOST_AUTO_TEST_CASE(ListCommandTest) +{ + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + advanceClocks(io, time::milliseconds(10), 10); + util::InMemoryStoragePersistent& cache = pib.getResponseCache(); + auto ownerMgmtCert = pib.getMgmtCert(); + m_keyChain.addCertificate(ownerMgmtCert); + + PibDb db(tmpPath.string()); + + Name testId("/test/identity"); + Name testIdCertName00 = m_keyChain.createIdentity(testId); + shared_ptr cert00 = m_keyChain.getCertificate(testIdCertName00); + Name testIdKeyName0 = cert00->getPublicKeyName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert01 = m_keyChain.selfSign(testIdKeyName0); + Name testIdCertName01 = cert01->getName(); + + advanceClocks(io, time::milliseconds(100)); + Name testIdKeyName1 = m_keyChain.generateRsaKeyPair(testId); + shared_ptr cert10 = m_keyChain.selfSign(testIdKeyName1); + Name testIdCertName10 = cert10->getName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert11 = m_keyChain.selfSign(testIdKeyName1); + Name testIdCertName11 = cert11->getName(); + + BOOST_CHECK_EQUAL(db.hasIdentity(testId), false); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName0), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName00), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName01), false); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName1), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName10), false); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName11), false); + + db.addCertificate(*cert00); + db.addCertificate(*cert01); + db.addCertificate(*cert10); + db.addCertificate(*cert11); + db.setDefaultIdentity(testId); + db.setDefaultKeyNameOfIdentity(testIdKeyName0); + db.setDefaultCertNameOfKey(testIdCertName00); + + BOOST_CHECK_EQUAL(db.hasIdentity(testId), true); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName0), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName00), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName01), true); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName1), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName10), true); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName11), true); + + Name wrongId("/wrong/id"); + + // List Param + ListParam param21; + shared_ptr interest21 = generateUnsignedInterest(param21, owner); + + face->sentDatas.clear(); + face->receive(*interest21); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest21->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibNameList result21; + BOOST_REQUIRE_NO_THROW(result21.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result21.getNameList().size(), 1); + + + ListParam param22(TYPE_ID, testId); + shared_ptr interest22 = generateUnsignedInterest(param22, owner); + + face->sentDatas.clear(); + face->receive(*interest22); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest22->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibNameList result22; + BOOST_REQUIRE_NO_THROW(result22.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result22.getNameList().size(), 2); + + + ListParam param23(TYPE_ID, wrongId); + shared_ptr interest23 = generateUnsignedInterest(param23, owner); + + face->sentDatas.clear(); + face->receive(*interest23); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest23->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibNameList result23; + BOOST_REQUIRE_NO_THROW(result23.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result23.getNameList().size(), 0); +} + +BOOST_AUTO_TEST_CASE(IsUpdateAllowedTest1) +{ + // This test case is to check the access control of local management key + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + + UpdateQueryProcessor& pro = pib.m_updateProcessor; + + Name target01("/localhost/pib"); + Name target02("/localhost/pib/alice/mgmt"); + Name target03("/localhost/pib/alice/mgmt/ok"); + Name target04("/localhost/pib/alice"); + Name target05("/test/id"); + Name target06("/test/id/ksk-123"); + Name target07("/test/id/KEY/ksk-123/ID-CERT/version"); + Name signer01 = pib.getMgmtCert().getName().getPrefix(-1); + Name signer02("/localhost/pib/bob/mgmt/KEY/ksk-1234/ID-CERT"); + + // TYPE_USER is handled separately, isUpdatedAllowed simply returns false + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_USER, target02, signer01, DEFAULT_OPT_NO), false); + + // Test access control of local management key + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, target01, signer01, DEFAULT_OPT_NO), false); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, target02, signer01, DEFAULT_OPT_NO), false); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, target03, signer01, DEFAULT_OPT_NO), false); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, target04, signer01, DEFAULT_OPT_NO), false); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, target05, signer01, DEFAULT_OPT_NO), true); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, target05, signer02, DEFAULT_OPT_NO), false); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, target06, signer01, DEFAULT_OPT_NO), true); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, target06, signer02, DEFAULT_OPT_NO), false); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, target07, signer01, DEFAULT_OPT_NO), true); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, target07, signer02, DEFAULT_OPT_NO), false); +} + +BOOST_AUTO_TEST_CASE(IsUpdateAllowedTest2) +{ + // This test case is to check the access control of regular key + + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + PibDb db(tmpPath.string()); + + UpdateQueryProcessor& pro = pib.m_updateProcessor; + + Name parent("/test"); + addIdentity(parent); + Name parentCertName = m_keyChain.getDefaultCertificateNameForIdentity(parent); + shared_ptr parentCert = m_keyChain.getCertificate(parentCertName); + Name parentSigner = parentCertName.getPrefix(-1); + + advanceClocks(io, time::milliseconds(100)); + Name parentKeyName2 = m_keyChain.generateRsaKeyPair(parent); + shared_ptr parentCert2 = m_keyChain.selfSign(parentKeyName2); + Name parentSigner2 = parentCert2->getName().getPrefix(-1); + + db.addIdentity(parent); + db.addKey(parentCert->getPublicKeyName(), parentCert->getPublicKeyInfo()); + db.addKey(parentCert2->getPublicKeyName(), parentCert2->getPublicKeyInfo()); + db.setDefaultKeyNameOfIdentity(parentCert->getPublicKeyName()); + db.addCertificate(*parentCert); + db.setDefaultCertNameOfKey(parentCert->getName()); + db.addCertificate(*parentCert2); + db.setDefaultCertNameOfKey(parentCert2->getName()); + + Name testId("/test/id"); + addIdentity(testId); + Name certName = m_keyChain.getDefaultCertificateNameForIdentity(testId); + shared_ptr testCert = m_keyChain.getCertificate(certName); + Name testKeyName = testCert->getPublicKeyName(); + Name testSigner = certName.getPrefix(-1); + + advanceClocks(io, time::milliseconds(100)); + Name secondKeyName = m_keyChain.generateRsaKeyPair(testId); + shared_ptr secondCert = m_keyChain.selfSign(secondKeyName); + Name secondCertName = secondCert->getName(); + Name secondSigner = secondCertName.getPrefix(-1); + + db.addIdentity(testId); + db.addKey(testKeyName, testCert->getPublicKeyInfo()); + db.addKey(secondKeyName, secondCert->getPublicKeyInfo()); + db.setDefaultKeyNameOfIdentity(testKeyName); + db.addCertificate(*testCert); + db.setDefaultCertNameOfKey(testCert->getName()); + db.addCertificate(*secondCert); + db.setDefaultCertNameOfKey(secondCert->getName()); + + Name nonSigner("/non-signer/KEY/ksk-123/ID-CERT"); + + // for target type = TYPE_ID + // one cannot add non-child + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, testId, nonSigner, DEFAULT_OPT_NO), false); + // parent can add child + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, testId, parentSigner, DEFAULT_OPT_NO), true); + // non-default parent key cannot add a child + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, testId, parentSigner2, DEFAULT_OPT_NO), false); + // only DEFAULT_OPT_NO is allowed if target type is TYPE_ID + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, testId, parentSigner, DEFAULT_OPT_ID), false); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, testId, parentSigner, DEFAULT_OPT_KEY), false); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_ID, testId, parentSigner, DEFAULT_OPT_USER), false); + + // for target type = TYPE_KEY + // one can add its own key + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, testKeyName, testSigner, DEFAULT_OPT_NO), + true); + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, secondKeyName, testSigner, DEFAULT_OPT_NO), + true); + // one can set its default key + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, testKeyName, testSigner, DEFAULT_OPT_ID), + true); + // non-default key cannot add its own key + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, secondKeyName, secondSigner, DEFAULT_OPT_NO), + false); + // non-default key cannot set its default key + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, testKeyName, secondSigner, DEFAULT_OPT_ID), + false); + // one can add its child's key + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, secondKeyName, parentSigner, DEFAULT_OPT_NO), + true); + // one can set its child's default key + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, testKeyName, parentSigner, DEFAULT_OPT_ID), + true); + // non-default key cannot add its child's key + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, secondKeyName, parentSigner2, DEFAULT_OPT_NO), + false); + // non-default parent key cannot set its child's default key + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, testKeyName, parentSigner2, DEFAULT_OPT_ID), + false); + // DEFAULT_OPT_KEY is not allowed if target type is TYPE_KEY + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, testKeyName, testSigner, DEFAULT_OPT_KEY), + false); + // DEFAULT_OPT_USER is not allowed if signer is no local management key + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_KEY, testKeyName, testSigner, DEFAULT_OPT_USER), + false); + + // for target type = TYPE_CERT + // one can add its own certificate + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, certName, testSigner, DEFAULT_OPT_NO), + true); + // one can set its own default certificate + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, certName, testSigner, DEFAULT_OPT_ID), + true); + // one can set its own key's default certificate + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, certName, testSigner, DEFAULT_OPT_KEY), + true); + // DEFAULT_OPT_USER is not allowed if signer is no local management key + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, certName, testSigner, DEFAULT_OPT_USER), + false); + // non-default key can add other key's certificate + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, certName, secondSigner, DEFAULT_OPT_NO), + false); + // non-default key can add its own certificate + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, secondCertName, secondSigner, DEFAULT_OPT_NO), + true); + // one can add its child's certificate + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, certName, parentSigner, DEFAULT_OPT_NO), + true); + // non-default key cannot add its child's certificate + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, certName, parentSigner2, DEFAULT_OPT_NO), + false); + // non-default key cannot set add its identity default certificate + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, secondCertName, secondSigner, DEFAULT_OPT_ID), + false); + // non-default key can set add its own default certificate + BOOST_CHECK_EQUAL(pro.isUpdateAllowed(TYPE_CERT, secondCertName, secondSigner, DEFAULT_OPT_KEY), + true); +} + +BOOST_AUTO_TEST_CASE(IsDeleteAllowedTest1) +{ + // This test case is to check the access control of local management key + + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + + DeleteQueryProcessor& pro = pib.m_deleteProcessor; + + Name target01("/localhost/pib"); + Name target02("/localhost/pib/alice/Mgmt"); + Name target03("/localhost/pib/alice/Mgmt/ok"); + Name target04("/localhost/pib/alice"); + Name target05("/test/id"); + Name target06("/test/id/ksk-123"); + Name target07("/test/id/KEY/ksk-123/ID-CERT/version"); + Name signer01 = pib.getMgmtCert().getName().getPrefix(-1); + Name signer02("/localhost/pib/bob/Mgmt/KEY/ksk-1234/ID-CERT"); + + // TYPE_USER is handled separately + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_USER, target02, signer01), false); + + // Test access control of local management key + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_ID, target01, signer01), false); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_ID, target02, signer01), false); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_ID, target03, signer01), false); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_ID, target04, signer01), false); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_ID, target05, signer01), true); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_KEY, target06, signer01), true); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_CERT, target07, signer01), true); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_ID, target05, signer02), false); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_KEY, target06, signer02), false); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_CERT, target07, signer02), false); +} + +BOOST_AUTO_TEST_CASE(IsDeleteAllowedTest2) +{ + // This test case is to check the access control of regular key + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + PibDb db(tmpPath.string()); + DeleteQueryProcessor& pro = pib.m_deleteProcessor; + + Name parent("/test"); + addIdentity(parent); + Name parentCertName = m_keyChain.getDefaultCertificateNameForIdentity(parent); + shared_ptr parentCert = m_keyChain.getCertificate(parentCertName); + Name parentSigner = parentCertName.getPrefix(-1); + + advanceClocks(io, time::milliseconds(100)); + Name parentKeyName2 = m_keyChain.generateRsaKeyPair(parent); + shared_ptr parentCert2 = m_keyChain.selfSign(parentKeyName2); + Name parentSigner2 = parentCert2->getName().getPrefix(-1); + + db.addIdentity(parent); + db.addKey(parentCert->getPublicKeyName(), parentCert->getPublicKeyInfo()); + db.addKey(parentCert2->getPublicKeyName(), parentCert2->getPublicKeyInfo()); + db.setDefaultKeyNameOfIdentity(parentCert->getPublicKeyName()); + db.addCertificate(*parentCert); + db.setDefaultCertNameOfKey(parentCert->getName()); + db.addCertificate(*parentCert2); + db.setDefaultCertNameOfKey(parentCert2->getName()); + + Name testId("/test/id"); + addIdentity(testId); + Name certName = m_keyChain.getDefaultCertificateNameForIdentity(testId); + shared_ptr testCert = m_keyChain.getCertificate(certName); + Name testKeyName = testCert->getPublicKeyName(); + Name testSigner = certName.getPrefix(-1); + + advanceClocks(io, time::milliseconds(100)); + Name secondKeyName = m_keyChain.generateRsaKeyPair(testId); + shared_ptr secondCert = m_keyChain.selfSign(secondKeyName); + Name secondCertName = secondCert->getName(); + Name secondSigner = secondCertName.getPrefix(-1); + + db.addIdentity(testId); + db.addKey(testKeyName, testCert->getPublicKeyInfo()); + db.addKey(secondKeyName, secondCert->getPublicKeyInfo()); + db.setDefaultKeyNameOfIdentity(testKeyName); + db.addCertificate(*testCert); + db.setDefaultCertNameOfKey(testCert->getName()); + db.addCertificate(*secondCert); + db.setDefaultCertNameOfKey(secondCert->getName()); + + Name nonSigner("/non-signer/KEY/ksk-123/ID-CERT"); + + // one can delete itself + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_ID, testId, testSigner), true); + // parent can delete its child + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_ID, testId, parentSigner), true); + // non-default key cannot delete its identity + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_ID, testId, secondSigner), false); + // non-default key cannot delete its child + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_ID, testId, parentSigner2), false); + // one cannot delete its parent + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_ID, parent, testSigner), false); + + // one can delete its own key + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_KEY, testKeyName, testSigner), true); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_KEY, secondKeyName, testSigner), true); + // parent can delete its child's key + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_KEY, testKeyName, parentSigner), true); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_KEY, secondKeyName, parentSigner), true); + // non-default key cannot delete other key + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_KEY, testKeyName, secondSigner), false); + // non-default key can delete itself + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_KEY, secondKeyName, secondSigner), true); + // non-default key cannot delete its child's key + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_KEY, testKeyName, parentSigner2), false); + + // one can delete its own certificate + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_CERT, certName, testSigner), true); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_CERT, secondCertName, testSigner), true); + // non-default key cannot delete other's certificate + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_CERT, certName, secondSigner), false); + // non-default key can delete its own certificate + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_CERT, secondCertName, secondSigner), true); + // parent can delete its child's certificate + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_CERT, certName, parentSigner), true); + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_CERT, secondCertName, parentSigner), true); + // non-default parent cannot delete its child's certificate + BOOST_CHECK_EQUAL(pro.isDeleteAllowed(TYPE_CERT, certName, parentSigner2), false); +} + + +BOOST_AUTO_TEST_CASE(UpdateUserTest) +{ + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + + advanceClocks(io, time::milliseconds(10), 10); + util::InMemoryStoragePersistent& cache = pib.getResponseCache(); + + m_keyChain.addCertificate(pib.getMgmtCert()); + + PibDb db(tmpPath.string()); + + Name bob("/localhost/pib/bob/mgmt"); + addIdentity(bob); + Name bobCertName = m_keyChain.getDefaultCertificateNameForIdentity(bob); + shared_ptr bobCert = m_keyChain.getCertificate(bobCertName); + + // signer is correct, but user name is wrong, should fall + PibUser pibUser1; + pibUser1.setMgmtCert(*bobCert); + UpdateParam param1(pibUser1); + auto interest1 = generateSignedInterest(param1, owner, db.getMgmtCertificate()->getName()); + + face->sentDatas.clear(); + face->receive(*interest1); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest1->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result; + BOOST_REQUIRE_NO_THROW(result.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result.getErrorCode(), ERR_WRONG_PARAM); + + // user name is correct, but signer is wrong, should fail + PibUser pibUser2; + pibUser2.setMgmtCert(pib.getMgmtCert()); + UpdateParam param2(pibUser2); + auto interest2 = generateSignedInterest(param2, owner, bobCertName); + + face->sentDatas.clear(); + face->receive(*interest2); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest2->getName()) == nullptr); // verification should fail, no response + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0); + + // update an existing user with a new mgmt key, signed by the old mgmt key. + advanceClocks(io, time::milliseconds(100)); + Name ownerSecondKeyName = + m_keyChain.generateRsaKeyPair(Name("/localhost/pib/alice/mgmt"), false); + shared_ptr ownerSecondCert = m_keyChain.selfSign(ownerSecondKeyName); + m_keyChain.addCertificate(*ownerSecondCert); + + PibUser pibUser3; + pibUser3.setMgmtCert(*ownerSecondCert); + UpdateParam param3(pibUser3); + auto interest3 = generateSignedInterest(param3, owner, db.getMgmtCertificate()->getName()); + + face->sentDatas.clear(); + face->receive(*interest3); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest3->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result3; + BOOST_REQUIRE_NO_THROW(result3.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result3.getErrorCode(), ERR_SUCCESS); + BOOST_CHECK(db.getMgmtCertificate()->wireEncode() == ownerSecondCert->wireEncode()); + + // Add an cert and set it as user default cert. + Name testId("/test/id"); + Name testIdCertName = m_keyChain.createIdentity(testId); + shared_ptr testIdCert = m_keyChain.getCertificate(testIdCertName); + Name testIdKeyName = testIdCert->getPublicKeyName(); + UpdateParam updateParam(*testIdCert, DEFAULT_OPT_USER); + auto interest4 = generateSignedInterest(updateParam, owner, ownerSecondCert->getName()); + + face->sentDatas.clear(); + face->receive(*interest4); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_REQUIRE(cache.find(interest4->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result4; + BOOST_REQUIRE_NO_THROW(result4.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result4.getErrorCode(), ERR_SUCCESS); + + BOOST_CHECK(pib.getDb().hasCertificate(testIdCertName)); + BOOST_CHECK(pib.getDb().hasKey(testIdKeyName)); + BOOST_CHECK(pib.getDb().hasIdentity(testId)); + + BOOST_REQUIRE_NO_THROW(pib.getDb().getDefaultCertNameOfKey(testIdKeyName)); + BOOST_REQUIRE_NO_THROW(pib.getDb().getDefaultKeyNameOfIdentity(testId)); + BOOST_REQUIRE_NO_THROW(pib.getDb().getDefaultIdentity()); + + BOOST_CHECK_EQUAL(pib.getDb().getDefaultCertNameOfKey(testIdKeyName), testIdCertName); + BOOST_CHECK_EQUAL(pib.getDb().getDefaultKeyNameOfIdentity(testId), testIdKeyName); + BOOST_CHECK_EQUAL(pib.getDb().getDefaultIdentity(), testId); +} + +BOOST_AUTO_TEST_CASE(UpdateRegularKeyTest) +{ + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + + advanceClocks(io, time::milliseconds(10), 10); + util::InMemoryStoragePersistent& cache = pib.getResponseCache(); + auto ownerMgmtCert = pib.getMgmtCert(); + m_keyChain.addCertificate(ownerMgmtCert); + + PibDb db(tmpPath.string()); + + Name id0("/test/identity0"); + Name certName000 = m_keyChain.createIdentity(id0); + shared_ptr cert000 = m_keyChain.getCertificate(certName000); + Name keyName00 = cert000->getPublicKeyName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert001 = m_keyChain.selfSign(keyName00); + Name certName001 = cert001->getName(); + + advanceClocks(io, time::milliseconds(100)); + Name keyName01 = m_keyChain.generateRsaKeyPair(id0); + shared_ptr cert010 = m_keyChain.selfSign(keyName01); + Name certName010 = cert010->getName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert011 = m_keyChain.selfSign(keyName01); + Name certName011 = cert011->getName(); + m_keyChain.addCertificate(*cert010); + + advanceClocks(io, time::milliseconds(100)); + Name id1("/test/identity1"); + Name certName100 = m_keyChain.createIdentity(id1); + shared_ptr cert100 = m_keyChain.getCertificate(certName100); + Name keyName10 = cert100->getPublicKeyName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert101 = m_keyChain.selfSign(keyName10); + Name certName101 = cert101->getName(); + + advanceClocks(io, time::milliseconds(100)); + Name keyName11 = m_keyChain.generateRsaKeyPair(id1); + shared_ptr cert110 = m_keyChain.selfSign(keyName11); + Name certName110 = cert110->getName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert111 = m_keyChain.selfSign(keyName11); + Name certName111 = cert111->getName(); + m_keyChain.addCertificate(*cert111); + + + // Add a cert + BOOST_CHECK_EQUAL(db.hasIdentity(id0), false); + BOOST_CHECK_EQUAL(db.hasKey(keyName00), false); + BOOST_CHECK_EQUAL(db.hasCertificate(certName000), false); + UpdateParam param1(*cert000); + auto interest1 = generateSignedInterest(param1, owner, ownerMgmtCert.getName()); + + face->sentDatas.clear(); + face->receive(*interest1); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest1->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result1; + BOOST_REQUIRE_NO_THROW(result1.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result1.getErrorCode(), ERR_SUCCESS); + BOOST_CHECK_EQUAL(db.hasIdentity(id0), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName00), true); + BOOST_CHECK_EQUAL(db.hasCertificate(certName000), true); + + db.addCertificate(*cert100); + BOOST_CHECK_EQUAL(db.hasIdentity(id1), true); + BOOST_CHECK_EQUAL(db.hasKey(keyName10), true); + BOOST_CHECK_EQUAL(db.hasCertificate(certName100), true); + + // Set default + BOOST_CHECK_EQUAL(db.getDefaultIdentity(), id0); + BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id0), keyName00); + BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName00), certName000); + + UpdateParam param2(id1, DEFAULT_OPT_USER); + auto interest2 = generateSignedInterest(param2, owner, ownerMgmtCert.getName()); + + face->sentDatas.clear(); + face->receive(*interest2); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest2->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result2; + BOOST_REQUIRE_NO_THROW(result2.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result2.getErrorCode(), ERR_SUCCESS); + BOOST_CHECK_EQUAL(db.getDefaultIdentity(), id1); + + db.addCertificate(*cert010); + UpdateParam param3(keyName01, cert010->getPublicKeyInfo(), DEFAULT_OPT_ID); + auto interest3 = generateSignedInterest(param3, owner, ownerMgmtCert.getName()); + + face->sentDatas.clear(); + face->receive(*interest3); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest3->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result3; + BOOST_REQUIRE_NO_THROW(result3.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result3.getErrorCode(), ERR_SUCCESS); + BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id0), keyName01); + + db.addCertificate(*cert011); + UpdateParam param4(*cert011, DEFAULT_OPT_KEY); + auto interest4 = generateSignedInterest(param4, owner, ownerMgmtCert.getName()); + + face->sentDatas.clear(); + face->receive(*interest4); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest4->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result4; + BOOST_REQUIRE_NO_THROW(result4.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result4.getErrorCode(), ERR_SUCCESS); + BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName01), certName011); + + // add key and certificate using regular keys. + BOOST_CHECK_EQUAL(db.hasKey(keyName11), false); + UpdateParam param5(keyName11, cert110->getPublicKeyInfo()); + auto interest5 = generateSignedInterest(param5, owner, cert100->getName()); + + face->sentDatas.clear(); + face->receive(*interest5); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest5->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result5; + BOOST_REQUIRE_NO_THROW(result5.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result5.getErrorCode(), ERR_SUCCESS); + BOOST_CHECK_EQUAL(db.hasKey(keyName11), true); + + // add cert using its own key which has been added before + BOOST_CHECK_EQUAL(db.hasCertificate(cert101->getName()), false); + UpdateParam param6(*cert101); + auto interest6 = generateSignedInterest(param6, owner, cert100->getName()); + + face->sentDatas.clear(); + face->receive(*interest6); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest6->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result6; + BOOST_REQUIRE_NO_THROW(result6.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result6.getErrorCode(), ERR_SUCCESS); + BOOST_CHECK_EQUAL(db.hasCertificate(cert101->getName()), true); +} + +BOOST_AUTO_TEST_CASE(DeleteUserTest) +{ + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + advanceClocks(io, time::milliseconds(10), 10); + util::InMemoryStoragePersistent& cache = pib.getResponseCache(); + auto ownerMgmtCert = pib.getMgmtCert(); + m_keyChain.addCertificate(ownerMgmtCert); + + PibDb db(tmpPath.string()); + + // Delete user should fail + DeleteParam param(Name(), TYPE_USER); + auto interest = generateSignedInterest(param, owner, ownerMgmtCert.getName()); + + face->receive(*interest); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result; + BOOST_REQUIRE_NO_THROW(result.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result.getErrorCode(), ERR_WRONG_PARAM); +} + +BOOST_AUTO_TEST_CASE(DeleteRegularKeyTest) +{ + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + advanceClocks(io, time::milliseconds(10), 10); + util::InMemoryStoragePersistent& cache = pib.getResponseCache(); + auto ownerMgmtCert = pib.getMgmtCert(); + m_keyChain.addCertificate(ownerMgmtCert); + + PibDb& db = pib.getDb(); + + Name testId("/test/identity"); + Name testIdCertName00 = m_keyChain.createIdentity(testId); + shared_ptr cert00 = m_keyChain.getCertificate(testIdCertName00); + Name testIdKeyName0 = cert00->getPublicKeyName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert01 = m_keyChain.selfSign(testIdKeyName0); + Name testIdCertName01 = cert01->getName(); + + advanceClocks(io, time::milliseconds(100)); + Name testIdKeyName1 = m_keyChain.generateRsaKeyPair(testId); + shared_ptr cert10 = m_keyChain.selfSign(testIdKeyName1); + Name testIdCertName10 = cert10->getName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert11 = m_keyChain.selfSign(testIdKeyName1); + Name testIdCertName11 = cert11->getName(); + m_keyChain.addCertificate(*cert11); + + db.addCertificate(*cert00); + db.addCertificate(*cert01); + db.addCertificate(*cert10); + db.addCertificate(*cert11); + db.setDefaultIdentity(testId); + db.setDefaultKeyNameOfIdentity(testIdKeyName0); + db.setDefaultCertNameOfKey(testIdCertName00); + db.setDefaultCertNameOfKey(testIdCertName10); + + // delete a certificate itself + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName11), true); + DeleteParam param1(testIdCertName11, TYPE_CERT); + auto interest1 = generateSignedInterest(param1, owner, testIdCertName11); + + face->sentDatas.clear(); + face->receive(*interest1); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest1->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result1; + BOOST_REQUIRE_NO_THROW(result1.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result1.getErrorCode(), ERR_SUCCESS); + BOOST_CHECK_EQUAL(db.hasCertificate(testIdCertName11), false); + + // delete a key itself + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName1), true); + DeleteParam param2(testIdKeyName1, TYPE_KEY); + auto interest2 = generateSignedInterest(param2, owner, testIdCertName11); + + face->sentDatas.clear(); + face->receive(*interest2); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest2->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result2; + BOOST_REQUIRE_NO_THROW(result2.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result2.getErrorCode(), ERR_SUCCESS); + BOOST_CHECK_EQUAL(db.hasKey(testIdKeyName1), false); + + // delete an identity using non-default key, should fail + db.addCertificate(*cert11); + BOOST_CHECK_EQUAL(db.hasIdentity(testId), true); + DeleteParam param3(testId, TYPE_ID); + auto interest3 = generateSignedInterest(param3, owner, testIdCertName11); + + face->sentDatas.clear(); + face->receive(*interest3); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest3->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result3; + BOOST_REQUIRE_NO_THROW(result3.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result3.getErrorCode(), ERR_WRONG_SIGNER); + BOOST_CHECK_EQUAL(db.hasIdentity(testId), true); + + // delete an identity using identity default key, should succeed + DeleteParam param4(testId, TYPE_ID); + auto interest4 = generateSignedInterest(param4, owner, testIdCertName00); + + face->sentDatas.clear(); + face->receive(*interest4); + advanceClocks(io, time::milliseconds(10), 10); + + BOOST_CHECK(cache.find(interest4->getName()) != nullptr); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + PibError result4; + BOOST_REQUIRE_NO_THROW(result4.wireDecode(face->sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(result4.getErrorCode(), ERR_SUCCESS); + BOOST_CHECK_EQUAL(db.hasIdentity(testId), false); +} + +BOOST_AUTO_TEST_CASE(ReadCommandTest2) +{ + // Read Certificates; + owner = "alice"; + + Pib pib(*face, + tmpPath.string(), + m_keyChain.getTpm().getTpmLocator(), + owner); + + advanceClocks(io, time::milliseconds(10), 100); + auto ownerMgmtCert = pib.getMgmtCert(); + m_keyChain.addCertificate(ownerMgmtCert); + + Name testId("/test/identity"); + Name testIdCertName00 = m_keyChain.createIdentity(testId); + shared_ptr cert00 = m_keyChain.getCertificate(testIdCertName00); + Name testIdKeyName0 = cert00->getPublicKeyName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert01 = m_keyChain.selfSign(testIdKeyName0); + Name testIdCertName01 = cert01->getName(); + + advanceClocks(io, time::milliseconds(100)); + Name testIdKeyName1 = m_keyChain.generateRsaKeyPair(testId); + shared_ptr cert10 = m_keyChain.selfSign(testIdKeyName1); + Name testIdCertName10 = cert10->getName(); + advanceClocks(io, time::milliseconds(100)); + shared_ptr cert11 = m_keyChain.selfSign(testIdKeyName1); + Name testIdCertName11 = cert11->getName(); + + + UpdateParam param00(*cert00); + UpdateParam param01(*cert01); + UpdateParam param10(*cert10); + UpdateParam param11(*cert11); + auto interest00 = generateSignedInterest(param00, owner, ownerMgmtCert.getName()); + auto interest01 = generateSignedInterest(param01, owner, ownerMgmtCert.getName()); + auto interest10 = generateSignedInterest(param10, owner, ownerMgmtCert.getName()); + auto interest11 = generateSignedInterest(param11, owner, ownerMgmtCert.getName()); + + face->sentDatas.clear(); + face->receive(*interest00); + advanceClocks(io, time::milliseconds(10), 10); + face->receive(*interest01); + advanceClocks(io, time::milliseconds(10), 10); + face->receive(*interest10); + advanceClocks(io, time::milliseconds(10), 10); + face->receive(*interest11); + advanceClocks(io, time::milliseconds(10), 10); + + auto interest1 = make_shared(testIdCertName11); + face->sentDatas.clear(); + face->receive(*interest1); + advanceClocks(io, time::milliseconds(10), 10); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + BOOST_CHECK(face->sentDatas[0].wireEncode() == cert11->wireEncode()); + + auto interest2 = make_shared(testIdCertName11.getPrefix(-1)); + face->sentDatas.clear(); + face->receive(*interest2); + advanceClocks(io, time::milliseconds(10), 10); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + BOOST_CHECK_EQUAL(face->sentDatas[0].getName().getPrefix(-1), + cert11->getName().getPrefix(-1)); + + auto interest3 = make_shared(testIdCertName11.getPrefix(-1)); + pib.getDb().deleteCertificate(testIdCertName11); + face->sentDatas.clear(); + face->receive(*interest3); + advanceClocks(io, time::milliseconds(10), 10); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1); + BOOST_CHECK(face->sentDatas[0].wireEncode() == cert10->wireEncode()); + + auto interest4 = make_shared(testIdCertName11); + face->sentDatas.clear(); + face->receive(*interest4); + advanceClocks(io, time::milliseconds(10), 10); + BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace tests +} // namespace pib +} // namespace ndn diff --git a/tests/pib/response-cache.t.cpp b/tests/pib/response-cache.t.cpp new file mode 100644 index 0000000..2653579 --- /dev/null +++ b/tests/pib/response-cache.t.cpp @@ -0,0 +1,64 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "tools/pib/response-cache.hpp" + +#include "tests/test-common.hpp" + +namespace ndn { +namespace pib { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestResponseCache) + +BOOST_AUTO_TEST_CASE(Basic) +{ + ResponseCache cache; + + Name dataName("/test/data"); + dataName.appendVersion(); + shared_ptr data = make_shared(dataName); + + Name dataNameNoVersion("/test/data"); + Name anotherDataName("/test/another"); + + BOOST_CHECK_EQUAL(static_cast(cache.find(dataNameNoVersion)), false); + BOOST_CHECK_EQUAL(static_cast(cache.find(dataName, true)), false); + + cache.insert(*data); + + BOOST_CHECK(static_cast(cache.find(dataNameNoVersion))); + BOOST_CHECK(static_cast(cache.find(dataName, true))); + BOOST_CHECK_EQUAL(static_cast(cache.find(anotherDataName)), false); + BOOST_CHECK_EQUAL(static_cast(cache.find(anotherDataName, true)), false); + + cache.erase(dataNameNoVersion); + + BOOST_CHECK_EQUAL(static_cast(cache.find(dataNameNoVersion)), false); + BOOST_CHECK_EQUAL(static_cast(cache.find(dataName, true)), false); +} + + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace tests +} // namespace pib +} // namespace ndn diff --git a/tests/wscript b/tests/wscript index c67d252..e44f2a4 100644 --- a/tests/wscript +++ b/tests/wscript @@ -10,4 +10,5 @@ def build(bld): source=bld.path.ant_glob(['*.cpp'] + ['%s/**/*.cpp' % tool for tool in bld.env['BUILD_TOOLS']]), use=['core-objects'] + ['%s-objects' % tool for tool in bld.env['BUILD_TOOLS']], headers='../common.hpp boost-test.hpp', + defines='TMP_TESTS_PATH=\"%s/tmp-tests\"' % bld.bldnode, ) diff --git a/tools/pib/cert-publisher.cpp b/tools/pib/cert-publisher.cpp new file mode 100644 index 0000000..abcd5a2 --- /dev/null +++ b/tools/pib/cert-publisher.cpp @@ -0,0 +1,128 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "cert-publisher.hpp" + +namespace ndn { +namespace pib { + +CertPublisher::CertPublisher(Face& face, PibDb& db) + : m_face(face) + , m_db(db) +{ + startPublishAll(); + + m_certDeletedConnection = + m_db.certificateDeleted.connect(bind(&CertPublisher::stopPublish, this, _1)); + m_certInsertedConnection = + m_db.certificateInserted.connect(bind(&CertPublisher::startPublish, this, _1)); +} + +CertPublisher::~CertPublisher() +{ + for (const auto& it : m_registeredPrefixes) + m_face.unsetInterestFilter(it.second); +} + +void +CertPublisher::startPublishAll() +{ + // For now we have to register the prefix of certificates separately. + // The reason is that certificates do not share the same prefix that + // can aggregate the certificates publishing without attracting interests + // for non-PIB data. + + std::vector identities = m_db.listIdentities(); + + for (const auto& identity : identities) { + std::vector keyNames = m_db.listKeyNamesOfIdentity(identity); + + for (const auto& key : keyNames) { + std::vector certNames = m_db.listCertNamesOfKey(key); + + for (const auto& certName : certNames) + startPublish(certName); + } + } +} + +void +CertPublisher::registerCertPrefix(const Name& certName) +{ + BOOST_ASSERT(!certName.empty()); + + const Name& prefix = certName.getPrefix(-1); + + if (m_registeredPrefixes.find(prefix) == m_registeredPrefixes.end()) { + m_registeredPrefixes[prefix] = + m_face.setInterestFilter(certName.getPrefix(-1), + bind(&CertPublisher::processInterest, this, _1, _2), + [] (const Name& name) {}, + [=] (const Name& name, const std::string& msg) { + if (m_registeredPrefixes.erase(prefix) == 0) { + // registration no longer needed - certificates deleted + return; + } + // retry + registerCertPrefix(certName); + }); + + } +} + +void +CertPublisher::processInterest(const InterestFilter& interestFilter, + const Interest& interest) +{ + shared_ptr certificate = m_responseCache.find(interest); + if (certificate != nullptr) { + m_face.put(*certificate); + } +} + +void +CertPublisher::startPublish(const Name& certName) +{ + m_responseCache.insert(*m_db.getCertificate(certName)); + registerCertPrefix(certName); +} + +void +CertPublisher::stopPublish(const Name& certName) +{ + BOOST_ASSERT(!certName.empty()); + + m_responseCache.erase(certName); + + // clear the listener if this is the only cert using the prefix + const Name& prefix = certName.getPrefix(-1); // strip version component + + if (m_responseCache.find(prefix) != nullptr) + return; + + auto it = m_registeredPrefixes.find(prefix); + BOOST_ASSERT(it != m_registeredPrefixes.end()); + m_face.unsetInterestFilter(it->second); + m_registeredPrefixes.erase(it); +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/cert-publisher.hpp b/tools/pib/cert-publisher.hpp new file mode 100644 index 0000000..052895c --- /dev/null +++ b/tools/pib/cert-publisher.hpp @@ -0,0 +1,99 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_CERT_PUBLISHER_HPP +#define NDN_PIB_CERT_PUBLISHER_HPP + +#include "pib-db.hpp" + +#include +#include + +namespace ndn { +namespace pib { + +/// @brief implements the certificate publisher +class CertPublisher : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + explicit + Error(const std::string& what) + : std::runtime_error(what) + { + } + }; + + /** + * @brief Constructor + * + * @param face The face pib used to receive queries and serve certificates. + * @param pibDb Database which holds the certificates. + */ + CertPublisher(Face& face, PibDb& pibDb); + + ~CertPublisher(); + +private: + void + startPublishAll(); + + /** + * @brief add an interest filter for the certificate + */ + void + registerCertPrefix(const Name& certName); + + void + processInterest(const InterestFilter& interestFilter, + const Interest& interest); + + void + startPublish(const Name& certName); + + /** + * @brief callback when a certificate is deleted + * + * The method will remove the cert from in-memory storage + * and also unset interest filter if the removed cert + * is the only one with the registered prefix. + * + * @param certName removed certificate name + */ + void + stopPublish(const Name& certName); + +private: + Face& m_face; + PibDb& m_db; + util::InMemoryStoragePersistent m_responseCache; + std::map m_registeredPrefixes; + + util::signal::ScopedConnection m_certDeletedConnection; + util::signal::ScopedConnection m_certInsertedConnection; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_CERT_PUBLISHER_HPP diff --git a/tools/pib/default-query-processor.cpp b/tools/pib/default-query-processor.cpp new file mode 100644 index 0000000..4909ea2 --- /dev/null +++ b/tools/pib/default-query-processor.cpp @@ -0,0 +1,199 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "default-query-processor.hpp" +#include "encoding/pib-encoding.hpp" + +#include + +namespace ndn { +namespace pib { + +using std::string; + +const size_t DefaultQueryProcessor::DEFAULT_QUERY_LENGTH = 5; + +DefaultQueryProcessor::DefaultQueryProcessor(PibDb& db) + : m_db(db) +{ +} + +std::pair +DefaultQueryProcessor::operator()(const Interest& interest) +{ + const Name& interestName = interest.getName(); + + // handle pib query: /localhost/pib/[UserName]/default/param + if (interestName.size() != DEFAULT_QUERY_LENGTH) { + // malformed interest, discard + return std::make_pair(false, Block()); + } + + DefaultParam param; + + try { + param.wireDecode(interestName.get(OFFSET_PARAM).blockFromValue()); + } + catch (const tlv::Error& e) { + PibError error(ERR_WRONG_PARAM, "error in parsing param: " + string(e.what())); + return std::make_pair(true, error.wireEncode()); + } + + switch (param.getTargetType()) { + case TYPE_ID: + return processDefaultIdQuery(param); + case TYPE_KEY: + return processDefaultKeyQuery(param); + case TYPE_CERT: + return processDefaultCertQuery(param); + default: + { + PibError error(ERR_WRONG_PARAM, + "target type is not supported: " + + boost::lexical_cast(param.getTargetType())); + return std::make_pair(true, error.wireEncode()); + } + } +} + +std::pair +DefaultQueryProcessor::processDefaultIdQuery(const DefaultParam& param) +{ + if (param.getOriginType() == TYPE_USER) { + try { + PibIdentity result(m_db.getDefaultIdentity()); + return std::make_pair(true, result.wireEncode()); + } + catch (PibDb::Error&) { + PibError error(ERR_NO_DEFAULT_ID, "default identity does not exist"); + return std::make_pair(true, error.wireEncode()); + } + } + else { + PibError error(ERR_WRONG_PARAM, + "origin type of id target must be USER(0), but gets: " + + boost::lexical_cast(param.getOriginType())); + return std::make_pair(true, error.wireEncode()); + } +} + +std::pair +DefaultQueryProcessor::processDefaultKeyQuery(const DefaultParam& param) +{ + Name identity; + if (param.getOriginType() == TYPE_ID) + identity = param.getOriginName(); + else if (param.getOriginType() == TYPE_USER) { + try { + identity = m_db.getDefaultIdentity(); + } + catch (PibDb::Error&) { + PibError error(ERR_NO_DEFAULT_ID, "default identity does not exist"); + return std::make_pair(true, error.wireEncode()); + } + } + else { + PibError error(ERR_WRONG_PARAM, + "origin type of key target must be ID(1) or USER(0), but gets: " + + boost::lexical_cast(param.getOriginType())); + return std::make_pair(true, error.wireEncode()); + } + + try { + Name keyName = m_db.getDefaultKeyNameOfIdentity(identity); + shared_ptr key = m_db.getKey(keyName); + + if (key == nullptr) { + PibError error(ERR_NO_DEFAULT_KEY, "default key does not exist"); + return std::make_pair(true, error.wireEncode()); + } + + PibPublicKey result(keyName, *key); + return std::make_pair(true, result.wireEncode()); + } + catch (PibDb::Error& e) { + PibError error(ERR_NO_DEFAULT_KEY, + "default key does not exist: " + string(e.what())); + return std::make_pair(true, error.wireEncode()); + } +} + +std::pair +DefaultQueryProcessor::processDefaultCertQuery(const DefaultParam& param) +{ + Name identity; + if (param.getOriginType() == TYPE_USER) { + try { + identity = m_db.getDefaultIdentity(); + } + catch (PibDb::Error&) { + PibError error(ERR_NO_DEFAULT_ID, "default identity does not exist"); + return std::make_pair(true, error.wireEncode()); + } + } + else if (param.getOriginType() == TYPE_ID) + identity = param.getOriginName(); + else if (param.getOriginType() != TYPE_KEY) { + PibError error(ERR_WRONG_PARAM, + "origin type of cert target must be KEY(2), ID(1) or USER(0), but gets: " + + boost::lexical_cast(param.getOriginType())); + return std::make_pair(true, error.wireEncode()); + } + + Name keyName; + if (param.getOriginType() == TYPE_KEY) { + keyName = param.getOriginName(); + if (keyName.size() < 1) { + PibError error(ERR_WRONG_PARAM, + "key name must contain key id component"); + return std::make_pair(true, error.wireEncode()); + } + } + else { + try { + keyName = m_db.getDefaultKeyNameOfIdentity(identity); + } + catch (PibDb::Error&) { + PibError error(ERR_NO_DEFAULT_KEY, "default key does not exist"); + return std::make_pair(true, error.wireEncode()); + } + } + + try { + Name certName = m_db.getDefaultCertNameOfKey(keyName); + shared_ptr certificate = m_db.getCertificate(certName); + + if (certificate == nullptr) { + PibError error (ERR_NO_DEFAULT_CERT, "default cert does not exist"); + return std::make_pair(true, error.wireEncode()); + } + + PibCertificate result(*certificate); + return std::make_pair(true, result.wireEncode()); + } + catch (PibDb::Error&) { + PibError error(ERR_NO_DEFAULT_CERT, "default cert does not exist"); + return std::make_pair(true, error.wireEncode()); + } +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/default-query-processor.hpp b/tools/pib/default-query-processor.hpp new file mode 100644 index 0000000..1938074 --- /dev/null +++ b/tools/pib/default-query-processor.hpp @@ -0,0 +1,76 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_DEFAULT_QUERY_PROCESSOR_HPP +#define NDN_PIB_DEFAULT_QUERY_PROCESSOR_HPP + +#include "pib-db.hpp" +#include "encoding/default-param.hpp" +#include +#include + +namespace ndn { +namespace pib { + +class DefaultQueryProcessor : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + explicit + Error(const std::string& what) + : std::runtime_error(what) + { + } + }; + + /** + * @brief Constructor + * + * @param db The pib database. + */ + explicit + DefaultQueryProcessor(PibDb& db); + + std::pair + operator()(const Interest& interest); + +private: + std::pair + processDefaultIdQuery(const DefaultParam& param); + + std::pair + processDefaultKeyQuery(const DefaultParam& param); + + std::pair + processDefaultCertQuery(const DefaultParam& param); + +private: + static const size_t DEFAULT_QUERY_LENGTH; + + const PibDb& m_db; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_DEFAULT_QUERY_PROCESSOR_HPP diff --git a/tools/pib/delete-query-processor.cpp b/tools/pib/delete-query-processor.cpp new file mode 100644 index 0000000..9174784 --- /dev/null +++ b/tools/pib/delete-query-processor.cpp @@ -0,0 +1,205 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "delete-query-processor.hpp" +#include "encoding/pib-encoding.hpp" +#include "pib.hpp" + +#include + +namespace ndn { +namespace pib { + +using std::string; + +const size_t DeleteQueryProcessor::DELETE_QUERY_LENGTH = 9; +const Name DeleteQueryProcessor::PIB_PREFIX("/localhost/pib"); + +DeleteQueryProcessor::DeleteQueryProcessor(PibDb& db) + : m_db(db) +{ +} + +std::pair +DeleteQueryProcessor::operator()(const Interest& interest) +{ + const Name& interestName = interest.getName(); + + // handle pib query: /localhost/pib/[UserName]/delete/param/ + if (interestName.size() != DELETE_QUERY_LENGTH) { + // malformed interest, discard + return std::make_pair(false, Block()); + } + + try { + DeleteParam param; + param.wireDecode(interestName.get(OFFSET_PARAM).blockFromValue()); + + SignatureInfo sigInfo; + sigInfo.wireDecode(interestName.get(OFFSET_SIG_INFO).blockFromValue()); + + // sigInfo must have KeyLocator.Name if the interest passed validation. + Name signerName; + signerName = sigInfo.getKeyLocator().getName(); + + switch (param.getTargetType()) { + case TYPE_USER: + return std::make_pair(true, PibError(ERR_WRONG_PARAM, "not allowed to delete user").wireEncode()); + case TYPE_ID: + return processDeleteIdQuery(param, signerName); + case TYPE_KEY: + return processDeleteKeyQuery(param, signerName); + case TYPE_CERT: + return processDeleteCertQuery(param, signerName); + default: + { + PibError error(ERR_WRONG_PARAM, + "target type is not supported: " + + boost::lexical_cast(param.getTargetType())); + return std::make_pair(true, error.wireEncode()); + } + } + } + catch (const PibDb::Error& e) { + PibError error(ERR_INTERNAL_ERROR, e.what()); + return std::make_pair(true, error.wireEncode()); + } + catch (const tlv::Error& e) { + PibError error(ERR_WRONG_PARAM, "error in parsing param: " + string(e.what())); + return std::make_pair(true, error.wireEncode()); + } +} + +std::pair +DeleteQueryProcessor::processDeleteIdQuery(const DeleteParam& param, const Name& signerName) +{ + Name identity = param.getTargetName(); + if (!isDeleteAllowed(TYPE_ID, identity, signerName)) { + PibError error(ERR_WRONG_SIGNER, "signer is not trusted for this command"); + return std::make_pair(true, error.wireEncode()); + } + + m_db.deleteIdentity(identity); + + return std::make_pair(true, PibError(ERR_SUCCESS).wireEncode()); +} + +std::pair +DeleteQueryProcessor::processDeleteKeyQuery(const DeleteParam& param, const Name& signerName) +{ + const Name& keyName = param.getTargetName(); + if (!isDeleteAllowed(TYPE_KEY, keyName, signerName)) { + PibError error(ERR_WRONG_SIGNER, "signer is not trusted for this command"); + return std::make_pair(true, error.wireEncode()); + } + + m_db.deleteKey(keyName); + + return std::make_pair(true, PibError(ERR_SUCCESS).wireEncode()); +} + +std::pair +DeleteQueryProcessor::processDeleteCertQuery(const DeleteParam& param, const Name& signerName) +{ + const Name& certName = param.getTargetName(); + if (!isDeleteAllowed(TYPE_CERT, certName, signerName)) { + PibError error(ERR_WRONG_SIGNER, "signer is not trusted for this command"); + return std::make_pair(true, error.wireEncode()); + } + + m_db.deleteCertificate(certName); + + return std::make_pair(true, PibError(ERR_SUCCESS).wireEncode()); +} + +bool +DeleteQueryProcessor::isDeleteAllowed(const pib::Type targetType, + const Name& targetName, + const Name& signer) const +{ + // sanity checking, user cannot be deleted. + if (targetType == TYPE_USER) + return false; + + // Any identity with prefix /localhost/pib is reserved. Any operation with a targetName under + // that prefix will be rejected. + if (PIB_PREFIX.isPrefixOf(targetName)) + return false; + + // Rules for other items: + // + // signer | deleting privilege + // =========================+=============================================== + // local mgmt key | any id, key, and cert + // -------------------------+----------------------------------------------- + // default key of an id | any id, key, and cert under the id's namespace + // -------------------------+----------------------------------------------- + // non-default key of an id | any cert of the key + + const Name& signerKeyName = IdentityCertificate::certificateNameToPublicKeyName(signer); + const Name& signerId = signerKeyName.getPrefix(-1); + + bool hasSignerDefaultKey = true; + Name signerDefaultKeyName; + try { + signerDefaultKeyName = m_db.getDefaultKeyNameOfIdentity(signerId); + } + catch (PibDb::Error&) { + hasSignerDefaultKey = false; + } + + Name mgmtCertName; + try { + mgmtCertName = m_db.getMgmtCertificate()->getName().getPrefix(-1); + } + catch (PibDb::Error&) { + return false; + } + + if (signer == mgmtCertName) { + // signer is current management key, anything is allowed. + return true; + } + else if (hasSignerDefaultKey && signerDefaultKeyName == signerKeyName) { + // signer is an identity's default key + if (!signerId.isPrefixOf(targetName)) + return false; + else + return true; + } + else { + // non-default key + if (targetType == TYPE_CERT) { + // check if it is for the key's cert + if (IdentityCertificate::certificateNameToPublicKeyName(targetName) == signerKeyName) + return true; + } + else if (targetType == TYPE_KEY) { + // check if it is for the key itself + if (targetName == signerKeyName) + return true; + } + return false; + } +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/delete-query-processor.hpp b/tools/pib/delete-query-processor.hpp new file mode 100644 index 0000000..3336deb --- /dev/null +++ b/tools/pib/delete-query-processor.hpp @@ -0,0 +1,93 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_DELETE_QUERY_PROCESSOR_HPP +#define NDN_PIB_DELETE_QUERY_PROCESSOR_HPP + +#include "pib-db.hpp" +#include "encoding/delete-param.hpp" +#include +#include + +namespace ndn { +namespace pib { + +class Pib; + +/// @brief Processing unit for PIB delete query +class DeleteQueryProcessor : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + explicit + Error(const std::string& what) + : std::runtime_error(what) + { + } + }; + + /** + * @brief Constructor + * + * @param db The pib database. + */ + explicit + DeleteQueryProcessor(PibDb& db); + + std::pair + operator()(const Interest& interest); + +PUBLIC_WITH_TESTS_ELSE_PRIVATE: + /** + * @brief Determine if a delete command is allowed. + * + * @param targetType The type of the target that will be deleted. + * @param targetName The name of the target that will be deleted. + * @param signer The name of the command signer. + */ + bool + isDeleteAllowed(const pib::Type targetType, + const Name& targetName, + const Name& signer) const; + +private: + std::pair + processDeleteIdQuery(const DeleteParam& param, const Name& signerName); + + std::pair + processDeleteKeyQuery(const DeleteParam& param, const Name& signerName); + + std::pair + processDeleteCertQuery(const DeleteParam& param, const Name& signerName); + +private: + static const size_t DELETE_QUERY_LENGTH; + static const Name PIB_PREFIX; + + PibDb& m_db; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_DELETE_QUERY_PROCESSOR_HPP diff --git a/tools/pib/encoding/default-param.cpp b/tools/pib/encoding/default-param.cpp new file mode 100644 index 0000000..015bf19 --- /dev/null +++ b/tools/pib/encoding/default-param.cpp @@ -0,0 +1,168 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "default-param.hpp" +#include +#include + +namespace ndn { +namespace pib { + +static_assert(std::is_base_of::value, + "DefaultParam::Error must inherit from tlv::Error"); + +const std::string DefaultParam::VERB("default"); + +DefaultParam::DefaultParam() + : m_targetType(TYPE_DEFAULT) + , m_originType(TYPE_DEFAULT) +{ +} + +DefaultParam::DefaultParam(const pib::Type targetType, + const pib::Type originType, + const Name& originName) + : m_targetType(targetType) + , m_originType(originType) + , m_originName(originName) +{ +} + +DefaultParam::DefaultParam(const Block& wire) +{ + wireDecode(wire); +} + +const Name& +DefaultParam::getOriginName() const +{ + if (m_originType == TYPE_ID || m_originType == TYPE_KEY || m_originType == TYPE_CERT) + return m_originName; + else + throw Error("DefaultParam::getOriginName: origin name does not exist"); +} + +template +size_t +DefaultParam::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = 0; + + switch (m_originType) { + case TYPE_ID: + case TYPE_KEY: + case TYPE_CERT: + { + totalLength += m_originName.wireEncode(block); + break; + } + case TYPE_USER: + break; + default: + throw Error("DefaultParam::wireEncode: unsupported PibType: " + + boost::lexical_cast(m_originType)); + } + + totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::Type, m_originType); + totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::Type, m_targetType); + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::pib::DefaultParam); + + return totalLength; +} + +template size_t +DefaultParam::wireEncode(EncodingImpl& block) const; + +template size_t +DefaultParam::wireEncode(EncodingImpl& block) const; + +const Block& +DefaultParam::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +DefaultParam::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + throw Error("The supplied block does not contain wire format"); + } + + m_wire = wire; + m_wire.parse(); + + if (m_wire.type() != tlv::pib::DefaultParam) + throw Error("Unexpected TLV type when decoding DefaultParam"); + + Block::element_const_iterator it = m_wire.elements_begin(); + + // the first block must be PibType + if (it != m_wire.elements_end() && it->type() == tlv::pib::Type) { + m_targetType = static_cast(readNonNegativeInteger(*it)); + it++; + } + else + throw Error("DefaultParam requires the first sub-TLV to be PibType"); + + // the second block must be PibType + if (it != m_wire.elements_end() && it->type() == tlv::pib::Type) { + m_originType = static_cast(readNonNegativeInteger(*it)); + it++; + } + else + throw Error("DefaultParam requires the second sub-TLV to be PibType"); + + switch (m_originType) { + case TYPE_ID: + case TYPE_KEY: + case TYPE_CERT: + { + if (it != m_wire.elements_end()) { + // the third block, if exists, must be Name + m_originName.wireDecode(*it); + return; + } + else { + throw Error("DefaultParam requires the third sub-TLV to be Name"); + } + } + case TYPE_USER: + return; + default: + throw Error("DefaultParam::wireDecode: unsupported PibType: " + + boost::lexical_cast(m_originType)); + } +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/encoding/default-param.hpp b/tools/pib/encoding/default-param.hpp new file mode 100644 index 0000000..1906954 --- /dev/null +++ b/tools/pib/encoding/default-param.hpp @@ -0,0 +1,128 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + + +#ifndef NDN_PIB_DEFAULT_PARAM_HPP +#define NDN_PIB_DEFAULT_PARAM_HPP + +#include "pib-common.hpp" +#include + +namespace ndn { +namespace pib { + +/** + * @brief DefaultParam is the abstraction of PIB Default parameter. + * + * PibDefaultParam := PIB-DEFAULT-PARAM-TYPE TLV-LENGTH + * PibType // target type + * PibType // origin type + * Name? // origin name + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Default-Parameters + */ + +class DefaultParam : noncopyable +{ +public: + class Error : public tlv::Error + { + public: + explicit + Error(const std::string& what) + : tlv::Error(what) + { + } + }; + + DefaultParam(); + + DefaultParam(const pib::Type targetType, + const pib::Type originType, + const Name& originName = Name()); + + explicit + DefaultParam(const Block& wire); + + tlv::pib::ParamType + getParamType() const + { + return tlv::pib::DefaultParam; + } + + pib::Type + getTargetType() const + { + return m_targetType; + } + + pib::Type + getOriginType() const + { + return m_originType; + } + + /** + * @brief Get target name + * + * @throws Error if origin name does not exist + */ + const Name& + getOriginName() const; + + /// @brief Encode to a wire format or estimate wire format + template + size_t + wireEncode(EncodingImpl& block) const; + + /** + * @brief Encode to a wire format + * + * @throws Error if encoding fails + */ + const Block& + wireEncode() const; + + /** + * @brief Decode GetParam from a wire encoded block + * + * @throws Error if decoding fails + */ + void + wireDecode(const Block& wire); + +public: + static const std::string VERB; + +private: + pib::Type m_targetType; + pib::Type m_originType; + Name m_originName; + + mutable Block m_wire; +}; + +} // namespace pib +} // namespace ndn + + + +#endif // NDN_PIB_DEFAULT_PARAM_HPP diff --git a/tools/pib/encoding/delete-param.cpp b/tools/pib/encoding/delete-param.cpp new file mode 100644 index 0000000..41c8f6a --- /dev/null +++ b/tools/pib/encoding/delete-param.cpp @@ -0,0 +1,129 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "delete-param.hpp" +#include +#include + +namespace ndn { +namespace pib { + +static_assert(std::is_base_of::value, + "DeleteParam::Error must inherit from tlv::Error"); + +const std::string DeleteParam::VERB("delete"); + +DeleteParam::DeleteParam() + : m_targetType(TYPE_DEFAULT) +{ +} + +DeleteParam::DeleteParam(const Name& name, pib::Type type) + : m_targetType(type) + , m_targetName(name) +{ +} + +DeleteParam::DeleteParam(const Block& wire) +{ + wireDecode(wire); +} + +template +size_t +DeleteParam::wireEncode(EncodingImpl& block) const +{ + if (m_targetType != TYPE_ID && + m_targetType != TYPE_KEY && + m_targetType != TYPE_CERT && + m_targetType != TYPE_USER) + throw Error("DeleteParam::wireEncode: Wrong Type value: " + + boost::lexical_cast(m_targetType)); + + size_t totalLength = 0; + + totalLength += m_targetName.wireEncode(block); + totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::Type, m_targetType); + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::pib::DeleteParam); + + return totalLength; +} + +template size_t +DeleteParam::wireEncode(EncodingImpl& block) const; + +template size_t +DeleteParam::wireEncode(EncodingImpl& block) const; + +const Block& +DeleteParam::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +DeleteParam::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + throw Error("The supplied block does not contain wire format"); + } + + m_wire = wire; + m_wire.parse(); + + if (m_wire.type() != tlv::pib::DeleteParam) + throw Error("Unexpected TLV type when decoding DeleteParam"); + + Block::element_const_iterator it = m_wire.elements_begin(); + + // the first block must be Type + if (it != m_wire.elements_end() && it->type() == tlv::pib::Type) { + m_targetType = static_cast(readNonNegativeInteger(*it)); + it++; + } + else + throw Error("DeleteParam requires the first sub-TLV to be Type"); + + // the second block must be Name + if (it != m_wire.elements_end() && it->type() == tlv::Name) { + m_targetName.wireDecode(*it); + it++; + } + else + throw Error("DeleteParam requires the second sub-TLV to be Name"); + + if (it != m_wire.elements_end()) + throw Error("DeleteParam must not contain more than two sub-TLVs"); +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/encoding/delete-param.hpp b/tools/pib/encoding/delete-param.hpp new file mode 100644 index 0000000..14d8392 --- /dev/null +++ b/tools/pib/encoding/delete-param.hpp @@ -0,0 +1,114 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_DELETE_PARAM_HPP +#define NDN_PIB_DELETE_PARAM_HPP + +#include "pib-common.hpp" +#include + +namespace ndn { +namespace pib { + +/** + * @brief DeleteParam is the abstraction of PIB Delete parameter. + * + * PibDeleteParam := PIB-DELETE-PARAM-TYPE TLV-LENGTH + * PibType + * Name + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Delete-Parameters + */ + +class DeleteParam : noncopyable +{ +public: + class Error : public tlv::Error + { + public: + explicit + Error(const std::string& what) + : tlv::Error(what) + { + } + }; + + DeleteParam(); + + explicit + DeleteParam(const Name& name, const pib::Type type = TYPE_ID); + + explicit + DeleteParam(const Block& wire); + + tlv::pib::ParamType + getParamType() const + { + return tlv::pib::DeleteParam; + } + + pib::Type + getTargetType() const + { + return m_targetType; + } + + const Name& + getTargetName() const + { + return m_targetName; + } + + /// @brief Encode to a wire format or estimate wire format + template + size_t + wireEncode(EncodingImpl& block) const; + + /** + * @brief Encode to a wire format + * + * @throws Error if encoding fails + */ + const Block& + wireEncode() const; + + /** + * @brief Decode GetParam from a wire encoded block + * + * @throws Error if decoding fails + */ + void + wireDecode(const Block& wire); + +public: + static const std::string VERB; + +private: + pib::Type m_targetType; + Name m_targetName; + + mutable Block m_wire; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_DELETE_PARAM_HPP diff --git a/tools/pib/encoding/get-param.cpp b/tools/pib/encoding/get-param.cpp new file mode 100644 index 0000000..ea076f9 --- /dev/null +++ b/tools/pib/encoding/get-param.cpp @@ -0,0 +1,156 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "get-param.hpp" +#include +#include + +namespace ndn { +namespace pib { + +static_assert(std::is_base_of::value, + "GetParam::Error must inherit from tlv::Error"); + +const std::string GetParam::VERB("get"); + +GetParam::GetParam() + : m_targetType(TYPE_USER) +{ +} + +GetParam::GetParam(const pib::Type targetType, const Name& targetName) + : m_targetType(targetType) + , m_targetName(targetName) +{ +} + +GetParam::GetParam(const Block& wire) +{ + wireDecode(wire); +} + +const Name& +GetParam::getTargetName() const +{ + if (m_targetType == TYPE_ID || m_targetType == TYPE_KEY || m_targetType == TYPE_CERT) + return m_targetName; + else + throw Error("GetParam::getTargetName: target name does not exist"); +} + +template +size_t +GetParam::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = 0; + + switch (m_targetType) { + case TYPE_ID: + case TYPE_KEY: + case TYPE_CERT: + { + totalLength += m_targetName.wireEncode(block); + break; + } + case TYPE_USER: + break; + default: + throw Error("GetParam::wireEncode: unsupported PibType: " + + boost::lexical_cast(m_targetType)); + } + + // Encode Type + totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::Type, m_targetType); + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::pib::GetParam); + + return totalLength; +} + +template size_t +GetParam::wireEncode(EncodingImpl& block) const; + +template size_t +GetParam::wireEncode(EncodingImpl& block) const; + +const Block& +GetParam::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +GetParam::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + throw Error("The supplied block does not contain wire format"); + } + + m_wire = wire; + m_wire.parse(); + + if (m_wire.type() != tlv::pib::GetParam) + throw Error("Unexpected TLV type when decoding GetParam"); + + Block::element_const_iterator it = m_wire.elements_begin(); + + // the first block must be Type + if (it != m_wire.elements_end() && it->type() == tlv::pib::Type) { + m_targetType = static_cast(readNonNegativeInteger(*it)); + it++; + } + else + throw Error("GetParam requires the first sub-TLV to be PibType"); + + switch (m_targetType) { + case TYPE_ID: + case TYPE_KEY: + case TYPE_CERT: + { + if (it != m_wire.elements_end()) { + // the second block, if exists, must be Name + m_targetName.wireDecode(*it); + return; + } + else { + throw Error("GetParam requires the second sub-TLV to be Name"); + } + } + case TYPE_USER: + return; + default: + throw Error("GetParam::wireDecode: unsupported PibType: " + + boost::lexical_cast(m_targetType)); + } +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/encoding/get-param.hpp b/tools/pib/encoding/get-param.hpp new file mode 100644 index 0000000..39a6c0e --- /dev/null +++ b/tools/pib/encoding/get-param.hpp @@ -0,0 +1,115 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_GET_PARAM_HPP +#define NDN_PIB_GET_PARAM_HPP + +#include "pib-common.hpp" +#include + +namespace ndn { +namespace pib { + +/** + * @brief GetParam is the abstraction of PIB Get parameter. + * + * PibGetParam := PIB-GET-PARAM-TYPE TLV-LENGTH + * PibType + * Name? + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Get-Parameters + */ + +class GetParam : noncopyable +{ +public: + class Error : public tlv::Error + { + public: + explicit + Error(const std::string& what) + : tlv::Error(what) + { + } + }; + + GetParam(); + + GetParam(const pib::Type targetType, const Name& targetName); + + explicit + GetParam(const Block& wire); + + tlv::pib::ParamType + getParamType() const + { + return tlv::pib::GetParam; + } + + pib::Type + getTargetType() const + { + return m_targetType; + } + + /** + * @brief Get target name + * + * @throws Error if target name does not exist + */ + const Name& + getTargetName() const; + + /// @brief Encode to a wire format or estimate wire format + template + size_t + wireEncode(EncodingImpl& block) const; + + /** + * @brief Encode to a wire format + * + * @throws Error if encoding fails + */ + const Block& + wireEncode() const; + + /** + * @brief Decode GetParam from a wire encoded block + * + * @throws Error if decoding fails + */ + void + wireDecode(const Block& wire); + +public: + static const std::string VERB; + +private: + pib::Type m_targetType; + Name m_targetName; + + mutable Block m_wire; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_GET_PARAM_HPP diff --git a/tools/pib/encoding/list-param.cpp b/tools/pib/encoding/list-param.cpp new file mode 100644 index 0000000..cb604e6 --- /dev/null +++ b/tools/pib/encoding/list-param.cpp @@ -0,0 +1,155 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "list-param.hpp" +#include +#include + +namespace ndn { +namespace pib { + +static_assert(std::is_base_of::value, + "ListParam::Error must inherit from tlv::Error"); + +const std::string ListParam::VERB("list"); + +ListParam::ListParam() + : m_originType(TYPE_USER) +{ +} + +ListParam::ListParam(const pib::Type originType, const Name& originName) + : m_originType(originType) + , m_originName(originName) +{ +} + +ListParam::ListParam(const Block& wire) +{ + wireDecode(wire); +} + +const Name& +ListParam::getOriginName() const +{ + if (m_originType == TYPE_ID || m_originType == TYPE_KEY || m_originType == TYPE_CERT) + return m_originName; + else + throw Error("ListParam::getOriginName: origin name does not exist"); +} + +template +size_t +ListParam::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = 0; + + switch (m_originType) { + case TYPE_ID: + case TYPE_KEY: + case TYPE_CERT: + { + totalLength += m_originName.wireEncode(block); + break; + } + case TYPE_USER: + break; + default: + throw Error("ListParam::wireEncode: unsupported PibType: " + + boost::lexical_cast(m_originType)); + } + + totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::Type, m_originType); + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::pib::ListParam); + + return totalLength; +} + +template size_t +ListParam::wireEncode(EncodingImpl& block) const; + +template size_t +ListParam::wireEncode(EncodingImpl& block) const; + +const Block& +ListParam::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +ListParam::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + throw Error("The supplied block does not contain wire format"); + } + + m_wire = wire; + m_wire.parse(); + + if (m_wire.type() != tlv::pib::ListParam) + throw Error("Unexpected TLV type when decoding ListParam"); + + Block::element_const_iterator it = m_wire.elements_begin(); + + // the first block must be PibType + if (it != m_wire.elements_end() && it->type() == tlv::pib::Type) { + m_originType = static_cast(readNonNegativeInteger(*it)); + it++; + } + else + throw Error("ListParam requires the first sub-TLV to be PibType"); + + switch (m_originType) { + case TYPE_ID: + case TYPE_KEY: + case TYPE_CERT: + { + if (it != m_wire.elements_end()) { + // the second block, if exists, must be Name + m_originName.wireDecode(*it); + return; + } + else { + throw Error("ListParam requires the second sub-TLV to be Name"); + } + } + case TYPE_USER: + return; + default: + throw Error("ListParam::wireDecode: unsupported PibType: " + + boost::lexical_cast(m_originType)); + } +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/encoding/list-param.hpp b/tools/pib/encoding/list-param.hpp new file mode 100644 index 0000000..f94732e --- /dev/null +++ b/tools/pib/encoding/list-param.hpp @@ -0,0 +1,118 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + + +#ifndef NDN_PIB_LIST_PARAM_HPP +#define NDN_PIB_LIST_PARAM_HPP + +#include "pib-common.hpp" +#include + +namespace ndn { +namespace pib { + +/** + * @brief ListParam is the abstraction of PIB List parameter. + * + * PibListParam := PIB-LIST-PARAM-TYPE TLV-LENGTH + * PibType // origin type + * Name? // origin name + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#List-Parameters + */ + +class ListParam : noncopyable +{ +public: + class Error : public tlv::Error + { + public: + explicit + Error(const std::string& what) + : tlv::Error(what) + { + } + }; + + ListParam(); + + ListParam(const pib::Type originType, const Name& originName); + + explicit + ListParam(const Block& wire); + + tlv::pib::ParamType + getParamType() const + { + return tlv::pib::ListParam; + } + + pib::Type + getOriginType() const + { + return m_originType; + } + + /** + * @brief Get target name + * + * @throws Error if origin name does not exist + */ + const Name& + getOriginName() const; + + /// @brief Encode to a wire format or estimate wire format + template + size_t + wireEncode(EncodingImpl& block) const; + + /** + * @brief Encode to a wire format + * + * @throws Error if encoding fails + */ + const Block& + wireEncode() const; + + /** + * @brief Decode GetParam from a wire encoded block + * + * @throws Error if decoding fails + */ + void + wireDecode(const Block& wire); + +public: + static const std::string VERB; + +private: + pib::Type m_originType; + Name m_originName; + + mutable Block m_wire; +}; + +} // namespace pib +} // namespace ndn + + + +#endif // NDN_PIB_LIST_PARAM_HPP diff --git a/tools/pib/encoding/pib-common.hpp b/tools/pib/encoding/pib-common.hpp new file mode 100644 index 0000000..74c5daf --- /dev/null +++ b/tools/pib/encoding/pib-common.hpp @@ -0,0 +1,128 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_PIB_COMMON_HPP +#define NDN_PIB_PIB_COMMON_HPP + +namespace ndn { +namespace pib { + +/// @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base + +enum { + OFFSET_USER = 2, + OFFSET_VERB = 3, + OFFSET_PARAM = 4, + OFFSET_TIMESTAMP = 5, + OFFSET_NONCE = 6, + OFFSET_SIG_INFO = 7, + OFFSET_SIG_VALUE = 8, + + MIN_PIB_INTEREST_SIZE = 5, + SIGNED_PIB_INTEREST_SIZE = 9 +}; + +enum Type { + TYPE_USER = 0, + TYPE_ID = 1, + TYPE_KEY = 2, + TYPE_CERT = 3, + TYPE_DEFAULT = 255 +}; + +enum DefaultOpt { + DEFAULT_OPT_NO = 0, + DEFAULT_OPT_KEY = 1, // 0x01 + DEFAULT_OPT_ID = 3, // 0x03 + DEFAULT_OPT_USER = 7 // 0x07 +}; + +enum DefaultOptMask { + DEFAULT_OPT_KEY_MASK = 0x1, + DEFAULT_OPT_ID_MASK = 0x2, + DEFAULT_OPT_USER_MASK = 0x4 +}; + +enum ErrCode { + ERR_SUCCESS = 0, + + // Invalid query + ERR_INCOMPLETE_COMMAND = 1, + ERR_WRONG_VERB = 2, + ERR_WRONG_PARAM = 3, + ERR_WRONG_SIGNER = 4, + ERR_INTERNAL_ERROR = 5, + + // Non existing entity + ERR_NON_EXISTING_USER = 128, + ERR_NON_EXISTING_ID = 129, + ERR_NON_EXISTING_KEY = 130, + ERR_NON_EXISTING_CERT = 131, + + // No default setting + ERR_NO_DEFAULT_ID = 256, + ERR_NO_DEFAULT_KEY = 257, + ERR_NO_DEFAULT_CERT = 258, + + // Delete default setting + ERR_DELETE_DEFAULT_SETTING = 384 +}; + +} // namespace pib + + +namespace tlv { +namespace pib { + +enum ParamType { + GetParam = 128, // 0x80 + DefaultParam = 129, // 0x81 + ListParam = 130, // 0x82 + UpdateParam = 131, // 0x83 + DeleteParam = 132 // 0x84 +}; + +enum EntityType { + User = 144, // 0x90 + Identity = 145, // 0x91 + PublicKey = 146, // 0x92 + Certificate = 147 // 0x93 +}; + +// Other +enum { + Bytes = 148, // 0x94 + DefaultOpt = 149, // 0x95 + NameList = 150, // 0x96 + Type = 151, // 0x97 + Error = 152, // 0x98 + TpmLocator = 153, // 0x99 + + // ErrorCode + ErrorCode = 252 // 0xfc +}; + +} // namespace pib +} // namespace tlv +} // namespace ndn + + +#endif // NDN_PIB_PIB_COMMON_HPP diff --git a/tools/pib/encoding/pib-encoding.cpp b/tools/pib/encoding/pib-encoding.cpp new file mode 100644 index 0000000..e7c5ca4 --- /dev/null +++ b/tools/pib/encoding/pib-encoding.cpp @@ -0,0 +1,525 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "pib-encoding.hpp" +#include +#include +#include +#include + +namespace ndn { +namespace pib { + +using std::vector; +using std::string; + +PibIdentity::PibIdentity() +{ +} + +PibIdentity::PibIdentity(const Name& identity) + : m_identity(identity) +{ +} + +PibIdentity::PibIdentity(const Block& wire) +{ + wireDecode(wire); +} + +template +size_t +PibIdentity::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = m_identity.wireEncode(block); + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::pib::Identity); + + return totalLength; +} + +template size_t +PibIdentity::wireEncode(EncodingImpl& block) const; + +template size_t +PibIdentity::wireEncode(EncodingImpl& block) const; + +const Block& +PibIdentity::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +PibIdentity::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + throw tlv::Error("The supplied block does not contain wire format"); + } + + if (wire.type() != tlv::pib::Identity) + throw tlv::Error("Unexpected TLV type when decoding PibIdentity"); + + m_wire = wire; + m_identity.wireDecode(m_wire.blockFromValue()); +} + + + +PibPublicKey::PibPublicKey() + : m_isValueSet(false) +{ +} + +PibPublicKey::PibPublicKey(const Name& keyName, const PublicKey& key) + : m_isValueSet(true) + , m_keyName(keyName) + , m_key(key) +{ +} + +PibPublicKey::PibPublicKey(const Block& wire) +{ + wireDecode(wire); +} + +const Name& +PibPublicKey::getKeyName() const +{ + if (m_isValueSet) + return m_keyName; + else + throw tlv::Error("PibPublicKey::getKeyName: keyName is not set"); +} + +const PublicKey& +PibPublicKey::getPublicKey() const +{ + if (m_isValueSet) + return m_key; + else + throw tlv::Error("PibPublicKey::getPublicKey: key is not set"); +} + +template +size_t +PibPublicKey::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = prependByteArrayBlock(block, tlv::pib::Bytes, + m_key.get().buf(), m_key.get().size()); + totalLength += m_keyName.wireEncode(block); + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::pib::PublicKey); + + return totalLength; +} + +template size_t +PibPublicKey::wireEncode(EncodingImpl& block) const; + +template size_t +PibPublicKey::wireEncode(EncodingImpl& block) const; + +const Block& +PibPublicKey::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +PibPublicKey::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + throw tlv::Error("The supplied block does not contain wire format"); + } + + if (wire.type() != tlv::pib::PublicKey) + throw tlv::Error("Unexpected TLV type when decoding PibPublicKey"); + + m_wire = wire; + m_wire.parse(); + + Block::element_const_iterator it = m_wire.elements_begin(); + if (it != m_wire.elements_end() && it->type() == tlv::Name) { + m_keyName.wireDecode(*it); + it++; + } + else + throw tlv::Error("PibPublicKey requires the first sub-TLV to be Name"); + + if (it != m_wire.elements_end() && it->type() == tlv::pib::Bytes) { + m_key = PublicKey(it->value(), it->value_size()); + it++; + } + else + throw tlv::Error("PibPublicKey requires the second sub-TLV to be Bytes"); + + m_isValueSet = true; + if (it != m_wire.elements_end()) + throw tlv::Error("PibPublicKey must contain only two sub-TLVs"); +} + + +PibCertificate::PibCertificate() + : m_isValueSet(false) +{ +} + +PibCertificate::PibCertificate(const IdentityCertificate& certificate) + : m_isValueSet(true) + , m_certificate(certificate) +{ +} + +PibCertificate::PibCertificate(const Block& wire) +{ + wireDecode(wire); +} + +const IdentityCertificate& +PibCertificate::getCertificate() const +{ + if (m_isValueSet) + return m_certificate; + else + throw tlv::Error("PibCertificate::getCertificate: certificate is not set"); +} + +template +size_t +PibCertificate::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = prependBlock(block, m_certificate.wireEncode()); + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::pib::Certificate); + + return totalLength; +} + +template size_t +PibCertificate::wireEncode(EncodingImpl& block) const; + +template size_t +PibCertificate::wireEncode(EncodingImpl& block) const; + +const Block& +PibCertificate::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +PibCertificate::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + throw tlv::Error("The supplied block does not contain wire format"); + } + + if (wire.type() != tlv::pib::Certificate) + throw tlv::Error("Unexpected TLV type when decoding PibCertificate"); + + m_wire = wire; + m_certificate.wireDecode(m_wire.blockFromValue()); + + m_isValueSet = true; +} + + +PibNameList::PibNameList() +{ +} + +PibNameList::PibNameList(const std::vector& names) + : m_names(names) +{ +} + +PibNameList::PibNameList(const Block& wire) +{ + wireDecode(wire); +} + +template +size_t +PibNameList::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = 0; + + for (vector::const_reverse_iterator it = m_names.rbegin(); + it != m_names.rend(); it++) { + totalLength += it->wireEncode(block); + } + + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::pib::NameList); + return totalLength; +} + +template size_t +PibNameList::wireEncode(EncodingImpl& block) const; + +template size_t +PibNameList::wireEncode(EncodingImpl& block) const; + + +const Block& +PibNameList::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +PibNameList::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + throw tlv::Error("The supplied block does not contain wire format"); + } + + if (wire.type() != tlv::pib::NameList) + throw tlv::Error("Unexpected TLV type when decoding PibNameList"); + + m_wire = wire; + m_wire.parse(); + for (Block::element_const_iterator it = m_wire.elements_begin(); + it != m_wire.elements_end(); it++) { + if (it->type() == tlv::Name) { + Name name; + name.wireDecode(*it); + m_names.push_back(name); + } + } +} + +PibError::PibError() + : m_errCode(ERR_SUCCESS) +{ +} + +PibError::PibError(const pib::ErrCode errCode, const std::string& msg) + : m_errCode(errCode) + , m_msg(msg) +{ +} + +PibError::PibError(const Block& wire) +{ + wireDecode(wire); +} + +template +size_t +PibError::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = 0; + totalLength += prependByteArrayBlock(block, tlv::pib::Bytes, + reinterpret_cast(m_msg.c_str()), + m_msg.size()); + totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::ErrorCode, m_errCode); + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::pib::Error); + return totalLength; +} + +template size_t +PibError::wireEncode(EncodingImpl& block) const; + +template size_t +PibError::wireEncode(EncodingImpl& block) const; + + +const Block& +PibError::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +PibError::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + throw tlv::Error("The supplied block does not contain wire format"); + } + + if (wire.type() != tlv::pib::Error) + throw tlv::Error("Unexpected TLV type when decoding Error"); + + m_wire = wire; + m_wire.parse(); + Block::element_const_iterator it = m_wire.elements_begin(); + + if (it != m_wire.elements_end() && it->type() == tlv::pib::ErrorCode) { + m_errCode = static_cast(readNonNegativeInteger(*it)); + it++; + } + else + throw tlv::Error("PibError requires the first sub-TLV to be ErrorCode"); + + if (it != m_wire.elements_end() && it->type() == tlv::pib::Bytes) { + m_msg = string(reinterpret_cast(it->value()), it->value_size()); + it++; + } + else + throw tlv::Error("PibError requires the second sub-TLV to be Bytes"); +} + +PibUser::PibUser() +{ +} + +PibUser::PibUser(const Block& wire) +{ + wireDecode(wire); +} + +void +PibUser::setMgmtCert(const IdentityCertificate& mgmtCert) +{ + m_wire.reset(); + m_mgmtCert = mgmtCert; +} + +void +PibUser::setTpmLocator(const std::string& tpmLocator) +{ + m_wire.reset(); + m_tpmLocator = tpmLocator; +} + +template +size_t +PibUser::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = 0; + + if (!m_tpmLocator.empty()) + totalLength = prependByteArrayBlock(block, tlv::pib::TpmLocator, + reinterpret_cast(m_tpmLocator.c_str()), + m_tpmLocator.size()); + + totalLength += prependBlock(block, m_mgmtCert.wireEncode()); + + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::pib::User); + + return totalLength; +} + +template size_t +PibUser::wireEncode(EncodingImpl& block) const; + +template size_t +PibUser::wireEncode(EncodingImpl& block) const; + + +const Block& +PibUser::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +PibUser::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + throw tlv::Error("The supplied block does not contain wire format"); + } + + if (wire.type() != tlv::pib::User) + throw tlv::Error("Unexpected TLV type when decoding Content"); + + m_wire = wire; + m_wire.parse(); + + Block::element_const_iterator it = m_wire.elements_begin(); + if (it != m_wire.elements_end() && it->type() == tlv::Data) { + m_mgmtCert.wireDecode(*it); + it++; + } + else + throw tlv::Error("PibError requires the first sub-TLV to be Data"); + + if (it != m_wire.elements_end() && it->type() == tlv::pib::TpmLocator) { + m_tpmLocator = string(reinterpret_cast(it->value()), it->value_size()); + } +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/encoding/pib-encoding.hpp b/tools/pib/encoding/pib-encoding.hpp new file mode 100644 index 0000000..9ebb4c4 --- /dev/null +++ b/tools/pib/encoding/pib-encoding.hpp @@ -0,0 +1,316 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_PIB_ENCODING_HPP +#define NDN_PIB_PIB_ENCODING_HPP + +#include "pib-common.hpp" +#include + +namespace ndn { +namespace pib { + +/** + * @brief Abstraction of pib::Identity TLV. + * + * This class is copyable since it is used by a variety of pib parameters + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Query-Responses + */ +class PibIdentity +{ +public: + PibIdentity(); + + explicit + PibIdentity(const Name& identity); + + explicit + PibIdentity(const Block& wire); + + const Name& + getIdentity() const + { + return m_identity; + } + + template + size_t + wireEncode(EncodingImpl& block) const; + + const Block& + wireEncode() const; + + /** + * @brief Decode PibIdentity from a wire encoded block + * + * @throws tlv::Error if decoding fails + */ + void + wireDecode(const Block& wire); + +private: + Name m_identity; + + mutable Block m_wire; +}; + +/** + * @brief Abstraction of pib::PublicKey TLV. + * + * This class is copyable since it is used by a variety of pib parameters + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Query-Responses + */ +class PibPublicKey +{ +public: + PibPublicKey(); + + PibPublicKey(const Name& keyName, const PublicKey& key); + + explicit + PibPublicKey(const Block& wire); + + const Name& + getKeyName() const; + + const PublicKey& + getPublicKey() const; + + template + size_t + wireEncode(EncodingImpl& block) const; + + const Block& + wireEncode() const; + + /** + * @brief Decode PibPublicKey from a wire encoded block + * + * @throws tlv::Error if decoding fails + */ + void + wireDecode(const Block& wire); + +private: + bool m_isValueSet; + Name m_keyName; + PublicKey m_key; + + mutable Block m_wire; +}; + +/** + * @brief Abstraction of pib::Certificate TLV. + * + * This class is copyable since it is used by a variety of pib parameters + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Query-Responses + */ +class PibCertificate +{ +public: + PibCertificate(); + + explicit + PibCertificate(const IdentityCertificate& certificate); + + explicit + PibCertificate(const Block& wire); + + const IdentityCertificate& + getCertificate() const; + + template + size_t + wireEncode(EncodingImpl& block) const; + + const Block& + wireEncode() const; + + /** + * @brief Decode PibCertificate from a wire encoded block + * + * @throws tlv::Error if decoding fails + */ + void + wireDecode(const Block& wire); + +private: + bool m_isValueSet; + IdentityCertificate m_certificate; + + mutable Block m_wire; +}; + +/** + * @brief Abstraction of pib::NameList TLV. + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#List-Parameters + */ +class PibNameList : noncopyable +{ +public: + PibNameList(); + + explicit + PibNameList(const std::vector& names); + + explicit + PibNameList(const Block& wire); + + const std::vector& + getNameList() const + { + return m_names; + } + + template + size_t + wireEncode(EncodingImpl& block) const; + + const Block& + wireEncode() const; + + /** + * @brief Decode PibCertificate from a wire encoded block + * + * @throws tlv::Error if decoding fails + */ + void + wireDecode(const Block& wire); + +private: + std::vector m_names; + + mutable Block m_wire; +}; + +/** + * @brief Abstraction of pib::Error TLV. + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Query-Responses + */ +class PibError : noncopyable +{ +public: + PibError(); + + explicit + PibError(const pib::ErrCode errCode, const std::string& msg = ""); + + explicit + PibError(const Block& wire); + + pib::ErrCode + getErrorCode() const + { + return m_errCode; + } + + const std::string& + getErrorMsg() const + { + return m_msg; + } + + template + size_t + wireEncode(EncodingImpl& block) const; + + const Block& + wireEncode() const; + + /** + * @brief Decode PibCertificate from a wire encoded block + * + * @throws tlv::Error if decoding fails + */ + void + wireDecode(const Block& wire); + +private: + pib::ErrCode m_errCode; + std::string m_msg; + + mutable Block m_wire; +}; + +/** + * @brief Abstraction of pib::User TLV. + * + * This class is copyable since it is used by a variety of pib parameters + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Query-Responses + */ +class PibUser +{ +public: + PibUser(); + + explicit + PibUser(const Block& wire); + + void + setMgmtCert(const IdentityCertificate& mgmtCert); + + const IdentityCertificate& + getMgmtCert() const + { + return m_mgmtCert; + } + + void + setTpmLocator(const std::string& tpmLocator); + + const std::string& + getTpmLocator() const + { + return m_tpmLocator; + } + + template + size_t + wireEncode(EncodingImpl& block) const; + + const Block& + wireEncode() const; + + /** + * @brief Decode PibCertificate from a wire encoded block + * + * @throws tlv::Error if decoding fails + */ + void + wireDecode(const Block& wire); + +private: + IdentityCertificate m_mgmtCert; + std::string m_tpmLocator; + + mutable Block m_wire; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_PIB_ENCODING_HPP diff --git a/tools/pib/encoding/update-param.cpp b/tools/pib/encoding/update-param.cpp new file mode 100644 index 0000000..71a6602 --- /dev/null +++ b/tools/pib/encoding/update-param.cpp @@ -0,0 +1,235 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "update-param.hpp" +#include +#include + +namespace ndn { +namespace pib { + +static_assert(std::is_base_of::value, + "UpdateParam::Error must inherit from tlv::Error"); + +const std::string UpdateParam::VERB("update"); + +UpdateParam::UpdateParam() + : m_defaultOpt(DEFAULT_OPT_NO) +{ +} + +UpdateParam::UpdateParam(const PibUser& user) + : m_entityType(tlv::pib::User) + , m_user(user) + , m_defaultOpt(DEFAULT_OPT_NO) +{ +} + +UpdateParam::UpdateParam(const Name& identity, DefaultOpt defaultOpt) + : m_entityType(tlv::pib::Identity) + , m_identity(identity) + , m_defaultOpt(defaultOpt) +{ +} + +UpdateParam::UpdateParam(const Name& keyName, const PublicKey& key, DefaultOpt defaultOpt) + : m_entityType(tlv::pib::PublicKey) + , m_key(keyName, key) + , m_defaultOpt(defaultOpt) +{ +} + +UpdateParam::UpdateParam(const IdentityCertificate& certificate, DefaultOpt defaultOpt) + : m_entityType(tlv::pib::Certificate) + , m_certificate(certificate) + , m_defaultOpt(defaultOpt) +{ +} + +UpdateParam::UpdateParam(const Block& wire) +{ + wireDecode(wire); +} + +const PibUser& +UpdateParam::getUser() const +{ + if (m_entityType == tlv::pib::User) + return m_user; + else + throw Error("UpdateParam::getUser: entityType must be User"); +} + +const PibIdentity& +UpdateParam::getIdentity() const +{ + if (m_entityType == tlv::pib::Identity) + return m_identity; + else + throw Error("UpdateParam::getIdentity: entityType must be Identity"); +} + +const PibPublicKey& +UpdateParam::getPublicKey() const +{ + if (m_entityType == tlv::pib::PublicKey) + return m_key; + else + throw Error("UpdateParam::getPublicKey: entityType must be PublicKey"); +} + +const PibCertificate& +UpdateParam::getCertificate() const +{ + if (m_entityType == tlv::pib::Certificate) + return m_certificate; + else + throw Error("UpdateParam::getCertificate: entityType must be Certificate"); +} + +template +size_t +UpdateParam::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = 0; + + totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::DefaultOpt, m_defaultOpt); + + // Encode Entity + switch (m_entityType) { + case tlv::pib::Identity: + { + totalLength += m_identity.wireEncode(block); + break; + } + case tlv::pib::PublicKey: + { + totalLength += m_key.wireEncode(block); + break; + } + case tlv::pib::Certificate: + { + totalLength += m_certificate.wireEncode(block); + break; + } + case tlv::pib::User: + { + totalLength += m_user.wireEncode(block); + break; + } + default: + throw Error("UpdateParam::wireEncode: unsupported entity type: " + + boost::lexical_cast(m_entityType)); + } + + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::pib::UpdateParam); + + return totalLength; +} + +template size_t +UpdateParam::wireEncode(EncodingImpl& block) const; + +template size_t +UpdateParam::wireEncode(EncodingImpl& block) const; + +const Block& +UpdateParam::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +UpdateParam::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + throw Error("The supplied block does not contain wire format"); + } + + m_wire = wire; + m_wire.parse(); + + if (m_wire.type() != tlv::pib::UpdateParam) + throw Error("Unexpected TLV type when decoding UpdateParam"); + + Block::element_const_iterator it = m_wire.elements_begin(); + + // the first block must be Entity + if (it != m_wire.elements_end()) { + switch (it->type()) { + case tlv::pib::Identity: + { + m_entityType = tlv::pib::Identity; + m_identity.wireDecode(*it); + break; + } + case tlv::pib::PublicKey: + { + m_entityType = tlv::pib::PublicKey; + m_key.wireDecode(*it); + break; + } + case tlv::pib::Certificate: + { + m_entityType = tlv::pib::Certificate; + m_certificate.wireDecode(*it); + break; + } + case tlv::pib::User: + { + m_entityType = tlv::pib::User; + m_user.wireDecode(*it); + break; + } + default: + throw Error("The first sub-TLV of UpdateParam is not an entity type"); + } + + it++; + } + else + throw Error("UpdateParam requires the first sub-TLV to be an entity type"); + + // the second block must be DefaultOpt + if (it != m_wire.elements_end() && it->type() == tlv::pib::DefaultOpt) { + m_defaultOpt = static_cast(readNonNegativeInteger(*it)); + it++; + } + else + throw Error("UpdateParam requires the second sub-TLV to be DefaultOpt"); + + if (it != m_wire.elements_end()) + throw Error("UpdateParam must not contain more than two sub-TLVs"); +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/encoding/update-param.hpp b/tools/pib/encoding/update-param.hpp new file mode 100644 index 0000000..6a6e5ba --- /dev/null +++ b/tools/pib/encoding/update-param.hpp @@ -0,0 +1,136 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_UPDATE_PARAM_HPP +#define NDN_PIB_UPDATE_PARAM_HPP + +#include "pib-common.hpp" +#include "pib-encoding.hpp" +#include +#include + +namespace ndn { +namespace pib { + +/** + * @brief UpdateParam is the abstraction of PIB Update parameter. + * + * PibUpdateParam := PIB-UPDATE-PARAM-TYPE TLV-LENGTH + * (PibIdentity | PibPublicKey | PibCertificate) + * PibDefaultOpt + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Update-Parameters + */ + +class UpdateParam : noncopyable +{ +public: + class Error : public tlv::Error + { + public: + explicit + Error(const std::string& what) + : tlv::Error(what) + { + } + }; + + UpdateParam(); + + explicit + UpdateParam(const PibUser& user); + + explicit + UpdateParam(const Name& identity, DefaultOpt defaultOpt = DEFAULT_OPT_NO); + + UpdateParam(const Name& keyName, const PublicKey& key, DefaultOpt defaultOpt = DEFAULT_OPT_NO); + + explicit + UpdateParam(const IdentityCertificate& certificate, DefaultOpt defaultOpt = DEFAULT_OPT_NO); + + explicit + UpdateParam(const Block& wire); + + tlv::pib::ParamType + getParamType() const + { + return tlv::pib::UpdateParam; + } + + tlv::pib::EntityType + getEntityType() const + { + return m_entityType; + } + + const PibUser& + getUser() const; + + const PibIdentity& + getIdentity() const; + + const PibPublicKey& + getPublicKey() const; + + const PibCertificate& + getCertificate() const; + + pib::DefaultOpt + getDefaultOpt() const + { + return m_defaultOpt; + } + + /// @brief Encode to a wire format or estimate wire format + template + size_t + wireEncode(EncodingImpl& block) const; + + /// @brief Encode to a wire format + const Block& + wireEncode() const; + + /** + * @brief Decode GetParam from a wire encoded block + * + * @throws Error if decoding fails + */ + void + wireDecode(const Block& wire); + +public: + static const std::string VERB; + +private: + tlv::pib::EntityType m_entityType; + PibUser m_user; + PibIdentity m_identity; + PibPublicKey m_key; + PibCertificate m_certificate; + pib::DefaultOpt m_defaultOpt; + + mutable Block m_wire; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_UPDATE_PARAM_HPP diff --git a/tools/pib/get-query-processor.cpp b/tools/pib/get-query-processor.cpp new file mode 100644 index 0000000..bc22747 --- /dev/null +++ b/tools/pib/get-query-processor.cpp @@ -0,0 +1,132 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "get-query-processor.hpp" +#include "encoding/pib-encoding.hpp" +#include + +namespace ndn { +namespace pib { + +const Name GetQueryProcessor::PIB_PREFIX("/localhost/pib"); +const size_t GetQueryProcessor::GET_QUERY_LENGTH = 5; + +GetQueryProcessor::GetQueryProcessor(PibDb& db) + : m_db(db) +{ +} + +std::pair +GetQueryProcessor::operator()(const Interest& interest) +{ + const Name& interestName = interest.getName(); + + // handle pib query: /localhost/pib/[UserName]/get/param + if (interestName.size() != GET_QUERY_LENGTH) { + // malformed interest, discard + return std::make_pair(false, Block()); + } + + GetParam param; + + try { + param.wireDecode(interestName.get(OFFSET_PARAM).blockFromValue()); + } + catch (const tlv::Error& e) { + PibError error(ERR_WRONG_PARAM, "error in parsing param: " + std::string(e.what())); + return std::make_pair(true, error.wireEncode()); + } + + switch (param.getTargetType()) { + case TYPE_ID: + return processGetIdQuery(param); + case TYPE_KEY: + return processGetKeyQuery(param); + case TYPE_CERT: + return processGetCertQuery(param); + case TYPE_USER: + if (interest.getName().get(2).toUri() != m_db.getOwnerName()) + return std::make_pair(false, Block()); + else + return processGetUserQuery(param); + default: + { + PibError error(ERR_WRONG_PARAM, "requested type is not supported:" + + boost::lexical_cast(param.getTargetType())); + return std::make_pair(true, error.wireEncode()); + } + } +} + +std::pair +GetQueryProcessor::processGetIdQuery(const GetParam& param) +{ + if (!m_db.hasIdentity(param.getTargetName())) { + PibError error(ERR_NON_EXISTING_ID, "requested id does not exist"); + return std::make_pair(true, error.wireEncode()); + } + + PibIdentity result(param.getTargetName()); + return std::make_pair(true, result.wireEncode()); +} + +std::pair +GetQueryProcessor::processGetKeyQuery(const GetParam& param) +{ + if (param.getTargetName().empty()) { + PibError error(ERR_WRONG_PARAM, "key name does not have id-component"); + return std::make_pair(true, error.wireEncode()); + } + + shared_ptr key = m_db.getKey(param.getTargetName()); + if (key == nullptr) { + PibError error(ERR_NON_EXISTING_KEY, "requested key does not exist"); + return std::make_pair(true, error.wireEncode()); + } + + PibPublicKey result(param.getTargetName(), *key); + return std::make_pair(true, result.wireEncode()); +} + +std::pair +GetQueryProcessor::processGetCertQuery(const GetParam& param) +{ + shared_ptr certificate = m_db.getCertificate(param.getTargetName()); + if (certificate == nullptr) { + PibError error(ERR_NON_EXISTING_CERT, "requested certificate does not exist"); + return std::make_pair(true, error.wireEncode()); + } + + PibCertificate result(*certificate); + return std::make_pair(true, result.wireEncode()); +} + +std::pair +GetQueryProcessor::processGetUserQuery(const GetParam& param) +{ + PibUser result; + result.setMgmtCert(*m_db.getMgmtCertificate()); + result.setTpmLocator(m_db.getTpmLocator()); + return std::make_pair(true, result.wireEncode()); +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/get-query-processor.hpp b/tools/pib/get-query-processor.hpp new file mode 100644 index 0000000..f4eca40 --- /dev/null +++ b/tools/pib/get-query-processor.hpp @@ -0,0 +1,82 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_GET_QUERY_PROCESSOR_HPP +#define NDN_PIB_GET_QUERY_PROCESSOR_HPP + +#include "pib-db.hpp" +#include "encoding/get-param.hpp" +#include +#include + +namespace ndn { +namespace pib { + +/// @brief implements the PIB service +class GetQueryProcessor : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + explicit + Error(const std::string& what) + : std::runtime_error(what) + { + } + }; + + /** + * @brief Constructor + * + * @param db The pib database. + * @param owner Owner of the pib database. + */ + explicit + GetQueryProcessor(PibDb& db); + + std::pair + operator()(const Interest& interest); + +private: + std::pair + processGetUserQuery(const GetParam& param); + + std::pair + processGetIdQuery(const GetParam& param); + + std::pair + processGetKeyQuery(const GetParam& param); + + std::pair + processGetCertQuery(const GetParam& param); + +private: + static const Name PIB_PREFIX; + static const size_t GET_QUERY_LENGTH; + + const PibDb& m_db; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_GET_QUERY_PROCESSOR_HPP diff --git a/tools/pib/key-cache.cpp b/tools/pib/key-cache.cpp new file mode 100644 index 0000000..431e635 --- /dev/null +++ b/tools/pib/key-cache.cpp @@ -0,0 +1,106 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "key-cache.hpp" + +namespace ndn { +namespace pib { + +KeyCacheEntry::KeyCacheEntry(const Name& name, shared_ptr key) + : name(name) + , key(key) +{ + BOOST_ASSERT(static_cast(key)); +} + +KeyCache::KeyCache(size_t capacity) + : m_capacity(capacity) +{ +} + +void +KeyCache::insert(const Name& name, shared_ptr key) +{ + // check if key exist + KeyContainer::index::type::iterator it = m_keys.get().find(name); + if (it != m_keys.get().end()) { + adjustLru(it); + return; + } + + // evict key when capacity is reached + if (size() >= m_capacity) + evictKey(); + + // insert entry + m_keys.insert(KeyCacheEntry(name, key)); +} + +shared_ptr +KeyCache::find(const Name& name) const +{ + // check if key exist + KeyContainer::index::type::iterator it = m_keys.get().find(name); + if (it == m_keys.get().end()) + return shared_ptr(); + else { + // adjust lru + shared_ptr key = it->key; + adjustLru(it); + return key; + } +} + +void +KeyCache::erase(const Name& name) +{ + // check if key exist + KeyContainer::index::type::iterator it = m_keys.get().find(name); + if (it != m_keys.get().end()) { + m_keys.erase(it); + } +} + +size_t +KeyCache::size() const +{ + return m_keys.size(); +} + +void +KeyCache::evictKey() +{ + if (!m_keys.get().empty()) { + KeyContainer::index::type::iterator it = m_keys.get().begin(); + m_keys.erase(m_keys.project<0>(it)); + } +} + +void +KeyCache::adjustLru(KeyContainer::iterator it) const +{ + KeyCacheEntry entry = std::move(*it); + m_keys.erase(it); + m_keys.insert(entry); +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/key-cache.hpp b/tools/pib/key-cache.hpp new file mode 100644 index 0000000..5df077a --- /dev/null +++ b/tools/pib/key-cache.hpp @@ -0,0 +1,108 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_KEY_CACHE_HPP +#define NDN_PIB_KEY_CACHE_HPP + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace ndn { +namespace pib { + +struct KeyCacheEntry +{ + KeyCacheEntry(const Name& name, shared_ptr key); + + Name name; + shared_ptr key; +}; + +class byName; +class byUsedTime; + +typedef boost::multi_index::multi_index_container< + KeyCacheEntry, + boost::multi_index::indexed_by< + boost::multi_index::hashed_unique< + boost::multi_index::tag, + boost::multi_index::member, + std::hash + >, + + boost::multi_index::sequenced< + boost::multi_index::tag + > + > +> KeyContainer; + +class KeyCache : noncopyable +{ +public: + explicit + KeyCache(size_t capacity = getDefaultCapacity()); + + void + insert(const Name& name, shared_ptr key); + + shared_ptr + find(const Name& name) const; + + void + erase(const Name& name); + + size_t + size() const; + +private: + static size_t + getDefaultCapacity() + { + return 100; + } + + void + evictKey(); + + void + adjustLru(KeyContainer::iterator it) const; + + void + freeEntry(KeyContainer::iterator it); + +private: + size_t m_capacity; + mutable KeyContainer m_keys; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_KEY_CACHE_HPP diff --git a/tools/pib/list-query-processor.cpp b/tools/pib/list-query-processor.cpp new file mode 100644 index 0000000..ad4e2d5 --- /dev/null +++ b/tools/pib/list-query-processor.cpp @@ -0,0 +1,98 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "list-query-processor.hpp" +#include "encoding/pib-encoding.hpp" +#include + +namespace ndn { +namespace pib { + +using std::string; +using std::vector; + +const size_t ListQueryProcessor::LIST_QUERY_LENGTH = 5; + +ListQueryProcessor::ListQueryProcessor(PibDb& db) + : m_db(db) +{ +} + +std::pair +ListQueryProcessor::operator()(const Interest& interest) +{ + const Name& interestName = interest.getName(); + + // handle pib query: /localhost/pib/[UserName]/list/param + if (interestName.size() != MIN_PIB_INTEREST_SIZE) { + // malformed interest, discard + return std::make_pair(false, Block()); + } + + ListParam param; + + try { + param.wireDecode(interestName.get(OFFSET_PARAM).blockFromValue()); + } + catch (const tlv::Error& e) { + PibError error(ERR_WRONG_PARAM, "error in parsing param: " + string(e.what())); + return std::make_pair(true, error.wireEncode()); + } + + vector nameList; + switch (param.getOriginType()) { + case TYPE_USER: + { + nameList = m_db.listIdentities(); + break; + } + case TYPE_ID: + { + nameList = m_db.listKeyNamesOfIdentity(param.getOriginName()); + break; + } + case TYPE_KEY: + { + const Name& keyName = param.getOriginName(); + if (keyName.empty()) { + PibError error(ERR_WRONG_PARAM, + "key name must contain key id component"); + return std::make_pair(true, error.wireEncode()); + } + + nameList = m_db.listCertNamesOfKey(keyName); + break; + } + default: + { + PibError error(ERR_WRONG_PARAM, + "origin type is not supported: " + + boost::lexical_cast(param.getOriginType())); + return std::make_pair(true, error.wireEncode()); + } + } + + PibNameList result(nameList); + return std::make_pair(true, result.wireEncode()); +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/list-query-processor.hpp b/tools/pib/list-query-processor.hpp new file mode 100644 index 0000000..4b814f7 --- /dev/null +++ b/tools/pib/list-query-processor.hpp @@ -0,0 +1,66 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_LIST_QUERY_PROCESSOR_HPP +#define NDN_PIB_LIST_QUERY_PROCESSOR_HPP + +#include "pib-db.hpp" +#include "encoding/list-param.hpp" +#include +#include + +namespace ndn { +namespace pib { + +class ListQueryProcessor : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + explicit + Error(const std::string& what) + : std::runtime_error(what) + { + } + }; + + /** + * @brief Constructor + * + * @param db The pib database. + */ + explicit + ListQueryProcessor(PibDb& db); + + std::pair + operator()(const Interest& interest); + +private: + static const size_t LIST_QUERY_LENGTH; + + const PibDb& m_db; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_LIST_QUERY_PROCESSOR_HPP diff --git a/tools/pib/ndn-pib.cpp b/tools/pib/ndn-pib.cpp new file mode 100644 index 0000000..4166bd8 --- /dev/null +++ b/tools/pib/ndn-pib.cpp @@ -0,0 +1,127 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "pib.hpp" + +#include +#include +#include + +#include +#include +#include +#include + +namespace ndn { +namespace pib { + +int +main(int argc, char** argv) +{ + namespace po = boost::program_options; + namespace fs = boost::filesystem; + + std::string owner; + std::string dbDir; + std::string tpmLocator; + Face face; + + std::cerr << "hello" << std::endl; + + po::options_description description( + "General Usage\n" + " ndn-pib [-h] -o owner -d database_dir -t tpm_locator\n" + "General options"); + + description.add_options() + ("help,h", "produce help message") + ("owner,o", po::value(&owner), + "Name of the owner, PIB will listen to /localhost/pib/[owner].") + ("database,d", po::value(&dbDir), + "Absolute path to the directory of PIB database, //pib.db") + ("tpm,t", po::value(&tpmLocator), + "URI of the tpm. e.g., tpm-file:/var") + ; + + po::variables_map vm; + try { + po::store(po::parse_command_line(argc, argv, description), vm); + po::notify(vm); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + std::cerr << description << std::endl; + return 1; + } + + if (vm.count("help") != 0) { + std::cerr << description << std::endl; + return 0; + } + + try { + if (vm.count("owner") == 0 && vm.count("database") == 0 && vm.count("tpm") == 0) { + if (std::getenv("HOME")) { + fs::path pibDir(std::getenv("HOME")); + pibDir /= ".ndn/pib"; + dbDir = pibDir.string(); + } + else { + std::cerr << "ERROR: HOME variable is not set" << std::endl; + return 1; + } + + tpmLocator = KeyChain::getDefaultTpmLocator(); + + if (std::getenv("USER")) { + owner = std::string(std::getenv("USER")); + } + else { + std::cerr << "ERROR: HOME variable is not set" << std::endl; + return 1; + } + } + else if (vm.count("owner") == 0 || vm.count("database") == 0 || + vm.count("tpm") == 0) { + std::cerr << description << std::endl; + return 1; + } + + Pib pib(face, dbDir, tpmLocator, owner); + face.processEvents(); + } + catch (std::runtime_error& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + return 1; + } + + + return 0; +} + +} // namespace pib +} // namespace ndn + +int +main(int argc, char** argv) +{ + ndn::pib::main(argc, argv); +} diff --git a/tools/pib/pib-db.cpp b/tools/pib/pib-db.cpp new file mode 100644 index 0000000..0e2ce87 --- /dev/null +++ b/tools/pib/pib-db.cpp @@ -0,0 +1,825 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "pib-db.hpp" +#include +#include +#include + +namespace ndn { +namespace pib { + +using std::string; +using std::vector; +using std::set; + +const Name PibDb::NON_EXISTING_IDENTITY("/localhost/reserved/non-existing-identity"); +const Name PibDb::NON_EXISTING_KEY("/localhost/reserved/non-existing-key"); +const Name PibDb::NON_EXISTING_CERTIFICATE("/localhost/reserved/non-existing-certificate"); + +const Name PibDb::LOCALHOST_PIB("/localhost/pib"); +const name::Component PibDb::MGMT_LABEL("mgmt"); + + +static const string INITIALIZATION = + "CREATE TABLE IF NOT EXISTS \n" + " mgmt( \n" + " id INTEGER PRIMARY KEY,\n" + " owner BLOB NOT NULL, \n" + " tpm_locator BLOB, \n" + " local_management_cert BLOB NOT NULL \n" + " ); \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " mgmt_insert_trigger \n" + " BEFORE INSERT ON mgmt \n" + " FOR EACH ROW \n" + " BEGIN \n" + " DELETE FROM mgmt; \n" + " END; \n" + " \n" + "CREATE TABLE IF NOT EXISTS \n" + " identities( \n" + " id INTEGER PRIMARY KEY,\n" + " identity BLOB NOT NULL, \n" + " is_default INTEGER DEFAULT 0 \n" + " ); \n" + "CREATE UNIQUE INDEX IF NOT EXISTS \n" + " identityIndex ON identities(identity); \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " identity_default_before_insert_trigger \n" + " BEFORE INSERT ON identities \n" + " FOR EACH ROW \n" + " WHEN NEW.is_default=1 \n" + " BEGIN \n" + " UPDATE identities SET is_default=0; \n" + " END; \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " identity_default_after_insert_trigger \n" + " AFTER INSERT ON identities \n" + " FOR EACH ROW \n" + " WHEN NOT EXISTS \n" + " (SELECT id \n" + " FROM identities \n" + " WHERE is_default=1) \n" + " BEGIN \n" + " UPDATE identities \n" + " SET is_default=1 \n" + " WHERE identity=NEW.identity; \n" + " END; \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " identity_default_update_trigger \n" + " BEFORE UPDATE ON identities \n" + " FOR EACH ROW \n" + " WHEN NEW.is_default=1 AND OLD.is_default=0 \n" + " BEGIN \n" + " UPDATE identities SET is_default=0; \n" + " END; \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " identity_delete_trigger \n" + " AFTER DELETE ON identities \n" + " FOR EACH ROW \n" + " BEGIN \n" + " SELECT identityDeleted (OLD.identity); \n" + " END; \n" + " \n" + "CREATE TABLE IF NOT EXISTS \n" + " keys( \n" + " id INTEGER PRIMARY KEY,\n" + " identity_id INTEGER NOT NULL, \n" + " key_name BLOB NOT NULL, \n" + " key_type INTEGER NOT NULL, \n" + " key_bits BLOB NOT NULL, \n" + " is_default INTEGER DEFAULT 0, \n" + " FOREIGN KEY(identity_id) \n" + " REFERENCES identities(id) \n" + " ON DELETE CASCADE \n" + " ON UPDATE CASCADE \n" + " ); \n" + "CREATE UNIQUE INDEX IF NOT EXISTS \n" + " keyIndex ON keys(key_name); \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " key_default_before_insert_trigger \n" + " BEFORE INSERT ON keys \n" + " FOR EACH ROW \n" + " WHEN NEW.is_default=1 \n" + " BEGIN \n" + " UPDATE keys \n" + " SET is_default=0 \n" + " WHERE identity_id=NEW.identity_id; \n" + " END; \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " key_default_after_insert_trigger \n" + " AFTER INSERT ON keys \n" + " FOR EACH ROW \n" + " WHEN NOT EXISTS \n" + " (SELECT id \n" + " FROM keys \n" + " WHERE is_default=1 \n" + " AND identity_id=NEW.identity_id) \n" + " BEGIN \n" + " UPDATE keys \n" + " SET is_default=1 \n" + " WHERE key_name=NEW.key_name; \n" + " END; \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " key_default_update_trigger \n" + " BEFORE UPDATE ON keys \n" + " FOR EACH ROW \n" + " WHEN NEW.is_default=1 AND OLD.is_default=0 \n" + " BEGIN \n" + " UPDATE keys \n" + " SET is_default=0 \n" + " WHERE identity_id=NEW.identity_id; \n" + " END; \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " key_delete_trigger \n" + " AFTER DELETE ON keys \n" + " FOR EACH ROW \n" + " BEGIN \n" + " SELECT keyDeleted (OLD.key_name); \n" + " END; \n" + " \n" + "CREATE TABLE IF NOT EXISTS \n" + " certificates( \n" + " id INTEGER PRIMARY KEY,\n" + " key_id INTEGER NOT NULL, \n" + " certificate_name BLOB NOT NULL, \n" + " certificate_data BLOB NOT NULL, \n" + " is_default INTEGER DEFAULT 0, \n" + " FOREIGN KEY(key_id) \n" + " REFERENCES keys(id) \n" + " ON DELETE CASCADE \n" + " ON UPDATE CASCADE \n" + " ); \n" + "CREATE UNIQUE INDEX IF NOT EXISTS \n" + " certIndex ON certificates(certificate_name);\n" + "CREATE TRIGGER IF NOT EXISTS \n" + " cert_default_before_insert_trigger \n" + " BEFORE INSERT ON certificates \n" + " FOR EACH ROW \n" + " WHEN NEW.is_default=1 \n" + " BEGIN \n" + " UPDATE certificates \n" + " SET is_default=0 \n" + " WHERE key_id=NEW.key_id; \n" + " END; \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " cert_default_after_insert_trigger \n" + " AFTER INSERT ON certificates \n" + " FOR EACH ROW \n" + " WHEN NOT EXISTS \n" + " (SELECT id \n" + " FROM certificates \n" + " WHERE is_default=1 \n" + " AND key_id=NEW.key_id) \n" + " BEGIN \n" + " UPDATE certificates \n" + " SET is_default=1 \n" + " WHERE certificate_name=NEW.certificate_name;\n" + " END; \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " cert_default_update_trigger \n" + " BEFORE UPDATE ON certificates \n" + " FOR EACH ROW \n" + " WHEN NEW.is_default=1 AND OLD.is_default=0 \n" + " BEGIN \n" + " UPDATE certificates \n" + " SET is_default=0 \n" + " WHERE key_id=NEW.key_id; \n" + " END; \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " cert_delete_trigger \n" + " AFTER DELETE ON certificates \n" + " FOR EACH ROW \n" + " BEGIN \n" + " SELECT certDeleted (OLD.certificate_name);\n" + " END; \n" + "CREATE TRIGGER IF NOT EXISTS \n" + " cert_insert_trigger \n" + " AFTER INSERT ON certificates \n" + " FOR EACH ROW \n" + " BEGIN \n" + " SELECT certInserted (NEW.certificate_name);\n" + " END; \n"; + + +/** + * A utility function to call the normal sqlite3_bind_text where the value and length are + * value.c_str() and value.size(). + */ +static int +sqlite3_bind_string(sqlite3_stmt* statement, + int index, + const string& value, + void(*destructor)(void*)) +{ + return sqlite3_bind_text(statement, index, value.c_str(), value.size(), destructor); +} + +/** + * A utility function to call the normal sqlite3_bind_blob where the value and length are + * block.wire() and block.size(). + */ +static int +sqlite3_bind_block(sqlite3_stmt* statement, + int index, + const Block& block, + void(*destructor)(void*)) +{ + return sqlite3_bind_blob(statement, index, block.wire(), block.size(), destructor); +} + +/** + * A utility function to generate string by calling the normal sqlite3_column_text. + */ +static string +sqlite3_column_string(sqlite3_stmt* statement, int column) +{ + return string(reinterpret_cast(sqlite3_column_text(statement, column)), + sqlite3_column_bytes(statement, column)); +} + +/** + * A utility function to generate block by calling the normal sqlite3_column_text. + */ +static Block +sqlite3_column_block(sqlite3_stmt* statement, int column) +{ + return Block(sqlite3_column_blob(statement, column), sqlite3_column_bytes(statement, column)); +} + +PibDb::PibDb(const string& dbDir) +{ + // Determine the path of PIB DB + boost::filesystem::path dir; + if (dbDir == "") { + dir = boost::filesystem::path(getenv("HOME")) / ".ndn"; + boost::filesystem::create_directories(dir); + } + else { + dir = boost::filesystem::path(dbDir); + boost::filesystem::create_directories(dir); + } + // Open PIB + int result = sqlite3_open_v2((dir / "pib.db").c_str(), &m_database, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, +#ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING + "unix-dotfile" +#else + nullptr +#endif + ); + + if (result != SQLITE_OK) + throw Error("PIB DB cannot be opened/created: " + dbDir); + + + // enable foreign key + sqlite3_exec(m_database, "PRAGMA foreign_keys = ON", nullptr, nullptr, nullptr); + + // initialize PIB specific tables + char* errorMessage = nullptr; + result = sqlite3_exec(m_database, INITIALIZATION.c_str(), nullptr, nullptr, &errorMessage); + if (result != SQLITE_OK && errorMessage != nullptr) { + sqlite3_free(errorMessage); + throw Error("PIB DB cannot be initialized"); + } + + // create delete trigger functions + createDbDeleteTrigger(); + + getOwnerName(); +} + +void +PibDb::createDbDeleteTrigger() +{ + int res = 0; + + res = sqlite3_create_function(m_database, "identityDeleted", -1, SQLITE_UTF8, + reinterpret_cast(this), + PibDb::identityDeletedFun, nullptr, nullptr); + if (res != SQLITE_OK) + throw Error("Cannot create function ``identityDeleted''"); + + res = sqlite3_create_function(m_database, "keyDeleted", -1, SQLITE_UTF8, + reinterpret_cast(this), + PibDb::keyDeletedFun, nullptr, nullptr); + if (res != SQLITE_OK) + throw Error("Cannot create function ``keyDeleted''"); + + res = sqlite3_create_function(m_database, "certDeleted", -1, SQLITE_UTF8, + reinterpret_cast(this), + PibDb::certDeletedFun, nullptr, nullptr); + if (res != SQLITE_OK) + throw Error("Cannot create function ``certDeleted''"); + + res = sqlite3_create_function(m_database, "certInserted", -1, SQLITE_UTF8, + reinterpret_cast(this), + PibDb::certInsertedFun, nullptr, nullptr); + if (res != SQLITE_OK) + throw Error("Cannot create function ``certInserted''"); +} + +void +PibDb::identityDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + BOOST_ASSERT(argc == 1); + + PibDb* pibDb = reinterpret_cast(sqlite3_user_data(context)); + Name identity(Block(sqlite3_value_blob(argv[0]), sqlite3_value_bytes(argv[0]))); + + pibDb->identityDeleted(identity); +} + +void +PibDb::keyDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + BOOST_ASSERT(argc == 1); + + PibDb* pibDb = reinterpret_cast(sqlite3_user_data(context)); + Name keyName(Block(sqlite3_value_blob(argv[0]), sqlite3_value_bytes(argv[0]))); + + pibDb->keyDeleted(keyName); +} + +void +PibDb::certDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + BOOST_ASSERT(argc == 1); + + PibDb* pibDb = reinterpret_cast(sqlite3_user_data(context)); + Name certName(Block(sqlite3_value_blob(argv[0]), sqlite3_value_bytes(argv[0]))); + + pibDb->certificateDeleted(certName); +} + +void +PibDb::certInsertedFun(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + BOOST_ASSERT(argc == 1); + + PibDb* pibDb = reinterpret_cast(sqlite3_user_data(context)); + Name certName(Block(sqlite3_value_blob(argv[0]), sqlite3_value_bytes(argv[0]))); + + pibDb->certificateInserted(certName); +} + +void +PibDb::updateMgmtCertificate(const IdentityCertificate& certificate) +{ + const Name& keyName = certificate.getPublicKeyName(); + + // Name of mgmt key should be "/localhost/pib/[UserName]/mgmt/[KeyID]" + if (keyName.size() != 5 || + keyName.compare(0, 2, LOCALHOST_PIB) || + keyName.get(3) != MGMT_LABEL) + throw Error("PibDb::updateMgmtCertificate: certificate does not follow the naming convention"); + + string owner = keyName.get(2).toUri(); + sqlite3_stmt* statement; + if (!m_owner.empty()) { + if (m_owner != owner) + throw Error("PibDb::updateMgmtCertificate: owner name does not match"); + else { + sqlite3_prepare_v2(m_database, + "UPDATE mgmt SET local_management_cert=? WHERE owner=?", + -1, &statement, nullptr); + } + } + else { + sqlite3_prepare_v2(m_database, + "INSERT INTO mgmt (local_management_cert, owner) VALUES (?, ?)", + -1, &statement, nullptr); + } + + sqlite3_bind_block(statement, 1, certificate.wireEncode(), SQLITE_TRANSIENT); + sqlite3_bind_string(statement, 2, owner, SQLITE_TRANSIENT); + sqlite3_step(statement); + sqlite3_finalize(statement); + + m_owner = owner; + + mgmtCertificateChanged(); +} + +string +PibDb::getOwnerName() const +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, "SELECT owner FROM mgmt", -1, &statement, nullptr); + + if (sqlite3_step(statement) == SQLITE_ROW) { + m_owner = sqlite3_column_string(statement, 0); + } + + sqlite3_finalize(statement); + return m_owner; +} + +shared_ptr +PibDb::getMgmtCertificate() const +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, "SELECT local_management_cert FROM mgmt", -1, &statement, nullptr); + + shared_ptr certificate; + if (sqlite3_step(statement) == SQLITE_ROW) { + certificate = make_shared(); + certificate->wireDecode(sqlite3_column_block(statement, 0)); + } + + sqlite3_finalize(statement); + return certificate; +} + +void +PibDb::setTpmLocator(const std::string& tpmLocator) +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "UPDATE mgmt SET tpm_locator=? WHERE owner=?", + -1, &statement, nullptr); + sqlite3_bind_string(statement, 1, tpmLocator, SQLITE_TRANSIENT); + sqlite3_bind_string(statement, 2, m_owner, SQLITE_TRANSIENT); + sqlite3_step(statement); + sqlite3_finalize(statement); +} + +std::string +PibDb::getTpmLocator() const +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, "SELECT tpm_locator FROM mgmt", -1, &statement, nullptr); + + string tpmLocator; + if (sqlite3_step(statement) == SQLITE_ROW) { + tpmLocator = sqlite3_column_string(statement, 0); + } + + sqlite3_finalize(statement); + return tpmLocator; +} + +int64_t +PibDb::addIdentity(const Name& identity) +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "INSERT INTO identities (identity) values (?)", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT); + sqlite3_step(statement); + sqlite3_finalize(statement); + + return sqlite3_last_insert_rowid(m_database); +} + +void +PibDb::deleteIdentity(const Name& identity) +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "DELETE FROM identities WHERE identity=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT); + sqlite3_step(statement); + sqlite3_finalize(statement); +} + +bool +PibDb::hasIdentity(const Name& identity) const +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "SELECT id FROM identities WHERE identity=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT); + int result = sqlite3_step(statement); + sqlite3_finalize(statement); + + if (result == SQLITE_ROW) + return true; + else + return false; +} + +void +PibDb::setDefaultIdentity(const Name& identity) +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "UPDATE identities SET is_default=1 WHERE identity=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT); + sqlite3_step(statement); + sqlite3_finalize(statement); +} + +Name +PibDb::getDefaultIdentity() const +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "SELECT identity FROM identities WHERE is_default=1", + -1, &statement, nullptr); + + Name identity = NON_EXISTING_IDENTITY; + if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_bytes(statement, 0) != 0) { + identity = Name(sqlite3_column_block(statement, 0)); + } + sqlite3_finalize(statement); + return identity; +} + +vector +PibDb::listIdentities() const +{ + vector identities; + + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, "SELECT identity FROM identities", -1, &statement, nullptr); + + identities.clear(); + while (sqlite3_step(statement) == SQLITE_ROW) { + Name name(sqlite3_column_block(statement, 0)); + identities.push_back(name); + } + sqlite3_finalize(statement); + + return identities; +} + +int64_t +PibDb::addKey(const Name& keyName, const PublicKey& key) +{ + if (keyName.empty()) + return 0; + + Name&& identity = keyName.getPrefix(-1); + if (!hasIdentity(identity)) + addIdentity(identity); + + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "INSERT INTO keys (identity_id, key_name, key_type, key_bits) \ + values ((SELECT id FROM identities WHERE identity=?), ?, ?, ?)", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT); + sqlite3_bind_block(statement, 2, keyName.wireEncode(), SQLITE_TRANSIENT); + sqlite3_bind_int(statement, 3, key.getKeyType()); + sqlite3_bind_blob(statement, 4, key.get().buf(), key.get().size(), SQLITE_STATIC); + sqlite3_step(statement); + sqlite3_finalize(statement); + + return sqlite3_last_insert_rowid(m_database); +} + +shared_ptr +PibDb::getKey(const Name& keyName) const +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "SELECT key_bits FROM keys WHERE key_name=?" + , -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT); + + shared_ptr key; + if (sqlite3_step(statement) == SQLITE_ROW) { + key = make_shared(static_cast(sqlite3_column_blob(statement, 0)), + sqlite3_column_bytes(statement, 0)); + } + sqlite3_finalize(statement); + return key; +} + +void +PibDb::deleteKey(const Name& keyName) +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "DELETE FROM keys WHERE key_name=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT); + sqlite3_step(statement); + sqlite3_finalize(statement); +} + +bool +PibDb::hasKey(const Name& keyName) const +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "SELECT id FROM keys WHERE key_name=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT); + + int result = sqlite3_step(statement); + sqlite3_finalize(statement); + + if (result == SQLITE_ROW) + return true; + else + return false; +} + +void +PibDb::setDefaultKeyNameOfIdentity(const Name& keyName) +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "UPDATE keys SET is_default=1 WHERE key_name=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT); + sqlite3_step(statement); + sqlite3_finalize(statement); +} + +Name +PibDb::getDefaultKeyNameOfIdentity(const Name& identity) const +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "SELECT key_name FROM keys JOIN identities ON keys.identity_id=identities.id\ + WHERE identities.identity=? AND keys.is_default=1", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT); + + Name keyName = NON_EXISTING_KEY; + if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_bytes(statement, 0) != 0) { + keyName = Name(sqlite3_column_block(statement, 0)); + } + + sqlite3_finalize(statement); + return keyName; +} + +vector +PibDb::listKeyNamesOfIdentity(const Name& identity) const +{ + vector keyNames; + + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "SELECT key_name FROM keys JOIN identities ON keys.identity_id=identities.id\ + WHERE identities.identity=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT); + + keyNames.clear(); + while (sqlite3_step(statement) == SQLITE_ROW) { + Name keyName(sqlite3_column_block(statement, 0)); + keyNames.push_back(keyName); + } + + sqlite3_finalize(statement); + return keyNames; +} + + +int64_t +PibDb::addCertificate(const IdentityCertificate& certificate) +{ + const Name& certName = certificate.getName(); + const Name& keyName = certificate.getPublicKeyName(); + + if (!hasKey(keyName)) + addKey(keyName, certificate.getPublicKeyInfo()); + + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "INSERT INTO certificates \ + (key_id, certificate_name, certificate_data) \ + values ((SELECT id FROM keys WHERE key_name=?), ?, ?)", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT); + sqlite3_bind_block(statement, 2, certName.wireEncode(), SQLITE_TRANSIENT); + sqlite3_bind_block(statement, 3, certificate.wireEncode(), SQLITE_STATIC); + sqlite3_step(statement); + sqlite3_finalize(statement); + + return sqlite3_last_insert_rowid(m_database); +} + +shared_ptr +PibDb::getCertificate(const Name& certificateName) const +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "SELECT certificate_data FROM certificates WHERE certificate_name=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, certificateName.wireEncode(), SQLITE_TRANSIENT); + + shared_ptr certificate; + if (sqlite3_step(statement) == SQLITE_ROW) { + certificate = make_shared(); + certificate->wireDecode(sqlite3_column_block(statement, 0)); + } + + sqlite3_finalize(statement); + return certificate; +} + +void +PibDb::deleteCertificate(const Name& certificateName) +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "DELETE FROM certificates WHERE certificate_name=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, certificateName.wireEncode(), SQLITE_TRANSIENT); + sqlite3_step(statement); + sqlite3_finalize(statement); +} + +bool +PibDb::hasCertificate(const Name& certificateName) const +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "SELECT id FROM certificates WHERE certificate_name=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, certificateName.wireEncode(), SQLITE_TRANSIENT); + int result = sqlite3_step(statement); + sqlite3_finalize(statement); + + if (result == SQLITE_ROW) + return true; + else + return false; +} + +void +PibDb::setDefaultCertNameOfKey(const Name& certificateName) +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "UPDATE certificates SET is_default=1 WHERE certificate_name=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, certificateName.wireEncode(), SQLITE_TRANSIENT); + sqlite3_step(statement); + sqlite3_finalize(statement); +} + +Name +PibDb::getDefaultCertNameOfKey(const Name& keyName) const +{ + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "SELECT certificate_name\ + FROM certificates JOIN keys ON certificates.key_id=keys.id\ + WHERE keys.key_name=? AND certificates.is_default=1", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT); + + Name certName = NON_EXISTING_CERTIFICATE; + if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_bytes(statement, 0) != 0) { + certName = Name(sqlite3_column_block(statement, 0)); + } + sqlite3_finalize(statement); + return certName; +} + +vector +PibDb::listCertNamesOfKey(const Name& keyName) const +{ + vector certNames; + + sqlite3_stmt* statement; + sqlite3_prepare_v2(m_database, + "SELECT certificate_name\ + FROM certificates JOIN keys ON certificates.key_id=keys.id\ + WHERE keys.key_name=?", + -1, &statement, nullptr); + sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT); + + certNames.clear(); + while (sqlite3_step(statement) == SQLITE_ROW) { + Name name(sqlite3_column_block(statement, 0)); + certNames.push_back(name); + } + sqlite3_finalize(statement); + + return certNames; +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/pib-db.hpp b/tools/pib/pib-db.hpp new file mode 100644 index 0000000..5101e25 --- /dev/null +++ b/tools/pib/pib-db.hpp @@ -0,0 +1,265 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_PIB_DB_HPP +#define NDN_PIB_PIB_DB_HPP + +#include "core/common.hpp" +#include +#include + +#include +#include + +struct sqlite3; +struct sqlite3_context; +struct Mem; +typedef Mem sqlite3_value; + +namespace ndn { +namespace pib { + +/// @brief Callback to report changes on user info. +typedef function UserChangedEventHandler; + +/// @brief Callback to report that a key is deleted. +typedef function KeyDeletedEventHandler; + +/** + * @brief PibDb is a class to manage the database of PIB service. + * + * only public key related information is stored in this database. + * Detail information can be found at: + * http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base + */ +class PibDb : noncopyable +{ +public: + util::signal::Signal mgmtCertificateChanged; + util::signal::Signal certificateDeleted; + util::signal::Signal keyDeleted; + util::signal::Signal identityDeleted; + util::signal::Signal certificateInserted; + +public: + class Error : public std::runtime_error + { + public: + explicit + Error(const std::string& what) + : std::runtime_error(what) + { + } + }; + + explicit + PibDb(const std::string& dbDir = ""); + +public: // Owner management + /** + * @brief Update owner's management certificate + * + * Since owner name is encoded in the management certificate, + * this method can also set the owner name if it is not set. + * If the owner name is set but does not match the one in the + * supplied certificate, it throws @p Error. + * + * @throws Error if supplied certificate is wrong + */ + void + updateMgmtCertificate(const IdentityCertificate& certificate); + + /** + * @brief Get owner name + * + * return empty string when owner name is not set. + */ + std::string + getOwnerName() const; + + /** @brief Get the management cert + * + * return nullptr when the management cert is not set + */ + shared_ptr + getMgmtCertificate() const; + + /// @brief Set TPM locator + void + setTpmLocator(const std::string& tpmLocator); + + /** + * @brief Get TPM locator + * + * return empty string when tpmLocator is not set. + */ + std::string + getTpmLocator() const; + +public: // Identity management + + /** + * @brief Add an identity + * + * @return row id of the added identity, 0 if insert fails. + */ + int64_t + addIdentity(const Name& identity); + + /// @brief Delete an identity + void + deleteIdentity(const Name& identity); + + /// @brief Check if an identity exists + bool + hasIdentity(const Name& identity) const; + + /// @brief Get all identities + std::vector + listIdentities() const; + + /// @brief Set the default identity + void + setDefaultIdentity(const Name& identity); + + /** + * @brief Get the default identity + * + * @return default identity or /localhost/reserved/non-existing-identity if no default identity + */ + Name + getDefaultIdentity() const; + +public: // Key management + + /// @brief Add key + int64_t + addKey(const Name& keyName, const PublicKey& key); + + /// @brief Delete key + void + deleteKey(const Name& keyName); + + /// @brief Check if a key exists + bool + hasKey(const Name& keyName) const; + + /** + * @brief Get key + * + * @return shared pointer to the key, nullptr if the key does not exit + */ + shared_ptr + getKey(const Name& keyName) const; + + /// @brief Get all the key names of an identity + std::vector + listKeyNamesOfIdentity(const Name& identity) const; + + /// @brief Set an identity's default key name + void + setDefaultKeyNameOfIdentity(const Name& keyName); + + /** + * @brief Get the default key name of an identity + * + * @return default key name or /localhost/reserved/non-existing-key if no default key + */ + Name + getDefaultKeyNameOfIdentity(const Name& identity) const; + +public: // Certificate management + + /// @brief Add a certificate + int64_t + addCertificate(const IdentityCertificate& certificate); + + /// @brief Delete a certificate + void + deleteCertificate(const Name& certificateName); + + /// @brief Check if the certificate exist + bool + hasCertificate(const Name& certificateName) const; + + /** + * @brief Get a certificate + * + * @return shared pointer to the certificate, nullptr if the certificate does not exist + */ + shared_ptr + getCertificate(const Name& certificateName) const; + + /// @brief Get all the cert names of a key + std::vector + listCertNamesOfKey(const Name& keyName) const; + + /// @brief Set a key's default certificate name + void + setDefaultCertNameOfKey(const Name& certificateName); + + /** + * @brief Get a key's default certificate name + * + * @return default certificate name or /localhost/reserved/non-existing-certificate if no default + * certificate. + */ + Name + getDefaultCertNameOfKey(const Name& keyName) const; + +private: + void + createDbDeleteTrigger(); + +private: + static void + identityDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv); + + static void + keyDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv); + + static void + certDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv); + + static void + certInsertedFun(sqlite3_context* context, int argc, sqlite3_value** argv); + +public: + static const Name NON_EXISTING_IDENTITY; + static const Name NON_EXISTING_KEY; + static const Name NON_EXISTING_CERTIFICATE; + +private: + static const Name LOCALHOST_PIB; + static const name::Component MGMT_LABEL; + +private: + sqlite3* m_database; + + mutable std::string m_owner; +}; + +} // namespace pib +} // namespace ndn + + +#endif // NDN_PIB_PIB_DB_HPP diff --git a/tools/pib/pib-validator.cpp b/tools/pib/pib-validator.cpp new file mode 100644 index 0000000..cc34645 --- /dev/null +++ b/tools/pib/pib-validator.cpp @@ -0,0 +1,163 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "pib-validator.hpp" +#include "encoding/pib-common.hpp" +#include "encoding/update-param.hpp" +#include +#include + +namespace ndn { +namespace pib { + +using std::set; +using std::string; + +PibValidator::PibValidator(const PibDb& db, size_t maxCacheSize) + : m_db(db) + , m_isMgmtReady(false) +{ + m_owner = m_db.getOwnerName(); + m_mgmtCert = m_db.getMgmtCertificate(); + + if (!m_owner.empty() && m_mgmtCert != nullptr) + m_isMgmtReady = true; + + m_mgmtChangeConnection = + const_cast(m_db).mgmtCertificateChanged.connect([this] () { + m_owner = m_db.getOwnerName(); + m_mgmtCert = m_db.getMgmtCertificate(); + if (!m_owner.empty() && m_mgmtCert != nullptr) + m_isMgmtReady = true; + }); + + m_keyDeletedConnection = + const_cast(m_db).keyDeleted.connect([this] (Name keyName) { + m_keyCache.erase(keyName); + }); +} + +PibValidator::~PibValidator() +{ +} + +void +PibValidator::checkPolicy(const Interest& interest, + int nSteps, + const OnInterestValidated& onValidated, + const OnInterestValidationFailed& onValidationFailed, + std::vector>& nextSteps) +{ + if (!m_isMgmtReady) + return onValidationFailed(interest.shared_from_this(), "PibDb is not initialized"); + + const Name& interestName = interest.getName(); + + if (interestName.size() != SIGNED_PIB_INTEREST_SIZE) { + return onValidationFailed(interest.shared_from_this(), + "Interest is not signed: " + interest.getName().toUri()); + } + + // Check if the user exists in PIB + string user = interestName.get(OFFSET_USER).toUri(); + if (user != m_owner) + return onValidationFailed(interest.shared_from_this(), "Wrong user: " + user); + + // Verify signature + try { + Signature signature(interestName[OFFSET_SIG_INFO].blockFromValue(), + interestName[OFFSET_SIG_VALUE].blockFromValue()); + // KeyLocator is required to contain the name of signing certificate (w/o version) + if (!signature.hasKeyLocator()) + return onValidationFailed(interest.shared_from_this(), "No valid KeyLocator"); + + const KeyLocator& keyLocator = signature.getKeyLocator(); + if (keyLocator.getType() != KeyLocator::KeyLocator_Name) + return onValidationFailed(interest.shared_from_this(), "Key Locator is not a name"); + + // Check if PIB has the corresponding public key + shared_ptr publicKey; + + if (keyLocator.getName() == m_mgmtCert->getName().getPrefix(-1)) { + // the signing key is mgmt key. + publicKey = make_shared(m_mgmtCert->getPublicKeyInfo()); + } + else { + // the signing key is normal key. + Name keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName()); + + shared_ptr key = m_keyCache.find(keyName); + if (key != nullptr) { + // the signing key is cached. + publicKey = key; + } + else { + // the signing key is not cached. + publicKey = m_db.getKey(keyName); + if (publicKey == nullptr) { + // the signing key does not exist in PIB. + return onValidationFailed(interest.shared_from_this(), "Public key is not trusted"); + } + else { + // the signing key is retrieved from PIB. + m_keyCache.insert(keyName, publicKey); + } + } + } + + if (verifySignature(interest, signature, *publicKey)) + onValidated(interest.shared_from_this()); + else + onValidationFailed(interest.shared_from_this(), "Cannot verify signature"); + + } + catch (KeyLocator::Error&) { + return onValidationFailed(interest.shared_from_this(), + "No valid KeyLocator"); + } + catch (Signature::Error&) { + return onValidationFailed(interest.shared_from_this(), + "No valid signature"); + } + catch (IdentityCertificate::Error&) { + return onValidationFailed(interest.shared_from_this(), + "Cannot determine the signing key"); + } + catch (tlv::Error&) { + return onValidationFailed(interest.shared_from_this(), + "Cannot decode signature"); + } +} + +void +PibValidator::checkPolicy(const Data& data, + int nSteps, + const OnDataValidated& onValidated, + const OnDataValidationFailed& onValidationFailed, + std::vector>& nextSteps) +{ + // Pib does not express any interest, therefor should not validate any data. + onValidationFailed(data.shared_from_this(), + "PibValidator should not receive data packet"); +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/pib-validator.hpp b/tools/pib/pib-validator.hpp new file mode 100644 index 0000000..9d7a3e1 --- /dev/null +++ b/tools/pib/pib-validator.hpp @@ -0,0 +1,81 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_PIB_VALIDATOR_HPP +#define NDN_PIB_PIB_VALIDATOR_HPP + +#include "pib-db.hpp" +#include "key-cache.hpp" +#include +#include + +namespace ndn { +namespace pib { + + +/* + * @brief The validator to verify the command interests to PIB service + * + * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base + */ +class PibValidator : public Validator +{ + struct UserKeyCache; +public: + explicit + PibValidator(const PibDb& pibDb, + size_t maxCacheSize = 1000); + + ~PibValidator(); + +protected: + virtual void + checkPolicy(const Interest& interest, + int nSteps, + const OnInterestValidated& onValidated, + const OnInterestValidationFailed& onValidationFailed, + std::vector>& nextSteps); + + virtual void + checkPolicy(const Data& data, + int nSteps, + const OnDataValidated& onValidated, + const OnDataValidationFailed& onValidationFailed, + std::vector>& nextSteps); + +private: + + const PibDb& m_db; + + bool m_isMgmtReady; + std::string m_owner; + shared_ptr m_mgmtCert; + + KeyCache m_keyCache; + + util::signal::ScopedConnection m_mgmtChangeConnection; + util::signal::ScopedConnection m_keyDeletedConnection; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_PIB_VALIDATOR_HPP diff --git a/tools/pib/pib.cpp b/tools/pib/pib.cpp new file mode 100644 index 0000000..d5a4e5c --- /dev/null +++ b/tools/pib/pib.cpp @@ -0,0 +1,282 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "pib.hpp" + +#include "encoding/pib-encoding.hpp" +#include +#include +#include +#include + +#include + +namespace ndn { +namespace pib { + +using std::string; +using std::vector; +using std::set; + +const Name Pib::PIB_PREFIX("/localhost/pib"); +const Name Pib::EMPTY_SIGNER_NAME; +const name::Component Pib::MGMT_LABEL("mgmt"); + +// \todo make this a static method in KeyChain +static inline void +signWithDigestSha256(Data& data) +{ + DigestSha256 sig; + data.setSignature(sig); + Block sigValue(tlv::SignatureValue, + crypto::sha256(data.wireEncode().value(), + data.wireEncode().value_size() - + data.getSignature().getValue().size())); + data.setSignatureValue(sigValue); + data.wireEncode(); +} + +Pib::Pib(Face& face, + const std::string& dbDir, + const std::string& tpmLocator, + const std::string& owner) + : m_db(dbDir) + , m_tpm(nullptr) + , m_owner(owner) + , m_validator(m_db) + , m_face(face) + , m_certPublisher(m_face, m_db) + , m_getProcessor(m_db) + , m_defaultProcessor(m_db) + , m_listProcessor(m_db) + , m_updateProcessor(m_db, *this) + , m_deleteProcessor(m_db) +{ + if (!m_db.getOwnerName().empty() && m_db.getOwnerName() != owner) + throw Error("owner argument differs from OwnerName in database"); + + if (!m_db.getTpmLocator().empty() && m_db.getTpmLocator() != tpmLocator) + throw Error("tpmLocator argument differs from TpmLocator in database"); + + initializeTpm(tpmLocator); + initializeMgmtCert(); + m_db.setTpmLocator(tpmLocator); + + registerPrefix(); +} + +Pib::~Pib() +{ + m_face.unsetInterestFilter(m_pibMgmtFilterId); + m_face.unsetInterestFilter(m_pibGetFilterId); + m_face.unsetInterestFilter(m_pibDefaultFilterId); + m_face.unsetInterestFilter(m_pibListFilterId); + m_face.unsetInterestFilter(m_pibUpdateFilterId); + m_face.unsetInterestFilter(m_pibDeleteFilterId); + + m_face.unsetInterestFilter(m_pibPrefixId); +} + +void +Pib::setMgmtCert(std::shared_ptr mgmtCert) +{ + if (mgmtCert != nullptr) + m_mgmtCert = mgmtCert; +} + +void +Pib::initializeTpm(const string& tpmLocator) +{ + m_tpm = KeyChain::createTpm(tpmLocator); +} + +void +Pib::initializeMgmtCert() +{ + shared_ptr mgmtCert = m_db.getMgmtCertificate(); + + if (mgmtCert == nullptr || + !m_tpm->doesKeyExistInTpm(mgmtCert->getPublicKeyName(), KEY_CLASS_PRIVATE)) { + // If mgmt cert is set, or corresponding private key of the current mgmt cert is missing, + // generate new mgmt cert + + // key name: /localhost/pib/[UserName]/mgmt/dsk-... + Name mgmtKeyName = PIB_PREFIX; + mgmtKeyName.append(m_owner).append(MGMT_LABEL); + std::ostringstream oss; + oss << "dsk-" << time::toUnixTimestamp(time::system_clock::now()).count(); + mgmtKeyName.append(oss.str()); + + // self-sign pib root key + m_mgmtCert = prepareCertificate(mgmtKeyName, RsaKeyParams(), + time::system_clock::now(), + time::system_clock::now() + time::days(7300)); + + // update management certificate in database + m_db.updateMgmtCertificate(*m_mgmtCert); + } + else + m_mgmtCert = mgmtCert; +} + +shared_ptr +Pib::prepareCertificate(const Name& keyName, const KeyParams& keyParams, + const time::system_clock::TimePoint& notBefore, + const time::system_clock::TimePoint& notAfter, + const Name& signerName) +{ + // Generate mgmt key + m_tpm->generateKeyPairInTpm(keyName, keyParams); + shared_ptr publicKey = m_tpm->getPublicKeyFromTpm(keyName); + + // Set mgmt cert + auto certificate = make_shared(); + Name certName = keyName.getPrefix(-1); + certName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion(); + certificate->setName(certName); + certificate->setNotBefore(notBefore); + certificate->setNotAfter(notAfter); + certificate->setPublicKeyInfo(*publicKey); + CertificateSubjectDescription subjectName(oid::ATTRIBUTE_NAME, keyName.getPrefix(-1).toUri()); + certificate->addSubjectDescription(subjectName); + certificate->encode(); + + + Name signingKeyName; + KeyLocator keyLocator; + if (signerName == EMPTY_SIGNER_NAME) { + // Self-sign mgmt cert + keyLocator = KeyLocator(certificate->getName().getPrefix(-1)); + signingKeyName = keyName; + } + else { + keyLocator = KeyLocator(signerName.getPrefix(-1)); + signingKeyName = IdentityCertificate::certificateNameToPublicKeyName(signerName); + } + + SignatureSha256WithRsa signature(keyLocator); + certificate->setSignature(signature); + EncodingBuffer encoder; + certificate->wireEncode(encoder, true); + Block signatureValue = m_tpm->signInTpm(encoder.buf(), encoder.size(), + signingKeyName, DIGEST_ALGORITHM_SHA256); + certificate->wireEncode(encoder, signatureValue); + + return certificate; +} + +void +Pib::registerPrefix() +{ + // register pib prefix + Name pibPrefix = PIB_PREFIX; + pibPrefix.append(m_owner); + m_pibPrefixId = + m_face.registerPrefix(pibPrefix, + [] (const Name& name) {}, + [] (const Name& name, const string& msg) { + throw Error("cannot register pib prefix"); + }); + + // set interest filter for management certificate + m_pibMgmtFilterId = + m_face.setInterestFilter(Name(pibPrefix).append(MGMT_LABEL), + [this] (const InterestFilter&, const Interest& interest) { + if (m_mgmtCert != nullptr) { + m_face.put(*m_mgmtCert); + } + }); + + // set interest filter for get command + m_pibGetFilterId = registerProcessor(Name(pibPrefix).append(GetParam::VERB), m_getProcessor); + + // set interest filter for default command + m_pibDefaultFilterId = registerProcessor(Name(pibPrefix).append(DefaultParam::VERB), + m_defaultProcessor); + + // set interest filter for list command + m_pibListFilterId = registerProcessor(Name(pibPrefix).append(ListParam::VERB), + m_listProcessor); + + // set interest filter for update command + m_pibUpdateFilterId = registerSignedCommandProcessor(Name(pibPrefix).append(UpdateParam::VERB), + m_updateProcessor); + + // set interest filter for delete command + m_pibDeleteFilterId = registerSignedCommandProcessor(Name(pibPrefix).append(DeleteParam::VERB), + m_deleteProcessor); +} + +template +const InterestFilterId* +Pib::registerProcessor(const Name& prefix, Processor& process) +{ + return m_face.setInterestFilter(prefix, + [&] (const InterestFilter&, const Interest& interest) { + processCommand(process, interest); + }); +} + +template +const InterestFilterId* +Pib::registerSignedCommandProcessor(const Name& prefix, Processor& process) +{ + const InterestFilterId* filterId = + m_face.setInterestFilter(prefix, + [&] (const InterestFilter&, const Interest& interest) { + m_validator.validate(interest, + [&] (const shared_ptr& interest) { + processCommand(process, *interest); + }, + [] (const shared_ptr&, const string&) {}); + }); + + return filterId; +} + +template +void +Pib::processCommand(Processor& process, const Interest& interest) +{ + std::pair result = process(interest); + if (result.first) + returnResult(Name(interest.getName()).appendVersion(), + result.second); +} + +void +Pib::returnResult(const Name& dataName, const Block& content) +{ + shared_ptr data = make_shared(dataName); + + data->setFreshnessPeriod(time::milliseconds::zero()); + data->setContent(content); + signWithDigestSha256(*data); + + // Put data into response cache + m_responseCache.insert(*data); + + // Put data to face. + m_face.put(*data); +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/pib.hpp b/tools/pib/pib.hpp new file mode 100644 index 0000000..3128191 --- /dev/null +++ b/tools/pib/pib.hpp @@ -0,0 +1,178 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_PIB_HPP +#define NDN_PIB_PIB_HPP + +#include "pib-db.hpp" +#include "pib-validator.hpp" +#include "cert-publisher.hpp" + +#include +#include + +#include "get-query-processor.hpp" +#include "default-query-processor.hpp" +#include "list-query-processor.hpp" +#include "update-query-processor.hpp" +#include "delete-query-processor.hpp" + +#include + +namespace ndn { +namespace pib { + +/// @brief implements the PIB service +class Pib : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + explicit + Error(const std::string& what) + : std::runtime_error(what) + { + } + }; + + /** + * @brief Constructor + * + * @param face The face pib used to receive queries and serve certificates. + * @param dbDir Absolute path to the directory of the pib database. + * @param tpmLocator URI to locate the TPM for pib service. + * @param owner Owner of the pib database. + */ + Pib(Face& face, + const std::string& dbDir, + const std::string& tpmLocator, + const std::string& owner); + + ~Pib(); + + void + setMgmtCert(std::shared_ptr mgmtCert); + +PUBLIC_WITH_TESTS_ELSE_PROTECTED: + PibDb& + getDb() + { + return m_db; + } + + SecTpm& + getTpm() + { + return *m_tpm; + } + + util::InMemoryStoragePersistent& + getResponseCache() + { + return m_responseCache; + } + + const std::string& + getOwner() const + { + return m_owner; + } + + const IdentityCertificate& + getMgmtCert() const + { + BOOST_ASSERT(m_mgmtCert != nullptr); + return *m_mgmtCert; + } + +private: // initialization + /// @brief initialize the PIB's own TPM. + void + initializeTpm(const std::string& tpmLocator); + + /// @brief initialize management certificate + void + initializeMgmtCert(); + + std::shared_ptr + prepareCertificate(const Name& keyName, const KeyParams& keyParams, + const time::system_clock::TimePoint& notBefore, + const time::system_clock::TimePoint& notAfter, + const Name& signerName = EMPTY_SIGNER_NAME); + + /// @brief register prefix for PIB query and management certificate + void + registerPrefix(); + + template + const InterestFilterId* + registerProcessor(const Name& prefix, Processor& process); + + template + const InterestFilterId* + registerSignedCommandProcessor(const Name& prefix, Processor& process); + + template + void + processCommand(Processor& process, const Interest& interest); + + void + returnResult(const Name& dataName, const Block& content); + +private: + + static const Name EMPTY_SIGNER_NAME; + static const Name PIB_PREFIX; + static const name::Component MGMT_LABEL; + + PibDb m_db; + std::unique_ptr m_tpm; + std::string m_owner; + std::shared_ptr m_mgmtCert; + + PibValidator m_validator; + + Face& m_face; + CertPublisher m_certPublisher; + util::InMemoryStoragePersistent m_responseCache; + + const RegisteredPrefixId* m_pibPrefixId; + const InterestFilterId* m_pibMgmtFilterId; + const InterestFilterId* m_pibGetFilterId; + const InterestFilterId* m_pibDefaultFilterId; + const InterestFilterId* m_pibListFilterId; + const InterestFilterId* m_pibUpdateFilterId; + const InterestFilterId* m_pibDeleteFilterId; + +PUBLIC_WITH_TESTS_ELSE_PRIVATE: + + GetQueryProcessor m_getProcessor; + DefaultQueryProcessor m_defaultProcessor; + ListQueryProcessor m_listProcessor; + UpdateQueryProcessor m_updateProcessor; + DeleteQueryProcessor m_deleteProcessor; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_PIB_HPP diff --git a/tools/pib/response-cache.cpp b/tools/pib/response-cache.cpp new file mode 100644 index 0000000..57c211e --- /dev/null +++ b/tools/pib/response-cache.cpp @@ -0,0 +1,73 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "response-cache.hpp" + +namespace ndn { +namespace pib { + +using std::map; + +ResponseCache::ResponseCache() +{ +} + + +shared_ptr +ResponseCache::find(const Name& dataName, bool hasVersion) const +{ + if (!hasVersion) { + Storage::const_iterator it = m_storage.find(dataName); + if (it != m_storage.end()) + return it->second; + else + return shared_ptr(); + } + else { + Storage::const_iterator it = m_storage.find(dataName.getPrefix(-1)); + if (it != m_storage.end() && it->second->getName() == dataName) + return it->second; + else + return shared_ptr(); + } +} + +void +ResponseCache::insert(const Data& data) +{ + data.getName().at(-1).toVersion(); // ensures last component is version + m_storage[data.getName().getPrefix(-1)] = data.shared_from_this(); +} + +void +ResponseCache::erase(const Name& dataNameWithoutVersion) +{ + m_storage.erase(dataNameWithoutVersion); +} + +void +ResponseCache::clear() +{ + m_storage.clear(); +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/response-cache.hpp b/tools/pib/response-cache.hpp new file mode 100644 index 0000000..40edd04 --- /dev/null +++ b/tools/pib/response-cache.hpp @@ -0,0 +1,74 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_RESPONSE_CACHE_HPP +#define NDN_PIB_RESPONSE_CACHE_HPP + +#include +#include + + +namespace ndn { +namespace pib { + +/** + * @brief ResponseCache is an abstraction of a cache of response made before + * + * ResponseCache is used to reduce the number of PibDb lookup and Data signing + * operations. + * + * Eventually, it should be replaced by a formal application level cache. This + * one is only a temporary module and is used for test. + */ +class ResponseCache : noncopyable +{ +public: + ResponseCache(); + + shared_ptr + find(const Name& dataName, bool hasVersion = false) const; + + /** + * @brief Insert a data packet into cache + * + * Name of the inserted data must end with a version component + * + * @param data Data to insert. It MUST have been created with make_shared. + */ + void + insert(const Data& data); + + void + erase(const Name& dataNameWithoutVersion); + + void + clear(); + +private: + typedef std::map > Storage; + + Storage m_storage; +}; + +} // namespace ndn +} // namespace pib + +#endif // NDN_PIB_RESPONSE_CACHE_HPP diff --git a/tools/pib/update-query-processor.cpp b/tools/pib/update-query-processor.cpp new file mode 100644 index 0000000..4ab853d --- /dev/null +++ b/tools/pib/update-query-processor.cpp @@ -0,0 +1,267 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "update-query-processor.hpp" +#include "encoding/pib-encoding.hpp" +#include "pib.hpp" + +#include + +namespace ndn { +namespace pib { + +using std::string; + +const size_t UpdateQueryProcessor::UPDATE_QUERY_LENGTH = 9; +const Name UpdateQueryProcessor::PIB_PREFIX("/localhost/pib"); + +UpdateQueryProcessor::UpdateQueryProcessor(PibDb& db, Pib& pib) + : m_db(db) + , m_pib(pib) +{ +} + +std::pair +UpdateQueryProcessor::operator()(const Interest& interest) +{ + const Name& interestName = interest.getName(); + + // handle pib query: /localhost/pib/[UserName]/update/param/ + if (interestName.size() != UPDATE_QUERY_LENGTH) { + // malformed interest, discard + return std::make_pair(false, Block()); + } + + try { + UpdateParam param; + param.wireDecode(interestName.get(OFFSET_PARAM).blockFromValue()); + + SignatureInfo sigInfo; + sigInfo.wireDecode(interestName.get(OFFSET_SIG_INFO).blockFromValue()); + + // sigInfo must have KeyLocator.Name if the interest passed validation. + Name signerName; + signerName = sigInfo.getKeyLocator().getName(); + + switch (param.getEntityType()) { + case tlv::pib::User: + return processUpdateUserQuery(param, signerName); + case tlv::pib::Identity: + return processUpdateIdQuery(param, signerName); + case tlv::pib::PublicKey: + return processUpdateKeyQuery(param, signerName); + case tlv::pib::Certificate: + return processUpdateCertQuery(param, signerName); + default: + { + PibError error(ERR_WRONG_PARAM, + "entity type is not supported: " + + boost::lexical_cast(param.getEntityType())); + return std::make_pair(true, error.wireEncode()); + } + } + } + catch (const PibDb::Error& e) { + PibError error(ERR_INTERNAL_ERROR, e.what()); + return std::make_pair(true, error.wireEncode()); + } + catch (const tlv::Error& e) { + PibError error(ERR_WRONG_PARAM, "error in parsing param: " + string(e.what())); + return std::make_pair(true, error.wireEncode()); + } +} + +std::pair +UpdateQueryProcessor::processUpdateUserQuery(const UpdateParam& param, const Name& signerName) +{ + Name expectedId = m_db.getMgmtCertificate()->getPublicKeyName().getPrefix(-1); + Name targetId = param.getUser().getMgmtCert().getPublicKeyName().getPrefix(-1); + Name signerId = IdentityCertificate::certificateNameToPublicKeyName(signerName).getPrefix(-1); + + if (expectedId == targetId && expectedId == signerId) { + m_db.updateMgmtCertificate(param.getUser().getMgmtCert()); + m_pib.setMgmtCert(make_shared(param.getUser().getMgmtCert())); + return std::make_pair(true, PibError(ERR_SUCCESS).wireEncode()); + } + + PibError error(ERR_WRONG_PARAM, "not allowed to update user"); + return std::make_pair(true, error.wireEncode()); +} + +std::pair +UpdateQueryProcessor::processUpdateIdQuery(const UpdateParam& param, const Name& signerName) +{ + const Name& identity = param.getIdentity().getIdentity(); + if (!isUpdateAllowed(TYPE_ID, identity, signerName, param.getDefaultOpt())) { + PibError error(ERR_WRONG_SIGNER, "signer is not trusted for this command"); + return std::make_pair(true, error.wireEncode()); + } + + // add the identity + m_db.addIdentity(identity); + + // set the identity as user default if it is requested. + const pib::DefaultOpt& defaultOpt = param.getDefaultOpt(); + if (DEFAULT_OPT_USER_MASK & defaultOpt) { + m_db.setDefaultIdentity(identity); + } + + return std::make_pair(true, PibError(ERR_SUCCESS).wireEncode()); +} + +std::pair +UpdateQueryProcessor::processUpdateKeyQuery(const UpdateParam& param, const Name& signerName) +{ + const Name& keyName = param.getPublicKey().getKeyName(); + if (!isUpdateAllowed(TYPE_KEY, keyName, signerName, param.getDefaultOpt())) { + PibError error(ERR_WRONG_SIGNER, "signer is not trusted for this command"); + return std::make_pair(true, error.wireEncode()); + } + + Name identity = keyName.getPrefix(-1); + + // add the key + m_db.addKey(keyName, param.getPublicKey().getPublicKey()); + + const pib::DefaultOpt& defaultOpt = param.getDefaultOpt(); + if (DEFAULT_OPT_ID_MASK & defaultOpt) // set the key as identity default if requested. + m_db.setDefaultKeyNameOfIdentity(keyName); + if (DEFAULT_OPT_USER_MASK & defaultOpt) // set the identity as user default if requested. + m_db.setDefaultIdentity(identity); + + return std::make_pair(true, PibError(ERR_SUCCESS).wireEncode()); +} + +std::pair +UpdateQueryProcessor::processUpdateCertQuery(const UpdateParam& param, const Name& signerName) +{ + const IdentityCertificate& cert = param.getCertificate().getCertificate(); + const Name& certName = cert.getName(); + if (!isUpdateAllowed(TYPE_CERT, certName, signerName, param.getDefaultOpt())) { + PibError error(ERR_WRONG_SIGNER, "signer is not trusted for this command"); + return std::make_pair(true, error.wireEncode()); + } + + const Name& keyName = cert.getPublicKeyName(); + Name identity = keyName.getPrefix(-1); + + // add certificate + m_db.addCertificate(cert); + + const pib::DefaultOpt& defaultOpt = param.getDefaultOpt(); + if (DEFAULT_OPT_KEY_MASK & defaultOpt) // set the cert as key default if requested. + m_db.setDefaultCertNameOfKey(certName); + if (DEFAULT_OPT_ID_MASK & defaultOpt) // set the key as identity default if requested. + m_db.setDefaultKeyNameOfIdentity(keyName); + if (DEFAULT_OPT_USER_MASK & defaultOpt) // set the identity as user default if requested. + m_db.setDefaultIdentity(identity); + + return std::make_pair(true, PibError(ERR_SUCCESS).wireEncode()); +} + +bool +UpdateQueryProcessor::isUpdateAllowed(const pib::Type targetType, + const Name& targetName, + const Name& signer, + const pib::DefaultOpt defaultOpt) const +{ + // Any identity with prefix /localhost/pib is reserved. Any operation with a targetName under + // that prefix will be rejected. + if (PIB_PREFIX.isPrefixOf(targetName)) + return false; + + // A request is wrong if + // 1) it wants to change the default setting of an identity, but the target is not key nor cert + // 2) it wants to change the default setting of a key, but the target is not cert + if ((defaultOpt == DEFAULT_OPT_ID && (targetType != TYPE_KEY && targetType != TYPE_CERT)) || + (defaultOpt == DEFAULT_OPT_KEY && targetType != TYPE_CERT)) + return false; + + + // Rules for other items: + // + // signer | adding privilege | default setting privilege + // ================+==========================+============================================ + // local mgmt key | any id, key, and cert | the default id, + // | | the default key of any id, + // | | the default cert of any key of any id + // ----------------+--------------------------+-------------------------------------------- + // default key of | any id, key, and cert | the default key of the id and its sub ids, + // an id | under the id's namespace | the default cert of any key of the id + // | | and its sub ids + // ----------------+--------------------------+-------------------------------------------- + // non-default key | any cert of the key | the default cert of the key + // of an id + + const Name& signerKeyName = IdentityCertificate::certificateNameToPublicKeyName(signer); + const Name& signerId = signerKeyName.getPrefix(-1); + + bool hasSignerDefaultKey = true; + Name signerDefaultKeyName; + try { + signerDefaultKeyName = m_db.getDefaultKeyNameOfIdentity(signerId); + } + catch (PibDb::Error&) { + hasSignerDefaultKey = false; + } + + Name mgmtCertName; + try { + mgmtCertName = m_db.getMgmtCertificate()->getName().getPrefix(-1); + } + catch (PibDb::Error&) { + return false; + } + + if (signer == mgmtCertName) { + // signer is current management key, anything is allowed. + return true; + } + else if (hasSignerDefaultKey && signerDefaultKeyName == signerKeyName) { + // signer is an identity's default key + if (!signerId.isPrefixOf(targetName)) + return false; + + // check default setting + // user default setting is not allowed + if (defaultOpt == DEFAULT_OPT_USER) + return false; + else + return true; + } + else { + // non-default key + if (targetType != TYPE_CERT) + return false; + + // check if it is for the key's cert + if (IdentityCertificate::certificateNameToPublicKeyName(targetName) != signerKeyName) + return false; + + if (defaultOpt == DEFAULT_OPT_USER || defaultOpt == DEFAULT_OPT_ID) + return false; + else + return true; + } +} + +} // namespace pib +} // namespace ndn diff --git a/tools/pib/update-query-processor.hpp b/tools/pib/update-query-processor.hpp new file mode 100644 index 0000000..6c0655b --- /dev/null +++ b/tools/pib/update-query-processor.hpp @@ -0,0 +1,98 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2015 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 + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_PIB_UPDATE_QUERY_PROCESSOR_HPP +#define NDN_PIB_UPDATE_QUERY_PROCESSOR_HPP + +#include "pib-db.hpp" +#include "encoding/update-param.hpp" +#include +#include + +namespace ndn { +namespace pib { + +class Pib; + +/// @brief Processing unit for PIB update query +class UpdateQueryProcessor : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + explicit + Error(const std::string& what) + : std::runtime_error(what) + { + } + }; + + /** + * @brief Constructor + * + * @param db The pib database. + */ + UpdateQueryProcessor(PibDb& db, Pib& pib); + + std::pair + operator()(const Interest& interest); + +PUBLIC_WITH_TESTS_ELSE_PRIVATE: + /** + * @brief Determine if an update command is allowed. + * + * @param targetType The type of the target that will be updated. + * @param targetName The name of the target that will be updated. + * @param signer The name of the command signer. + * @param defaultOpt The default settings that is requested to update. + */ + bool + isUpdateAllowed(const pib::Type targetType, + const Name& targetName, + const Name& signer, + const pib::DefaultOpt defaultOpt) const; + +private: + std::pair + processUpdateUserQuery(const UpdateParam& param, const Name& signerName); + + std::pair + processUpdateIdQuery(const UpdateParam& param, const Name& signerName); + + std::pair + processUpdateKeyQuery(const UpdateParam& param, const Name& signerName); + + std::pair + processUpdateCertQuery(const UpdateParam& param, const Name& signerName); + +private: + static const size_t UPDATE_QUERY_LENGTH; + static const Name PIB_PREFIX; + + PibDb& m_db; + Pib& m_pib; +}; + +} // namespace pib +} // namespace ndn + +#endif // NDN_PIB_UPDATE_QUERY_PROCESSOR_HPP diff --git a/tools/pib/wscript b/tools/pib/wscript new file mode 100644 index 0000000..7a40d5a --- /dev/null +++ b/tools/pib/wscript @@ -0,0 +1,19 @@ +# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +top = '../..' + +def build(bld): + + bld(features=['cxx'], + name="pib-objects", + target="pib-objects", + source=bld.path.ant_glob('**/*.cpp', excl=['ndn-pib.cpp']), + use='core-objects', + install_path=None, + ) + + + bld(features=['cxx', 'cxxprogram'], + target='ndn-pib', + source='ndn-pib.cpp', + use='pib-objects', + )