Beispiel #1
0
    def encodeValue(self, value, asn1Spec, encodeFun, **options):

        if asn1Spec is None:
            substrate = value.asOctets()

        elif not isOctetsType(value):
            substrate = asn1Spec.clone(value).asOctets()

        else:
            substrate = value

        maxChunkSize = options.get('maxChunkSize', 0)

        if not maxChunkSize or len(substrate) <= maxChunkSize:
            return substrate, False, True

        if LOG:
            LOG('encoding into up to %s-octet chunks' % maxChunkSize)

        # strip off explicit tags for inner chunks

        if asn1Spec is None:
            baseTag = value.tagSet.baseTag

            # strip off explicit tags
            if baseTag:
                tagSet = tag.TagSet(baseTag, baseTag)

            else:
                tagSet = tag.TagSet()

            asn1Spec = value.clone(tagSet=tagSet)

        elif not isOctetsType(value):
            baseTag = asn1Spec.tagSet.baseTag

            # strip off explicit tags
            if baseTag:
                tagSet = tag.TagSet(baseTag, baseTag)

            else:
                tagSet = tag.TagSet()

            asn1Spec = asn1Spec.clone(tagSet=tagSet)

        pos = 0
        substrate = null

        while True:
            chunk = value[pos:pos + maxChunkSize]
            if not chunk:
                break

            substrate += encodeFun(chunk, asn1Spec, **options)
            pos += maxChunkSize

        return substrate, True, True
    def encodeValue(self, value, asn1Spec, encodeFun, **options):

        if asn1Spec is None:
            substrate = value.asOctets()

        elif not isOctetsType(value):
            substrate = asn1Spec.clone(value).asOctets()

        else:
            substrate = value

        maxChunkSize = options.get('maxChunkSize', 0)

        if not maxChunkSize or len(substrate) <= maxChunkSize:
            return substrate, False, True

        if LOG:
            LOG('encoding into up to %s-octet chunks' % maxChunkSize)

        # strip off explicit tags for inner chunks

        if asn1Spec is None:
            baseTag = value.tagSet.baseTag

            # strip off explicit tags
            if baseTag:
                tagSet = tag.TagSet(baseTag, baseTag)

            else:
                tagSet = tag.TagSet()

            asn1Spec = value.clone(tagSet=tagSet)

        elif not isOctetsType(value):
            baseTag = asn1Spec.tagSet.baseTag

            # strip off explicit tags
            if baseTag:
                tagSet = tag.TagSet(baseTag, baseTag)

            else:
                tagSet = tag.TagSet()

            asn1Spec = asn1Spec.clone(tagSet=tagSet)

        pos = 0
        substrate = null

        while True:
            chunk = value[pos:pos + maxChunkSize]
            if not chunk:
                break

            substrate += encodeFun(chunk, asn1Spec, **options)
            pos += maxChunkSize

        return substrate, True, True
Beispiel #3
0
    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if asn1Spec is None:
            value = value.asOctets()
        elif not isOctetsType(value):
            value = asn1Spec.clone(value).asOctets()

        return value, not options.get('defMode', True), True
Beispiel #4
0
    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if asn1Spec is None:
            # will strip off explicit tags
            tagSet = value.tagSet
            asn1Spec = value.clone(
                tagSet=tag.TagSet(tagSet.baseTag, tagSet.baseTag))

            value = value.asOctets()

        elif not isOctetsType(value):
            # will strip off explicit tags
            tagSet = asn1Spec.tagSet
            asn1Spec = asn1Spec.clone(
                tagSet=tag.TagSet(tagSet.baseTag, tagSet.baseTag))

            value = asn1Spec.clone(value).asOctets()

        maxChunkSize = options.get('maxChunkSize', 0)
        if not maxChunkSize or len(value) <= maxChunkSize:
            return value, False, True

        else:
            pos = 0
            substrate = null
            while True:
                chunk = value[pos:pos + maxChunkSize]
                if not chunk:
                    break

                substrate += encodeFun(chunk, asn1Spec, **options)
                pos += maxChunkSize

            return substrate, True, True
    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if asn1Spec is None:
            value = value.asOctets()
        elif not isOctetsType(value):
            value = asn1Spec.clone(value).asOctets()

        return value, not options.get('defMode', True), True
Beispiel #6
0
    def evaluateValue(self, oid, tag, value, **context):
        tag, encodingId = self.unpackTag(tag)

        try:
            if encodingId == 'e':

                value = self.evaluateRawString(value)

                return oid, tag, self.grammar.TAG_MAP[tag](value)

            elif encodingId == 'x':
                if octets.isOctetsType(value):
                    value = octets.octs2str(value)

                return oid, tag, self.grammar.TAG_MAP[tag](hexValue=value)

            else:
                return oid, tag, self.grammar.TAG_MAP[tag](value)

        except Exception:
            raise error.SnmpsimError(
                'value evaluation error for tag %r, value '
                '%r: %s' % (tag, value, sys.exc_info()[1]))
Beispiel #7
0
    def evaluate_value(self, oid, tag, value, **context):
        tag, encoding_id = self.unpack_tag(tag)

        try:
            if encoding_id == 'e':

                value = self.evaluate_raw_string(value)

                return oid, tag, self.grammar.TAG_MAP[tag](value)

            elif encoding_id == 'x':
                if octets.isOctetsType(value):
                    value = octets.octs2str(value)

                return oid, tag, self.grammar.TAG_MAP[tag](hexValue=value)

            else:
                return oid, tag, self.grammar.TAG_MAP[tag](value)

        except Exception as exc:
            raise error.SnmpsimError(
                'value evaluation error for tag %r, value '
                '%r: %s' % (tag, value, exc))
Beispiel #8
0
    def evaluateValue(self, oid, tag, value, **context):
        tag, encodingId = self.unpackTag(tag)

        try:
            if encodingId == 'e':

                value = self.evaluateRawString(value)

                return oid, tag, self.grammar.TAG_MAP[tag](value)

            elif encodingId == 'x':
                if octets.isOctetsType(value):
                    value = octets.octs2str(value)

                return oid, tag, self.grammar.TAG_MAP[tag](hexValue=value)

            else:
                return oid, tag, self.grammar.TAG_MAP[tag](value)

        except Exception:
            raise error.SnmpsimError(
                'value evaluation error for tag %r, value '
                '%r: %s' % (tag, value, sys.exc_info()[1]))
Beispiel #9
0
    def prettyIn(self, value):  # override asn1 type method
        """Implements DISPLAY-HINT parsing into base SNMP value

        Proper parsing seems impossible due to ambiguities.
        Here we are trying to do our best, but be prepared
        for failures on complicated DISPLAY-HINTs.

        Keep in mind that this parser only works with "text"
        input meaning `unicode` (Py2) or `str` (Py3).
        """
        for base in inspect.getmro(self.__class__):
            if not issubclass(base, TextualConvention) and issubclass(
                    base, Asn1Item):
                break
        else:
            raise SmiError(
                'TEXTUAL-CONVENTION has no underlying SNMP base type')

        if self.displayHint and (
                self.__integer.isSuperTypeOf(self, matchConstraints=False)
                and self.getNamedValues() or self.__unsigned32.isSuperTypeOf(
                    self, matchConstraints=False) or
                self.__timeticks.isSuperTypeOf(self, matchConstraints=False)):
            value = str(value)

            _ = lambda t, f=0: (t, f)
            displayHintType, decimalPrecision = _(*self.displayHint.split('-'))
            if displayHintType == 'x' and (value.startswith('0x')
                                           or value.startswith('-0x')):
                try:
                    if value.startswith('-'):
                        return base.prettyIn(self, -int(value[3:], 16))
                    else:
                        return base.prettyIn(self, int(value[2:], 16))
                except Exception:
                    raise SmiError('integer evaluation error: %s' %
                                   sys.exc_info()[1])
            elif displayHintType == 'd':
                try:
                    return base.prettyIn(
                        self, int(float(value) * 10**int(decimalPrecision)))
                except Exception:
                    raise SmiError('float evaluation error: %s' %
                                   sys.exc_info()[1])
            elif displayHintType == 'o' and (value.startswith('0')
                                             or value.startswith('-0')):
                try:
                    return base.prettyIn(self, int(value, 8))
                except Exception:
                    raise SmiError('octal evaluation error: %s' %
                                   sys.exc_info()[1])
            elif displayHintType == 'b' and (value.startswith('B')
                                             or value.startswith('-B')):
                negative = value.startswith('-')
                if negative:
                    value = value[2:]
                else:
                    value = value[1:]
                value = [x != '0' and 1 or 0 for x in value]
                binValue = 0
                while value:
                    binValue <<= value[0]
                    del value[0]
                return base.prettyIn(self, binValue)
            else:
                raise SmiError('Unsupported numeric type spec "%s" at %s' %
                               (displayHintType, self.__class__.__name__))

        elif self.displayHint and self.__octetString.isSuperTypeOf(
                self, matchConstraints=False):
            numBase = {'x': 16, 'd': 10, 'o': 8}
            numDigits = {
                'x': octets.str2octs(string.hexdigits),
                'o': octets.str2octs(string.octdigits),
                'd': octets.str2octs(string.digits)
            }

            # how do we know if object is initialized with display-hint
            # formatted text? based on "text" input maybe?
            # That boils down to `str` object on Py3 or `unicode` on Py2.
            if octets.isStringType(value) and not octets.isOctetsType(value):
                value = base.prettyIn(self, value)
            else:
                return base.prettyIn(self, value)

            outputValue = octets.str2octs('')
            runningValue = value
            displayHint = self.displayHint

            while runningValue and displayHint:
                # 1 this information is totally lost, just fail explicitly
                if displayHint[0] == '*':
                    raise SmiError('Can\'t parse "*" in DISPLAY-HINT (%s)' %
                                   self.__class__.__name__)

                # 2 this becomes ambiguous when it comes to rendered value
                octetLength = ''
                while displayHint and displayHint[0] in string.digits:
                    octetLength += displayHint[0]
                    displayHint = displayHint[1:]

                # length is mandatory but people ignore that
                if not octetLength:
                    octetLength = len(runningValue)

                try:
                    octetLength = int(octetLength)
                except Exception:
                    raise SmiError('Bad octet length: %s' % octetLength)

                if not displayHint:
                    raise SmiError('Short octet length: %s' % self.displayHint)

                # 3
                displayFormat = displayHint[0]
                displayHint = displayHint[1:]

                # 4 this is the lifesaver -- we could use it as an anchor
                if displayHint and displayHint[
                        0] not in string.digits and displayHint[0] != '*':
                    displaySep = displayHint[0]
                    displayHint = displayHint[1:]
                else:
                    displaySep = ''

                # 5 is probably impossible to support

                if displayFormat in ('a', 't'):
                    outputValue += runningValue[:octetLength]
                elif displayFormat in numBase:
                    if displaySep:
                        guessedOctetLength = runningValue.find(
                            octets.str2octs(displaySep))
                        if guessedOctetLength == -1:
                            guessedOctetLength = len(runningValue)
                    else:
                        for idx in range(len(runningValue)):
                            if runningValue[idx] not in numDigits[
                                    displayFormat]:
                                guessedOctetLength = idx
                                break
                        else:
                            guessedOctetLength = len(runningValue)

                    try:
                        num = int(
                            octets.octs2str(runningValue[:guessedOctetLength]),
                            numBase[displayFormat])
                    except Exception:
                        raise SmiError('Display format eval failure: %s: %s' %
                                       (runningValue[:guessedOctetLength],
                                        sys.exc_info()[1]))

                    num_as_bytes = []
                    if num:
                        while num:
                            num_as_bytes.append(num & 0xFF)
                            num >>= 8
                    else:
                        num_as_bytes = [0]

                    while len(num_as_bytes) < octetLength:
                        num_as_bytes.append(0)

                    num_as_bytes.reverse()

                    outputValue += octets.ints2octs(num_as_bytes)

                    if displaySep:
                        guessedOctetLength += 1

                    octetLength = guessedOctetLength
                else:
                    raise SmiError('Unsupported display format char: %s' %
                                   displayFormat)

                runningValue = runningValue[octetLength:]

                if not displayHint:
                    displayHint = self.displayHint

            return base.prettyIn(self, outputValue)

        else:
            return base.prettyIn(self, value)
