UNPKG

ndn-js

Version:

A JavaScript client library for Named Data Networking

387 lines (339 loc) 13.6 kB
/** * Copyright (C) 2018-2019 Regents of the University of California. * @author: Jeff Thompson <jefft0@remap.ucla.edu> * @author: From ndn-cxx security https://github.com/named-data/ndn-cxx/blob/master/ndn-cxx/security/v2/validator-config/checker.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. * * 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. */ /** @ignore */ var Name = require('../../../name.js').Name; /** @ignore */ var PibKey = require('../../pib/pib-key.js').PibKey; /** @ignore */ var ValidationError = require('../validation-error.js').ValidationError; /** @ignore */ var ConfigNameRelation = require('./config-name-relation.js').ConfigNameRelation; /** @ignore */ var NdnRegexTopMatcher = require('../../../util/regex/ndn-regex-top-matcher.js').NdnRegexTopMatcher; /** @ignore */ var ValidatorConfigError = require('../../validator-config-error.js').ValidatorConfigError; /** * A ConfigChecker is an abstract base class for ConfigNameRelationChecker, etc. * used by ValidatorConfig to check if a packet name and KeyLocator satisfy the * conditions in a configuration section. * @constructor */ var ConfigChecker = function ConfigChecker() { }; exports.ConfigChecker = ConfigChecker; /** * Check if the packet name ane KeyLocator name satisfy this checker's * conditions. * @param {boolean} isForInterest True if packetName is for an Interest, false * if for a Data packet. * @param {Name} packetName The packet name. For a signed interest, the last two * components are skipped but not removed. * @param {Name} keyLocatorName The KeyLocator's name. * @param {ValidationState} state This calls state.fail() if the packet is * invalid. * @return {boolean} True if further signature verification is needed, or false * if the packet is immediately determined to be invalid in which case this * calls state.fail() with the proper code and message. */ ConfigChecker.prototype.check = function (isForInterest, packetName, keyLocatorName, state) { if (isForInterest) { var signedInterestMinSize = 2; if (packetName.size() < signedInterestMinSize) return false; return this.checkNames (packetName.getPrefix(-signedInterestMinSize), keyLocatorName, state); } else return this.checkNames(packetName, keyLocatorName, state); }; /** * Create a checker from the configuration section. * @param {BoostInfoTree} configSection The section containing the definition of * the checker, e.g. one of "validation.rule.checker". * @return {ConfigChecker} A new checker created from the configuration section. */ ConfigChecker.create = function(configSection) { // Get checker.type. var checkerType = configSection.getFirstValue("type"); if (checkerType == null) throw new ValidatorConfigError(new Error("Expected <checker.type>")); if (checkerType.toLowerCase() == "customized") return ConfigChecker.createCustomizedChecker_(configSection); else if (checkerType.toLowerCase() == "hierarchical") return ConfigChecker.createHierarchicalChecker_(configSection); else throw new ValidatorConfigError(new Error ("Unsupported checker type: " + checkerType)); }; /** * Check if the packet name ane KeyLocator name satisfy this checker's * conditions. * @param {Name} packetName The packet name, which is already stripped of * signature components if this is a signed Interest name. * @param {Name} keyLocatorName The KeyLocator's name. * @param {ValidationState} state This calls state.fail() if the packet is * invalid. * @return {boolean} True if further signature verification is needed, or false * if the packet is immediately determined to be invalid in which case this * calls state.fail() with the proper code and message. */ ConfigChecker.prototype.checkNames = function (packetName, keyLocatorName, state) { throw new Error("ConfigChecker.checkNames is not implemented"); }; /** * @param {BoostInfoTree} configSection * @return {ConfigChecker} */ ConfigChecker.createCustomizedChecker_ = function( configSection) { // Ignore sig-type. // Get checker.key-locator . keyLocatorSection = configSection.get("key-locator"); if (keyLocatorSection.length != 1) throw new ValidatorConfigError(new Error("Expected one <checker.key-locator>")); return ConfigChecker.createKeyLocatorChecker_(keyLocatorSection[0]); }; /** * @param {BoostInfoTree} configSection * @return {ConfigChecker} */ ConfigChecker.createHierarchicalChecker_ = function(configSection) { // Ignore sig-type. return new ConfigHyperRelationChecker ("^(<>*)$", "\\1", "^(<>*)<KEY><>$", "\\1", ConfigNameRelation.Relation.IS_PREFIX_OF); }; /** * @param {BoostInfoTree} configSection * @return {ConfigChecker} */ ConfigChecker.createKeyLocatorChecker_ = function(configSection) { // Get checker.key-locator.type . var keyLocatorType = configSection.getFirstValue("type"); if (keyLocatorType == null) throw new ValidatorConfigError(new Error("Expected <checker.key-locator.type>")); if (keyLocatorType.toLowerCase() == "name") return ConfigChecker.createKeyLocatorNameChecker_(configSection); else throw new ValidatorConfigError(new Error ("Unsupported checker.key-locator.type: " + keyLocatorType)); }; /** * @param {BoostInfoTree} configSection * @return {ConfigChecker} */ ConfigChecker.createKeyLocatorNameChecker_ = function(configSection) { var nameUri = configSection.getFirstValue("name"); if (nameUri != null) { var name = new Name(nameUri); var relationValue = configSection.getFirstValue("relation"); if (relationValue == null) throw new ValidatorConfigError(new Error ("Expected <checker.key-locator.relation>")); relation = ConfigNameRelation.getNameRelationFromString(relationValue); return new ConfigNameRelationChecker(name, relation); } var regexString = configSection.getFirstValue("regex"); if (regexString != null) { try { return new ConfigRegexChecker(regexString); } catch (ex) { throw new ValidatorConfigError(new Error ("Invalid checker.key-locator.regex: " + regexString)); } } var hyperRelationList = configSection.get("hyper-relation"); if (hyperRelationList.length == 1) { var hyperRelation = hyperRelationList[0]; // Get k-regex. var keyRegex = hyperRelation.getFirstValue("k-regex"); if (keyRegex == null) throw new ValidatorConfigError(new Error ("Expected <checker.key-locator.hyper-relation.k-regex>")); // Get k-expand. var keyExpansion = hyperRelation.getFirstValue("k-expand"); if (keyExpansion == null) throw new ValidatorConfigError(new Error ("Expected <checker.key-locator.hyper-relation.k-expand")); // Get h-relation. var hyperRelationString = hyperRelation.getFirstValue("h-relation"); if (hyperRelationString == null) throw new ValidatorConfigError(new Error ("Expected <checker.key-locator.hyper-relation.h-relation>")); // Get p-regex. var packetNameRegex = hyperRelation.getFirstValue("p-regex"); if (packetNameRegex == null) throw new ValidatorConfigError(new Error ("Expected <checker.key-locator.hyper-relation.p-regex>")); // Get p-expand. var packetNameExpansion = hyperRelation.getFirstValue("p-expand"); if (packetNameExpansion == null) throw new ValidatorConfigError(new Error ("Expected <checker.key-locator.hyper-relation.p-expand>")); var relation = ConfigNameRelation.getNameRelationFromString(hyperRelationString); try { return new ConfigHyperRelationChecker (packetNameRegex, packetNameExpansion, keyRegex, keyExpansion, relation); } catch (ex) { throw new ValidatorConfigError(new Error ("Invalid regex for key-locator.hyper-relation")); } } throw new ValidatorConfigError(new Error("Unsupported checker.key-locator")); }; /** * ConfigNameRelationChecker extends ConfigChecker. * @param {Name} name * @param {number} relation The value for the ConfigNameRelation.Relation enum. * @constructor */ var ConfigNameRelationChecker = function ConfigNameRelationChecker(name, relation) { // Call the base constructor. ConfigChecker.call(this); this.name_ = name; this.relation_ = relation; }; ConfigNameRelationChecker.prototype = new ConfigChecker(); ConfigNameRelationChecker.prototype.name = "ConfigNameRelationChecker"; exports.ConfigNameRelationChecker = ConfigNameRelationChecker; /** * @param {Name} packetName * @param {Name} keyLocatorName * @param {ValidationState} state * @return {boolean} */ ConfigNameRelationChecker.prototype.checkNames = function (packetName, keyLocatorName, state) { // packetName is not used in this check. var identity = PibKey.extractIdentityFromKeyName(keyLocatorName); var result = ConfigNameRelation.checkNameRelation (this.relation_, this.name_, identity); if (!result) state.fail(new ValidationError(ValidationError.POLICY_ERROR, "KeyLocator check failed: name relation " + this.name_.toUri() + " " + ConfigNameRelation.toString(this.relation_) + " for packet " + packetName.toUri() + " is invalid (KeyLocator=" + keyLocatorName.toUri() + ", identity=" + identity.toUri() + ")")); return result; }; /** * ConfigRegexChecker extends ConfigChecker. * @param {String} regexString * @constructor */ var ConfigRegexChecker = function ConfigRegexChecker(regexString) { // Call the base constructor. ConfigChecker.call(this); this.regex_ = new NdnRegexTopMatcher(regexString); }; ConfigRegexChecker.prototype = new ConfigChecker(); ConfigRegexChecker.prototype.name = "ConfigRegexChecker"; exports.ConfigRegexChecker = ConfigRegexChecker; /** * @param {Name} packetName * @param {Name} keyLocatorName * @param {ValidationState} state * @return {boolean} */ ConfigRegexChecker.prototype.checkNames = function (packetName, keyLocatorName, state) { var result = this.regex_.match(keyLocatorName); if (!result) state.fail(new ValidationError(ValidationError.POLICY_ERROR, "KeyLocator check failed: regex " + this.regex_.getExpr() + " for packet " + packetName.toUri() + " is invalid (KeyLocator=" + keyLocatorName.toUri() + ")")); return result; }; /** * ConfigHyperRelationChecker extends ConfigChecker. * @param {String} packetNameRegexString * @param {String} packetNameExpansion * @param {String} keyNameRegexString * @param {String} keyNameExpansion * @param {number} hyperRelation The value for the ConfigNameRelation.Relation enum. * @constructor */ var ConfigHyperRelationChecker = function ConfigHyperRelationChecker (packetNameRegexString, packetNameExpansion, keyNameRegexString, keyNameExpansion, hyperRelation) { // Call the base constructor. ConfigChecker.call(this); this.packetNameRegex_ = new NdnRegexTopMatcher(packetNameRegexString); this.packetNameExpansion_ = packetNameExpansion; this.keyNameRegex_ = new NdnRegexTopMatcher(keyNameRegexString); this.keyNameExpansion_ = keyNameExpansion; this.hyperRelation_ = hyperRelation; }; ConfigHyperRelationChecker.prototype = new ConfigChecker(); ConfigHyperRelationChecker.prototype.name = "ConfigHyperRelationChecker"; exports.ConfigHyperRelationChecker = ConfigHyperRelationChecker; /** * @param {Name} packetName * @param {Name} keyLocatorName * @param {ValidationState} state * @return {boolean} */ ConfigHyperRelationChecker.prototype.checkNames = function (packetName, keyLocatorName, state) { if (!this.packetNameRegex_.match(packetName)) { state.fail(new ValidationError(ValidationError.POLICY_ERROR, "The packet " + packetName.toUri() + " (KeyLocator=" + keyLocatorName.toUri() + ") does not match the hyper relation packet name regex " + this.packetNameRegex_.getExpr())); return false; } if (!this.keyNameRegex_.match(keyLocatorName)) { state.fail(new ValidationError(ValidationError.POLICY_ERROR, "The packet " + packetName.toUri() + " (KeyLocator=" + keyLocatorName.toUri() + ") does not match the hyper relation key name regex " + this.keyNameRegex_.getExpr())); return false; } var keyNameMatchExpansion = this.keyNameRegex_.expand(this.keyNameExpansion_); var packetNameMatchExpansion = this.packetNameRegex_.expand(this.packetNameExpansion_); var result = ConfigNameRelation.checkNameRelation (this.hyperRelation_, keyNameMatchExpansion, packetNameMatchExpansion); if (!result) state.fail(new ValidationError(ValidationError.POLICY_ERROR, "KeyLocator check failed: hyper relation " + ConfigNameRelation.toString(this.hyperRelation_) + " packet name match=" + packetNameMatchExpansion.toUri() + ", key name match=" + keyNameMatchExpansion.toUri() + " of packet " + packetName.toUri() + " (KeyLocator=" + keyLocatorName.toUri() + ") is invalid")); return result; };