Ejemplo n.º 1
0
    def test_append(self):
        # could possibly split this into different tests
        uri = "/localhost/user/folders/files/%00%0F"
        name = Name(uri)
        name2 = Name("/localhost").append(Name("/user/folders/"))
        self.assertEqual(name2.size(), 3, 'Name constructed by appending names has ' + str(name2.size()) + ' components instead of 3')
        self.assertTrue(name2.get(2).getValue().equals(Blob(bytearray("folders"))), 'Name constructed with append has wrong suffix')
        name2 = name2.append("files")
        self.assertEqual(name2.size(), 4, 'Name constructed by appending string has ' + str(name2.size()) + ' components instead of 4')
        name2 = name2.appendSegment(15)
        self.assertTrue(name2.get(4).getValue().equals(Blob(bytearray([0x00, 0x0F]))), 'Name constructed by appending segment has wrong segment value')

        self.assertTrue(name2.equals(name), 'Name constructed with append is not equal to URI constructed name')
        self.assertEqual(name2.toUri(), name.toUri(), 'Name constructed with append has wrong URI')
Ejemplo n.º 2
0
    def test_append(self):
        # could possibly split this into different tests
        uri = "/localhost/user/folders/files/%00%0F"
        name = Name(uri)
        name2 = Name("/localhost").append(Name("/user/folders/"))
        self.assertEqual(name2.size(), 3, 'Name constructed by appending names has ' + str(name2.size()) + ' components instead of 3')
        self.assertTrue(name2.get(2).getValue().equals(Blob(bytearray("folders"))), 'Name constructed with append has wrong suffix')
        name2 = name2.append("files")
        self.assertEqual(name2.size(), 4, 'Name constructed by appending string has ' + str(name2.size()) + ' components instead of 4')
        name2 = name2.appendSegment(15)
        self.assertTrue(name2.get(4).getValue().equals(Blob(bytearray([0x00, 0x0F]))), 'Name constructed by appending segment has wrong segment value')

        self.assertTrue(name2.equals(name), 'Name constructed with append is not equal to URI constructed name')
        self.assertEqual(name2.toUri(), name.toUri(), 'Name constructed with append has wrong URI')
Ejemplo n.º 3
0
def main():
    # The default Face will connect using a Unix socket, or to "localhost".
    face = Face()

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(
      IdentityManager(identityStorage, privateKeyStorage), None)
    keyChain.setFace(face)

    # Initialize the storage.
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(0, keyName.size() - 1).append(
      "KEY").append(keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(
      keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER, DEFAULT_RSA_PRIVATE_KEY_DER)

    echo = Echo(keyChain, certificateName)
    prefix = Name("/testecho")
    dump("Register prefix", prefix.toUri())
    face.registerPrefix(prefix, echo.onInterest, echo.onRegisterFailed)

    while echo._responseCount < 1:
        face.processEvents()
        # We need to sleep for a few milliseconds so we don't use 100% of the CPU.
        time.sleep(0.01)    

    face.shutdown()
Ejemplo n.º 4
0
    def wrap_content(self, name, content, key=None, key_locator=None):
        """
        @param name - name of the data
        @param content - data to be wrapped
        @param key - key used to sign the data
        @return the content object created
        wraps the given name and content into a content object
        """
        co = Data(Name(name))
        co.setContent(content)
        co.getMetaInfo().setFreshnessPeriod(5000)
        co.getMetaInfo().setFinalBlockID(Name("/%00%09")[0])

        identityStorage = MemoryIdentityStorage()
        privateKeyStorage = MemoryPrivateKeyStorage()
        identityManager = IdentityManager(identityStorage, privateKeyStorage)
        keyChain = KeyChain(identityManager, None)

        # Initialize the storage.
        keyName = Name("/ndn/bms/DSK-default")
        certificateName = keyName.getSubName(0, keyName.size() - 1).append(
                "KEY").append(keyName[-1]).append("ID-CERT").append("0")
        identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_PUBLIC_KEY_DER))
        privateKeyStorage.setKeyPairForKeyName(keyName, DEFAULT_PUBLIC_KEY_DER, 
                DEFAULT_PRIVATE_KEY_DER)

        keyChain.sign(co, certificateName)

        _data = co.wireEncode()

        return _data.toRawStr()
Ejemplo n.º 5
0
def createKeyChain():
    """
    Create an in-memory KeyChain with default keys.

    :return: A tuple with the new KeyChain and certificate name.
    :rtype: (KeyChain,Name)
    """
    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        NoVerifyPolicyManager())

    # Initialize the storage.
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(
        0,
        keyName.size() - 1).append("KEY").append(
            keyName.get(-1)).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA,
                           Blob(DEFAULT_RSA_PUBLIC_KEY_DER, False))
    privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA,
                                           DEFAULT_RSA_PUBLIC_KEY_DER,
                                           DEFAULT_RSA_PRIVATE_KEY_DER)

    return keyChain, certificateName
Ejemplo n.º 6
0
    def _updateCapabilities(self):
        """
        Send the controller a list of our commands.
        """ 
        fullCommandName = Name(self._policyManager.getTrustRootIdentity()
                ).append('updateCapabilities')
        capabilitiesMessage = UpdateCapabilitiesCommandMessage()

        for command in self._commands:
            commandName = Name(self.prefix).append(Name(command.suffix))
            capability = capabilitiesMessage.capabilities.add()
            for i in range(commandName.size()):
                capability.commandPrefix.components.append(
                        str(commandName.get(i).getValue()))

            for kw in command.keywords:
                capability.keywords.append(kw)

            capability.needsSignature = command.isSigned

        encodedCapabilities = ProtobufTlv.encode(capabilitiesMessage)
        fullCommandName.append(encodedCapabilities)
        interest = Interest(fullCommandName)
        interest.setInterestLifetimeMilliseconds(5000)
        self.face.makeCommandInterest(interest)
        signature = self._policyManager._extractSignature(interest)

        self.log.info("Sending capabilities to controller")
        self.face.expressInterest(interest, self._onCapabilitiesAck, self._onCapabilitiesTimeout)

        # update twice a minute
        self.loop.call_later(30, self._updateCapabilities)
Ejemplo n.º 7
0
def main():
    face = Face("localhost")

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(
      IdentityManager(identityStorage, privateKeyStorage), None)
    keyChain.setFace(face)

    # Initialize the storage.
    keyName = Name("/testname/DSK-reposerver")
    certificateName = keyName.getSubName(0, keyName.size() - 1).append(
      "KEY").append(keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(
      keyName, DEFAULT_PUBLIC_KEY_DER, DEFAULT_PRIVATE_KEY_DER)

    echo = RepoServer(keyChain, certificateName)
    prefix = Name("/ndn/ucla.edu/bms")
    dump("Register prefix", prefix.toUri())
    face.registerPrefix(prefix, echo.onInterest, echo.onRegisterFailed)

    while True: 
        face.processEvents()
        # We need to sleep for a few milliseconds so we don't use 100% of the CPU.
        time.sleep(0.01)

    face.shutdown()
def benchmarkDecodeDataSeconds(nIterations, useCrypto, encoding):
    """
    Loop to decode a data packet nIterations times.

    :param int nIterations: The number of iterations.
    :param bool useCrypto: If true, verify the signature.  If false, don't
      verify.
    :param Blob encoding: The wire encoding to decode.
    """
    # Initialize the private key storage in case useCrypto is true.
    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        SelfVerifyPolicyManager(identityStorage))
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(0, keyName.size() - 1).append(
      "KEY").append(keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER))

    start = getNowSeconds()
    for i in range(nIterations):
        data = Data()
        data.wireDecode(encoding)

        if useCrypto:
            keyChain.verifyData(data, onVerified, onVerifyFailed)

    finish = getNowSeconds()

    return finish - start
Ejemplo n.º 9
0
def main():
    # The default Face will connect using a Unix socket, or to "localhost".
    face = Face()

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        None)
    keyChain.setFace(face)

    # Initialize the storage.
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(
        0,
        keyName.size() - 1).append("KEY").append(
            keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA,
                           Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA,
                                           DEFAULT_RSA_PUBLIC_KEY_DER,
                                           DEFAULT_RSA_PRIVATE_KEY_DER)

    echo = Echo(keyChain, certificateName)
    prefix = Name("/testecho")
    dump("Register prefix", prefix.toUri())
    face.registerPrefix(prefix, echo.onInterest, echo.onRegisterFailed)

    while echo._responseCount < 1:
        face.processEvents()
        # We need to sleep for a few milliseconds so we don't use 100% of the CPU.
        time.sleep(0.01)

    face.shutdown()
Ejemplo n.º 10
0
def benchmarkDecodeDataSeconds(nIterations, useCrypto, encoding):
    """
    Loop to decode a data packet nIterations times.

    :param int nIterations: The number of iterations.
    :param bool useCrypto: If true, verify the signature.  If false, don't
      verify.
    :param Blob encoding: The wire encoding to decode.
    """
    # Initialize the private key storage in case useCrypto is true.
    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        SelfVerifyPolicyManager(identityStorage))
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(
        0,
        keyName.size() - 1).append("KEY").append(
            keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA,
                           Blob(DEFAULT_RSA_PUBLIC_KEY_DER))

    start = getNowSeconds()
    for i in range(nIterations):
        data = Data()
        data.wireDecode(encoding)

        if useCrypto:
            keyChain.verifyData(data, onVerified, onVerifyFailed)

    finish = getNowSeconds()

    return finish - start
Ejemplo n.º 11
0
    def _updateCapabilities(self):
        """
        Send the controller a list of our commands.
        """
        fullCommandName = Name(
            self._policyManager.getTrustRootIdentity()).append(
                'updateCapabilities')
        capabilitiesMessage = UpdateCapabilitiesCommandMessage()

        for command in self._commands:
            commandName = Name(self.prefix).append(Name(command.suffix))
            capability = capabilitiesMessage.capabilities.add()
            for i in range(commandName.size()):
                capability.commandPrefix.components.append(
                    str(commandName.get(i).getValue()))

            for kw in command.keywords:
                capability.keywords.append(kw)

            capability.needsSignature = command.isSigned

        encodedCapabilities = ProtobufTlv.encode(capabilitiesMessage)
        fullCommandName.append(encodedCapabilities)
        interest = Interest(fullCommandName)
        interest.setInterestLifetimeMilliseconds(5000)
        self.face.makeCommandInterest(interest)
        signature = self._policyManager._extractSignature(interest)

        self.log.info("Sending capabilities to controller")
        self.face.expressInterest(interest, self._onCapabilitiesAck,
                                  self._onCapabilitiesTimeout)

        # update twice a minute
        self.loop.call_later(30, self._updateCapabilities)
def main():
    interest = Interest()
    interest.wireDecode(TlvInterest)
    dump("Interest:")
    dumpInterest(interest)

    # Set the name again to clear the cached encoding so we encode again.
    interest.setName(interest.getName())
    encoding = interest.wireEncode()
    dump("")
    dump("Re-encoded interest", encoding.toHex())

    reDecodedInterest = Interest()
    reDecodedInterest.wireDecode(encoding)
    dump("Re-decoded Interest:")
    dumpInterest(reDecodedInterest)

    freshInterest = Interest(Name("/ndn/abc"))
    freshInterest.setMustBeFresh(False)
    dump(freshInterest.toUri())
    freshInterest.setMinSuffixComponents(4)
    freshInterest.setMaxSuffixComponents(6)
    freshInterest.getKeyLocator().setType(KeyLocatorType.KEY_LOCATOR_DIGEST)
    freshInterest.getKeyLocator().setKeyData(bytearray(
      [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F]))
    freshInterest.getExclude().appendComponent(Name("abc")[0]).appendAny()
    freshInterest.setInterestLifetimeMilliseconds(30000)
    freshInterest.setChildSelector(1)
    freshInterest.setMustBeFresh(True);
    freshInterest.setScope(2)

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        SelfVerifyPolicyManager(identityStorage))

    # Initialize the storage.
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(0, keyName.size() - 1).append(
      "KEY").append(keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(
      keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER, DEFAULT_RSA_PRIVATE_KEY_DER)

    # Make a Face just so that we can sign the interest.
    face = Face("localhost")
    face.setCommandSigningInfo(keyChain, certificateName)
    face.makeCommandInterest(freshInterest)

    reDecodedFreshInterest = Interest()
    reDecodedFreshInterest.wireDecode(freshInterest.wireEncode())
    dump("")
    dump("Re-decoded fresh Interest:")
    dumpInterest(reDecodedFreshInterest)

    keyChain.verifyInterest(
      reDecodedFreshInterest, makeOnVerified("Freshly-signed Interest"),
      makeOnVerifyFailed("Freshly-signed Interest"))
Ejemplo n.º 13
0
    def __init__(self):
        self.identityStorage = MemoryIdentityStorage()
        self.privateKeyStorage = MemoryPrivateKeyStorage()
        self.keyChain = KeyChain(IdentityManager(self.identityStorage, self.privateKeyStorage), 
                        SelfVerifyPolicyManager(self.identityStorage))
        keyName = Name("/testname/DSK-123")
        self.defaultCertName = keyName.getSubName(0, keyName.size() - 1).append(
      "KEY").append(keyName[-1]).append("ID-CERT").append("0")

        self.identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
        self.privateKeyStorage.setKeyPairForKeyName(
      keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER, DEFAULT_RSA_PRIVATE_KEY_DER)
Ejemplo n.º 14
0
    def setUp(self):
        self.decryptionKeys = {}  # key: Name, value: Blob
        self.encryptionKeys = {}  # key: Name, value: Data

        # Reuse the policy_config subdirectory for the temporary SQLite files.
        self.databaseFilePath = "policy_config/test.db"
        try:
            os.remove(self.databaseFilePath)
        except OSError:
            # no such file
            pass

        self.groupName = Name("/Prefix/READ")
        self.contentName = Name("/Prefix/SAMPLE/Content")
        self.cKeyName = Name("/Prefix/SAMPLE/Content/C-KEY/1")
        self.eKeyName = Name("/Prefix/READ/E-KEY/1/2")
        self.dKeyName = Name("/Prefix/READ/D-KEY/1/2")
        self.uKeyName = Name("/U/Key")
        self.uName = Name("/U")

        # Generate the E-KEY and D-KEY.
        params = RsaKeyParams()
        self.fixtureDKeyBlob = RsaAlgorithm.generateKey(params).getKeyBits()
        self.fixtureEKeyBlob = RsaAlgorithm.deriveEncryptKey(
            self.fixtureDKeyBlob).getKeyBits()

        # Generate the user key.
        self.fixtureUDKeyBlob = RsaAlgorithm.generateKey(params).getKeyBits()
        self.fixtureUEKeyBlob = RsaAlgorithm.deriveEncryptKey(
            self.fixtureUDKeyBlob).getKeyBits()

        # Load the C-KEY.
        self.fixtureCKeyBlob = Blob(AES_KEY, False)

        # Set up the keyChain.
        identityStorage = MemoryIdentityStorage()
        privateKeyStorage = MemoryPrivateKeyStorage()
        self.keyChain = KeyChain(
            IdentityManager(identityStorage, privateKeyStorage),
            NoVerifyPolicyManager())

        # Initialize the storage.
        keyName = Name("/testname/DSK-123")
        self.certificateName = keyName.getSubName(
            0,
            keyName.size() - 1).append("KEY").append(
                keyName.get(-1)).append("ID-CERT").append("0")
        identityStorage.addKey(keyName, KeyType.RSA,
                               Blob(DEFAULT_RSA_PUBLIC_KEY_DER, False))
        privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA,
                                               DEFAULT_RSA_PUBLIC_KEY_DER,
                                               DEFAULT_RSA_PRIVATE_KEY_DER)
    def createCheckInterest(self, fullName, checkNum):
        insertionName = Name(self.repoPrefix).append('insert check')
        commandParams = RepoCommandParameterMessage()
        interestName = Name(fullName)

        commandParams.repo_command_parameter.process_id = checkNum
        for i in range(interestName.size()):
            commandParams.repo_command_parameter.name.component.append(str(interestName.get(i).getValue()))

        commandName = insertionName.append(ProtobufTlv.encode(commandParams))
        interest = Interest(commandName)

        return interest
Ejemplo n.º 16
0
def createCheckInterest(fullName, checkNum):
    insertionName = Name("/repotest/repo/insert check")
    commandParams = RepoCommandParameterMessage()
    interestName = Name(fullName)

    commandParams.repo_command_parameter.process_id = checkNum
    for i in range(interestName.size()):
        commandParams.repo_command_parameter.name.component.append(interestName.get(i).toEscapedString())

    commandName = insertionName.append(ProtobufTlv.encode(commandParams))
    interest = Interest(commandName)

    return interest
Ejemplo n.º 17
0
    def setUp(self):
        self.decryptionKeys = {} # key: Name, value: Blob
        self.encryptionKeys = {} # key: Name, value: Data

        # Reuse the policy_config subdirectory for the temporary SQLite files.
        self.databaseFilePath = "policy_config/test.db"
        try:
            os.remove(self.databaseFilePath)
        except OSError:
            # no such file
            pass

        self.groupName = Name("/Prefix/READ")
        self.contentName = Name("/Prefix/SAMPLE/Content")
        self.cKeyName = Name("/Prefix/SAMPLE/Content/C-KEY/1")
        self.eKeyName = Name("/Prefix/READ/E-KEY/1/2")
        self.dKeyName = Name("/Prefix/READ/D-KEY/1/2")
        self.uKeyName = Name("/U/Key")
        self.uName = Name("/U")

        # Generate the E-KEY and D-KEY.
        params = RsaKeyParams()
        self.fixtureDKeyBlob = RsaAlgorithm.generateKey(params).getKeyBits()
        self.fixtureEKeyBlob = RsaAlgorithm.deriveEncryptKey(
          self.fixtureDKeyBlob).getKeyBits()

        # Generate the user key.
        self.fixtureUDKeyBlob = RsaAlgorithm.generateKey(params).getKeyBits()
        self.fixtureUEKeyBlob = RsaAlgorithm.deriveEncryptKey(
          self.fixtureUDKeyBlob).getKeyBits()

        # Load the C-KEY.
        self.fixtureCKeyBlob = Blob(AES_KEY, False)

        # Set up the keyChain.
        identityStorage = MemoryIdentityStorage()
        privateKeyStorage = MemoryPrivateKeyStorage()
        self.keyChain = KeyChain(
          IdentityManager(identityStorage, privateKeyStorage),
          NoVerifyPolicyManager())

        # Initialize the storage.
        keyName = Name("/testname/DSK-123")
        self.certificateName = keyName.getSubName(0, keyName.size() - 1).append(
          "KEY").append(keyName.get(-1)).append("ID-CERT").append("0")
        identityStorage.addKey(
          keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER, False))
        privateKeyStorage.setKeyPairForKeyName(
          keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER,
          DEFAULT_RSA_PRIVATE_KEY_DER)
Ejemplo n.º 18
0
    def onListResponse(self, interest, data):
        
        tempCont = data.getContent()
        tempStr = tempCont.__str__()
	#sleep for 1 sec therefore we can run more important process in the threadSafeFace        
	time.sleep(1)
        tempList = tempStr.split(",")
	#add songs to song list        
	for i in tempList:
                self.totalList.append(i)
        print "List Update:",self.totalList
        dataName = Name(data.getName())
        deviceComponent = data.getName().get(dataName.size()-1)
        device = deviceComponent.toEscapedString()
        self.issueListCommand(device)
Ejemplo n.º 19
0
    def onListResponse(self, interest, data):

        tempCont = data.getContent()
        tempStr = tempCont.__str__()
        #sleep for 1 sec therefore we can run more important process in the threadSafeFace
        time.sleep(1)
        tempList = tempStr.split(",")
        #add songs to song list
        for i in tempList:
            self.totalList.append(i)
        print "List Update:", self.totalList
        dataName = Name(data.getName())
        deviceComponent = data.getName().get(dataName.size() - 1)
        device = deviceComponent.toEscapedString()
        self.issueListCommand(device)
Ejemplo n.º 20
0
def main():
    data = Data()
    data.wireDecode(TlvData)
    dump("Decoded Data:")
    dumpData(data)

    # Set the content again to clear the cached encoding so we encode again.
    data.setContent(data.getContent())
    encoding = data.wireEncode()

    reDecodedData = Data()
    reDecodedData.wireDecode(encoding)
    dump("")
    dump("Re-decoded Data:")
    dumpData(reDecodedData)

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        SelfVerifyPolicyManager(identityStorage))

    # Initialize the storage.
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(
        0,
        keyName.size() - 1).append("KEY").append(
            keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA,
                           Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA,
                                           DEFAULT_RSA_PUBLIC_KEY_DER,
                                           DEFAULT_RSA_PRIVATE_KEY_DER)

    keyChain.verifyData(reDecodedData, makeOnVerified("Re-decoded Data"),
                        makeOnVerifyFailed("Re-decoded Data"))

    freshData = Data(Name("/ndn/abc"))
    freshData.setContent("SUCCESS!")
    freshData.getMetaInfo().setFreshnessPeriod(5000)
    freshData.getMetaInfo().setFinalBlockId(Name("/%00%09")[0])
    keyChain.sign(freshData, certificateName)
    dump("")
    dump("Freshly-signed Data:")
    dumpData(freshData)

    keyChain.verifyData(freshData, makeOnVerified("Freshly-signed Data"),
                        makeOnVerifyFailed("Freshly-signed Data"))
