def _createNameFilter(configSection): """ This is a helper for create() to create a filter from the configuration section which is type "name". :param BoostInfoTree configSection: The section containing the definition of the filter. :return: A new filter created from the configuration section. :rtype: ConfigFilter """ nameUri = configSection.getFirstValue("name") if nameUri != None: # Get the filter.name. name = Name(nameUri) # Get the filter.relation. relationValue = configSection.getFirstValue("relation") if relationValue == None: raise ValidatorConfigError("Expected <filter.relation>") relation = ConfigNameRelation.getNameRelationFromString( relationValue) return ConfigRelationNameFilter(name, relation) regexString = configSection.getFirstValue("regex") if regexString != None: try: return ConfigRegexNameFilter(regexString) except: raise ValidatorConfigError("Wrong filter.regex: " + regexString) raise ValidatorConfigError("Wrong filter(name) properties")
def _createKeyLocatorChecker(configSection): """ :param BoostInfoTree configSection: :rtype: ConfigChecker """ # Get checker.key-locator.type . keyLocatorType = configSection.getFirstValue("type") if keyLocatorType == None: raise ValidatorConfigError("Expected <checker.key-locator.type>") if keyLocatorType.lower() == "name": return ConfigChecker._createKeyLocatorNameChecker(configSection) else: raise ValidatorConfigError( "Unsupported checker.key-locator.type: " + keyLocatorType)
def match(self, isForInterest, packetName): """ Check if the packet name matches the rule's filter. If no filters were added, the rule matches everything. :param bool 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. :return: True if at least one filter matches the packet name, False if none of the filters match the packet name. :rtype: bool :raises: ValidatorConfigError if the supplied isForInterest doesn't match the one for which the rule is designed. """ logging.getLogger(__name__).info("Trying to match " + packetName.toUri()) if isForInterest != self._isForInterest: raise ValidatorConfigError( ("Invalid packet type supplied ( " + ("interest" if isForInterest else "data") + " != " + ("interest" if self._isForInterest else "data") + ")")) if len(self._filters) == 0: return True result = False for i in range(len(self._filters)): result = (result or self._filters[i].match(isForInterest, packetName)) if result: break return result
def create(configSection): """ Create a rule from configuration section. :param BoostInfoTree configSection: The section containing the definition of the checker, e.g. one of "validator.rule". :return: A new ConfigRule created from the configuration. :rtype: ConfigRule """ # Get rule.id . ruleId = configSection.getFirstValue("id") if ruleId == None: raise ValidatorConfigError("Expecting <rule.id>") # Get rule.for . usage = configSection.getFirstValue("for") if usage == None: raise ValidatorConfigError("Expecting <rule.for> in rule: " + ruleId) if usage.lower() == "data": isForInterest = False elif usage.lower() == "interest": isForInterest = True else: raise ValidatorConfigError("Unrecognized <rule.for>: " + usage + " in rule: " + ruleId) rule = ConfigRule(ruleId, isForInterest) # Get rule.filter(s) filterList = configSection["filter"] for i in range(len(filterList)): rule.addFilter(ConfigFilter.create(filterList[i])) # Get rule.checker(s) checkerList = configSection["checker"] for i in range(len(checkerList)): rule.addChecker(ConfigChecker.create(checkerList[i])) # Check other stuff. if len(checkerList) == 0: raise ValidatorConfigError( "No <rule.checker> is specified in rule: " + ruleId) return rule
def create(configSection): """ Create a filter from the configuration section. :param BoostInfoTree configSection: The section containing the definition of the filter, e.g. one of "validator.rule.filter". :return: A new filter created from the configuration section. :rtype: ConfigFilter """ filterType = configSection.getFirstValue("type") if filterType == None: raise ValidatorConfigError("Expected <filter.type>") if filterType.lower() == "name": return ConfigFilter._createNameFilter(configSection) else: raise ValidatorConfigError("Unsupported filter.type: " + filterType)
def create(configSection): """ 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: A new checker created from the configuration section. :rtype: ConfigChecker """ # Get checker.type. checkerType = configSection.getFirstValue("type") if checkerType == None: raise ValidatorConfigError("Expected <checker.type>") if checkerType.lower() == "customized": return ConfigChecker._createCustomizedChecker(configSection) elif checkerType.lower() == "hierarchical": return ConfigChecker._createHierarchicalChecker(configSection) else: raise ValidatorConfigError("Unsupported checker type: " + checkerType)
def _createCustomizedChecker(configSection): """ :param BoostInfoTree configSection: :rtype: ConfigChecker """ # Ignore sig-type. # Get checker.key-locator . keyLocatorSection = configSection["key-locator"] if len(keyLocatorSection) != 1: raise ValidatorConfigError("Expected one <checker.key-locator>") return ConfigChecker._createKeyLocatorChecker(keyLocatorSection[0])
def _processConfigTrustAnchor(self, configSection, inputName): """ Process the trust-anchor configuration section and call validator_.loadAnchor as needed. :param BoostInfoTree configSection: The section containing the definition of the trust anchor, e.g. one of "validator.trust-anchor". :param str inputName: Used for log messages, etc. """ anchorType = configSection.getFirstValue("type") if anchorType == None: raise ValidatorConfigError("Expected <trust-anchor.type>") if anchorType.lower() == "file": # Get trust-anchor.file . fileName = configSection.getFirstValue("file-name") if fileName == None: raise ValidatorConfigError("Expected <trust-anchor.file-name>") refreshPeriod = ValidationPolicyConfig._getRefreshPeriod( configSection) self._validator.loadAnchor(fileName, fileName, refreshPeriod, False) return elif anchorType.lower() == "base64": # Get trust-anchor.base64-string . base64String = configSection.getFirstValue("base64-string") if base64String == None: raise ValidatorConfigError( "Expected <trust-anchor.base64-string>") encoding = b64decode(base64String) certificate = CertificateV2() try: certificate.wireDecode(Blob(encoding, False)) except Exception as ex: raise ValidatorConfigError( "Cannot decode certificate from base64-string: " + repr(ex)) self._validator.loadAnchor("", certificate) return elif anchorType.lower() == "dir": # Get trust-anchor.dir . dirString = configSection.getFirstValue("dir") if dirString == None: raise ValidatorConfigError("Expected <trust-anchor.dir>") refreshPeriod = ValidationPolicyConfig._getRefreshPeriod( configSection) self._validator.loadAnchor(dirString, dirString, refreshPeriod, True) return elif anchorType.lower() == "any": self._shouldBypass = True else: raise ValidatorConfigError("Unsupported trust-anchor.type")
def getNameRelationFromString(relationString): """ Convert relationString to a Relation enum. :param str relationString: the string to convert. :return: The value for the ConfigNameRelation.Relation enum. :rtype: int :raises: ValidatorConfigError if relationString cannot be converted. """ if relationString.lower() == "equal": return ConfigNameRelation.Relation.EQUAL elif relationString.lower() == "is-prefix-of": return ConfigNameRelation.Relation.IS_PREFIX_OF elif relationString.lower() == "is-strict-prefix-of": return ConfigNameRelation.Relation.IS_STRICT_PREFIX_OF else: raise ValidatorConfigError("Unsupported relation: " + relationString)
def check(self, isForInterest, packetName, keyLocatorName, state): """ Check if the packet satisfies the rule's condition. :param bool 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: 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. :rtype: bool :raises: ValidatorConfigError if the supplied isForInterest doesn't match the one for which the rule is designed. """ logging.getLogger(__name__).info("Trying to check " + packetName.toUri() + " with keyLocator " + keyLocatorName.toUri()) if isForInterest != self._isForInterest: raise ValidatorConfigError( "Invalid packet type supplied ( " + ("interest" if isForInterest else "data") + " != " + ("interest" if self._isForInterest else "data") + ")") hasPendingResult = False for i in range(len(self._checkers)): result = self._checkers[i].check(isForInterest, packetName, keyLocatorName, state) if not result: return result hasPendingResult = True return hasPendingResult
def load(self, filePathOrInputOrConfigSection, inputName=None): """ There are three forms of load: load(filePath) - Load the configuration from the given config file. load(input, inputName) - Load the configuration from the given input string. load(configSection, inputName) - Load the configuration from the given configSection. Each of these forms of load replaces any existing configuration. :param str filePath: The The path of the config file. :param str input: The contents of the configuration rules, with lines separated by NL or CR/NL. :param BoostInfoTree configSection: The configuration section loaded from the config file. It should have one "validator" section. :param str inputName: Used for log messages, etc. """ if type(filePathOrInputOrConfigSection) is str and inputName == None: filePath = filePathOrInputOrConfigSection parser = BoostInfoParser() parser.read(filePath) self.load(parser.getRoot(), filePath) elif (type(filePathOrInputOrConfigSection) is str and type(inputName) is str): input = filePathOrInputOrConfigSection parser = BoostInfoParser() parser.read(input, inputName) self.load(parser.getRoot(), inputName) else: configSection = filePathOrInputOrConfigSection if self._isConfigured: # Reset the previous configuration. self._shouldBypass = False self._dataRules = [] self._interestRules = [] self._validator.resetAnchors() self._validator.resetVerifiedCertificates() self._isConfigured = True validatorList = configSection["validator"] if len(validatorList) != 1: raise ValidatorConfigError( "ValidationPolicyConfig: Expected one validator section") validatorSection = validatorList[0] # Get the rules. ruleList = validatorSection["rule"] for i in range(len(ruleList)): rule = ConfigRule.create(ruleList[i]) if rule.getIsForInterest(): self._interestRules.append(rule) else: self._dataRules.append(rule) # Get the trust anchors. trustAnchorList = validatorSection["trust-anchor"] for i in range(len(trustAnchorList)): self._processConfigTrustAnchor(trustAnchorList[i], inputName)
def checkPolicy(self, dataOrInterest, state, continueValidation): """ :param dataOrInterest: :type dataOrInterest: Data or Interest :param ValidationState state: :param continueValidation: :type continueValidation: function object """ if self.hasInnerPolicy(): raise ValidatorConfigError( "ValidationPolicyConfig must be a terminal inner policy") if self._shouldBypass: continueValidation(None, state) return keyLocatorName = ValidationPolicy.getKeyLocatorName( dataOrInterest, state) if state.isOutcomeFailed(): # Already called state.fail() . return if isinstance(dataOrInterest, Data): data = dataOrInterest for i in range(len(self._dataRules)): rule = self._dataRules[i] if rule.match(False, data.getName()): if rule.check(False, data.getName(), keyLocatorName, state): continueValidation( CertificateRequest(Interest(keyLocatorName)), state) return else: # rule.check failed and already called state.fail() . return state.fail( ValidationError( ValidationError.POLICY_ERROR, "No rule matched for data `" + data.getName().toUri() + "`")) else: interest = dataOrInterest for i in range(len(self._interestRules)): rule = self._interestRules[i] if rule.match(True, interest.getName()): if rule.check(True, interest.getName(), keyLocatorName, state): continueValidation( CertificateRequest(Interest(keyLocatorName)), state) return else: # rule.check failed and already called state.fail() . return state.fail( ValidationError( ValidationError.POLICY_ERROR, "No rule matched for interest `" + interest.getName().toUri() + "`"))
def _createKeyLocatorNameChecker(configSection): """ :param BoostInfoTree configSection: :rtype: ConfigChecker """ nameUri = configSection.getFirstValue("name") if nameUri != None: name = Name(nameUri) relationValue = configSection.getFirstValue("relation") if relationValue == None: raise ValidatorConfigError( "Expected <checker.key-locator.relation>") relation = ConfigNameRelation.getNameRelationFromString( relationValue) return ConfigNameRelationChecker(name, relation) regexString = configSection.getFirstValue("regex") if regexString != None: try: return ConfigRegexChecker(regexString) except: raise ValidatorConfigError( "Invalid checker.key-locator.regex: " + regexString) hyperRelationList = configSection["hyper-relation"] if len(hyperRelationList) == 1: hyperRelation = hyperRelationList[0] # Get k-regex. keyRegex = hyperRelation.getFirstValue("k-regex") if keyRegex == None: raise ValidatorConfigError( "Expected <checker.key-locator.hyper-relation.k-regex>") # Get k-expand. keyExpansion = hyperRelation.getFirstValue("k-expand") if keyExpansion == None: raise ValidatorConfigError( "Expected <checker.key-locator.hyper-relation.k-expand") # Get h-relation. hyperRelationString = hyperRelation.getFirstValue("h-relation") if hyperRelationString == None: raise ValidatorConfigError( "Expected <checker.key-locator.hyper-relation.h-relation>") # Get p-regex. packetNameRegex = hyperRelation.getFirstValue("p-regex") if packetNameRegex == None: raise ValidatorConfigError( "Expected <checker.key-locator.hyper-relation.p-regex>") # Get p-expand. packetNameExpansion = hyperRelation.getFirstValue("p-expand") if packetNameExpansion == None: raise ValidatorConfigError( "Expected <checker.key-locator.hyper-relation.p-expand>") relation = ConfigNameRelation.getNameRelationFromString( hyperRelationString) try: return ConfigHyperRelationChecker(packetNameRegex, packetNameExpansion, keyRegex, keyExpansion, relation) except: raise ValidatorConfigError( "Invalid regex for key-locator.hyper-relation") raise ValidatorConfigError("Unsupported checker.key-locator")