Esempio n. 1
0
    def sign(self, data, keyName, digestAlgorithm=DigestAlgorithm.SHA256):
        """
        Fetch the private key for keyName and sign the data, returning a
        signature Blob.

        :param data: Pointer the input byte buffer to sign.
        :type data: An array type with int elements
        :param Name keyName: The name of the signing key.
        :param digestAlgorithm: (optional) the digest algorithm. If omitted,
          use DigestAlgorithm.SHA256.
        :type digestAlgorithm: int from DigestAlgorithm
        :return: The signature Blob.
        :rtype: Blob
        """
        keyURI = keyName.toUri()

        if not self.doesKeyExist(keyName, KeyClass.PRIVATE):
            raise SecurityException(
                "FilePrivateKeyStorage.sign: private key doesn't exist")

        if digestAlgorithm != DigestAlgorithm.SHA256:
            raise SecurityException(
                "FilePrivateKeyStorage.sign: Unsupported digest algorithm")

        # Read the private key.
        base64Content = None
        with open(self.nameTransform(keyURI, ".pri")) as keyFile:
            base64Content = keyFile.read()
        der = Blob(base64.b64decode(base64Content), False)

        # Decode the PKCS #8 key to get the algorithm OID.
        parsedNode = DerNode.parse(der.buf(), 0)
        pkcs8Children = parsedNode.getChildren()
        algorithmIdChildren = DerNode.getSequence(pkcs8Children,
                                                  1).getChildren()
        oidString = algorithmIdChildren[0].toVal()

        privateKey = serialization.load_der_private_key(
            der.toBytes(), password=None, backend=default_backend())

        # Sign the data.
        data = Blob(data, False).toBytes()
        if (oidString == PublicKey.RSA_ENCRYPTION_OID
                or oidString == PublicKey.EC_ENCRYPTION_OID):
            if oidString == PublicKey.RSA_ENCRYPTION_OID:
                signer = privateKey.signer(padding.PKCS1v15(), hashes.SHA256())
            else:
                signer = privateKey.signer(ec.ECDSA(hashes.SHA256()))

            signer.update(data)
            signature = signer.finalize()
            return Blob(bytearray(signature), False)
        else:
            raise SecurityException(
                "FilePrivateKeyStorage.sign: Unrecognized private key type")
Esempio n. 2
0
    def sign(self, data, keyName, digestAlgorithm = DigestAlgorithm.SHA256):
        """
        Fetch the private key for keyName and sign the data, returning a
        signature Blob.

        :param data: Pointer the input byte buffer to sign.
        :type data: An array type with int elements
        :param Name keyName: The name of the signing key.
        :param digestAlgorithm: (optional) the digest algorithm. If omitted,
          use DigestAlgorithm.SHA256.
        :type digestAlgorithm: int from DigestAlgorithm
        :return: The signature Blob.
        :rtype: Blob
        """
        keyURI = keyName.toUri()

        if not self.doesKeyExist(keyName, KeyClass.PRIVATE):
            raise SecurityException(
              "FilePrivateKeyStorage.sign: private key doesn't exist")

        if digestAlgorithm != DigestAlgorithm.SHA256:
            raise SecurityException(
              "FilePrivateKeyStorage.sign: Unsupported digest algorithm")

        # Read the private key.
        base64Content = None
        with open(self.nameTransform(keyURI, ".pri")) as keyFile:
            base64Content = keyFile.read()
        der = Blob(base64.b64decode(base64Content), False)

        # Decode the PKCS #8 key to get the algorithm OID.
        parsedNode = DerNode.parse(der.buf(), 0)
        pkcs8Children = parsedNode.getChildren()
        algorithmIdChildren = DerNode.getSequence(pkcs8Children, 1).getChildren()
        oidString = algorithmIdChildren[0].toVal()

        privateKey = serialization.load_der_private_key(
          der.toBytes(), password = None, backend = default_backend())

        # Sign the data.
        data = Blob(data, False).toBytes()
        if (oidString == PublicKey.RSA_ENCRYPTION_OID or
            oidString == PublicKey.EC_ENCRYPTION_OID):
            if oidString == PublicKey.RSA_ENCRYPTION_OID:
                signer = privateKey.signer(padding.PKCS1v15(), hashes.SHA256())
            else:
                signer = privateKey.signer(ec.ECDSA(hashes.SHA256()))

            signer.update(data)
            signature = signer.finalize()
            return Blob(bytearray(signature), False)
        else:
            raise SecurityException(
              "FilePrivateKeyStorage.sign: Unrecognized private key type")
    def _decode(encoding):
        """
        Decode the IBLT from the Blob. This converts the Blob into a uint8_t
        array which is then decoded to a uint32_t array.

        :param Blob encoding: The encoded IBLT.
        :return: A uint32_t array representing the hash table of the IBLT.
        :rtype: Array<int>
        """
        # Use Blob to convert bytes to an integer array.
        ibltValues = Blob(zlib.decompress(encoding.toBytes()), False)

        nEntries = int(len(ibltValues) / 4)
        values = [0] * nEntries

        ibltValuesBuf = ibltValues.buf()
        for i in range(0, 4 * nEntries, 4):
            t = ((ibltValuesBuf[i + 3] << 24) + (ibltValuesBuf[i + 2] << 16) +
                 (ibltValuesBuf[i + 1] << 8) + ibltValuesBuf[i])
            values[int(i / 4)] = t

        return values
    def _decode(encoding):
        """
        Decode the IBLT from the Blob. This converts the Blob into a uint8_t
        array which is then decoded to a uint32_t array.

        :param Blob encoding: The encoded IBLT.
        :return: A uint32_t array representing the hash table of the IBLT.
        :rtype: Array<int>
        """
        # Use Blob to convert bytes to an integer array.
        ibltValues = Blob(zlib.decompress(encoding.toBytes()), False)

        nEntries = int(len(ibltValues) / 4)
        values = [0] * nEntries

        ibltValuesBuf = ibltValues.buf()
        for i in range(0, 4 * nEntries, 4):
          t = ((ibltValuesBuf[i + 3] << 24) +
               (ibltValuesBuf[i + 2] << 16) +
               (ibltValuesBuf[i + 1] << 8)  +
               ibltValuesBuf[i])
          values[int(i / 4)] = t

        return values