Ejemplo n.º 21
0
    def __init__(self):
        self.identityStorage = MemoryIdentityStorage()
        self.privateKeyStorage = MemoryPrivateKeyStorage()
        self.keyChain = KeyChain(
            IdentityManager(self.identityStorage, self.privateKeyStorage),
            SelfVerifyPolicyManager(self.identityStorage))
        keyName = Name("/testname/DSK-123")
        self.defaultCertName = keyName.getSubName(
            0,
            keyName.size() - 1).append("KEY").append(
                keyName[-1]).append("ID-CERT").append("0")

        self.identityStorage.addKey(keyName, KeyType.RSA,
                                    Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
        self.privateKeyStorage.setKeyPairForKeyName(
            keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER,
            DEFAULT_RSA_PRIVATE_KEY_DER)
Ejemplo n.º 22
0
def createInsertInterest(fullName):
    # we have to do the versioning when we poke the repo
    interestName = Name(fullName)
    logger.debug('Creating insert interest for: '+interestName.toUri())
    
    insertionName = Name("/repotest/repo/insert")
    commandParams = RepoCommandParameterMessage()

    for i in range(interestName.size()):
        commandParams.repo_command_parameter.name.component.append(interestName.get(i).toEscapedString())

    commandParams.repo_command_parameter.start_block_id = 0
    commandParams.repo_command_parameter.end_block_id = 0

    commandName = insertionName.append(ProtobufTlv.encode(commandParams))
    interest = Interest(commandName)

    return interest
Ejemplo n.º 23
0
def main():
    data = Data()
    data.wireDecode(TlvData)
    dump("Decoded Data:")
    dumpData(data)

    # Set the content again to clear the cached encoding so we encode again.
    data.setContent(data.getContent())
    encoding = data.wireEncode()

    reDecodedData = Data()
    reDecodedData.wireDecode(encoding)
    dump("")
    dump("Re-decoded Data:")
    dumpData(reDecodedData)

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        SelfVerifyPolicyManager(identityStorage))

    # Initialize the storage.
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(0, keyName.size() - 1).append(
      "KEY").append(keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(
      keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER, DEFAULT_RSA_PRIVATE_KEY_DER)

    keyChain.verifyData(reDecodedData, makeOnVerified("Re-decoded Data"),
                        makeOnVerifyFailed("Re-decoded Data"))

    freshData = Data(Name("/ndn/abc"))
    freshData.setContent("SUCCESS!")
    freshData.getMetaInfo().setFreshnessPeriod(5000)
    freshData.getMetaInfo().setFinalBlockId(Name("/%00%09")[0])
    keyChain.sign(freshData, certificateName)
    dump("")
    dump("Freshly-signed Data:")
    dumpData(freshData)

    keyChain.verifyData(freshData, makeOnVerified("Freshly-signed Data"),
                        makeOnVerifyFailed("Freshly-signed Data"))
Ejemplo n.º 24
0
    def test_append_parameters_digest(self):
        name = Name("/local/ndn/prefix")
        interest = Interest(name)

        self.assertTrue(not interest.hasApplicationParameters())
        # No parameters yet, so it should do nothing.
        interest.appendParametersDigestToName()
        self.assertEqual("/local/ndn/prefix", interest.getName().toUri())

        applicationParameters = Blob(bytearray([ 0x23, 0x01, 0xC0 ]))
        interest.setApplicationParameters(applicationParameters)
        self.assertTrue(interest.hasApplicationParameters())
        interest.appendParametersDigestToName()
        self.assertEqual(name.size() + 1, interest.getName().size())
        self.assertTrue(interest.getName().getPrefix(-1).equals(name))
        SHA256_LENGTH = 32
        self.assertEqual(SHA256_LENGTH, interest.getName().get(-1).getValue().size())
        
        self.assertEqual(interest.getName().toUri(), "/local/ndn/prefix/" +
          "params-sha256=a16cc669b4c9ef6801e1569488513f9523ffb28a39e53aa6e11add8d00a413fc")
    def createInsertInterest(self, fullName):
        '''
            For poking the repo
        '''
        # we have to do the versioning before we poke the repo
        interestName = Name(fullName)
        logger.debug('Creating insert interest for: '+interestName.toUri())
        
        insertionName = Name(self.repoPrefix).append('insert')
        commandParams = RepoCommandParameterMessage()

        for i in range(interestName.size()):
            commandParams.repo_command_parameter.name.component.append(interestName.get(i).getValue().toRawStr())

        commandParams.repo_command_parameter.start_block_id = 0
        commandParams.repo_command_parameter.end_block_id = 0

        commandName = insertionName.append(ProtobufTlv.encode(commandParams))
        interest = Interest(commandName)

        interest.setInterestLifetimeMilliseconds(2000)

        return interest
Ejemplo n.º 26
0
def createKeyChain():
    """
    Create an in-memory KeyChain with default keys.

    :return: A tuple with the new KeyChain and certificate name.
    :rtype: (KeyChain,Name)
    """
    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(
      IdentityManager(identityStorage, privateKeyStorage),
      NoVerifyPolicyManager())

    # Initialize the storage.
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(0, keyName.size() - 1).append(
      "KEY").append(keyName.get(-1)).append("ID-CERT").append("0")
    identityStorage.addKey(
      keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER, False))
    privateKeyStorage.setKeyPairForKeyName(
      keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER,
      DEFAULT_RSA_PRIVATE_KEY_DER)

    return keyChain, certificateName
Ejemplo n.º 27
0
class BACnetAggregator(BIPSimpleApplication, Logging):

    def __init__(self, config):
        if _debug: BACnetAggregator._debug("__init__ %r", config)

        # get local address from the config file
        laddr = config.get('BACpypes', 'address')
        
        # make a local device object
        local_device = \
          LocalDeviceObject( objectName=config.get('BACpypes','objectName')
                             , objectIdentifier=config.getint('BACpypes','objectIdentifier')
                             , maxApduLengthAccepted=config.getint('BACpypes','maxApduLengthAccepted')
                             , segmentationSupported=config.get('BACpypes','segmentationSupported')
                             , vendorIdentifier=config.getint('BACpypes','vendorIdentifier')
              )
        
        # build a bit string that knows about the bit names
        pss = ServicesSupported()
        pss['whoIs'] = 1
        pss['iAm'] = 1
        pss['readProperty'] = 1
        pss['writeProperty'] = 1
        
        # set the property value to be just the bits
        local_device.protocolServicesSupported = pss.value
        
        # make a simple application
        BIPSimpleApplication.__init__(self, local_device, laddr)

        
        # create logger
        self.logger = BACnetDataLogger(self, config)
        self.loadKey()
        # keep track of requests to line up responses
        self._request = None

        # connect to local repo
        self.publisher = RepoSocketPublisher(12345)
        self.interval = 5 # in seconds
    
    def loadKey(self):
        self.identityStorage = MemoryIdentityStorage()
        self.privateKeyStorage = MemoryPrivateKeyStorage()
        self.keychain = KeyChain(IdentityManager(self.identityStorage, self.privateKeyStorage))

        f = open(key_file, "r")
        self.key = RSA.importKey(f.read())
        self.key_name = Name(bld_root).append(getKeyID(self.key))
        key_pub_der = bytearray(self.key.publickey().exportKey(format="DER"))
        key_pri_der = bytearray(self.key.exportKey(format="DER"))
        self.identityStorage.addKey(self.key_name, KeyType.RSA, Blob(key_pub_der))
        self.privateKeyStorage.setKeyPairForKeyName(self.key_name, key_pub_der, key_pri_der)
        self.cert_name = self.key_name.getSubName(0, self.key_name.size() - 1).append(
            "KEY").append(self.key_name[-1]).append("ID-CERT").append("0")

        print 'KeyName = ' + self.key_name.toUri()
        print 'CertName = ' + self.cert_name.toUri()

    def publishData(self, name_str, payload, timestamp):
        data = Data(Name(name_str).append(bytearray(timestamp)))
        iv = Random.new().read(AES.block_size)
        encryptor = AES.new(key, AES.MODE_CBC, iv)
        data.setContent(bytearray(time_s + iv + encryptor.encrypt(pad(json.dumps(payload)))))
        data.getMetaInfo().setFreshnessPeriod(10000)
        self.keychain.sign(data, self.cert_name)
        self.publisher.put(data)
        #print payload
        #print 'Publish ' + data.getName().toUri()

    def request(self, apdu):
        if _debug: BACnetAggregator._debug("request %r", apdu)

        # save a copy of the request
        self._request = apdu

        # forward it along
        BIPSimpleApplication.request(self, apdu)

    def confirmation(self, apdu):
        #print thread.get_ident()
        global kds_count, key, time_s, point_count
        
        if _debug: BACnetAggregator._debug("confirmation %r", apdu)

        if isinstance(apdu, Error):
            sys.stdout.write("error: %s\n" % (apdu.errorCode,))
            sys.stdout.flush()

        elif isinstance(apdu, AbortPDU):
            apdu.debug_contents()

        elif (isinstance(self._request, ReadPropertyRequest)) and (isinstance(apdu, ReadPropertyACK)):
            # find the datatype
            datatype = get_datatype(apdu.objectIdentifier[0], apdu.propertyIdentifier)
            BACnetAggregator._debug("    - datatype: %r", datatype)
            if not datatype:
                raise TypeError, "unknown datatype"

            # special case for array parts, others are managed by cast_out
            if issubclass(datatype, Array) and (apdu.propertyArrayIndex is not None):
                if apdu.propertyArrayIndex == 0:
                    value = apdu.propertyValue.cast_out(Unsigned)
                else:
                    value = apdu.propertyValue.cast_out(datatype.subtype)
            else:
                value = apdu.propertyValue.cast_out(datatype)
            BACnetAggregator._debug("    - value: %r", value)

            #sys.stdout.write(str(value) + '\n')
            #sys.stdout.flush()

            # KDS
            if kds_count % 1200 == 0:
                time_t = int(time.time() * 1000)
                time_s = struct.pack("!Q", time_t)
                
                key = Random.new().read(32)
                kds_thread = kds.SimpleKDSPublisher(Name(bld_root), self.keychain, self.cert_name, key, time_s)
                kds_thread.start()
                kds_count = 0

            kds_count = kds_count + 1
            #
            
            now = int(time.time() * 1000) # in milliseconds
            
            payload = {'ts': now, 'val': value}
            
            timestamp = struct.pack("!Q", now)
            self.publishData(datapoints[point_count]['prefix'], payload, timestamp)
            point_count = (point_count + 1) % len(datapoints)

            #
            #
            # We could move the 'sleep&read' looping into logger thread so
            # that we could parallel read and write processes. For now we
            # only work on a single thread. The logger thread simply kicks 
            # off the initial request and then exits.
            #
            if point_count == 0:
                time.sleep(self.interval)

            self.logger.do_read()

    def indication(self, apdu):
        if _debug: BACnetAggregator._debug("indication %r", apdu)

        if (isinstance(self._request, WhoIsRequest)) and (isinstance(apdu, IAmRequest)):
            device_type, device_instance = apdu.iAmDeviceIdentifier
            if device_type != 'device':
                raise DecodingError, "invalid object type"

            if (self._request.deviceInstanceRangeLowLimit is not None) and \
                (device_instance < self._request.deviceInstanceRangeLowLimit):
                pass
            elif (self._request.deviceInstanceRangeHighLimit is not None) and \
                (device_instance > self._request.deviceInstanceRangeHighLimit):
                pass
            else:
                # print out the contents
                sys.stdout.write('pduSource = ' + repr(apdu.pduSource) + '\n')
                sys.stdout.write('iAmDeviceIdentifier = ' + str(apdu.iAmDeviceIdentifier) + '\n')
                sys.stdout.write('maxAPDULengthAccepted = ' + str(apdu.maxAPDULengthAccepted) + '\n')
                sys.stdout.write('segmentationSupported = ' + str(apdu.segmentationSupported) + '\n')
                sys.stdout.write('vendorID = ' + str(apdu.vendorID) + '\n')
                sys.stdout.flush()

        # forward it along
        BIPSimpleApplication.indication(self, apdu)
Ejemplo n.º 28
0
class IotController(BaseNode):
    """
    The controller class has a few built-in commands:
        - listCommands: return the names and capabilities of all attached 
            devices
        - certificateRequest: takes public key information and returns name of
            new certificate
        - updateCapabilities: should be sent periodically from IotNodes to 
            update their command lists
        - addDevice: called by the console to begin pairing, the payload is 
            encrypted for the controller as it contains a PIN
    It is unlikely that you will need to subclass this.
    """
    def __init__(self, nodeName, networkName):
        super(IotController, self).__init__()
        
        self.deviceSuffix = Name(nodeName)
        self.networkPrefix = Name(networkName)
        self.prefix = Name(self.networkPrefix).append(self.deviceSuffix)

        self._policyManager.setEnvironmentPrefix(self.networkPrefix)
        self._policyManager.setTrustRootIdentity(self.prefix)
        self._policyManager.setDeviceIdentity(self.prefix)
        self._policyManager.updateTrustRules()
        
        # the controller keeps a directory of capabilities->names
        self._directory = defaultdict(list)

        # keep track of who's still using HMACs
        # key is device serial, value is the HmacHelper
        self._hmacDevices = {}

        # our capabilities
        self._baseDirectory = {}

        # add the built-ins
        self._insertIntoCapabilities('listCommands', 'directory', False)

        # TODO: use xDialog in XWindows
        self.ui = Dialog(backtitle='NDN IoT User Console', height=18, width=78)

        self._directory.update(self._baseDirectory)
        self.setLogLevel(logging.INFO)

    def _insertIntoCapabilities(self, commandName, keyword, isSigned):
        newUri = Name(self.prefix).append(Name(commandName)).toUri()
        self._baseDirectory[keyword] = [{'signed':isSigned, 'name':newUri}]

    def beforeLoopStart(self):
        if not self._policyManager.hasRootSignedCertificate():
            # make one....
            self.log.warn('Generating controller key pair (this could take a while)...')
            newKey = self._identityManager.generateRSAKeyPairAsDefault(
                self.prefix, isKsk=True, progressFunc=self._showRSAProgress)
            newCert = self._identityManager.selfSign(newKey)
            self._identityManager.addCertificateAsDefault(newCert)
        self.face.setCommandSigningInfo(self._keyChain, self.getDefaultCertificateName())
        self.face.registerPrefix(self.prefix, 
            self._onCommandReceived, self.onRegisterFailed)
        self.loop.call_soon(self.onStartup)


######
# Initial device configuration
#######

    def _beginPairing(self, encryptedMessage):
        # base64 decode, decrypt, protobuf decode
        responseCode = 202
        try:
            encryptedBytes = base64.urlsafe_b64decode(str(encryptedMessage.getValue()))
            decryptedBytes = self._identityManager.decryptAsIdentity(encryptedBytes, self.prefix)
            message = DevicePairingInfoMessage()
            ProtobufTlv.decode(message, decryptedBytes)
        except:
            responseCode = 500
        else:
            info = message.info
            self.loop.call_soon(self._addDeviceToNetwork, info.deviceSerial, 
                info.deviceSuffix, info.devicePin)
        return responseCode

    def _addDeviceToNetwork(self, deviceSerial, newDeviceSuffix, pin):
        h = HmacHelper(pin)
        self._hmacDevices[deviceSerial] = h

        d = DeviceConfigurationMessage()

        newDeviceSuffix = Name(newDeviceSuffix)

        for source, dest in [(self.networkPrefix, d.configuration.networkPrefix),
                             (self.deviceSuffix, d.configuration.controllerName),
                             (newDeviceSuffix, d.configuration.deviceSuffix)]:
            for i in range(len(source)):
                component = source.get(i)
                dest.components.append(component.getValue().toRawStr())

        interestName = Name('/localhop/configure').append(Name(deviceSerial))
        encodedParams = ProtobufTlv.encode(d)
        interestName.append(encodedParams)
        interest = Interest(interestName)
        interest.setInterestLifetimeMilliseconds(5000)
        h.signInterest(interest)

        self.face.expressInterest(interest, self._deviceAdditionResponse,
            self._deviceAdditionTimedOut)

    def _deviceAdditionTimedOut(self, interest):
        deviceSerial = str(interest.getName().get(2).getValue())
        self.log.warn("Timed out trying to configure device " + deviceSerial)
        # don't try again
        self._hmacDevices.pop(deviceSerial)

    def _deviceAdditionResponse(self, interest, data):
        status = data.getContent().toRawStr()
        deviceSerial = str(interest.getName().get(2).getValue())
        hmacChecker = self._hmacDevices[deviceSerial]
        if (hmacChecker.verifyData(data)): 
            self.log.info("Received {} from {}".format(status, deviceSerial))
        else:
            self.log.warn("Received invalid HMAC from {}".format(deviceSerial))
        
######
# Certificate signing
######

    def _handleCertificateRequest(self, interest, transport):
        """
        Extracts a public key name and key bits from a command interest name 
        component. Generates a certificate if the request is verifiable.

        This expects an HMAC signed interest.
        """
        message = CertificateRequestMessage()
        commandParamsTlv = interest.getName().get(self.prefix.size()+1)
        ProtobufTlv.decode(message, commandParamsTlv.getValue())

        signature = HmacHelper.extractInterestSignature(interest)
        deviceSerial = str(signature.getKeyLocator().getKeyName().get(-1).getValue())

        response = Data(interest.getName())
        certData = None
        hmac = None
        try:
            hmac = self._hmacDevices[deviceSerial]
            if hmac.verifyInterest(interest):
                certData = self._createCertificateFromRequest(message)
                # remove this hmac; another request will require a new pin
                self._hmacDevices.pop(deviceSerial)
        except KeyError:
            self.log.warn('Received certificate request for device with no registered key')
        except SecurityException:
            self.log.warn('Could not create device certificate')
        else:
            self.log.info('Creating certificate for device {}'.format(deviceSerial))

        if certData is not None:
            response.setContent(certData.wireEncode())
            response.getMetaInfo().setFreshnessPeriod(10000) # should be good even longer
        else:
            response.setContent("Denied")
        if hmac is not None:
            hmac.signData(response)
        self.sendData(response, transport, False)

    def _createCertificateFromRequest(self, message):
        """
        Generate an IdentityCertificate from the public key information given.
        """
        # TODO: Verify the certificate was actually signed with the private key
        # matching the public key we are issuing a cert for!!

        keyComponents = message.command.keyName.components
        keyName = Name("/".join(keyComponents))

        self.log.debug("Key name: " + keyName.toUri())

        if not self._policyManager.getEnvironmentPrefix().match(keyName):
            # we do not issue certs for keys outside of our network
            return None

        keyDer = Blob(message.command.keyBits)
        keyType = message.command.keyType

        try:
            self._identityStorage.addKey(keyName, keyType, keyDer)
        except SecurityException:
            # assume this is due to already existing?
            pass

        certificate = self._identityManager.generateCertificateForKey(keyName)

        self._keyChain.sign(certificate, self.getDefaultCertificateName())
        # store it for later use + verification
        self._identityStorage.addCertificate(certificate)
        return certificate

######
# Device Capabilities
######

    def _updateDeviceCapabilities(self, interest):
        """
        Take the received capabilities update interest and update our directory listings.
        """
        # we assume the sender is the one who signed the interest...
        signature = self._policyManager._extractSignature(interest)
        certificateName = signature.getKeyLocator().getKeyName()
        senderIdentity = IdentityCertificate.certificateNameToPublicKeyName(certificateName).getPrefix(-1)

        self.log.info('Updating capabilities for {}'.format(senderIdentity.toUri()))

        # get the params from the interest name
        messageComponent = interest.getName().get(self.prefix.size()+1)
        message = UpdateCapabilitiesCommandMessage()
        ProtobufTlv.decode(message, messageComponent.getValue())
        # we remove all the old capabilities for the sender
        tempDirectory = defaultdict(list)
        for keyword in self._directory:
            tempDirectory[keyword] = [cap for cap in self._directory[keyword] 
                    if not senderIdentity.match(Name(cap['name']))]

        # then we add the ones from the message
        for capability in message.capabilities:
            capabilityPrefix = Name()
            for component in capability.commandPrefix.components:
                capabilityPrefix.append(component)
            commandUri = capabilityPrefix.toUri()
            if not senderIdentity.match(capabilityPrefix):
                self.log.error("Node {} tried to register another prefix: {} - ignoring update".format(
                    senderIdentity.toUri(),commandUri))
            else:    
                for keyword in capability.keywords:
                    allUris = [info['name'] for info in tempDirectory[keyword]]
                    if capabilityPrefix not in allUris:
                        listing = {'signed':capability.needsSignature,
                                'name':commandUri}
                        tempDirectory[keyword].append(listing)
        self._directory= tempDirectory

    def _prepareCapabilitiesList(self, interestName):
        """
        Responds to a directory listing request with JSON
        """
        
        dataName = Name(interestName).append(Name.Component.fromNumber(int(time.time())))
        response = Data(dataName)

        response.setContent(json.dumps(self._directory))

        return response

#####
# Interest handling
####

    def _onCommandReceived(self, prefix, interest, transport, prefixId):
        """
        """
        interestName = interest.getName()

        #if it is a certificate name, serve the certificate
        foundCert = self._identityStorage.getCertificate(interestName)
        if foundCert is not None:
            self.log.debug("Serving certificate request")
            transport.send(foundCert.wireEncode().buf())
            return

        afterPrefix = interestName.get(prefix.size()).toEscapedString()
        if afterPrefix == "listCommands":
            #compose device list
            self.log.debug("Received device list request")
            response = self._prepareCapabilitiesList(interestName)
            self.sendData(response, transport)
        elif afterPrefix == "certificateRequest":
            #build and sign certificate
            self.log.debug("Received certificate request")
            self._handleCertificateRequest(interest, transport)
        elif afterPrefix == "updateCapabilities":
            # needs to be signed!
            self.log.debug("Received capabilities update")
            def onVerifiedCapabilities(interest):
                response = Data(interest.getName())
                response.setContent(str(time.time()))
                self.sendData(response, transport)
                self._updateDeviceCapabilities(interest)
            self._keyChain.verifyInterest(interest, 
                    onVerifiedCapabilities, self.verificationFailed)
        elif afterPrefix == "addDevice":
            self.log.debug("Received pairing request")
            def onVerifiedPairingRequest(interest):
                response = Data(interest.getName())
                encryptedMessage = interest.getName()[len(prefix)+1]
                responseCode = self._beginPairing(encryptedMessage)
                response.setContent(str(responseCode))
                self.sendData(response, transport)
            self._keyChain.verifyInterest(interest, onVerifiedPairingRequest, self.verificationFailed)
        else:
            response = Data(interest.getName())
            response.setContent("500")
            response.getMetaInfo().setFreshnessPeriod(1000)
            transport.send(response.wireEncode().buf())

    def onStartup(self):
        # begin taking add requests
        self.log.info('Controller is ready')

    def _showRSAProgress(self, displayStr=''):
        displayStr = displayStr.strip()
        msg = ''
        if displayStr == 'p,q':
            msg = 'Generating giant prime numbers...'
        elif displayStr == 'd':
            msg = 'Generating private exponent...'
        elif displayStr == 'u':
            msg = 'Checking CRT coefficient...'
        self.log.debug(msg)
