예제 #1
0
    def __call__(self, pyObject, asn1Spec, **options):

        if LOG:
            debug.scope.push(type(pyObject).__name__)
            LOG('decoder called at scope %s, working with type %s' % (debug.scope, type(pyObject).__name__))

        if asn1Spec is None or not isinstance(asn1Spec, base.Asn1Item):
            raise error.PyAsn1Error('asn1Spec is not valid (should be an instance of an ASN.1 Item, not %s)' % asn1Spec.__class__.__name__)

        try:
            valueDecoder = self.__typeMap[asn1Spec.typeId]

        except KeyError:
            # use base type for codec lookup to recover untagged types
            baseTagSet = tag.TagSet(asn1Spec.tagSet.baseTag, asn1Spec.tagSet.baseTag)

            try:
                valueDecoder = self.__tagMap[baseTagSet]
            except KeyError:
                raise error.PyAsn1Error('Unknown ASN.1 tag %s' % asn1Spec.tagSet)

        if LOG:
            LOG('calling decoder %s on Python type %s <%s>' % (type(valueDecoder).__name__, type(pyObject).__name__, repr(pyObject)))

        value = valueDecoder(pyObject, asn1Spec, self, **options)

        if LOG:
            LOG('decoder %s produced ASN.1 type %s <%s>' % (type(valueDecoder).__name__, type(value).__name__, repr(value)))
            debug.scope.pop()

        return value
예제 #2
0
    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        # Encoding constraints:
        # - minutes are mandatory, seconds are optional
        # - sub-seconds must NOT be zero
        # - no hanging fraction dot
        # - time in UTC (Z)
        # - only dot is allowed for fractions

        if asn1Spec is not None:
            value = asn1Spec.clone(value)

        octets = value.asOctets()

        if not self.minLength < len(octets) < self.maxLength:
            raise error.PyAsn1Error('Length constraint violated: %r' % value)

        if self.pluschar in octets or self.minuschar in octets:
            raise error.PyAsn1Error('Must be UTC time: %r' % octets)

        if octets[-1] != self.zchar:
            raise error.PyAsn1Error('Missing "Z" time zone specifier: %r' %
                                    octets)

        if self.commachar in octets:
            raise error.PyAsn1Error('Comma in fractions disallowed: %r' %
                                    value)

        options.update(maxChunkSize=1000)

        return encoder.OctetStringEncoder.encodeValue(self, value, asn1Spec,
                                                      encodeFun, **options)
예제 #3
0
    def __call__(self, value, **options):
        if not isinstance(value, base.Asn1Item):
            raise error.PyAsn1Error('value is not valid (should be an instance of an ASN.1 Item)')

        if LOG:
            debug.scope.push(type(value).__name__)
            LOG('encoder called for type %s <%s>' % (type(value).__name__, value.prettyPrint()))

        tagSet = value.tagSet

        try:
            concreteEncoder = self.__typeMap[value.typeId]

        except KeyError:
            # use base type for codec lookup to recover untagged types
            baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag)

            try:
                concreteEncoder = self.__tagMap[baseTagSet]

            except KeyError:
                raise error.PyAsn1Error('No encoder for %s' % (value,))

        if LOG:
            LOG('using value codec %s chosen by %s' % (concreteEncoder.__class__.__name__, tagSet))

        pyObject = concreteEncoder.encode(value, self, **options)

        if LOG:
            LOG('encoder %s produced: %s' % (type(concreteEncoder).__name__, repr(pyObject)))
            debug.scope.pop()

        return pyObject