Esempio n. 5
0
    class Component(object):
        """
        Create a new Name.Component with a copy of the given value.
        (To create an ImplicitSha256Digest component, use fromImplicitSha256Digest.)

        :param value: (optional) If value is already a Blob or Name.Component,
          then take another pointer to the value.  Otherwise, create a new
          Blob with a copy of the value.  If omitted, create an empty component.
        :type value: Blob or Name.Component or value for Blob constructor
        :param int type: (optional) The component type as an int from the
          ComponentType enum. If name component type is not a recognized
          ComponentType enum value, then set this to ComponentType.OTHER_CODE
          and use the otherTypeCode parameter. If omitted, use
          ComponentType.GENERIC.
        :param int otherTypeCode: (optional) If type is ComponentType.OTHER_CODE,
          then this is the packet's unrecognized content type code, which must
          be non-negative.
        """
        def __init__(self, value=None, type=None, otherTypeCode=None):
            if isinstance(value, Name.Component):
                # Copy constructor. Use the existing Blob in the other Component.
                self._value = value._value
                self._type = value._type
                self._otherTypeCode = value._otherTypeCode
                return

            if value == None:
                self._value = Blob([])
            else:
                # Blob will make a copy.
                self._value = value if isinstance(value, Blob) else Blob(value)

            if type == ComponentType.OTHER_CODE:
                if otherTypeCode == None:
                    raise ValueError(
                        "To use an other code, call Name.Component(value, ComponentType.OTHER_CODE, otherTypeCode)"
                    )

                if otherTypeCode < 0:
                    raise ValueError(
                        "Name.Component other type code must be non-negative")
                self._otherTypeCode = otherTypeCode
            else:
                self._otherTypeCode = -1

            self._type = ComponentType.GENERIC if type == None else type

        def getValue(self):
            """
            Get the value of the component.

            :return: The component value.
            :rtype: Blob
            """
            return self._value

        def getType(self):
            """
            Get the name component type.

            :return: The name component type as an int from the ComponentType
              enum. If this is ComponentType.OTHER_CODE, then call
              getOtherTypeCode() to get the unrecognized component type code.
            :rtype: int
            """
            return self._type

        def getOtherTypeCode(self):
            """
            Get the component type code from the packet which is other than a
              recognized ComponentType enum value. This is only meaningful if
              getType() is ComponentType.OTHER_CODE.

            :return: The type code.
            :rtype: int
            """
            return self._otherTypeCode

        def toEscapedString(self, result=None):
            """
            Convert this component to a string, escaping characters according
            to the NDN URI Scheme. This also adds "..." to a value with zero or
            more ".". This adds a type code prefix as needed, such as
            "sha256digest=".

            :param BytesIO result: (optional) The BytesIO stream to write to.
              If omitted, return a str with the result.
            :return: The result as a string (only if result is omitted).
            :rtype: str
            """
            if result == None:
                result = BytesIO()
                self.toEscapedString(result)
                return Common.getBytesIOString(result)

            if self._type == ComponentType.IMPLICIT_SHA256_DIGEST:
                result.write("sha256digest=".encode('utf-8'))
                self._value.toHex(result)
                return

            if self._type != ComponentType.GENERIC:
                result.write(
                    str(self._otherTypeCode) if self._type ==
                    ComponentType.OTHER_CODE else str(self._type))
                result.write("=")

            Name.toEscapedString(self._value.buf(), result)

        def isSegment(self):
            """
            Check if this component is a segment number according to NDN
            naming conventions for "Segment number" (marker 0x00).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: True if this is a segment number.
            :rtype: bool
            """
            return (self._value.size() >= 1 and self._value.buf()[0] == 0x00
                    and self.isGeneric())

        def isSegmentOffset(self):
            """
            Check if this component is a segment byte offset according to NDN
            naming conventions for segment "Byte offset" (marker 0xFB).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: True if this is a segment byte offset.
            :rtype: bool
            """
            return (self._value.size() >= 1 and self._value.buf()[0] == 0xFB
                    and self.isGeneric())

        def isVersion(self):
            """
            Check if this component is a version number according to NDN
            naming conventions for "Versioning" (marker 0xFD).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: True if this is a version number.
            :rtype: bool
            """
            return (self._value.size() >= 1 and self._value.buf()[0] == 0xFD
                    and self.isGeneric())

        def isTimestamp(self):
            """
            Check if this component is a timestamp according to NDN
            naming conventions for "Timestamp" (marker 0xFC).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: True if this is a timestamp.
            :rtype: bool
            """
            return (self._value.size() >= 1 and self._value.buf()[0] == 0xFC
                    and self.isGeneric())

        def isSequenceNumber(self):
            """
            Check if this component is a sequence number according to NDN
            naming conventions for "Sequencing" (marker 0xFE).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: True if this is a sequence number.
            :rtype: bool
            """
            return (self._value.size() >= 1 and self._value.buf()[0] == 0xFE
                    and self.isGeneric())

        def isGeneric(self):
            """
            Check if this component is a generic component.

            :return: True if this is an generic component.
            :rtype: bool
            """
            return self._type == ComponentType.GENERIC

        def isImplicitSha256Digest(self):
            """
            Check if this component is an ImplicitSha256Digest component.

            :return: True if this is an ImplicitSha256Digest component.
            :rtype: bool
            """
            return self._type == ComponentType.IMPLICIT_SHA256_DIGEST

        def toNumber(self):
            """
            Interpret this name component as a network-ordered number and return
            an integer.

            :return: The integer number.
            :rtype: int
            """
            result = 0
            for i in range(self._value.size()):
                result *= 256
                result += self._value.buf()[i]
            return result

        def toNumberWithMarker(self, marker):
            """
            Interpret this name component as a network-ordered number with a
            marker and return an integer.

            :param int marker: The required first byte of the component.
            :return: The integer number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component does not
              equal the marker.
            """
            if self._value.size() <= 0 or self._value.buf()[0] != marker:
                raise RuntimeError(
                    "Name component does not begin with the expected marker")

            result = 0
            for i in range(1, self._value.size()):
                result *= 256
                result += self._value.buf()[i]
            return result

        def toSegment(self):
            """
            Interpret this name component as a segment number according to NDN
            naming conventions for "Segment number" (marker 0x00).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer segment number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0x00)

        def toSegmentOffset(self):
            """
            Interpret this name component as a segment byte offset according to
            NDN naming conventions for segment "Byte offset" (marker 0xFB).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer segment byte offset.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFB)

        def toVersion(self):
            """
            Interpret this name component as a version number  according to NDN
            naming conventions for "Versioning" (marker 0xFD). Note that this
            returns the exact number from the component without converting it to
            a time representation.
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer version number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFD)

        def toTimestamp(self):
            """
            Interpret this name component as a timestamp  according to NDN naming
            conventions for "Timestamp" (marker 0xFC).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The number of microseconds since the UNIX epoch (Thursday,
              1 January 1970) not counting leap seconds.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFC)

        def toSequenceNumber(self):
            """
            Interpret this name component as a sequence number according to NDN
            naming conventions for "Sequencing" (marker 0xFE).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer sequence number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFE)

        def equals(self, other):
            """
            Check if this is the same component as other.

            :param Name.Component other: The other Component to compare with.
            :return: True if the components are equal, otherwise False.
            :rtype: bool
            """
            if self._type == ComponentType.OTHER_CODE:
                return (self._value.equals(other._value)
                        and other._type == ComponentType.OTHER_CODE
                        and self._otherTypeCode == other._otherTypeCode)
            else:
                return self._value.equals(
                    other._value) and self._type == other._type

        def compare(self, other):
            """
            Compare this to the other Component using NDN canonical ordering.

            :param Name.Component other: The other Component to compare with.
            :return: 0 If they compare equal, -1 if self comes before other in
              the canonical ordering, or 1 if self comes after other in the
              canonical ordering.
            :rtype: int
            :see: http://named-data.net/doc/0.2/technical/CanonicalOrder.html
            """
            myTypeCode = (self._otherTypeCode if self._type
                          == ComponentType.OTHER_CODE else self._type)
            otherTypeCode = (other._otherTypeCode if other._type
                             == ComponentType.OTHER_CODE else other._type)

            if myTypeCode < otherTypeCode:
                return -1
            if myTypeCode > otherTypeCode:
                return 1

            if self._value.size() < other._value.size():
                return -1
            if self._value.size() > other._value.size():
                return 1

            # The components are equal length. Just do a byte compare.
            return self._value.compare(other._value)

        @staticmethod
        def fromNumber(number, type=None, otherTypeCode=None):
            """
            Create a component whose value is the nonNegativeInteger encoding of
            the number.

            :param int number: The number to be encoded.
            :param int type: (optional) The component type as an int from the
              ComponentType enum. If name component type is not a recognized
              ComponentType enum value, then set this to ComponentType.OTHER_CODE
              and use the otherTypeCode parameter. If omitted, use
              ComponentType.GENERIC.
            :param int otherTypeCode: (optional) If type is
              ComponentType.OTHER_CODE, then this is the packet's unrecognized
              content type code, which must be non-negative.
            :return: The new component value.
            :rtype: Name.Component
            """
            encoder = TlvEncoder(8)
            encoder.writeNonNegativeInteger(number)
            return Name.Component(Blob(encoder.getOutput(), False), type,
                                  otherTypeCode)

        @staticmethod
        def fromNumberWithMarker(number, marker):
            """
            Create a component whose value is the marker appended with the
            nonNegativeInteger encoding of the number.

            :param int number: The number to be encoded.
            :param int marker: The marker to use as the first byte of the
              component.
            :return: The component value.
            :rtype: Name.Component
            """
            encoder = TlvEncoder(9)
            # Encode backwards.
            encoder.writeNonNegativeInteger(number)
            encoder.writeNonNegativeInteger(marker)
            return Name.Component(Blob(encoder.getOutput(), False))

        @staticmethod
        def fromSegment(segment):
            """
            Create a component with the encoded segment number according to NDN
            naming conventions for "Segment number" (marker 0x00).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :param int segment: The segment number.
            :return: The new Component.
            :rtype: Name.Component
            """
            return Name.Component.fromNumberWithMarker(segment, 0x00)

        @staticmethod
        def fromSegmentOffset(segmentOffset):
            """
            Create a component with the encoded segment byte offset according to NDN
            naming conventions for segment "Byte offset" (marker 0xFB).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :param int segmentOffset: The segment byte offset.
            :return: The new Component.
            :rtype: Name.Component
            """
            return Name.Component.fromNumberWithMarker(segmentOffset, 0xFB)

        @staticmethod
        def fromVersion(version):
            """
            Create a component with the encoded version number according to NDN
            naming conventions for "Versioning" (marker 0xFD).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf
            Note that this encodes the exact value of version without converting
            from a time representation.

            :param int version: The version number.
            :return: The new Component.
            :rtype: Name.Component
            """
            return Name.Component.fromNumberWithMarker(version, 0xFD)

        @staticmethod
        def fromTimestamp(timestamp):
            """
            Create a component with the encoded timestamp according to NDN naming
            conventions for "Timestamp" (marker 0xFC).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :param int timestamp: The number of microseconds since the UNIX epoch
              (Thursday, 1 January 1970) not counting leap seconds.
            :return: The new Component.
            :rtype: Name.Component
            """
            return Name.Component.fromNumberWithMarker(timestamp, 0xFC)

        @staticmethod
        def fromSequenceNumber(sequenceNumber):
            """
            Create a component with the encoded sequence number according to NDN naming
            conventions for "Sequencing" (marker 0xFE).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :param int sequenceNumber: The sequence number.
            :return: The new Component.
            :rtype: Name.Component
            """
            return Name.Component.fromNumberWithMarker(sequenceNumber, 0xFE)

        @staticmethod
        def fromImplicitSha256Digest(digest):
            """
            Create a component of type ImplicitSha256DigestComponent, so that
            isImplicitSha256Digest() is true.

            :param digest: The SHA-256 digest value.
            :type digest: Blob or value for Blob constructor
            :return: The new Component.
            :rtype: Name.Component
            :raises RuntimeError: If the digest length is not 32 bytes.
            """
            digestBlob = digest if isinstance(digest, Blob) else Blob(digest)
            if digestBlob.size() != 32:
                raise RuntimeError(
                    "Name.Component.fromImplicitSha256Digest: The digest length must be 32 bytes"
                )

            result = Name.Component(digestBlob)
            result._type = ComponentType.IMPLICIT_SHA256_DIGEST
            return result

        def getSuccessor(self):
            """
            Get the successor of this component, as described in
            Name.getSuccessor.

            :return: A new Name.Component which is the successor of this.
            :rtype: Name.Component
            """
            # Allocate an extra byte in case the result is larger.
            result = bytearray(self._value.size() + 1)

            carry = True
            for i in range(self._value.size() - 1, -1, -1):
                if carry:
                    result[i] = (self._value.buf()[i] + 1) & 0xff
                    carry = (result[i] == 0)
                else:
                    result[i] = self._value.buf()[i]

            if carry:
                # Assume all the bytes were set to zero (or the component was
                # empty). In NDN ordering, carry does not mean to prepend a 1,
                # but to make a component one byte longer of all zeros.
                result[len(result) - 1] = 0
            else:
                # We didn't need the extra byte.
                result = result[0:self._value.size()]

            return Name.Component(Blob(result, False), self._type,
                                  self._otherTypeCode)

        # Python operators

        def __eq__(self, other):
            return isinstance(other, Name.Component) and self.equals(other)

        def __ne__(self, other):
            return not self == other

        def __le__(self, other):
            return self.compare(other) <= 0

        def __lt__(self, other):
            return self.compare(other) < 0

        def __ge__(self, other):
            return self.compare(other) >= 0

        def __gt__(self, other):
            return self.compare(other) > 0

        def __len__(self):
            return self._value.size()

        def __str__(self):
            return self.toEscapedString()

        def __hash__(self):
            return (37 * (self._otherTypeCode if self._type
                          == ComponentType.OTHER_CODE else self._type) +
                    hash(self._value))
Esempio n. 6
0
    class Component(object):
        """
        Create a new GENERIC Name.Component.

        :param value: (optional) If value is already a Blob or Name.Component,
          then take another pointer to the value.  Otherwise, create a new
          Blob with a copy of the value.  If omitted, create an empty component.
        :type value: Blob or Name.Component or value for Blob constructor
        """
        def __init__(self, value = None):
            if type(value) is Name.Component:
                # Copy constructor. Use the existing Blob in the other Component.
                self._value = value._value
                self._type = value._type
                return

            if value == None:
                self._value = Blob([])
            else:
                # Blob will make a copy.
                self._value = value if isinstance(value, Blob) else Blob(value)

            self._type = Name.Component.ComponentType.GENERIC

        class ComponentType(object):
            """
            A Name.Component.ComponentType specifies the recognized types of a
            name component.
            """
            IMPLICIT_SHA256_DIGEST = 1
            GENERIC                = 8

        def getValue(self):
            """
            Get the value of the component.

            :return: The component value.
            :rtype: Blob
            """
            return self._value

        def toEscapedString(self, result = None):
            """
            Convert this component to a string, escaping characters according
            to the NDN URI Scheme. This also adds "..." to a value with zero or
            more ".". This adds a type code prefix as needed, such as
            "sha256digest=".

            :param BytesIO result: (optional) The BytesIO stream to write to.
              If omitted, return a str with the result.
            :return: The result as a string (only if result is omitted).
            :rtype: str
            """
            if result == None:
                result = BytesIO()
                self.toEscapedString(result)
                return Common.getBytesIOString(result)
            else:
                if self._type == Name.Component.ComponentType.IMPLICIT_SHA256_DIGEST:
                    result.write("sha256digest=".encode('utf-8'))
                    self._value.toHex(result)
                else:
                    Name.toEscapedString(self._value.buf(), result)

        def isSegment(self):
            """
            Check if this component is a segment number according to NDN
            naming conventions for "Segment number" (marker 0x00).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: True if this is a segment number.
            :rtype: bool
            """
            return (self._value.size() >= 1 and self._value.buf()[0] == 0x00 and
                    self.isGeneric())

        def isSegmentOffset(self):
            """
            Check if this component is a segment byte offset according to NDN
            naming conventions for segment "Byte offset" (marker 0xFB).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: True if this is a segment byte offset.
            :rtype: bool
            """
            return (self._value.size() >= 1 and self._value.buf()[0] == 0xFB and
                    self.isGeneric())

        def isVersion(self):
            """
            Check if this component is a version number according to NDN
            naming conventions for "Versioning" (marker 0xFD).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: True if this is a version number.
            :rtype: bool
            """
            return (self._value.size() >= 1 and self._value.buf()[0] == 0xFD and
                    self.isGeneric())

        def isTimestamp(self):
            """
            Check if this component is a timestamp according to NDN
            naming conventions for "Timestamp" (marker 0xFC).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: True if this is a timestamp.
            :rtype: bool
            """
            return (self._value.size() >= 1 and self._value.buf()[0] == 0xFC and
                    self.isGeneric())

        def isSequenceNumber(self):
            """
            Check if this component is a sequence number according to NDN
            naming conventions for "Sequencing" (marker 0xFE).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: True if this is a sequence number.
            :rtype: bool
            """
            return (self._value.size() >= 1 and self._value.buf()[0] == 0xFE and
                    self.isGeneric())

        def isGeneric(self):
            """
            Check if this component is a generic component.

            :return: True if this is an generic component.
            :rtype: bool
            """
            return self._type == Name.Component.ComponentType.GENERIC

        def isImplicitSha256Digest(self):
            """
            Check if this component is an ImplicitSha256Digest component.

            :return: True if this is an ImplicitSha256Digest component.
            :rtype: bool
            """
            return self._type == Name.Component.ComponentType.IMPLICIT_SHA256_DIGEST

        def toNumber(self):
            """
            Interpret this name component as a network-ordered number and return
            an integer.

            :return: The integer number.
            :rtype: int
            """
            result = 0
            for i in range(self._value.size()):
                result *= 256
                result += self._value.buf()[i]
            return result

        def toNumberWithMarker(self, marker):
            """
            Interpret this name component as a network-ordered number with a
            marker and return an integer.

            :param int marker: The required first byte of the component.
            :return: The integer number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component does not
              equal the marker.
            """
            if self._value.size() <= 0 or self._value.buf()[0] != marker:
                raise RuntimeError(
                       "Name component does not begin with the expected marker")

            result = 0
            for i in range(1, self._value.size()):
                result *= 256
                result += self._value.buf()[i]
            return result

        def toSegment(self):
            """
            Interpret this name component as a segment number according to NDN
            naming conventions for "Segment number" (marker 0x00).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer segment number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0x00)

        def toSegmentOffset(self):
            """
            Interpret this name component as a segment byte offset according to
            NDN naming conventions for segment "Byte offset" (marker 0xFB).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer segment byte offset.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFB)

        def toVersion(self):
            """
            Interpret this name component as a version number  according to NDN
            naming conventions for "Versioning" (marker 0xFD). Note that this
            returns the exact number from the component without converting it to
            a time representation.
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer version number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFD)

        def toTimestamp(self):
            """
            Interpret this name component as a timestamp  according to NDN naming
            conventions for "Timestamp" (marker 0xFC).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The number of microseconds since the UNIX epoch (Thursday,
              1 January 1970) not counting leap seconds.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFC)

        def toSequenceNumber(self):
            """
            Interpret this name component as a sequence number according to NDN
            naming conventions for "Sequencing" (marker 0xFE).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer sequence number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFE)

        def equals(self, other):
            """
            Check if this is the same component as other.

            :param Name.Component other: The other Component to compare with.
            :return: True if the components are equal, otherwise False.
            :rtype: bool
            """
            return self._value.equals(other._value) and self._type == other._type

        def compare(self, other):
            """
            Compare this to the other Component using NDN canonical ordering.

            :param Name.Component other: The other Component to compare with.
            :return: 0 If they compare equal, -1 if self comes before other in
              the canonical ordering, or 1 if self comes after other in the
              canonical ordering.
            :rtype: int
            :see: http://named-data.net/doc/0.2/technical/CanonicalOrder.html
            """
            if self._type < other._type:
                return -1
            if self._type > other._type:
                return 1

            if self._value.size() < other._value.size():
                return -1
            if self._value.size() > other._value.size():
                return 1

            # The components are equal length. Just do a byte compare.
            return self._value.compare(other._value)

        @staticmethod
        def fromNumber(number):
            """
            Create a component whose value is the nonNegativeInteger encoding of
            the number.

            :param int number: The number to be encoded.
            :return: The component value.
            :rtype: Name.Component
            """
            encoder = TlvEncoder(8)
            encoder.writeNonNegativeInteger(number)
            return Name.Component(Blob(encoder.getOutput(), False))

        @staticmethod
        def fromNumberWithMarker(number, marker):
            """
            Create a component whose value is the marker appended with the
            nonNegativeInteger encoding of the number.

            :param int number: The number to be encoded.
            :param int marker: The marker to use as the first byte of the
              component.
            :return: The component value.
            :rtype: Name.Component
            """
            encoder = TlvEncoder(9)
            # Encode backwards.
            encoder.writeNonNegativeInteger(number)
            encoder.writeNonNegativeInteger(marker)
            return Name.Component(Blob(encoder.getOutput(), False))

        @staticmethod
        def fromSegment(segment):
            """
            Create a component with the encoded segment number according to NDN
            naming conventions for "Segment number" (marker 0x00).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :param int segment: The segment number.
            :return: The new Component.
            :rtype: Name.Component
            """
            return Name.Component.fromNumberWithMarker(segment, 0x00)

        @staticmethod
        def fromSegmentOffset(segmentOffset):
            """
            Create a component with the encoded segment byte offset according to NDN
            naming conventions for segment "Byte offset" (marker 0xFB).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :param int segmentOffset: The segment byte offset.
            :return: The new Component.
            :rtype: Name.Component
            """
            return Name.Component.fromNumberWithMarker(segmentOffset, 0xFB)

        @staticmethod
        def fromVersion(version):
            """
            Create a component with the encoded version number according to NDN
            naming conventions for "Versioning" (marker 0xFD).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf
            Note that this encodes the exact value of version without converting
            from a time representation.

            :param int version: The version number.
            :return: The new Component.
            :rtype: Name.Component
            """
            return Name.Component.fromNumberWithMarker(version, 0xFD)

        @staticmethod
        def fromTimestamp(timestamp):
            """
            Create a component with the encoded timestamp according to NDN naming
            conventions for "Timestamp" (marker 0xFC).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :param int timestamp: The number of microseconds since the UNIX epoch
              (Thursday, 1 January 1970) not counting leap seconds.
            :return: The new Component.
            :rtype: Name.Component
            """
            return Name.Component.fromNumberWithMarker(timestamp, 0xFC)

        @staticmethod
        def fromSequenceNumber(sequenceNumber):
            """
            Create a component with the encoded sequence number according to NDN naming
            conventions for "Sequencing" (marker 0xFE).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :param int sequenceNumber: The sequence number.
            :return: The new Component.
            :rtype: Name.Component
            """
            return Name.Component.fromNumberWithMarker(sequenceNumber, 0xFE)

        @staticmethod
        def fromImplicitSha256Digest(digest):
            """
            Create a component of type ImplicitSha256DigestComponent, so that
            isImplicitSha256Digest() is true.

            :param digest: The SHA-256 digest value.
            :type digest: Blob or value for Blob constructor
            :return: The new Component.
            :rtype: Name.Component
            :raises RuntimeError: If the digest length is not 32 bytes.
            """
            digestBlob = digest if isinstance(digest, Blob) else Blob(digest)
            if digestBlob.size() != 32:
              raise RuntimeError(
                "Name.Component.fromImplicitSha256Digest: The digest length must be 32 bytes")

            result = Name.Component(digestBlob)
            result._type = Name.Component.ComponentType.IMPLICIT_SHA256_DIGEST
            return result

        def getSuccessor(self):
            """
            Get the successor of this component, as described in
            Name.getSuccessor.

            :return: A new Name.Component which is the successor of this.
            :rtype: Name.Component
            """
            # Allocate an extra byte in case the result is larger.
            result = bytearray(self._value.size() + 1)

            carry = True
            for i in range(self._value.size() - 1, -1, -1):
                if carry:
                    result[i] = (self._value.buf()[i] + 1) & 0xff
                    carry = (result[i] == 0)
                else:
                    result[i] = self._value.buf()[i]

            if carry:
                # Assume all the bytes were set to zero (or the component was
                # empty). In NDN ordering, carry does not mean to prepend a 1,
                # but to make a component one byte longer of all zeros.
                result[len(result) - 1] = 0
            else:
                # We didn't need the extra byte.
                result = result[0:self._value.size()]

            return Name.Component(Blob(result, False))

        # Python operators

        def __eq__(self, other):
            return type(other) is Name.Component and self.equals(other)

        def __ne__(self, other):
            return not self == other

        def __le__(self, other):
            return self.compare(other) <= 0

        def __lt__(self, other):
            return self.compare(other) < 0

        def __ge__(self, other):
            return self.compare(other) >= 0

        def __gt__(self, other):
            return self.compare(other) > 0

        def __len__(self):
            return self._value.size()

        def __str__(self):
            return self.toEscapedString()

        def __hash__(self):
            return hash(self._value)