Ejemplo n.º 29
0
def main():
    # Uncomment these lines to print ChronoSync debug messages.
    # logging.getLogger('').addHandler(logging.StreamHandler(sys.stdout))
    # logging.getLogger('').setLevel(logging.INFO)

    screenName = promptAndInput("Enter your chat username: "******"ndn/edu/ucla/remap"
    hubPrefix = promptAndInput("Enter your hub prefix [" + defaultHubPrefix +
                               "]: ")
    if hubPrefix == "":
        hubPrefix = defaultHubPrefix

    defaultChatRoom = "ndnchat"
    chatRoom = promptAndInput("Enter the chatroom name [" + defaultChatRoom +
                              "]: ")
    if chatRoom == "":
        chatRoom = defaultChatRoom

    host = "localhost"
    print("Connecting to " + host + ", Chatroom: " + chatRoom +
          ", Username: "******"")

    # Set up the key chain.
    face = Face(host)

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        NoVerifyPolicyManager())
    keyChain.setFace(face)
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(
        0,
        keyName.size() - 1).append("KEY").append(
            keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA,
                           Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA,
                                           DEFAULT_RSA_PUBLIC_KEY_DER,
                                           DEFAULT_RSA_PRIVATE_KEY_DER)
    face.setCommandSigningInfo(keyChain, certificateName)

    chat = Chat(screenName, chatRoom, Name(hubPrefix), face, keyChain,
                certificateName)

    # The main loop to process Chat while checking stdin to send a message.
    print("Enter your chat message. To quit, enter \"leave\" or \"exit\".")
    while True:
        # Set timeout to 0 for an immediate check.
        isReady, _, _ = select.select([sys.stdin], [], [], 0)
        if len(isReady) != 0:
            input = promptAndInput("")
            if input == "leave" or input == "exit":
                # We will send the leave message below.
                break

            chat.sendMessage(input)

        face.processEvents()
        # We need to sleep for a few milliseconds so we don't use 100% of the CPU.
        time.sleep(0.01)

    # The user entered the command to leave.
    chat.leave()
    # Wait a little bit to allow other applications to fetch the leave message.
    startTime = Chat.getNowMilliseconds()
    while True:
        if Chat.getNowMilliseconds() - startTime >= 1000.0:
            break

        face.processEvents()
        time.sleep(0.01)
Ejemplo n.º 30
0
class IotController(BaseNode):
    """
    The controller class has a few built-in commands:
        - listDevices: return the names and capabilities of all attached devices
        - certificateRequest: takes public key information and returns name of
            new certificate
        - updateCapabilities: should be sent periodically from IotNodes to update their
           command lists
        - addDevice: add a device based on HMAC
    It is unlikely that you will need to subclass this.
    """
    def __init__(self, nodeName, networkName):
        super(IotController, self).__init__()
        
        self.deviceSuffix = Name(nodeName)
        self.networkPrefix = Name(networkName)
        self.prefix = Name(self.networkPrefix).append(self.deviceSuffix)

        self._policyManager.setEnvironmentPrefix(self.networkPrefix)
        self._policyManager.setTrustRootIdentity(self.prefix)
        self._policyManager.setDeviceIdentity(self.prefix)
        self._policyManager.updateTrustRules()
        
        # the controller keeps a directory of capabilities->names
        self._directory = defaultdict(list)

        # keep track of who's still using HMACs
        # key is device serial, value is the HmacHelper
        self._hmacDevices = {}

        # our capabilities
        self._baseDirectory = {}

        # add the built-ins
        self._insertIntoCapabilities('listDevices', 'directory', False)
        self._insertIntoCapabilities('updateCapabilities', 'capabilities', True)

        self._directory.update(self._baseDirectory)

    def _insertIntoCapabilities(self, commandName, keyword, isSigned):
        newUri = Name(self.prefix).append(Name(commandName)).toUri()
        self._baseDirectory[keyword] = [{'signed':isSigned, 'name':newUri}]

    def beforeLoopStart(self):
        if not self._policyManager.hasRootSignedCertificate():
            # make one....
            self.log.warn('Generating controller certificate...')
            newKey = self._identityManager.generateRSAKeyPairAsDefault(
                self.prefix, isKsk=True)
            newCert = self._identityManager.selfSign(newKey)
            self._identityManager.addCertificateAsDefault(newCert)
        self.face.setCommandSigningInfo(self._keyChain, self.getDefaultCertificateName())
        self.face.registerPrefix(self.prefix, 
            self._onCommandReceived, self.onRegisterFailed)
        self.loop.call_soon(self.onStartup)


######
# Initial configuration
#######
    # TODO: deviceSuffix will be replaced by deviceSerial
    def _addDeviceToNetwork(self, deviceSerial, newDeviceSuffix, pin):
        h = HmacHelper(pin)
        self._hmacDevices[deviceSerial] = h

        d = DeviceConfigurationMessage()

        for source, dest in [(self.networkPrefix, d.configuration.networkPrefix),
                             (self.deviceSuffix, d.configuration.controllerName),
                             (newDeviceSuffix, d.configuration.deviceSuffix)]:
            for i in range(source.size()):
                component = source.get(i)
                dest.components.append(component.getValue().toRawStr())

        interestName = Name('/localhop/configure').append(Name(deviceSerial))
        encodedParams = ProtobufTlv.encode(d)
        interestName.append(encodedParams)
        interest = Interest(interestName)
        h.signInterest(interest)

        self.face.expressInterest(interest, self._deviceAdditionResponse,
            self._deviceAdditionTimedOut)

    def _deviceAdditionTimedOut(self, interest):
        deviceSerial = str(interest.getName().get(2).getValue())
        self.log.warn("Timed out trying to configure device " + deviceSerial)
        # don't try again
        self._hmacDevices.pop(deviceSerial)

    def _deviceAdditionResponse(self, interest, data):
        status = data.getContent().toRawStr()
        deviceSerial = str(interest.getName().get(2).getValue())
        hmacChecker = self._hmacDevices[deviceSerial]
        if (hmacChecker.verifyData(data)): 
            self.log.info("Received {} from {}".format(status, deviceSerial))
        else:
            self.log.warn("Received invalid HMAC from {}".format(deviceSerial))
        
######
# Certificate signing
######

    def _handleCertificateRequest(self, interest, transport):
        """
        Extracts a public key name and key bits from a command interest name 
        component. Generates a certificate if the request is verifiable.

        This expects an HMAC signed interest.
        """
        message = CertificateRequestMessage()
        commandParamsTlv = interest.getName().get(self.prefix.size()+1)
        ProtobufTlv.decode(message, commandParamsTlv.getValue())

        signature = HmacHelper.extractInterestSignature(interest)
        deviceSerial = str(signature.getKeyLocator().getKeyName().get(-1).getValue())

        response = Data(interest.getName())
        certData = None
        hmac = None
        try:
            hmac = self._hmacDevices[deviceSerial]
            if hmac.verifyInterest(interest):
                certData = self._createCertificateFromRequest(message)
                # remove this hmac; another request will require a new pin
                self._hmacDevices.pop(deviceSerial)
        except KeyError:
            self.log.warn('Received certificate request for device with no registered key')
        except SecurityException:
            self.log.warn('Could not create device certificate')
        else:
            self.log.info('Creating certificate for device {}'.format(deviceSerial))

        if certData is not None:
            response.setContent(certData.wireEncode())
            response.getMetaInfo().setFreshnessPeriod(10000) # should be good even longer
        else:
            response.setContent("Denied")
        if hmac is not None:
            hmac.signData(response)
        self.sendData(response, transport, False)

    def _createCertificateFromRequest(self, message):
        """
        Generate an IdentityCertificate from the public key information given.
        """
        # TODO: Verify the certificate was actually signed with the private key
        # matching the public key we are issuing a cert for!!

        keyComponents = message.command.keyName.components
        keyName = Name("/".join(keyComponents))

        self.log.debug("Key name: " + keyName.toUri())

        if not self._policyManager.getEnvironmentPrefix().match(keyName):
            # we do not issue certs for keys outside of our network
            return None

        keyDer = Blob(message.command.keyBits)
        keyType = message.command.keyType

        try:
            self._identityStorage.addKey(keyName, keyType, keyDer)
        except SecurityException:
            # assume this is due to already existing?
            pass

        certificate = self._identityManager.generateCertificateForKey(keyName)

        self._keyChain.sign(certificate, self.getDefaultCertificateName())
        # store it for later use + verification
        self._identityStorage.addCertificate(certificate)
        self._policyManager._certificateCache.insertCertificate(certificate)
        return certificate

######
# Device Capabilities
######

    def _updateDeviceCapabilities(self, interest):
        """
        Take the received capabilities update interest and update our directory listings.
        """
        # we assume the sender is the one who signed the interest...
        signature = self._policyManager._extractSignature(interest)
        certificateName = signature.getKeyLocator().getKeyName()
        senderIdentity = IdentityCertificate.certificateNameToPublicKeyName(certificateName).getPrefix(-1)

        self.log.info('Updating capabilities for {}'.format(senderIdentity.toUri()))

        # get the params from the interest name
        messageComponent = interest.getName().get(self.prefix.size()+1)
        message = UpdateCapabilitiesCommandMessage()
        ProtobufTlv.decode(message, messageComponent.getValue())
        # we remove all the old capabilities for the sender
        tempDirectory = defaultdict(list)
        for keyword in self._directory:
            tempDirectory[keyword] = [cap for cap in self._directory[keyword] 
                    if not senderIdentity.match(Name(cap['name']))]

        # then we add the ones from the message
        for capability in message.capabilities:
            capabilityPrefix = Name()
            for component in capability.commandPrefix.components:
                capabilityPrefix.append(component)
            commandUri = capabilityPrefix.toUri()
            if not senderIdentity.match(capabilityPrefix):
                self.log.error("Node {} tried to register another prefix: {} - ignoring update".format(
                    senderIdentity.toUri(),commandUri))
            else:    
                for keyword in capability.keywords:
                    allUris = [info['name'] for info in tempDirectory[keyword]]
                    if capabilityPrefix not in allUris:
                        listing = {'signed':capability.needsSignature,
                                'name':commandUri}
                        tempDirectory[keyword].append(listing)
        self._directory= tempDirectory

    def _prepareCapabilitiesList(self, interestName):
        """
        Responds to a directory listing request with JSON
        """
        
        dataName = Name(interestName).append(Name.Component.fromNumber(int(time.time())))
        response = Data(dataName)

        response.setContent(json.dumps(self._directory))

        return response

#####
# Interest handling
####

    def _onCommandReceived(self, prefix, interest, transport, prefixId):
        """
        """
        interestName = interest.getName()

        #if it is a certificate name, serve the certificate
        foundCert = self._identityStorage.getCertificate(interestName)
        if foundCert is not None:
            self.log.debug("Serving certificate request")
            transport.send(foundCert.wireEncode().buf())
            return

        afterPrefix = interestName.get(prefix.size()).toEscapedString()
        if afterPrefix == "listDevices":
            #compose device list
            self.log.debug("Received device list request")
            response = self._prepareCapabilitiesList(interestName)
            self.sendData(response, transport)
        elif afterPrefix == "certificateRequest":
            #build and sign certificate
            self.log.debug("Received certificate request")
            self._handleCertificateRequest(interest, transport)

        elif afterPrefix == "updateCapabilities":
            # needs to be signed!
            self.log.debug("Received capabilities update")
            def onVerifiedCapabilities(interest):
                response = Data(interest.getName())
                response.setContent(str(time.time()))
                self.sendData(response, transport)
                self._updateDeviceCapabilities(interest)
            self._keyChain.verifyInterest(interest, 
                    onVerifiedCapabilities, self.verificationFailed)
        else:
            response = Data(interest.getName())
            response.setContent("500")
            response.getMetaInfo().setFreshnessPeriod(1000)
            transport.send(response.wireEncode().buf())

    def onStartup(self):
        # begin taking add requests
        self.loop.call_soon(self.displayMenu)
        self.loop.add_reader(stdin, self.handleUserInput) 

    def displayMenu(self):
        menuStr = "\n"
        menuStr += "P)air a new device with serial and PIN\n"
        menuStr += "D)irectory listing\n"
        menuStr += "E)xpress an interest\n"
        menuStr += "Q)uit\n"

        print(menuStr)
        print ("> ", end="")
        stdout.flush()

    def listDevices(self):
        menuStr = ''
        for capability, commands in self._directory.items():
            menuStr += '{}:\n'.format(capability)
            for info in commands:
                signingStr = 'signed' if info['signed'] else 'unsigned'
                menuStr += '\t{} ({})\n'.format(info['name'], signingStr)
        print(menuStr)
        self.loop.call_soon(self.displayMenu)

    def onInterestTimeout(self, interest):
        print('Interest timed out: {}'.interest.getName().toUri())

    def onDataReceived(self, interest, data):
        print('Received data named: {}'.format(data.getName().toUri()))
        print('Contents:\n{}'.format(data.getContent().toRawStr()))
    
    def expressInterest(self):
        try:
            interestName = input('Interest name: ')
            if len(interestName):
                toSign = input('Signed? (y/N): ').upper().startswith('Y')
                interest = Interest(Name(interestName))
                interest.setInterestLifetimeMilliseconds(5000)
                interest.setChildSelector(1)
                if (toSign):
                    self.face.makeCommandInterest(interest) 
                self.face.expressInterest(interest, self.onDataReceived, self.onInterestTimeout)
            else:
                print("Aborted")
        except KeyboardInterrupt:
                print("Aborted")
        finally:
                self.loop.call_soon(self.displayMenu)

    def beginPairing(self):
        try:
            deviceSerial = input('Device serial: ') 
            devicePin = input('PIN: ')
            deviceSuffix = input('Node name: ')
        except KeyboardInterrupt:
               print('Pairing attempt aborted')
        else:
            if len(deviceSerial) and len(devicePin) and len(deviceSuffix):
                self._addDeviceToNetwork(deviceSerial, Name(deviceSuffix), 
                    devicePin.decode('hex'))
            else:
               print('Pairing attempt aborted')
        finally:
            self.loop.call_soon(self.displayMenu)

    def handleUserInput(self):
        inputStr = stdin.readline().upper()
        if inputStr.startswith('D'):
            self.listDevices()
        elif inputStr.startswith('P'):
            self.beginPairing()
        elif inputStr.startswith('E'):
            self.expressInterest()
        elif inputStr.startswith('Q'):
            self.stop()
        else:
            self.loop.call_soon(self.displayMenu)
Ejemplo n.º 31
0
    rp.setName(dataPrefix)
    rp.setStartBlockId(0)

    interest = Interest(
        Name("/example/repo/1").append("insert").append(rp.wireEncode()))

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        SelfVerifyPolicyManager(identityStorage))

    # Initialize the storage.
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(
        0,
        keyName.size() - 1).append("KEY").append(
            keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA,
                           Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA,
                                           DEFAULT_RSA_PUBLIC_KEY_DER,
                                           DEFAULT_RSA_PRIVATE_KEY_DER)

    # Make a Face just so that we can sign the interest.
    face = Face("localhost")
    face.setCommandSigningInfo(keyChain, certificateName)
    face.makeCommandInterest(interest)

    callbacks = Callbacks()
    print interest.getName().toUri()
    face.expressInterest(interest, callbacks.onData, callbacks.onTimeout)
Ejemplo n.º 32
0
class Chat(object):
    def __init__(self, screenName, chatRoom, hubPrefix, face, keyChain,
      certificateName):
        self._screenName = screenName
        self._chatRoom = chatRoom
        self._face = face
        self._keyChain = keyChain
        self._certificateName = certificateName

        self._messageCache = [] # of CachedMessage
        self._roster = [] # of str
        self._maxMessageCacheLength = 100
        self._isRecoverySyncState = True
        self._syncLifetime = 5000.0 # milliseconds

        # This should only be called once, so get the random string here.
        self._chatPrefix = Name(hubPrefix).append(self._chatRoom).append(
          self._getRandomString())
        session = int(round(self.getNowMilliseconds() / 1000.0))
        self._userName = self._screenName + str(session)

        self._sync = ChronoSync2013(
           self._sendInterest, self._initial, self._chatPrefix,
           Name("/ndn/broadcast/ChronoChat-0.3").append(self._chatRoom), session,
           face, keyChain, certificateName, self._syncLifetime,
           onRegisterFailed)

        face.registerPrefix(self._chatPrefix, self._onInterest, onRegisterFailed)

    def sendMessage(self, chatMessage):
        """
        Send a chat message.
        """
        if len(self._messageCache) == 0:
            self._messageCacheAppend(chatbuf_pb2.ChatMessage.JOIN, "xxx")

        # Ignore an empty message.
        # Forming Sync Data Packet.
        if chatMessage != "":
            self._sync.publishNextSequenceNo()
            self._messageCacheAppend(chatbuf_pb2.ChatMessage.CHAT, chatMessage)
            print(self._screenName + ": " + chatMessage)

    def leave(self):
        """
        Send the leave message and leave.
        """
        self._sync.publishNextSequenceNo()
        self._messageCacheAppend(chatbuf_pb2.ChatMessage.LEAVE, "xxx")

    @staticmethod
    def getNowMilliseconds():
        """
        Get the current time in milliseconds.

        :return: The current time in milliseconds since 1/1/1970, including
          fractions of a millisecond.
        :rtype: float
        """
        return time.time() * 1000.0

    def _initial(self):
        """
        Push the JOIN message in to the messageCache_, update roster
        and start the heartbeat.
        """
        # Set the heartbeat timeout using the Interest timeout mechanism. The
        # heartbeat() function will call itself again after a timeout.
        # TODO: Are we sure using a "/local/timeout" interest is the best future call
        # approach?
        timeout = Interest(Name("/local/timeout"))
        timeout.setInterestLifetimeMilliseconds(60000)
        self._face.expressInterest(timeout, self._dummyOnData, self._heartbeat)

        try:
           self._roster.index(self._userName)
        except ValueError:
            self._roster.append(self._userName)
            print("Member: " + self._screenName)
            print(self._screenName + ": Join")
            self._messageCacheAppend(chatbuf_pb2.ChatMessage.JOIN, "xxx")

    def _sendInterest(self, syncStates, isRecovery):
        """
        Send a Chat Interest to fetch chat messages after the user gets the Sync
        data packet back but will not send interest.
        """
        # This is used by _onData to decide whether to display the chat messages.
        self._isRecoverySyncState = isRecovery

        sendList = []       # of str
        sessionNoList = []  # of int
        sequenceNoList = [] # of int
        for j in range(len(syncStates)):
            syncState = syncStates[j]
            nameComponents = Name(syncState.getDataPrefix())
            tempName = nameComponents.get(-1).toEscapedString()
            sessionNo = syncState.getSessionNo()
            if not tempName == self._screenName:
                index = -1
                for k in range(len(sendList)):
                    if sendList[k] == syncState.getDataPrefix():
                        index = k
                        break

                if index != -1:
                    sessionNoList[index] = sessionNo
                    sequenceNoList[index] = syncState.getSequenceNo()
                else:
                    sendList.append(syncState.getDataPrefix())
                    sessionNoList.append(sessionNo)
                    sequenceNoList.append(syncState.getSequenceNo())

        for i in range(len(sendList)):
            uri = (sendList[i] + "/" + str(sessionNoList[i]) + "/" +
              str(sequenceNoList[i]))
            interest = Interest(Name(uri))
            interest.setInterestLifetimeMilliseconds(self._syncLifetime)
            self._face.expressInterest(interest, self._onData, self._chatTimeout)

    def _onInterest(self, prefix, interest, face, interestFilterId, filter):
        """
        Send back a Chat Data Packet which contains the user's message.
        """
        content = chatbuf_pb2.ChatMessage()
        sequenceNo = int(
          interest.getName().get(self._chatPrefix.size() + 1).toEscapedString())
        gotContent = False
        for i in range(len(self._messageCache) - 1, -1, -1):
            message = self._messageCache[i]
            if message.sequenceNo == sequenceNo:
                if message.messageType != chatbuf_pb2.ChatMessage.CHAT:
                    # Use setattr because "from" is a reserved keyword.
                    setattr(content, "from", self._screenName)
                    content.to = self._chatRoom
                    content.type = message.messageType
                    content.timestamp = int(round(message.time / 1000.0))
                else:
                    setattr(content, "from", self._screenName)
                    content.to = self._chatRoom
                    content.type = message.messageType
                    content.data = message.message
                    content.timestamp = int(round(message.time / 1000.0))

                gotContent = True
                break

        if gotContent:
            # TODO: Check if this works in Python 3.
            array = content.SerializeToString()
            data = Data(interest.getName())
            data.setContent(Blob(array))
            self._keyChain.sign(data, self._certificateName)
            try:
                face.putData(data)
            except Exception as ex:
                logging.getLogger(__name__).error(
                  "Error in transport.send: %s", str(ex))
                return

    def _onData(self, interest, data):
        """
        Process the incoming Chat data.
        """
        # TODO: Check if this works in Python 3.
        content = chatbuf_pb2.ChatMessage()
        content.ParseFromString(data.getContent().toRawStr())

        if self.getNowMilliseconds() - content.timestamp * 1000.0 < 120000.0:
            # Use getattr because "from" is a reserved keyword.
            name = getattr(content, "from")
            prefix = data.getName().getPrefix(-2).toUri()
            sessionNo = int(data.getName().get(-2).toEscapedString())
            sequenceNo = int(data.getName().get(-1).toEscapedString())
            nameAndSession = name + str(sessionNo)

            l = 0
            # Update roster.
            while l < len(self._roster):
                entry = self._roster[l]
                tempName = entry[0:len(entry) - 10]
                tempSessionNo = int(entry[len(entry) - 10:])
                if (name != tempName and
                    content.type != chatbuf_pb2.ChatMessage.LEAVE):
                    l += 1
                else:
                    if name == tempName and sessionNo > tempSessionNo:
                        self._roster[l] = nameAndSession
                    break

            if l == len(self._roster):
                self._roster.append(nameAndSession)
                print(name + ": Join")

            # Set the alive timeout using the Interest timeout mechanism.
            # TODO: Are we sure using a "/local/timeout" interest is the best
            # future call approach?
            timeout = Interest(Name("/local/timeout"))
            timeout.setInterestLifetimeMilliseconds(120000)
            self._face.expressInterest(
              timeout, self._dummyOnData,
              self._makeAlive(sequenceNo, name, sessionNo, prefix))

            # isRecoverySyncState_ was set by sendInterest.
            # TODO: If isRecoverySyncState_ changed, this assumes that we won't get
            #     data from an interest sent before it changed.
            # Use getattr because "from" is a reserved keyword.
            if (content.type == chatbuf_pb2.ChatMessage.CHAT and
                 not self._isRecoverySyncState and
                 getattr(content, "from") != self._screenName):
                print(getattr(content, "from") + ": " + content.data)
            elif content.type == chatbuf_pb2.ChatMessage.LEAVE:
                # leave message
                try:
                    n = self._roster.index(nameAndSession)
                    if name != self._screenName:
                        self._roster.pop(n)
                        print(name + ": Leave")
                except ValueError:
                    pass

    @staticmethod
    def _chatTimeout(interest):
        print("Timeout waiting for chat data")

    def _heartbeat(self, interest):
        """
        This repeatedly calls itself after a timeout to send a heartbeat message
        (chat message type HELLO). This method has an "interest" argument
        because we use it as the onTimeout for Face.expressInterest.
        """
        if len(self._messageCache) == 0:
            self._messageCacheAppend(chatbuf_pb2.ChatMessage.JOIN, "xxx")

        self._sync.publishNextSequenceNo()
        self._messageCacheAppend(chatbuf_pb2.ChatMessage.HELLO, "xxx")

        # Call again.
        # TODO: Are we sure using a "/local/timeout" interest is the best future call
        # approach?
        timeout = Interest(Name("/local/timeout"))
        timeout.setInterestLifetimeMilliseconds(60000)
        self._face.expressInterest(timeout, self._dummyOnData, self._heartbeat)

    def _makeAlive(self, tempSequenceNo, name, sessionNo, prefix):
        """
        Return a function for onTimeout which calls _alive.
        """
        def f(interest):
            self._alive(interest, tempSequenceNo, name, sessionNo, prefix)
        return f

    def _alive(self, interest, tempSequenceNo, name, sessionNo, prefix):
        """
        This is called after a timeout to check if the user with prefix has a
        newer sequence number than the given tempSequenceNo. If not, assume the
        user is idle and remove from the roster and print a leave message. This
        method has an "interest" argument because we use it as the onTimeout for
        Face.expressInterest.
        """
        sequenceNo = self._sync.getProducerSequenceNo(prefix, sessionNo)
        nameAndSession = name + sessionNo
        try:
            n = self._roster.index(nameAndSession)
        except ValueError:
            n = -1

        if sequenceNo != -1 and n >= 0:
            if tempSequenceNo == sequenceNo:
                self._roster.pop(n)
                print(name + ": Leave")

    def _messageCacheAppend(self, messageType, message):
        """
        Append a new CachedMessage to messageCache_, using given messageType and
        message, the sequence number from _sync.getSequenceNo() and the current
        time. Also remove elements from the front of the cache as needed to keep
        the size to _maxMessageCacheLength.
        """
        self._messageCache.append(self._CachedMessage(
          self._sync.getSequenceNo(), messageType, message,
          self.getNowMilliseconds()))
        while len(self._messageCache) > self._maxMessageCacheLength:
          self._messageCache.pop(0)

    @staticmethod
    def _getRandomString():
        """
        Generate a random name for ChronoSync.
        """
        seed = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789"
        result = ""
        for i in range(10):
          # Using % means the distribution isn't uniform, but that's OK.
          position = random.randrange(256) % len(seed)
          result += seed[position]

        return result

    @staticmethod
    def _dummyOnData(interest, data):
        """
        This is a do-nothing onData for using expressInterest for timeouts.
        This should never be called.
        """
        pass

    class _CachedMessage(object):
        def __init__(self, sequenceNo, messageType, message, time):
            self.sequenceNo = sequenceNo
            self.messageType = messageType
            self.message = message
            self.time = time