예제 #4
0
    def __call__(self, value, asn1Spec=None, **options):
        try:
            if asn1Spec is None:
                typeId = value.typeId
            else:
                typeId = asn1Spec.typeId

        except AttributeError:
            raise error.PyAsn1Error('Value %r is not ASN.1 type instance '
                                    'and "asn1Spec" not given' % (value, ))

        if LOG:
            LOG('encoder called in %sdef mode, chunk size %s for '
                'type %s, value:\n%s' %
                (not options.get('defMode', True) and 'in' or '',
                 options.get('maxChunkSize',
                             0), asn1Spec is None and value.prettyPrintType()
                 or asn1Spec.prettyPrintType(), value))

        if self.fixedDefLengthMode is not None:
            options.update(defMode=self.fixedDefLengthMode)

        if self.fixedChunkSize is not None:
            options.update(maxChunkSize=self.fixedChunkSize)

        try:
            concreteEncoder = self.__typeMap[typeId]

            if LOG:
                LOG('using value codec %s chosen by type ID %s' %
                    (concreteEncoder.__class__.__name__, typeId))

        except KeyError:
            if asn1Spec is None:
                tagSet = value.tagSet
            else:
                tagSet = asn1Spec.tagSet

            # use base type for codec lookup to recover untagged types
            baseTagSet = tag.TagSet(tagSet.baseTag, tagSet.baseTag)

            try:
                concreteEncoder = self.__tagMap[baseTagSet]

            except KeyError:
                raise error.PyAsn1Error('No encoder for %r (%s)' %
                                        (value, tagSet))

            if LOG:
                LOG('using value codec %s chosen by tagSet %s' %
                    (concreteEncoder.__class__.__name__, tagSet))

        substrate = concreteEncoder.encode(value, asn1Spec, self, **options)

        if LOG:
            LOG('codec %s built %s octets of substrate: %s\nencoder completed'
                % (concreteEncoder, len(substrate), debug.hexdump(substrate)))

        return substrate
예제 #5
0
    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if asn1Spec is not None:
            value = asn1Spec.clone(value)

        oid = value.asTuple()

        # Build the first pair
        try:
            first = oid[0]
            second = oid[1]

        except IndexError:
            raise error.PyAsn1Error('Short OID %s' % (value, ))

        if 0 <= second <= 39:
            if first == 1:
                oid = (second + 40, ) + oid[2:]
            elif first == 0:
                oid = (second, ) + oid[2:]
            elif first == 2:
                oid = (second + 80, ) + oid[2:]
            else:
                raise error.PyAsn1Error('Impossible first/second arcs at %s' %
                                        (value, ))

        elif first == 2:
            oid = (second + 80, ) + oid[2:]

        else:
            raise error.PyAsn1Error('Impossible first/second arcs at %s' %
                                    (value, ))

        octets = ()

        # Cycle through subIds
        for subOid in oid:
            if 0 <= subOid <= 127:
                # Optimize for the common case
                octets += (subOid, )

            elif subOid > 127:
                # Pack large Sub-Object IDs
                res = (subOid & 0x7f, )
                subOid >>= 7

                while subOid:
                    res = (0x80 | (subOid & 0x7f), ) + res
                    subOid >>= 7

                # Add packed Sub-Object ID to resulted Object ID
                octets += res

            else:
                raise error.PyAsn1Error('Negative OID arc %s at %s' %
                                        (subOid, value))

        return octets, False, False
예제 #6
0
    def _componentSortKey(componentAndType):
        """Sort SET components by tag

        Sort depending on the actual Choice value (dynamic sort)
        """
        component, asn1Spec = componentAndType

        if asn1Spec is None:
            compType = component
        else:
            compType = asn1Spec

        if compType.typeId == univ.Choice.typeId and not compType.tagSet:
            if asn1Spec is None:
                return component.getComponent().tagSet
            else:
                # TODO: move out of sorting key function
                names = [namedType.name for namedType in asn1Spec.componentType.namedTypes
                         if namedType.name in component]
                if len(names) != 1:
                    raise error.PyAsn1Error(
                        '%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', component))

                # TODO: support nested CHOICE ordering
                return asn1Spec[names[0]].tagSet

        else:
            return compType.tagSet
예제 #7
0
    def getValues(self, *names):
        try:
            return [self.__names[name] for name in names]

        except KeyError:
            raise error.PyAsn1Error('Unknown bit identifier(s): %s' %
                                    (set(names).difference(self.__names), ))
