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 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)
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 __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 _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 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 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')
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))
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')
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 __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))
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 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
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 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))
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 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 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, ))
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')
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, ))
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')
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 __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 encode(self, value, encodeFun, **options): raise error.PyAsn1Error('Not implemented')
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 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
def getComponentByPosition(self, idx): raise error.PyAsn1Error('Method not implemented')
def setComponentByPosition(self, idx, value, verifyConstraints=True): raise error.PyAsn1Error('Method not implemented')
def __getitem__(self, item): raise error.PyAsn1Error(self.__errorMsg)