533 lines
19 KiB
C++
533 lines
19 KiB
C++
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
|
/*
|
|
* Copyright (c) 2013-2023 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 "ndn-cxx/security/validation-policy-command-interest.hpp"
|
|
|
|
#include "ndn-cxx/security/interest-signer.hpp"
|
|
#include "ndn-cxx/security/validation-policy-accept-all.hpp"
|
|
#include "ndn-cxx/security/validation-policy-simple-hierarchy.hpp"
|
|
|
|
#include "tests/test-common.hpp"
|
|
#include "tests/unit/security/validator-fixture.hpp"
|
|
|
|
#include <boost/mp11/list.hpp>
|
|
|
|
namespace ndn::tests {
|
|
|
|
using namespace ndn::security;
|
|
|
|
BOOST_AUTO_TEST_SUITE(Security)
|
|
|
|
struct CommandInterestDefaultOptions
|
|
{
|
|
static ValidationPolicyCommandInterest::Options
|
|
getOptions()
|
|
{
|
|
return {};
|
|
}
|
|
};
|
|
|
|
template<class T, class InnerPolicy>
|
|
class CommandInterestPolicyWrapper : public ValidationPolicyCommandInterest
|
|
{
|
|
public:
|
|
CommandInterestPolicyWrapper()
|
|
: ValidationPolicyCommandInterest(make_unique<InnerPolicy>(), T::getOptions())
|
|
{
|
|
}
|
|
};
|
|
|
|
template<class T, class InnerPolicy = ValidationPolicySimpleHierarchy>
|
|
class ValidationPolicyCommandInterestFixture
|
|
: public HierarchicalValidatorFixture<CommandInterestPolicyWrapper<T, InnerPolicy>>
|
|
{
|
|
protected:
|
|
Interest
|
|
makeCommandInterest(const Identity& id, SignedInterestFormat format = SignedInterestFormat::V02)
|
|
{
|
|
Name name = id.getName();
|
|
name.append("CMD");
|
|
switch (format) {
|
|
case SignedInterestFormat::V02:
|
|
return m_signer.makeCommandInterest(name, signingByIdentity(id));
|
|
case SignedInterestFormat::V03: {
|
|
Interest interest(name);
|
|
m_signer.makeSignedInterest(interest, signingByIdentity(id));
|
|
return interest;
|
|
}
|
|
}
|
|
NDN_CXX_UNREACHABLE;
|
|
}
|
|
|
|
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(BasicV02)
|
|
{
|
|
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, SignedInterestFormat::V02);
|
|
VALIDATE_SUCCESS(i2, "Should succeed (timestamp larger than previous)");
|
|
|
|
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(BasicV03)
|
|
{
|
|
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, 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(DataPassthrough)
|
|
{
|
|
Data d1("/Security/ValidatorFixture/Sub1");
|
|
m_keyChain.sign(d1);
|
|
VALIDATE_SUCCESS(d1, "Should succeed (fallback on inner validation policy for data)");
|
|
}
|
|
|
|
using ValidationPolicyAcceptAllCommands = ValidationPolicyCommandInterestFixture<CommandInterestDefaultOptions,
|
|
ValidationPolicyAcceptAll>;
|
|
|
|
BOOST_FIXTURE_TEST_CASE(SignedWithSha256, ValidationPolicyAcceptAllCommands) // Bug 4635
|
|
{
|
|
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());
|
|
VALIDATE_SUCCESS(i2, "Should succeed (timestamp larger than previous)");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // Accepts
|
|
|
|
BOOST_AUTO_TEST_SUITE(Rejects)
|
|
|
|
BOOST_AUTO_TEST_CASE(NotSigned)
|
|
{
|
|
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::MALFORMED_SIGNATURE);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(BadSigInfo)
|
|
{
|
|
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::MALFORMED_SIGNATURE);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(BadTimestampV02)
|
|
{
|
|
// 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(std::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(std::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, SignedInterestFormat::V02);
|
|
KeyLocator kl;
|
|
kl.setKeyDigest(makeBinaryBlock(tlv::KeyDigest, {0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD}));
|
|
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, 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, 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);
|
|
}
|
|
|
|
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<GracePeriodSeconds<15>>)
|
|
{
|
|
auto i1 = makeCommandInterest(identity); // signed at 0s
|
|
advanceClocks(1_s);
|
|
auto i2 = makeCommandInterest(identity); // signed at +1s
|
|
advanceClocks(1_s);
|
|
auto i3 = makeCommandInterest(identity); // signed at +2s
|
|
|
|
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
|
|
advanceClocks(18_s); // verifying at +2s
|
|
VALIDATE_SUCCESS(i3, "Should succeed");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TimestampReorderEqual)
|
|
{
|
|
auto i1 = makeCommandInterest(identity); // signed at 0s
|
|
VALIDATE_SUCCESS(i1, "Should succeed");
|
|
|
|
auto i2 = makeCommandInterest(identity); // signed at 0s
|
|
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
|
|
VALIDATE_SUCCESS(i3, "Should succeed");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TimestampReorderNegative)
|
|
{
|
|
auto i2 = makeCommandInterest(identity); // signed at 0ms
|
|
advanceClocks(200_ms);
|
|
auto i3 = makeCommandInterest(identity); // signed at +200ms
|
|
advanceClocks(900_ms);
|
|
auto i1 = makeCommandInterest(identity); // signed at +1100ms
|
|
advanceClocks(300_ms);
|
|
auto i4 = makeCommandInterest(identity); // signed at +1400ms
|
|
|
|
m_systemClock->advance(-300_ms); // verifying at +1100ms
|
|
VALIDATE_SUCCESS(i1, "Should succeed");
|
|
rewindClockAfterValidation();
|
|
|
|
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
|
|
VALIDATE_SUCCESS(i4, "Should succeed");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // Rejects
|
|
|
|
BOOST_AUTO_TEST_SUITE(Options)
|
|
|
|
using NonPositiveGracePeriods = boost::mp11::mp_list<GracePeriodSeconds<0>, GracePeriodSeconds<-1>>;
|
|
|
|
BOOST_FIXTURE_TEST_CASE_TEMPLATE(GraceNonPositive, GracePeriod, NonPositiveGracePeriods,
|
|
ValidationPolicyCommandInterestFixture<GracePeriod>)
|
|
{
|
|
auto i1 = this->makeCommandInterest(this->identity); // signed at 0ms
|
|
auto i2 = this->makeCommandInterest(this->subIdentity); // signed at 0ms
|
|
for (auto interest : {&i1, &i2}) {
|
|
setNameComponent(*interest, command_interest::POS_TIMESTAMP,
|
|
name::Component::fromNumber(time::toUnixTimestamp(time::system_clock::now()).count()));
|
|
} // ensure timestamps are exactly 0ms
|
|
|
|
VALIDATE_SUCCESS(i1, "Should succeed when validating at 0ms");
|
|
this->rewindClockAfterValidation();
|
|
|
|
this->advanceClocks(1_ms);
|
|
VALIDATE_FAILURE(i2, "Should fail when validating at 1ms");
|
|
BOOST_TEST(this->lastError.getCode() == ValidationError::POLICY_ERROR);
|
|
}
|
|
|
|
class LimitedRecordsOptions
|
|
{
|
|
public:
|
|
static ValidationPolicyCommandInterest::Options
|
|
getOptions()
|
|
{
|
|
ValidationPolicyCommandInterest::Options options;
|
|
options.gracePeriod = 15_s;
|
|
options.maxRecords = 3;
|
|
return options;
|
|
}
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_CASE(LimitedRecords, ValidationPolicyCommandInterestFixture<LimitedRecordsOptions>)
|
|
{
|
|
Identity id1 = this->addSubCertificate("/Security/ValidatorFixture/Sub1", identity);
|
|
this->cache.insert(id1.getDefaultKey().getDefaultCertificate());
|
|
Identity id2 = this->addSubCertificate("/Security/ValidatorFixture/Sub2", identity);
|
|
this->cache.insert(id2.getDefaultKey().getDefaultCertificate());
|
|
Identity id3 = this->addSubCertificate("/Security/ValidatorFixture/Sub3", identity);
|
|
this->cache.insert(id3.getDefaultKey().getDefaultCertificate());
|
|
Identity id4 = this->addSubCertificate("/Security/ValidatorFixture/Sub4", identity);
|
|
this->cache.insert(id4.getDefaultKey().getDefaultCertificate());
|
|
|
|
auto i1 = makeCommandInterest(id2);
|
|
auto i2 = makeCommandInterest(id3);
|
|
auto i3 = makeCommandInterest(id4);
|
|
auto i00 = makeCommandInterest(id1); // signed at 0s
|
|
advanceClocks(1_s);
|
|
auto i01 = makeCommandInterest(id1); // signed at 1s
|
|
advanceClocks(1_s);
|
|
auto i02 = makeCommandInterest(id1); // signed at 2s
|
|
|
|
VALIDATE_SUCCESS(i00, "Should succeed");
|
|
rewindClockAfterValidation();
|
|
|
|
VALIDATE_SUCCESS(i02, "Should succeed");
|
|
rewindClockAfterValidation();
|
|
|
|
VALIDATE_SUCCESS(i1, "Should succeed");
|
|
rewindClockAfterValidation();
|
|
|
|
VALIDATE_SUCCESS(i2, "Should succeed");
|
|
rewindClockAfterValidation();
|
|
|
|
VALIDATE_SUCCESS(i3, "Should succeed, forgets identity id1");
|
|
rewindClockAfterValidation();
|
|
|
|
VALIDATE_SUCCESS(i01, "Should succeed despite timestamp is reordered, because record has been evicted");
|
|
}
|
|
|
|
class UnlimitedRecordsOptions
|
|
{
|
|
public:
|
|
static ValidationPolicyCommandInterest::Options
|
|
getOptions()
|
|
{
|
|
ValidationPolicyCommandInterest::Options options;
|
|
options.gracePeriod = 15_s;
|
|
options.maxRecords = -1;
|
|
return options;
|
|
}
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_CASE(UnlimitedRecords, ValidationPolicyCommandInterestFixture<UnlimitedRecordsOptions>)
|
|
{
|
|
std::vector<Identity> identities;
|
|
for (size_t i = 0; i < 20; ++i) {
|
|
Identity id = this->addSubCertificate("/Security/ValidatorFixture/Sub" + to_string(i), identity);
|
|
this->cache.insert(id.getDefaultKey().getDefaultCertificate());
|
|
identities.push_back(id);
|
|
}
|
|
|
|
auto i1 = makeCommandInterest(identities.at(0)); // signed at 0s
|
|
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
|
|
{
|
|
public:
|
|
static ValidationPolicyCommandInterest::Options
|
|
getOptions()
|
|
{
|
|
ValidationPolicyCommandInterest::Options options;
|
|
options.gracePeriod = 15_s;
|
|
options.maxRecords = 0;
|
|
return options;
|
|
}
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_CASE(ZeroRecords, ValidationPolicyCommandInterestFixture<ZeroRecordsOptions>)
|
|
{
|
|
auto i1 = makeCommandInterest(identity); // signed at 0s
|
|
advanceClocks(1_s);
|
|
auto i2 = makeCommandInterest(identity); // signed at +1s
|
|
VALIDATE_SUCCESS(i2, "Should succeed");
|
|
rewindClockAfterValidation();
|
|
|
|
VALIDATE_SUCCESS(i1, "Should succeed despite timestamp is reordered, because record isn't kept");
|
|
}
|
|
|
|
class LimitedRecordLifetimeOptions
|
|
{
|
|
public:
|
|
static ValidationPolicyCommandInterest::Options
|
|
getOptions()
|
|
{
|
|
ValidationPolicyCommandInterest::Options options;
|
|
options.gracePeriod = 400_s;
|
|
options.recordLifetime = 300_s;
|
|
return options;
|
|
}
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_CASE(LimitedRecordLifetime, ValidationPolicyCommandInterestFixture<LimitedRecordLifetimeOptions>)
|
|
{
|
|
auto i1 = makeCommandInterest(identity); // signed at 0s
|
|
advanceClocks(240_s);
|
|
auto i2 = makeCommandInterest(identity); // signed at +240s
|
|
advanceClocks(120_s);
|
|
auto i3 = makeCommandInterest(identity); // signed at +360s
|
|
|
|
m_systemClock->advance(-360_s); // rewind system clock to 0s
|
|
VALIDATE_SUCCESS(i1, "Should succeed");
|
|
rewindClockAfterValidation();
|
|
|
|
VALIDATE_SUCCESS(i3, "Should succeed");
|
|
rewindClockAfterValidation();
|
|
|
|
advanceClocks(30_s, 301_s); // advance steady clock by 301s, and system clock to +301s
|
|
VALIDATE_SUCCESS(i2, "Should succeed despite timestamp is reordered, because record has been expired");
|
|
}
|
|
|
|
class ZeroRecordLifetimeOptions
|
|
{
|
|
public:
|
|
static ValidationPolicyCommandInterest::Options
|
|
getOptions()
|
|
{
|
|
ValidationPolicyCommandInterest::Options options;
|
|
options.gracePeriod = 15_s;
|
|
options.recordLifetime = time::seconds::zero();
|
|
return options;
|
|
}
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_CASE(ZeroRecordLifetime, ValidationPolicyCommandInterestFixture<ZeroRecordLifetimeOptions>)
|
|
{
|
|
auto i1 = makeCommandInterest(identity); // signed at 0s
|
|
advanceClocks(1_s);
|
|
auto i2 = makeCommandInterest(identity); // signed at +1s
|
|
VALIDATE_SUCCESS(i2, "Should succeed");
|
|
rewindClockAfterValidation();
|
|
|
|
VALIDATE_SUCCESS(i1, "Should succeed despite timestamp is reordered, because record has been expired");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // Options
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // TestValidationPolicyCommandInterest
|
|
BOOST_AUTO_TEST_SUITE_END() // Security
|
|
|
|
} // namespace ndn::tests
|