Beispiel #10
0
    def __call__(self, substrate, asn1Spec=None, tagSet=None,
                 length=None, state=stDecodeTag, recursiveFlag=1,
                 substrateFun=None, allowEoo=False):
        if debug.logger & debug.flagDecoder:
            debug.logger('decoder called at scope %s with state %d, working with up to %d octets of substrate: %s' % (debug.scope, state, len(substrate), debug.hexdump(substrate)))
        if asn1Spec is not None and not isinstance(asn1Spec, (base.Asn1Item, tagmap.TagMap)):
            raise error.PyAsn1Error('asn1Spec is not valid (should be an instance of an ASN.1 Item, not %s)' % asn1Spec.__class__.__name__)

        fullSubstrate = substrate
        while state != stStop:
            if state == stDecodeTag:
                if not substrate:
                    raise error.SubstrateUnderrunError(
                        'Short octet stream on tag decoding'
                        )
                if not isOctetsType(substrate) and \
                   not isinstance(substrate, univ.OctetString):
                    raise error.PyAsn1Error('Bad octet stream type')
                # Decode tag
                firstOctet = substrate[0]
                substrate = substrate[1:]
                if firstOctet in self.__tagCache:
                    lastTag = self.__tagCache[firstOctet]
                else:
                    t = oct2int(firstOctet)
                    # Look for end-of-octets sentinel
                    if t == 0:
                        if substrate and oct2int(substrate[0]) == 0:
                            if allowEoo and self.supportIndefLength:
                                debug.logger and debug.logger & debug.flagDecoder and debug.logger('end-of-octets sentinel found')
                                value, substrate = eoo.endOfOctets, substrate[1:]
                                state = stStop
                                continue
                            else:
                                raise error.PyAsn1Error('Unexpected end-of-contents sentinel')
                        else:
                            raise error.PyAsn1Error('Zero tag encountered')
                    tagClass = t&0xC0
                    tagFormat = t&0x20
                    tagId = t&0x1F
                    if tagId == 0x1F:
                        tagId = 0
                        while 1:
                            if not substrate:
                                raise error.SubstrateUnderrunError(
                                    'Short octet stream on long tag decoding'
                                    )
                            t = oct2int(substrate[0])
                            tagId = tagId << 7 | (t&0x7F)
                            substrate = substrate[1:]
                            if not t&0x80:
                                break
                    lastTag = tag.Tag(
                        tagClass=tagClass, tagFormat=tagFormat, tagId=tagId
                    )
                    if tagId < 31:
                        # cache short tags
                        self.__tagCache[firstOctet] = lastTag
                if tagSet is None:
                    if firstOctet in self.__tagSetCache:
                        tagSet = self.__tagSetCache[firstOctet]
                    else:
                        # base tag not recovered
                        tagSet = tag.TagSet((), lastTag)
                        if firstOctet in self.__tagCache:
                            self.__tagSetCache[firstOctet] = tagSet
                else:
                    tagSet = lastTag + tagSet
                state = stDecodeLength
                debug.logger and debug.logger & debug.flagDecoder and debug.logger('tag decoded into %s, decoding length' % tagSet)
            if state == stDecodeLength:
                # Decode length
                if not substrate:
                    raise error.SubstrateUnderrunError(
                        'Short octet stream on length decoding'
                    )
                firstOctet  = oct2int(substrate[0])
                if firstOctet == 128:
                    size = 1
                    length = -1
                elif firstOctet < 128:
                    length, size = firstOctet, 1
                else:
                    size = firstOctet & 0x7F
                    # encoded in size bytes
                    length = 0
                    lengthString = substrate[1:size+1]
                    # missing check on maximum size, which shouldn't be a
                    # problem, we can handle more than is possible
                    if len(lengthString) != size:
                        raise error.SubstrateUnderrunError(
                            '%s<%s at %s' %
                            (size, len(lengthString), tagSet)
                            )
                    for char in lengthString:
                        length = (length << 8) | oct2int(char)
                    size += 1
                substrate = substrate[size:]
                if length != -1 and len(substrate) < length:
                    raise error.SubstrateUnderrunError(
                        '%d-octet short' % (length - len(substrate))
                        )
                if length == -1 and not self.supportIndefLength:
                    error.PyAsn1Error('Indefinite length encoding not supported by this codec')
                state = stGetValueDecoder
                debug.logger and debug.logger & debug.flagDecoder and debug.logger('value length decoded into %d, payload substrate is: %s' % (length, debug.hexdump(length == -1 and substrate or substrate[:length])))
            if state == stGetValueDecoder:
                if asn1Spec is None:
                    state = stGetValueDecoderByTag
                else:
                    state = stGetValueDecoderByAsn1Spec
            #
            # There're two ways of creating subtypes in ASN.1 what influences
            # decoder operation. These methods are:
            # 1) Either base types used in or no IMPLICIT tagging has been
            #    applied on subtyping.
            # 2) Subtype syntax drops base type information (by means of
            #    IMPLICIT tagging.
            # The first case allows for complete tag recovery from substrate
            # while the second one requires original ASN.1 type spec for
            # decoding.
            #
            # In either case a set of tags (tagSet) is coming from substrate
            # in an incremental, tag-by-tag fashion (this is the case of
            # EXPLICIT tag which is most basic). Outermost tag comes first
            # from the wire.
            #            
            if state == stGetValueDecoderByTag:
                if tagSet in self.__tagMap:
                    concreteDecoder = self.__tagMap[tagSet]
                else:
                    concreteDecoder = None
                if concreteDecoder:
                    state = stDecodeValue
                else:
                    _k = tagSet[:1]
                    if _k in self.__tagMap:
                        concreteDecoder = self.__tagMap[_k]
                    else:
                        concreteDecoder = None
                    if concreteDecoder:
                        state = stDecodeValue
                    else:
                        state = stTryAsExplicitTag
                if debug.logger and debug.logger & debug.flagDecoder:
                    debug.logger('codec %s chosen by a built-in type, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag'))
                    debug.scope.push(concreteDecoder is None and '?' or concreteDecoder.protoComponent.__class__.__name__)
            if state == stGetValueDecoderByAsn1Spec:
                if isinstance(asn1Spec, (dict, tagmap.TagMap)):
                    if tagSet in asn1Spec:
                        __chosenSpec = asn1Spec[tagSet]
                    else:
                        __chosenSpec = None
                    if debug.logger and debug.logger & debug.flagDecoder:
                        debug.logger('candidate ASN.1 spec is a map of:')
                        for t, v in asn1Spec.getPosMap().items():
                            debug.logger('  %s -> %s' % (t, v.__class__.__name__))
                        if asn1Spec.getNegMap():
                            debug.logger('but neither of: ')
                            for t, v in asn1Spec.getNegMap().items():
                                debug.logger('  %s -> %s' % (t, v.__class__.__name__))
                        debug.logger('new candidate ASN.1 spec is %s, chosen by %s' % (__chosenSpec is None and '<none>' or __chosenSpec.prettyPrintType(), tagSet))
                else:
                    __chosenSpec = asn1Spec
                    debug.logger and debug.logger & debug.flagDecoder and debug.logger('candidate ASN.1 spec is %s' % asn1Spec.__class__.__name__)
                if __chosenSpec is not None and (
                       tagSet == __chosenSpec.getTagSet() or \
                       tagSet in __chosenSpec.getTagMap()
                       ):
                    # use base type for codec lookup to recover untagged types
                    baseTagSet = __chosenSpec.baseTagSet
                    if __chosenSpec.typeId is not None and \
                           __chosenSpec.typeId in self.__typeMap:
                        # ambiguous type
                        concreteDecoder = self.__typeMap[__chosenSpec.typeId]
                        debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen for an ambiguous type by type ID %s' % (__chosenSpec.typeId,))
                    elif baseTagSet in self.__tagMap:
                        # base type or tagged subtype
                        concreteDecoder = self.__tagMap[baseTagSet]
                        debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen by base %s' % (baseTagSet,))
                    else:
                        concreteDecoder = None
                    if concreteDecoder:
                        asn1Spec = __chosenSpec
                        state = stDecodeValue
                    else:
                        state = stTryAsExplicitTag
                else:
                    concreteDecoder = None
                    state = stTryAsExplicitTag
                if debug.logger and debug.logger & debug.flagDecoder:
                    debug.logger('codec %s chosen by ASN.1 spec, decoding %s' % (state == stDecodeValue and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag'))
                    debug.scope.push(__chosenSpec is None and '?' or __chosenSpec.__class__.__name__)
            if state == stTryAsExplicitTag:
                if tagSet and \
                       tagSet[0][1] == tag.tagFormatConstructed and \
                       tagSet[0][0] != tag.tagClassUniversal:
                    # Assume explicit tagging
                    concreteDecoder = explicitTagDecoder
                    state = stDecodeValue
                else:
                    concreteDecoder = None
                    state = self.defaultErrorState
                debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as failure'))
            if state == stDumpRawValue:
                concreteDecoder = self.defaultRawDecoder
                debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding value' % concreteDecoder.__class__.__name__)
                state = stDecodeValue
            if state == stDecodeValue:
                if recursiveFlag == 0 and not substrateFun: # legacy
                    substrateFun = lambda a,b,c: (a,b[:c])
                if length == -1:  # indef length
                    value, substrate = concreteDecoder.indefLenValueDecoder(
                        fullSubstrate, substrate, asn1Spec, tagSet, length,
                        stGetValueDecoder, self, substrateFun
                        )
                else:
                    value, substrate = concreteDecoder.valueDecoder(
                        fullSubstrate, substrate, asn1Spec, tagSet, length,
                        stGetValueDecoder, self, substrateFun
                        )
                state = stStop
                debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, value.prettyPrint(), substrate and debug.hexdump(substrate) or '<none>'))
            if state == stErrorCondition:
                raise error.PyAsn1Error(
                    '%s not in asn1Spec: %s' % (tagSet, asn1Spec)
                )
        if debug.logger and debug.logger & debug.flagDecoder:
            debug.scope.pop()
            debug.logger('decoder left scope %s, call completed' % debug.scope)
        return value, substrate