Ejemplo n.º 33
0
 def test_uri_constructor(self):
     name = Name(self.expectedURI)
     self.assertEqual(name.size(),3, 'Constructed name has ' + str(name.size()) + ' components instead of 3')
     self.assertEqual(name.toUri(), self.expectedURI, 'URI is incorrect')
Ejemplo n.º 34
0
class SensorDataLogger:
    def __init__(self, data_interval):
        # connect to modbus
        self.master = modbus_tcp.TcpMaster("172.17.66.246", 502)
        # self.master.set_timeout(120) # in seconds
        
        # connect to local repo
        self.publisher = RepoSocketPublisher(12345)
        self.prefix = "/ndn/ucla.edu/bms/strathmore/data/demand"
        self.interval = data_interval # in seconds
        
        self.loadKey()
        
    def loadKey(self):
        self.identityStorage = MemoryIdentityStorage()
        self.privateKeyStorage = MemoryPrivateKeyStorage()
        self.keychain = KeyChain(IdentityManager(self.identityStorage, self.privateKeyStorage))

        f = open(key_file, "r")
        self.key = RSA.importKey(f.read())
        self.key_name = Name(bld_root).append(getKeyID(self.key))
        key_pub_der = bytearray(self.key.publickey().exportKey(format="DER"))
        key_pri_der = bytearray(self.key.exportKey(format="DER"))
        self.identityStorage.addKey(self.key_name, KeyType.RSA, Blob(key_pub_der))
        self.privateKeyStorage.setKeyPairForKeyName(self.key_name, key_pub_der, key_pri_der)
        self.cert_name = self.key_name.getSubName(0, self.key_name.size() - 1).append(
            "KEY").append(self.key_name[-1]).append("ID-CERT").append("0")

        print 'KeyName = ' + self.key_name.toUri()
        print 'CertName = ' + self.cert_name.toUri()

    def publishData(self, key, key_ts, payload, timestamp):
        data = Data(Name(self.prefix).append(bytearray(timestamp)))
        iv = Random.new().read(AES.block_size)
        encryptor = AES.new(key, AES.MODE_CBC, iv)
        data.setContent(bytearray(key_ts + iv + encryptor.encrypt(pad(json.dumps(payload)))))
        data.getMetaInfo().setFreshnessPeriod(5000)
        self.keychain.sign(data, self.cert_name)
        self.publisher.put(data)
        #print payload
        #print data.getName().toUri()

    def run(self):
        key_ts = struct.pack('!Q', int(time.time() * 1000))
        key = Random.new().read(32)
        kds_count = -1
        
        while (True):
            # KDS
            kds_count = kds_count + 1
            if kds_count % 120 == 0:
                key_ts = struct.pack("!Q", int(time.time() * 1000))
                key = Random.new().read(32)
                kds_thread = kds.SimpleKDSPublisher(Name(bld_root), self.keychain, self.cert_name, key, key_ts)
                kds_thread.start()
                kds_count = 0

            # Data
            now = int(time.time() * 1000) # in milliseconds

            a = self.master.execute(100, cst.READ_HOLDING_REGISTERS, 166, 1)
            b = self.master.execute(100, cst.READ_HOLDING_REGISTERS, 167, 1)
            vln = (b[0] << 16) + a[0]
            c = self.master.execute(1, cst.READ_HOLDING_REGISTERS, 150, 1)
            la = c[0]
            
            payload = {'ts': now, 'vlna': vln, 'la': la}
            timestamp = struct.pack("!Q", now) # timestamp is in milliseconds

            self.publishData(key, key_ts, payload, timestamp)

            time.sleep(self.interval)
Ejemplo n.º 35
0
class SyncBasedDiscovery(object):
    """
    Sync (digest exchange) based name discovery.
    Discovery maintains a list of discovered, and a list of hosted objects.
    Calls observer.onStateChanged(name, msgType, msg) when an entity is discovered or removed.
    Uses serializer.serialize(entityObject) to serialize a hosted entity's entityInfo into string.

    :param face:
    :type face: Face
    :param keyChain: 
    :type keyChain: KeyChain
    :param certificateName:
    :type certificateName: Name
    :param syncPrefix:
    :type syncPrefix: Name
    :param observer:
    :type observer: ExternalObserver
    :param serializer:
    :type serializer: EntitySerializer
    """
    def __init__(self, face, keyChain, certificateName, syncPrefix, observer, serializer, 
      syncDataFreshnessPeriod = 4000, initialDigest = "00", syncInterestLifetime = 4000, syncInterestMinInterval = 500,
      timeoutCntThreshold = 3, maxResponseWaitPeriod = 2000, minResponseWaitPeriod = 400, entityDataFreshnessPeriod = 10000):
        self._face = face
        self._keyChain = keyChain
        self._syncPrefix = Name(syncPrefix)

        self._objects = dict()
        self._hostedObjects = dict()

        self._memoryContentCache = MemoryContentCache(self._face)
        self._certificateName = Name(certificateName)

        self._currentDigest = initialDigest
        self._syncDataFreshnessPeriod = syncDataFreshnessPeriod
        self._initialDigest = initialDigest
        self._syncInterestLifetime = syncInterestLifetime

        self._syncInterestMinInterval = syncInterestMinInterval
        self._timeoutCntThreshold = timeoutCntThreshold
        self._entityDataFreshnessPeriod = entityDataFreshnessPeriod
        # TODO: policy manager etc setup

        #self._maxResponseWaitPeriod = maxResponseWaitPeriod
        #self._minResponseWaitPeriod = minResponseWaitPeriod

        self._observer = observer
        self._serializer = serializer
        self._numOutstandingInterest = 0

        return

    """
    Public facing interface
    """
    def start(self):
        """
        Starts the discovery
        """
        interest = Interest(Name(self._syncPrefix).append(self._initialDigest))
        interest.setMustBeFresh(True)
        interest.setInterestLifetimeMilliseconds(self._syncInterestLifetime)
        self._face.expressInterest(interest, self.onSyncData, self.onSyncTimeout)
        self._numOutstandingInterest += 1
        if __debug__:
            print("Express interest: " + interest.getName().toUri())
        return

    def stop(self):
        """
        Stops the discovery
        """
        # TODO: interest expression and data response flag
        self._memoryContentCache.unregisterAll()
        return

    def getHostedObjects(self):
        return self._hostedObjects

    def getObjects(self):
        return self._objects

    def publishObject(self, name, entityInfo):
        """
        Adds another object and registers prefix for that object's name

        :param name: the object's name string
        :type name: str
        :param entityInfo: the application given entity info to describe this object name with
        :type entityInfo: EntityInfo
        """
        # If this is the first object we host, we register for sync namespace: meaning a participant not hosting anything 
        #   is only "listening" for sync, and will not help in the sync process
        if len(self._hostedObjects.keys()) == 0:
            self._memoryContentCache.registerPrefix(self._syncPrefix, self.onRegisterFailed, self.onSyncInterest)
        if self.addObject(name, False):
            # Do not add itself to contentCache if its currentDigest is "00".
            if self._currentDigest != self._initialDigest:
                self.contentCacheAddSyncData(Name(self._syncPrefix).append(self._currentDigest))
            
            self.updateDigest()
            
            interest = Interest(Name(self._syncPrefix).append(self._currentDigest))
            interest.setInterestLifetimeMilliseconds(self._syncInterestLifetime)
            interest.setMustBeFresh(True)
            
            self._face.expressInterest(interest, self.onSyncData, self.onSyncTimeout)
            self._numOutstandingInterest += 1

            self._hostedObjects[name] = entityInfo
            self.contentCacheAddEntityData(name, entityInfo)
            self.notifyObserver(name, "ADD", "")
            # TODO: should the user configure this prefix as well?
            self._memoryContentCache.registerPrefix(Name(name), self.onRegisterFailed, self.onEntityDataNotFound)
        else:
            if __debug__:
                print("Item with this name already added")
        return

    def removeHostedObject(self, name):
        """
        Removes a locally hosted object

        :param name: the object's name string
        :type name: str
        :return: whether removal's successful or not
        :rtype: bool
        """
        if name in self._hostedObjects:
            del self._hostedObjects[name]
            if len(self._hostedObjects) == 0:
                self._memoryContentCache.unregisterAll()
            if self.removeObject(name):    
                return True
            else:
                if __debug__:
                    print("Hosted item not in objects list")
                return False
        else:
            return False

    """
    Internal functions
    """
    def contentCacheAddEntityData(self, name, entityInfo):
        content = self._serializer.serialize(entityInfo)
        data = Data(Name(name))

        data.setContent(content)

        data.getMetaInfo().setFreshnessPeriod(self._entityDataFreshnessPeriod)
        self._keyChain.sign(data, self._certificateName)
        self._memoryContentCache.add(data)
        print "added entity to cache: " + data.getName().toUri() + "; " + data.getContent().toRawStr()

    def contentCacheAddSyncData(self, dataName):
        sortedKeys = sorted(self._objects.keys())
        content = ""
        for key in sortedKeys:
            content += key + "\n"
        content.strip()

        data = Data(Name(dataName))
        
        data.setContent(content)
        data.getMetaInfo().setFreshnessPeriod(self._syncDataFreshnessPeriod)
        self._keyChain.sign(data, self._certificateName)
        # adding this data to memoryContentCache should satisfy the pending interest
        self._memoryContentCache.add(data)

    def onSyncInterest(self, prefix, interest, face, interestFilterId, filter):
        if interest.getName().size() != self._syncPrefix.size() + 1:
            # Not an interest for us
            return
        digest = interest.getName().get(-1).toEscapedString()
        self.updateDigest()
        if digest != self._currentDigest:
            # Wait a random period before replying; rationale being that "we are always doing ChronoSync recovery...this is the recovery timer but randomized"
            # Consider this statement: we are always doing ChronoSync recovery
            # TODO: this has the problem of potentially answering with wrong data, there will be more interest exchanges needed for the lifetime duration of one wrong answer
            # Consider appending "answerer" as the last component of data name?
            # TODO2: don't see why we should wait here

            self.replySyncInterest(interest, digest)
            #dummyInterest = Interest(Name("/local/timeout1"))
            #dummyInterest.setInterestLifetimeMilliseconds(random.randint(self._minResponseWaitPeriod, self._maxResponseWaitPeriod))
            #self._face.expressInterest(dummyInterest, self.onDummyData, lambda a : self.replySyncInterest(a, digest))
        return

    def replySyncInterest(self, interest, receivedDigest):
        self.updateDigest()
        if receivedDigest != self._currentDigest:
            # TODO: one participant may be answering with wrong info: scenario: 1 has {a}, 2 has {b}
            # 2 gets 1's {a} and asks again before 1 gets 2's {b}, 2 asks 1 with the digest of {a, b}, 1 will 
            # create a data with the content {a} for the digest of {a, b}, and this data will be able to answer
            # later steady state interests from 2 until it expires (and by which time 1 should be updated with
            # {a, b} as well)
            self.contentCacheAddSyncData(Name(self._syncPrefix).append(receivedDigest))
        return

    def onSyncData(self, interest, data):
        # TODO: do verification first
        if __debug__:
            print("Got sync data; name: " + data.getName().toUri() + "; content: " + data.getContent().toRawStr())
        content = data.getContent().toRawStr().split('\n')
        self._numOutstandingInterest -= 1
        for itemName in content:
            if itemName not in self._objects:
                if itemName != "":
                    self.onReceivedSyncData(itemName)

        # Hack for re-expressing sync interest after a short interval
        dummyInterest = Interest(Name("/local/timeout"))
        dummyInterest.setInterestLifetimeMilliseconds(self._syncInterestLifetime)
        self._face.expressInterest(dummyInterest, self.onDummyData, self.onSyncTimeout)
        self._numOutstandingInterest += 1
        return

    def onSyncTimeout(self, interest):
        newInterest = Interest(Name(self._syncPrefix).append(self._currentDigest))
        newInterest.setInterestLifetimeMilliseconds(self._syncInterestLifetime)
        newInterest.setMustBeFresh(True)
        self._numOutstandingInterest -= 1
        print "re-expressing: " + newInterest.getName().toUri()

        if self._numOutstandingInterest <= 0:
            self._face.expressInterest(newInterest, self.onSyncData, self.onSyncTimeout)
            self._numOutstandingInterest += 1
        return

    """
    Handling received sync data: express entity interest
    """
    def onReceivedSyncData(self, itemName):
        interest = Interest(Name(itemName))
        interest.setInterestLifetimeMilliseconds(4000)
        interest.setMustBeFresh(False)
        self._face.expressInterest(interest, self.onEntityData, self.onEntityTimeout) 
        return

    def onEntityTimeout(self, interest):
        print "Item interest times out: " + interest.getName().toUri()
        return

    def onEntityData(self, interest, data):
        self.addObject(interest.getName().toUri(), True)
        self.notifyObserver(interest.getName().toUri(), "ADD", "");

        dummyInterest = Interest(Name("/local/timeout"))
        dummyInterest.setInterestLifetimeMilliseconds(4000)
        self._face.expressInterest(dummyInterest, self.onDummyData, lambda a : self.expressHeartbeatInterest(a, interest))
        return

    def expressHeartbeatInterest(self, dummyInterest, entityInterest):
        newInterest = Interest(entityInterest)
        newInterest.refreshNonce()
        self._face.expressInterest(newInterest, self.onHeartbeatData, self.onHeartbeatTimeout)

    def onHeartbeatData(self, interest, data):
        self.resetTimeoutCnt(interest.getName().toUri())
        dummyInterest = Interest(Name("/local/timeout"))
        dummyInterest.setInterestLifetimeMilliseconds(4000)
        self._face.expressInterest(dummyInterest, self.onDummyData, lambda a : self.expressHeartbeatInterest(a, interest))

    def onHeartbeatTimeout(self, interest):
        if self.incrementTimeoutCnt(interest.getName().toUri()):
            print "Remove: " + interest.getName().toUri() + " because of consecutive timeout cnt exceeded"
        else:
            newInterest = Interest(interest.getName())
            newInterest.setInterestLifetimeMilliseconds(4000)
            self._face.expressInterest(newInterest, self.onHeartbeatData, self.onHeartbeatTimeout)

    def onDummyData(self, interest, data):
        if __debug__:
            print("Unexpected reply to dummy interest: " + data.getContent().toRawStr())
        return

    def expressSyncInterest(self, interest):
        self.onSyncTimeout(interest)
        return

    def addObject(self, name, update):
        if name in self._objects:
            return False
        else:
            self._objects[name] = {"timeout_count": 0}
            if update:
                self.updateDigest()
            return True

    def removeObject(self, name):
        if name in self._objects:
            del self._objects[name]
            self.notifyObserver(name, "REMOVE", "")
            self.contentCacheAddSyncData(Name(self._syncPrefix).append(self._currentDigest))
            self.updateDigest()
            return True
        else:
            return False

    def updateDigest(self):
        # TODO: for now, may change the format of the list encoding for easier cross language compatibility
        if len(self._objects) > 0:
            m = hashlib.sha256()
            for item in sorted(self._objects.keys()):
                m.update(item)
            self._currentDigest = str(m.hexdigest())
        else:
            self._currentDigest = self._initialDigest
        return

    def incrementTimeoutCnt(self, name):
        if name in self._objects:
            self._objects[name]["timeout_count"] += 1
            if self._objects[name]["timeout_count"] >= self._timeoutCntThreshold:
                return self.removeObject(name)
            else:
                return False
        else:
            return False

    def resetTimeoutCnt(self, name):
        if name in self._objects:
            self._objects[name]["timeout_count"] = 0
            return True
        else:
            return False

    def notifyObserver(self, name, msgType, msg):
        self._observer.onStateChanged(name, msgType, msg)
        return

    def onRegisterFailed(self, prefix):
        if __debug__:
            print("Prefix registration failed: " + prefix.toUri())
        return

    def onEntityDataNotFound(self, prefix, interest, face, interestFilterId, filter):
        name = interest.getName().toUri()
        if name in self._hostedObjects:
            content = self._serializer.serialize(self._hostedObjects[name])
            data = Data(Name(name))
            data.setContent(content)
            data.getMetaInfo().setFreshnessPeriod(self._entityDataFreshnessPeriod)
            self._keyChain.sign(data, self._certificateName)
            self._face.putData(data)
        return
class RepoPublisher:
    def __init__(self, repoPrefix, dataPrefix, dataSuffix, keychain=None):
        self.currentInsertion = -1
        self.currentStatus = -1
        self.face = None
        self.loop = None
        self.repoPrefix = Name(repoPrefix)
        self.dataName = Name(dataPrefix).append(dataSuffix)
        self.dataPrefix = Name(dataPrefix)

        if keychain is not None:
            self.keychain = keychain
        else:
            self.keychain = KeyChain()

        self.certificateName = self.keychain.getDefaultCertificateName()

        self.failureCount = 0
        self.successCount = 0

        self.processIdToVersion = {}

    def onRegisterFailed(self):
        logger.error("Could not register data publishing face!")
        self.stop()

    def versionFromCommandMessage(self, component):
        command = RepoCommandParameterMessage()
        try:
            ProtobufTlv.decode(command, component.getValue())
        except Exception as e:
            logger.warn(e)

        # last component of name to insert is version
        versionStr = command.repo_command_parameter.name.component[-1]

        return versionStr

    def stop(self):
        self.loop.close()
        self.face.shutdown()

    def onPublishInterest(self, prefix, interest, transport, pxID):
        '''
           For publishing face
        '''
        # just make up some data and return it
        interestName = interest.getName()
        logger.info("Interest for " + interestName.toUri())

        ## CURRENTLY ASSUMES THERE'S A VERSION+SEGMENT SUFFIX!
        dataName = Name(interestName)
        ts = (time.time())
        segmentId = 0
        #try:
        #   segmentId = interestName.get(-1).toSegment()
        #except:
            #logger.debug("Could not find segment id!")
            #dataName.appendSegment(segmentId)
        versionStr = str(interestName.get(-2).getValue())
        logger.debug('Publishing ' + versionStr + ' @ ' + str(ts))

        d = Data(dataName)
        content = "(" + str(ts) +  ") Data named " + dataName.toUri()
        d.setContent(content)
        d.getMetaInfo().setFinalBlockID(segmentId)
        d.getMetaInfo().setFreshnessPeriod(1000)
        self.keychain.sign(d, self.certificateName)

        encodedData = d.wireEncode()

        stats.insertDataForVersion(versionStr, {'publish_time': time.time()})
        transport.send(encodedData.toBuffer())
        #yield from asyncio.sleep()

    def generateVersionedName(self):
        fullName = Name(self.dataName)
        # currently we need to provide the version ourselves when we
        # poke the repo
        ts = int(time.time()*1000)
        fullName.appendVersion(int(ts))
        return fullName

    def onTimeout(self, prefix):
        logger.warn('Timeout waiting for '+prefix.toUri())

    
    def start(self):
        self.loop = asyncio.new_event_loop()
        self.face = ThreadsafeFace(self.loop, "")

        asyncio.set_event_loop(self.loop)
        self.face.setCommandSigningInfo(self.keychain, self.certificateName)
        self.face.registerPrefix(self.dataPrefix,self.onPublishInterest, self.onRegisterFailed)
        try:
            self.loop.call_soon(self.kickRepo)
            self.loop.run_forever()
        finally:
           self.stop() 


    def kickRepo(self):
        # command the repo to insert a new bit of data
        fullName = self.generateVersionedName()
        versionStr = str(fullName.get(-1).getValue())
        command = self.createInsertInterest(fullName)

        logger.debug('inserting: ' + versionStr)

        self.face.makeCommandInterest(command)
        def timeoutLoop(interest):
            logger.warn('Timed out on ' + interest.toUri())
            self.face.expressInterest(command, self.onCommandData, self.onTimeout)

        self.face.expressInterest(command, self.onCommandData, timeoutLoop)
        stats.insertDataForVersion(versionStr, {'insert_request':time.time()})

    def checkInsertion(self, versionStr, processID):
        fullName = Name(self.dataName).append(Name.fromEscapedString(versionStr))
        checkCommand = self.createCheckInterest(fullName, processID)
        self.face.makeCommandInterest(checkCommand)
        def timeoutLoop(interest):
            logger.warn('Timed out waiting on: '+interest.toUri())
            self.face.expressInterest(checkCommand, self.onCommandData, self.onTimeout)
        self.face.expressInterest(checkCommand, self.onCommandData, timeoutLoop)

    def createInsertInterest(self, fullName):
        '''
            For poking the repo
        '''
        # we have to do the versioning before we poke the repo
        interestName = Name(fullName)
        logger.debug('Creating insert interest for: '+interestName.toUri())
        
        insertionName = Name(self.repoPrefix).append('insert')
        commandParams = RepoCommandParameterMessage()

        for i in range(interestName.size()):
            commandParams.repo_command_parameter.name.component.append(interestName.get(i).getValue().toRawStr())

        commandParams.repo_command_parameter.start_block_id = 0
        commandParams.repo_command_parameter.end_block_id = 0

        commandName = insertionName.append(ProtobufTlv.encode(commandParams))
        interest = Interest(commandName)

        interest.setInterestLifetimeMilliseconds(2000)

        return interest

    def createCheckInterest(self, fullName, checkNum):
        insertionName = Name(self.repoPrefix).append('insert check')
        commandParams = RepoCommandParameterMessage()
        interestName = Name(fullName)

        commandParams.repo_command_parameter.process_id = checkNum
        for i in range(interestName.size()):
            commandParams.repo_command_parameter.name.component.append(str(interestName.get(i).getValue()))

        commandName = insertionName.append(ProtobufTlv.encode(commandParams))
        interest = Interest(commandName)

        return interest

    def onCommandData(self, interest, data):
        # assume it's a command response
        now = time.time()
        response = RepoCommandResponseMessage()
        ProtobufTlv.decode(response, data.getContent())


        self.currentStatus = response.repo_command_response.status_code
        self.currentInsertion =  response.repo_command_response.process_id
        logger.debug("Response status code: " + str(self.currentStatus) + ", process id: " + str(self.currentInsertion) + ", insert #" + str(response.repo_command_response.insert_num))

        command_idx = self.repoPrefix.size()
        # we also need to keep track of the mapping from version to processID for stats
        commandName = interest.getName().get(command_idx).getValue().toRawStr()
        if commandName == 'insert check':
            try:
                versionStr = self.processIdToVersion[self.currentInsertion]
                if self.currentStatus == 200:
                    stats.insertDataForVersion(versionStr, {'insert_complete': now})
                    self.loop.call_soon(self.kickRepo)
                elif self.currentStatus >= 400:
                    self.failureCount += 1
                    self.loop.call_soon(self.kickRepo)
                else:
                    self.loop.call_soon(self.checkInsertion, versionStr, self.currentInserion)
            except:
                logger.warn('Missing version for process ID {}'.format(self.currentInsertion))
        elif commandName == 'insert':
            if self.currentStatus == 100:
                versionStr = self.versionFromCommandMessage(interest.getName().get(command_idx+1))
                self.processIdToVersion[self.currentInsertion] = versionStr
                stats.insertDataForVersion(versionStr, {'insert_begin': now})
                self.loop.call_soon(self.checkInsertion, versionStr, self.currentInsertion)
            else:
                self.failureCount += 1
                self.loop.call_soon(self.kickRepo)
