예제 #1
0
    def _processRecoveryInterest(self, interest, syncDigest, face):
        logging.getLogger(__name__).info("processRecoveryInterest")
        if self._logFind(syncDigest) != -1:
            tempContent = SyncStateMsg()
            for i in range(self._digestTree.size()):
                content = getattr(tempContent, "ss").add()
                content.name = self._digestTree.get(i).getDataPrefix()
                content.type = SyncState_UPDATE
                content.seqno.seq = self._digestTree.get(i).getSequenceNo()
                content.seqno.session = self._digestTree.get(i).getSessionNo()

            if len(getattr(tempContent, "ss")) != 0:
                # TODO: Check if this works in Python 3.
                #pylint: disable=E1103
                array = tempContent.SerializeToString()
                #pylint: enable=E1103
                data = Data(interest.getName())
                data.setContent(Blob(array))
                if interest.getName().get(-1).toEscapedString() == "00":
                    # Limit the lifetime of replies to interest for "00" since
                    # they can be different.
                    data.getMetaInfo().setFreshnessPeriod(1000)

                self._keyChain.sign(data, self._certificateName)
                try:
                    face.putData(data)
                except Exception as ex:
                    logging.getLogger(__name__).error(
                        "Error in face.putData: %s", str(ex))
                    return

                logging.getLogger(__name__).info("send recovery data back")
                logging.getLogger(__name__).info("%s",
                                                 interest.getName().toUri())
예제 #2
0
    def _createDKeyData(self, startTimeStamp, endTimeStamp, keyName,
                        privateKeyBlob, certificateKey):
        """
        Create a D-KEY Data packet with an EncryptedContent for the given
        private key, encrypted with the certificate key.

        :param str startTimeStamp: The start time stamp string to put in the name.
        :param str endTimeStamp: The end time stamp string to put in the name.
        :param Name keyName The key name to put in the data packet name and the
          EncryptedContent key locator.
        :param Blob privateKeyBlob: A Blob of the encoded private key.
        :param Blob certificateKey: The certificate key encoding, used to
          encrypt the private key.
        :return: The Data packet.
        :rtype: Data
        """
        name = Name(self._namespace)
        name.append(Encryptor.NAME_COMPONENT_D_KEY)
        name.append(startTimeStamp).append(endTimeStamp)
        data = Data(name)
        data.getMetaInfo().setFreshnessPeriod(
            self._freshnessHours * GroupManager.MILLISECONDS_IN_HOUR)
        encryptParams = EncryptParams(EncryptAlgorithmType.RsaOaep)
        Encryptor.encryptData(data, privateKeyBlob, keyName, certificateKey,
                              encryptParams)
        self._keyChain.sign(data)
        return data
예제 #3
0
    def _processRecoveryInterest(self, interest, syncDigest, face):
        logging.getLogger(__name__).info("processRecoveryInterest")
        if self._logFind(syncDigest) != -1:
            tempContent = SyncStateMsg()
            for i in range(self._digestTree.size()):
                content = getattr(tempContent, "ss").add()
                content.name = self._digestTree.get(i).getDataPrefix()
                content.type = SyncState_UPDATE
                content.seqno.seq = self._digestTree.get(i).getSequenceNo()
                content.seqno.session = self._digestTree.get(i).getSessionNo()

            if len(getattr(tempContent, "ss")) != 0:
                # TODO: Check if this works in Python 3.
#pylint: disable=E1103
                array = tempContent.SerializeToString()
#pylint: enable=E1103
                data = Data(interest.getName())
                data.setContent(Blob(array))
                if interest.getName().get(-1).toEscapedString() == "00":
                    # Limit the lifetime of replies to interest for "00" since
                    # they can be different.
                    data.getMetaInfo().setFreshnessPeriod(1000)

                self._keyChain.sign(data, self._certificateName)
                try:
                    face.putData(data)
                except Exception as ex:
                    logging.getLogger(__name__).error(
                      "Error in face.putData: %s", str(ex))
                    return

                logging.getLogger(__name__).info("send recovery data back")
                logging.getLogger(__name__).info("%s", interest.getName().toUri())
