ndn-js
Version:
A JavaScript client library for Named Data Networking
413 lines (350 loc) • 17.7 kB
JavaScript
/**
* Copyright (C) 2018-2019 Regents of the University of California.
* @author: Jeff Thompson <jefft0@remap.ucla.edu>
* From ndn-cxx unit tests:
* https://github.com/named-data/ndn-cxx/blob/master/tests/unit-tests/security/validation-policy-command-interest.t.cpp
*
* This program 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, with the additional exemption that
* compiling, linking, and/or using OpenSSL is allowed.
*
* This program 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 a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* A copy of the GNU Lesser General Public License is in the file COPYING.
*/
var assert = require("assert");
var Blob = require('../../..').Blob;
var Name = require('../../..').Name;
var Interest = require('../../..').Interest;
var Data = require('../../..').Data;
var Sha256WithRsaSignature = require('../../..').Sha256WithRsaSignature;
var TlvWireFormat = require('../../..').TlvWireFormat;
var KeyLocator = require('../../..').KeyLocator;
var KeyLocatorType = require('../../..').KeyLocatorType;
var SigningInfo = require('../../..').SigningInfo;
var CommandInterestSigner = require('../../..').CommandInterestSigner;
var ValidationPolicyAcceptAll = require('../../..').ValidationPolicyAcceptAll;
var ValidationPolicyCommandInterest = require('../../..').ValidationPolicyCommandInterest;
var ValidationPolicySimpleHierarchy = require('../../..').ValidationPolicySimpleHierarchy;
var HierarchicalValidatorFixture = require('./hierarchical-validator-fixture.js').HierarchicalValidatorFixture;
/**
* @param {ValidationPolicyCommandInterest.Options} options (optional)
* @constructor
*/
var ValidationPolicyCommandInterestFixture = function ValidationPolicyCommandInterestFixture
(options)
{
// Call the base constructor.
HierarchicalValidatorFixture.call(this, new ValidationPolicyCommandInterest
(new ValidationPolicySimpleHierarchy(), options));
this.signer_ = new CommandInterestSigner(this.keyChain_);
};
ValidationPolicyCommandInterestFixture.prototype = new HierarchicalValidatorFixture
(new ValidationPolicyAcceptAll());
ValidationPolicyCommandInterestFixture.prototype.name = "ValidationPolicyCommandInterestFixture";
/**
* @param {PibIdentity} identity
* @returns {Interest}
*/
ValidationPolicyCommandInterestFixture.prototype.makeCommandInterest = function
(identity)
{
return this.signer_.makeCommandInterest
(new Name(identity.getName()).append("CMD"), new SigningInfo(identity));
};
/**
* Set the offset for the validation policy and signer.
* @param {number} nowOffsetMilliseconds The offset in milliseconds.
*/
ValidationPolicyCommandInterestFixture.prototype.setNowOffsetMilliseconds = function
(nowOffsetMilliseconds)
{
this.validator_.getPolicy().setNowOffsetMilliseconds_(nowOffsetMilliseconds);
this.validator_.setCacheNowOffsetMilliseconds_(nowOffsetMilliseconds);
this.signer_.setNowOffsetMilliseconds_(nowOffsetMilliseconds);
};
/**
* @param {Interest} interest
* @param {number} index
* @param {Name.Component|String|Array<number>|ArrayBuffer|Buffer} component
*/
function setNameComponent(interest, index, component)
{
var name = interest.getName().getPrefix(index);
name.append(new Name.Component(component));
name.append(interest.getName().getSubName(name.size()));
interest.setName(name);
}
describe ("TestValidationPolicyCommandInterest", function() {
beforeEach(function() {
this.fixture_ = new ValidationPolicyCommandInterestFixture();
/**
* Call fixture_.validator_.validate and if it calls the failureCallback then
* fail the test with the given message.
* @param {Data|Interest} dataOrInterest The Data or Interest to validate.
* @param {String} message The message to show if the test fails.
*/
this.validateExpectSuccess = function(dataOrInterest, message) {
this.fixture_.validator_.validate
(dataOrInterest,
function(dataOrInterest) {},
function(dataOrInterest, error) { assert.fail('', '', message); });
};
/**
* Call fixture_.validator_.validate and if it calls the successCallback then
* fail the test with the given message.
* @param {Data|Interest} dataOrInterest The Data or Interest to validate.
* @param {String} message The message to show if the test succeeds.
*/
this.validateExpectFailure = function(dataOrInterest, message) {
this.fixture_.validator_.validate
(dataOrInterest,
function(dataOrInterest) { assert.fail('', '', message); },
function(dataOrInterest, error) {});
};
});
it("Basic", function() {
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
this.validateExpectSuccess(interest1, "Should succeed (within grace period)");
this.fixture_.setNowOffsetMilliseconds(5 * 1000.0);
var interest2 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
this.validateExpectSuccess(interest2,
"Should succeed (timestamp larger than previous)");
});
it("DataPassthrough", function() {
var data1 = new Data(new Name("/Security/V2/ValidatorFixture/Sub1"));
this.fixture_.keyChain_.sign(data1);
this.validateExpectSuccess(data1,
"Should succeed (fallback on inner validation policy for data)");
});
it("NameTooShort", function() {
var interest1 = new Interest(new Name("/name/too/short"));
this.validateExpectFailure(interest1, "Should fail (name is too short)");
});
it("BadSignatureInfo", function() {
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
setNameComponent
(interest1, CommandInterestSigner.POS_SIGNATURE_INFO, "not-SignatureInfo");
this.validateExpectFailure(interest1, "Should fail (missing signature info)");
});
it("MissingKeyLocator", function() {
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
var signatureInfo = new Sha256WithRsaSignature();
setNameComponent
(interest1, CommandInterestSigner.POS_SIGNATURE_INFO,
TlvWireFormat.get().encodeSignatureInfo(signatureInfo));
this.validateExpectFailure(interest1, "Should fail (missing KeyLocator)");
});
it("BadKeyLocatorType", function() {
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
var keyLocator = new KeyLocator();
keyLocator.setType(KeyLocatorType.KEY_LOCATOR_DIGEST);
keyLocator.setKeyData(new Blob
([ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd ]));
var signatureInfo = new Sha256WithRsaSignature();
signatureInfo.setKeyLocator(keyLocator);
setNameComponent
(interest1, CommandInterestSigner.POS_SIGNATURE_INFO,
TlvWireFormat.get().encodeSignatureInfo(signatureInfo));
this.validateExpectFailure(interest1, "Should fail (bad KeyLocator type)");
});
it("BadCertificateName", function() {
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
var keyLocator = new KeyLocator();
keyLocator.setType(KeyLocatorType.KEYNAME);
keyLocator.setKeyName(new Name("/bad/cert/name"));
var signatureInfo = new Sha256WithRsaSignature();
signatureInfo.setKeyLocator(keyLocator);
setNameComponent
(interest1, CommandInterestSigner.POS_SIGNATURE_INFO,
TlvWireFormat.get().encodeSignatureInfo(signatureInfo));
this.validateExpectFailure(interest1, "Should fail (bad certificate name)");
});
it("InnerPolicyReject", function() {
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.otherIdentity_);
this.validateExpectFailure(interest1, "Should fail (inner policy should reject)");
});
it("TimestampOutOfGracePositive", function() {
this.fixture_ = new ValidationPolicyCommandInterestFixture
(new ValidationPolicyCommandInterest.Options(15 * 1000.0));
// Signed at 0 seconds.
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Verifying at +16 seconds.
this.fixture_.setNowOffsetMilliseconds(16 * 1000.0);
this.validateExpectFailure(interest1,
"Should fail (timestamp outside the grace period)");
// Signed at +16 seconds.
var interest2 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
this.validateExpectSuccess(interest2, "Should succeed");
});
it("TimestampOutOfGraceNegative", function() {
this.fixture_ = new ValidationPolicyCommandInterestFixture
(new ValidationPolicyCommandInterest.Options(15 * 1000.0));
// Signed at 0 seconds.
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Signed at +1 seconds.
this.fixture_.setNowOffsetMilliseconds(1 * 1000.0);
var interest2 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Signed at +2 seconds.
this.fixture_.setNowOffsetMilliseconds(2 * 1000.0);
var interest3 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Verifying at -16 seconds.
this.fixture_.setNowOffsetMilliseconds(-16 * 1000.0);
this.validateExpectFailure(interest1,
"Should fail (timestamp outside the grace period)");
// The CommandInterestValidator should not remember interest1's timestamp.
this.validateExpectFailure(interest2,
"Should fail (timestamp outside the grace period)");
// The CommandInterestValidator should not remember interest2's timestamp, and
// should treat interest3 as initial.
// Verifying at +2 seconds.
this.fixture_.setNowOffsetMilliseconds(2 * 1000.0);
this.validateExpectSuccess(interest3, "Should succeed");
});
it("TimestampReorderEqual", function() {
// Signed at 0 seconds.
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
this.validateExpectSuccess(interest1, "Should succeed");
// Signed at 0 seconds.
var interest2 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
setNameComponent
(interest2, CommandInterestSigner.POS_TIMESTAMP,
interest1.getName().get(CommandInterestSigner.POS_TIMESTAMP));
this.validateExpectFailure(interest2, "Should fail (timestamp reordered)");
// Signed at +2 seconds.
this.fixture_.setNowOffsetMilliseconds(2 * 1000.0);
var interest3 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
this.validateExpectSuccess(interest3, "Should succeed");
});
it("TimestampReorderNegative", function() {
// Signed at 0 seconds.
var interest2 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Signed at +200 milliseconds.
this.fixture_.setNowOffsetMilliseconds(200.0);
var interest3 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Signed at +1100 milliseconds.
this.fixture_.setNowOffsetMilliseconds(1100.0);
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Signed at +1400 milliseconds.
this.fixture_.setNowOffsetMilliseconds(1400.0);
var interest4 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Verifying at +1100 milliseconds.
this.fixture_.setNowOffsetMilliseconds(1100.0);
this.validateExpectSuccess(interest1, "Should succeed");
// Verifying at 0 milliseconds.
this.fixture_.setNowOffsetMilliseconds(0.0);
this.validateExpectFailure(interest2, "Should fail (timestamp reordered)");
// The CommandInterestValidator should not remember interest2's timestamp.
// Verifying at +200 milliseconds.
this.fixture_.setNowOffsetMilliseconds(200.0);
this.validateExpectFailure(interest3, "Should fail (timestamp reordered)");
// Verifying at +1400 milliseconds.
this.fixture_.setNowOffsetMilliseconds(1400.0);
this.validateExpectSuccess(interest4, "Should succeed");
});
it("LimitedRecords", function() {
this.fixture_ = new ValidationPolicyCommandInterestFixture
(new ValidationPolicyCommandInterest.Options(15 * 1000.0, 3));
var identity1 = this.fixture_.addSubCertificate
(new Name("/Security/V2/ValidatorFixture/Sub1"), this.fixture_.identity_);
this.fixture_.cache_.insert(identity1.getDefaultKey().getDefaultCertificate());
var identity2 = this.fixture_.addSubCertificate
(new Name("/Security/V2/ValidatorFixture/Sub2"), this.fixture_.identity_);
this.fixture_.cache_.insert(identity2.getDefaultKey().getDefaultCertificate());
var identity3 = this.fixture_.addSubCertificate
(new Name("/Security/V2/ValidatorFixture/Sub3"), this.fixture_.identity_);
this.fixture_.cache_.insert(identity3.getDefaultKey().getDefaultCertificate());
var identity4 = this.fixture_.addSubCertificate
(new Name("/Security/V2/ValidatorFixture/Sub4"), this.fixture_.identity_);
this.fixture_.cache_.insert(identity4.getDefaultKey().getDefaultCertificate());
var interest1 = this.fixture_.makeCommandInterest(identity2);
var interest2 = this.fixture_.makeCommandInterest(identity3);
var interest3 = this.fixture_.makeCommandInterest(identity4);
// Signed at 0 seconds.
var interest00 = this.fixture_.makeCommandInterest(identity1);
// Signed at +1 seconds.
this.fixture_.setNowOffsetMilliseconds(1 * 1000.0);
var interest01 = this.fixture_.makeCommandInterest(identity1);
// Signed at +2 seconds.
this.fixture_.setNowOffsetMilliseconds(2 * 1000.0);
var interest02 = this.fixture_.makeCommandInterest(identity1);
this.validateExpectSuccess(interest00, "Should succeed");
this.validateExpectSuccess(interest02, "Should succeed");
this.validateExpectSuccess(interest1, "Should succeed");
this.validateExpectSuccess(interest2, "Should succeed");
this.validateExpectSuccess(interest3, "Should succeed, forgets identity1");
this.validateExpectSuccess(interest01,
"Should succeed despite timestamp is reordered, because the record has been evicted");
});
it("UnlimitedRecords", function() {
this.fixture_ = new ValidationPolicyCommandInterestFixture
(new ValidationPolicyCommandInterest.Options(15 * 1000.0, -1));
var identities = [];
for (var i = 0; i < 20; ++i) {
var identity = this.fixture_.addSubCertificate
(new Name("/Security/V2/ValidatorFixture/Sub" + i), this.fixture_.identity_);
this.fixture_.cache_.insert(identity.getDefaultKey().getDefaultCertificate());
identities.push(identity);
}
// Signed at 0 seconds.
var interest1 = this.fixture_.makeCommandInterest(identities[0]);
this.fixture_.setNowOffsetMilliseconds(1 * 1000.0);
for (var i = 0; i < 20; ++i) {
// Signed at +1 seconds.
var interest2 = this.fixture_.makeCommandInterest(identities[i]);
this.validateExpectSuccess(interest2, "Should succeed");
}
this.validateExpectFailure(interest1, "Should fail (timestamp reorder)");
});
it("ZeroRecords", function() {
this.fixture_ = new ValidationPolicyCommandInterestFixture
(new ValidationPolicyCommandInterest.Options(15 * 1000.0, 0));
// Signed at 0 seconds.
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Signed at +1 seconds.
this.fixture_.setNowOffsetMilliseconds(1 * 1000.0);
var interest2 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
this.validateExpectSuccess(interest2, "Should succeed");
this.validateExpectSuccess(interest1,
"Should succeed despite the timestamp being reordered, because the record isn't kept");
});
it("LimitedRecordLifetime", function() {
this.fixture_ = new ValidationPolicyCommandInterestFixture
(new ValidationPolicyCommandInterest.Options(400 * 1000.0, 1000, 300 * 1000.0));
// Signed at 0 seconds.
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Signed at +240 seconds.
this.fixture_.setNowOffsetMilliseconds(240 * 1000.0);
var interest2 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Signed at +360 seconds.
this.fixture_.setNowOffsetMilliseconds(360 * 1000.0);
var interest3 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Validate at 0 seconds.
this.fixture_.setNowOffsetMilliseconds(0.0);
this.validateExpectSuccess(interest1, "Should succeed");
this.validateExpectSuccess(interest3, "Should succeed");
// Validate at +301 seconds.
this.fixture_.setNowOffsetMilliseconds(301 * 1000.0);
this.validateExpectSuccess(interest2,
"Should succeed despite the timestamp being reordered, because the record has expired");
});
it("ZeroRecordLifetime", function() {
this.fixture_ = new ValidationPolicyCommandInterestFixture
(new ValidationPolicyCommandInterest.Options(15 * 1000.0, 1000, 0.0));
// Signed at 0 seconds.
var interest1 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
// Signed at +1 second.
this.fixture_.setNowOffsetMilliseconds(1 * 1000.0);
var interest2 = this.fixture_.makeCommandInterest(this.fixture_.identity_);
this.validateExpectSuccess(interest2, "Should succeed");
this.validateExpectSuccess(interest1,
"Should succeed despite the timestamp being reordered, because the record has expired");
});
});