Ejemplo n.º 37
0
def main():
    interest = Interest()
    interest.wireDecode(TlvInterest)
    dump("Interest:")
    dumpInterest(interest)

    # Set the name again to clear the cached encoding so we encode again.
    interest.setName(interest.getName())
    encoding = interest.wireEncode()
    dump("")
    dump("Re-encoded interest", encoding.toHex())

    reDecodedInterest = Interest()
    reDecodedInterest.wireDecode(encoding)
    dump("Re-decoded Interest:")
    dumpInterest(reDecodedInterest)

    freshInterest = (Interest(
        Name("/ndn/abc")).setMustBeFresh(False).setMinSuffixComponents(
            4).setMaxSuffixComponents(6).setInterestLifetimeMilliseconds(
                30000).setChildSelector(1).setMustBeFresh(True))
    freshInterest.getKeyLocator().setType(KeyLocatorType.KEY_LOCATOR_DIGEST)
    freshInterest.getKeyLocator().setKeyData(
        bytearray([
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
            0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
            0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
        ]))
    freshInterest.getExclude().appendComponent(Name("abc")[0]).appendAny()
    dump(freshInterest.toUri())

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        SelfVerifyPolicyManager(identityStorage))

    # Initialize the storage.
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(
        0,
        keyName.size() - 1).append("KEY").append(
            keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA,
                           Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA,
                                           DEFAULT_RSA_PUBLIC_KEY_DER,
                                           DEFAULT_RSA_PRIVATE_KEY_DER)

    # Make a Face just so that we can sign the interest.
    face = Face("localhost")
    face.setCommandSigningInfo(keyChain, certificateName)
    face.makeCommandInterest(freshInterest)

    reDecodedFreshInterest = Interest()
    reDecodedFreshInterest.wireDecode(freshInterest.wireEncode())
    dump("")
    dump("Re-decoded fresh Interest:")
    dumpInterest(reDecodedFreshInterest)

    keyChain.verifyInterest(reDecodedFreshInterest,
                            makeOnVerified("Freshly-signed Interest"),
                            makeOnVerifyFailed("Freshly-signed Interest"))
Ejemplo n.º 38
0
class RegisterSongList(object):


    def __init__(self,sFace,sLoop,skeychain,scertificateName,prefix="/ndn/edu/ucla/remap/music/list"):
	logging.basicConfig()        
    	self.device = "PC1"
    	self.deviceComponent = Name.Component(self.device)
	self.excludeDevice = None
        self.listPrefix = Name(prefix)
        self.address = ""
        self._isStopped = True

	self.face = sFace
	self.loop = sLoop
	self.keychain = skeychain
	self.certificateName = scertificateName
    
    def start(self):
        self.face.registerPrefix(self.listPrefix,self.onInterest,self.onRegisterFailed)

    def stop(self):
        self.loop.close()       
        self.face.shutdown()
        self.face = None
        sys.exit(1)

    def signData(self,data):
	data.setSignature(Sha256WithRsaSignature())


    def onInterest(self, prefix, interest, transport, registeredPrefixId):
        initInterest = Name(interest.getName())
        print "interest name:",initInterest.toUri()
	d = Data(interest.getName().append(self.deviceComponent))
	
		  
        try:
	    if(initInterest == self.listPrefix):
	    
		#receive the .../list interest
		currentString = ','.join(currentList)
		d.setContent(currentString)
		encodedData = d.wireEncode()
		transport.send(encodedData.toBuffer())
		print d.getName().toUri()
		print d.getContent()
		
            else:
		self.excludeDevice = initInterest.get(self.listPrefix.size())
		excDevice = self.excludeDevice.toEscapedString()
		if(excDevice != str("exc")+self.device):
			# receive the .../list/excOther interest                
			currentString = ','.join(currentList)
			d.setContent(currentString)
			encodedData = d.wireEncode()
			transport.send(encodedData.toBuffer())
			print d.getName().toUri()
			print d.getContent()
			
		else:
			# receive the .../list/excMe interest
			print"controller has exclude me, I have to remove register!"
                	self.face.removeRegisteredPrefix(registeredPrefixId)
			time.sleep(30)
			print"register again"
                	self.face.registerPrefix(self.listPrefix,self.onInterest,self.onRegisterFailed)
    

	except KeyboardInterrupt:
		print "key interrupt"
		sys.exit(1)
	except Exception as e:
		print e
		d.setContent("Bad command\n")
	finally:
		self.keychain.sign(d,self.certificateName)
		


    def onRegisterFailed(self, prefix):
        self.log.error("Could not register " + prefix.toUri())
        self.stop()	
Ejemplo n.º 39
0
def main():
    # Uncomment these lines to print ChronoSync debug messages.
    # logging.getLogger('').addHandler(logging.StreamHandler(sys.stdout))
    # logging.getLogger('').setLevel(logging.INFO)

    defaultUserPrefix = "com/newspaper/USER/bob"
    userPrefix = promptAndInput("Enter user prefix: [" + defaultUserPrefix + "]")
    if userPrefix == "":
        userPrefix = defaultUserPrefix

    defaultNamespacePrefix = "/ndn/hackathon/cnl-demo/slides" #"com/newspaper"
    namespacePrefix = promptAndInput("Enter namespace prefix [" + defaultNamespacePrefix + "]: ")
    if namespacePrefix == "":
        namespacePrefix = defaultNamespacePrefix

    host = "localhost" #"memoria.ndn.ucla.edu"
    print("Connecting to " + host)
    print("")

    # Set up the key chain.
    face = Face(host)

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        NoVerifyPolicyManager())
    keyChain.setFace(face)
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(0, keyName.size() - 1).append(
      "KEY").append(keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(
      keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER, DEFAULT_RSA_PRIVATE_KEY_DER)
    face.setCommandSigningInfo(keyChain, certificateName)

    newspaper = Namespace(namespacePrefix)
    
    def onContentSet(namespace, contentNamespace, callbackId):
        global currentSlideName
        if contentNamespace == namespace:
            print("content size "+str(contentNamespace.content.size()))
            currentSlideName = contentNamespace.getName()
            displayImage(contentNamespace.content.toRawStr(), contentNamespace.getName().toUri())
            # dump("Got segmented content ", contentNamespace.content.toRawStr())

    def onNewName(namespace, addedNamespace, callbackId):
        print("namespace ("+addedNamespace.getName().toUri()+") added to "+namespace.getName().toUri())
        if addedNamespace.getName().get(-1).isSegment() and addedNamespace.getName().get(-1).toSegment() == 0:
            addedNamespace.getParent().addOnContentSet(onContentSet)
            SegmentedContent(addedNamespace.getParent()).start()

    newspaper.addOnNameAdded(onNewName)
    newspaper.setFace(face)

    namesync = NameSyncHandler(newspaper, userPrefix, keyChain, certificateName)

    # The main loop to process Chat while checking stdin to send a message.
    print("Enter your namespace update. To quit, enter \"exit\".")

    def process():
        # while True:
        # Set timeout to 0 for an immediate check.
        isReady, _, _ = select.select([sys.stdin], [], [], 0)
        if len(isReady) != 0:
            input = promptAndInput("")
            if input == "exit":
                stopGui()
                # We will send the leave message below.
                # break

            # before producer has namespace.publish call, we manually call onNameAdded as a hack to publish
            namesync.onNameAdded(None, Namespace(Name(input)), 0, True)
        face.processEvents()
        if root: 
            root.after(100, process)

    def leftKey(event):
        global currentSlideName
        allVersions = newspaper.getChildComponents()
        currentVersion = currentSlideName[-1]
        selected = allVersions[0]
        for c in allVersions:
            print(str(c.toVersion()))
            if c.toVersion() == currentVersion.toVersion():
                break
            selected = c
        currentSlideName = Name(newspaper.getName()).append(selected)
        displayImage(newspaper.getChild(selected).content.toRawStr(), currentSlideName.toUri())

    def rightKey(event):
        global currentSlideName
        allVersions = newspaper.getChildComponents()
        currentVersion = currentSlideName[-1]
        selected = None
        for c in allVersions[::-1]:
            if c.toVersion() == currentVersion.toVersion():
                break
            selected = c
        if selected:
            currentSlideName = Name(newspaper.getName()).append(selected)
            displayImage(newspaper.getChild(selected).content.toRawStr(), currentSlideName.toUri())
        else:
            print("no slides to show")

    runGui(process, leftKey, rightKey)
Ejemplo n.º 40
0
def benchmarkEncodeDataSeconds(nIterations, useComplex, useCrypto):
    """
    Loop to encode a data packet nIterations times.

    :param int nIterations: The number of iterations.
    :param bool useComplex: If true, use a large name, large content and all
      fields. If false, use a small name, small content and only required
      fields.
    :param bool useCrypto: If true, sign the data packet.  If false, use a blank
      signature.
    :return: A tuple (duration, encoding) where duration is the number of
      seconds for all iterations and encoding is the wire encoding.
    :rtype: (float, Blob)
    """
    if useComplex:
        # Use a large name and content.
        name = Name(
            "/ndn/ucla.edu/apps/lwndn-test/numbers.txt/%FD%05%05%E8%0C%CE%1D/%00"
        )

        contentString = ""
        count = 1
        contentString += "%d" % count
        count += 1
        while len(contentString) < 1115:
            contentString += " %d" % count
            count += 1
        content = Name.fromEscapedString(contentString)
    else:
        # Use a small name and content.
        name = Name("/test")
        content = Name.fromEscapedString("abc")
    finalBlockId = Name("/%00")[0]

    # Initialize the private key storage in case useCrypto is true.
    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        SelfVerifyPolicyManager(identityStorage))
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(
        0,
        keyName.size() - 1).append("KEY").append(
            keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA,
                           Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA,
                                           DEFAULT_RSA_PUBLIC_KEY_DER,
                                           DEFAULT_RSA_PRIVATE_KEY_DER)

    # Set up signatureBits in case useCrypto is false.
    signatureBits = Blob(bytearray(256))
    emptyBlob = Blob([])

    start = getNowSeconds()
    for i in range(nIterations):
        data = Data(name)
        data.setContent(content)
        if useComplex:
            data.getMetaInfo().setFreshnessPeriod(1000)
            data.getMetaInfo().setFinalBlockId(finalBlockId)

        if useCrypto:
            # This sets the signature fields.
            keyChain.sign(data, certificateName)
        else:
            # Imitate IdentityManager.signByCertificate to set up the signature
            # fields, but don't sign.
            sha256Signature = data.getSignature()
            keyLocator = sha256Signature.getKeyLocator()
            keyLocator.setType(KeyLocatorType.KEYNAME)
            keyLocator.setKeyName(certificateName)
            sha256Signature.setSignature(signatureBits)

        encoding = data.wireEncode()

    finish = getNowSeconds()

    return (finish - start, encoding)
Ejemplo n.º 41
0
    def test_content_key_request(self):
        prefix = Name("/prefix")
        suffix = Name("/a/b/c")
        expectedInterest = Name(prefix)
        expectedInterest.append(Encryptor.NAME_COMPONENT_READ)
        expectedInterest.append(suffix)
        expectedInterest.append(Encryptor.NAME_COMPONENT_E_KEY)

        cKeyName = Name(prefix)
        cKeyName.append(Encryptor.NAME_COMPONENT_SAMPLE)
        cKeyName.append(suffix)
        cKeyName.append(Encryptor.NAME_COMPONENT_C_KEY)

        timeMarker = Name("20150101T100000/20150101T120000")
        testTime1 = Schedule.fromIsoString("20150101T100001")
        testTime2 = Schedule.fromIsoString("20150101T110001")
        testTimeRounded1 = Name.Component("20150101T100000")
        testTimeRounded2 = Name.Component("20150101T110000")
        testTimeComponent2 = Name.Component("20150101T110001")

        # Create content keys required for this test case:
        for i in range(suffix.size()):
            self.createEncryptionKey(expectedInterest, timeMarker)
            expectedInterest = expectedInterest.getPrefix(-2).append(
                Encryptor.NAME_COMPONENT_E_KEY)

        expressInterestCallCount = [0]

        # Prepare a TestFace to instantly answer calls to expressInterest.
        class TestFace(object):
            def __init__(self, handleExpressInterest):
                self.handleExpressInterest = handleExpressInterest

            def expressInterest(self, interest, onData, onTimeout,
                                onNetworkNack):
                return self.handleExpressInterest(interest, onData, onTimeout,
                                                  onNetworkNack)

        def handleExpressInterest(interest, onData, onTimeout, onNetworkNack):
            expressInterestCallCount[0] += 1

            interestName = Name(interest.getName())
            interestName.append(timeMarker)
            self.assertTrue(interestName in self.encryptionKeys)
            onData(interest, self.encryptionKeys[interestName])

            return 0

        face = TestFace(handleExpressInterest)

        # Verify that the content key is correctly encrypted for each domain, and
        # the produce method encrypts the provided data with the same content key.
        testDb = Sqlite3ProducerDb(self.databaseFilePath)
        producer = Producer(prefix, suffix, face, self.keyChain, testDb)
        contentKey = [None]  # Blob

        def checkEncryptionKeys(result, testTime, roundedTime,
                                expectedExpressInterestCallCount):
            self.assertEqual(expectedExpressInterestCallCount,
                             expressInterestCallCount[0])

            self.assertEqual(True, testDb.hasContentKey(testTime))
            contentKey[0] = testDb.getContentKey(testTime)

            params = EncryptParams(EncryptAlgorithmType.RsaOaep)
            for i in range(len(result)):
                key = result[i]
                keyName = key.getName()
                self.assertEqual(cKeyName, keyName.getSubName(0, 6))
                self.assertEqual(keyName.get(6), roundedTime)
                self.assertEqual(keyName.get(7), Encryptor.NAME_COMPONENT_FOR)
                self.assertEqual(True,
                                 keyName.getSubName(8) in self.decryptionKeys)

                decryptionKey = self.decryptionKeys[keyName.getSubName(8)]
                self.assertEqual(True, decryptionKey.size() != 0)
                encryptedKeyEncoding = key.getContent()

                content = EncryptedContent()
                content.wireDecode(encryptedKeyEncoding)
                encryptedKey = content.getPayload()
                retrievedKey = RsaAlgorithm.decrypt(decryptionKey,
                                                    encryptedKey, params)

                self.assertTrue(contentKey[0].equals(retrievedKey))

            self.assertEqual(3, len(result))

        # An initial test to confirm that keys are created for this time slot.
        contentKeyName1 = producer.createContentKey(
            testTime1, lambda keys: checkEncryptionKeys(
                keys, testTime1, testTimeRounded1, 3))

        # Verify that we do not repeat the search for e-keys. The total
        #   expressInterestCallCount should be the same.
        contentKeyName2 = producer.createContentKey(
            testTime2, lambda keys: checkEncryptionKeys(
                keys, testTime2, testTimeRounded2, 3))

        # Confirm content key names are correct
        self.assertEqual(cKeyName, contentKeyName1.getPrefix(-1))
        self.assertEqual(testTimeRounded1, contentKeyName1.get(6))
        self.assertEqual(cKeyName, contentKeyName2.getPrefix(-1))
        self.assertEqual(testTimeRounded2, contentKeyName2.get(6))

        # Confirm that produce encrypts with the correct key and has the right name.
        testData = Data()
        producer.produce(testData, testTime2, Blob(DATA_CONTENT, False))

        producedName = testData.getName()
        self.assertEqual(cKeyName.getPrefix(-1), producedName.getSubName(0, 5))
        self.assertEqual(testTimeComponent2, producedName.get(5))
        self.assertEqual(Encryptor.NAME_COMPONENT_FOR, producedName.get(6))
        self.assertEqual(cKeyName, producedName.getSubName(7, 6))
        self.assertEqual(testTimeRounded2, producedName.get(13))

        dataBlob = testData.getContent()

        dataContent = EncryptedContent()
        dataContent.wireDecode(dataBlob)
        encryptedData = dataContent.getPayload()
        initialVector = dataContent.getInitialVector()

        params = EncryptParams(EncryptAlgorithmType.AesCbc, 16)
        params.setInitialVector(initialVector)
        decryptTest = AesAlgorithm.decrypt(contentKey[0], encryptedData,
                                           params)
        self.assertTrue(decryptTest.equals(Blob(DATA_CONTENT, False)))
Ejemplo n.º 42
0
    def on_result_interest(self, _prefix, interest, face, _interest_filter_id, _filter_obj):
        # type: (Name, Interest, Face, int, InterestFilter) -> bool
        prefix = Name(SERVER_PREFIX).append(RESULT_PREFIX)
        if not prefix.isPrefixOf(interest.name):
            # Wrong prefix
            return False

        data_name = interest.name[prefix.size():]
        logging.info("On result interest: %s", data_name.toUri())
        # key, stat = self._result_set_prefix_match(data_name)
        status = self.load_status(data_name)
        if status is None:
            # No such request
            self.nodata_reply(interest.name, RET_NO_REQUEST)
            return True

        if data_name[-1].isSegment():
            # Segment no suffix
            seg_no = data_name[-1].toSegment()
            result = self.storage.get(data_name.getPrefix(-1))
        elif data_name[-1] == Name("_meta")[0]:
            # MetaInfo suffix
            seg_no = -1
            result = self.storage.get(data_name.getPrefix(-1))
        else:
            # No suffix
            seg_no = None
            result = self.storage.get(data_name)

        if result is not None:
            # There are data
            segment_cnt = (len(result) + self.segment_size - 1) // self.segment_size
            # Note: I don't understand why namespace keep all data in memory
            metainfo = MetaInfo()
            # metainfo.setFinalBlockId(segment_cnt - 1) # WHY this doesn't work?
            metainfo.setFinalBlockId(Name().appendSegment(segment_cnt - 1)[0])
            if segment_cnt > 1 and seg_no is None:
                # Fetch segmented data with no suffix will get only first segment
                seg_no = 0
                data_name.appendSequenceNumber(seg_no)

            data = Data(Name(prefix).append(data_name))
            data.setMetaInfo(metainfo)
            if seg_no == -1:
                # _meta
                data.content = self.storage.get(data_name)
            else:
                # data
                if segment_cnt > 1:
                    # Segmented
                    if seg_no < segment_cnt:
                        start_offset = seg_no * self.segment_size
                        end_offset = start_offset + self.segment_size
                        data.content = Blob(bytearray(result[start_offset:end_offset]))
                    else:
                        data.content = None
                else:
                    # No segmentation
                    data.content = Blob(bytearray(result))

            self.keychain.sign(data)
            face.putData(data)
            return True
        else:
            # Data are not ready
            if status.status == STATUS_NO_INPUT:
                self.nodata_reply(interest.name, RET_NO_INPUT)
            elif status.status == STATUS_FAILED:
                self.nodata_reply(interest.name, RET_EXECUTION_FAILED)
            else:
                self.nodata_reply(interest.name, RET_RETRY_AFTER, status.estimated_time - Common.getNowMilliseconds())
            return True