예제 #4
0
    def _createDKeyData(self, startTimeStamp, endTimeStamp, keyName,
                        privateKeyBlob, certificateKey):
        """
        Create a D-KEY Data packet with an EncryptedContent for the given
        private key, encrypted with the certificate key.

        :param str startTimeStamp: The start time stamp string to put in the name.
        :param str endTimeStamp: The end time stamp string to put in the name.
        :param Name keyName The key name to put in the data packet name and the
          EncryptedContent key locator.
        :param Blob privateKeyBlob: A Blob of the encoded private key.
        :param Blob certificateKey: The certificate key encoding, used to
          encrypt the private key.
        :return: The Data packet.
        :rtype: Data
        """
        name = Name(self._namespace)
        name.append(Encryptor.NAME_COMPONENT_D_KEY)
        name.append(startTimeStamp).append(endTimeStamp)
        data = Data(name)
        data.getMetaInfo().setFreshnessPeriod(
          self._freshnessHours * GroupManager.MILLISECONDS_IN_HOUR)
        encryptParams = EncryptParams(EncryptAlgorithmType.RsaOaep)
        Encryptor.encryptData(
          data, privateKeyBlob, keyName, certificateKey, encryptParams)
        self._keyChain.sign(data)
        return data
예제 #5
0
    def __init__(self, identity, dataset, keyChain, face):
        self._identity = identity
        self._keyChain = keyChain
        self._face = face

        # storage_ is for the KEK and KDKs.
        self._storage = InMemoryStorageRetaining()

        # The NAC identity is: <identity>/NAC/<dataset>
        # Generate the NAC key.
        nacIdentity = self._keyChain.createIdentityV2(
          Name(identity.getName())
          .append(EncryptorV2.NAME_COMPONENT_NAC).append(dataset),
          RsaKeyParams())
        self._nacKey = nacIdentity.getDefaultKey()
        if self._nacKey.getKeyType() != KeyType.RSA:
            logging.getLogger(__name__).info(
              "Cannot re-use existing KEK/KDK pair, as it is not an RSA key, regenerating")
            self._nacKey = self._keyChain.createKey(nacIdentity, RsaKeyParams())

        nacKeyId = self._nacKey.getName().get(-1)

        kekPrefix = Name(self._nacKey.getIdentityName()).append(
          EncryptorV2.NAME_COMPONENT_KEK)

        kekData = Data(self._nacKey.getDefaultCertificate())
        kekData.setName(Name(kekPrefix).append(nacKeyId))
        kekData.getMetaInfo().setFreshnessPeriod(
          AccessManagerV2.DEFAULT_KEK_FRESHNESS_PERIOD_MS)
        self._keyChain.sign(kekData, SigningInfo(self._identity))
        # kek looks like a cert, but doesn't have ValidityPeriod
        self._storage.insert(kekData)

        def serveFromStorage(prefix, interest, face, interestFilterId, filter):
            data = self._storage.find(interest)
            if data != None:
                logging.getLogger(__name__).info("Serving " +
                  data.getName().toUri() + " from in-memory-storage")
                try:
                    face.putData(data)
                except:
                    logging.exception("AccessManagerV2: Error in Face.putData")
            else:
                logging.getLogger(__name__).info("Didn't find data for " +
                  interest.getName().toUri())
                # TODO: Send NACK?

        def onRegisterFailed(prefix):
            logging.getLogger(__name__).error(
              "AccessManagerV2: Failed to register prefix " + prefix.toUri())

        self._kekRegisteredPrefixId = self._face.registerPrefix(
          kekPrefix, serveFromStorage, onRegisterFailed)

        kdkPrefix = Name(self._nacKey.getIdentityName()).append(
          EncryptorV2.NAME_COMPONENT_KDK).append(nacKeyId)
        self._kdkRegisteredPrefixId_ = self._face.registerPrefix(
          kdkPrefix, serveFromStorage, onRegisterFailed)
