523 lines
18 KiB
C++
523 lines
18 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-signed-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 SignedInterestDefaultOptions
|
|
{
|
|
static ValidationPolicySignedInterest::Options
|
|
getOptions()
|
|
{
|
|
return {};
|
|
}
|
|
};
|
|
|
|
template<class T, class InnerPolicy>
|
|
class SignedInterestPolicyWrapper : public ValidationPolicySignedInterest
|
|
{
|
|
public:
|
|
SignedInterestPolicyWrapper()
|
|
: ValidationPolicySignedInterest(make_unique<InnerPolicy>(), T::getOptions())
|
|
{
|
|
}
|
|
};
|
|
|
|
template<class T, class InnerPolicy = ValidationPolicySimpleHierarchy>
|
|
class ValidationPolicySignedInterestFixture
|
|
: public HierarchicalValidatorFixture<SignedInterestPolicyWrapper<T, InnerPolicy>>
|
|
{
|
|
protected:
|
|
Interest
|
|
makeSignedInterest(const Identity& identity,
|
|
uint32_t signingFlags = InterestSigner::WantNonce | InterestSigner::WantTime)
|
|
{
|
|
Interest i(Name(identity.getName()).append("CMD"));
|
|
m_signer.makeSignedInterest(i, signingByIdentity(identity), signingFlags);
|
|
return i;
|
|
}
|
|
|
|
protected:
|
|
InterestSigner m_signer{this->m_keyChain};
|
|
|
|
static constexpr uint32_t WantAll = InterestSigner::WantNonce |
|
|
InterestSigner::WantTime |
|
|
InterestSigner::WantSeqNum;
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(TestValidationPolicySignedInterest,
|
|
ValidationPolicySignedInterestFixture<SignedInterestDefaultOptions>)
|
|
|
|
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);
|
|
VALIDATE_SUCCESS(i2, "Should succeed (timestamp and sequence number 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)");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(InnerPolicyReject)
|
|
{
|
|
auto i1 = makeSignedInterest(otherIdentity);
|
|
VALIDATE_FAILURE(i1, "Should fail (inner policy should reject)");
|
|
BOOST_TEST(lastError.getCode() == ValidationError::LOOP_DETECTED);
|
|
}
|
|
|
|
template<ssize_t count>
|
|
struct MaxRecordCount
|
|
{
|
|
static ValidationPolicySignedInterest::Options
|
|
getOptions()
|
|
{
|
|
ValidationPolicySignedInterest::Options options;
|
|
options.timestampGracePeriod = 15_s;
|
|
options.maxRecordCount = count;
|
|
return options;
|
|
}
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_CASE(LimitedRecords, ValidationPolicySignedInterestFixture<MaxRecordCount<3>>)
|
|
{
|
|
Identity id1 = addSubCertificate("/Security/ValidatorFixture/Sub1", identity);
|
|
cache.insert(id1.getDefaultKey().getDefaultCertificate());
|
|
Identity id2 = addSubCertificate("/Security/ValidatorFixture/Sub2", identity);
|
|
cache.insert(id2.getDefaultKey().getDefaultCertificate());
|
|
Identity id3 = addSubCertificate("/Security/ValidatorFixture/Sub3", identity);
|
|
cache.insert(id3.getDefaultKey().getDefaultCertificate());
|
|
Identity id4 = addSubCertificate("/Security/ValidatorFixture/Sub4", identity);
|
|
cache.insert(id4.getDefaultKey().getDefaultCertificate());
|
|
|
|
auto i1 = makeSignedInterest(id2);
|
|
auto i2 = makeSignedInterest(id3);
|
|
auto i3 = makeSignedInterest(id4);
|
|
auto i00 = makeSignedInterest(id1); // signed at 0s
|
|
advanceClocks(1_s);
|
|
auto i01 = makeSignedInterest(id1); // signed at 1s
|
|
advanceClocks(1_s);
|
|
auto i02 = makeSignedInterest(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");
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(UnlimitedRecords, ValidationPolicySignedInterestFixture<MaxRecordCount<-1>>)
|
|
{
|
|
std::vector<Identity> identities;
|
|
for (size_t i = 0; i < 20; ++i) {
|
|
Identity id = addSubCertificate("/Security/ValidatorFixture/Sub" + to_string(i), identity);
|
|
cache.insert(id.getDefaultKey().getDefaultCertificate());
|
|
identities.push_back(id);
|
|
}
|
|
|
|
auto i1 = makeSignedInterest(identities.at(0)); // signed at 0s
|
|
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);
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(ZeroRecords, ValidationPolicySignedInterestFixture<MaxRecordCount<0>>)
|
|
{
|
|
auto i1 = makeSignedInterest(identity); // signed at 0s
|
|
advanceClocks(1_s);
|
|
auto i2 = makeSignedInterest(identity); // signed at +1s
|
|
VALIDATE_SUCCESS(i2, "Should succeed");
|
|
rewindClockAfterValidation();
|
|
|
|
VALIDATE_SUCCESS(i1, "Should succeed despite timestamp reordering, as records aren't kept");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE(TimestampValidation)
|
|
|
|
BOOST_AUTO_TEST_CASE(MissingTimestamp)
|
|
{
|
|
auto i1 = makeSignedInterest(identity, InterestSigner::WantSeqNum);
|
|
VALIDATE_FAILURE(i1, "Should fail (timestamp missing)");
|
|
BOOST_TEST(lastError.getCode() == ValidationError::POLICY_ERROR);
|
|
}
|
|
|
|
struct DisabledTimestampValidationOptions
|
|
{
|
|
static ValidationPolicySignedInterest::Options
|
|
getOptions()
|
|
{
|
|
ValidationPolicySignedInterest::Options options;
|
|
options.shouldValidateTimestamps = false;
|
|
return options;
|
|
}
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_CASE(Disabled,
|
|
ValidationPolicySignedInterestFixture<DisabledTimestampValidationOptions>)
|
|
{
|
|
auto i1 = makeSignedInterest(identity); // signed at 0ms
|
|
advanceClocks(100_ms);
|
|
VALIDATE_SUCCESS(i1, "Should succeed");
|
|
|
|
auto i2 = makeSignedInterest(identity); // signed at +100ms
|
|
// Set i2 to have same timestamp as i1
|
|
auto si2 = i2.getSignatureInfo();
|
|
si2->setTime(i2.getSignatureInfo()->getTime());
|
|
i2.setSignatureInfo(*si2);
|
|
VALIDATE_SUCCESS(i2, "Should succeed");
|
|
}
|
|
|
|
template<int secs>
|
|
struct GracePeriodSeconds
|
|
{
|
|
static ValidationPolicySignedInterest::Options
|
|
getOptions()
|
|
{
|
|
ValidationPolicySignedInterest::Options options;
|
|
options.timestampGracePeriod = time::seconds(secs);
|
|
return options;
|
|
}
|
|
};
|
|
|
|
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<GracePeriodSeconds<15>>)
|
|
{
|
|
auto i1 = makeSignedInterest(identity); // signed at 0s
|
|
advanceClocks(1_s);
|
|
auto i2 = makeSignedInterest(identity); // signed at +1s
|
|
advanceClocks(1_s);
|
|
auto i3 = makeSignedInterest(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();
|
|
|
|
// 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
|
|
advanceClocks(18_s); // verifying at +2s
|
|
VALIDATE_SUCCESS(i3, "Should succeed");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TimestampReorderEqual)
|
|
{
|
|
auto i1 = makeSignedInterest(identity); // signed at 0s
|
|
VALIDATE_SUCCESS(i1, "Should succeed");
|
|
|
|
auto i2 = makeSignedInterest(identity); // signed at 0s
|
|
auto si2 = i2.getSignatureInfo();
|
|
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
|
|
VALIDATE_SUCCESS(i3, "Should succeed");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TimestampReorderNegative)
|
|
{
|
|
auto i2 = makeSignedInterest(identity); // signed at 0ms
|
|
advanceClocks(200_ms);
|
|
auto i3 = makeSignedInterest(identity); // signed at +200ms
|
|
advanceClocks(900_ms);
|
|
auto i1 = makeSignedInterest(identity); // signed at +1100ms
|
|
advanceClocks(300_ms);
|
|
auto i4 = makeSignedInterest(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();
|
|
|
|
// 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");
|
|
}
|
|
|
|
using NonPositiveGracePeriods = boost::mp11::mp_list<GracePeriodSeconds<0>, GracePeriodSeconds<-1>>;
|
|
|
|
BOOST_FIXTURE_TEST_CASE_TEMPLATE(GraceNonPositive, GracePeriod, NonPositiveGracePeriods,
|
|
ValidationPolicySignedInterestFixture<GracePeriod>)
|
|
{
|
|
auto i1 = this->makeSignedInterest(this->identity); // signed at 0ms
|
|
auto i2 = this->makeSignedInterest(this->subIdentity); // signed at 0ms
|
|
// ensure timestamps are exactly 0ms
|
|
for (auto interest : {&i1, &i2}) {
|
|
auto si = interest->getSignatureInfo();
|
|
si->setTime(time::system_clock::now());
|
|
interest->setSignatureInfo(*si);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // TimestampValidation
|
|
|
|
BOOST_AUTO_TEST_SUITE(SeqNumValidation)
|
|
|
|
// By default, sequence number validation is disabled
|
|
BOOST_AUTO_TEST_CASE(Disabled)
|
|
{
|
|
auto i1 = makeSignedInterest(identity, WantAll); // signed at 0ms
|
|
VALIDATE_SUCCESS(i1, "Should succeed");
|
|
|
|
auto i2 = makeSignedInterest(identity, WantAll); // signed at +100ms
|
|
// Set i2 to have same seq num as i1
|
|
auto si2 = i2.getSignatureInfo();
|
|
si2->setSeqNum(i2.getSignatureInfo()->getSeqNum());
|
|
i2.setSignatureInfo(*si2);
|
|
VALIDATE_SUCCESS(i2, "Should succeed");
|
|
}
|
|
|
|
struct SeqNumValidationOptions
|
|
{
|
|
static ValidationPolicySignedInterest::Options
|
|
getOptions()
|
|
{
|
|
ValidationPolicySignedInterest::Options options;
|
|
options.shouldValidateSeqNums = true;
|
|
return options;
|
|
}
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_CASE(MissingSeqNum,
|
|
ValidationPolicySignedInterestFixture<SeqNumValidationOptions>)
|
|
{
|
|
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,
|
|
ValidationPolicySignedInterestFixture<SeqNumValidationOptions>)
|
|
{
|
|
auto i1 = makeSignedInterest(identity, WantAll); // seq num is i
|
|
VALIDATE_SUCCESS(i1, "Should succeed");
|
|
|
|
auto i2 = makeSignedInterest(identity, WantAll); // seq num is i+1
|
|
auto si2 = i2.getSignatureInfo();
|
|
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");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // SeqNumValidation
|
|
|
|
BOOST_AUTO_TEST_SUITE(NonceValidation)
|
|
|
|
BOOST_AUTO_TEST_CASE(MissingNonce)
|
|
{
|
|
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)
|
|
{
|
|
auto i1 = makeSignedInterest(identity, WantAll);
|
|
VALIDATE_SUCCESS(i1, "Should succeed");
|
|
|
|
auto i2 = makeSignedInterest(identity, WantAll);
|
|
auto si2 = i2.getSignatureInfo();
|
|
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
|
|
while (i3.getSignatureInfo()->getNonce() == i1.getSignatureInfo()->getNonce()) {
|
|
i3 = makeSignedInterest(identity, WantAll);
|
|
}
|
|
VALIDATE_SUCCESS(i3, "Should succeed");
|
|
}
|
|
|
|
struct DisabledNonceValidationOptions
|
|
{
|
|
static ValidationPolicySignedInterest::Options
|
|
getOptions()
|
|
{
|
|
ValidationPolicySignedInterest::Options options;
|
|
options.shouldValidateNonces = false;
|
|
return options;
|
|
}
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_CASE(Disabled,
|
|
ValidationPolicySignedInterestFixture<DisabledNonceValidationOptions>)
|
|
{
|
|
auto i1 = makeSignedInterest(identity, WantAll ^ InterestSigner::WantNonce);
|
|
VALIDATE_SUCCESS(i1, "Should succeed");
|
|
|
|
// Ensure still works when a nonce is present
|
|
auto i2 = makeSignedInterest(identity, WantAll);
|
|
VALIDATE_SUCCESS(i2, "Should succeed");
|
|
|
|
// Ensure a duplicate still succeeds
|
|
auto i3 = makeSignedInterest(identity, WantAll);
|
|
auto si3 = i3.getSignatureInfo();
|
|
si3->setNonce(i2.getSignatureInfo()->getNonce());
|
|
i3.setSignatureInfo(*si3);
|
|
m_keyChain.sign(i3, signingByIdentity(identity).setSignedInterestFormat(SignedInterestFormat::V03)
|
|
.setSignatureInfo(*si3));
|
|
VALIDATE_SUCCESS(i3, "Should succeed");
|
|
}
|
|
|
|
struct NonceLimit2Options
|
|
{
|
|
static ValidationPolicySignedInterest::Options
|
|
getOptions()
|
|
{
|
|
ValidationPolicySignedInterest::Options options;
|
|
options.shouldValidateTimestamps = false;
|
|
options.shouldValidateSeqNums = false;
|
|
options.maxNonceRecordCount = 2;
|
|
return options;
|
|
}
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_CASE(NonceRecordLimit,
|
|
ValidationPolicySignedInterestFixture<NonceLimit2Options>)
|
|
{
|
|
auto i1 = makeSignedInterest(identity, WantAll);
|
|
VALIDATE_SUCCESS(i1, "Should succeed");
|
|
|
|
auto i2 = makeSignedInterest(identity, WantAll);
|
|
// On the off chance that the generated nonce is identical to i1
|
|
while (i2.getSignatureInfo()->getNonce() == i1.getSignatureInfo()->getNonce()) {
|
|
i2 = makeSignedInterest(identity, WantAll);
|
|
}
|
|
VALIDATE_SUCCESS(i2, "Should succeed");
|
|
|
|
auto i3 = makeSignedInterest(identity, WantAll);
|
|
auto si3 = i3.getSignatureInfo();
|
|
si3->setNonce(i1.getSignatureInfo()->getNonce());
|
|
i3.setSignatureInfo(*si3);
|
|
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);
|
|
// On the off chance that the generated nonce is identical to i1 or i2
|
|
while (i4.getSignatureInfo()->getNonce() == i1.getSignatureInfo()->getNonce() ||
|
|
i4.getSignatureInfo()->getNonce() == i2.getSignatureInfo()->getNonce()) {
|
|
i4 = makeSignedInterest(identity, WantAll);
|
|
}
|
|
VALIDATE_SUCCESS(i4, "Should succeed");
|
|
|
|
// Now i3 should succeed because i1's nonce has been popped off the list
|
|
auto i5 = makeSignedInterest(identity, WantAll);
|
|
auto si5 = i5.getSignatureInfo();
|
|
si5->setNonce(i1.getSignatureInfo()->getNonce());
|
|
i5.setSignatureInfo(*si5);
|
|
m_keyChain.sign(i5, signingByIdentity(identity).setSignedInterestFormat(SignedInterestFormat::V03)
|
|
.setSignatureInfo(*si5));
|
|
VALIDATE_SUCCESS(i5, "Should succeed");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // NonceValidation
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // TestValidationPolicySignedInterest
|
|
BOOST_AUTO_TEST_SUITE_END() // Security
|
|
|
|
} // namespace ndn::tests
|