Ejemplo n.º 43
0
def startFileSync():
    global EXIT
    screenName = promptAndInput("Enter your name: ")

    defaultHubPrefix = "ndn/no/ntnu"
    hubPrefix = promptAndInput("Enter your hub prefix [" + defaultHubPrefix + "]: ")
    if hubPrefix == "":
        hubPrefix = defaultHubPrefix

    defaultpkList = "pklist"
    pkListName = promptAndInput("Sync with public key list [" + defaultpkList + "]: ")
    if pkListName == "":
        pkListName = defaultpkList

    host = "localhost" 
    # host = "129.241.208.115"
    logging.info("Connecting to " + host + ", public Key List: " + pkListName + ", Name: " + screenName)

    # Set up the key chain.
    face = Face(host)

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    # privateKeyStorage = OSXPrivateKeyStorage()
    identityManager = IdentityManager(identityStorage, privateKeyStorage)
    # identityManager.createIdentity(Name("/name/"))
    keyChain = KeyChain(identityManager, NoVerifyPolicyManager())
    keyChain.setFace(face)
    
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(0, keyName.size() - 1).append("KEY").append(keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER, DEFAULT_RSA_PRIVATE_KEY_DER)
    face.setCommandSigningInfo(keyChain, certificateName)

    # keyName = Name("/ndn/no/ntnu/stud/haakonmo/ksk-1426537450856")
    # certificateName = Name("/ndn/no/ntnu/KEY/stud/haakonmo/ksk-1426537450856/ID-CERT/%FD%00%00%01L%26%D9E%92")

    # publicKey = privateKeyStorage.getPublicKey(keyName)
    # identityStorage.addKey(keyName, publicKey.getKeyType(), publicKey.getKeyDer())
    # face.setCommandSigningInfo(keyChain, certificateName)

    # print(identityStorage.getCertificate(certificateName))
    # print(identityStorage.getKey(keyName))

    path = './files/'
    fileSyncer = FileSync(screenName, pkListName, Name(hubPrefix), face, keyChain, certificateName, path)
    fileSyncer.initial()    

    fileWatcher = FileWatch(fileSyncer, path)
    # TODO:
    #    1. Generate new public key or use existing?
    #    2. Watch new public key
    #    3. sendUpdatedPublicKey if key is changed
    #    4. Download and store other keys
    #    5. Verify data packet
    while not EXIT:
        isReady, _, _ = select.select([sys.stdin], [], [], 0)
        if len(isReady) != 0:
            input = promptAndInput("")
            if input == "leave" or input == "exit":
                EXIT = True
                break
            #fileSyncer.onFileUpdate(input)

        fileSyncer.face.processEvents()
        # We need to sleep for a few milliseconds so we don't use 100% of the CPU.
        time.sleep(0.01)

    fileSyncer.unsubscribe()
    startTime = FileSync.getNowMilliseconds()
    while True:
        if FileSync.getNowMilliseconds() - startTime >= 1000.0:
            break

        face.processEvents()
        time.sleep(0.01)

    # Shutdown all services
    fileSyncer.face.shutdown()
    fileWatcher.stopFileWatch()