예제 #6
0
    def addMember(self, memberCertificate):
        """
        Authorize a member identified by memberCertificate to decrypt data under
        the policy.

        :param CertificateV2 memberCertificate: The certificate that identifies
          the member to authorize.
        :return: The published KDK Data packet.
        :rtype: Data
        """
        kdkName = Name(self._nacKey.getIdentityName())
        kdkName.append(EncryptorV2.NAME_COMPONENT_KDK).append(
            # key-id
            self._nacKey.getName().get(-1)).append(
                EncryptorV2.NAME_COMPONENT_ENCRYPTED_BY).append(
                    memberCertificate.getKeyName())

        secretLength = 32
        secret = bytearray(secretLength)
        for i in range(secretLength):
            secret[i] = _systemRandom.randint(0, 0xff)
        # To be compatible with OpenSSL which uses a null-terminated string,
        # replace each 0 with 1. And to be compatible with the Java security
        # library which interprets the secret as a char array converted to UTF8,
        # limit each byte to the ASCII range 1 to 127.
        for i in range(secretLength):
            if secret[i] == 0:
                secret[i] = 1

            secret[i] &= 0x7f

        kdkSafeBag = self._keyChain.exportSafeBag(
            self._nacKey.getDefaultCertificate(),
            Blob(secret, False).toBytes())

        memberKey = PublicKey(memberCertificate.getPublicKey())

        encryptedContent = EncryptedContent()
        encryptedContent.setPayload(kdkSafeBag.wireEncode())
        encryptedContent.setPayloadKey(
            memberKey.encrypt(
                Blob(secret, False).toBytes(), EncryptAlgorithmType.RsaOaep))

        kdkData = Data(kdkName)
        kdkData.setContent(encryptedContent.wireEncodeV2())
        # FreshnessPeriod can serve as a soft access control for revoking access.
        kdkData.getMetaInfo().setFreshnessPeriod(
            AccessManagerV2.DEFAULT_KDK_FRESHNESS_PERIOD_MS)
        self._keyChain.sign(kdkData, SigningInfo(self._identity))

        self._storage.insert(kdkData)

        return kdkData
예제 #7
0
    def _createEKeyData(self, startTimeStamp, endTimeStamp, publicKeyBlob):
        """
        Create an E-KEY Data packet for the given public key.

        :param str startTimeStamp: The start time stamp string to put in the name.
        :param str endTimeStamp: The end time stamp string to put in the name.
        :param Blob publicKeyBlob: A Blob of the public key DER.
        :return: The Data packet.
        :rtype: Data
        """
        name = Name(self._namespace)
        name.append(Encryptor.NAME_COMPONENT_E_KEY).append(startTimeStamp).append(endTimeStamp)

        data = Data(name)
        data.getMetaInfo().setFreshnessPeriod(self._freshnessHours * GroupManager.MILLISECONDS_IN_HOUR)
        data.setContent(publicKeyBlob)
        self._keyChain.sign(data)
        return data
예제 #8
0
    def _createEKeyData(self, startTimeStamp, endTimeStamp, publicKeyBlob):
        """
        Create an E-KEY Data packet for the given public key.

        :param str startTimeStamp: The start time stamp string to put in the name.
        :param str endTimeStamp: The end time stamp string to put in the name.
        :param Blob publicKeyBlob: A Blob of the public key DER.
        :return: The Data packet.
        :rtype: Data
        """
        name = Name(self._namespace)
        name.append(Encryptor.NAME_COMPONENT_E_KEY).append(
            startTimeStamp).append(endTimeStamp)

        data = Data(name)
        data.getMetaInfo().setFreshnessPeriod(
            self._freshnessHours * GroupManager.MILLISECONDS_IN_HOUR)
        data.setContent(publicKeyBlob)
        self._keyChain.sign(data)
        return data