Esempio n. 7
0
class PublicKey(object):
    """
    Create a new PublicKey by decoding the keyDer. Set the key type from the
    decoding.

    :param Blob keyDer: The blob of the PublicKeyInfo in terms of DER.
    :raises: UnrecognizedKeyFormatException if can't decode the key DER.
    """
    def __init__(self, keyDer = None):
        # TODO: Implementation of managed properties?

        if keyDer == None:
            self._keyDer = Blob()
            self._keyType = None
            return

        self._keyDer = keyDer

        # Get the public key OID.
        oidString = ""
        try:
            parsedNode = DerNode.parse(keyDer.buf(), 0)
            rootChildren = parsedNode.getChildren()
            algorithmIdChildren = DerNode.getSequence(
              rootChildren, 0).getChildren()
            oidString = algorithmIdChildren[0].toVal()
        except DerDecodingException as ex:
          raise UnrecognizedKeyFormatException(
            "PublicKey.decodeKeyType: Error decoding the public key" + str(ex))

        # Verify that the we can decode.
        if oidString == self.RSA_ENCRYPTION_OID:
            self._keyType = KeyType.RSA
            RSA.importKey(keyDer.toRawStr())
        elif oidString == self.EC_ENCRYPTION_OID:
            self._keyType = KeyType.ECDSA
            # TODO: Check EC decoding.
        else:
            raise UnrecognizedKeyFormatException(
              "PublicKey.decodeKeyType: Unrecognized OID " + oidString)

    def toDer(self):
        """
        Encode the public key into DER.

        :return: The encoded DER syntax tree.
        :rtype: DerNode
        """
        return DerNode.parse(self._keyDer)

    def getDigest(self, digestAlgorithm = DigestAlgorithm.SHA256):
        """
        Get the digest of the public key.

        :param digestAlgorithm: (optional) The digest algorithm.  If omitted,
          use DigestAlgorithm.SHA256 .
        :type digestAlgorithm: int from DigestAlgorithm
        :return: The digest value
        :rtype: Blob
        """
        if digestAlgorithm == DigestAlgorithm.SHA256:
            hashFunc  = SHA256.new()
            hashFunc.update(self._keyDer.buf())

            return Blob(hashFunc.digest())
        else:
            raise RuntimeError("Unimplemented digest algorithm")


    def getKeyType(self):
        """
        Get the key type.

        :return: The key type
        :rtype: an int from KeyType
        """
        return self._keyType

    def getKeyDer(self):
        """
        Get the raw bytes of the public key in DER format.

        :return: The public key DER
        :rtype: Blob
        """
        return self._keyDer

    RSA_ENCRYPTION_OID = "1.2.840.113549.1.1.1"
    EC_ENCRYPTION_OID = "1.2.840.10045.2.1"