def benchmarkEncodeDataSeconds(nIterations, useComplex, useCrypto):
    """
    Loop to encode a data packet nIterations times.

    :param int nIterations: The number of iterations.
    :param bool useComplex: If true, use a large name, large content and all
      fields. If false, use a small name, small content and only required
      fields.
    :param bool useCrypto: If true, sign the data packet.  If false, use a blank
      signature.
    :return: A tuple (duration, encoding) where duration is the number of
      seconds for all iterations and encoding is the wire encoding.
    :rtype: (float, Blob)
    """
    if useComplex:
        # Use a large name and content.
        name = Name(
          "/ndn/ucla.edu/apps/lwndn-test/numbers.txt/%FD%05%05%E8%0C%CE%1D/%00")

        contentString = ""
        count = 1
        contentString += "%d" % count
        count += 1
        while len(contentString) < 1115:
            contentString += " %d" % count
            count += 1
        content = Name.fromEscapedString(contentString)
    else:
        # Use a small name and content.
        name = Name("/test")
        content = Name.fromEscapedString("abc")
    finalBlockId = Name("/%00")[0]

    # Initialize the private key storage in case useCrypto is true.
    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        SelfVerifyPolicyManager(identityStorage))
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(0, keyName.size() - 1).append(
      "KEY").append(keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(
      keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER, DEFAULT_RSA_PRIVATE_KEY_DER)

    # Set up signatureBits in case useCrypto is false.
    signatureBits = Blob(bytearray(256))
    emptyBlob = Blob([])

    start = getNowSeconds()
    for i in range(nIterations):
        data = Data(name)
        data.setContent(content)
        if useComplex:
            data.getMetaInfo().setFreshnessPeriod(1000)
            data.getMetaInfo().setFinalBlockId(finalBlockId)

        if useCrypto:
            # This sets the signature fields.
            keyChain.sign(data, certificateName)
        else:
            # Imitate IdentityManager.signByCertificate to set up the signature
            # fields, but don't sign.
            sha256Signature = data.getSignature()
            keyLocator = sha256Signature.getKeyLocator()
            keyLocator.setType(KeyLocatorType.KEYNAME)
            keyLocator.setKeyName(certificateName)
            sha256Signature.setSignature(signatureBits)

        encoding = data.wireEncode()

    finish = getNowSeconds()

    return (finish - start, encoding)
Ejemplo n.º 45
0
def main():
    # Uncomment these lines to print ChronoSync debug messages.
    # logging.getLogger('').addHandler(logging.StreamHandler(sys.stdout))
    # logging.getLogger('').setLevel(logging.INFO)

    screenName = promptAndInput("Enter your chat username: "******"ndn/edu/ucla/remap"
    hubPrefix = promptAndInput("Enter your hub prefix [" + defaultHubPrefix + "]: ")
    if hubPrefix == "":
        hubPrefix = defaultHubPrefix

    defaultChatRoom = "ndnchat"
    chatRoom = promptAndInput("Enter the chatroom name [" + defaultChatRoom + "]: ")
    if chatRoom == "":
        chatRoom = defaultChatRoom

    host = "localhost"
    print("Connecting to " + host + ", Chatroom: " + chatRoom + ", Username: "******"")

    # Set up the key chain.
    face = Face(host)

    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        NoVerifyPolicyManager())
    keyChain.setFace(face)
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(0, keyName.size() - 1).append(
      "KEY").append(keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(
      keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER, DEFAULT_RSA_PRIVATE_KEY_DER)
    face.setCommandSigningInfo(keyChain, certificateName)

    chat = Chat(
      screenName, chatRoom, Name(hubPrefix), face, keyChain, certificateName)

    # The main loop to process Chat while checking stdin to send a message.
    print("Enter your chat message. To quit, enter \"leave\" or \"exit\".")
    while True:
        # Set timeout to 0 for an immediate check.
        isReady, _, _ = select.select([sys.stdin], [], [], 0)
        if len(isReady) != 0:
            input = promptAndInput("")
            if input == "leave" or input == "exit":
                # We will send the leave message below.
                break

            chat.sendMessage(input)

        face.processEvents()
        # We need to sleep for a few milliseconds so we don't use 100% of the CPU.
        time.sleep(0.01)

    # The user entered the command to leave.
    chat.leave()
    # Wait a little bit to allow other applications to fetch the leave message.
    startTime = Chat.getNowMilliseconds()
    while True:
        if Chat.getNowMilliseconds() - startTime >= 1000.0:
            break

        face.processEvents()
        time.sleep(0.01)
Ejemplo n.º 46
0
 def test_uri_constructor(self):
     name = Name(self.expectedURI)
     self.assertEqual(name.size(),3, 'Constructed name has ' + str(name.size()) + ' components instead of 3')
     self.assertEqual(name.toUri(), self.expectedURI, 'URI is incorrect')
Ejemplo n.º 47
0
class IotController(BaseNode):
    """
    The controller class has a few built-in commands:
        - listDevices: return the names and capabilities of all attached devices
        - certificateRequest: takes public key information and returns name of
            new certificate
        - updateCapabilities: should be sent periodically from IotNodes to update their
           command lists
        - addDevice: add a device based on HMAC
    It is unlikely that you will need to subclass this.
    """
    def __init__(self, nodeName, networkName, applicationDirectory=""):
        super(IotController, self).__init__()

        self.deviceSuffix = Name(nodeName)
        self.networkPrefix = Name(networkName)
        self.prefix = Name(self.networkPrefix).append(self.deviceSuffix)

        self._policyManager.setEnvironmentPrefix(self.networkPrefix)
        self._policyManager.setTrustRootIdentity(self.prefix)
        self._policyManager.setDeviceIdentity(self.prefix)
        self._policyManager.updateTrustRules()

        # the controller keeps a directory of capabilities->names
        self._directory = defaultdict(list)

        # keep track of who's still using HMACs
        # key is device serial, value is the HmacHelper
        self._hmacDevices = {}

        # our capabilities
        self._baseDirectory = {}

        # add the built-ins
        self._insertIntoCapabilities('listDevices', 'directory', False)
        self._insertIntoCapabilities('updateCapabilities', 'capabilities',
                                     True)

        self._directory.update(self._baseDirectory)

        # Set up application directory
        if applicationDirectory == "":
            applicationDirectory = os.path.expanduser(
                '~/.ndn/iot/applications')
        self._applicationDirectory = applicationDirectory
        self._applications = dict()

    def _insertIntoCapabilities(self, commandName, keyword, isSigned):
        newUri = Name(self.prefix).append(Name(commandName)).toUri()
        self._baseDirectory[keyword] = [{'signed': isSigned, 'name': newUri}]

    def beforeLoopStart(self):
        if not self._policyManager.hasRootSignedCertificate():
            # make one....
            self.log.warn('Generating controller certificate...')
            newKey = self._identityManager.generateRSAKeyPairAsDefault(
                self.prefix, isKsk=True)
            newCert = self._identityManager.selfSign(newKey)
            self._identityManager.addCertificateAsDefault(newCert)
        # Trusting root's own certificate upon each run
        # TODO: debug where application starts first and controller starts second, application's interest cannot be verified
        self._rootCertificate = self._keyChain.getCertificate(
            self.getDefaultCertificateName())
        self._policyManager._certificateCache.insertCertificate(
            self._rootCertificate)

        self._memoryContentCache = MemoryContentCache(self.face)
        self.face.setCommandSigningInfo(self._keyChain,
                                        self.getDefaultCertificateName())
        self._memoryContentCache.registerPrefix(
            self.prefix,
            onRegisterFailed=self.onRegisterFailed,
            onRegisterSuccess=None,
            onDataNotFound=self._onCommandReceived)
        # Serve root certificate in our memoryContentCache
        self._memoryContentCache.add(self._rootCertificate)
        self.loadApplications()
        self.loop.call_soon(self.onStartup)

######
# Initial configuration
#######
# TODO: deviceSuffix will be replaced by deviceSerial

    def _addDeviceToNetwork(self, deviceSerial, newDeviceSuffix, pin):
        h = HmacHelper(pin)
        self._hmacDevices[deviceSerial] = h

        d = DeviceConfigurationMessage()

        for source, dest in [
            (self.networkPrefix, d.configuration.networkPrefix),
            (self.deviceSuffix, d.configuration.controllerName),
            (newDeviceSuffix, d.configuration.deviceSuffix)
        ]:
            for i in range(source.size()):
                component = source.get(i)
                dest.components.append(component.getValue().toRawStr())

        interestName = Name('/home/configure').append(Name(deviceSerial))
        encodedParams = ProtobufTlv.encode(d)
        interestName.append(encodedParams)
        interest = Interest(interestName)
        h.signInterest(interest)

        self.face.expressInterest(interest, self._deviceAdditionResponse,
                                  self._deviceAdditionTimedOut)

    def _deviceAdditionTimedOut(self, interest):
        deviceSerial = str(interest.getName().get(2).getValue())
        self.log.warn("Timed out trying to configure device " + deviceSerial)
        # don't try again
        self._hmacDevices.pop(deviceSerial)

    def _deviceAdditionResponse(self, interest, data):
        status = data.getContent().toRawStr()
        deviceSerial = str(interest.getName().get(2).getValue())
        hmacChecker = self._hmacDevices[deviceSerial]
        if (hmacChecker.verifyData(data)):
            self.log.info("Received {} from {}".format(status, deviceSerial))
        else:
            self.log.warn("Received invalid HMAC from {}".format(deviceSerial))

######
# Certificate signing
######

    def _handleCertificateRequest(self, interest):
        """
        Extracts a public key name and key bits from a command interest name 
        component. Generates a certificate if the request is verifiable.

        This expects an HMAC signed interest.
        """
        message = CertificateRequestMessage()
        commandParamsTlv = interest.getName().get(self.prefix.size() + 1)
        ProtobufTlv.decode(message, commandParamsTlv.getValue())

        signature = HmacHelper.extractInterestSignature(interest)
        deviceSerial = str(
            signature.getKeyLocator().getKeyName().get(-1).getValue())

        response = Data(interest.getName())
        certData = None
        hmac = None
        try:
            hmac = self._hmacDevices[deviceSerial]
            if hmac.verifyInterest(interest):
                certData = self._createCertificateFromRequest(message)
                # remove this hmac; another request will require a new pin
                self._hmacDevices.pop(deviceSerial)
        except KeyError:
            self.log.warn(
                'Received certificate request for device with no registered key'
            )
        except SecurityException as e:
            self.log.warn('Could not create device certificate: ' + str(e))
        else:
            self.log.info(
                'Creating certificate for device {}'.format(deviceSerial))

        if certData is not None:
            response.setContent(certData.wireEncode())
            response.getMetaInfo().setFreshnessPeriod(
                10000)  # should be good even longer
        else:
            response.setContent("Denied")
        if hmac is not None:
            hmac.signData(response)
        self.sendData(response, False)

    def _createCertificateFromRequest(self, message):
        """
        Generate an IdentityCertificate from the public key information given.
        """
        # TODO: Verify the certificate was actually signed with the private key
        # matching the public key we are issuing a cert for!!

        keyComponents = message.command.keyName.components
        keyName = Name("/".join(keyComponents))

        self.log.debug("Key name: " + keyName.toUri())

        if not self._policyManager.getEnvironmentPrefix().match(keyName):
            # we do not issue certs for keys outside of our network
            return None

        keyDer = Blob(message.command.keyBits)
        keyType = message.command.keyType

        try:
            self._identityStorage.addKey(keyName, keyType, keyDer)
        except SecurityException as e:
            print(e)
            # assume this is due to already existing?
            pass

        certificate = self._identityManager._generateCertificateForKey(keyName)

        self._keyChain.sign(certificate, self.getDefaultCertificateName())
        # store it for later use + verification
        self._identityStorage.addCertificate(certificate)
        self._policyManager._certificateCache.insertCertificate(certificate)

        return certificate

######
# Device Capabilities
######

    def _updateDeviceCapabilities(self, interest):
        """
        Take the received capabilities update interest and update our directory listings.
        """
        # we assume the sender is the one who signed the interest...
        signature = self._policyManager._extractSignature(interest)
        certificateName = signature.getKeyLocator().getKeyName()
        senderIdentity = IdentityCertificate.certificateNameToPublicKeyName(
            certificateName).getPrefix(-1)

        self.log.info('Updating capabilities for {}'.format(
            senderIdentity.toUri()))

        # get the params from the interest name
        messageComponent = interest.getName().get(self.prefix.size() + 1)
        message = UpdateCapabilitiesCommandMessage()
        ProtobufTlv.decode(message, messageComponent.getValue())
        # we remove all the old capabilities for the sender
        tempDirectory = defaultdict(list)
        for keyword in self._directory:
            tempDirectory[keyword] = [
                cap for cap in self._directory[keyword]
                if not senderIdentity.match(Name(cap['name']))
            ]

        # then we add the ones from the message
        for capability in message.capabilities:
            capabilityPrefix = Name()
            for component in capability.commandPrefix.components:
                capabilityPrefix.append(component)
            commandUri = capabilityPrefix.toUri()
            if not senderIdentity.match(capabilityPrefix):
                self.log.error(
                    "Node {} tried to register another prefix: {} - ignoring update"
                    .format(senderIdentity.toUri(), commandUri))
            else:
                for keyword in capability.keywords:
                    allUris = [info['name'] for info in tempDirectory[keyword]]
                    if capabilityPrefix not in allUris:
                        listing = {
                            'signed': capability.needsSignature,
                            'name': commandUri
                        }
                        tempDirectory[keyword].append(listing)
        self._directory = tempDirectory

    def _prepareCapabilitiesList(self, interestName):
        """
        Responds to a directory listing request with JSON
        """

        dataName = Name(interestName).append(
            Name.Component.fromNumber(int(time.time())))
        response = Data(dataName)

        response.setContent(json.dumps(self._directory))

        return response

#####
# Interest handling
####

    def _onCommandReceived(self, prefix, interest, face, interestFilterId,
                           filter):
        """
        """
        interestName = interest.getName()

        #if it is a certificate name, serve the certificate
        # TODO: since we've memoryContentCache serving root cert now, this should no longer be required
        try:
            if interestName.isPrefixOf(self.getDefaultCertificateName()):
                foundCert = self._identityManager.getCertificate(
                    self.getDefaultCertificateName())
                self.log.debug("Serving certificate request")
                self.face.putData(foundCert)
                return
        except SecurityException as e:
            # We don't have this certificate, this is probably not a certificate request
            # TODO: this does not differentiate from certificate request but certificate not exist; should update
            print(str(e))
            pass

        afterPrefix = interestName.get(prefix.size()).toEscapedString()
        if afterPrefix == "listDevices":
            #compose device list
            self.log.debug("Received device list request")
            response = self._prepareCapabilitiesList(interestName)
            self.sendData(response)
        elif afterPrefix == "certificateRequest":
            #build and sign certificate
            self.log.debug("Received certificate request")
            self._handleCertificateRequest(interest)

        elif afterPrefix == "updateCapabilities":
            # needs to be signed!
            self.log.debug("Received capabilities update")

            def onVerifiedCapabilities(interest):
                print("capabilities good")
                response = Data(interest.getName())
                response.setContent(str(time.time()))
                self.sendData(response)
                self._updateDeviceCapabilities(interest)

            self._keyChain.verifyInterest(interest, onVerifiedCapabilities,
                                          self.verificationFailed)
        elif afterPrefix == "requests":
            # application request to publish under some names received; need to be signed
            def onVerifiedAppRequest(interest):
                # TODO: for now, we automatically grant access to any valid signed interest
                print("verified! send response!")
                message = AppRequestMessage()
                ProtobufTlv.decode(
                    message,
                    interest.getName().get(prefix.size() + 1).getValue())
                certName = Name("/".join(message.command.idName.components))
                dataPrefix = Name("/".join(
                    message.command.dataPrefix.components))
                appName = message.command.appName
                isUpdated = self.updateTrustSchema(appName, certName,
                                                   dataPrefix, True)

                response = Data(interest.getName())
                if isUpdated:
                    response.setContent(
                        "{\"status\": 200, \"message\": \"granted, trust schema updated OK\" }"
                    )
                    self.log.info(
                        "Verified and granted application publish request")
                else:
                    response.setContent(
                        "{\"status\": 400, \"message\": \"not granted, requested publishing namespace already exists\" }"
                    )
                    self.log.info(
                        "Verified and but requested namespace already exists")
                self.sendData(response)
                return

            def onVerificationFailedAppRequest(interest):
                print("application request verify failed!")
                response = Data(interest.getName())
                response.setContent(
                    "{\"status\": 401, \"message\": \"command interest verification failed\" }"
                )
                self.sendData(response)

            self.log.info("Received application request: " +
                          interestName.toUri())
            #print("Verifying with trust schema: ")
            #print(self._policyManager.config)
            self._keyChain.verifyInterest(interest, onVerifiedAppRequest,
                                          onVerificationFailedAppRequest)
        else:
            print("Got interest unable to answer yet: " +
                  interest.getName().toUri())
            if interest.getExclude():
                print("interest has exclude: " + interest.getExclude().toUri())
            # response = Data(interest.getName())
            # response.setContent("500")
            # response.getMetaInfo().setFreshnessPeriod(1000)
            # self.sendData(response)

    def onStartup(self):
        # begin taking add requests
        self.loop.call_soon(self.displayMenu)
        self.loop.add_reader(stdin, self.handleUserInput)

    def displayMenu(self):
        menuStr = "\n"
        menuStr += "P)air a new device with serial and PIN\n"
        menuStr += "D)irectory listing\n"
        menuStr += "E)xpress an interest\n"
        menuStr += "L)oad hosted applications (" + (
            self._applicationDirectory) + ")\n"
        menuStr += "Q)uit\n"

        print(menuStr)
        print("> ", end="")
        stdout.flush()

    def listDevices(self):
        menuStr = ''
        for capability, commands in self._directory.items():
            menuStr += '{}:\n'.format(capability)
            for info in commands:
                signingStr = 'signed' if info['signed'] else 'unsigned'
                menuStr += '\t{} ({})\n'.format(info['name'], signingStr)
        print(menuStr)
        self.loop.call_soon(self.displayMenu)

    def loadApplicationsMenuSelect(self):
        try:
            confirm = input(
                'This will override existing trust schemas, continue? (Y/N): '
            ).upper().startswith('Y')
            if confirm:
                self.loadApplications(override=True)
            else:
                print("Aborted")
        except KeyboardInterrupt:
            print("Aborted")
        finally:
            self.loop.call_soon(self.displayMenu)

    def onInterestTimeout(self, interest):
        print('Interest timed out: {}'.interest.getName().toUri())

    def onDataReceived(self, interest, data):
        print('Received data named: {}'.format(data.getName().toUri()))
        print('Contents:\n{}'.format(data.getContent().toRawStr()))

    def expressInterest(self):
        try:
            interestName = input('Interest name: ')
            if len(interestName):
                toSign = input('Signed? (y/N): ').upper().startswith('Y')
                interest = Interest(Name(interestName))
                print(interest)
                interest.setInterestLifetimeMilliseconds(10000)
                interest.setChildSelector(1)
                if (toSign):
                    self.face.makeCommandInterest(interest)
                self.face.expressInterest(interest, self.onDataReceived,
                                          self.onInterestTimeout)
            else:
                print("Aborted")
        except KeyboardInterrupt:
            print("Aborted")
        finally:
            self.loop.call_soon(self.displayMenu)

    def beginPairing(self):
        try:
            deviceSerial = input('Device serial: ')
            devicePin = input('PIN: ')
            deviceSuffix = input('Node name: ')
        except KeyboardInterrupt:
            print('Pairing attempt aborted')
        else:
            if len(deviceSerial) and len(devicePin) and len(deviceSuffix):
                self._addDeviceToNetwork(deviceSerial, Name(deviceSuffix),
                                         devicePin.decode('hex'))
            else:
                print('Pairing attempt aborted')
        finally:
            self.loop.call_soon(self.displayMenu)

    def handleUserInput(self):
        inputStr = stdin.readline().upper()
        if inputStr.startswith('D'):
            self.listDevices()
        elif inputStr.startswith('P'):
            self.beginPairing()
        elif inputStr.startswith('E'):
            self.expressInterest()
        elif inputStr.startswith('Q'):
            self.stop()
        elif inputStr.startswith('L'):
            self.loadApplicationsMenuSelect()
        else:
            self.loop.call_soon(self.displayMenu)


########################
# application trust schema distribution
########################

    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

    # TODO: putting existing confs into memoryContentCache
    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
Ejemplo n.º 48
0
    def test_content_key_request(self):
        prefix = Name("/prefix")
        suffix = Name("/a/b/c")
        expectedInterest = Name(prefix)
        expectedInterest.append(Encryptor.NAME_COMPONENT_READ)
        expectedInterest.append(suffix)
        expectedInterest.append(Encryptor.NAME_COMPONENT_E_KEY)

        cKeyName = Name(prefix)
        cKeyName.append(Encryptor.NAME_COMPONENT_SAMPLE)
        cKeyName.append(suffix)
        cKeyName.append(Encryptor.NAME_COMPONENT_C_KEY)

        timeMarker = Name("20150101T100000/20150101T120000")
        testTime1 = Schedule.fromIsoString("20150101T100001")
        testTime2 = Schedule.fromIsoString("20150101T110001")
        testTimeRounded1 = Name.Component("20150101T100000")
        testTimeRounded2 = Name.Component("20150101T110000")

        # Create content keys required for this test case:
        for i in range(suffix.size()):
          self.createEncryptionKey(expectedInterest, timeMarker)
          expectedInterest = expectedInterest.getPrefix(-2).append(
            Encryptor.NAME_COMPONENT_E_KEY)

        expressInterestCallCount = [0]

        # Prepare a TestFace to instantly answer calls to expressInterest.
        class TestFace(object):
            def __init__(self, handleExpressInterest):
                self.handleExpressInterest = handleExpressInterest
            def expressInterest(self, interest, onData, onTimeout):
                return self.handleExpressInterest(interest, onData, onTimeout)

        def handleExpressInterest(interest, onData, onTimeout):
            expressInterestCallCount[0] += 1

            interestName = Name(interest.getName())
            interestName.append(timeMarker)
            self.assertTrue(interestName in self.encryptionKeys)
            onData(interest, self.encryptionKeys[interestName])

            return 0
        face = TestFace(handleExpressInterest)

        # Verify that the content key is correctly encrypted for each domain, and
        # the produce method encrypts the provided data with the same content key.
        testDb = Sqlite3ProducerDb(self.databaseFilePath)
        producer = Producer(prefix, suffix, face, self.keyChain, testDb)
        contentKey = [None] # Blob

        def checkEncryptionKeys(
          result, testTime, roundedTime, expectedExpressInterestCallCount):
            self.assertEqual(expectedExpressInterestCallCount,
                             expressInterestCallCount[0])

            self.assertEqual(True, testDb.hasContentKey(testTime))
            contentKey[0] = testDb.getContentKey(testTime)

            params = EncryptParams(EncryptAlgorithmType.RsaOaep)
            for i in range(len(result)):
                key = result[i]
                keyName = key.getName()
                self.assertEqual(cKeyName, keyName.getSubName(0, 6))
                self.assertEqual(keyName.get(6), roundedTime)
                self.assertEqual(keyName.get(7), Encryptor.NAME_COMPONENT_FOR)
                self.assertEqual(
                  True, keyName.getSubName(8) in self.decryptionKeys)

                decryptionKey = self.decryptionKeys[keyName.getSubName(8)]
                self.assertEqual(True, decryptionKey.size() != 0)
                encryptedKeyEncoding = key.getContent()

                content = EncryptedContent()
                content.wireDecode(encryptedKeyEncoding)
                encryptedKey = content.getPayload()
                retrievedKey = RsaAlgorithm.decrypt(
                  decryptionKey, encryptedKey, params)

                self.assertTrue(contentKey[0].equals(retrievedKey))

            self.assertEqual(3, len(result))

        # An initial test to confirm that keys are created for this time slot.
        contentKeyName1 = producer.createContentKey(
          testTime1,
          lambda keys: checkEncryptionKeys(keys, testTime1, testTimeRounded1, 3))

        # Verify that we do not repeat the search for e-keys. The total
        #   expressInterestCallCount should be the same.
        contentKeyName2 = producer.createContentKey(
          testTime2,
          lambda keys: checkEncryptionKeys(keys, testTime2, testTimeRounded2, 3))

        # Confirm content key names are correct
        self.assertEqual(cKeyName, contentKeyName1.getPrefix(-1))
        self.assertEqual(testTimeRounded1, contentKeyName1.get(6))
        self.assertEqual(cKeyName, contentKeyName2.getPrefix(-1))
        self.assertEqual(testTimeRounded2, contentKeyName2.get(6))

        # Confirm that produce encrypts with the correct key and has the right name.
        testData = Data()
        producer.produce(testData, testTime2, Blob(DATA_CONTENT, False))

        producedName = testData.getName()
        self.assertEqual(cKeyName.getPrefix(-1), producedName.getSubName(0, 5))
        self.assertEqual(testTimeRounded2, producedName.get(5))
        self.assertEqual(Encryptor.NAME_COMPONENT_FOR, producedName.get(6))
        self.assertEqual(cKeyName, producedName.getSubName(7, 6))
        self.assertEqual(testTimeRounded2, producedName.get(13))

        dataBlob = testData.getContent()

        dataContent = EncryptedContent()
        dataContent.wireDecode(dataBlob)
        encryptedData = dataContent.getPayload()
        initialVector = dataContent.getInitialVector()

        params = EncryptParams(EncryptAlgorithmType.AesCbc, 16)
        params.setInitialVector(initialVector)
        decryptTest = AesAlgorithm.decrypt(contentKey[0], encryptedData, params)
        self.assertTrue(decryptTest.equals(Blob(DATA_CONTENT, False)))
Ejemplo n.º 49
0
class FileSync(object):
    def __init__(self, screenName, fileFolderName, hubPrefix, face, keyChain,
                 certificateName, path):
        """
        FileSync:
            To be written (TBW)

        """

        self.screenName = screenName
        self.fileFolderName = fileFolderName
        self.path = path
        # ChronoSync2013: The Face for calling registerPrefix and expressInterest.
        # The Face object must remain valid for the life of this ChronoSync2013 object.
        self.face = face
        self.keyChain = keyChain
        self.certificateName = certificateName

        self.syncDataCache = []  # of CachedSyncData
        self.roster = []  # of str (list of all nodes that are subscribing)
        self.maxDataCacheLength = 100
        self.isRecoverySyncState = True
        self.syncLifetime = 15000.0  # milliseconds

        # This should only be called once, so get the random string here.
        self.fileFolderPrefix = Name(hubPrefix).append(
            self.fileFolderName).append(self.getRandomString())

        # ChronoSync2013: The session number used with the applicationDataPrefix in sync state messages.
        session = int(round(self.getNowMilliseconds() / 1000.0))

        self.userName = self.screenName + str(session)

        broadcastPrefix = Name("/ndn/broadcast/FileSync-0.1").append(
            self.fileFolderName)
        self.sync = ChronoSync2013(
            self.sendInterest,  #onReceivedSyncState        (function object)
            self.initial,  #onInitialized              (function object)
            self.fileFolderPrefix,  #applicationDataPrefix      (Name)
            broadcastPrefix,  #applicationBroadcastPrefix (Name)
            session,  #sessionNo                  (int)
            self.face,  #face                       (Face)
            self.keyChain,  #KeyChain                   (KeyChain)
            self.certificateName,  #certificateName            (Name)
            self.syncLifetime,  #syncLifetime               (float)
            self.onRegisterFailed
        )  #onRegisterFailed           (function object)

        face.registerPrefix(self.fileFolderPrefix, self.onInterest,
                            self.onRegisterFailed)

    def onFileUpdate(self, data):
        """
        FileSync:
            When a key pair is edited, i.e. renewed, the application will publish a new sequence number in ChronoSync2013

        """
        # When the application wants to publish data, it calls ChronoSync2013 method publishNextSequenceNo()

        #Subscribe to "file folder" if not subscribing already
        if len(self.syncDataCache) == 0:
            self.syncDataCacheAppend(fileSyncBuf_pb2.FileSync.SUBSCRIBE, "xxx")

        #TODO: check wether the new public key is new.
        self.sync.publishNextSequenceNo()
        self.syncDataCacheAppend(fileSyncBuf_pb2.FileSync.UPDATE, data)

    def unsubscribe(self):
        """
        FileSync:
            Send the unsubscribe message and unsubscribe the public key.
        """
        self.sync.publishNextSequenceNo()
        self.syncDataCacheAppend(fileSyncBuf_pb2.FileSync.UNSUBSCRIBE, "xxx")

    # onInitialized
    def initial(self):
        """
        FileSync:
            To be written (TBW)

        ChronoSync2013 docs: 
        onInitialized: 
            This calls onInitialized() when the first sync data is received 
            (or the interest times out because there are no other publishers yet).
        """
        timeout = Interest(Name("/local/timeout"))
        timeout.setInterestLifetimeMilliseconds(60000)
        self.face.expressInterest(timeout, self.dummyOnData, self.onTimeout)

        try:
            self.roster.index(self.userName)
        except ValueError:
            self.roster.append(self.userName)
            print("Member: " + self.screenName)
            print(self.screenName + ": Subscribe")
            self.syncDataCacheAppend(fileSyncBuf_pb2.FileSync.SUBSCRIBE, "xxx")

    # onReceivedSyncState
    def sendInterest(self, syncStates, isRecovery):
        """
        FileSync:
            To be written (TBW)

        ChronoSync2013 docs:
        onReceivedSyncState: 
            When ChronoSync receives a sync state message, this calls onReceivedSyncState(syncStates, isRecovery) 
            where syncStates is the list of SyncState messages and isRecovery is true if this is the initial list of SyncState 
            messages or from a recovery interest. (For example, if isRecovery is true, a chat application would not 
            want to re-display all the associated chat messages.) The callback should send interests to fetch the application 
            data for the sequence numbers in the sync state.
        """
        self.isRecoverySyncState = isRecovery
        util.dump("onReceivedSyncState in recovery: ",
                  self.isRecoverySyncState)

        sendList = []  # of str
        sessionNoList = []  # of int
        sequenceNoList = []  # of int
        # Loops through the syncStates
        # ChronoSync2013: A SyncState holds the values of a sync state message which is passed to the
        #     onReceivedSyncState callback which was given to the ChronoSync2013 constructor.
        for j in range(len(syncStates)):
            syncState = syncStates[j]

            # ChronoSync2013: Get the application data prefix for this sync state message.
            nameComponents = Name(syncState.getDataPrefix())

            #TODO not used..
            tempName = nameComponents.get(-1).toEscapedString()
            # tempName is the random string
            # ChronoSync2013: Get the sequence number for this sync state message.
            sequenceNo = syncState.getSequenceNo()
            # ChronoSync2013: Get the session number associated with the application data prefix for this sync state message.
            sessionNo = syncState.getSessionNo()

            #Loop through sendList for not adding duplcates
            index = -1
            for k in range(len(sendList)):
                if sendList[k] == syncState.getDataPrefix():
                    index = k
                    break
            if index != -1:
                sessionNoList[index] = sessionNo
                sequenceNoList[index] = sequenceNo
            else:
                #append to sendList for sending out interest
                sendList.append(syncState.getDataPrefix())
                sessionNoList.append(sessionNo)
                sequenceNoList.append(sequenceNo)

        # Loop through all syncStates and send an interest for all.
        for i in range(len(sendList)):
            uri = (sendList[i] + "/" + str(sessionNoList[i]) + "/" +
                   str(sequenceNoList[i]))
            interestName = Name(uri)
            util.dump("Sync - sending interest: ", interestName.toUri())

            interest = Interest(interestName)
            interest.setInterestLifetimeMilliseconds(self.syncLifetime)
            self.face.expressInterest(interest, self.onData, self.onTimeout)

    def onInterest(self, prefix, interest, transport, registeredPrefixId):
        """
        FileSync:
            To be written (TBW)

        """
        util.dump("Got interest packet with name", interest.getName().toUri())
        util.dumpInterest(interest)

        content = fileSyncBuf_pb2.FileSync()
        sequenceNo = int(interest.getName().get(self.fileFolderPrefix.size() +
                                                1).toEscapedString())
        gotContent = False

        #loop through all cached data and find out if you have some new content to respond with
        for i in range(len(self.syncDataCache) - 1, -1, -1):
            data = self.syncDataCache[i]
            if data.sequenceNo == sequenceNo:
                if data.dataType != fileSyncBuf_pb2.FileSync.UPDATE:
                    # Use setattr because "from" is a reserved keyword.
                    setattr(content, "from", self.screenName)
                    content.to = self.fileFolderName
                    content.dataType = data.dataType
                    content.timestamp = int(round(data.time / 1000.0))
                else:
                    setattr(content, "from", self.screenName)
                    content.to = self.fileFolderName
                    content.dataType = data.dataType
                    content.data = data.data
                    content.timestamp = int(round(data.time / 1000.0))
                gotContent = True
                break

        if gotContent:
            logging.info("new content!")
            #Serialize the pklistbuf
            array = content.SerializeToString()
            #Initialize the data with Name
            data = Data(interest.getName())
            #Set content for the data --> the serialized content to bytes
            data.setContent(Blob(array))
            #Add sign the data
            self.keyChain.sign(data, self.certificateName)
            try:
                transport.send(data.wireEncode().toBuffer())
            except Exception as ex:
                logging.getLogger(__name__).error(
                    "Error in transport.send: %s", str(ex))
                return

    def onData(self, interest, data):
        """
        FileSync:
            To be written (TBW)

        """
        # TODO: Verify packet
        self.keyChain.verifyData(data, self.onVerified, self.onVerifyFailed)

        util.dump("Got data packet with name", data.getName().toUri())
        util.dumpData(data)

        content = fileSyncBuf_pb2.FileSync()
        content.ParseFromString(data.getContent().toRawStr())
        print("Type: " + str(content.dataType) + ", data: " + content.data)

        if self.getNowMilliseconds() - content.timestamp * 1000.0 < 120000.0:
            # Use getattr because "from" is a reserved keyword.
            name = getattr(content, "from")
            prefix = data.getName().getPrefix(-2).toUri()
            sessionNo = int(data.getName().get(-2).toEscapedString())
            sequenceNo = int(data.getName().get(-1).toEscapedString())
            nameAndSession = name + str(sessionNo)

            l = 0
            # Update roster.
            while l < len(self.roster):
                entry = self.roster[l]
                tempName = entry[0:len(entry) - 10]
                tempSessionNo = int(entry[len(entry) - 10:])
                if (name != tempName and content.dataType !=
                        fileSyncBuf_pb2.FileSync.UNSUBSCRIBE):
                    l += 1
                else:
                    if name == tempName and sessionNo > tempSessionNo:
                        self.roster[l] = nameAndSession
                    break

            if l == len(self.roster):
                self.roster.append(nameAndSession)
                print(name + ": Subscribe")

            # Use getattr because "from" is a reserved keyword.
            if (content.dataType == fileSyncBuf_pb2.FileSync.UPDATE
                    and not self.isRecoverySyncState
                    and getattr(content, "from") != self.screenName):
                self.onRecievedFileUpdate(content)
            elif content.dataType == fileSyncBuf_pb2.FileSync.UNSUBSCRIBE:
                # leave message
                try:
                    n = self.roster.index(nameAndSession)
                    if name != self.screenName:
                        self.roster.pop(n)
                        print(name + ": Unsubscribe")
                except ValueError:
                    pass

    def onVerified(self, data):
        #TODO
        print("Data packet verified")

    def onVerifyFailed(self, data):
        #TODO
        print("Data packet failed verification")

    def onRecievedFileUpdate(self, content):
        print(getattr(content, "from") + ": " + content.data)
        fileName = self.path + getattr(content, "from")
        if (os.path.isfile(fileName)):
            # update file
            logging.info("Updating file" + fileName)
            fileTemp = open(fileName, 'r+')
            fileTemp.write(content.data)
            fileTemp.close()
        else:
            # create file
            logging.info("Creating file" + fileName)
            fileTemp = open(fileName, "w")
            fileTemp.write(content.data)
            fileTemp.close()

    def onRegisterFailed(prefix):
        print("Register failed for prefix " + prefix.toUri())

    def heartbeat(self, interest):
        """
        This repeatedly calls itself after a timeout to send a heartbeat message
        (pksync message type HELLO). This method has an "interest" argument
        because we use it as the onTimeout for Face.expressInterest.
        """
        if len(self.syncDataCache) == 0:
            self.syncDataCacheAppend(fileSyncBuf_pb2.FileSync.SUBSCRIBE, "xxx")

        self.sync.publishNextSequenceNo()
        self.syncDataCacheAppend(fileSyncBuf_pb2.FileSync.HELLO, "xxx")

        # Call again.
        # TODO: Are we sure using a "/local/timeout" interest is the best future call
        # approach?
        timeout = Interest(Name("/local/timeout"))
        timeout.setInterestLifetimeMilliseconds(60000)
        self.face.expressInterest(timeout, self.dummyOnData, self.heartbeat)

    def onTimeout(self, interest):
        """
        FileSync:
            To be written (TBW)
        """
        util.dump("Time out for interest", interest.getName().toUri())

    def syncDataCacheAppend(self, dataType, data):
        """
        FileSync:
            To be written (TBW)

        ChronoChat:
            Append a new CachedMessage to messageCache_, using given messageType and
            message, the sequence number from _sync.getSequenceNo() and the current
            time. Also remove elements from the front of the cache as needed to keep
            the size to _maxMessageCacheLength.
        """
        cachedData = self.CachedData(self.sync.getSequenceNo(), dataType, data,
                                     self.getNowMilliseconds())

        self.syncDataCache.append(cachedData)

        while len(self.syncDataCache) > self.maxDataCacheLength:
            self.syncDataCache.pop(0)

    @staticmethod
    def getNowMilliseconds():
        """
        Get the current time in milliseconds.
        
        :return: The current time in milliseconds since 1/1/1970, including fractions of a millisecond.
        :rtype: float
        """
        return time.time() * 1000.0

    @staticmethod
    def getRandomString():
        """
        Generate a random name for ChronoSync.
        """
        #TODO: better seed
        seed = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789"
        result = ""
        for i in range(10):
            # Using % means the distribution isn't uniform, but that's OK.
            position = random.randrange(256) % len(seed)
            result += seed[position]

        return result

    @staticmethod
    def dummyOnData(interest, data):
        """
        This is a do-nothing onData for using expressInterest for timeouts.
        This should never be called.
        """
        pass

    class CachedData(object):
        def __init__(self, sequenceNo, dataType, data, time):
            self.sequenceNo = sequenceNo
            self.dataType = dataType
            self.data = data
            self.time = time
Ejemplo n.º 50
0
class IotController(BaseNode):
    """
    The controller class has a few built-in commands:
        - listDevices: return the names and capabilities of all attached devices
        - certificateRequest: takes public key information and returns name of
            new certificate
        - updateCapabilities: should be sent periodically from IotNodes to update their
           command lists
        - addDevice: add a device based on HMAC
    It is unlikely that you will need to subclass this.
    """
    def __init__(self, nodeName, networkName, applicationDirectory = ""):
        super(IotController, self).__init__()
        
        self.deviceSuffix = Name(nodeName)
        self.networkPrefix = Name(networkName)
        self.prefix = Name(self.networkPrefix).append(self.deviceSuffix)

        self._policyManager.setEnvironmentPrefix(self.networkPrefix)
        self._policyManager.setTrustRootIdentity(self.prefix)
        self._policyManager.setDeviceIdentity(self.prefix)
        self._policyManager.updateTrustRules()
        
        # the controller keeps a directory of capabilities->names
        self._directory = defaultdict(list)

        # keep track of who's still using HMACs
        # key is device serial, value is the HmacHelper
        self._hmacDevices = {}

        # our capabilities
        self._baseDirectory = {}

        # add the built-ins
        self._insertIntoCapabilities('listDevices', 'directory', False)
        self._insertIntoCapabilities('updateCapabilities', 'capabilities', True)

        self._directory.update(self._baseDirectory)

        # Set up application directory
        if applicationDirectory == "":
            applicationDirectory = os.path.expanduser('~/.ndn/iot/applications')
        self._applicationDirectory = applicationDirectory
        self._applications = dict()
        
    def _insertIntoCapabilities(self, commandName, keyword, isSigned):
        newUri = Name(self.prefix).append(Name(commandName)).toUri()
        self._baseDirectory[keyword] = [{'signed':isSigned, 'name':newUri}]

    def beforeLoopStart(self):
        if not self._policyManager.hasRootSignedCertificate():
            # make one....
            self.log.warn('Generating controller certificate...')
            newKey = self._identityManager.generateRSAKeyPairAsDefault(
                self.prefix, isKsk=True)
            newCert = self._identityManager.selfSign(newKey)
            self._identityManager.addCertificateAsDefault(newCert)
        # Trusting root's own certificate upon each run
        # TODO: debug where application starts first and controller starts second, application's interest cannot be verified
        self._rootCertificate = self._keyChain.getCertificate(self.getDefaultCertificateName())
        self._policyManager._certificateCache.insertCertificate(self._rootCertificate)
        
        self._memoryContentCache = MemoryContentCache(self.face)
        self.face.setCommandSigningInfo(self._keyChain, self.getDefaultCertificateName())
        self._memoryContentCache.registerPrefix(self.prefix, onRegisterFailed = self.onRegisterFailed, 
          onRegisterSuccess = None, onDataNotFound = self._onCommandReceived)
        # Serve root certificate in our memoryContentCache
        self._memoryContentCache.add(self._rootCertificate)
        self.loadApplications()
        self.loop.call_soon(self.onStartup)

######
# Initial configuration
#######
    # TODO: deviceSuffix will be replaced by deviceSerial
    def _addDeviceToNetwork(self, deviceSerial, newDeviceSuffix, pin):
        h = HmacHelper(pin)
        self._hmacDevices[deviceSerial] = h

        d = DeviceConfigurationMessage()

        for source, dest in [(self.networkPrefix, d.configuration.networkPrefix),
                             (self.deviceSuffix, d.configuration.controllerName),
                             (newDeviceSuffix, d.configuration.deviceSuffix)]:
            for i in range(source.size()):
                component = source.get(i)
                dest.components.append(component.getValue().toRawStr())

        interestName = Name('/home/configure').append(Name(deviceSerial))
        encodedParams = ProtobufTlv.encode(d)
        interestName.append(encodedParams)
        interest = Interest(interestName)
        h.signInterest(interest)

        self.face.expressInterest(interest, self._deviceAdditionResponse,
            self._deviceAdditionTimedOut)

    def _deviceAdditionTimedOut(self, interest):
        deviceSerial = str(interest.getName().get(2).getValue())
        self.log.warn("Timed out trying to configure device " + deviceSerial)
        # don't try again
        self._hmacDevices.pop(deviceSerial)

    def _deviceAdditionResponse(self, interest, data):
        status = data.getContent().toRawStr()
        deviceSerial = str(interest.getName().get(2).getValue())
        hmacChecker = self._hmacDevices[deviceSerial]
        if (hmacChecker.verifyData(data)): 
            self.log.info("Received {} from {}".format(status, deviceSerial))
        else:
            self.log.warn("Received invalid HMAC from {}".format(deviceSerial))
        
######
# Certificate signing
######

    def _handleCertificateRequest(self, interest):
        """
        Extracts a public key name and key bits from a command interest name 
        component. Generates a certificate if the request is verifiable.

        This expects an HMAC signed interest.
        """
        message = CertificateRequestMessage()
        commandParamsTlv = interest.getName().get(self.prefix.size()+1)
        ProtobufTlv.decode(message, commandParamsTlv.getValue())

        signature = HmacHelper.extractInterestSignature(interest)
        deviceSerial = str(signature.getKeyLocator().getKeyName().get(-1).getValue())

        response = Data(interest.getName())
        certData = None
        hmac = None
        try:
            hmac = self._hmacDevices[deviceSerial]
            if hmac.verifyInterest(interest):
                certData = self._createCertificateFromRequest(message)
                # remove this hmac; another request will require a new pin
                self._hmacDevices.pop(deviceSerial)
        except KeyError:
            self.log.warn('Received certificate request for device with no registered key')
        except SecurityException as e:
            self.log.warn('Could not create device certificate: ' + str(e))
        else:
            self.log.info('Creating certificate for device {}'.format(deviceSerial))

        if certData is not None:
            response.setContent(certData.wireEncode())
            response.getMetaInfo().setFreshnessPeriod(10000) # should be good even longer
        else:
            response.setContent("Denied")
        if hmac is not None:
            hmac.signData(response)
        self.sendData(response, False)

    def _createCertificateFromRequest(self, message):
        """
        Generate an IdentityCertificate from the public key information given.
        """
        # TODO: Verify the certificate was actually signed with the private key
        # matching the public key we are issuing a cert for!!

        keyComponents = message.command.keyName.components
        keyName = Name("/".join(keyComponents))

        self.log.debug("Key name: " + keyName.toUri())

        if not self._policyManager.getEnvironmentPrefix().match(keyName):
            # we do not issue certs for keys outside of our network
            return None

        keyDer = Blob(message.command.keyBits)
        keyType = message.command.keyType

        try:
            self._identityStorage.addKey(keyName, keyType, keyDer)
        except SecurityException as e:
            print(e)
            # assume this is due to already existing?
            pass

        certificate = self._identityManager._generateCertificateForKey(keyName)

        self._keyChain.sign(certificate, self.getDefaultCertificateName())
        # store it for later use + verification
        self._identityStorage.addCertificate(certificate)
        self._policyManager._certificateCache.insertCertificate(certificate)

        return certificate

######
# Device Capabilities
######

    def _updateDeviceCapabilities(self, interest):
        """
        Take the received capabilities update interest and update our directory listings.
        """
        # we assume the sender is the one who signed the interest...
        signature = self._policyManager._extractSignature(interest)
        certificateName = signature.getKeyLocator().getKeyName()
        senderIdentity = IdentityCertificate.certificateNameToPublicKeyName(certificateName).getPrefix(-1)

        self.log.info('Updating capabilities for {}'.format(senderIdentity.toUri()))

        # get the params from the interest name
        messageComponent = interest.getName().get(self.prefix.size()+1)
        message = UpdateCapabilitiesCommandMessage()
        ProtobufTlv.decode(message, messageComponent.getValue())
        # we remove all the old capabilities for the sender
        tempDirectory = defaultdict(list)
        for keyword in self._directory:
            tempDirectory[keyword] = [cap for cap in self._directory[keyword] 
                    if not senderIdentity.match(Name(cap['name']))]

        # then we add the ones from the message
        for capability in message.capabilities:
            capabilityPrefix = Name()
            for component in capability.commandPrefix.components:
                capabilityPrefix.append(component)
            commandUri = capabilityPrefix.toUri()
            if not senderIdentity.match(capabilityPrefix):
                self.log.error("Node {} tried to register another prefix: {} - ignoring update".format(
                    senderIdentity.toUri(),commandUri))
            else:    
                for keyword in capability.keywords:
                    allUris = [info['name'] for info in tempDirectory[keyword]]
                    if capabilityPrefix not in allUris:
                        listing = {'signed':capability.needsSignature,
                                'name':commandUri}
                        tempDirectory[keyword].append(listing)
        self._directory = tempDirectory

    def _prepareCapabilitiesList(self, interestName):
        """
        Responds to a directory listing request with JSON
        """
        
        dataName = Name(interestName).append(Name.Component.fromNumber(int(time.time())))
        response = Data(dataName)

        response.setContent(json.dumps(self._directory))

        return response

#####
# Interest handling
####

    def _onCommandReceived(self, prefix, interest, face, interestFilterId, filter):
        """
        """
        interestName = interest.getName()

        #if it is a certificate name, serve the certificate
        # TODO: since we've memoryContentCache serving root cert now, this should no longer be required
        try:
            if interestName.isPrefixOf(self.getDefaultCertificateName()):
                foundCert = self._identityManager.getCertificate(self.getDefaultCertificateName())
                self.log.debug("Serving certificate request")
                self.face.putData(foundCert)
                return
        except SecurityException as e:
            # We don't have this certificate, this is probably not a certificate request
            # TODO: this does not differentiate from certificate request but certificate not exist; should update
            print(str(e))
            pass

        afterPrefix = interestName.get(prefix.size()).toEscapedString()
        if afterPrefix == "listDevices":
            #compose device list
            self.log.debug("Received device list request")
            response = self._prepareCapabilitiesList(interestName)
            self.sendData(response)
        elif afterPrefix == "certificateRequest":
            #build and sign certificate
            self.log.debug("Received certificate request")
            self._handleCertificateRequest(interest)

        elif afterPrefix == "updateCapabilities":
            # needs to be signed!
            self.log.debug("Received capabilities update")
            def onVerifiedCapabilities(interest):
                print("capabilities good")
                response = Data(interest.getName())
                response.setContent(str(time.time()))
                self.sendData(response)
                self._updateDeviceCapabilities(interest)
            self._keyChain.verifyInterest(interest, 
                    onVerifiedCapabilities, self.verificationFailed)
        elif afterPrefix == "requests":
            # application request to publish under some names received; need to be signed
            def onVerifiedAppRequest(interest):
                # TODO: for now, we automatically grant access to any valid signed interest
                print("verified! send response!")
                message = AppRequestMessage()
                ProtobufTlv.decode(message, interest.getName().get(prefix.size() + 1).getValue())
                certName = Name("/".join(message.command.idName.components))
                dataPrefix = Name("/".join(message.command.dataPrefix.components))
                appName = message.command.appName
                isUpdated = self.updateTrustSchema(appName, certName, dataPrefix, True)

                response = Data(interest.getName())
                if isUpdated:
                    response.setContent("{\"status\": 200, \"message\": \"granted, trust schema updated OK\" }")
                    self.log.info("Verified and granted application publish request")
                else:
                    response.setContent("{\"status\": 400, \"message\": \"not granted, requested publishing namespace already exists\" }")
                    self.log.info("Verified and but requested namespace already exists")
                self.sendData(response)
                return
            def onVerificationFailedAppRequest(interest):
                print("application request verify failed!")
                response = Data(interest.getName())
                response.setContent("{\"status\": 401, \"message\": \"command interest verification failed\" }")
                self.sendData(response)
            self.log.info("Received application request: " + interestName.toUri())
            #print("Verifying with trust schema: ")
            #print(self._policyManager.config)
            self._keyChain.verifyInterest(interest, 
                    onVerifiedAppRequest, onVerificationFailedAppRequest)
        else:
            print("Got interest unable to answer yet: " + interest.getName().toUri())
            if interest.getExclude():
                print("interest has exclude: " + interest.getExclude().toUri())
            # response = Data(interest.getName())
            # response.setContent("500")
            # response.getMetaInfo().setFreshnessPeriod(1000)
            # self.sendData(response)

    def onStartup(self):
        # begin taking add requests
        self.loop.call_soon(self.displayMenu)
        self.loop.add_reader(stdin, self.handleUserInput) 

    def displayMenu(self):
        menuStr = "\n"
        menuStr += "P)air a new device with serial and PIN\n"
        menuStr += "D)irectory listing\n"
        menuStr += "E)xpress an interest\n"
        menuStr += "L)oad hosted applications (" + (self._applicationDirectory) + ")\n"
        menuStr += "Q)uit\n"

        print(menuStr)
        print ("> ", end="")
        stdout.flush()

    def listDevices(self):
        menuStr = ''
        for capability, commands in self._directory.items():
            menuStr += '{}:\n'.format(capability)
            for info in commands:
                signingStr = 'signed' if info['signed'] else 'unsigned'
                menuStr += '\t{} ({})\n'.format(info['name'], signingStr)
        print(menuStr)
        self.loop.call_soon(self.displayMenu)

    def loadApplicationsMenuSelect(self):
        try:
            confirm = input('This will override existing trust schemas, continue? (Y/N): ').upper().startswith('Y')
            if confirm:
                self.loadApplications(override = True)
            else:
                print("Aborted")
        except KeyboardInterrupt:
            print("Aborted")
        finally:
            self.loop.call_soon(self.displayMenu)

    def onInterestTimeout(self, interest):
        print('Interest timed out: {}'.interest.getName().toUri())

    def onDataReceived(self, interest, data):
        print('Received data named: {}'.format(data.getName().toUri()))
        print('Contents:\n{}'.format(data.getContent().toRawStr()))
    
    def expressInterest(self):
        try:
            interestName = input('Interest name: ')
            if len(interestName):
                toSign = input('Signed? (y/N): ').upper().startswith('Y')
                interest = Interest(Name(interestName))
                interest.setInterestLifetimeMilliseconds(5000)
                interest.setChildSelector(1)
                if (toSign):
                    self.face.makeCommandInterest(interest) 
                self.face.expressInterest(interest, self.onDataReceived, self.onInterestTimeout)
            else:
                print("Aborted")
        except KeyboardInterrupt:
                print("Aborted")
        finally:
                self.loop.call_soon(self.displayMenu)

    def beginPairing(self):
        try:
            deviceSerial = input('Device serial: ') 
            devicePin = input('PIN: ')
            deviceSuffix = input('Node name: ')
        except KeyboardInterrupt:
            print('Pairing attempt aborted')
        else:
            if len(deviceSerial) and len(devicePin) and len(deviceSuffix):
                self._addDeviceToNetwork(deviceSerial, Name(deviceSuffix), 
                    devicePin.decode('hex'))
            else:
               print('Pairing attempt aborted')
        finally:
            self.loop.call_soon(self.displayMenu)

    def handleUserInput(self):
        inputStr = stdin.readline().upper()
        if inputStr.startswith('D'):
            self.listDevices()
        elif inputStr.startswith('P'):
            self.beginPairing()
        elif inputStr.startswith('E'):
            self.expressInterest()
        elif inputStr.startswith('Q'):
            self.stop()
        elif inputStr.startswith('L'):
            self.loadApplicationsMenuSelect()
        else:
            self.loop.call_soon(self.displayMenu)
            
########################
# application trust schema distribution
########################
    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
    
    # TODO: putting existing confs into memoryContentCache        
    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
Ejemplo n.º 51
0
class Chat(object):
    def __init__(self, screenName, chatRoom, hubPrefix, face, keyChain,
                 certificateName):
        self._screenName = screenName
        self._chatRoom = chatRoom
        self._face = face
        self._keyChain = keyChain
        self._certificateName = certificateName

        self._messageCache = []  # of CachedMessage
        self._roster = []  # of str
        self._maxMessageCacheLength = 100
        self._isRecoverySyncState = True
        self._syncLifetime = 5000.0  # milliseconds

        # This should only be called once, so get the random string here.
        self._chatPrefix = Name(hubPrefix).append(self._chatRoom).append(
            self._getRandomString())
        session = int(round(self.getNowMilliseconds() / 1000.0))
        self._userName = self._screenName + str(session)

        self._sync = ChronoSync2013(
            self._sendInterest, self._initial, self._chatPrefix,
            Name("/ndn/broadcast/ChronoChat-0.3").append(self._chatRoom),
            session, face, keyChain, certificateName, self._syncLifetime,
            onRegisterFailed)

        face.registerPrefix(self._chatPrefix, self._onInterest,
                            onRegisterFailed)

    def sendMessage(self, chatMessage):
        """
        Send a chat message.
        """
        if len(self._messageCache) == 0:
            self._messageCacheAppend(chatbuf_pb2.ChatMessage.JOIN, "xxx")

        # Ignore an empty message.
        # Forming Sync Data Packet.
        if chatMessage != "":
            self._sync.publishNextSequenceNo()
            self._messageCacheAppend(chatbuf_pb2.ChatMessage.CHAT, chatMessage)
            print(self._screenName + ": " + chatMessage)

    def leave(self):
        """
        Send the leave message and leave.
        """
        self._sync.publishNextSequenceNo()
        self._messageCacheAppend(chatbuf_pb2.ChatMessage.LEAVE, "xxx")

    @staticmethod
    def getNowMilliseconds():
        """
        Get the current time in milliseconds.

        :return: The current time in milliseconds since 1/1/1970, including
          fractions of a millisecond.
        :rtype: float
        """
        return time.time() * 1000.0

    def _initial(self):
        """
        Push the JOIN message in to the messageCache_, update roster
        and start the heartbeat.
        """
        # Set the heartbeat timeout using the Interest timeout mechanism. The
        # heartbeat() function will call itself again after a timeout.
        # TODO: Are we sure using a "/local/timeout" interest is the best future call
        # approach?
        timeout = Interest(Name("/local/timeout"))
        timeout.setInterestLifetimeMilliseconds(60000)
        self._face.expressInterest(timeout, self._dummyOnData, self._heartbeat)

        try:
            self._roster.index(self._userName)
        except ValueError:
            self._roster.append(self._userName)
            print("Member: " + self._screenName)
            print(self._screenName + ": Join")
            self._messageCacheAppend(chatbuf_pb2.ChatMessage.JOIN, "xxx")

    def _sendInterest(self, syncStates, isRecovery):
        """
        Send a Chat Interest to fetch chat messages after the user gets the Sync
        data packet back but will not send interest.
        """
        # This is used by _onData to decide whether to display the chat messages.
        self._isRecoverySyncState = isRecovery

        sendList = []  # of str
        sessionNoList = []  # of int
        sequenceNoList = []  # of int
        for j in range(len(syncStates)):
            syncState = syncStates[j]
            nameComponents = Name(syncState.getDataPrefix())
            tempName = nameComponents.get(-1).toEscapedString()
            sessionNo = syncState.getSessionNo()
            if not tempName == self._screenName:
                index = -1
                for k in range(len(sendList)):
                    if sendList[k] == syncState.getDataPrefix():
                        index = k
                        break

                if index != -1:
                    sessionNoList[index] = sessionNo
                    sequenceNoList[index] = syncState.getSequenceNo()
                else:
                    sendList.append(syncState.getDataPrefix())
                    sessionNoList.append(sessionNo)
                    sequenceNoList.append(syncState.getSequenceNo())

        for i in range(len(sendList)):
            uri = (sendList[i] + "/" + str(sessionNoList[i]) + "/" +
                   str(sequenceNoList[i]))
            interest = Interest(Name(uri))
            interest.setInterestLifetimeMilliseconds(self._syncLifetime)
            self._face.expressInterest(interest, self._onData,
                                       self._chatTimeout)

    def _onInterest(self, prefix, interest, face, interestFilterId, filter):
        """
        Send back a Chat Data Packet which contains the user's message.
        """
        content = chatbuf_pb2.ChatMessage()
        sequenceNo = int(interest.getName().get(self._chatPrefix.size() +
                                                1).toEscapedString())
        gotContent = False
        for i in range(len(self._messageCache) - 1, -1, -1):
            message = self._messageCache[i]
            if message.sequenceNo == sequenceNo:
                if message.messageType != chatbuf_pb2.ChatMessage.CHAT:
                    # Use setattr because "from" is a reserved keyword.
                    setattr(content, "from", self._screenName)
                    content.to = self._chatRoom
                    content.type = message.messageType
                    content.timestamp = int(round(message.time / 1000.0))
                else:
                    setattr(content, "from", self._screenName)
                    content.to = self._chatRoom
                    content.type = message.messageType
                    content.data = message.message
                    content.timestamp = int(round(message.time / 1000.0))

                gotContent = True
                break

        if gotContent:
            # TODO: Check if this works in Python 3.
            array = content.SerializeToString()
            data = Data(interest.getName())
            data.setContent(Blob(array))
            self._keyChain.sign(data, self._certificateName)
            try:
                face.putData(data)
            except Exception as ex:
                logging.getLogger(__name__).error(
                    "Error in transport.send: %s", str(ex))
                return

    def _onData(self, interest, data):
        """
        Process the incoming Chat data.
        """
        # TODO: Check if this works in Python 3.
        content = chatbuf_pb2.ChatMessage()
        content.ParseFromString(data.getContent().toBytes())

        if self.getNowMilliseconds() - content.timestamp * 1000.0 < 120000.0:
            # Use getattr because "from" is a reserved keyword.
            name = getattr(content, "from")
            prefix = data.getName().getPrefix(-2).toUri()
            sessionNo = int(data.getName().get(-2).toEscapedString())
            sequenceNo = int(data.getName().get(-1).toEscapedString())
            nameAndSession = name + str(sessionNo)

            l = 0
            # Update roster.
            while l < len(self._roster):
                entry = self._roster[l]
                tempName = entry[0:len(entry) - 10]
                tempSessionNo = int(entry[len(entry) - 10:])
                if (name != tempName
                        and content.type != chatbuf_pb2.ChatMessage.LEAVE):
                    l += 1
                else:
                    if name == tempName and sessionNo > tempSessionNo:
                        self._roster[l] = nameAndSession
                    break

            if l == len(self._roster):
                self._roster.append(nameAndSession)
                print(name + ": Join")

            # Set the alive timeout using the Interest timeout mechanism.
            # TODO: Are we sure using a "/local/timeout" interest is the best
            # future call approach?
            timeout = Interest(Name("/local/timeout"))
            timeout.setInterestLifetimeMilliseconds(120000)
            self._face.expressInterest(
                timeout, self._dummyOnData,
                self._makeAlive(sequenceNo, name, sessionNo, prefix))

            # isRecoverySyncState_ was set by sendInterest.
            # TODO: If isRecoverySyncState_ changed, this assumes that we won't get
            #     data from an interest sent before it changed.
            # Use getattr because "from" is a reserved keyword.
            if (content.type == chatbuf_pb2.ChatMessage.CHAT
                    and not self._isRecoverySyncState
                    and getattr(content, "from") != self._screenName):
                print(getattr(content, "from") + ": " + content.data)
            elif content.type == chatbuf_pb2.ChatMessage.LEAVE:
                # leave message
                try:
                    n = self._roster.index(nameAndSession)
                    if name != self._screenName:
                        self._roster.pop(n)
                        print(name + ": Leave")
                except ValueError:
                    pass

    @staticmethod
    def _chatTimeout(interest):
        print("Timeout waiting for chat data")

    def _heartbeat(self, interest):
        """
        This repeatedly calls itself after a timeout to send a heartbeat message
        (chat message type HELLO). This method has an "interest" argument
        because we use it as the onTimeout for Face.expressInterest.
        """
        if len(self._messageCache) == 0:
            self._messageCacheAppend(chatbuf_pb2.ChatMessage.JOIN, "xxx")

        self._sync.publishNextSequenceNo()
        self._messageCacheAppend(chatbuf_pb2.ChatMessage.HELLO, "xxx")

        # Call again.
        # TODO: Are we sure using a "/local/timeout" interest is the best future call
        # approach?
        timeout = Interest(Name("/local/timeout"))
        timeout.setInterestLifetimeMilliseconds(60000)
        self._face.expressInterest(timeout, self._dummyOnData, self._heartbeat)

    def _makeAlive(self, tempSequenceNo, name, sessionNo, prefix):
        """
        Return a function for onTimeout which calls _alive.
        """
        def f(interest):
            self._alive(interest, tempSequenceNo, name, sessionNo, prefix)

        return f

    def _alive(self, interest, tempSequenceNo, name, sessionNo, prefix):
        """
        This is called after a timeout to check if the user with prefix has a
        newer sequence number than the given tempSequenceNo. If not, assume the
        user is idle and remove from the roster and print a leave message. This
        method has an "interest" argument because we use it as the onTimeout for
        Face.expressInterest.
        """
        sequenceNo = self._sync.getProducerSequenceNo(prefix, sessionNo)
        nameAndSession = name + sessionNo
        try:
            n = self._roster.index(nameAndSession)
        except ValueError:
            n = -1

        if sequenceNo != -1 and n >= 0:
            if tempSequenceNo == sequenceNo:
                self._roster.pop(n)
                print(name + ": Leave")

    def _messageCacheAppend(self, messageType, message):
        """
        Append a new CachedMessage to messageCache_, using given messageType and
        message, the sequence number from _sync.getSequenceNo() and the current
        time. Also remove elements from the front of the cache as needed to keep
        the size to _maxMessageCacheLength.
        """
        self._messageCache.append(
            self._CachedMessage(self._sync.getSequenceNo(), messageType,
                                message, self.getNowMilliseconds()))
        while len(self._messageCache) > self._maxMessageCacheLength:
            self._messageCache.pop(0)

    @staticmethod
    def _getRandomString():
        """
        Generate a random name for ChronoSync.
        """
        seed = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789"
        result = ""
        for i in range(10):
            # Using % means the distribution isn't uniform, but that's OK.
            position = random.randrange(256) % len(seed)
            result += seed[position]

        return result

    @staticmethod
    def _dummyOnData(interest, data):
        """
        This is a do-nothing onData for using expressInterest for timeouts.
        This should never be called.
        """
        pass

    class _CachedMessage(object):
        def __init__(self, sequenceNo, messageType, message, time):
            self.sequenceNo = sequenceNo
            self.messageType = messageType
            self.message = message
            self.time = time
Ejemplo n.º 52
0
    rp = RepoCommandParameter()
    dataPrefix = Name("/example/data/1/test/test1")
    
    rp.setName(dataPrefix)
    rp.setStartBlockId(0)
    
    interest = Interest(Name("/example/repo/1").append("insert").append(rp.wireEncode()))
    
    identityStorage = MemoryIdentityStorage()
    privateKeyStorage = MemoryPrivateKeyStorage()
    keyChain = KeyChain(IdentityManager(identityStorage, privateKeyStorage),
                        SelfVerifyPolicyManager(identityStorage))

    # Initialize the storage.
    keyName = Name("/testname/DSK-123")
    certificateName = keyName.getSubName(0, keyName.size() - 1).append(
      "KEY").append(keyName[-1]).append("ID-CERT").append("0")
    identityStorage.addKey(keyName, KeyType.RSA, Blob(DEFAULT_RSA_PUBLIC_KEY_DER))
    privateKeyStorage.setKeyPairForKeyName(
      keyName, KeyType.RSA, DEFAULT_RSA_PUBLIC_KEY_DER, DEFAULT_RSA_PRIVATE_KEY_DER)

    # Make a Face just so that we can sign the interest.
    face = Face("localhost")
    face.setCommandSigningInfo(keyChain, certificateName)
    face.makeCommandInterest(interest)
    
    callbacks = Callbacks()
    print interest.getName().toUri()
    face.expressInterest(interest, callbacks.onData, callbacks.onTimeout)
    
    face.registerPrefix(dataPrefix, callbacks.onInterest, callbacks.onRegisterFailed)