Beispiel #11
0
 def test_isOctetsType(self):
     assert octets.isOctetsType('abc') == True
     assert octets.isOctetsType(123) == False
     assert octets.isOctetsType(unicode('abc')) == False
Beispiel #12
0
 def test_isOctetsType(self):
     assert octets.isOctetsType('abc') == False
     assert octets.isOctetsType(123) == False
     assert octets.isOctetsType(bytes()) == True
Beispiel #13
0
    def __call__(self,
                 substrate,
                 asn1Spec=None,
                 tagSet=None,
                 length=None,
                 state=stDecodeTag,
                 recursiveFlag=1,
                 substrateFun=None,
                 allowEoo=False):
        if debug.logger & debug.flagDecoder:
            debug.logger(
                'decoder called at scope %s with state %d, working with up to %d octets of substrate: %s'
                %
                (debug.scope, state, len(substrate), debug.hexdump(substrate)))
        if asn1Spec is not None and not isinstance(
                asn1Spec, (base.Asn1Item, tagmap.TagMap)):
            raise error.PyAsn1Error(
                'asn1Spec is not valid (should be an instance of an ASN.1 Item, not %s)'
                % asn1Spec.__class__.__name__)

        value = base.noValue

        fullSubstrate = substrate
        while state != stStop:
            if state == stDecodeTag:
                if not substrate:
                    raise error.SubstrateUnderrunError(
                        'Short octet stream on tag decoding')
                if not isOctetsType(substrate) and \
                        not isinstance(substrate, univ.OctetString):
                    raise error.PyAsn1Error('Bad octet stream type')
                # Decode tag
                firstOctet = substrate[0]
                substrate = substrate[1:]
                if firstOctet in self.__tagCache:
                    lastTag = self.__tagCache[firstOctet]
                else:
                    t = oct2int(firstOctet)
                    # Look for end-of-octets sentinel
                    if t == 0:
                        if substrate and oct2int(substrate[0]) == 0:
                            if allowEoo and self.supportIndefLength:
                                debug.logger and debug.logger & debug.flagDecoder and debug.logger(
                                    'end-of-octets sentinel found')
                                value, substrate = eoo.endOfOctets, substrate[
                                    1:]
                                state = stStop
                                continue
                            else:
                                raise error.PyAsn1Error(
                                    'Unexpected end-of-contents sentinel')
                        else:
                            raise error.PyAsn1Error('Zero tag encountered')
                    tagClass = t & 0xC0
                    tagFormat = t & 0x20
                    tagId = t & 0x1F
                    short = True
                    if tagId == 0x1F:
                        short = False
                        tagId = 0
                        while True:
                            if not substrate:
                                raise error.SubstrateUnderrunError(
                                    'Short octet stream on long tag decoding')
                            t = oct2int(substrate[0])
                            tagId = tagId << 7 | (t & 0x7F)
                            substrate = substrate[1:]
                            if not t & 0x80:
                                break
                    lastTag = tag.Tag(tagClass=tagClass,
                                      tagFormat=tagFormat,
                                      tagId=tagId)
                    if short:
                        # cache short tags
                        self.__tagCache[firstOctet] = lastTag
                if tagSet is None:
                    if firstOctet in self.__tagSetCache:
                        tagSet = self.__tagSetCache[firstOctet]
                    else:
                        # base tag not recovered
                        tagSet = tag.TagSet((), lastTag)
                        if firstOctet in self.__tagCache:
                            self.__tagSetCache[firstOctet] = tagSet
                else:
                    tagSet = lastTag + tagSet
                state = stDecodeLength
                debug.logger and debug.logger & debug.flagDecoder and debug.logger(
                    'tag decoded into %s, decoding length' % tagSet)
            if state == stDecodeLength:
                # Decode length
                if not substrate:
                    raise error.SubstrateUnderrunError(
                        'Short octet stream on length decoding')
                firstOctet = oct2int(substrate[0])
                if firstOctet == 128:
                    size = 1
                    length = -1
                elif firstOctet < 128:
                    length, size = firstOctet, 1
                else:
                    size = firstOctet & 0x7F
                    # encoded in size bytes
                    length = 0
                    lengthString = substrate[1:size + 1]
                    # missing check on maximum size, which shouldn't be a
                    # problem, we can handle more than is possible
                    if len(lengthString) != size:
                        raise error.SubstrateUnderrunError(
                            '%s<%s at %s' % (size, len(lengthString), tagSet))
                    for char in lengthString:
                        length = (length << 8) | oct2int(char)
                    size += 1
                substrate = substrate[size:]
                if length != -1 and len(substrate) < length:
                    raise error.SubstrateUnderrunError(
                        '%d-octet short' % (length - len(substrate)))
                if length == -1 and not self.supportIndefLength:
                    error.PyAsn1Error(
                        'Indefinite length encoding not supported by this codec'
                    )
                state = stGetValueDecoder
                debug.logger and debug.logger & debug.flagDecoder and debug.logger(
                    'value length decoded into %d, payload substrate is: %s' %
                    (length,
                     debug.hexdump(length == -1 and substrate
                                   or substrate[:length])))
            if state == stGetValueDecoder:
                if asn1Spec is None:
                    state = stGetValueDecoderByTag
                else:
                    state = stGetValueDecoderByAsn1Spec
            #
            # There're two ways of creating subtypes in ASN.1 what influences
            # decoder operation. These methods are:
            # 1) Either base types used in or no IMPLICIT tagging has been
            #    applied on subtyping.
            # 2) Subtype syntax drops base type information (by means of
            #    IMPLICIT tagging.
            # The first case allows for complete tag recovery from substrate
            # while the second one requires original ASN.1 type spec for
            # decoding.
            #
            # In either case a set of tags (tagSet) is coming from substrate
            # in an incremental, tag-by-tag fashion (this is the case of
            # EXPLICIT tag which is most basic). Outermost tag comes first
            # from the wire.
            #
            if state == stGetValueDecoderByTag:
                if tagSet in self.__tagMap:
                    concreteDecoder = self.__tagMap[tagSet]
                else:
                    concreteDecoder = None
                if concreteDecoder:
                    state = stDecodeValue
                else:
                    _k = tagSet[:1]
                    if _k in self.__tagMap:
                        concreteDecoder = self.__tagMap[_k]
                    else:
                        concreteDecoder = None
                    if concreteDecoder:
                        state = stDecodeValue
                    else:
                        state = stTryAsExplicitTag
                if debug.logger and debug.logger & debug.flagDecoder:
                    debug.logger(
                        'codec %s chosen by a built-in type, decoding %s' %
                        (concreteDecoder and concreteDecoder.__class__.__name__
                         or "<none>", state == stDecodeValue and 'value'
                         or 'as explicit tag'))
                    debug.scope.push(
                        concreteDecoder is None and '?'
                        or concreteDecoder.protoComponent.__class__.__name__)
            if state == stGetValueDecoderByAsn1Spec:
                if isinstance(asn1Spec, (dict, tagmap.TagMap)):
                    if tagSet in asn1Spec:
                        __chosenSpec = asn1Spec[tagSet]
                    else:
                        __chosenSpec = None
                    if debug.logger and debug.logger & debug.flagDecoder:
                        debug.logger('candidate ASN.1 spec is a map of:')
                        for t, v in asn1Spec.getPosMap().items():
                            debug.logger('  %s -> %s' %
                                         (t, v.__class__.__name__))
                        if asn1Spec.getNegMap():
                            debug.logger('but neither of: ')
                            for t, v in asn1Spec.getNegMap().items():
                                debug.logger('  %s -> %s' %
                                             (t, v.__class__.__name__))
                        debug.logger(
                            'new candidate ASN.1 spec is %s, chosen by %s' %
                            (__chosenSpec is None and '<none>'
                             or __chosenSpec.prettyPrintType(), tagSet))
                else:
                    __chosenSpec = asn1Spec
                    debug.logger and debug.logger & debug.flagDecoder and debug.logger(
                        'candidate ASN.1 spec is %s' %
                        asn1Spec.__class__.__name__)
                if __chosenSpec is not None and (
                        tagSet == __chosenSpec.getTagSet()
                        or tagSet in __chosenSpec.getTagMap()):
                    # use base type for codec lookup to recover untagged types
                    baseTagSet = __chosenSpec.baseTagSet
                    if __chosenSpec.typeId is not None and \
                            __chosenSpec.typeId in self.__typeMap:
                        # ambiguous type
                        concreteDecoder = self.__typeMap[__chosenSpec.typeId]
                        debug.logger and debug.logger & debug.flagDecoder and debug.logger(
                            'value decoder chosen for an ambiguous type by type ID %s'
                            % (__chosenSpec.typeId, ))
                    elif baseTagSet in self.__tagMap:
                        # base type or tagged subtype
                        concreteDecoder = self.__tagMap[baseTagSet]
                        debug.logger and debug.logger & debug.flagDecoder and debug.logger(
                            'value decoder chosen by base %s' % (baseTagSet, ))
                    else:
                        concreteDecoder = None
                    if concreteDecoder:
                        asn1Spec = __chosenSpec
                        state = stDecodeValue
                    else:
                        state = stTryAsExplicitTag
                else:
                    concreteDecoder = None
                    state = stTryAsExplicitTag
                if debug.logger and debug.logger & debug.flagDecoder:
                    debug.logger(
                        'codec %s chosen by ASN.1 spec, decoding %s' %
                        (state == stDecodeValue
                         and concreteDecoder.__class__.__name__
                         or "<none>", state == stDecodeValue and 'value'
                         or 'as explicit tag'))
                    debug.scope.push(__chosenSpec is None and '?'
                                     or __chosenSpec.__class__.__name__)
            if state == stTryAsExplicitTag:
                if tagSet and tagSet[0][1] == tag.tagFormatConstructed and \
                        tagSet[0][0] != tag.tagClassUniversal:
                    # Assume explicit tagging
                    concreteDecoder = explicitTagDecoder
                    state = stDecodeValue
                else:
                    concreteDecoder = None
                    state = self.defaultErrorState
                debug.logger and debug.logger & debug.flagDecoder and debug.logger(
                    'codec %s chosen, decoding %s' %
                    (concreteDecoder and concreteDecoder.__class__.__name__
                     or "<none>", state == stDecodeValue and 'value'
                     or 'as failure'))
            if state == stDumpRawValue:
                concreteDecoder = self.defaultRawDecoder
                debug.logger and debug.logger & debug.flagDecoder and debug.logger(
                    'codec %s chosen, decoding value' %
                    concreteDecoder.__class__.__name__)
                state = stDecodeValue
            if state == stDecodeValue:
                if recursiveFlag == 0 and not substrateFun:  # legacy

                    def substrateFun(a, b, c):
                        return a, b[:c]

                if length == -1:  # indef length
                    value, substrate = concreteDecoder.indefLenValueDecoder(
                        fullSubstrate, substrate, asn1Spec, tagSet, length,
                        stGetValueDecoder, self, substrateFun)
                else:
                    value, substrate = concreteDecoder.valueDecoder(
                        fullSubstrate, substrate, asn1Spec, tagSet, length,
                        stGetValueDecoder, self, substrateFun)
                state = stStop
                debug.logger and debug.logger & debug.flagDecoder and debug.logger(
                    'codec %s yields type %s, value:\n%s\n...remaining substrate is: %s'
                    % (concreteDecoder.__class__.__name__,
                       value.__class__.__name__, value.prettyPrint(),
                       substrate and debug.hexdump(substrate) or '<none>'))
            if state == stErrorCondition:
                raise error.PyAsn1Error('%s not in asn1Spec: %s' %
                                        (tagSet, asn1Spec))
        if debug.logger and debug.logger & debug.flagDecoder:
            debug.scope.pop()
            debug.logger('decoder left scope %s, call completed' % debug.scope)
        return value, substrate
 def test_isOctetsType(self):
     assert octets.isOctetsType('abc') == True
     assert octets.isOctetsType(123) == False
     assert octets.isOctetsType(unicode('abc')) == False
 def test_isOctetsType(self):
     assert octets.isOctetsType('abc') == False
     assert octets.isOctetsType(123) == False
     assert octets.isOctetsType(bytes()) == True