예제 #8
0
    def getPositionNearType(self, tagSet, idx):
        """Return the closest field position where given ASN.1 type is allowed.

        Some ASN.1 serialisation allow for skipping optional and defaulted fields.
        Some constructed ASN.1 types allow reordering of the fields. When recovering
        such objects it may be important to know at which field position, in field set,
        given *tagSet* is allowed at or past *idx* position.

        Parameters
        ----------
        tagSet: :class:`~pyasn1.type.tag.TagSet`
           ASN.1 type which field position to look up

        idx: :py:class:`int`
            Field position at or past which to perform ASN.1 type look up

        Returns
        -------
        : :py:class:`int`
            Field position in fields set

        Raises
        ------
        : :class:`~pyasn1.error.PyAsn1Error`
            If *tagSet* is not present or not unique within callee *NamedTypes*
            or *idx* is out of fields range
        """
        try:
            return idx + self.__ambiguousTypes[idx].getPositionByType(tagSet)

        except KeyError:
            raise error.PyAsn1Error('Type position out of range')
예제 #9
0
 def __bytes__(self):
     try:
         return self._value.encode(self.encoding)
     except UnicodeEncodeError:
         raise error.PyAsn1Error(
             "Can't encode string '%s' with codec %s" %
             (self._value, self.encoding))
예제 #10
0
    def getTagMapNearPosition(self, idx):
        """Return ASN.1 types that are allowed at or past given field position.

        Some ASN.1 serialisation allow for skipping optional and defaulted fields.
        Some constructed ASN.1 types allow reordering of the fields. When recovering
        such objects it may be important to know which types can possibly be
        present at any given position in the field sets.

        Parameters
        ----------
        idx: :py:class:`int`
            Field index

        Returns
        -------
        : :class:`~pyasn1.type.tagmap.TagMap`
            Map if ASN.1 types allowed at given field position

        Raises
        ------
        : :class:`~pyasn1.error.PyAsn1Error`
            If given position is out of fields range
        """
        try:
            return self.__ambiguousTypes[idx].tagMap

        except KeyError:
            raise error.PyAsn1Error('Type position out of range')
예제 #11
0
 def __init__(self, tagClass, tagFormat, tagId):
     if tagId < 0:
         raise error.PyAsn1Error('Negative tag ID (%s) not allowed' % tagId)
     self.__tagClass = tagClass
     self.__tagFormat = tagFormat
     self.__tagId = tagId
     self.__tagClassId = tagClass, tagId
     self.__hash = hash(self.__tagClassId)
예제 #12
0
        def __str__(self):
            try:
                # `str` is Py2 text representation
                return self._value.encode(self.encoding)

            except UnicodeEncodeError:
                raise error.PyAsn1Error(
                    "Can't encode string '%s' with codec %s" %
                    (self._value, self.encoding))
예제 #13
0
 def __getitem__(self, tagSet):
     try:
         return self.__presentTypes[tagSet]
     except KeyError:
         if self.__defaultType is None:
             raise KeyError()
         elif tagSet in self.__skipTypes:
             raise error.PyAsn1Error('Key in negative map')
         else:
             return self.__defaultType
예제 #14
0
 def valueDecoder(self,
                  substrate,
                  asn1Spec,
                  tagSet=None,
                  length=None,
                  state=None,
                  decodeFun=None,
                  substrateFun=None,
                  **options):
     head, tail = substrate[:length], substrate[length:]
     if not head or length != 1:
         raise error.PyAsn1Error('Not single-octet Boolean payload')
     byte = oct2int(head[0])
     # CER/DER specifies encoding of TRUE as 0xFF and FALSE as 0x0, while
     # BER allows any non-zero value as TRUE; cf. sections 8.2.2. and 11.1
     # in https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
     if byte == 0xff:
         value = 1
     elif byte == 0x00:
         value = 0
     else:
         raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte)
     return self._createComponent(asn1Spec, tagSet, value, **options), tail