Esempio n. 8
0
class SafeBag(object):
    """
    There are three forms of the SafeBag constructor:
    SafeBag(certificate, privateKeyBag) - Create a SafeBag with the given
    certificate and private key.
    SafeBag(keyName, privateKeyBag, publicKeyEncoding [, password,
    digestAlgorithm, wireFormat]) - Create a SafeBag with given private key
    and a new self-signed certificate for the given public key.
    SafeBag(input) - Create a SafeBag by decoding the input as an NDN-TLV SafeBag.

    :param Data certificate: The certificate data packet (used only for
      SafeBag(certificate, privateKeyBag)). This copies the object.
    :param Blob privateKeyBag: The encoded private key. If encrypted, this is a
      PKCS #8 EncryptedPrivateKeyInfo. If not encrypted, this is an unencrypted
      PKCS #8 PrivateKeyInfo.
    :param password: (optional) The password for decrypting the private key in
      order to sign the self-signed certificate, which should have characters in 
      the range of 1 to 127. If the password is supplied, use it to decrypt the
      PKCS #8 EncryptedPrivateKeyInfo. If the password is omitted or None,
      privateKeyBag is an unencrypted PKCS #8 PrivateKeyInfo.
    :type password: an array which implements the buffer protocol
    :param int digestAlgorithm: (optional) The digest algorithm for signing the
      self-signed certificate. If omitted, use DigestAlgorithm.SHA256 .
    :type digestAlgorithm: int from the DigestAlgorithm enum
    :param WireFormat wireFormat: (optional) A WireFormat object used to encode
      the self-signed certificate in order to sign it. If omitted, use
      WireFormat.getDefaultWireFormat().
    :param input: The array with the bytes to decode.
    :type input: A Blob or an array type with int elements
    """
    def __init__(self, arg1, privateKeyBag = None,
      publicKeyEncoding = None, password = None,
      digestAlgorithm = DigestAlgorithm.SHA256, wireFormat = None):
        if isinstance(arg1, Name):
            keyName = arg1
            if wireFormat == None:
                # Don't use a default argument since getDefaultWireFormat can change.
                wireFormat = WireFormat.getDefaultWireFormat()

            self._certificate = SafeBag._makeSelfSignedCertificate(
              keyName, privateKeyBag, publicKeyEncoding, password,
              digestAlgorithm, wireFormat)
            self._privateKeyBag = privateKeyBag
        elif isinstance(arg1, Data):
            # The certificate is supplied.
            self._certificate = Data(arg1)
            self._privateKeyBag = privateKeyBag
        else:
            # Assume the first argument is the encoded SafeBag.
            self.wireDecode(arg1)

    def getCertificate(self):
        """
        Get the certificate data packet.

        :return: The certificate as a Data packet. If you need to process it as
          a certificate object then you must create a new CertificateV2(data).
        :rtype: Data
        """
        return self._certificate

    def getPrivateKeyBag(self):
        """
        Get the encoded private key.

        :return: The encoded private key. If encrypted, this is a PKCS #8
          EncryptedPrivateKeyInfo. If not encrypted, this is an unencrypted PKCS
          #8 PrivateKeyInfo.
        :rtype: Blob
        """
        return self._privateKeyBag

    def wireDecode(self, input):
        """
        Decode the input as an NDN-TLV SafeBag and update this object.

        :param input: The array with the bytes to decode.
        :type input: A Blob or an array type with int elements
        """
        if isinstance(input, Blob):
          input = input.buf()

        # Decode directly as TLV. We don't support the WireFormat abstraction
        # because this isn't meant to go directly on the wire.
        decoder = TlvDecoder(input)
        endOffset = decoder.readNestedTlvsStart(Tlv.SafeBag_SafeBag)

        # Get the bytes of the certificate and decode.
        certificateBeginOffset = decoder.getOffset()
        certificateEndOffset = decoder.readNestedTlvsStart(Tlv.Data)
        decoder.seek(certificateEndOffset)
        self._certificate = Data()
        self._certificate.wireDecode(
          decoder.getSlice(certificateBeginOffset, certificateEndOffset),
          TlvWireFormat.get())

        self._privateKeyBag = Blob(
          decoder.readBlobTlv(Tlv.SafeBag_EncryptedKeyBag), True)

        decoder.finishNestedTlvs(endOffset)

    def wireEncode(self, wireFormat = None):
        """
        Encode this as an NDN-TLV SafeBag.

        :return: The encoded byte array as a Blob.
        :rtype: Blob
        """
        # Encode directly as TLV. We don't support the WireFormat abstraction
        # because this isn't meant to go directly on the wire.
        encoder = TlvEncoder(256)
        saveLength = len(encoder)

        # Encode backwards.
        encoder.writeBlobTlv(
          Tlv.SafeBag_EncryptedKeyBag, self._privateKeyBag.buf())
        # Add the entire Data packet encoding as is.
        encoder.writeBuffer(
          self._certificate.wireEncode(TlvWireFormat.get()).buf())

        encoder.writeTypeAndLength(
          Tlv.SafeBag_SafeBag, len(encoder) - saveLength)

        return Blob(encoder.getOutput(), False)

    @staticmethod
    def _makeSelfSignedCertificate(
      keyName, privateKeyBag, publicKeyEncoding, password, digestAlgorithm,
      wireFormat):
        certificate = CertificateV2()

        # Set the name.
        now = Common.getNowMilliseconds()
        certificateName = Name(keyName)
        certificateName.append("self").appendVersion(int(now))
        certificate.setName(certificateName)

        # Set the MetaInfo.
        certificate.getMetaInfo().setType(ContentType.KEY)
        # Set a one-hour freshness period.
        certificate.getMetaInfo().setFreshnessPeriod(3600 * 1000.0)

        # Set the content.
        publicKey = PublicKey(publicKeyEncoding)
        certificate.setContent(publicKey.getKeyDer())

        # Create a temporary in-memory Tpm and import the private key.
        tpm = Tpm("", "", TpmBackEndMemory())
        tpm._importPrivateKey(keyName, privateKeyBag.toBytes(), password)

        # Set the signature info.
        if publicKey.getKeyType() == KeyType.RSA:
            certificate.setSignature(Sha256WithRsaSignature())
        elif publicKey.getKeyType() == KeyType.EC:
            certificate.setSignature(Sha256WithEcdsaSignature())
        else:
            raise ValueError("Unsupported key type")
        signatureInfo = certificate.getSignature()
        KeyLocator.getFromSignature(signatureInfo).setType(KeyLocatorType.KEYNAME)
        KeyLocator.getFromSignature(signatureInfo).setKeyName(keyName)

        # Set a 20-year validity period.
        ValidityPeriod.getFromSignature(signatureInfo).setPeriod(
          now, now + 20 * 365 * 24 * 3600 * 1000.0)

        # Encode once to get the signed portion.
        encoding = certificate.wireEncode(wireFormat)
        signatureBytes = tpm.sign(encoding.toSignedBytes(), keyName,
          digestAlgorithm)
        signatureInfo.setSignature(signatureBytes)

        # Encode again to include the signature.
        certificate.wireEncode(wireFormat)

        return certificate
Esempio n. 9
0
class SafeBag(object):
    """
    There are three forms of the SafeBag constructor:
    SafeBag(certificate, privateKeyBag) - Create a SafeBag with the given
    certificate and private key.
    SafeBag(keyName, privateKeyBag, publicKeyEncoding [, password,
    digestAlgorithm, wireFormat]) - Create a SafeBag with given private key
    and a new self-signed certificate for the given public key.
    SafeBag(input) - Create a SafeBag by decoding the input as an NDN-TLV SafeBag.

    :param Data certificate: The certificate data packet (used only for
      SafeBag(certificate, privateKeyBag)). This copies the object.
    :param Blob privateKeyBag: The encoded private key. If encrypted, this is a
      PKCS #8 EncryptedPrivateKeyInfo. If not encrypted, this is an unencrypted
      PKCS #8 PrivateKeyInfo.
    :param password: (optional) The password for decrypting the private key in
      order to sign the self-signed certificate, which should have characters in 
      the range of 1 to 127. If the password is supplied, use it to decrypt the
      PKCS #8 EncryptedPrivateKeyInfo. If the password is omitted or None,
      privateKeyBag is an unencrypted PKCS #8 PrivateKeyInfo.
    :type password: an array which implements the buffer protocol
    :param int digestAlgorithm: (optional) The digest algorithm for signing the
      self-signed certificate. If omitted, use DigestAlgorithm.SHA256 .
    :type digestAlgorithm: int from the DigestAlgorithm enum
    :param WireFormat wireFormat: (optional) A WireFormat object used to encode
      the self-signed certificate in order to sign it. If omitted, use
      WireFormat.getDefaultWireFormat().
    :param input: The array with the bytes to decode.
    :type input: A Blob or an array type with int elements
    """
    def __init__(self,
                 arg1,
                 privateKeyBag=None,
                 publicKeyEncoding=None,
                 password=None,
                 digestAlgorithm=DigestAlgorithm.SHA256,
                 wireFormat=None):
        if isinstance(arg1, Name):
            keyName = arg1
            if wireFormat == None:
                # Don't use a default argument since getDefaultWireFormat can change.
                wireFormat = WireFormat.getDefaultWireFormat()

            self._certificate = SafeBag._makeSelfSignedCertificate(
                keyName, privateKeyBag, publicKeyEncoding, password,
                digestAlgorithm, wireFormat)
            self._privateKeyBag = privateKeyBag
        elif isinstance(arg1, Data):
            # The certificate is supplied.
            self._certificate = Data(arg1)
            self._privateKeyBag = privateKeyBag
        else:
            # Assume the first argument is the encoded SafeBag.
            self.wireDecode(arg1)

    def getCertificate(self):
        """
        Get the certificate data packet.

        :return: The certificate as a Data packet. If you need to process it as
          a certificate object then you must create a new CertificateV2(data).
        :rtype: Data
        """
        return self._certificate

    def getPrivateKeyBag(self):
        """
        Get the encoded private key.

        :return: The encoded private key. If encrypted, this is a PKCS #8
          EncryptedPrivateKeyInfo. If not encrypted, this is an unencrypted PKCS
          #8 PrivateKeyInfo.
        :rtype: Blob
        """
        return self._privateKeyBag

    def wireDecode(self, input):
        """
        Decode the input as an NDN-TLV SafeBag and update this object.

        :param input: The array with the bytes to decode.
        :type input: A Blob or an array type with int elements
        """
        if isinstance(input, Blob):
            input = input.buf()

        # Decode directly as TLV. We don't support the WireFormat abstraction
        # because this isn't meant to go directly on the wire.
        decoder = TlvDecoder(input)
        endOffset = decoder.readNestedTlvsStart(Tlv.SafeBag_SafeBag)

        # Get the bytes of the certificate and decode.
        certificateBeginOffset = decoder.getOffset()
        certificateEndOffset = decoder.readNestedTlvsStart(Tlv.Data)
        decoder.seek(certificateEndOffset)
        self._certificate = Data()
        self._certificate.wireDecode(
            decoder.getSlice(certificateBeginOffset, certificateEndOffset),
            TlvWireFormat.get())

        self._privateKeyBag = Blob(
            decoder.readBlobTlv(Tlv.SafeBag_EncryptedKeyBag), True)

        decoder.finishNestedTlvs(endOffset)

    def wireEncode(self, wireFormat=None):
        """
        Encode this as an NDN-TLV SafeBag.

        :return: The encoded byte array as a Blob.
        :rtype: Blob
        """
        # Encode directly as TLV. We don't support the WireFormat abstraction
        # because this isn't meant to go directly on the wire.
        encoder = TlvEncoder(256)
        saveLength = len(encoder)

        # Encode backwards.
        encoder.writeBlobTlv(Tlv.SafeBag_EncryptedKeyBag,
                             self._privateKeyBag.buf())
        # Add the entire Data packet encoding as is.
        encoder.writeBuffer(
            self._certificate.wireEncode(TlvWireFormat.get()).buf())

        encoder.writeTypeAndLength(Tlv.SafeBag_SafeBag,
                                   len(encoder) - saveLength)

        return Blob(encoder.getOutput(), False)

    @staticmethod
    def _makeSelfSignedCertificate(keyName, privateKeyBag, publicKeyEncoding,
                                   password, digestAlgorithm, wireFormat):
        certificate = CertificateV2()

        # Set the name.
        now = Common.getNowMilliseconds()
        certificateName = Name(keyName)
        certificateName.append("self").appendVersion(int(now))
        certificate.setName(certificateName)

        # Set the MetaInfo.
        certificate.getMetaInfo().setType(ContentType.KEY)
        # Set a one-hour freshness period.
        certificate.getMetaInfo().setFreshnessPeriod(3600 * 1000.0)

        # Set the content.
        publicKey = PublicKey(publicKeyEncoding)
        certificate.setContent(publicKey.getKeyDer())

        # Create a temporary in-memory Tpm and import the private key.
        tpm = Tpm("", "", TpmBackEndMemory())
        tpm._importPrivateKey(keyName, privateKeyBag.toBytes(), password)

        # Set the signature info.
        if publicKey.getKeyType() == KeyType.RSA:
            certificate.setSignature(Sha256WithRsaSignature())
        elif publicKey.getKeyType() == KeyType.EC:
            certificate.setSignature(Sha256WithEcdsaSignature())
        else:
            raise ValueError("Unsupported key type")
        signatureInfo = certificate.getSignature()
        KeyLocator.getFromSignature(signatureInfo).setType(
            KeyLocatorType.KEYNAME)
        KeyLocator.getFromSignature(signatureInfo).setKeyName(keyName)

        # Set a 20-year validity period.
        ValidityPeriod.getFromSignature(signatureInfo).setPeriod(
            now, now + 20 * 365 * 24 * 3600 * 1000.0)

        # Encode once to get the signed portion.
        encoding = certificate.wireEncode(wireFormat)
        signatureBytes = tpm.sign(encoding.toSignedBytes(), keyName,
                                  digestAlgorithm)
        signatureInfo.setSignature(signatureBytes)

        # Encode again to include the signature.
        certificate.wireEncode(wireFormat)

        return certificate
