build: Reviving support for precompiled headers
This commit also includes an update of ./waf, which has several
improvements. In particular, clang++ is now default compiler on OSX
platform.
This commit also includes reorganization of tests. All unit tests are
now under tests/unit-tests and integrated tests are under
tests/integrated. This change allows small compilation optimization,
partially related to precompiled headers.
Change-Id: I4c171c04d18e9cb83e461264a35b9ed85ea4d50e
diff --git a/tests/unit-tests/security/config-file-empty-home/.ndn/client.conf b/tests/unit-tests/security/config-file-empty-home/.ndn/client.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/unit-tests/security/config-file-empty-home/.ndn/client.conf
diff --git a/tests/unit-tests/security/config-file-home/.ndn/client.conf b/tests/unit-tests/security/config-file-home/.ndn/client.conf
new file mode 100644
index 0000000..cc05409
--- /dev/null
+++ b/tests/unit-tests/security/config-file-home/.ndn/client.conf
@@ -0,0 +1,2 @@
+pib=sqlite3
+tpm=file
\ No newline at end of file
diff --git a/tests/unit-tests/security/config-file-malformed-home/.ndn/client.conf b/tests/unit-tests/security/config-file-malformed-home/.ndn/client.conf
new file mode 100644
index 0000000..4ed6728
--- /dev/null
+++ b/tests/unit-tests/security/config-file-malformed-home/.ndn/client.conf
@@ -0,0 +1,2 @@
+pib=lord
+tpm=ring
diff --git a/tests/unit-tests/security/config-file-malformed2-home/.ndn/client.conf b/tests/unit-tests/security/config-file-malformed2-home/.ndn/client.conf
new file mode 100644
index 0000000..3f7795d
--- /dev/null
+++ b/tests/unit-tests/security/config-file-malformed2-home/.ndn/client.conf
@@ -0,0 +1,2 @@
+pib=sqlite3
+tpm=just-wrong
diff --git a/tests/unit-tests/security/identity-fixture.cpp b/tests/unit-tests/security/identity-fixture.cpp
new file mode 100644
index 0000000..31bd3a2
--- /dev/null
+++ b/tests/unit-tests/security/identity-fixture.cpp
@@ -0,0 +1,79 @@
+/* -*- 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/key-chain.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+
+// OSX KeyChain, when used on a headless server,
+// forbids usage of a private key if that key isn't created by the calling process.
+// Therefore, unit testing must create its own key pair.
+
+class IdentityFixture
+{
+public:
+ IdentityFixture()
+ {
+ // save the old default identity
+ try {
+ m_oldDefaultIdentity = m_keyChain.getDefaultIdentity();
+ m_hasOldDefaultIdentity = true;
+ }
+ catch (SecPublicInfo::Error& e) {
+ m_hasOldDefaultIdentity = false;
+ }
+
+ m_newIdentity.set("/ndn-cxx-test-identity");
+ m_newIdentity.appendVersion();
+
+ // create the new identity and self-signed certificate
+ m_keyChain.createIdentity(m_newIdentity);
+
+ // set the new identity as default identity,
+ // and the corresponding certificate becomes the default certificate
+ m_keyChain.setDefaultIdentity(m_newIdentity);
+ }
+
+ ~IdentityFixture()
+ {
+ // recover the old default setting
+ if (m_hasOldDefaultIdentity) {
+ m_keyChain.setDefaultIdentity(m_oldDefaultIdentity);
+ }
+
+ // remove the temporarily created identity and certificates
+ // XXX This has no effect if oldDefaultIdentity doesn't exist.
+ // newIdentity would be kept as default.
+ m_keyChain.deleteIdentity(m_newIdentity);
+ }
+
+private:
+ KeyChain m_keyChain;
+ bool m_hasOldDefaultIdentity;
+ Name m_oldDefaultIdentity;
+ Name m_newIdentity;
+};
+
+BOOST_GLOBAL_FIXTURE(IdentityFixture)
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-certificate-cache.cpp b/tests/unit-tests/security/test-certificate-cache.cpp
new file mode 100644
index 0000000..2934a47
--- /dev/null
+++ b/tests/unit-tests/security/test-certificate-cache.cpp
@@ -0,0 +1,99 @@
+/* -*- 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/certificate-cache-ttl.hpp"
+#include "face.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestCertificateCache)
+
+void
+getCertificateTtl(shared_ptr<CertificateCacheTtl> cache, const Name &name, bool cached)
+{
+ BOOST_CHECK_EQUAL(static_cast<bool>(cache->getCertificate(name)), cached);
+}
+
+void
+checkSize(shared_ptr<CertificateCacheTtl> cache, size_t size)
+{
+ BOOST_CHECK_EQUAL(cache->getSize(), size);
+}
+
+
+BOOST_AUTO_TEST_CASE (Ttl)
+{
+ boost::asio::io_service io;
+ shared_ptr<CertificateCacheTtl> cache =
+ make_shared<CertificateCacheTtl>(ref(io), time::seconds(1));
+ Scheduler scheduler(io);
+
+ shared_ptr<IdentityCertificate> cert1 = make_shared<IdentityCertificate>();
+ Name certName1("/tmp/KEY/ksk-1/ID-CERT/1");
+ cert1->setName(certName1);
+ cert1->setFreshnessPeriod(time::milliseconds(500));
+ shared_ptr<IdentityCertificate> cert2 = make_shared<IdentityCertificate>();
+ Name certName2("/tmp/KEY/ksk-2/ID-CERT/2");
+ cert2->setName(certName2);
+ cert2->setFreshnessPeriod(time::milliseconds(1000));
+
+ Name name1 = certName1.getPrefix(-1);
+ Name name2 = certName2.getPrefix(-1);
+
+ cache->insertCertificate(cert1);
+ cache->insertCertificate(cert2);
+
+ scheduler.scheduleEvent(time::milliseconds(200), bind(&checkSize, cache, 2));
+ scheduler.scheduleEvent(time::milliseconds(200), bind(&getCertificateTtl, cache, name1, true));
+ scheduler.scheduleEvent(time::milliseconds(200), bind(&getCertificateTtl, cache, name2, true));
+
+ // cert1 should removed from the cache
+ scheduler.scheduleEvent(time::milliseconds(900), bind(&checkSize, cache, 1));
+ scheduler.scheduleEvent(time::milliseconds(900), bind(&getCertificateTtl, cache, name1, false));
+ scheduler.scheduleEvent(time::milliseconds(900), bind(&getCertificateTtl, cache, name2, true));
+
+ // Refresh certificate in cache
+ scheduler.scheduleEvent(time::milliseconds(900), bind(&CertificateCache::insertCertificate,
+ cache, cert2));
+ scheduler.scheduleEvent(time::milliseconds(1500), bind(&getCertificateTtl, cache, name2, true));
+ scheduler.scheduleEvent(time::milliseconds(2500), bind(&getCertificateTtl, cache, name2, false));
+
+ // Purge
+ scheduler.scheduleEvent(time::milliseconds(3000), bind(&CertificateCache::insertCertificate,
+ cache, cert1));
+ scheduler.scheduleEvent(time::milliseconds(3000), bind(&CertificateCache::insertCertificate,
+ cache, cert2));
+ scheduler.scheduleEvent(time::milliseconds(3100), bind(&checkSize, cache, 2));
+ scheduler.scheduleEvent(time::milliseconds(3200), bind(&CertificateCache::reset, cache));
+ scheduler.scheduleEvent(time::milliseconds(3300), bind(&getCertificateTtl, cache, name1, false));
+ scheduler.scheduleEvent(time::milliseconds(3300), bind(&getCertificateTtl, cache, name2, false));
+ scheduler.scheduleEvent(time::milliseconds(3400), bind(&checkSize, cache, 0));
+
+ io.run();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-encode-decode-certificate.cpp b/tests/unit-tests/security/test-encode-decode-certificate.cpp
new file mode 100644
index 0000000..2577509
--- /dev/null
+++ b/tests/unit-tests/security/test-encode-decode-certificate.cpp
@@ -0,0 +1,199 @@
+/* -*- 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/certificate.hpp"
+#include "security/public-key.hpp"
+
+#include "security/cryptopp.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+using namespace CryptoPP;
+
+BOOST_AUTO_TEST_SUITE(SecurityTestCertificate)
+
+const uint8_t PUBLIC_KEY[] = {
+0x30, 0x81, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x01, 0x05, 0x00, 0x03, 0x81, 0x8b, 0x00, 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e,
+0x06, 0x3e, 0x47, 0x85, 0xb2, 0x34, 0x37, 0xaa, 0x85, 0x47, 0xac, 0x03, 0x24, 0x83, 0xb5,
+0x9c, 0xa8, 0x05, 0x3a, 0x24, 0x1e, 0xeb, 0x89, 0x01, 0xbb, 0xe9, 0x9b, 0xb2, 0xc3, 0x22,
+0xac, 0x68, 0xe3, 0xf0, 0x6c, 0x02, 0xce, 0x68, 0xa6, 0xc4, 0xd0, 0xa7, 0x06, 0x90, 0x9c,
+0xaa, 0x1b, 0x08, 0x1d, 0x8b, 0x43, 0x9a, 0x33, 0x67, 0x44, 0x6d, 0x21, 0xa3, 0x1b, 0x88,
+0x9a, 0x97, 0x5e, 0x59, 0xc4, 0x15, 0x0b, 0xd9, 0x2c, 0xbd, 0x51, 0x07, 0x61, 0x82, 0xad,
+0xc1, 0xb8, 0xd7, 0xbf, 0x9b, 0xcf, 0x7d, 0x24, 0xc2, 0x63, 0xf3, 0x97, 0x17, 0xeb, 0xfe,
+0x62, 0x25, 0xba, 0x5b, 0x4d, 0x8a, 0xc2, 0x7a, 0xbd, 0x43, 0x8a, 0x8f, 0xb8, 0xf2, 0xf1,
+0xc5, 0x6a, 0x30, 0xd3, 0x50, 0x8c, 0xc8, 0x9a, 0xdf, 0xef, 0xed, 0x35, 0xe7, 0x7a, 0x62,
+0xea, 0x76, 0x7c, 0xbb, 0x08, 0x26, 0xc7, 0x02, 0x01, 0x11
+};
+
+const uint8_t CERT[] = {
+0x30, 0x81, 0xff, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x33, 0x31, 0x32, 0x32, 0x36,
+0x32, 0x33, 0x32, 0x32, 0x35, 0x34, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x33, 0x31, 0x32,
+0x32, 0x36, 0x32, 0x33, 0x32, 0x32, 0x35, 0x34, 0x5a, 0x30, 0x12, 0x30, 0x10, 0x06, 0x03,
+0x55, 0x04, 0x29, 0x13, 0x09, 0x54, 0x45, 0x53, 0x54, 0x20, 0x4e, 0x41, 0x4d, 0x45, 0x30,
+0x81, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+0x05, 0x00, 0x03, 0x81, 0x8b, 0x00, 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x06,
+0x3e, 0x47, 0x85, 0xb2, 0x34, 0x37, 0xaa, 0x85, 0x47, 0xac, 0x03, 0x24, 0x83, 0xb5, 0x9c,
+0xa8, 0x05, 0x3a, 0x24, 0x1e, 0xeb, 0x89, 0x01, 0xbb, 0xe9, 0x9b, 0xb2, 0xc3, 0x22, 0xac,
+0x68, 0xe3, 0xf0, 0x6c, 0x02, 0xce, 0x68, 0xa6, 0xc4, 0xd0, 0xa7, 0x06, 0x90, 0x9c, 0xaa,
+0x1b, 0x08, 0x1d, 0x8b, 0x43, 0x9a, 0x33, 0x67, 0x44, 0x6d, 0x21, 0xa3, 0x1b, 0x88, 0x9a,
+0x97, 0x5e, 0x59, 0xc4, 0x15, 0x0b, 0xd9, 0x2c, 0xbd, 0x51, 0x07, 0x61, 0x82, 0xad, 0xc1,
+0xb8, 0xd7, 0xbf, 0x9b, 0xcf, 0x7d, 0x24, 0xc2, 0x63, 0xf3, 0x97, 0x17, 0xeb, 0xfe, 0x62,
+0x25, 0xba, 0x5b, 0x4d, 0x8a, 0xc2, 0x7a, 0xbd, 0x43, 0x8a, 0x8f, 0xb8, 0xf2, 0xf1, 0xc5,
+0x6a, 0x30, 0xd3, 0x50, 0x8c, 0xc8, 0x9a, 0xdf, 0xef, 0xed, 0x35, 0xe7, 0x7a, 0x62, 0xea,
+0x76, 0x7c, 0xbb, 0x08, 0x26, 0xc7, 0x02, 0x01, 0x11, 0x30, 0x25, 0x30, 0x23, 0x06, 0x06,
+0x2b, 0x06, 0x01, 0x05, 0x20, 0x01, 0x01, 0x01, 0xff, 0x04, 0x16, 0x30, 0x14, 0x04, 0x0c,
+0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2f, 0x6b, 0x69, 0x74, 0x74, 0x79, 0x02, 0x01, 0x00,
+0x02, 0x01, 0x0a
+};
+
+const std::string CERT_INFO = "Certificate name:\n"
+ " /\n"
+ "Validity:\n"
+ " NotBefore: 20131226T232254\n"
+ " NotAfter: 20131226T232254\n"
+ "Subject Description:\n"
+ " 2.5.4.41: TEST NAME\n"
+ "Public key bits:\n"
+ "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCeBj5HhbI0N6qFR6wDJIO1nKgF\n"
+ "OiQe64kBu+mbssMirGjj8GwCzmimxNCnBpCcqhsIHYtDmjNnRG0hoxuImpdeWcQV\n"
+ "C9ksvVEHYYKtwbjXv5vPfSTCY/OXF+v+YiW6W02Kwnq9Q4qPuPLxxWow01CMyJrf\n"
+ "7+0153pi6nZ8uwgmxwIB\n";
+
+BOOST_AUTO_TEST_CASE(Encode)
+{
+ ndn::Certificate certificate;
+
+ // validity
+ // not before 12/26/2013 @ 11:22pm
+ certificate.setNotBefore(time::fromUnixTimestamp(time::milliseconds(1388100174000LL)));
+ // not after 12/26/2013 @ 11:22pm
+ certificate.setNotAfter(time::fromUnixTimestamp(time::milliseconds(1388100174000LL)));
+
+ // subject
+ certificate.addSubjectDescription(CertificateSubjectDescription("2.5.4.41", "TEST NAME"));
+
+ // publicKeyInfo
+ ndn::PublicKey key(PUBLIC_KEY, sizeof(PUBLIC_KEY));
+ certificate.setPublicKeyInfo(key);
+
+ // extensions
+ BOOST_REQUIRE_NO_THROW({
+ std::string extenstionValue;
+ StringSink sink(extenstionValue);
+ DERSequenceEncoder seq(sink);
+ {
+ std::string name("/hello/kitty");
+ DEREncodeOctetString(seq, reinterpret_cast<const uint8_t*>(name.c_str()), name.size());
+ // trustClass
+ DEREncodeUnsigned<uint32_t>(seq, 0);
+ // trustLevel
+ DEREncodeUnsigned<uint32_t>(seq, 10);
+ }
+ seq.MessageEnd();
+
+ certificate.addExtension(CertificateExtension("1.3.6.1.5.32.1", true,
+ reinterpret_cast<const uint8_t*>(extenstionValue.c_str()),
+ extenstionValue.size()));
+ });
+ // RSA::PublicKey p;
+ // StringSource source(T, sizeof(T), true);
+ // p.Load(source);
+
+ BOOST_REQUIRE_NO_THROW(certificate.encode());
+
+ // ofstream of("cert.out");
+ // of.write((const char*certificate.getContent().value(), certificate.getContent().value_size());
+
+ // const Block &wire = i.wireEncode();
+ BOOST_REQUIRE_EQUAL_COLLECTIONS(CERT, CERT+sizeof(CERT),
+ certificate.getContent().value_begin(),
+ certificate.getContent().value_end());
+
+ std::ostringstream os;
+ os << certificate << std::endl;
+ std::string info(os.str());
+
+ BOOST_CHECK_EQUAL(CERT_INFO, info);
+}
+
+const unsigned char REAL_CERT[] = {
+0x30, 0x82, 0x01, 0x63, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x33, 0x31, 0x31, 0x30,
+0x31, 0x31, 0x37, 0x31, 0x31, 0x32, 0x32, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x34, 0x31,
+0x31, 0x30, 0x31, 0x31, 0x37, 0x31, 0x31, 0x32, 0x32, 0x5a, 0x30, 0x19, 0x30, 0x17, 0x06,
+0x03, 0x55, 0x04, 0x29, 0x13, 0x10, 0x4e, 0x44, 0x4e, 0x20, 0x54, 0x65, 0x73, 0x74, 0x62,
+0x65, 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x82, 0x01, 0x20, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0d,
+0x00, 0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd3, 0xac, 0x7e, 0x7a, 0x5c,
+0x33, 0x58, 0x21, 0xda, 0xe0, 0x8d, 0xdb, 0xca, 0xb6, 0x02, 0x30, 0x02, 0x15, 0xc5, 0x0a,
+0x51, 0x54, 0xbb, 0x8e, 0x5e, 0x9d, 0x21, 0xf8, 0x14, 0xbe, 0xe4, 0x63, 0x60, 0x31, 0x53,
+0xe2, 0xef, 0xee, 0x34, 0xa3, 0x8c, 0xd2, 0x24, 0x6f, 0xa4, 0x89, 0x4f, 0x02, 0x20, 0x7d,
+0x66, 0xb6, 0x3f, 0x11, 0x40, 0x0c, 0xc1, 0x5f, 0xd8, 0x45, 0x23, 0x95, 0x40, 0xc8, 0xe0,
+0xbc, 0x9d, 0x2f, 0x03, 0xf1, 0x83, 0x9f, 0x07, 0x0b, 0x76, 0xc9, 0x10, 0xd9, 0x3e, 0x0b,
+0x75, 0x13, 0x93, 0xe9, 0xc9, 0x85, 0x01, 0x88, 0x36, 0x2e, 0xab, 0xfc, 0xe6, 0x24, 0x32,
+0xfc, 0xc6, 0x3c, 0x40, 0x97, 0x1a, 0xcc, 0xcd, 0x53, 0xaa, 0x0f, 0xfb, 0xa3, 0xfe, 0xf9,
+0x24, 0x70, 0x13, 0x3f, 0x4f, 0x5b, 0x7d, 0x43, 0xaa, 0x75, 0x0a, 0x94, 0x72, 0xab, 0xe1,
+0x8c, 0x45, 0xb5, 0x78, 0x10, 0x01, 0xef, 0x1f, 0xb3, 0x05, 0x6f, 0xa6, 0xc3, 0xac, 0x7f,
+0x6d, 0xf0, 0x31, 0xc4, 0x83, 0xb3, 0x4f, 0x50, 0x26, 0x92, 0x40, 0x1a, 0xdd, 0xec, 0xfb,
+0xcb, 0xef, 0x63, 0xfe, 0x41, 0xd8, 0x8d, 0x1f, 0xdc, 0xec, 0xfc, 0x48, 0x95, 0xcc, 0x09,
+0x1e, 0x30, 0x6e, 0x22, 0x9e, 0x24, 0x97, 0x2e, 0xe6, 0x0c, 0xdf, 0x3d, 0x20, 0x32, 0xaa,
+0x9c, 0xc9, 0x45, 0x14, 0xaf, 0xaa, 0xf5, 0x17, 0xd2, 0x01, 0x98, 0x33, 0xbe, 0x2a, 0x9f,
+0x7b, 0x9d, 0x98, 0x7c, 0x54, 0x22, 0xfe, 0x72, 0x72, 0x04, 0xc3, 0x2c, 0xc0, 0x14, 0x0b,
+0xa9, 0x40, 0x7e, 0x46, 0xa1, 0x75, 0x16, 0x1a, 0x27, 0x9e, 0xf2, 0x82, 0x96, 0xc0, 0x7d,
+0xaf, 0x18, 0x75, 0xfb, 0xbb, 0xab, 0x16, 0x66, 0xc0, 0xa9, 0xd7, 0x93, 0x4c, 0x48, 0x6d,
+0xce, 0x0b, 0x88, 0xd4, 0x21, 0x93, 0x84, 0x89, 0x55, 0x05, 0xd5, 0x02, 0x01, 0x11
+};
+
+const std::string REAL_CERT_INFO = "Certificate name:\n"
+" /tmp\n"
+"Validity:\n"
+" NotBefore: 20131101T171122\n"
+" NotAfter: 20141101T171122\n"
+"Subject Description:\n"
+" 2.5.4.41: NDN Testbed Root\n"
+"Public key bits:\n"
+"MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA06x+elwzWCHa4I3byrYC\n"
+"MAIVxQpRVLuOXp0h+BS+5GNgMVPi7+40o4zSJG+kiU8CIH1mtj8RQAzBX9hFI5VA\n"
+"yOC8nS8D8YOfBwt2yRDZPgt1E5PpyYUBiDYuq/zmJDL8xjxAlxrMzVOqD/uj/vkk\n"
+"cBM/T1t9Q6p1CpRyq+GMRbV4EAHvH7MFb6bDrH9t8DHEg7NPUCaSQBrd7PvL72P+\n"
+"QdiNH9zs/EiVzAkeMG4iniSXLuYM3z0gMqqcyUUUr6r1F9IBmDO+Kp97nZh8VCL+\n"
+"cnIEwyzAFAupQH5GoXUWGiee8oKWwH2vGHX7u6sWZsCp15NMSG3OC4jUIZOEiVUF\n"
+"1QIB\n";
+
+BOOST_AUTO_TEST_CASE(Decode)
+{
+ ndn::Data data("/tmp");
+ data.setContent(REAL_CERT, sizeof(REAL_CERT));
+
+ ndn::Certificate certificate(data);
+
+ std::ostringstream os;
+ os << certificate << std::endl;
+ std::string info(os.str());
+ BOOST_CHECK_EQUAL(REAL_CERT_INFO, info);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-keychain.cpp b/tests/unit-tests/security/test-keychain.cpp
new file mode 100644
index 0000000..9a2300d
--- /dev/null
+++ b/tests/unit-tests/security/test-keychain.cpp
@@ -0,0 +1,213 @@
+/* -*- 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/key-chain.hpp"
+#include <boost/filesystem.hpp>
+
+#include "boost-test.hpp"
+
+using namespace std;
+
+namespace ndn {
+namespace tests {
+
+class KeychainConfigFileFixture
+{
+public:
+ KeychainConfigFileFixture()
+ {
+ if (std::getenv("TEST_HOME"))
+ m_HOME = std::getenv("TEST_HOME");
+ }
+
+ ~KeychainConfigFileFixture()
+ {
+ if (!m_HOME.empty())
+ setenv("TEST_HOME", m_HOME.c_str(), 1);
+ else
+ unsetenv("TEST_HOME");
+ }
+
+protected:
+ std::string m_HOME;
+};
+
+BOOST_FIXTURE_TEST_SUITE(SecurityTestKeyChain, KeychainConfigFileFixture)
+
+BOOST_AUTO_TEST_CASE(ConstructorNormalConfig)
+{
+ using namespace boost::filesystem;
+
+ setenv("TEST_HOME", "tests/unit-tests/security/config-file-home", 1);
+
+ BOOST_REQUIRE_NO_THROW(KeyChain());
+
+ path pibPath(absolute(std::getenv("TEST_HOME")));
+ pibPath /= ".ndn/ndnsec-public-info.db";
+
+ boost::filesystem::remove(pibPath);
+}
+
+BOOST_AUTO_TEST_CASE(ConstructorEmptyConfig)
+{
+ using namespace boost::filesystem;
+
+ setenv("TEST_HOME", "tests/unit-tests/security/config-file-empty-home", 1);
+
+ BOOST_REQUIRE_NO_THROW(KeyChain());
+
+ path pibPath(absolute(std::getenv("TEST_HOME")));
+ pibPath /= ".ndn/ndnsec-public-info.db";
+
+ boost::filesystem::remove(pibPath);
+}
+
+BOOST_AUTO_TEST_CASE(ConstructorMalConfig)
+{
+ using namespace boost::filesystem;
+
+ setenv("TEST_HOME", "tests/unit-tests/security/config-file-malformed-home", 1);
+
+ BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
+}
+
+BOOST_AUTO_TEST_CASE(ConstructorMal2Config)
+{
+ using namespace boost::filesystem;
+
+ setenv("TEST_HOME", "tests/unit-tests/security/config-file-malformed2-home", 1);
+
+ BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
+}
+
+BOOST_AUTO_TEST_CASE(ExportIdentity)
+{
+ BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+ KeyChain keyChain("sqlite3", "file");
+
+ Name identity("/TestKeyChain/ExportIdentity/");
+ identity.appendVersion();
+ keyChain.createIdentity(identity);
+
+ shared_ptr<SecuredBag> exported = keyChain.exportIdentity(identity, "1234");
+
+ Block block = exported->wireEncode();
+
+ Name keyName = keyChain.getDefaultKeyNameForIdentity(identity);
+ Name certName = keyChain.getDefaultCertificateNameForKey(keyName);
+
+ keyChain.deleteIdentity(identity);
+
+ BOOST_REQUIRE(keyChain.doesIdentityExist(identity) == false);
+ BOOST_REQUIRE(keyChain.doesPublicKeyExist(keyName) == false);
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+ BOOST_REQUIRE(keyChain.doesCertificateExist(certName) == false);
+
+ SecuredBag imported;
+ imported.wireDecode(block);
+ keyChain.importIdentity(imported, "1234");
+
+ BOOST_REQUIRE(keyChain.doesIdentityExist(identity));
+ BOOST_REQUIRE(keyChain.doesPublicKeyExist(keyName));
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE));
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC));
+ BOOST_REQUIRE(keyChain.doesCertificateExist(certName));
+
+ keyChain.deleteIdentity(identity);
+
+ BOOST_REQUIRE(keyChain.doesIdentityExist(identity) == false);
+ BOOST_REQUIRE(keyChain.doesPublicKeyExist(keyName) == false);
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+ BOOST_REQUIRE(keyChain.doesCertificateExist(certName) == false);
+}
+
+BOOST_AUTO_TEST_CASE(PrepareIdentityCertificate)
+{
+ BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+ KeyChain keyChain("sqlite3", "file");
+
+ Name identity("/TestKeyChain/PrepareIdentityCertificate/");
+ identity.appendVersion();
+ keyChain.createIdentity(identity);
+
+ vector<CertificateSubjectDescription> subjectDescription;
+ Name lowerIdentity = identity;
+ lowerIdentity.append("Lower").appendVersion();
+ Name lowerKeyName = keyChain.generateRsaKeyPair(lowerIdentity, true);
+ shared_ptr<IdentityCertificate> idCert
+ = keyChain.prepareUnsignedIdentityCertificate(lowerKeyName, identity,
+ time::system_clock::now(),
+ time::system_clock::now() + time::days(365),
+ subjectDescription);
+ BOOST_CHECK(static_cast<bool>(idCert));
+ BOOST_CHECK(idCert->getName().getPrefix(5) ==
+ Name().append(identity).append("KEY").append("Lower"));
+
+
+ Name anotherIdentity("/TestKeyChain/PrepareIdentityCertificate/Another/");
+ anotherIdentity.appendVersion();
+ Name anotherKeyName = keyChain.generateRsaKeyPair(anotherIdentity, true);
+ shared_ptr<IdentityCertificate> idCert2
+ = keyChain.prepareUnsignedIdentityCertificate(anotherKeyName, identity,
+ time::system_clock::now(),
+ time::system_clock::now() + time::days(365),
+ subjectDescription);
+ BOOST_CHECK(static_cast<bool>(idCert2));
+ BOOST_CHECK(idCert2->getName().getPrefix(5) == Name().append(anotherIdentity).append("KEY"));
+
+
+ Name wrongKeyName1;
+ shared_ptr<IdentityCertificate> idCert3
+ = keyChain.prepareUnsignedIdentityCertificate(wrongKeyName1, identity,
+ time::system_clock::now(),
+ time::system_clock::now() + time::days(365),
+ subjectDescription);
+ BOOST_CHECK(!static_cast<bool>(idCert3));
+
+
+ Name wrongKeyName2("/TestKeyChain/PrepareIdentityCertificate");
+ shared_ptr<IdentityCertificate> idCert4
+ = keyChain.prepareUnsignedIdentityCertificate(wrongKeyName2, identity,
+ time::system_clock::now(),
+ time::system_clock::now() + time::days(365),
+ subjectDescription);
+ BOOST_CHECK(!static_cast<bool>(idCert4));
+
+
+ Name wrongKeyName3("/TestKeyChain/PrepareIdentityCertificate/ksk-1234");
+ shared_ptr<IdentityCertificate> idCert5
+ = keyChain.prepareUnsignedIdentityCertificate(wrongKeyName3, identity,
+ time::system_clock::now(),
+ time::system_clock::now() + time::days(365),
+ subjectDescription);
+ BOOST_CHECK(!static_cast<bool>(idCert5));
+
+ keyChain.deleteIdentity(identity);
+ keyChain.deleteIdentity(lowerIdentity);
+ keyChain.deleteIdentity(anotherIdentity);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp b/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp
new file mode 100644
index 0000000..b91fed1
--- /dev/null
+++ b/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp
@@ -0,0 +1,103 @@
+/* -*- 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/sec-public-info-sqlite3.hpp"
+#include "security/key-chain.hpp"
+#include "util/time.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestSecPublicInfoSqlite3)
+
+BOOST_AUTO_TEST_CASE(Delete)
+{
+ BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+ KeyChain keyChain("sqlite3", "file");
+
+ Name identity("/TestSecPublicInfoSqlite3/Delete");
+ identity.appendVersion();
+
+ Name certName1;
+ BOOST_REQUIRE_NO_THROW(certName1 = keyChain.createIdentity(identity));
+
+ Name keyName1 = IdentityCertificate::certificateNameToPublicKeyName(certName1);
+ Name keyName2;
+ BOOST_REQUIRE_NO_THROW(keyName2 = keyChain.generateRsaKeyPairAsDefault(identity));
+
+ shared_ptr<IdentityCertificate> cert2;
+ BOOST_REQUIRE_NO_THROW(cert2 = keyChain.selfSign(keyName2));
+ Name certName2 = cert2->getName();
+ BOOST_REQUIRE_NO_THROW(keyChain.addCertificateAsKeyDefault(*cert2));
+
+ Name keyName3;
+ BOOST_REQUIRE_NO_THROW(keyName3 = keyChain.generateRsaKeyPairAsDefault(identity));
+
+ shared_ptr<IdentityCertificate> cert3;
+ BOOST_REQUIRE_NO_THROW(cert3 = keyChain.selfSign(keyName3));
+ Name certName3 = cert3->getName();
+ BOOST_REQUIRE_NO_THROW(keyChain.addCertificateAsKeyDefault(*cert3));
+ shared_ptr<IdentityCertificate> cert4;
+ BOOST_REQUIRE_NO_THROW(cert4 = keyChain.selfSign(keyName3));
+ Name certName4 = cert4->getName();
+ BOOST_REQUIRE_NO_THROW(keyChain.addCertificateAsKeyDefault(*cert4));
+ shared_ptr<IdentityCertificate> cert5;
+ BOOST_REQUIRE_NO_THROW(cert5 = keyChain.selfSign(keyName3));
+ Name certName5 = cert5->getName();
+ BOOST_REQUIRE_NO_THROW(keyChain.addCertificateAsKeyDefault(*cert5));
+
+ BOOST_CHECK_EQUAL(keyChain.doesIdentityExist(identity), true);
+ BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName1), true);
+ BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName2), true);
+ BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName3), true);
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName1), true);
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName2), true);
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName3), true);
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName4), true);
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName5), true);
+
+ BOOST_REQUIRE_NO_THROW(keyChain.deleteCertificate(certName5));
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName5), false);
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName3), true);
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName4), true);
+ BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName3), true);
+
+ BOOST_REQUIRE_NO_THROW(keyChain.deleteKey(keyName3));
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName4), false);
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName3), false);
+ BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName3), false);
+ BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName2), true);
+ BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName1), true);
+ BOOST_CHECK_EQUAL(keyChain.doesIdentityExist(identity), true);
+
+ BOOST_REQUIRE_NO_THROW(keyChain.deleteIdentity(identity));
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName2), false);
+ BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName2), false);
+ BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName1), false);
+ BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName1), false);
+ BOOST_CHECK_EQUAL(keyChain.doesIdentityExist(identity), false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-sec-tpm-file.cpp b/tests/unit-tests/security/test-sec-tpm-file.cpp
new file mode 100644
index 0000000..98c6e9a
--- /dev/null
+++ b/tests/unit-tests/security/test-sec-tpm-file.cpp
@@ -0,0 +1,219 @@
+/* -*- 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/sec-tpm-file.hpp"
+#include "security/key-chain.hpp"
+#include "security/cryptopp.hpp"
+
+#include "util/time.hpp"
+
+#include <boost/lexical_cast.hpp>
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestSecTpmFile)
+
+BOOST_AUTO_TEST_CASE (Delete)
+{
+ SecTpmFile tpm;
+
+ Name keyName("/TestSecTpmFile/Delete/ksk-" +
+ boost::lexical_cast<string>(time::toUnixTimestamp(time::system_clock::now())));
+ BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, KEY_TYPE_RSA, 2048));
+
+ BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
+ BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
+
+ tpm.deleteKeyPairInTpm(keyName);
+
+ BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), false);
+ BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), false);
+}
+
+BOOST_AUTO_TEST_CASE (SignVerify)
+{
+ SecTpmFile tpm;
+
+ Name keyName("/TestSecTpmFile/SignVerify/ksk-" +
+ boost::lexical_cast<string>(time::toUnixTimestamp(time::system_clock::now())));
+ BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, KEY_TYPE_RSA, 2048));
+
+ Data data("/tmp/test/1");
+ const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+
+ Block sigBlock;
+ BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
+ keyName, DIGEST_ALGORITHM_SHA256));
+ shared_ptr<PublicKey> pubkeyPtr;
+ BOOST_CHECK_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName));
+
+ try
+ {
+ using namespace CryptoPP;
+
+ RSA::PublicKey publicKey;
+ ByteQueue queue;
+ queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+ publicKey.Load(queue);
+
+ RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+ bool result = verifier.VerifyMessage(content, sizeof(content),
+ sigBlock.value(), sigBlock.value_size());
+
+ BOOST_CHECK_EQUAL(result, true);
+ }
+ catch (CryptoPP::Exception& e)
+ {
+ BOOST_CHECK(false);
+ }
+
+ tpm.deleteKeyPairInTpm(keyName);
+}
+
+BOOST_AUTO_TEST_CASE (RandomGenerator)
+{
+ SecTpmFile tpm;
+
+ size_t scale = 1000;
+ size_t size = 256 * scale;
+ uint8_t* block = new uint8_t[size];
+ tpm.generateRandomBlock(block, size);
+
+ map<uint8_t, int> counter;
+ for(size_t i = 0; i < size; i++)
+ counter[block[i]] += 1;
+
+ float dev = 0.0;
+ for(size_t i = 0; i != 255; i++)
+ dev += ((counter[i] - scale) * (counter[i] - scale)) * 1.0 / (scale * scale);
+
+ BOOST_CHECK_CLOSE(dev / 256, 0.001, 100);
+
+}
+
+BOOST_AUTO_TEST_CASE (ImportExportKey)
+{
+ using namespace CryptoPP;
+
+ string imported(
+"3082050E304006092A864886F70D01050D3033301B06092A864886F70D01050C300E0408209CF0B1B4C856A802020800301406082A864886F70D0307040884B1229D80690211048204C8DA62C11E1CCFC43F318D0C03DA4B11350122B18F23645C454F41BB46C7F8EED4F95041A9130B33E989AF338951A286B55FB9A707AF1C5B2E1FAE7CD66D6D556CBFD90640BDA0D7904DD8D89CF15AB24F1A652AB76E16411B78E8A9AAEEB6EE06FA793B2B4A3EE4B9B5DFB3FC3D38076145915A11CEC8FD2EAB70F51A0DA8B88B73B4DD5BAFB933ABCD92FFBA7843083CCE6B7A6BD9A51094EFF93DC93A19B4982F5FF8696FDF07B76366B6408EC18F4EA218A4F6B5EA85A5AF3B082D0E3AE74665BDD9FC7DE87A7A54EB038AB2E9196365F8481F1CC601EB866D554B4FBCDABECD35CBE404F3CB313E9799D111AD955C42629FB1A01E6138EFF15E6DE7D2BF8754868157DAC72EE5125221D502DCF0B8E8FF5CA87B601357785E7C95CBFC369B31D747ADACFB95E614507A5622ACAA3541B4FE02AEEC2DD588D3D7860A50C78EF460C39E250851140155052F18419F37D551FC3F5224764A17A2C47F9CEDC63780E3AF48C421D682FD3A68A2E12EB28737DB0F785137FC01282D0D82220E2D147E4E2D261046D3C5842B55C1C2F6BA51727AF57C502242F397ACEC341F2C6C6E739E629A144602C9994C88B4F8B4F7150C087C143D9FEC23A686E5E46A5541A071869089BECC05B186FC3D8F95668A671D7088462D61423BAEB73B41CDA5B69E22D6EE3A64BB523B1522F2433BA8AD98A7500EB5C5859469F45C15E91AC1DA9D9473B3C2B37C38D038F99122E157166B89C1EA941A683A73C3F7C0762E79E9C1E28A306042D8683C26995F7AA1B5CC1B985BB0A9DEE6471E9BCEF977A2BE84BD90CE3025FA76B8B546725D85C37543B69604D3F0822DBA3067E9CF9BF2F0DC676E0D718C963C71DBD7A278BAF2A2FFA65BDB8E60FCDD0D0BA841E37284FB6174047D1EC974730A77A7E808C5F27BF1FF0818AD7B0596C538ECFF2068BD5EED5E90102918E2F224EBFFDB2C8366A5C819A00BF6DDF823BD861331F4BF2323ECA284B90C96AB6C7CDBB200163AEA8FD9EC18BA5ACAA8B8B4BDA532A04AD179D402F09E69F5CE0A179EBEF9A99E8B0C5BC8A9C3CA71C820508E33C79A98B9C31F856F53D1369AD7D9C668BC9160D6C7F3612842BDCDB42F5AE6860E93B2B203CAE26C93A7640640D403BC107DDA031CAD54DC63FFF73861D25DE26B9147C328B3940F2CFB44E82112DD6FA514CB8FD5DD6E6FF4D4EFF430B06AC970D8D75F5BD6A015558ED8D82C5121115DC3657BE88356348C0F8B8EADFD5506C0C046984BB1F12F3EEFD32FED4C8684ABD252BF3CA56092D4A752CF51E13755568C3BF25CFCA0F7AF9279CA593305C27645022DD2DD0F7FFCAC92EDEF04B9DCAE7FD55E2C69C76CF061F1ECD724850FCA574543954105B9A3824B849DDD75DEB57B382054AAB4A1FE467D235FB77C220730ED7D9B79A575831395AAE0C4C0B0D3E7EC17511C3DE9A86AD1C68BFF861FA0151020E43A1C6B4F4D6273D586B1D291AEF45DF454463F39BACA2FF07AA5E24A7EA850189F8C39BA8E88FEB21C1647EF910898B02492C49599111D3558F05A4CFD0FDBF33E802798FF2C437FCD65AAC1024FB29D08DCD7DB7E08279C3EB4B64E58747096641D1886145EC9E5ADDC8BBC81BE0DC77C3F3A017311050B921B5506F13AF30BA04AFAA210F0359E710C01319DE7BFF165A3615E8DDFC6E3FC167BA39B332B42E5207CA4934EABDAE2D057FA661DEB3EBC1A4AFD4F3E014918EC");
+
+ string decoded;
+ BOOST_CHECK_NO_THROW(StringSource source(imported,
+ true,
+ new HexDecoder(new StringSink(decoded)))); //StringSource
+
+ SecTpmFile tpm;
+
+ Name keyName("/TestSecTpmFile/ImportKey/ksk-" +
+ boost::lexical_cast<string>(time::toUnixTimestamp(time::system_clock::now())));
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+
+ BOOST_REQUIRE_NO_THROW(
+ tpm.importPrivateKeyPkcs5IntoTpm(keyName,
+ reinterpret_cast<const uint8_t*>(decoded.c_str()),
+ decoded.size(),
+ "1234"));
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+
+ shared_ptr<PublicKey> pubkeyPtr;
+ BOOST_CHECK_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName));
+
+ const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+ Block sigBlock;
+ BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
+ keyName, DIGEST_ALGORITHM_SHA256));
+
+ try
+ {
+ using namespace CryptoPP;
+
+ RSA::PublicKey publicKey;
+ ByteQueue queue;
+ queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+ publicKey.Load(queue);
+
+ RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+ bool result = verifier.VerifyMessage(content, sizeof(content),
+ sigBlock.value(), sigBlock.value_size());
+
+ BOOST_CHECK_EQUAL(result, true);
+ }
+ catch (CryptoPP::Exception& e)
+ {
+ BOOST_CHECK(false);
+ }
+
+ ConstBufferPtr exported;
+ BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "5678"));
+
+ tpm.deleteKeyPairInTpm(keyName);
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+
+ BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName, exported->buf(), exported->size(),
+ "5678"));
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+
+ const uint8_t content2[] = {0x05, 0x06, 0x07, 0x08};
+ Block sigBlock2;
+ BOOST_CHECK_NO_THROW(sigBlock2 = tpm.signInTpm(content2, sizeof(content2),
+ keyName, DIGEST_ALGORITHM_SHA256));
+
+ try
+ {
+ using namespace CryptoPP;
+
+ RSA::PublicKey publicKey;
+ ByteQueue queue;
+ queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+ publicKey.Load(queue);
+
+ RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+ bool result = verifier.VerifyMessage(content2, sizeof(content2),
+ sigBlock2.value(), sigBlock2.value_size());
+
+ BOOST_CHECK_EQUAL(result, true);
+ }
+ catch (CryptoPP::Exception& e)
+ {
+ BOOST_CHECK(false);
+ }
+
+ tpm.deleteKeyPairInTpm(keyName);
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-sec-tpm-osx.cpp b/tests/unit-tests/security/test-sec-tpm-osx.cpp
new file mode 100644
index 0000000..a179e30
--- /dev/null
+++ b/tests/unit-tests/security/test-sec-tpm-osx.cpp
@@ -0,0 +1,200 @@
+/* -*- 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/sec-tpm-osx.hpp"
+#include "security/cryptopp.hpp"
+
+#include "util/time.hpp"
+
+#include <boost/lexical_cast.hpp>
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestSecTpmOsx)
+
+BOOST_AUTO_TEST_CASE(Delete)
+{
+ SecTpmOsx tpm;
+
+ Name keyName("/TestSecTpmOsx/Delete/ksk-" +
+ boost::lexical_cast<string>(
+ time::toUnixTimestamp(time::system_clock::now()).count()));
+ BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, KEY_TYPE_RSA, 2048));
+
+ BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
+ BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
+
+ tpm.deleteKeyPairInTpm(keyName);
+
+ BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), false);
+ BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), false);
+}
+
+BOOST_AUTO_TEST_CASE(SignVerify)
+{
+ SecTpmOsx tpm;
+
+ Name keyName("/TestSecTpmOsx/SignVerify/ksk-" +
+ boost::lexical_cast<string>(
+ time::toUnixTimestamp(time::system_clock::now()).count()));
+ BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, KEY_TYPE_RSA, 2048));
+
+ Data data("/TestSecTpmOsx/SignVaerify/Data/1");
+ const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+
+ Block sigBlock;
+ BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
+ keyName, DIGEST_ALGORITHM_SHA256));
+
+ shared_ptr<PublicKey> pubkeyPtr;
+ BOOST_CHECK_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName));
+ try
+ {
+ using namespace CryptoPP;
+
+ RSA::PublicKey publicKey;
+ ByteQueue queue;
+ queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+ publicKey.Load(queue);
+
+ RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+ bool result = verifier.VerifyMessage(content, sizeof(content),
+ sigBlock.value(), sigBlock.value_size());
+
+ BOOST_CHECK_EQUAL(result, true);
+ }
+ catch (CryptoPP::Exception& e)
+ {
+ BOOST_CHECK(false);
+ }
+
+ tpm.deleteKeyPairInTpm(keyName);
+}
+
+BOOST_AUTO_TEST_CASE(RandomGenerator)
+{
+ SecTpmOsx tpm;
+
+ size_t scale = 1000;
+ size_t size = 256 * scale;
+ uint8_t* block = new uint8_t[size];
+ tpm.generateRandomBlock(block, size);
+
+ map<uint8_t, int> counter;
+ for(size_t i = 0; i < size; i++)
+ counter[block[i]] += 1;
+
+ float dev = 0.0;
+ for(size_t i = 0; i != 255; i++)
+ dev += ((counter[i] - scale) * (counter[i] - scale)) * 1.0 / (scale * scale);
+
+ BOOST_CHECK_CLOSE(dev / 256, 0.001, 100);
+
+}
+
+BOOST_AUTO_TEST_CASE(ExportImportKey)
+{
+ using namespace CryptoPP;
+
+ SecTpmOsx tpm;
+
+ Name keyName("/TestSecTpmOsx/ExportImportKey/ksk-" +
+ boost::lexical_cast<string>(
+ time::toUnixTimestamp(time::system_clock::now()).count()));
+
+ BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, KEY_TYPE_RSA, 2048));
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+
+ ConstBufferPtr exported;
+ BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "1234"));
+ shared_ptr<PublicKey> pubkeyPtr;
+ BOOST_REQUIRE_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName));
+
+ tpm.deleteKeyPairInTpm(keyName);
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+
+ BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName,
+ exported->buf(), exported->size(),
+ "1234"));
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+
+ const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+ Block sigBlock;
+ BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
+ keyName, DIGEST_ALGORITHM_SHA256));
+
+ try
+ {
+ using namespace CryptoPP;
+
+ RSA::PublicKey publicKey;
+ ByteQueue queue;
+ queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+ publicKey.Load(queue);
+
+ RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+ bool result = verifier.VerifyMessage(content, sizeof(content),
+ sigBlock.value(), sigBlock.value_size());
+
+ BOOST_CHECK_EQUAL(result, true);
+ }
+ catch (CryptoPP::Exception& e)
+ {
+ BOOST_CHECK(false);
+ }
+
+ tpm.deleteKeyPairInTpm(keyName);
+ // This is some problem related to Mac OS Key chain, and we will fix it later.
+ // BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ // BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+}
+
+BOOST_AUTO_TEST_CASE(NonExistingKey)
+{
+ using namespace CryptoPP;
+
+ SecTpmOsx tpm;
+
+ Name keyName("/TestSecTpmOsx/NonExistingKey");
+
+ BOOST_REQUIRE_THROW(tpm.getPublicKeyFromTpm(keyName), SecTpmOsx::Error);
+
+ const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+ BOOST_REQUIRE_THROW(tpm.signInTpm(content, sizeof(content), keyName, DIGEST_ALGORITHM_SHA256),
+ SecTpmOsx::Error);
+
+ BOOST_REQUIRE_THROW(tpm.signInTpm(0, 1, keyName, DIGEST_ALGORITHM_SHA256),
+ SecTpmOsx::Error);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-signature-sha256.cpp b/tests/unit-tests/security/test-signature-sha256.cpp
new file mode 100644
index 0000000..7aac44e
--- /dev/null
+++ b/tests/unit-tests/security/test-signature-sha256.cpp
@@ -0,0 +1,71 @@
+/* -*- 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/key-chain.hpp"
+#include "security/validator.hpp"
+
+#include "security/cryptopp.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestSignatureSha256)
+
+string SHA256_RESULT("a883dafc480d466ee04e0d6da986bd78eb1fdd2178d04693723da3a8f95d42f4");
+
+BOOST_AUTO_TEST_CASE (Sha256)
+{
+ using namespace CryptoPP;
+
+ char content[6] = "1234\n";
+ ConstBufferPtr buf = crypto::sha256(reinterpret_cast<uint8_t*>(content), 5);
+ string result;
+ StringSource(buf->buf(), buf->size(), true, new HexEncoder(new StringSink(result), false));
+
+ BOOST_REQUIRE_EQUAL(SHA256_RESULT, result);
+}
+
+BOOST_AUTO_TEST_CASE (Signature)
+{
+ using namespace CryptoPP;
+
+ Name name("/TestSignatureSha/Basic");
+ Data testData(name);
+ char content[5] = "1234";
+ testData.setContent(reinterpret_cast<uint8_t*>(content), 5);
+
+ BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+ KeyChain keyChain("sqlite3", "file");
+
+ keyChain.signWithSha256(testData);
+
+ testData.wireEncode();
+
+ SignatureSha256 sig(testData.getSignature());
+
+ BOOST_REQUIRE(Validator::verifySignature(testData, sig));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-signed-interest.cpp b/tests/unit-tests/security/test-signed-interest.cpp
new file mode 100644
index 0000000..56b05f9
--- /dev/null
+++ b/tests/unit-tests/security/test-signed-interest.cpp
@@ -0,0 +1,191 @@
+/* -*- 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/key-chain.hpp"
+#include "security/validator.hpp"
+
+#include "util/command-interest-generator.hpp"
+#include "util/command-interest-validator.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestSignedInterest)
+
+BOOST_AUTO_TEST_CASE(SignedInterest)
+{
+ BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+ KeyChain keyChain("sqlite3", "file");
+
+ Name identityName("/TestSignedInterest/SignVerify");
+ identityName.appendVersion();
+
+ Name certificateName;
+ BOOST_REQUIRE_NO_THROW(certificateName = keyChain.createIdentity(identityName));
+
+ Interest interest("/TestSignedInterest/SignVerify/Interest1");
+ BOOST_CHECK_NO_THROW(keyChain.signByIdentity(interest, identityName));
+
+ Block interestBlock(interest.wireEncode().wire(), interest.wireEncode().size());
+
+ Interest interest2;
+ interest2.wireDecode(interestBlock);
+
+ shared_ptr<PublicKey> publicKey;
+ BOOST_REQUIRE_NO_THROW(publicKey = keyChain.getPublicKeyFromTpm(
+ keyChain.getDefaultKeyNameForIdentity(identityName)));
+ bool result = Validator::verifySignature(interest2, *publicKey);
+
+ BOOST_CHECK_EQUAL(result, true);
+
+ keyChain.deleteIdentity(identityName);
+}
+
+class CommandInterestFixture
+{
+public:
+ CommandInterestFixture()
+ : m_validity(false)
+ {}
+
+ void
+ validated(const shared_ptr<const Interest>& interest)
+ { m_validity = true; }
+
+ void
+ validationFailed(const shared_ptr<const Interest>& interest, const string& failureInfo)
+ {
+ m_validity = false;
+ }
+
+ void
+ reset()
+ { m_validity = false; }
+
+ bool m_validity;
+};
+
+BOOST_FIXTURE_TEST_CASE(CommandInterest, CommandInterestFixture)
+{
+ KeyChain keyChain;
+ Name identity("/TestCommandInterest/Validation");
+ identity.appendVersion();
+
+ Name certName;
+ BOOST_REQUIRE_NO_THROW(certName = keyChain.createIdentity(identity));
+
+ CommandInterestGenerator generator;
+ CommandInterestValidator validator;
+
+ validator.addInterestRule("^<TestCommandInterest><Validation>",
+ *keyChain.getCertificate(certName));
+
+ //Test a legitimate command
+ shared_ptr<Interest> commandInterest1 =
+ make_shared<Interest>("/TestCommandInterest/Validation/Command1");
+ generator.generateWithIdentity(*commandInterest1, identity);
+ validator.validate(*commandInterest1,
+ bind(&CommandInterestFixture::validated, this, _1),
+ bind(&CommandInterestFixture::validationFailed, this, _1, _2));
+
+ BOOST_CHECK_EQUAL(m_validity, true);
+
+ //Test an outdated command
+ reset();
+ shared_ptr<Interest> commandInterest2 =
+ make_shared<Interest>("/TestCommandInterest/Validation/Command2");
+ time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
+ timestamp -= time::seconds(5);
+
+ Name commandName = commandInterest2->getName();
+ commandName
+ .appendNumber(timestamp.count())
+ .appendNumber(random::generateWord64());
+ commandInterest2->setName(commandName);
+
+ keyChain.signByIdentity(*commandInterest2, identity);
+ validator.validate(*commandInterest2,
+ bind(&CommandInterestFixture::validated, this, _1),
+ bind(&CommandInterestFixture::validationFailed, this, _1, _2));
+
+ BOOST_CHECK_EQUAL(m_validity, false);
+
+ //Test an unauthorized command
+ Name identity2("/TestCommandInterest/Validation2");
+ Name certName2;
+ BOOST_REQUIRE_NO_THROW(certName2 = keyChain.createIdentity(identity2));
+
+ shared_ptr<Interest> commandInterest3 =
+ make_shared<Interest>("/TestCommandInterest/Validation/Command3");
+ generator.generateWithIdentity(*commandInterest3, identity2);
+ validator.validate(*commandInterest3,
+ bind(&CommandInterestFixture::validated, this, _1),
+ bind(&CommandInterestFixture::validationFailed, this, _1, _2));
+
+ BOOST_CHECK_EQUAL(m_validity, false);
+
+ //Test another unauthorized command
+ shared_ptr<Interest> commandInterest4 =
+ make_shared<Interest>("/TestCommandInterest/Validation2/Command");
+ generator.generateWithIdentity(*commandInterest4, identity);
+ validator.validate(*commandInterest4,
+ bind(&CommandInterestFixture::validated, this, _1),
+ bind(&CommandInterestFixture::validationFailed, this, _1, _2));
+
+ BOOST_CHECK_EQUAL(m_validity, false);
+
+ BOOST_CHECK_NO_THROW(keyChain.deleteIdentity(identity));
+ BOOST_CHECK_NO_THROW(keyChain.deleteIdentity(identity2));
+}
+
+BOOST_FIXTURE_TEST_CASE(Exemption, CommandInterestFixture)
+{
+ KeyChain keyChain;
+ Name identity("/TestCommandInterest/AnyKey");
+
+ Name certName;
+ BOOST_REQUIRE_NO_THROW(certName = keyChain.createIdentity(identity));
+
+ CommandInterestGenerator generator;
+ CommandInterestValidator validator;
+
+ validator.addInterestBypassRule("^<TestCommandInterest><Exemption>");
+
+ //Test a legitimate command
+ shared_ptr<Interest> commandInterest1 =
+ make_shared<Interest>("/TestCommandInterest/Exemption/Command1");
+ generator.generateWithIdentity(*commandInterest1, identity);
+ validator.validate(*commandInterest1,
+ bind(&CommandInterestFixture::validated, this, _1),
+ bind(&CommandInterestFixture::validationFailed, this, _1, _2));
+
+ BOOST_CHECK_EQUAL(m_validity, true);
+
+ BOOST_CHECK_NO_THROW(keyChain.deleteIdentity(identity));
+}
+
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-validator.cpp b/tests/unit-tests/security/test-validator.cpp
new file mode 100644
index 0000000..40e667d
--- /dev/null
+++ b/tests/unit-tests/security/test-validator.cpp
@@ -0,0 +1,72 @@
+/* -*- 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/validator-null.hpp"
+#include "security/key-chain.hpp"
+#include "util/time.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestValidator)
+
+void
+onValidated(const shared_ptr<const Data>& data)
+{ BOOST_CHECK(true); }
+
+void
+onValidationFailed(const shared_ptr<const Data>& data, const string& failureInfo)
+{
+ BOOST_CHECK(false);
+}
+
+BOOST_AUTO_TEST_CASE(Null)
+{
+ BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+ KeyChain keyChain("sqlite3", "file");
+
+ Name identity("/TestValidator/Null");
+ identity.appendVersion();
+
+ BOOST_REQUIRE_NO_THROW(keyChain.createIdentity(identity));
+
+ Name dataName = identity;
+ dataName.append("1");
+ shared_ptr<Data> data = make_shared<Data>(dataName);
+
+ BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data, identity));
+
+ ValidatorNull validator;
+
+ // data must be a shared pointer
+ validator.validate(*data,
+ bind(&onValidated, _1),
+ bind(&onValidationFailed, _1, _2));
+
+ keyChain.deleteIdentity(identity);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn