security: various enhancements to Interest and Data validation
* Avoid decoding SignatureInfo multiple times while validating an Interest
* Fix handling of signed Interests with malformed InterestSignatureInfo
* Report a NO_SIGNATURE error when SignatureInfo is missing or malformed
* Fail with POLICY_ERROR in ValidationPolicySimpleHierarchy when the
signing identity violates the policy
* Reduce code duplication
* Expand unit test coverage
Change-Id: I1c9d532b2307d5df8f4bd75152af57a4e10835aa
diff --git a/tests/unit/security/certificate-fetcher-direct-fetch.t.cpp b/tests/unit/security/certificate-fetcher-direct-fetch.t.cpp
index 183a947..7c9ba90 100644
--- a/tests/unit/security/certificate-fetcher-direct-fetch.t.cpp
+++ b/tests/unit/security/certificate-fetcher-direct-fetch.t.cpp
@@ -21,11 +21,10 @@
#include "ndn-cxx/security/certificate-fetcher-direct-fetch.hpp"
-#include "ndn-cxx/lp/nack.hpp"
#include "ndn-cxx/lp/tags.hpp"
#include "ndn-cxx/security/validation-policy-simple-hierarchy.hpp"
-#include "tests/boost-test.hpp"
+#include "tests/test-common.hpp"
#include "tests/unit/security/validator-fixture.hpp"
#include <boost/range/adaptor/sliced.hpp>
@@ -133,9 +132,7 @@
void
CertificateFetcherDirectFetchFixture<Nack>::makeResponse(const Interest& interest)
{
- lp::Nack nack(interest);
- nack.setHeader(lp::NackHeader().setReason(lp::NackReason::NO_ROUTE));
- face.receive(nack);
+ face.receive(makeNack(interest, lp::NackReason::NO_ROUTE));
}
using Failures = boost::mpl::vector<Timeout, Nack>;
@@ -174,9 +171,10 @@
BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateFailureData, T, Failures, CertificateFetcherDirectFetchFixture<T>)
{
VALIDATE_FAILURE(this->data, "Should fail, as all interests either NACKed or timeout");
+ BOOST_TEST(this->lastError.getCode() == ValidationError::CANNOT_RETRIEVE_CERT);
// Direct fetcher sends two interests each time - to network and face
// 3 retries on nack or timeout (2 * (1 + 3) = 8)
- BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 8);
+ BOOST_TEST(this->face.sentInterests.size() == 8);
// odd interests
for (const auto& sentInterest : this->face.sentInterests | boost::adaptors::strided(2)) {
@@ -197,9 +195,10 @@
static_cast<CertificateFetcherDirectFetch&>(this->validator.getFetcher()).setSendDirectInterestOnly(true);
VALIDATE_FAILURE(this->data, "Should fail, as all interests either NACKed or timeout");
+ BOOST_TEST(this->lastError.getCode() == ValidationError::CANNOT_RETRIEVE_CERT);
// Direct fetcher sends two interests each time - to network and face
// 3 retries on nack or timeout (1 + 3 = 4)
- BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 4);
+ BOOST_TEST(this->face.sentInterests.size() == 4);
for (const auto& sentInterest : this->face.sentInterests) {
BOOST_CHECK(sentInterest.template getTag<lp::NextHopFaceIdTag>() != nullptr);
@@ -215,8 +214,8 @@
this->interest.template removeTag<lp::IncomingFaceIdTag>();
VALIDATE_FAILURE(this->data, "Should fail, as no interests are expected");
- BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 0);
- BOOST_CHECK_NE(this->lastError.getCode(), ValidationError::IMPLEMENTATION_ERROR);
+ BOOST_TEST(this->lastError.getCode() == ValidationError::CANNOT_RETRIEVE_CERT);
+ BOOST_TEST(this->face.sentInterests.size() == 0);
}
BOOST_FIXTURE_TEST_CASE(ValidateSuccessInterest, CertificateFetcherDirectFetchFixture<Cert>)
@@ -240,9 +239,10 @@
BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateFailureInterest, T, Failures, CertificateFetcherDirectFetchFixture<T>)
{
VALIDATE_FAILURE(this->interest, "Should fail, as all interests either NACKed or timeout");
+ BOOST_TEST(this->lastError.getCode() == ValidationError::CANNOT_RETRIEVE_CERT);
// Direct fetcher sends two interests each time - to network and face
// 3 retries on nack or timeout (2 * (1 + 3) = 4)
- BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 8);
+ BOOST_TEST(this->face.sentInterests.size() == 8);
// odd interests
for (const auto& sentInterest : this->face.sentInterests | boost::adaptors::strided(2)) {
diff --git a/tests/unit/security/certificate-fetcher-from-network.t.cpp b/tests/unit/security/certificate-fetcher-from-network.t.cpp
index 29d8243..cb3e0b5 100644
--- a/tests/unit/security/certificate-fetcher-from-network.t.cpp
+++ b/tests/unit/security/certificate-fetcher-from-network.t.cpp
@@ -119,15 +119,17 @@
BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateFailure, T, Failures, CertificateFetcherFromNetworkFixture<T>)
{
VALIDATE_FAILURE(this->data, "Should fail, as interests don't bring data");
+ BOOST_TEST(this->lastError.getCode() == ValidationError::CANNOT_RETRIEVE_CERT);
// first interest + 3 retries
- BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 4);
+ BOOST_TEST(this->face.sentInterests.size() == 4);
this->face.sentInterests.clear();
this->advanceClocks(1_h, 2); // expire validator caches
VALIDATE_FAILURE(this->interest, "Should fail, as interests don't bring data");
- BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 4);
+ BOOST_TEST(this->lastError.getCode() == ValidationError::CANNOT_RETRIEVE_CERT);
+ BOOST_TEST(this->face.sentInterests.size() == 4);
}
BOOST_AUTO_TEST_SUITE_END() // TestCertificateFetcherFromNetwork
diff --git a/tests/unit/security/certificate-fetcher-offline.t.cpp b/tests/unit/security/certificate-fetcher-offline.t.cpp
index f674993..f48971f 100644
--- a/tests/unit/security/certificate-fetcher-offline.t.cpp
+++ b/tests/unit/security/certificate-fetcher-offline.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2020 Regents of the University of California.
+ * Copyright (c) 2013-2022 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -54,7 +54,8 @@
auto packet = Packet::makePacket(name);
m_keyChain.sign(packet, signingByIdentity(subIdentity));
VALIDATE_FAILURE(packet, "Should fail, as no cert should be requested");
- BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 0);
+ BOOST_TEST(this->lastError.getCode() == ValidationError::CANNOT_RETRIEVE_CERT);
+ BOOST_TEST(this->face.sentInterests.size() == 0);
packet = Packet::makePacket(name);
m_keyChain.sign(packet, signingByIdentity(identity));
diff --git a/tests/unit/security/validation-policy-command-interest.t.cpp b/tests/unit/security/validation-policy-command-interest.t.cpp
index cf91ee3..d6fd74f 100644
--- a/tests/unit/security/validation-policy-command-interest.t.cpp
+++ b/tests/unit/security/validation-policy-command-interest.t.cpp
@@ -28,7 +28,6 @@
#include "tests/test-common.hpp"
#include "tests/unit/security/validator-fixture.hpp"
-#include <boost/lexical_cast.hpp>
#include <boost/mpl/vector.hpp>
namespace ndn {
@@ -40,9 +39,8 @@
BOOST_AUTO_TEST_SUITE(Security)
-class CommandInterestDefaultOptions
+struct CommandInterestDefaultOptions
{
-public:
static ValidationPolicyCommandInterest::Options
getOptions()
{
@@ -61,62 +59,82 @@
};
template<class T, class InnerPolicy = ValidationPolicySimpleHierarchy>
-class ValidationPolicyCommandInterestFixture : public HierarchicalValidatorFixture<CommandInterestPolicyWrapper<T, InnerPolicy>>
+class ValidationPolicyCommandInterestFixture
+ : public HierarchicalValidatorFixture<CommandInterestPolicyWrapper<T, InnerPolicy>>
{
-public:
+protected:
Interest
- makeCommandInterest(const Identity& identity, bool wantV3 = false)
+ makeCommandInterest(const Identity& identity, SignedInterestFormat format = SignedInterestFormat::V02)
{
- if (wantV3) {
- Interest i(Name(identity.getName()).append("CMD"));
- m_signer.makeSignedInterest(i, signingByIdentity(identity));
- return i;
+ Name name = identity.getName();
+ name.append("CMD");
+ switch (format) {
+ case SignedInterestFormat::V02:
+ return m_signer.makeCommandInterest(name, signingByIdentity(identity));
+ case SignedInterestFormat::V03: {
+ Interest interest(name);
+ m_signer.makeSignedInterest(interest, signingByIdentity(identity));
+ return interest;
+ }
}
- else {
- return m_signer.makeCommandInterest(Name(identity.getName()).append("CMD"),
- signingByIdentity(identity));
- }
+ NDN_CXX_UNREACHABLE;
}
-public:
+protected:
InterestSigner m_signer{this->m_keyChain};
};
BOOST_FIXTURE_TEST_SUITE(TestValidationPolicyCommandInterest,
ValidationPolicyCommandInterestFixture<CommandInterestDefaultOptions>)
+template<int secs>
+struct GracePeriodSeconds
+{
+ static ValidationPolicyCommandInterest::Options
+ getOptions()
+ {
+ ValidationPolicyCommandInterest::Options options;
+ options.gracePeriod = time::seconds(secs);
+ return options;
+ }
+};
+
BOOST_AUTO_TEST_SUITE(Accepts)
-BOOST_AUTO_TEST_CASE(Basic)
+BOOST_AUTO_TEST_CASE(BasicV02)
{
- auto i1 = makeCommandInterest(identity);
+ auto i1 = makeCommandInterest(identity, SignedInterestFormat::V02);
VALIDATE_SUCCESS(i1, "Should succeed (within grace period)");
VALIDATE_FAILURE(i1, "Should fail (replay attack)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
advanceClocks(5_ms);
- auto i2 = makeCommandInterest(identity);
+ auto i2 = makeCommandInterest(identity, SignedInterestFormat::V02);
VALIDATE_SUCCESS(i2, "Should succeed (timestamp larger than previous)");
- auto i3 = m_signer.makeCommandInterest(Name(identity.getName()).append("CMD"), signingWithSha256());
+ auto i3 = m_signer.makeCommandInterest(Name(identity.getName()).append("CMD"), signingWithSha256());
VALIDATE_FAILURE(i3, "Should fail (Sha256 signature violates policy)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
}
-BOOST_AUTO_TEST_CASE(BasicV3)
+BOOST_AUTO_TEST_CASE(BasicV03)
{
- auto i1 = makeCommandInterest(identity, true);
+ auto i1 = makeCommandInterest(identity, SignedInterestFormat::V03);
VALIDATE_SUCCESS(i1, "Should succeed (within grace period)");
VALIDATE_FAILURE(i1, "Should fail (replay attack)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
advanceClocks(5_ms);
- auto i2 = makeCommandInterest(identity, true);
+ auto i2 = makeCommandInterest(identity, SignedInterestFormat::V03);
VALIDATE_SUCCESS(i2, "Should succeed (timestamp larger than previous)");
Interest i3(Name(identity.getName()).append("CMD"));
m_signer.makeSignedInterest(i3, signingWithSha256());
VALIDATE_FAILURE(i3, "Should fail (Sha256 signature violates policy)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
}
-BOOST_AUTO_TEST_CASE(DataPassthru)
+BOOST_AUTO_TEST_CASE(DataPassthrough)
{
Data d1("/Security/ValidatorFixture/Sub1");
m_keyChain.sign(d1);
@@ -131,6 +149,7 @@
auto i1 = m_signer.makeCommandInterest("/hello/world/CMD", signingWithSha256());
VALIDATE_SUCCESS(i1, "Should succeed (within grace period)");
VALIDATE_FAILURE(i1, "Should fail (replay attack)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
advanceClocks(5_ms);
auto i2 = m_signer.makeCommandInterest("/hello/world/CMD", signingWithSha256());
@@ -141,89 +160,118 @@
BOOST_AUTO_TEST_SUITE(Rejects)
-BOOST_AUTO_TEST_CASE(NameTooShort)
+BOOST_AUTO_TEST_CASE(NotSigned)
{
- auto i1 = makeInterest("/name/too/short");
- VALIDATE_FAILURE(*i1, "Should fail (name is too short)");
-}
-
-BOOST_AUTO_TEST_CASE(BadTimestamp)
-{
- auto i1 = makeCommandInterest(identity);
- setNameComponent(i1, command_interest::POS_TIMESTAMP, "not-timestamp");
- VALIDATE_FAILURE(i1, "Should fail (timestamp is missing)");
+ auto i1 = Interest("/short");
+ BOOST_TEST_REQUIRE(i1.getName().size() < signed_interest::MIN_SIZE);
+ VALIDATE_FAILURE(i1, "Should fail (not signed / name too short)");
+ BOOST_TEST(lastError.getCode() == ValidationError::NO_SIGNATURE);
}
BOOST_AUTO_TEST_CASE(BadSigInfo)
{
- auto i1 = makeCommandInterest(identity);
+ auto i1 = makeCommandInterest(identity, SignedInterestFormat::V02);
setNameComponent(i1, command_interest::POS_SIG_INFO, "not-SignatureInfo");
+ BOOST_TEST_REQUIRE(i1.getName().size() >= command_interest::MIN_SIZE);
VALIDATE_FAILURE(i1, "Should fail (signature info is missing)");
+ BOOST_TEST(lastError.getCode() == ValidationError::NO_SIGNATURE);
}
-BOOST_AUTO_TEST_CASE(MissingKeyLocator)
+BOOST_AUTO_TEST_CASE(BadTimestampV02)
{
- auto i1 = makeCommandInterest(identity);
+ // i1 is a valid signed interest (in v0.2 format) but is not a valid command interest
+ auto i1 = Interest("/short");
+ m_keyChain.sign(i1, signingByIdentity(identity).setSignedInterestFormat(SignedInterestFormat::V02));
+ BOOST_TEST_REQUIRE((i1.getName().size() >= signed_interest::MIN_SIZE &&
+ i1.getName().size() < command_interest::MIN_SIZE));
+ VALIDATE_FAILURE(i1, "Should fail (timestamp is missing)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
+
+ auto i2 = makeCommandInterest(identity, SignedInterestFormat::V02);
+ setNameComponent(i2, command_interest::POS_TIMESTAMP, "not-timestamp");
+ BOOST_TEST_REQUIRE(i2.getName().size() >= command_interest::MIN_SIZE);
+ VALIDATE_FAILURE(i2, "Should fail (timestamp is malformed)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
+}
+
+BOOST_AUTO_TEST_CASE(BadTimestampV03)
+{
+ auto i1 = makeCommandInterest(identity, SignedInterestFormat::V03);
+ auto si = i1.getSignatureInfo().value();
+ si.setTime(nullopt);
+ i1.setSignatureInfo(si);
+ VALIDATE_FAILURE(i1, "Should fail (timestamp is missing)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
+}
+
+BOOST_AUTO_TEST_CASE(MissingKeyLocatorV02)
+{
+ auto i1 = makeCommandInterest(identity, SignedInterestFormat::V02);
SignatureInfo sigInfo(tlv::SignatureSha256WithRsa);
setNameComponent(i1, command_interest::POS_SIG_INFO,
sigInfo.wireEncode().begin(), sigInfo.wireEncode().end());
VALIDATE_FAILURE(i1, "Should fail (missing KeyLocator)");
+ BOOST_TEST(lastError.getCode() == ValidationError::INVALID_KEY_LOCATOR);
+}
+
+BOOST_AUTO_TEST_CASE(MissingKeyLocatorV03)
+{
+ auto i1 = makeCommandInterest(identity, SignedInterestFormat::V03);
+ auto si = i1.getSignatureInfo().value();
+ si.setKeyLocator(nullopt);
+ i1.setSignatureInfo(si);
+ VALIDATE_FAILURE(i1, "Should fail (missing KeyLocator)");
+ BOOST_TEST(lastError.getCode() == ValidationError::INVALID_KEY_LOCATOR);
}
BOOST_AUTO_TEST_CASE(BadKeyLocatorType)
{
- auto i1 = makeCommandInterest(identity);
+ auto i1 = makeCommandInterest(identity, SignedInterestFormat::V02);
KeyLocator kl;
kl.setKeyDigest(makeBinaryBlock(tlv::KeyDigest, {0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD}));
- SignatureInfo sigInfo(tlv::SignatureSha256WithRsa);
- sigInfo.setKeyLocator(kl);
+ SignatureInfo sigInfo(tlv::SignatureSha256WithRsa, kl);
setNameComponent(i1, command_interest::POS_SIG_INFO,
sigInfo.wireEncode().begin(), sigInfo.wireEncode().end());
VALIDATE_FAILURE(i1, "Should fail (bad KeyLocator type)");
+ BOOST_TEST(lastError.getCode() == ValidationError::INVALID_KEY_LOCATOR);
}
BOOST_AUTO_TEST_CASE(BadCertName)
{
- auto i1 = makeCommandInterest(identity);
- KeyLocator kl;
- kl.setName("/bad/cert/name");
- SignatureInfo sigInfo(tlv::SignatureSha256WithRsa);
- sigInfo.setKeyLocator(kl);
+ auto i1 = makeCommandInterest(identity, SignedInterestFormat::V02);
+ SignatureInfo sigInfo(tlv::SignatureSha256WithEcdsa, KeyLocator("/bad/cert/name"));
setNameComponent(i1, command_interest::POS_SIG_INFO,
sigInfo.wireEncode().begin(), sigInfo.wireEncode().end());
VALIDATE_FAILURE(i1, "Should fail (bad certificate name)");
+ BOOST_TEST(lastError.getCode() == ValidationError::INVALID_KEY_LOCATOR);
}
BOOST_AUTO_TEST_CASE(InnerPolicyReject)
{
- auto i1 = makeCommandInterest(otherIdentity);
+ auto i1 = makeCommandInterest(otherIdentity, SignedInterestFormat::V02);
VALIDATE_FAILURE(i1, "Should fail (inner policy should reject)");
+ BOOST_TEST(lastError.getCode() == ValidationError::LOOP_DETECTED);
+
+ auto i2 = makeCommandInterest(otherIdentity, SignedInterestFormat::V03);
+ VALIDATE_FAILURE(i2, "Should fail (inner policy should reject)");
+ BOOST_TEST(lastError.getCode() == ValidationError::LOOP_DETECTED);
}
-class GracePeriod15Sec
-{
-public:
- static ValidationPolicyCommandInterest::Options
- getOptions()
- {
- ValidationPolicyCommandInterest::Options options;
- options.gracePeriod = 15_s;
- return options;
- }
-};
-
-BOOST_FIXTURE_TEST_CASE(TimestampOutOfGracePositive, ValidationPolicyCommandInterestFixture<GracePeriod15Sec>)
+BOOST_FIXTURE_TEST_CASE(TimestampOutOfGracePositive,
+ ValidationPolicyCommandInterestFixture<GracePeriodSeconds<15>>)
{
auto i1 = makeCommandInterest(identity); // signed at 0s
advanceClocks(16_s); // verifying at +16s
VALIDATE_FAILURE(i1, "Should fail (timestamp outside the grace period)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
rewindClockAfterValidation();
auto i2 = makeCommandInterest(identity); // signed at +16s
VALIDATE_SUCCESS(i2, "Should succeed");
}
-BOOST_FIXTURE_TEST_CASE(TimestampOutOfGraceNegative, ValidationPolicyCommandInterestFixture<GracePeriod15Sec>)
+BOOST_FIXTURE_TEST_CASE(TimestampOutOfGraceNegative,
+ ValidationPolicyCommandInterestFixture<GracePeriodSeconds<15>>)
{
auto i1 = makeCommandInterest(identity); // signed at 0s
advanceClocks(1_s);
@@ -233,10 +281,12 @@
m_systemClock->advance(-18_s); // verifying at -16s
VALIDATE_FAILURE(i1, "Should fail (timestamp outside the grace period)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
rewindClockAfterValidation();
// CommandInterestValidator should not remember i1's timestamp
VALIDATE_FAILURE(i2, "Should fail (timestamp outside the grace period)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
rewindClockAfterValidation();
// CommandInterestValidator should not remember i2's timestamp, and should treat i3 as initial
@@ -250,9 +300,9 @@
VALIDATE_SUCCESS(i1, "Should succeed");
auto i2 = makeCommandInterest(identity); // signed at 0s
- setNameComponent(i2, command_interest::POS_TIMESTAMP,
- i1.getName()[command_interest::POS_TIMESTAMP]);
+ setNameComponent(i2, command_interest::POS_TIMESTAMP, i1.getName()[command_interest::POS_TIMESTAMP]);
VALIDATE_FAILURE(i2, "Should fail (timestamp reordered)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
advanceClocks(2_s);
auto i3 = makeCommandInterest(identity); // signed at +2s
@@ -275,11 +325,13 @@
m_systemClock->advance(-1100_ms); // verifying at 0ms
VALIDATE_FAILURE(i2, "Should fail (timestamp reordered)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
rewindClockAfterValidation();
// CommandInterestValidator should not remember i2's timestamp
advanceClocks(200_ms); // verifying at +200ms
VALIDATE_FAILURE(i3, "Should fail (timestamp reordered)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
rewindClockAfterValidation();
advanceClocks(1200_ms); // verifying at 1400ms
@@ -290,25 +342,12 @@
BOOST_AUTO_TEST_SUITE(Options)
-template<class T>
-class GracePeriod
-{
-public:
- static ValidationPolicyCommandInterest::Options
- getOptions()
- {
- ValidationPolicyCommandInterest::Options options;
- options.gracePeriod = time::seconds(T::value);
- return options;
- }
-};
+using NonPositiveGracePeriods = boost::mpl::vector<
+ GracePeriodSeconds<0>,
+ GracePeriodSeconds<-1>
+>;
-typedef boost::mpl::vector<
- GracePeriod<boost::mpl::int_<0>>,
- GracePeriod<boost::mpl::int_<-1>>
-> GraceNonPositiveValues;
-
-BOOST_FIXTURE_TEST_CASE_TEMPLATE(GraceNonPositive, GracePeriod, GraceNonPositiveValues,
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(GraceNonPositive, GracePeriod, NonPositiveGracePeriods,
ValidationPolicyCommandInterestFixture<GracePeriod>)
{
auto i1 = this->makeCommandInterest(this->identity); // signed at 0ms
@@ -323,6 +362,7 @@
this->advanceClocks(1_ms);
VALIDATE_FAILURE(i2, "Should fail when validating at 1ms");
+ BOOST_TEST(this->lastError.getCode() == ValidationError::POLICY_ERROR);
}
class LimitedRecordsOptions
@@ -402,11 +442,12 @@
advanceClocks(1_s);
for (size_t i = 0; i < 20; ++i) {
auto i2 = makeCommandInterest(identities.at(i)); // signed at +1s
-
VALIDATE_SUCCESS(i2, "Should succeed");
rewindClockAfterValidation();
}
+
VALIDATE_FAILURE(i1, "Should fail (timestamp reorder)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
}
class ZeroRecordsOptions
diff --git a/tests/unit/security/validation-policy-signed-interest.t.cpp b/tests/unit/security/validation-policy-signed-interest.t.cpp
index c3d37e6..58f502e 100644
--- a/tests/unit/security/validation-policy-signed-interest.t.cpp
+++ b/tests/unit/security/validation-policy-signed-interest.t.cpp
@@ -28,7 +28,6 @@
#include "tests/test-common.hpp"
#include "tests/unit/security/validator-fixture.hpp"
-#include <boost/lexical_cast.hpp>
#include <boost/mpl/vector.hpp>
namespace ndn {
@@ -40,9 +39,8 @@
BOOST_AUTO_TEST_SUITE(Security)
-class SignedInterestDefaultOptions
+struct SignedInterestDefaultOptions
{
-public:
static ValidationPolicySignedInterest::Options
getOptions()
{
@@ -64,12 +62,7 @@
class ValidationPolicySignedInterestFixture
: public HierarchicalValidatorFixture<SignedInterestPolicyWrapper<T, InnerPolicy>>
{
-public:
- ValidationPolicySignedInterestFixture()
- : m_signer(this->m_keyChain)
- {
- }
-
+protected:
Interest
makeSignedInterest(const Identity& identity,
uint32_t signingFlags = InterestSigner::WantNonce | InterestSigner::WantTime)
@@ -79,8 +72,8 @@
return i;
}
-public:
- InterestSigner m_signer;
+protected:
+ InterestSigner m_signer{this->m_keyChain};
static constexpr uint32_t WantAll = InterestSigner::WantNonce |
InterestSigner::WantTime |
@@ -90,11 +83,12 @@
BOOST_FIXTURE_TEST_SUITE(TestValidationPolicySignedInterest,
ValidationPolicySignedInterestFixture<SignedInterestDefaultOptions>)
-BOOST_AUTO_TEST_CASE(BasicV3)
+BOOST_AUTO_TEST_CASE(Basic)
{
auto i1 = makeSignedInterest(identity, WantAll);
VALIDATE_SUCCESS(i1, "Should succeed (within grace period)");
VALIDATE_FAILURE(i1, "Should fail (replay attack)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
advanceClocks(5_ms);
auto i2 = makeSignedInterest(identity, WantAll);
@@ -103,6 +97,7 @@
Interest i3(Name(identity.getName()).append("CMD"));
m_signer.makeSignedInterest(i3, signingWithSha256());
VALIDATE_FAILURE(i3, "Should fail (Sha256 signature violates policy)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
}
BOOST_AUTO_TEST_CASE(DataPassthrough)
@@ -116,22 +111,23 @@
{
auto i1 = makeSignedInterest(otherIdentity);
VALIDATE_FAILURE(i1, "Should fail (inner policy should reject)");
+ BOOST_TEST(lastError.getCode() == ValidationError::LOOP_DETECTED);
}
-class LimitedRecordsOptions
+template<ssize_t count>
+struct MaxRecordCount
{
-public:
static ValidationPolicySignedInterest::Options
getOptions()
{
ValidationPolicySignedInterest::Options options;
options.timestampGracePeriod = 15_s;
- options.maxRecordCount = 3;
+ options.maxRecordCount = count;
return options;
}
};
-BOOST_FIXTURE_TEST_CASE(LimitedRecords, ValidationPolicySignedInterestFixture<LimitedRecordsOptions>)
+BOOST_FIXTURE_TEST_CASE(LimitedRecords, ValidationPolicySignedInterestFixture<MaxRecordCount<3>>)
{
Identity id1 = addSubCertificate("/Security/ValidatorFixture/Sub1", identity);
cache.insert(id1.getDefaultKey().getDefaultCertificate());
@@ -169,20 +165,7 @@
VALIDATE_SUCCESS(i01, "Should succeed despite timestamp is reordered, because record has been evicted");
}
-class UnlimitedRecordsOptions
-{
-public:
- static ValidationPolicySignedInterest::Options
- getOptions()
- {
- ValidationPolicySignedInterest::Options options;
- options.timestampGracePeriod = 15_s;
- options.maxRecordCount = -1;
- return options;
- }
-};
-
-BOOST_FIXTURE_TEST_CASE(UnlimitedRecords, ValidationPolicySignedInterestFixture<UnlimitedRecordsOptions>)
+BOOST_FIXTURE_TEST_CASE(UnlimitedRecords, ValidationPolicySignedInterestFixture<MaxRecordCount<-1>>)
{
std::vector<Identity> identities;
for (size_t i = 0; i < 20; ++i) {
@@ -195,27 +178,15 @@
advanceClocks(1_s);
for (size_t i = 0; i < 20; ++i) {
auto i2 = makeSignedInterest(identities.at(i)); // signed at +1s
-
VALIDATE_SUCCESS(i2, "Should succeed");
rewindClockAfterValidation();
}
+
VALIDATE_FAILURE(i1, "Should fail (timestamp reorder)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
}
-class ZeroRecordsOptions
-{
-public:
- static ValidationPolicySignedInterest::Options
- getOptions()
- {
- ValidationPolicySignedInterest::Options options;
- options.timestampGracePeriod = 15_s;
- options.maxRecordCount = 0;
- return options;
- }
-};
-
-BOOST_FIXTURE_TEST_CASE(ZeroRecords, ValidationPolicySignedInterestFixture<ZeroRecordsOptions>)
+BOOST_FIXTURE_TEST_CASE(ZeroRecords, ValidationPolicySignedInterestFixture<MaxRecordCount<0>>)
{
auto i1 = makeSignedInterest(identity); // signed at 0s
advanceClocks(1_s);
@@ -232,11 +203,11 @@
{
auto i1 = makeSignedInterest(identity, InterestSigner::WantSeqNum);
VALIDATE_FAILURE(i1, "Should fail (timestamp missing)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
}
-class DisabledTimestampValidationOptions
+struct DisabledTimestampValidationOptions
{
-public:
static ValidationPolicySignedInterest::Options
getOptions()
{
@@ -261,30 +232,31 @@
VALIDATE_SUCCESS(i2, "Should succeed");
}
-class GracePeriod15Sec
+template<int secs>
+struct GracePeriodSeconds
{
-public:
static ValidationPolicySignedInterest::Options
getOptions()
{
ValidationPolicySignedInterest::Options options;
- options.timestampGracePeriod = 15_s;
+ options.timestampGracePeriod = time::seconds(secs);
return options;
}
};
-BOOST_FIXTURE_TEST_CASE(TimestampTooOld, ValidationPolicySignedInterestFixture<GracePeriod15Sec>)
+BOOST_FIXTURE_TEST_CASE(TimestampTooOld, ValidationPolicySignedInterestFixture<GracePeriodSeconds<15>>)
{
auto i1 = makeSignedInterest(identity); // signed at 0s
advanceClocks(16_s); // verifying at +16s
VALIDATE_FAILURE(i1, "Should fail (timestamp outside the grace period)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
rewindClockAfterValidation();
auto i2 = makeSignedInterest(identity); // signed at +16s
VALIDATE_SUCCESS(i2, "Should succeed");
}
-BOOST_FIXTURE_TEST_CASE(TimestampTooNew, ValidationPolicySignedInterestFixture<GracePeriod15Sec>)
+BOOST_FIXTURE_TEST_CASE(TimestampTooNew, ValidationPolicySignedInterestFixture<GracePeriodSeconds<15>>)
{
auto i1 = makeSignedInterest(identity); // signed at 0s
advanceClocks(1_s);
@@ -294,10 +266,12 @@
m_systemClock->advance(-18_s); // verifying at -16s
VALIDATE_FAILURE(i1, "Should fail (timestamp outside the grace period)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
rewindClockAfterValidation();
// SignedInterestValidator should not remember i1's timestamp
VALIDATE_FAILURE(i2, "Should fail (timestamp outside the grace period)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
rewindClockAfterValidation();
// SignedInterestValidator should not remember i2's timestamp, and should treat i3 as initial
@@ -315,6 +289,7 @@
si2->setTime(i1.getSignatureInfo()->getTime());
i2.setSignatureInfo(*si2);
VALIDATE_FAILURE(i2, "Should fail (timestamp reordered)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
advanceClocks(2_s);
auto i3 = makeSignedInterest(identity); // signed at +2s
@@ -337,36 +312,25 @@
m_systemClock->advance(-1100_ms); // verifying at 0ms
VALIDATE_FAILURE(i2, "Should fail (timestamp reordered)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
rewindClockAfterValidation();
// SignedInterestValidator should not remember i2's timestamp
advanceClocks(200_ms); // verifying at +200ms
VALIDATE_FAILURE(i3, "Should fail (timestamp reordered)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
rewindClockAfterValidation();
advanceClocks(1200_ms); // verifying at 1400ms
VALIDATE_SUCCESS(i4, "Should succeed");
}
-template<class T>
-class GracePeriod
-{
-public:
- static ValidationPolicySignedInterest::Options
- getOptions()
- {
- ValidationPolicySignedInterest::Options options;
- options.timestampGracePeriod = time::seconds(T::value);
- return options;
- }
-};
+using NonPositiveGracePeriods = boost::mpl::vector<
+ GracePeriodSeconds<0>,
+ GracePeriodSeconds<-1>
+>;
-typedef boost::mpl::vector<
- GracePeriod<boost::mpl::int_<0>>,
- GracePeriod<boost::mpl::int_<-1>>
-> GraceNonPositiveValues;
-
-BOOST_FIXTURE_TEST_CASE_TEMPLATE(GraceNonPositive, GracePeriod, GraceNonPositiveValues,
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(GraceNonPositive, GracePeriod, NonPositiveGracePeriods,
ValidationPolicySignedInterestFixture<GracePeriod>)
{
auto i1 = this->makeSignedInterest(this->identity); // signed at 0ms
@@ -383,6 +347,7 @@
this->advanceClocks(1_ms);
VALIDATE_FAILURE(i2, "Should fail when validating at 1ms");
+ BOOST_TEST(this->lastError.getCode() == ValidationError::POLICY_ERROR);
}
BOOST_AUTO_TEST_SUITE_END() // TimestampValidation
@@ -403,9 +368,8 @@
VALIDATE_SUCCESS(i2, "Should succeed");
}
-class SeqNumValidationOptions
+struct SeqNumValidationOptions
{
-public:
static ValidationPolicySignedInterest::Options
getOptions()
{
@@ -420,6 +384,7 @@
{
auto i1 = makeSignedInterest(identity, InterestSigner::WantTime);
VALIDATE_FAILURE(i1, "Should fail (sequence number missing");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
}
BOOST_FIXTURE_TEST_CASE(SeqNumReorder,
@@ -433,6 +398,7 @@
si2->setSeqNum(i1.getSignatureInfo()->getSeqNum());
i2.setSignatureInfo(*si2);
VALIDATE_FAILURE(i2, "Should fail (sequence number reordered)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
auto i3 = makeSignedInterest(identity, WantAll); // seq num is i+2
VALIDATE_SUCCESS(i3, "Should succeed");
@@ -446,6 +412,7 @@
{
auto i1 = makeSignedInterest(identity, InterestSigner::WantTime); // Specifically exclude nonce
VALIDATE_FAILURE(i1, "Should fail (nonce missing)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
}
BOOST_AUTO_TEST_CASE(DuplicateNonce)
@@ -458,6 +425,7 @@
si2->setNonce(i1.getSignatureInfo()->getNonce());
i2.setSignatureInfo(*si2);
VALIDATE_FAILURE(i2, "Should fail (duplicate nonce)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
auto i3 = makeSignedInterest(identity, WantAll);
// On the off chance that the generated nonce is identical to i1
@@ -467,9 +435,8 @@
VALIDATE_SUCCESS(i3, "Should succeed");
}
-class DisabledNonceValidationOptions
+struct DisabledNonceValidationOptions
{
-public:
static ValidationPolicySignedInterest::Options
getOptions()
{
@@ -499,9 +466,8 @@
VALIDATE_SUCCESS(i3, "Should succeed");
}
-class NonceLimit2Options
+struct NonceLimit2Options
{
-public:
static ValidationPolicySignedInterest::Options
getOptions()
{
@@ -533,6 +499,7 @@
m_keyChain.sign(i3, signingByIdentity(identity).setSignedInterestFormat(SignedInterestFormat::V03)
.setSignatureInfo(*si3));
VALIDATE_FAILURE(i3, "Should fail (duplicate nonce)");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
// Pop i1's nonce off the list
auto i4 = makeSignedInterest(identity, WantAll);
diff --git a/tests/unit/security/validation-policy-simple-hierarchy.t.cpp b/tests/unit/security/validation-policy-simple-hierarchy.t.cpp
index 70fb49e..38ab30c 100644
--- a/tests/unit/security/validation-policy-simple-hierarchy.t.cpp
+++ b/tests/unit/security/validation-policy-simple-hierarchy.t.cpp
@@ -43,10 +43,13 @@
auto packet = Packet::makePacket(name);
VALIDATE_FAILURE(packet, "Unsigned");
+ BOOST_TEST((lastError.getCode() == ValidationError::NO_SIGNATURE || // Interest
+ lastError.getCode() == ValidationError::INVALID_KEY_LOCATOR)); // Data
packet = Packet::makePacket(name);
m_keyChain.sign(packet, signingWithSha256());
VALIDATE_FAILURE(packet, "Should not be accepted, name not prefix of /localhost/identity/digest-sha256");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
packet = Packet::makePacket("/localhost/identity/digest-sha256/foobar");
m_keyChain.sign(packet, signingWithSha256());
@@ -63,15 +66,17 @@
packet = Packet::makePacket(name);
m_keyChain.sign(packet, signingByIdentity(otherIdentity));
VALIDATE_FAILURE(packet, "Should fail, as signed by the policy-violating cert");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
packet = Packet::makePacket(name);
m_keyChain.sign(packet, signingByIdentity(subSelfSignedIdentity));
VALIDATE_FAILURE(packet, "Should fail, because subSelfSignedIdentity is not a trust anchor");
+ BOOST_TEST(lastError.getCode() == ValidationError::LOOP_DETECTED);
// TODO add checks with malformed packets
}
-BOOST_AUTO_TEST_CASE(NonKeyNameInsideLocator)
+BOOST_AUTO_TEST_CASE(CertNameInKeyLocator)
{
// auto cert = identity.getDefaultKey().getDefaultCertificate().wireEncode();
// std::cerr << "Certificate idCert{\"" << toHex(cert) << "\"_block};" << std::endl;
@@ -107,14 +112,13 @@
"483046022100BDD3E0EF2385658825EB73E87A02D1A16AA8ACE50840C1B91782836164AACA3B0221008007B3EBA9"
"B7638BD204766B08AF6E4221CDB88156CC7DA13CD916610D6D3AED"_block};
+ BOOST_REQUIRE_EQUAL(packet.getKeyLocator().value().getName(),
+ "/Security/ValidatorFixture/Sub1/KEY/%D7j1%B0%1E%14%09%2B/parent/%FD%00%00%01I%9DY%8C%A0");
+
this->cache.insert(idCert);
this->cache.insert(subIdCert);
this->validator.loadAnchor("", std::move(idCert));
- BOOST_REQUIRE(packet.getKeyLocator());
- BOOST_CHECK_EQUAL(packet.getKeyLocator()->getName(),
- "/Security/ValidatorFixture/Sub1/KEY/%D7j1%B0%1E%14%09%2B/parent/%FD%00%00%01I%9DY%8C%A0");
-
VALIDATE_SUCCESS(packet, "Should get accepted, as signed by the policy-compliant cert");
}
diff --git a/tests/unit/security/validation-policy.t.cpp b/tests/unit/security/validation-policy.t.cpp
index e982f72..3d76f62 100644
--- a/tests/unit/security/validation-policy.t.cpp
+++ b/tests/unit/security/validation-policy.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2020 Regents of the University of California.
+ * Copyright (c) 2013-2022 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -35,17 +35,21 @@
BOOST_AUTO_TEST_CASE(ExtractIdentityNameFromKeyLocator)
{
auto id = m_keyChain.createIdentity("/random/identity");
-
auto keyName = id.getDefaultKey().getName();
auto certName = id.getDefaultKey().getDefaultCertificate().getName();
- auto partialCertName = id.getDefaultKey().getDefaultCertificate().getName().getPrefix(-1);
+ auto partialCertName = certName.getPrefix(-1);
BOOST_CHECK_EQUAL(extractIdentityNameFromKeyLocator(keyName), "/random/identity");
BOOST_CHECK_EQUAL(extractIdentityNameFromKeyLocator(certName), "/random/identity");
BOOST_CHECK_EQUAL(extractIdentityNameFromKeyLocator(partialCertName), "/random/identity");
+ BOOST_CHECK_EQUAL(extractIdentityNameFromKeyLocator("/KEY"), "/");
- BOOST_CHECK_THROW(extractIdentityNameFromKeyLocator(Name("/name/without/key/component")), std::runtime_error);
- BOOST_CHECK_THROW(extractIdentityNameFromKeyLocator(Name("/name/with/KEY/but/in/a/wrong/place")), std::runtime_error);
+ BOOST_CHECK_THROW(extractIdentityNameFromKeyLocator(Name("/short/name")),
+ KeyLocator::Error);
+ BOOST_CHECK_THROW(extractIdentityNameFromKeyLocator(Name("/name/without/key/component")),
+ KeyLocator::Error);
+ BOOST_CHECK_THROW(extractIdentityNameFromKeyLocator(Name("/name/with/KEY/but/in/a/wrong/place")),
+ KeyLocator::Error);
}
BOOST_AUTO_TEST_SUITE_END() // TestValidationPolicy
diff --git a/tests/unit/security/validator-fixture.cpp b/tests/unit/security/validator-fixture.cpp
index 8048fc4..8579fc8 100644
--- a/tests/unit/security/validator-fixture.cpp
+++ b/tests/unit/security/validator-fixture.cpp
@@ -56,6 +56,12 @@
advanceClocks(s_mockPeriod, s_mockTimes);
}
+void
+ValidatorFixtureBase::rewindClockAfterValidation()
+{
+ m_systemClock->advance(s_mockPeriod * s_mockTimes * -1);
+}
+
Identity
ValidatorFixtureBase::addSubCertificate(const Name& subIdentityName, const Identity& issuer)
{
diff --git a/tests/unit/security/validator-fixture.hpp b/tests/unit/security/validator-fixture.hpp
index b225c53..d8d357f 100644
--- a/tests/unit/security/validator-fixture.hpp
+++ b/tests/unit/security/validator-fixture.hpp
@@ -44,13 +44,11 @@
void
mockNetworkOperations();
- /** \brief undo clock advancement of mockNetworkOperations()
+ /**
+ * @brief Undo clock advancement of mockNetworkOperations()
*/
void
- rewindClockAfterValidation()
- {
- m_systemClock->advance(s_mockPeriod * s_mockTimes * -1);
- }
+ rewindClockAfterValidation();
/**
* @brief Issues a certificate for @p subIdentityName signed by @p issuer
@@ -71,8 +69,8 @@
ValidationError lastError{ValidationError::NO_ERROR};
private:
- const static time::milliseconds s_mockPeriod;
- const static int s_mockTimes;
+ static const time::milliseconds s_mockPeriod;
+ static const int s_mockTimes;
};
template<class ValidationPolicyT, class CertificateFetcherT = CertificateFetcherFromNetwork>
@@ -93,6 +91,7 @@
size_t nCallbacks = 0;
this->validator.validate(packet,
[&] (const Packet&) {
+ lastError = ValidationError::NO_ERROR;
++nCallbacks;
BOOST_CHECK_MESSAGE(expectSuccess,
(expectSuccess ? "OK: " : "FAILED: ") + detailedInfo);
diff --git a/tests/unit/security/validator.t.cpp b/tests/unit/security/validator.t.cpp
index 4acbe4d..842f2f5 100644
--- a/tests/unit/security/validator.t.cpp
+++ b/tests/unit/security/validator.t.cpp
@@ -22,7 +22,7 @@
#include "ndn-cxx/security/validator.hpp"
#include "ndn-cxx/security/validation-policy-simple-hierarchy.hpp"
-#include "tests/boost-test.hpp"
+#include "tests/test-common.hpp"
#include "tests/unit/security/validator-fixture.hpp"
namespace ndn {
@@ -46,33 +46,75 @@
BOOST_CHECK(validator.getPolicy().m_validator != nullptr);
BOOST_CHECK(validator.getPolicy().getInnerPolicy().m_validator != nullptr);
BOOST_CHECK(validator.getPolicy().getInnerPolicy().getInnerPolicy().m_validator != nullptr);
+
+ BOOST_CHECK_THROW(validator.getPolicy().setInnerPolicy(nullptr), std::invalid_argument);
}
-BOOST_AUTO_TEST_CASE(Timeouts)
+BOOST_AUTO_TEST_CASE(BadSignatureInfo)
{
- processInterest = nullptr; // no response for all interests
+ Interest interest("/Security/ValidatorFixture/Sub1/Sub2/Interest");
+ m_keyChain.sign(interest, signingByIdentity(subIdentity)
+ .setSignedInterestFormat(SignedInterestFormat::V03));
+
+ // add an unrecognized critical element inside InterestSignatureInfo
+ auto si = interest.getSignatureInfo().value();
+ si.addCustomTlv("7F00"_block);
+ interest.setSignatureInfo(si);
+ BOOST_REQUIRE_THROW(interest.getSignatureInfo(), tlv::Error);
+ BOOST_REQUIRE_NO_THROW(interest.getSignatureValue());
+
+ VALIDATE_FAILURE(interest, "InterestSignatureInfo decoding should fail");
+ BOOST_TEST(lastError.getCode() == ValidationError::NO_SIGNATURE);
+ BOOST_TEST(face.sentInterests.size() == 0);
+}
+
+BOOST_AUTO_TEST_CASE(BadSignatureValue)
+{
+ const uint8_t sv[] = {0x12, 0x34, 0x56, 0x78};
+
+ Interest interest("/Security/ValidatorFixture/Sub1/Sub2/Interest");
+ m_keyChain.sign(interest, signingByIdentity(subIdentity)
+ .setSignedInterestFormat(SignedInterestFormat::V03));
+ interest.setSignatureValue(sv);
+
+ VALIDATE_FAILURE(interest, "Signature check should fail");
+ BOOST_TEST(lastError.getCode() == ValidationError::INVALID_SIGNATURE);
+ BOOST_TEST(face.sentInterests.size() == 1);
+
+ Data data("/Security/ValidatorFixture/Sub1/Sub2/Data");
+ m_keyChain.sign(data, signingByIdentity(subIdentity));
+ data.setSignatureValue(sv);
+
+ VALIDATE_FAILURE(data, "Signature check should fail");
+ BOOST_TEST(lastError.getCode() == ValidationError::INVALID_SIGNATURE);
+ BOOST_TEST(face.sentInterests.size() == 1);
+}
+
+BOOST_AUTO_TEST_CASE(Timeout)
+{
+ processInterest = nullptr; // no response for any interest
Data data("/Security/ValidatorFixture/Sub1/Sub2/Data");
m_keyChain.sign(data, signingByIdentity(subIdentity));
VALIDATE_FAILURE(data, "Should fail to retrieve certificate");
- BOOST_CHECK_GT(face.sentInterests.size(), 1);
+ BOOST_TEST(lastError.getCode() == ValidationError::CANNOT_RETRIEVE_CERT);
+ BOOST_TEST(face.sentInterests.size() == 4);
}
-BOOST_AUTO_TEST_CASE(NackedInterests)
+BOOST_AUTO_TEST_CASE(Nack)
{
processInterest = [this] (const Interest& interest) {
- lp::Nack nack(interest);
- nack.setReason(lp::NackReason::NO_ROUTE);
- face.receive(nack);
+ face.receive(makeNack(interest, lp::NackReason::NO_ROUTE));
};
Data data("/Security/ValidatorFixture/Sub1/Sub2/Data");
m_keyChain.sign(data, signingByIdentity(subIdentity));
VALIDATE_FAILURE(data, "All interests should get NACKed");
+ BOOST_TEST(lastError.getCode() == ValidationError::CANNOT_RETRIEVE_CERT);
// 1 for the first interest, 3 for the retries on nack
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 4);
+ BOOST_TEST(face.sentInterests.size() == 4);
}
BOOST_AUTO_TEST_CASE(MalformedCert)
@@ -84,7 +126,7 @@
BOOST_REQUIRE_THROW(Certificate(malformedCert.wireEncode()), tlv::Error);
auto originalProcessInterest = processInterest;
- processInterest = [this, &originalProcessInterest, &malformedCert] (const Interest& interest) {
+ processInterest = [&] (const Interest& interest) {
if (interest.getName().isPrefixOf(malformedCert.getName())) {
face.receive(malformedCert);
}
@@ -97,20 +139,20 @@
m_keyChain.sign(data, signingByIdentity(subIdentity));
VALIDATE_FAILURE(data, "Signed by a malformed certificate");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
+ BOOST_TEST(lastError.getCode() == ValidationError::MALFORMED_CERT);
+ BOOST_TEST(face.sentInterests.size() == 1);
}
BOOST_AUTO_TEST_CASE(ExpiredCert)
{
Data expiredCert = subIdentity.getDefaultKey().getDefaultCertificate();
SignatureInfo info;
- info.setValidityPeriod(ValidityPeriod(time::system_clock::now() - 2_h,
- time::system_clock::now() - 1_h));
+ info.setValidityPeriod(ValidityPeriod::makeRelative(-2_h, -1_h));
m_keyChain.sign(expiredCert, signingByIdentity(identity).setSignatureInfo(info));
BOOST_REQUIRE_NO_THROW(Certificate(expiredCert.wireEncode()));
auto originalProcessInterest = processInterest;
- processInterest = [this, &originalProcessInterest, &expiredCert] (const Interest& interest) {
+ processInterest = [&] (const Interest& interest) {
if (interest.getName().isPrefixOf(expiredCert.getName())) {
face.receive(expiredCert);
}
@@ -123,7 +165,8 @@
m_keyChain.sign(data, signingByIdentity(subIdentity));
VALIDATE_FAILURE(data, "Signed by an expired certificate");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
+ BOOST_TEST(lastError.getCode() == ValidationError::EXPIRED_CERT);
+ BOOST_TEST(face.sentInterests.size() == 1);
}
BOOST_AUTO_TEST_CASE(ResetAnchors)
@@ -133,6 +176,7 @@
Data data("/Security/ValidatorFixture/Sub1/Sub2/Data");
m_keyChain.sign(data, signingByIdentity(subIdentity));
VALIDATE_FAILURE(data, "Should fail, as no anchors configured");
+ BOOST_TEST(lastError.getCode() == ValidationError::LOOP_DETECTED);
}
BOOST_AUTO_TEST_CASE(TrustedCertCaching)
@@ -141,23 +185,23 @@
m_keyChain.sign(data, signingByIdentity(subIdentity));
VALIDATE_SUCCESS(data, "Should get accepted, as signed by the policy-compliant cert");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
+ BOOST_TEST(face.sentInterests.size() == 1);
face.sentInterests.clear();
processInterest = nullptr; // disable data responses from mocked network
VALIDATE_SUCCESS(data, "Should get accepted, based on the cached trusted cert");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
+ BOOST_TEST(face.sentInterests.size() == 0);
face.sentInterests.clear();
advanceClocks(1_h, 2); // expire trusted cache
VALIDATE_FAILURE(data, "Should try and fail to retrieve certs");
- BOOST_CHECK_GT(face.sentInterests.size(), 1);
- face.sentInterests.clear();
+ BOOST_TEST(lastError.getCode() == ValidationError::CANNOT_RETRIEVE_CERT);
+ BOOST_TEST(face.sentInterests.size() > 1);
}
-BOOST_AUTO_TEST_CASE(ResetVerifiedCertificates)
+BOOST_AUTO_TEST_CASE(ResetVerifiedCerts)
{
Data data("/Security/ValidatorFixture/Sub1/Sub2/Data");
m_keyChain.sign(data, signingByIdentity(subIdentity));
@@ -170,6 +214,7 @@
// reset trusted cache
validator.resetVerifiedCertificates();
VALIDATE_FAILURE(data, "Should fail, as no trusted cache or anchors");
+ BOOST_TEST(lastError.getCode() == ValidationError::LOOP_DETECTED);
}
BOOST_AUTO_TEST_CASE(UntrustedCertCaching)
@@ -178,20 +223,22 @@
m_keyChain.sign(data, signingByIdentity(subSelfSignedIdentity));
VALIDATE_FAILURE(data, "Should fail, as signed by the policy-violating cert");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
+ BOOST_TEST(lastError.getCode() == ValidationError::LOOP_DETECTED);
+ BOOST_TEST(face.sentInterests.size() == 1);
face.sentInterests.clear();
processInterest = nullptr; // disable data responses from mocked network
VALIDATE_FAILURE(data, "Should fail again, but no network operations expected");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
+ BOOST_TEST(lastError.getCode() == ValidationError::LOOP_DETECTED);
+ BOOST_TEST(face.sentInterests.size() == 0);
face.sentInterests.clear();
advanceClocks(10_min, 2); // expire untrusted cache
VALIDATE_FAILURE(data, "Should try and fail to retrieve certs");
- BOOST_CHECK_GT(face.sentInterests.size(), 1);
- face.sentInterests.clear();
+ BOOST_TEST(lastError.getCode() == ValidationError::CANNOT_RETRIEVE_CERT);
+ BOOST_TEST(face.sentInterests.size() > 1);
}
class ValidationPolicySimpleHierarchyForInterestOnly : public ValidationPolicySimpleHierarchy
@@ -209,41 +256,45 @@
HierarchicalValidatorFixture<ValidationPolicySimpleHierarchyForInterestOnly>)
{
Interest interest("/Security/ValidatorFixture/Sub1/Sub2/Interest");
- Data data("/Security/ValidatorFixture/Sub1/Sub2/Interest");
+ Data data("/Security/ValidatorFixture/Sub1/Sub2/Data");
VALIDATE_FAILURE(interest, "Unsigned");
- VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
+ BOOST_TEST(lastError.getCode() == ValidationError::NO_SIGNATURE);
+ VALIDATE_SUCCESS(data, "Policy bypasses validation for all data");
+ BOOST_TEST(face.sentInterests.size() == 0);
face.sentInterests.clear();
interest = Interest("/Security/ValidatorFixture/Sub1/Sub2/Interest");
m_keyChain.sign(interest, signingWithSha256());
m_keyChain.sign(data, signingWithSha256());
VALIDATE_FAILURE(interest, "Required KeyLocator/Name missing (not passed to policy)");
- VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
+ VALIDATE_SUCCESS(data, "Policy bypasses validation for all data");
+ BOOST_TEST(face.sentInterests.size() == 0);
face.sentInterests.clear();
m_keyChain.sign(interest, signingByIdentity(identity));
m_keyChain.sign(data, signingByIdentity(identity));
VALIDATE_SUCCESS(interest, "Should get accepted, as signed by the anchor");
- VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
+ VALIDATE_SUCCESS(data, "Policy bypasses validation for all data");
+ BOOST_TEST(face.sentInterests.size() == 0);
face.sentInterests.clear();
m_keyChain.sign(interest, signingByIdentity(subIdentity));
m_keyChain.sign(data, signingByIdentity(subIdentity));
VALIDATE_FAILURE(interest, "Should fail, as policy is not allowed to create new trust anchors");
- VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
+ VALIDATE_SUCCESS(data, "Policy bypasses validation for all data");
+ BOOST_TEST(face.sentInterests.size() == 1);
face.sentInterests.clear();
m_keyChain.sign(interest, signingByIdentity(otherIdentity));
m_keyChain.sign(data, signingByIdentity(otherIdentity));
VALIDATE_FAILURE(interest, "Should fail, as signed by the policy-violating cert");
- VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data");
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
+ VALIDATE_SUCCESS(data, "Policy bypasses validation for all data");
// no network operations expected, as certificate is not validated by the policy
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
+ BOOST_TEST(face.sentInterests.size() == 0);
face.sentInterests.clear();
advanceClocks(1_h, 2); // expire trusted cache
@@ -251,8 +302,9 @@
m_keyChain.sign(interest, signingByIdentity(subSelfSignedIdentity));
m_keyChain.sign(data, signingByIdentity(subSelfSignedIdentity));
VALIDATE_FAILURE(interest, "Should fail, as policy is not allowed to create new trust anchors");
- VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
+ BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
+ VALIDATE_SUCCESS(data, "Policy bypasses validation for all data");
+ BOOST_TEST(face.sentInterests.size() == 1);
face.sentInterests.clear();
}
@@ -272,13 +324,15 @@
};
Data data("/Security/ValidatorFixture/Sub1/Sub2/Data");
- m_keyChain.sign(data, signingByIdentity(subIdentity).setSignatureInfo(
- SignatureInfo().setKeyLocator(subIdentity.getDefaultKey().getName())));
+ m_keyChain.sign(data, signingByIdentity(subIdentity)
+ .setSignatureInfo(SignatureInfo()
+ .setKeyLocator(subIdentity.getDefaultKey().getName())));
validator.setMaxDepth(40);
BOOST_CHECK_EQUAL(validator.getMaxDepth(), 40);
VALIDATE_FAILURE(data, "Should fail, as certificate should be looped");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 40);
+ BOOST_TEST(lastError.getCode() == ValidationError::EXCEEDED_DEPTH_LIMIT);
+ BOOST_TEST(face.sentInterests.size() == 40);
face.sentInterests.clear();
advanceClocks(1_h, 5); // expire caches
@@ -286,7 +340,8 @@
validator.setMaxDepth(30);
BOOST_CHECK_EQUAL(validator.getMaxDepth(), 30);
VALIDATE_FAILURE(data, "Should fail, as certificate chain is infinite");
- BOOST_CHECK_EQUAL(face.sentInterests.size(), 30);
+ BOOST_TEST(lastError.getCode() == ValidationError::EXCEEDED_DEPTH_LIMIT);
+ BOOST_TEST(face.sentInterests.size() == 30);
}
BOOST_AUTO_TEST_CASE(LoopedCertChain)
@@ -313,7 +368,8 @@
Data data("/loop/Data");
m_keyChain.sign(data, signingByKey(k1));
VALIDATE_FAILURE(data, "Should fail, as certificate chain loops");
- BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 3);
+ BOOST_TEST(lastError.getCode() == ValidationError::LOOP_DETECTED);
+ BOOST_TEST_REQUIRE(face.sentInterests.size() == 3);
BOOST_CHECK_EQUAL(face.sentInterests[0].getName(), k1.getDefaultCertificate().getName());
BOOST_CHECK_EQUAL(face.sentInterests[1].getName(), k2.getName());
BOOST_CHECK_EQUAL(face.sentInterests[2].getName(), k3.getName());