예제 #15
0
    def __init__(self, *args, **kwargs):
        self.__names = {}
        self.__numbers = {}

        anonymousNames = []

        for namedValue in args:
            if isinstance(namedValue, (tuple, list)):
                try:
                    name, number = namedValue

                except ValueError:
                    raise error.PyAsn1Error(
                        'Not a proper attribute-value pair %r' %
                        (namedValue, ))

            else:
                anonymousNames.append(namedValue)
                continue

            if name in self.__names:
                raise error.PyAsn1Error('Duplicate name %s' % (name, ))

            if number in self.__numbers:
                raise error.PyAsn1Error('Duplicate number  %s=%s' %
                                        (name, number))

            self.__names[name] = number
            self.__numbers[number] = name

        for name, number in kwargs.items():
            if name in self.__names:
                raise error.PyAsn1Error('Duplicate name %s' % (name, ))

            if number in self.__numbers:
                raise error.PyAsn1Error('Duplicate number  %s=%s' %
                                        (name, number))

            self.__names[name] = number
            self.__numbers[number] = name

        if anonymousNames:

            number = self.__numbers and max(self.__numbers) + 1 or 0

            for name in anonymousNames:

                if name in self.__names:
                    raise error.PyAsn1Error('Duplicate name %s' % (name, ))

                self.__names[name] = number
                self.__numbers[number] = name

                number += 1
예제 #16
0
        def prettyIn(self, value):
            try:
                if isinstance(value, unicode):
                    return value
                elif isinstance(value, str):
                    return value.decode(self.encoding)
                elif isinstance(value, (tuple, list)):
                    return self.prettyIn(''.join([chr(x) for x in value]))
                elif isinstance(value, univ.OctetString):
                    return value.asOctets().decode(self.encoding)
                else:
                    return unicode(value)

            except (UnicodeDecodeError, LookupError):
                raise error.PyAsn1Error(
                    "Can't decode string '%s' with codec %s" %
                    (value, self.encoding))
예제 #17
0
    def encodeLength(self, length, defMode):
        if not defMode and self.supportIndefLenMode:
            return (0x80, )

        if length < 0x80:
            return length,

        else:
            substrate = ()
            while length:
                substrate = (length & 0xff, ) + substrate
                length >>= 8

            substrateLen = len(substrate)

            if substrateLen > 126:
                raise error.PyAsn1Error('Length octets overflow (%d)' %
                                        substrateLen)

            return (0x80 | substrateLen, ) + substrate
예제 #18
0
    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if asn1Spec is None:
            component = value.getComponent()
        else:
            names = [
                namedType.name
                for namedType in asn1Spec.componentType.namedTypes
                if namedType.name in value
            ]
            if len(names) != 1:
                raise error.PyAsn1Error(
                    '%s components for Choice at %r' %
                    (len(names) and 'Multiple ' or 'None ', value))

            name = names[0]

            component = value[name]
            asn1Spec = asn1Spec[name]

        return encodeFun(component, asn1Spec, **options), True, True
예제 #19
0
    def getPositionByName(self, name):
        """Return field position by filed name.

        Parameters
        ----------
        name: :py:class:`str`
            Field name

        Returns
        -------
        : :py:class:`int`
            Field position in fields set

        Raises
        ------
        : :class:`~pyasn1.error.PyAsn1Error`
            If *name* is not present or not unique within callee *NamedTypes*
        """
        try:
            return self.__nameToPosMap[name]

        except KeyError:
            raise error.PyAsn1Error('Name %s not found' % (name, ))
예제 #20
0
    def getNameByPosition(self, idx):
        """Return field name by its position in fields set.

        Parameters
        ----------
        idx: :py:class:`idx`
            Field index

        Returns
        -------
        : :py:class:`str`
            Field name

        Raises
        ------
        : :class:`~pyasn1.error.PyAsn1Error`
            If given field name is not present in callee *NamedTypes*
        """
        try:
            return self.__namedTypes[idx].name

        except IndexError:
            raise error.PyAsn1Error('Type position out of range')
예제 #21
0
    def getPositionByType(self, tagSet):
        """Return field position by its ASN.1 type.

        Parameters
        ----------
        tagSet: :class:`~pysnmp.type.tag.TagSet`
            ASN.1 tag set distinguishing one ASN.1 type from others.

        Returns
        -------
        : :py:class:`int`
            ASN.1 type position in fields set

        Raises
        ------
        : :class:`~pyasn1.error.PyAsn1Error`
            If *tagSet* is not present or ASN.1 types are not unique within callee *NamedTypes*
        """
        try:
            return self.__tagToPosMap[tagSet]

        except KeyError:
            raise error.PyAsn1Error('Type %s not found' % (tagSet, ))
