def __init__(self, identityStorage, configFilename=None): """ :param pyndn.IdentityStorage: A class that stores signing identities and certificates. :param str configFilename: A configuration file specifying validation rules and network name settings. """ # use the default configuration where possible # TODO: use environment variable for this, fall back to default path = os.path.dirname(__file__) templateFilename = os.path.join(path, '.default.conf') self._configTemplate = BoostInfoParser() self._configTemplate.read(templateFilename) if configFilename is None: configFilename = templateFilename certificateCache = CertificateCache() super(IotPolicyManager, self).__init__(configFilename, certificateCache) self._identityStorage = identityStorage self.setEnvironmentPrefix(None) self.setTrustRootIdentity(None) self.setDeviceIdentity(None)
def reset(self): """ Reset the certificate cache and other fields to the constructor state. """ self._certificateCache.reset() # stores the fixed-signer certificate name associated with validation rules # so we don't keep loading from files self._fixedCertificateCache = {} # stores the timestamps for each public key used in command interests to avoid # replay attacks # key is public key name, value is last timestamp self._keyTimestamps = {} self.requiresVerification = True self.config = BoostInfoParser() self._refreshManager = TrustAnchorRefreshManager()
def loadApplications(self, directory=None, override=False): if not directory: directory = self._applicationDirectory if override: self._applications.clear() if os.path.exists(directory): for f in os.listdir(directory): fullFileName = os.path.join(directory, f) if os.path.isfile(fullFileName) and f.endswith('.conf'): appName = f.rstrip('.conf') if appName in self._applications and not override: print( "loadApplications: " + appName + " already exists, do nothing for configuration file: " + fullFileName) else: self._applications[appName] = { "tree": BoostInfoParser(), "dataPrefix": [], "version": int(time.time()) } self._applications[appName]["tree"].read(fullFileName) data = Data( Name(self.prefix).append(appName).append( "_schema").appendVersion( self._applications[appName]["version"])) data.setContent( str(self._applications[appName]["tree"].getRoot())) self.signData(data) self._memoryContentCache.add(data) try: validatorTree = self._applications[appName][ "tree"]["validator"][0] for rule in validatorTree["rule"]: self._applications[appName][ "dataPrefix"].append(rule["id"][0].value) # TODO: don't swallow any general exceptions, we want to catch only KeyError (make sure) here except Exception as e: print( "loadApplications parse configuration file " + fullFileName + " : " + str(e)) return
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)
self.log.debug(msg) if __name__ == '__main__': import sys import os # todo - should I enforce the suffix 'gateway'? nArgs = len(sys.argv) - 1 if nArgs < 2: from pyndn.util.boost_info_parser import BoostInfoParser fileName = '/usr/local/etc/ndn/iot_controller.conf' if nArgs == 1: fileName = sys.argv[1] try: config = BoostInfoParser() config.read(fileName) except IOError: print('Could not read {}, exiting...'.format(fileName)) sys.exit(1) else: deviceName = config["device/controllerName"][0].value networkName = config["device/environmentPrefix"][0].value elif nArgs == 2: networkName = sys.argv[1] deviceName = sys.argv[2] else: print('Usage: {} [network-name controller-name]'.format(sys.argv[0])) sys.exit(1) try:
def updateTrustSchema(self, appName, certName, dataPrefix, publishNew=False): if appName in self._applications: if dataPrefix.toUri() in self._applications[appName]["dataPrefix"]: print("some key is configured for namespace " + dataPrefix.toUri() + " for application " + appName + ". Ignoring this request.") return False else: # TODO: Handle malformed conf where validator tree does not exist validatorNode = self._applications[appName]["tree"][ "validator"][0] else: # This application does not previously exist, we create its trust schema # (and for now, add in static rules for sync data) self._applications[appName] = { "tree": BoostInfoParser(), "dataPrefix": [], "version": 0 } validatorNode = self._applications[appName]["tree"].getRoot( ).createSubtree("validator") trustAnchorNode = validatorNode.createSubtree("trust-anchor") #trustAnchorNode.createSubtree("type", "file") #trustAnchorNode.createSubtree("file-name", os.path.expanduser("~/.ndn/iot/root.cert")) trustAnchorNode.createSubtree("type", "base64") trustAnchorNode.createSubtree( "base64-string", Blob(b64encode(self._rootCertificate.wireEncode().toBytes()), False).toRawStr()) #create cert verification rule # TODO: the idea for this would be, if the cert has /home-prefix/<one-component>/KEY/ksk-*/ID-CERT, then it should be signed by fixed controller(s) # if the cert has /home-prefix/<multiple-components>/KEY/ksk-*/ID-CERT, then it should be checked hierarchically (this is for subdomain support) certRuleNode = validatorNode.createSubtree("rule") certRuleNode.createSubtree("id", "Certs") certRuleNode.createSubtree("for", "data") filterNode = certRuleNode.createSubtree("filter") filterNode.createSubtree("type", "regex") filterNode.createSubtree("regex", "^[^<KEY>]*<KEY><>*<ID-CERT>") checkerNode = certRuleNode.createSubtree("checker") # TODO: wait how did my first hierarchical verifier work? #checkerNode.createSubtree("type", "hierarchical") checkerNode.createSubtree("type", "customized") checkerNode.createSubtree("sig-type", "rsa-sha256") keyLocatorNode = checkerNode.createSubtree("key-locator") keyLocatorNode.createSubtree("type", "name") # We don't put cert version in there keyLocatorNode.createSubtree( "name", Name(self.getDefaultCertificateName()).getPrefix(-1).toUri()) keyLocatorNode.createSubtree("relation", "equal") # Discovery rule: anything that multicasts under my home prefix should be signed, and the signer should have been authorized by root # TODO: This rule as of right now is over-general discoveryRuleNode = validatorNode.createSubtree("rule") discoveryRuleNode.createSubtree("id", "sync-data") discoveryRuleNode.createSubtree("for", "data") filterNode = discoveryRuleNode.createSubtree("filter") filterNode.createSubtree("type", "regex") filterNode.createSubtree("regex", "^[^<MULTICAST>]*<MULTICAST><>*") checkerNode = discoveryRuleNode.createSubtree("checker") # TODO: wait how did my first hierarchical verifier work? #checkerNode.createSubtree("type", "hierarchical") checkerNode.createSubtree("type", "customized") checkerNode.createSubtree("sig-type", "rsa-sha256") keyLocatorNode = checkerNode.createSubtree("key-locator") keyLocatorNode.createSubtree("type", "name") keyLocatorNode.createSubtree("regex", "^[^<KEY>]*<KEY><>*<ID-CERT>") ruleNode = validatorNode.createSubtree("rule") ruleNode.createSubtree("id", dataPrefix.toUri()) ruleNode.createSubtree("for", "data") filterNode = ruleNode.createSubtree("filter") filterNode.createSubtree("type", "name") filterNode.createSubtree("name", dataPrefix.toUri()) filterNode.createSubtree("relation", "is-prefix-of") checkerNode = ruleNode.createSubtree("checker") checkerNode.createSubtree("type", "customized") checkerNode.createSubtree("sig-type", "rsa-sha256") keyLocatorNode = checkerNode.createSubtree("key-locator") keyLocatorNode.createSubtree("type", "name") # We don't put cert version in there keyLocatorNode.createSubtree("name", certName.getPrefix(-1).toUri()) keyLocatorNode.createSubtree("relation", "equal") if not os.path.exists(self._applicationDirectory): os.makedirs(self._applicationDirectory) self._applications[appName]["tree"].write( os.path.join(self._applicationDirectory, appName + ".conf")) self._applications[appName]["dataPrefix"].append(dataPrefix.toUri()) self._applications[appName]["version"] = int(time.time()) if publishNew: # TODO: ideally, this is the trust schema of the application, and does not necessarily carry controller prefix. # We make it carry controller prefix here so that prefix registration / route setup is easier (implementation workaround) data = Data( Name(self.prefix).append(appName).append( "_schema").appendVersion( self._applications[appName]["version"])) data.setContent(str(self._applications[appName]["tree"].getRoot())) self.signData(data) self._memoryContentCache.add(data) return True