예제 #9
0
    def _makeAndPublishCkData(self, onError):
        """
        Make a CK Data packet for _ckName encrypted by the KEK in _kekData and
        insert it in the _storage.

        :param onError: On failure, this calls onError(errorCode, message) where
          errorCode is from EncryptError.ErrorCode, and message is an error
          string.
        :type onError: function object
        :return: True on success, else False.
        :rtype: bool
        """
        try:
            kek = PublicKey(self._kekData.getContent())

            content = EncryptedContent()
            content.setPayload(
                kek.encrypt(Blob(self._ckBits, False),
                            EncryptAlgorithmType.RsaOaep))

            ckData = Data(
                Name(self._ckName).append(
                    EncryptorV2.NAME_COMPONENT_ENCRYPTED_BY).append(
                        self._kekData.getName()))
            ckData.setContent(content.wireEncodeV2())
            # FreshnessPeriod can serve as a soft access control for revoking access.
            ckData.getMetaInfo().setFreshnessPeriod(
                EncryptorV2.DEFAULT_CK_FRESHNESS_PERIOD_MS)
            self._keyChain.sign(ckData, self._ckDataSigningInfo)
            self._storage.insert(ckData)

            logging.getLogger(__name__).info("Publishing CK data: " +
                                             ckData.getName().toUri())
            return True
        except Exception as ex:
            onError(
                EncryptError.ErrorCode.EncryptionFailure,
                "Failed to encrypt generated CK with KEK " +
                self._kekData.getName().toUri())
            return False
예제 #10
0
    def _makeAndPublishCkData(self, onError):
        """
        Make a CK Data packet for _ckName encrypted by the KEK in _kekData and
        insert it in the _storage.

        :param onError: On failure, this calls onError(errorCode, message) where
          errorCode is from EncryptError.ErrorCode, and message is an error
          string.
        :type onError: function object
        :return: True on success, else False.
        :rtype: bool
        """
        try:
            kek = PublicKey(self._kekData.getContent())

            content = EncryptedContent()
            content.setPayload(kek.encrypt
              (Blob(self._ckBits, False), EncryptAlgorithmType.RsaOaep))

            ckData = Data(
              Name(self._ckName).append(EncryptorV2.NAME_COMPONENT_ENCRYPTED_BY)
               .append(self._kekData.getName()))
            ckData.setContent(content.wireEncodeV2())
            # FreshnessPeriod can serve as a soft access control for revoking access.
            ckData.getMetaInfo().setFreshnessPeriod(
              EncryptorV2.DEFAULT_CK_FRESHNESS_PERIOD_MS)
            self._keyChain.sign(ckData, self._ckDataSigningInfo)
            self._storage.insert(ckData)

            logging.getLogger(__name__).info("Publishing CK data: " +
              ckData.getName().toUri())
            return True
        except Exception as ex:
            onError(EncryptError.ErrorCode.EncryptionFailure,
              "Failed to encrypt generated CK with KEK " +
              self._kekData.getName().toUri())
            return False