Beispiel #16
0
    def prettyIn(self, value):  # override asn1 type method
        """Implements DISPLAY-HINT parsing into base SNMP value

        Proper parsing seems impossible due to ambiguities.
        Here we are trying to do our best, but be prepared
        for failures on complicated DISPLAY-HINTs.

        Keep in mind that this parser only works with "text"
        input meaning `unicode` (Py2) or `str` (Py3).
        """
        for base in inspect.getmro(self.__class__):
            if not issubclass(base, TextualConvention) and issubclass(base, Asn1Item):
                break
        else:
            raise SmiError('TEXTUAL-CONVENTION has no underlying SNMP base type')

        if self.displayHint and (self.__integer.isSuperTypeOf(self, matchConstraints=False) and
                                 self.getNamedValues() or
                                 self.__unsigned32.isSuperTypeOf(self, matchConstraints=False) or
                                 self.__timeticks.isSuperTypeOf(self, matchConstraints=False)):
            value = str(value)

            _ = lambda t, f=0: (t, f)
            displayHintType, decimalPrecision = _(*self.displayHint.split('-'))
            if displayHintType == 'x' and (value.startswith('0x') or value.startswith('-0x')):
                try:
                    if value.startswith('-'):
                        return base.prettyIn(self, -int(value[3:], 16))
                    else:
                        return base.prettyIn(self, int(value[2:], 16))
                except Exception as exc:
                    raise SmiError(
                        'integer evaluation error: %s' % exc
                    )
            elif displayHintType == 'd':
                try:
                    return base.prettyIn(self, int(float(value) * 10**int(decimalPrecision)))
                except Exception as exc:
                    raise SmiError(
                        'float evaluation error: %s' % exc
                    )
            elif displayHintType == 'o' and (value.startswith('0') or value.startswith('-0')):
                try:
                    return base.prettyIn(self, int(value, 8))
                except Exception as exc:
                    raise SmiError(
                        'octal evaluation error: %s' % exc
                    )
            elif displayHintType == 'b' and (value.startswith('B') or value.startswith('-B')):
                negative = value.startswith('-')
                if negative:
                    value = value[2:]
                else:
                    value = value[1:]
                value = [x != '0' and 1 or 0 for x in value]
                binValue = 0
                while value:
                    binValue <<= value[0]
                    del value[0]
                return base.prettyIn(self, binValue)
            else:
                raise SmiError(
                    'Unsupported numeric type spec "%s" at %s' % (displayHintType, self.__class__.__name__)
                )

        elif self.displayHint and self.__octetString.isSuperTypeOf(self, matchConstraints=False):
            numBase = {
                'x': 16,
                'd': 10,
                'o': 8
            }
            numDigits = {
                'x': octets.str2octs(string.hexdigits),
                'o': octets.str2octs(string.octdigits),
                'd': octets.str2octs(string.digits)
            }

            # how do we know if object is initialized with display-hint
            # formatted text? based on "text" input maybe?
            # That boils down to `str` object on Py3 or `unicode` on Py2.
            if octets.isStringType(value) and not octets.isOctetsType(value):
                value = base.prettyIn(self, value)
            else:
                return base.prettyIn(self, value)

            outputValue = octets.str2octs('')
            runningValue = value
            displayHint = self.displayHint

            while runningValue and displayHint:
                # 1 this information is totally lost, just fail explicitly
                if displayHint[0] == '*':
                    raise SmiError(
                        'Can\'t parse "*" in DISPLAY-HINT (%s)' % self.__class__.__name__
                    )

                # 2 this becomes ambiguous when it comes to rendered value
                octetLength = ''
                while displayHint and displayHint[0] in string.digits:
                    octetLength += displayHint[0]
                    displayHint = displayHint[1:]

                # length is mandatory but people ignore that
                if not octetLength:
                    octetLength = len(runningValue)

                try:
                    octetLength = int(octetLength)
                except Exception:
                    raise SmiError(
                        'Bad octet length: %s' % octetLength
                    )

                if not displayHint:
                    raise SmiError(
                        'Short octet length: %s' % self.displayHint
                    )

                # 3
                displayFormat = displayHint[0]
                displayHint = displayHint[1:]

                # 4 this is the lifesaver -- we could use it as an anchor
                if displayHint and displayHint[0] not in string.digits and displayHint[0] != '*':
                    displaySep = displayHint[0]
                    displayHint = displayHint[1:]
                else:
                    displaySep = ''

                # 5 is probably impossible to support

                if displayFormat in ('a', 't'):
                    outputValue += runningValue[:octetLength]
                elif displayFormat in numBase:
                    if displaySep:
                        guessedOctetLength = runningValue.find(octets.str2octs(displaySep))
                        if guessedOctetLength == -1:
                            guessedOctetLength = len(runningValue)
                    else:
                        for idx in range(len(runningValue)):
                            if runningValue[idx] not in numDigits[displayFormat]:
                                guessedOctetLength = idx
                                break
                        else:
                            guessedOctetLength = len(runningValue)

                    try:
                        num = int(octets.octs2str(runningValue[:guessedOctetLength]), numBase[displayFormat])
                    except Exception as exc:
                        raise SmiError(
                            'Display format eval failure: %s: %s'
                            % (runningValue[:guessedOctetLength], exc)
                        )

                    num_as_bytes = []
                    if num:
                        while num:
                            num_as_bytes.append(num & 0xFF)
                            num >>= 8
                    else:
                        num_as_bytes = [0]

                    while len(num_as_bytes) < octetLength:
                        num_as_bytes.append(0)

                    num_as_bytes.reverse()

                    outputValue += octets.ints2octs(num_as_bytes)

                    if displaySep:
                        guessedOctetLength += 1

                    octetLength = guessedOctetLength
                else:
                    raise SmiError(
                        'Unsupported display format char: %s' %
                        displayFormat
                    )

                runningValue = runningValue[octetLength:]

                if not displayHint:
                    displayHint = self.displayHint

            return base.prettyIn(self, outputValue)

        else:
            return base.prettyIn(self, value)