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
def encodeValue(self, value, asn1Spec, encodeFun, **options): # CER encoding constraints: # - minutes are mandatory, seconds are optional # - sub-seconds must NOT be zero / no meaningless zeros # - no hanging fraction dot # - time in UTC (Z) # - only dot is allowed for fractions if asn1Spec is not None: value = asn1Spec.clone(value) numbers = value.asNumbers() if self.PLUS_CHAR in numbers or self.MINUS_CHAR in numbers: raise error.PyAsn1Error('Must be UTC time: %r' % value) if numbers[-1] != self.Z_CHAR: raise error.PyAsn1Error('Missing "Z" time zone specifier: %r' % value) if self.COMMA_CHAR in numbers: raise error.PyAsn1Error('Comma in fractions disallowed: %r' % value) if self.DOT_CHAR in numbers: isModified = False numbers = list(numbers) searchIndex = min( numbers.index(self.DOT_CHAR) + 4, len(numbers) - 1) while numbers[searchIndex] != self.DOT_CHAR: if numbers[searchIndex] == self.ZERO_CHAR: del numbers[searchIndex] isModified = True searchIndex -= 1 searchIndex += 1 if searchIndex < len(numbers): if numbers[searchIndex] == self.Z_CHAR: # drop hanging comma del numbers[searchIndex - 1] isModified = True if isModified: value = value.clone(numbers) if not self.MIN_LENGTH < len(numbers) < self.MAX_LENGTH: raise error.PyAsn1Error('Length constraint violated: %r' % value) options.update(maxChunkSize=1000) return encoder.OctetStringEncoder.encodeValue(self, value, asn1Spec, encodeFun, **options)
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
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
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 ------ ~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')
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
def __init__(self, *flags, **options): self._flags = DEBUG_NONE if 'loggerName' in options: # route our logs to parent logger self._printer = Printer(logger=logging.getLogger( options['loggerName']), handler=NullHandler()) elif 'printer' in options: self._printer = options.get('printer') else: self._printer = self.defaultPrinter self._printer('running pyasn1 %s, debug flags %s' % (__version__, ', '.join(flags))) for flag in flags: inverse = flag and flag[0] in ('!', '~') if inverse: flag = flag[1:] try: if inverse: self._flags &= ~FLAG_MAP[flag] else: self._flags |= FLAG_MAP[flag] except KeyError: raise error.PyAsn1Error('bad debug flag %s' % flag) self._printer("debug category '%s' %s" % (flag, inverse and 'disabled' or 'enabled'))
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 ------ ~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')
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),) )
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)
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
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
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
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
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
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 ------ ~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')
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 ------ ~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, ))
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
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 ------ ~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, ))
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 ------ ~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')
def encodeValue(self, value, asn1Spec, encodeFun, **options): raise error.PyAsn1Error('Not implemented')
def encodeValue(self, value, asn1Spec, encodeFun, **options): substrate = null omitEmptyOptionals = options.get('omitEmptyOptionals', self.omitEmptyOptionals) if LOG: LOG('%sencoding empty OPTIONAL components' % (omitEmptyOptionals and 'not ' or '')) if asn1Spec is None: # instance of ASN.1 schema inconsistency = value.isInconsistent if inconsistency: raise inconsistency namedTypes = value.componentType for idx, component in enumerate(value.values()): if namedTypes: namedType = namedTypes[idx] if namedType.isOptional and not component.isValue: if LOG: LOG('not encoding OPTIONAL component %r' % (namedType, )) continue if namedType.isDefaulted and component == namedType.asn1Object: if LOG: LOG('not encoding DEFAULT component %r' % (namedType, )) continue if omitEmptyOptionals: options.update(ifNotEmpty=namedType.isOptional) # wrap open type blob if needed if namedTypes and namedType.openType: wrapType = namedType.asn1Object if wrapType.typeId in (univ.SetOf.typeId, univ.SequenceOf.typeId): substrate += encodeFun( component, asn1Spec, **dict(options, wrapType=wrapType.componentType)) else: chunk = encodeFun(component, asn1Spec, **options) if wrapType.isSameTypeWith(component): substrate += chunk else: substrate += encodeFun(chunk, wrapType, **options) if LOG: LOG('wrapped with wrap type %r' % (wrapType, )) else: substrate += encodeFun(component, asn1Spec, **options) 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: if LOG: LOG('not encoding OPTIONAL component %r' % (namedType, )) continue if namedType.isDefaulted and component == namedType.asn1Object: if LOG: LOG('not encoding DEFAULT component %r' % (namedType, )) continue if omitEmptyOptionals: options.update(ifNotEmpty=namedType.isOptional) componentSpec = namedType.asn1Object # wrap open type blob if needed if namedType.openType: if componentSpec.typeId in (univ.SetOf.typeId, univ.SequenceOf.typeId): substrate += encodeFun( component, componentSpec, **dict(options, wrapType=componentSpec.componentType)) else: chunk = encodeFun(component, componentSpec, **options) if componentSpec.isSameTypeWith(component): substrate += chunk else: substrate += encodeFun(chunk, componentSpec, **options) if LOG: LOG('wrapped with wrap type %r' % (componentSpec, )) else: substrate += encodeFun(component, componentSpec, **options) return substrate, True, True
def encodeValue(self, value, asn1Spec, encodeFun, **options): if asn1Spec is not None: value = asn1Spec.clone(value) if value.isPlusInf: return (0x40, ), False, False if value.isMinusInf: return (0x41, ), False, False m, b, e = value if not m: return null, False, True if b == 10: if LOG: LOG('encoding REAL into character form') return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), False, True elif b == 2: fo = 0x80 # binary encoding ms, m, encbase, e = self._chooseEncBase(value) if ms < 0: # mantissa sign fo |= 0x40 # sign bit # exponent & mantissa normalization if encbase == 2: while m & 0x1 == 0: m >>= 1 e += 1 elif encbase == 8: while m & 0x7 == 0: m >>= 3 e += 1 fo |= 0x10 else: # encbase = 16 while m & 0xf == 0: m >>= 4 e += 1 fo |= 0x20 sf = 0 # scale factor while m & 0x1 == 0: m >>= 1 sf += 1 if sf > 3: raise error.PyAsn1Error( 'Scale factor overflow') # bug if raised fo |= sf << 2 eo = null if e == 0 or e == -1: eo = int2oct(e & 0xff) else: while e not in (0, -1): eo = int2oct(e & 0xff) + eo e >>= 8 if e == 0 and eo and oct2int(eo[0]) & 0x80: eo = int2oct(0) + eo if e == -1 and eo and not (oct2int(eo[0]) & 0x80): eo = int2oct(0xff) + eo n = len(eo) if n > 0xff: raise error.PyAsn1Error('Real exponent overflow') if n == 1: pass elif n == 2: fo |= 1 elif n == 3: fo |= 2 else: fo |= 3 eo = int2oct(n & 0xff) + eo po = null while m: po = int2oct(m & 0xff) + po m >>= 8 substrate = int2oct(fo) + eo + po return substrate, False, True else: raise error.PyAsn1Error('Prohibited Real base %s' % b)
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)
def setComponentByPosition(self, idx, value, verifyConstraints=True): raise error.PyAsn1Error('Method not implemented')
def getComponentByPosition(self, idx): raise error.PyAsn1Error('Method not implemented')
def components(self): raise error.PyAsn1Error('Method not implemented')
def encode(self, value, asn1Spec=None, encodeFun=None, **options): if asn1Spec is None: tagSet = value.tagSet else: tagSet = asn1Spec.tagSet # untagged item? if not tagSet: substrate, isConstructed, isOctets = self.encodeValue( value, asn1Spec, encodeFun, **options) return substrate defMode = options.get('defMode', True) substrate = null for idx, singleTag in enumerate(tagSet.superTags): defModeOverride = defMode # base tag? if not idx: try: substrate, isConstructed, isOctets = self.encodeValue( value, asn1Spec, encodeFun, **options) except error.PyAsn1Error: exc = sys.exc_info() raise error.PyAsn1Error('Error encoding %r: %s' % (value, exc[1])) if LOG: LOG('encoded %svalue %s into %s' % (isConstructed and 'constructed ' or '', value, substrate)) if not substrate and isConstructed and options.get( 'ifNotEmpty', False): return substrate if not isConstructed: defModeOverride = True if LOG: LOG('overridden encoding mode into definitive for primitive type' ) header = self.encodeTag(singleTag, isConstructed) if LOG: LOG('encoded %stag %s into %s' % (isConstructed and 'constructed ' or '', singleTag, debug.hexdump(ints2octs(header)))) header += self.encodeLength(len(substrate), defModeOverride) if LOG: LOG('encoded %s octets (tag + payload) into %s' % (len(substrate), debug.hexdump(ints2octs(header)))) if isOctets: substrate = ints2octs(header) + substrate if not defModeOverride: substrate += self.eooOctetsSubstrate else: substrate = header + substrate if not defModeOverride: substrate += self.eooIntegerSubstrate if not isOctets: substrate = ints2octs(substrate) return substrate
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
def plug(self, *args, **kw): raise error.PyAsn1Error( 'Attempted "%s" operation on ASN.1 schema object' % name)