예제 #11
0
    def publish(self, interestName, dataName, content, freshnessPeriod, 
      signingInfo = SigningInfo()):
        """
        Put all the segments in the memory store.

        :param Name interestName: If the Interest name ends in a segment,
          immediately send the Data packet for the segment to the Face.
        :param Name dataName: The Data name, which has components after the
          Interest name.
        :param Blob content: The content of the data to be segmented.
        :param float freshnessPeriod The freshness period of the segments,
          in milliseconds.
        :param SigningInfo signingInfo (optional) The SigningInfo for signing
          segment Data packets. If omitted, use the default SigningInfo().
        """
        interestSegment = 0
        if interestName[-1].isSegment():
            interestSegment = interestName[-1].toSegment()

        rawBuffer = content.buf()
        iSegmentBegin = 0
        iEnd = len(content)

        maxPacketSize = int(Common.MAX_NDN_PACKET_SIZE / 2)

        totalSegments = int(len(content) / maxPacketSize)
        finalBlockId = Name.Component.fromSegment(totalSegments)

        segmentPrefix = Name(dataName)
        segmentPrefix.appendVersion(int(Common.getNowMilliseconds()))

        segmentNo = 0
        while(True):
            iSegmentEnd = iSegmentBegin + maxPacketSize
            if iSegmentEnd > iEnd:
                iSegmentEnd = iEnd

            segmentName = Name(segmentPrefix)
            segmentName.appendSegment(segmentNo)

            data = Data(segmentName)
            data.setContent(Blob(rawBuffer[iSegmentBegin : iSegmentEnd]))
            data.getMetaInfo().setFreshnessPeriod(freshnessPeriod)
            data.getMetaInfo().setFinalBlockId(finalBlockId)

            iSegmentBegin = iSegmentEnd

            self._keyChain.sign(data, signingInfo)

            # Only send the segment to the Face if it has a pending interest.
            # Otherwise, the segment is unsolicited.
            if interestSegment == segmentNo:
                self._face.putData(data)

            # Until InMemoryStorageFifo implements an eviction policy, use InMemoryStorageRetaining.
            # storage_.insert(*data, freshnessPeriod)
            self._storage.insert(data)

            # Make and return a callback since segmentName is different each time.
            def makeCallback(localSegmentName):
                def callback():
                    self._storage.remove(localSegmentName)
                return callback

            self._face.callLater(freshnessPeriod, makeCallback(segmentName))

            segmentNo += 1
            
            if not (iSegmentBegin < iEnd):
                break
예제 #12
0
    def publish(self,
                interestName,
                dataName,
                content,
                freshnessPeriod,
                signingInfo=SigningInfo()):
        """
        Put all the segments in the memory store.

        :param Name interestName: If the Interest name ends in a segment,
          immediately send the Data packet for the segment to the Face.
        :param Name dataName: The Data name, which has components after the
          Interest name.
        :param Blob content: The content of the data to be segmented.
        :param float freshnessPeriod The freshness period of the segments,
          in milliseconds.
        :param SigningInfo signingInfo (optional) The SigningInfo for signing
          segment Data packets. If omitted, use the default SigningInfo().
        """
        interestSegment = 0
        if interestName[-1].isSegment():
            interestSegment = interestName[-1].toSegment()

        rawBuffer = content.buf()
        iSegmentBegin = 0
        iEnd = len(content)

        maxPacketSize = int(Common.MAX_NDN_PACKET_SIZE / 2)

        totalSegments = int(len(content) / maxPacketSize)
        finalBlockId = Name.Component.fromSegment(totalSegments)

        segmentPrefix = Name(dataName)
        segmentPrefix.appendVersion(int(Common.getNowMilliseconds()))

        segmentNo = 0
        while (True):
            iSegmentEnd = iSegmentBegin + maxPacketSize
            if iSegmentEnd > iEnd:
                iSegmentEnd = iEnd

            segmentName = Name(segmentPrefix)
            segmentName.appendSegment(segmentNo)

            data = Data(segmentName)
            data.setContent(Blob(rawBuffer[iSegmentBegin:iSegmentEnd]))
            data.getMetaInfo().setFreshnessPeriod(freshnessPeriod)
            data.getMetaInfo().setFinalBlockId(finalBlockId)

            iSegmentBegin = iSegmentEnd

            self._keyChain.sign(data, signingInfo)

            # Only send the segment to the Face if it has a pending interest.
            # Otherwise, the segment is unsolicited.
            if interestSegment == segmentNo:
                self._face.putData(data)

            # Until InMemoryStorageFifo implements an eviction policy, use InMemoryStorageRetaining.
            # storage_.insert(*data, freshnessPeriod)
            self._storage.insert(data)

            # Make and return a callback since segmentName is different each time.
            def makeCallback(localSegmentName):
                def callback():
                    self._storage.remove(localSegmentName)

                return callback

            self._face.callLater(freshnessPeriod, makeCallback(segmentName))

            segmentNo += 1

            if not (iSegmentBegin < iEnd):
                break