예제 #22
0
    def getTypeByPosition(self, idx):
        """Return ASN.1 type object by its position in fields set.

        Parameters
        ----------
        idx: :py:class:`int`
            Field index

        Returns
        -------
        :
            ASN.1 type

        Raises
        ------
        : :class:`~pyasn1.error.PyAsn1Error`
            If given position is out of fields range
        """
        try:
            return self.__namedTypes[idx].asn1Object

        except IndexError:
            raise error.PyAsn1Error('Type position out of range')
예제 #23
0
    def tagExplicitly(self, superTag):
        """Return explicitly tagged *TagSet*

        Create a new *TagSet* representing callee *TagSet* explicitly tagged
        with passed tag(s). With explicit tagging mode, new tags are appended
        to existing tag(s).

        Parameters
        ----------
        superTag: :class:`~pyasn1.type.tag.Tag`
            *Tag* object to tag this *TagSet*

        Returns
        -------
        : :class:`~pyasn1.type.tag.TagSet`
            New *TagSet* object
        """
        if superTag.tagClass == tagClassUniversal:
            raise error.PyAsn1Error("Can't tag with UNIVERSAL class tag")
        if superTag.tagFormat != tagFormatConstructed:
            superTag = Tag(superTag.tagClass, tagFormatConstructed,
                           superTag.tagId)
        return self + superTag
예제 #24
0
    def __getattr__(self, attr):
        if attr in self.skipMethods:
            raise AttributeError('Attribute %s not present' % attr)

        raise error.PyAsn1Error(
            'Attempted "%s" operation on ASN.1 schema object' % attr)
예제 #25
0
 def encode(self, value, encodeFun, **options):
     raise error.PyAsn1Error('Not implemented')
예제 #26
0
    def __setattr__(self, name, value):
        if name[0] != '_' and name in self._readOnly:
            raise error.PyAsn1Error('read-only instance attribute "%s"' % name)

        self.__dict__[name] = value
예제 #27
0
    def encodeValue(self, value, asn1Spec, encodeFun, **options):

        substrate = null

        comps = []
        compsMap = {}

        if asn1Spec is None:
            # instance of ASN.1 schema
            value.verifySizeSpec()

            namedTypes = value.componentType

            for idx, component in enumerate(value.values()):
                if namedTypes:
                    namedType = namedTypes[idx]

                    if namedType.isOptional and not component.isValue:
                        continue

                    if namedType.isDefaulted and component == namedType.asn1Object:
                        continue

                    compsMap[id(component)] = namedType

                else:
                    compsMap[id(component)] = None

                comps.append((component, asn1Spec))

        else:
            # bare Python value + ASN.1 schema
            for idx, namedType in enumerate(asn1Spec.componentType.namedTypes):

                try:
                    component = value[namedType.name]

                except KeyError:
                    raise error.PyAsn1Error(
                        'Component name "%s" not found in %r' %
                        (namedType.name, value))

                if namedType.isOptional and namedType.name not in value:
                    continue

                if namedType.isDefaulted and component == namedType.asn1Object:
                    continue

                compsMap[id(component)] = namedType
                comps.append((component, asn1Spec[idx]))

        for comp, compType in sorted(comps, key=self._componentSortKey):
            namedType = compsMap[id(comp)]

            if namedType:
                options.update(ifNotEmpty=namedType.isOptional)

            chunk = encodeFun(comp, compType, **options)

            # wrap open type blob if needed
            if namedType and namedType.openType:
                wrapType = namedType.asn1Object
                if wrapType.tagSet and not wrapType.isSameTypeWith(comp):
                    chunk = encodeFun(chunk, wrapType, **options)

            substrate += chunk

        return substrate, True, True
예제 #28
0
 def getComponentByPosition(self, idx):
     raise error.PyAsn1Error('Method not implemented')
예제 #29
0
 def setComponentByPosition(self, idx, value, verifyConstraints=True):
     raise error.PyAsn1Error('Method not implemented')
예제 #30
0
 def __getitem__(self, item):
     raise error.PyAsn1Error(self.__errorMsg)