Esempio n. 10
0
    class Component(object):
        """
        Create a new Name.Component.

        :param value: (optional) If value is already a Blob or Name.Component,
          then take another pointer to the value.  Otherwise, create a new
          Blob with a copy of the value.  If omitted, create an empty component.
        :type value: Blob or Name.Component or value for Blob constructor
        """
        def __init__(self, value = None):
            if type(value) is Name.Component:
                # Use the existing Blob in the other Component.
                self._value = value._value
            elif value == None:
                self._value = Blob([])
            else:
                # Blob will make a copy.
                self._value = value if isinstance(value, Blob) else Blob(value)

        def getValue(self):
            """
            Get the value of the component.

            :return: The component value.
            :rtype: Blob
            """
            return self._value

        def toEscapedString(self, result = None):
            """
            Convert this component to a string, escaping characters according
            to the NDN URI Scheme. This also adds "..." to a value with zero or
            more ".".

            :param BytesIO result: (optional) The BytesIO stream to write to.
              If omitted, return a str with the result.
            :return: The result as a string (only if result is omitted).
            :rtype: str
            """
            if result == None:
                return Name.toEscapedString(self._value.buf())
            else:
                Name.toEscapedString(self._value.buf(), result)

        def toNumber(self):
            """
            Interpret this name component as a network-ordered number and return
            an integer.

            :return: The integer number.
            :rtype: int
            """
            result = 0
            for i in range(self._value.size()):
                result *= 256
                result += self._value.buf()[i]
            return result

        def toNumberWithMarker(self, marker):
            """
            Interpret this name component as a network-ordered number with a
            marker and return an integer.

            :param int marker: The required first byte of the component.
            :return: The integer number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component does not
              equal the marker.
            """
            if self._value.size() <= 0 or self._value.buf()[0] != marker:
                raise RuntimeError(
                       "Name component does not begin with the expected marker")

            result = 0
            for i in range(1, self._value.size()):
                result *= 256
                result += self._value.buf()[i]
            return result

        def toSegment(self):
            """
            Interpret this name component as a segment number according to NDN
            naming conventions for "Segment number" (marker 0x00).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer segment number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0x00)

        def toSegmentOffset(self):
            """
            Interpret this name component as a segment byte offset according to
            NDN naming conventions for segment "Byte offset" (marker 0xFB).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer segment byte offset.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFB)

        def toVersion(self):
            """
            Interpret this name component as a version number  according to NDN
            naming conventions for "Versioning" (marker 0xFD). Note that this
            returns the exact number from the component without converting it to
            a time representation.
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer version number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFD)

        def toTimestamp(self):
            """
            Interpret this name component as a timestamp  according to NDN naming
            conventions for "Timestamp" (marker 0xFC).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The number of microseconds since the UNIX epoch (Thursday,
              1 January 1970) not counting leap seconds.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFC)

        def toSequenceNumber(self):
            """
            Interpret this name component as a sequence number according to NDN
            naming conventions for "Sequencing" (marker 0xFE).
            http://named-data.net/doc/tech-memos/naming-conventions.pdf

            :return: The integer sequence number.
            :rtype: int
            :raises RuntimeError: If the first byte of the component is not the
              expected marker.
            """
            return self.toNumberWithMarker(0xFE)

        def equals(self, other):
            """
            Check if this is the same component as other.

            :param Name.Component other: The other Component to compare with.
            :return: True if the components are equal, otherwise False.
            :rtype: bool
            """
            return self._value.equals(other._value)

        def compare(self, other):
            """
            Compare this to the other Component using NDN canonical ordering.

            :param Name.Component other: The other Component to compare with.
            :return: 0 If they compare equal, -1 if self comes before other in
              the canonical ordering, or 1 if self comes after other in the
              canonical ordering.
            :rtype: int
            :see: http://named-data.net/doc/0.2/technical/CanonicalOrder.html
            """
            if self._value.size() < other._value.size():
                return -1
            if self._value.size() > other._value.size():
                return 1

            # The components are equal length. Just do a byte compare.
            return self._value.compare(other._value)

        @staticmethod
        def fromNumber(number):
            """
            Create a component whose value is the nonNegativeInteger encoding of
            the number.

            :param int number: The number to be encoded.
            :return: The component value.
            :rtype: Name.Component
            """
            encoder = TlvEncoder(8)
            encoder.writeNonNegativeInteger(number)
            return Name.Component(Blob(encoder.getOutput(), False))

        @staticmethod
        def fromNumberWithMarker(number, marker):
            """
            Create a component whose value is the marker appended with the
            nonNegativeInteger encoding of the number.

            :param int number: The number to be encoded.
            :param int marker: The marker to use as the first byte of the
              component.
            :return: The component value.
            :rtype: Name.Component
            """
            encoder = TlvEncoder(9)
            # Encode backwards.
            encoder.writeNonNegativeInteger(number)
            encoder.writeNonNegativeInteger(marker)
            return Name.Component(Blob(encoder.getOutput(), False))

        # Python operators

        def __eq__(self, other):
            return type(other) is Name.Component and self.equals(other)

        def __ne__(self, other):
            return not self == other

        def __le__(self, other):
            return self.compare(other) <= 0

        def __lt__(self, other):
            return self.compare(other) < 0

        def __ge__(self, other):
            return self.compare(other) >= 0

        def __gt__(self, other):
            return self.compare(other) > 0

        def __len__(self):
            return self._value.size()

        def __str__(self):
            return self.toEscapedString()