Updated DB_Helper by adding firebase methods.
This commit is contained in:
parent
485cc3bbba
commit
c82121d036
1810 changed files with 537281 additions and 1 deletions
7
venv/Lib/site-packages/pyasn1/__init__.py
Normal file
7
venv/Lib/site-packages/pyasn1/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
import sys
|
||||
|
||||
# https://www.python.org/dev/peps/pep-0396/
|
||||
__version__ = '0.4.8'
|
||||
|
||||
if sys.version_info[:2] < (2, 4):
|
||||
raise RuntimeError('PyASN1 requires Python 2.4 or later')
|
Binary file not shown.
BIN
venv/Lib/site-packages/pyasn1/__pycache__/debug.cpython-36.pyc
Normal file
BIN
venv/Lib/site-packages/pyasn1/__pycache__/debug.cpython-36.pyc
Normal file
Binary file not shown.
BIN
venv/Lib/site-packages/pyasn1/__pycache__/error.cpython-36.pyc
Normal file
BIN
venv/Lib/site-packages/pyasn1/__pycache__/error.cpython-36.pyc
Normal file
Binary file not shown.
1
venv/Lib/site-packages/pyasn1/codec/__init__.py
Normal file
1
venv/Lib/site-packages/pyasn1/codec/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
Binary file not shown.
1
venv/Lib/site-packages/pyasn1/codec/ber/__init__.py
Normal file
1
venv/Lib/site-packages/pyasn1/codec/ber/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1682
venv/Lib/site-packages/pyasn1/codec/ber/decoder.py
Normal file
1682
venv/Lib/site-packages/pyasn1/codec/ber/decoder.py
Normal file
File diff suppressed because it is too large
Load diff
890
venv/Lib/site-packages/pyasn1/codec/ber/encoder.py
Normal file
890
venv/Lib/site-packages/pyasn1/codec/ber/encoder.py
Normal file
|
@ -0,0 +1,890 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
import sys
|
||||
|
||||
from pyasn1 import debug
|
||||
from pyasn1 import error
|
||||
from pyasn1.codec.ber import eoo
|
||||
from pyasn1.compat.integer import to_bytes
|
||||
from pyasn1.compat.octets import (int2oct, oct2int, ints2octs, null,
|
||||
str2octs, isOctetsType)
|
||||
from pyasn1.type import char
|
||||
from pyasn1.type import tag
|
||||
from pyasn1.type import univ
|
||||
from pyasn1.type import useful
|
||||
|
||||
__all__ = ['encode']
|
||||
|
||||
LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_ENCODER)
|
||||
|
||||
|
||||
class AbstractItemEncoder(object):
|
||||
supportIndefLenMode = True
|
||||
|
||||
# An outcome of otherwise legit call `encodeFun(eoo.endOfOctets)`
|
||||
eooIntegerSubstrate = (0, 0)
|
||||
eooOctetsSubstrate = ints2octs(eooIntegerSubstrate)
|
||||
|
||||
# noinspection PyMethodMayBeStatic
|
||||
def encodeTag(self, singleTag, isConstructed):
|
||||
tagClass, tagFormat, tagId = singleTag
|
||||
encodedTag = tagClass | tagFormat
|
||||
if isConstructed:
|
||||
encodedTag |= tag.tagFormatConstructed
|
||||
|
||||
if tagId < 31:
|
||||
return encodedTag | tagId,
|
||||
|
||||
else:
|
||||
substrate = tagId & 0x7f,
|
||||
|
||||
tagId >>= 7
|
||||
|
||||
while tagId:
|
||||
substrate = (0x80 | (tagId & 0x7f),) + substrate
|
||||
tagId >>= 7
|
||||
|
||||
return (encodedTag | 0x1F,) + substrate
|
||||
|
||||
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):
|
||||
raise error.PyAsn1Error('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
|
||||
|
||||
|
||||
class EndOfOctetsEncoder(AbstractItemEncoder):
|
||||
def encodeValue(self, value, asn1Spec, encodeFun, **options):
|
||||
return null, False, True
|
||||
|
||||
|
||||
class BooleanEncoder(AbstractItemEncoder):
|
||||
supportIndefLenMode = False
|
||||
|
||||
def encodeValue(self, value, asn1Spec, encodeFun, **options):
|
||||
return value and (1,) or (0,), False, False
|
||||
|
||||
|
||||
class IntegerEncoder(AbstractItemEncoder):
|
||||
supportIndefLenMode = False
|
||||
supportCompactZero = False
|
||||
|
||||
def encodeValue(self, value, asn1Spec, encodeFun, **options):
|
||||
if value == 0:
|
||||
if LOG:
|
||||
LOG('encoding %spayload for zero INTEGER' % (
|
||||
self.supportCompactZero and 'no ' or ''
|
||||
))
|
||||
|
||||
# de-facto way to encode zero
|
||||
if self.supportCompactZero:
|
||||
return (), False, False
|
||||
else:
|
||||
return (0,), False, False
|
||||
|
||||
return to_bytes(int(value), signed=True), False, True
|
||||
|
||||
|
||||
class BitStringEncoder(AbstractItemEncoder):
|
||||
def encodeValue(self, value, asn1Spec, encodeFun, **options):
|
||||
if asn1Spec is not None:
|
||||
# TODO: try to avoid ASN.1 schema instantiation
|
||||
value = asn1Spec.clone(value)
|
||||
|
||||
valueLength = len(value)
|
||||
if valueLength % 8:
|
||||
alignedValue = value << (8 - valueLength % 8)
|
||||
else:
|
||||
alignedValue = value
|
||||
|
||||
maxChunkSize = options.get('maxChunkSize', 0)
|
||||
if not maxChunkSize or len(alignedValue) <= maxChunkSize * 8:
|
||||
substrate = alignedValue.asOctets()
|
||||
return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True
|
||||
|
||||
if LOG:
|
||||
LOG('encoding into up to %s-octet chunks' % maxChunkSize)
|
||||
|
||||
baseTag = value.tagSet.baseTag
|
||||
|
||||
# strip off explicit tags
|
||||
if baseTag:
|
||||
tagSet = tag.TagSet(baseTag, baseTag)
|
||||
|
||||
else:
|
||||
tagSet = tag.TagSet()
|
||||
|
||||
alignedValue = alignedValue.clone(tagSet=tagSet)
|
||||
|
||||
stop = 0
|
||||
substrate = null
|
||||
while stop < valueLength:
|
||||
start = stop
|
||||
stop = min(start + maxChunkSize * 8, valueLength)
|
||||
substrate += encodeFun(alignedValue[start:stop], asn1Spec, **options)
|
||||
|
||||
return substrate, True, True
|
||||
|
||||
|
||||
class OctetStringEncoder(AbstractItemEncoder):
|
||||
|
||||
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
|
||||
|
||||
|
||||
class NullEncoder(AbstractItemEncoder):
|
||||
supportIndefLenMode = False
|
||||
|
||||
def encodeValue(self, value, asn1Spec, encodeFun, **options):
|
||||
return null, False, True
|
||||
|
||||
|
||||
class ObjectIdentifierEncoder(AbstractItemEncoder):
|
||||
supportIndefLenMode = False
|
||||
|
||||
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
|
||||
|
||||
|
||||
class RealEncoder(AbstractItemEncoder):
|
||||
supportIndefLenMode = 0
|
||||
binEncBase = 2 # set to None to choose encoding base automatically
|
||||
|
||||
@staticmethod
|
||||
def _dropFloatingPoint(m, encbase, e):
|
||||
ms, es = 1, 1
|
||||
if m < 0:
|
||||
ms = -1 # mantissa sign
|
||||
|
||||
if e < 0:
|
||||
es = -1 # exponent sign
|
||||
|
||||
m *= ms
|
||||
|
||||
if encbase == 8:
|
||||
m *= 2 ** (abs(e) % 3 * es)
|
||||
e = abs(e) // 3 * es
|
||||
|
||||
elif encbase == 16:
|
||||
m *= 2 ** (abs(e) % 4 * es)
|
||||
e = abs(e) // 4 * es
|
||||
|
||||
while True:
|
||||
if int(m) != m:
|
||||
m *= encbase
|
||||
e -= 1
|
||||
continue
|
||||
break
|
||||
|
||||
return ms, int(m), encbase, e
|
||||
|
||||
def _chooseEncBase(self, value):
|
||||
m, b, e = value
|
||||
encBase = [2, 8, 16]
|
||||
if value.binEncBase in encBase:
|
||||
return self._dropFloatingPoint(m, value.binEncBase, e)
|
||||
|
||||
elif self.binEncBase in encBase:
|
||||
return self._dropFloatingPoint(m, self.binEncBase, e)
|
||||
|
||||
# auto choosing base 2/8/16
|
||||
mantissa = [m, m, m]
|
||||
exponent = [e, e, e]
|
||||
sign = 1
|
||||
encbase = 2
|
||||
e = float('inf')
|
||||
|
||||
for i in range(3):
|
||||
(sign,
|
||||
mantissa[i],
|
||||
encBase[i],
|
||||
exponent[i]) = self._dropFloatingPoint(mantissa[i], encBase[i], exponent[i])
|
||||
|
||||
if abs(exponent[i]) < abs(e) or (abs(exponent[i]) == abs(e) and mantissa[i] < m):
|
||||
e = exponent[i]
|
||||
m = int(mantissa[i])
|
||||
encbase = encBase[i]
|
||||
|
||||
if LOG:
|
||||
LOG('automatically chosen REAL encoding base %s, sign %s, mantissa %s, '
|
||||
'exponent %s' % (encbase, sign, m, e))
|
||||
|
||||
return sign, m, encbase, e
|
||||
|
||||
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)
|
||||
|
||||
|
||||
class SequenceEncoder(AbstractItemEncoder):
|
||||
omitEmptyOptionals = False
|
||||
|
||||
# TODO: handling three flavors of input is too much -- split over codecs
|
||||
|
||||
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
|
||||
|
||||
|
||||
class SequenceOfEncoder(AbstractItemEncoder):
|
||||
def _encodeComponents(self, value, asn1Spec, encodeFun, **options):
|
||||
|
||||
if asn1Spec is None:
|
||||
inconsistency = value.isInconsistent
|
||||
if inconsistency:
|
||||
raise inconsistency
|
||||
|
||||
else:
|
||||
asn1Spec = asn1Spec.componentType
|
||||
|
||||
chunks = []
|
||||
|
||||
wrapType = options.pop('wrapType', None)
|
||||
|
||||
for idx, component in enumerate(value):
|
||||
chunk = encodeFun(component, asn1Spec, **options)
|
||||
|
||||
if (wrapType is not None and
|
||||
not wrapType.isSameTypeWith(component)):
|
||||
# wrap encoded value with wrapper container (e.g. ANY)
|
||||
chunk = encodeFun(chunk, wrapType, **options)
|
||||
|
||||
if LOG:
|
||||
LOG('wrapped with wrap type %r' % (wrapType,))
|
||||
|
||||
chunks.append(chunk)
|
||||
|
||||
return chunks
|
||||
|
||||
def encodeValue(self, value, asn1Spec, encodeFun, **options):
|
||||
chunks = self._encodeComponents(
|
||||
value, asn1Spec, encodeFun, **options)
|
||||
|
||||
return null.join(chunks), True, True
|
||||
|
||||
|
||||
class ChoiceEncoder(AbstractItemEncoder):
|
||||
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
|
||||
|
||||
|
||||
class AnyEncoder(OctetStringEncoder):
|
||||
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
|
||||
|
||||
|
||||
tagMap = {
|
||||
eoo.endOfOctets.tagSet: EndOfOctetsEncoder(),
|
||||
univ.Boolean.tagSet: BooleanEncoder(),
|
||||
univ.Integer.tagSet: IntegerEncoder(),
|
||||
univ.BitString.tagSet: BitStringEncoder(),
|
||||
univ.OctetString.tagSet: OctetStringEncoder(),
|
||||
univ.Null.tagSet: NullEncoder(),
|
||||
univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(),
|
||||
univ.Enumerated.tagSet: IntegerEncoder(),
|
||||
univ.Real.tagSet: RealEncoder(),
|
||||
# Sequence & Set have same tags as SequenceOf & SetOf
|
||||
univ.SequenceOf.tagSet: SequenceOfEncoder(),
|
||||
univ.SetOf.tagSet: SequenceOfEncoder(),
|
||||
univ.Choice.tagSet: ChoiceEncoder(),
|
||||
# character string types
|
||||
char.UTF8String.tagSet: OctetStringEncoder(),
|
||||
char.NumericString.tagSet: OctetStringEncoder(),
|
||||
char.PrintableString.tagSet: OctetStringEncoder(),
|
||||
char.TeletexString.tagSet: OctetStringEncoder(),
|
||||
char.VideotexString.tagSet: OctetStringEncoder(),
|
||||
char.IA5String.tagSet: OctetStringEncoder(),
|
||||
char.GraphicString.tagSet: OctetStringEncoder(),
|
||||
char.VisibleString.tagSet: OctetStringEncoder(),
|
||||
char.GeneralString.tagSet: OctetStringEncoder(),
|
||||
char.UniversalString.tagSet: OctetStringEncoder(),
|
||||
char.BMPString.tagSet: OctetStringEncoder(),
|
||||
# useful types
|
||||
useful.ObjectDescriptor.tagSet: OctetStringEncoder(),
|
||||
useful.GeneralizedTime.tagSet: OctetStringEncoder(),
|
||||
useful.UTCTime.tagSet: OctetStringEncoder()
|
||||
}
|
||||
|
||||
# Put in ambiguous & non-ambiguous types for faster codec lookup
|
||||
typeMap = {
|
||||
univ.Boolean.typeId: BooleanEncoder(),
|
||||
univ.Integer.typeId: IntegerEncoder(),
|
||||
univ.BitString.typeId: BitStringEncoder(),
|
||||
univ.OctetString.typeId: OctetStringEncoder(),
|
||||
univ.Null.typeId: NullEncoder(),
|
||||
univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(),
|
||||
univ.Enumerated.typeId: IntegerEncoder(),
|
||||
univ.Real.typeId: RealEncoder(),
|
||||
# Sequence & Set have same tags as SequenceOf & SetOf
|
||||
univ.Set.typeId: SequenceEncoder(),
|
||||
univ.SetOf.typeId: SequenceOfEncoder(),
|
||||
univ.Sequence.typeId: SequenceEncoder(),
|
||||
univ.SequenceOf.typeId: SequenceOfEncoder(),
|
||||
univ.Choice.typeId: ChoiceEncoder(),
|
||||
univ.Any.typeId: AnyEncoder(),
|
||||
# character string types
|
||||
char.UTF8String.typeId: OctetStringEncoder(),
|
||||
char.NumericString.typeId: OctetStringEncoder(),
|
||||
char.PrintableString.typeId: OctetStringEncoder(),
|
||||
char.TeletexString.typeId: OctetStringEncoder(),
|
||||
char.VideotexString.typeId: OctetStringEncoder(),
|
||||
char.IA5String.typeId: OctetStringEncoder(),
|
||||
char.GraphicString.typeId: OctetStringEncoder(),
|
||||
char.VisibleString.typeId: OctetStringEncoder(),
|
||||
char.GeneralString.typeId: OctetStringEncoder(),
|
||||
char.UniversalString.typeId: OctetStringEncoder(),
|
||||
char.BMPString.typeId: OctetStringEncoder(),
|
||||
# useful types
|
||||
useful.ObjectDescriptor.typeId: OctetStringEncoder(),
|
||||
useful.GeneralizedTime.typeId: OctetStringEncoder(),
|
||||
useful.UTCTime.typeId: OctetStringEncoder()
|
||||
}
|
||||
|
||||
|
||||
class Encoder(object):
|
||||
fixedDefLengthMode = None
|
||||
fixedChunkSize = None
|
||||
|
||||
# noinspection PyDefaultArgument
|
||||
def __init__(self, tagMap, typeMap={}):
|
||||
self.__tagMap = tagMap
|
||||
self.__typeMap = typeMap
|
||||
|
||||
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
|
||||
|
||||
#: Turns ASN.1 object into BER octet stream.
|
||||
#:
|
||||
#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
|
||||
#: walks all its components recursively and produces a BER octet stream.
|
||||
#:
|
||||
#: Parameters
|
||||
#: ----------
|
||||
#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
|
||||
#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
|
||||
#: parameter is required to guide the encoding process.
|
||||
#:
|
||||
#: Keyword Args
|
||||
#: ------------
|
||||
#: asn1Spec:
|
||||
#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
|
||||
#:
|
||||
#: defMode: :py:class:`bool`
|
||||
#: If :obj:`False`, produces indefinite length encoding
|
||||
#:
|
||||
#: maxChunkSize: :py:class:`int`
|
||||
#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size)
|
||||
#:
|
||||
#: Returns
|
||||
#: -------
|
||||
#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
|
||||
#: Given ASN.1 object encoded into BER octetstream
|
||||
#:
|
||||
#: Raises
|
||||
#: ------
|
||||
#: ~pyasn1.error.PyAsn1Error
|
||||
#: On encoding errors
|
||||
#:
|
||||
#: Examples
|
||||
#: --------
|
||||
#: Encode Python value into BER with ASN.1 schema
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> seq = SequenceOf(componentType=Integer())
|
||||
#: >>> encode([1, 2, 3], asn1Spec=seq)
|
||||
#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
|
||||
#:
|
||||
#: Encode ASN.1 value object into BER
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> seq = SequenceOf(componentType=Integer())
|
||||
#: >>> seq.extend([1, 2, 3])
|
||||
#: >>> encode(seq)
|
||||
#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
|
||||
#:
|
||||
encode = Encoder(tagMap, typeMap)
|
28
venv/Lib/site-packages/pyasn1/codec/ber/eoo.py
Normal file
28
venv/Lib/site-packages/pyasn1/codec/ber/eoo.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from pyasn1.type import base
|
||||
from pyasn1.type import tag
|
||||
|
||||
__all__ = ['endOfOctets']
|
||||
|
||||
|
||||
class EndOfOctets(base.SimpleAsn1Type):
|
||||
defaultValue = 0
|
||||
tagSet = tag.initTagSet(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00)
|
||||
)
|
||||
|
||||
_instance = None
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls._instance is None:
|
||||
cls._instance = object.__new__(cls, *args, **kwargs)
|
||||
|
||||
return cls._instance
|
||||
|
||||
|
||||
endOfOctets = EndOfOctets()
|
1
venv/Lib/site-packages/pyasn1/codec/cer/__init__.py
Normal file
1
venv/Lib/site-packages/pyasn1/codec/cer/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
114
venv/Lib/site-packages/pyasn1/codec/cer/decoder.py
Normal file
114
venv/Lib/site-packages/pyasn1/codec/cer/decoder.py
Normal file
|
@ -0,0 +1,114 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from pyasn1 import error
|
||||
from pyasn1.codec.ber import decoder
|
||||
from pyasn1.compat.octets import oct2int
|
||||
from pyasn1.type import univ
|
||||
|
||||
__all__ = ['decode']
|
||||
|
||||
|
||||
class BooleanDecoder(decoder.AbstractSimpleDecoder):
|
||||
protoComponent = univ.Boolean(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
|
||||
|
||||
# TODO: prohibit non-canonical encoding
|
||||
BitStringDecoder = decoder.BitStringDecoder
|
||||
OctetStringDecoder = decoder.OctetStringDecoder
|
||||
RealDecoder = decoder.RealDecoder
|
||||
|
||||
tagMap = decoder.tagMap.copy()
|
||||
tagMap.update(
|
||||
{univ.Boolean.tagSet: BooleanDecoder(),
|
||||
univ.BitString.tagSet: BitStringDecoder(),
|
||||
univ.OctetString.tagSet: OctetStringDecoder(),
|
||||
univ.Real.tagSet: RealDecoder()}
|
||||
)
|
||||
|
||||
typeMap = decoder.typeMap.copy()
|
||||
|
||||
# Put in non-ambiguous types for faster codec lookup
|
||||
for typeDecoder in tagMap.values():
|
||||
if typeDecoder.protoComponent is not None:
|
||||
typeId = typeDecoder.protoComponent.__class__.typeId
|
||||
if typeId is not None and typeId not in typeMap:
|
||||
typeMap[typeId] = typeDecoder
|
||||
|
||||
|
||||
class Decoder(decoder.Decoder):
|
||||
pass
|
||||
|
||||
|
||||
#: Turns CER octet stream into an ASN.1 object.
|
||||
#:
|
||||
#: Takes CER octet-stream and decode it into an ASN.1 object
|
||||
#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which
|
||||
#: may be a scalar or an arbitrary nested structure.
|
||||
#:
|
||||
#: Parameters
|
||||
#: ----------
|
||||
#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
|
||||
#: CER octet-stream
|
||||
#:
|
||||
#: Keyword Args
|
||||
#: ------------
|
||||
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
|
||||
#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure
|
||||
#: being decoded, *asn1Spec* may or may not be required. Most common reason for
|
||||
#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode.
|
||||
#:
|
||||
#: Returns
|
||||
#: -------
|
||||
#: : :py:class:`tuple`
|
||||
#: A tuple of pyasn1 object recovered from CER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
|
||||
#: and the unprocessed trailing portion of the *substrate* (may be empty)
|
||||
#:
|
||||
#: Raises
|
||||
#: ------
|
||||
#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError
|
||||
#: On decoding errors
|
||||
#:
|
||||
#: Examples
|
||||
#: --------
|
||||
#: Decode CER serialisation without ASN.1 schema
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00')
|
||||
#: >>> str(s)
|
||||
#: SequenceOf:
|
||||
#: 1 2 3
|
||||
#:
|
||||
#: Decode CER serialisation with ASN.1 schema
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> seq = SequenceOf(componentType=Integer())
|
||||
#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00', asn1Spec=seq)
|
||||
#: >>> str(s)
|
||||
#: SequenceOf:
|
||||
#: 1 2 3
|
||||
#:
|
||||
decode = Decoder(tagMap, decoder.typeMap)
|
313
venv/Lib/site-packages/pyasn1/codec/cer/encoder.py
Normal file
313
venv/Lib/site-packages/pyasn1/codec/cer/encoder.py
Normal file
|
@ -0,0 +1,313 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from pyasn1 import error
|
||||
from pyasn1.codec.ber import encoder
|
||||
from pyasn1.compat.octets import str2octs, null
|
||||
from pyasn1.type import univ
|
||||
from pyasn1.type import useful
|
||||
|
||||
__all__ = ['encode']
|
||||
|
||||
|
||||
class BooleanEncoder(encoder.IntegerEncoder):
|
||||
def encodeValue(self, value, asn1Spec, encodeFun, **options):
|
||||
if value == 0:
|
||||
substrate = (0,)
|
||||
else:
|
||||
substrate = (255,)
|
||||
return substrate, False, False
|
||||
|
||||
|
||||
class RealEncoder(encoder.RealEncoder):
|
||||
def _chooseEncBase(self, value):
|
||||
m, b, e = value
|
||||
return self._dropFloatingPoint(m, b, e)
|
||||
|
||||
|
||||
# specialized GeneralStringEncoder here
|
||||
|
||||
class TimeEncoderMixIn(object):
|
||||
Z_CHAR = ord('Z')
|
||||
PLUS_CHAR = ord('+')
|
||||
MINUS_CHAR = ord('-')
|
||||
COMMA_CHAR = ord(',')
|
||||
DOT_CHAR = ord('.')
|
||||
ZERO_CHAR = ord('0')
|
||||
|
||||
MIN_LENGTH = 12
|
||||
MAX_LENGTH = 19
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
class GeneralizedTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):
|
||||
MIN_LENGTH = 12
|
||||
MAX_LENGTH = 20
|
||||
|
||||
|
||||
class UTCTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):
|
||||
MIN_LENGTH = 10
|
||||
MAX_LENGTH = 14
|
||||
|
||||
|
||||
class SetOfEncoder(encoder.SequenceOfEncoder):
|
||||
def encodeValue(self, value, asn1Spec, encodeFun, **options):
|
||||
chunks = self._encodeComponents(
|
||||
value, asn1Spec, encodeFun, **options)
|
||||
|
||||
# sort by serialised and padded components
|
||||
if len(chunks) > 1:
|
||||
zero = str2octs('\x00')
|
||||
maxLen = max(map(len, chunks))
|
||||
paddedChunks = [
|
||||
(x.ljust(maxLen, zero), x) for x in chunks
|
||||
]
|
||||
paddedChunks.sort(key=lambda x: x[0])
|
||||
|
||||
chunks = [x[1] for x in paddedChunks]
|
||||
|
||||
return null.join(chunks), True, True
|
||||
|
||||
|
||||
class SequenceOfEncoder(encoder.SequenceOfEncoder):
|
||||
def encodeValue(self, value, asn1Spec, encodeFun, **options):
|
||||
|
||||
if options.get('ifNotEmpty', False) and not len(value):
|
||||
return null, True, True
|
||||
|
||||
chunks = self._encodeComponents(
|
||||
value, asn1Spec, encodeFun, **options)
|
||||
|
||||
return null.join(chunks), True, True
|
||||
|
||||
|
||||
class SetEncoder(encoder.SequenceEncoder):
|
||||
@staticmethod
|
||||
def _componentSortKey(componentAndType):
|
||||
"""Sort SET components by tag
|
||||
|
||||
Sort regardless of the Choice value (static sort)
|
||||
"""
|
||||
component, asn1Spec = componentAndType
|
||||
|
||||
if asn1Spec is None:
|
||||
asn1Spec = component
|
||||
|
||||
if asn1Spec.typeId == univ.Choice.typeId and not asn1Spec.tagSet:
|
||||
if asn1Spec.tagSet:
|
||||
return asn1Spec.tagSet
|
||||
else:
|
||||
return asn1Spec.componentType.minTagSet
|
||||
else:
|
||||
return asn1Spec.tagSet
|
||||
|
||||
def encodeValue(self, value, asn1Spec, encodeFun, **options):
|
||||
|
||||
substrate = null
|
||||
|
||||
comps = []
|
||||
compsMap = {}
|
||||
|
||||
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:
|
||||
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
|
||||
|
||||
|
||||
class SequenceEncoder(encoder.SequenceEncoder):
|
||||
omitEmptyOptionals = True
|
||||
|
||||
|
||||
tagMap = encoder.tagMap.copy()
|
||||
tagMap.update({
|
||||
univ.Boolean.tagSet: BooleanEncoder(),
|
||||
univ.Real.tagSet: RealEncoder(),
|
||||
useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(),
|
||||
useful.UTCTime.tagSet: UTCTimeEncoder(),
|
||||
# Sequence & Set have same tags as SequenceOf & SetOf
|
||||
univ.SetOf.tagSet: SetOfEncoder(),
|
||||
univ.Sequence.typeId: SequenceEncoder()
|
||||
})
|
||||
|
||||
typeMap = encoder.typeMap.copy()
|
||||
typeMap.update({
|
||||
univ.Boolean.typeId: BooleanEncoder(),
|
||||
univ.Real.typeId: RealEncoder(),
|
||||
useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(),
|
||||
useful.UTCTime.typeId: UTCTimeEncoder(),
|
||||
# Sequence & Set have same tags as SequenceOf & SetOf
|
||||
univ.Set.typeId: SetEncoder(),
|
||||
univ.SetOf.typeId: SetOfEncoder(),
|
||||
univ.Sequence.typeId: SequenceEncoder(),
|
||||
univ.SequenceOf.typeId: SequenceOfEncoder()
|
||||
})
|
||||
|
||||
|
||||
class Encoder(encoder.Encoder):
|
||||
fixedDefLengthMode = False
|
||||
fixedChunkSize = 1000
|
||||
|
||||
#: Turns ASN.1 object into CER octet stream.
|
||||
#:
|
||||
#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
|
||||
#: walks all its components recursively and produces a CER octet stream.
|
||||
#:
|
||||
#: Parameters
|
||||
#: ----------
|
||||
#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
|
||||
#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
|
||||
#: parameter is required to guide the encoding process.
|
||||
#:
|
||||
#: Keyword Args
|
||||
#: ------------
|
||||
#: asn1Spec:
|
||||
#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
|
||||
#:
|
||||
#: Returns
|
||||
#: -------
|
||||
#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
|
||||
#: Given ASN.1 object encoded into BER octet-stream
|
||||
#:
|
||||
#: Raises
|
||||
#: ------
|
||||
#: ~pyasn1.error.PyAsn1Error
|
||||
#: On encoding errors
|
||||
#:
|
||||
#: Examples
|
||||
#: --------
|
||||
#: Encode Python value into CER with ASN.1 schema
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> seq = SequenceOf(componentType=Integer())
|
||||
#: >>> encode([1, 2, 3], asn1Spec=seq)
|
||||
#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'
|
||||
#:
|
||||
#: Encode ASN.1 value object into CER
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> seq = SequenceOf(componentType=Integer())
|
||||
#: >>> seq.extend([1, 2, 3])
|
||||
#: >>> encode(seq)
|
||||
#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'
|
||||
#:
|
||||
encode = Encoder(tagMap, typeMap)
|
||||
|
||||
# EncoderFactory queries class instance and builds a map of tags -> encoders
|
1
venv/Lib/site-packages/pyasn1/codec/der/__init__.py
Normal file
1
venv/Lib/site-packages/pyasn1/codec/der/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
94
venv/Lib/site-packages/pyasn1/codec/der/decoder.py
Normal file
94
venv/Lib/site-packages/pyasn1/codec/der/decoder.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from pyasn1.codec.cer import decoder
|
||||
from pyasn1.type import univ
|
||||
|
||||
__all__ = ['decode']
|
||||
|
||||
|
||||
class BitStringDecoder(decoder.BitStringDecoder):
|
||||
supportConstructedForm = False
|
||||
|
||||
|
||||
class OctetStringDecoder(decoder.OctetStringDecoder):
|
||||
supportConstructedForm = False
|
||||
|
||||
# TODO: prohibit non-canonical encoding
|
||||
RealDecoder = decoder.RealDecoder
|
||||
|
||||
tagMap = decoder.tagMap.copy()
|
||||
tagMap.update(
|
||||
{univ.BitString.tagSet: BitStringDecoder(),
|
||||
univ.OctetString.tagSet: OctetStringDecoder(),
|
||||
univ.Real.tagSet: RealDecoder()}
|
||||
)
|
||||
|
||||
typeMap = decoder.typeMap.copy()
|
||||
|
||||
# Put in non-ambiguous types for faster codec lookup
|
||||
for typeDecoder in tagMap.values():
|
||||
if typeDecoder.protoComponent is not None:
|
||||
typeId = typeDecoder.protoComponent.__class__.typeId
|
||||
if typeId is not None and typeId not in typeMap:
|
||||
typeMap[typeId] = typeDecoder
|
||||
|
||||
|
||||
class Decoder(decoder.Decoder):
|
||||
supportIndefLength = False
|
||||
|
||||
|
||||
#: Turns DER octet stream into an ASN.1 object.
|
||||
#:
|
||||
#: Takes DER octet-stream and decode it into an ASN.1 object
|
||||
#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which
|
||||
#: may be a scalar or an arbitrary nested structure.
|
||||
#:
|
||||
#: Parameters
|
||||
#: ----------
|
||||
#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
|
||||
#: DER octet-stream
|
||||
#:
|
||||
#: Keyword Args
|
||||
#: ------------
|
||||
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
|
||||
#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure
|
||||
#: being decoded, *asn1Spec* may or may not be required. Most common reason for
|
||||
#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode.
|
||||
#:
|
||||
#: Returns
|
||||
#: -------
|
||||
#: : :py:class:`tuple`
|
||||
#: A tuple of pyasn1 object recovered from DER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
|
||||
#: and the unprocessed trailing portion of the *substrate* (may be empty)
|
||||
#:
|
||||
#: Raises
|
||||
#: ------
|
||||
#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError
|
||||
#: On decoding errors
|
||||
#:
|
||||
#: Examples
|
||||
#: --------
|
||||
#: Decode DER serialisation without ASN.1 schema
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03')
|
||||
#: >>> str(s)
|
||||
#: SequenceOf:
|
||||
#: 1 2 3
|
||||
#:
|
||||
#: Decode DER serialisation with ASN.1 schema
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> seq = SequenceOf(componentType=Integer())
|
||||
#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03', asn1Spec=seq)
|
||||
#: >>> str(s)
|
||||
#: SequenceOf:
|
||||
#: 1 2 3
|
||||
#:
|
||||
decode = Decoder(tagMap, typeMap)
|
107
venv/Lib/site-packages/pyasn1/codec/der/encoder.py
Normal file
107
venv/Lib/site-packages/pyasn1/codec/der/encoder.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from pyasn1 import error
|
||||
from pyasn1.codec.cer import encoder
|
||||
from pyasn1.type import univ
|
||||
|
||||
__all__ = ['encode']
|
||||
|
||||
|
||||
class SetEncoder(encoder.SetEncoder):
|
||||
@staticmethod
|
||||
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
|
||||
|
||||
tagMap = encoder.tagMap.copy()
|
||||
tagMap.update({
|
||||
# Set & SetOf have same tags
|
||||
univ.Set.tagSet: SetEncoder()
|
||||
})
|
||||
|
||||
typeMap = encoder.typeMap.copy()
|
||||
typeMap.update({
|
||||
# Set & SetOf have same tags
|
||||
univ.Set.typeId: SetEncoder()
|
||||
})
|
||||
|
||||
|
||||
class Encoder(encoder.Encoder):
|
||||
fixedDefLengthMode = True
|
||||
fixedChunkSize = 0
|
||||
|
||||
#: Turns ASN.1 object into DER octet stream.
|
||||
#:
|
||||
#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
|
||||
#: walks all its components recursively and produces a DER octet stream.
|
||||
#:
|
||||
#: Parameters
|
||||
#: ----------
|
||||
#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
|
||||
#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
|
||||
#: parameter is required to guide the encoding process.
|
||||
#:
|
||||
#: Keyword Args
|
||||
#: ------------
|
||||
#: asn1Spec:
|
||||
#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
|
||||
#:
|
||||
#: Returns
|
||||
#: -------
|
||||
#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
|
||||
#: Given ASN.1 object encoded into BER octet-stream
|
||||
#:
|
||||
#: Raises
|
||||
#: ------
|
||||
#: ~pyasn1.error.PyAsn1Error
|
||||
#: On encoding errors
|
||||
#:
|
||||
#: Examples
|
||||
#: --------
|
||||
#: Encode Python value into DER with ASN.1 schema
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> seq = SequenceOf(componentType=Integer())
|
||||
#: >>> encode([1, 2, 3], asn1Spec=seq)
|
||||
#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
|
||||
#:
|
||||
#: Encode ASN.1 value object into DER
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> seq = SequenceOf(componentType=Integer())
|
||||
#: >>> seq.extend([1, 2, 3])
|
||||
#: >>> encode(seq)
|
||||
#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
|
||||
#:
|
||||
encode = Encoder(tagMap, typeMap)
|
1
venv/Lib/site-packages/pyasn1/codec/native/__init__.py
Normal file
1
venv/Lib/site-packages/pyasn1/codec/native/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
213
venv/Lib/site-packages/pyasn1/codec/native/decoder.py
Normal file
213
venv/Lib/site-packages/pyasn1/codec/native/decoder.py
Normal file
|
@ -0,0 +1,213 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from pyasn1 import debug
|
||||
from pyasn1 import error
|
||||
from pyasn1.type import base
|
||||
from pyasn1.type import char
|
||||
from pyasn1.type import tag
|
||||
from pyasn1.type import univ
|
||||
from pyasn1.type import useful
|
||||
|
||||
__all__ = ['decode']
|
||||
|
||||
LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_DECODER)
|
||||
|
||||
|
||||
class AbstractScalarDecoder(object):
|
||||
def __call__(self, pyObject, asn1Spec, decodeFun=None, **options):
|
||||
return asn1Spec.clone(pyObject)
|
||||
|
||||
|
||||
class BitStringDecoder(AbstractScalarDecoder):
|
||||
def __call__(self, pyObject, asn1Spec, decodeFun=None, **options):
|
||||
return asn1Spec.clone(univ.BitString.fromBinaryString(pyObject))
|
||||
|
||||
|
||||
class SequenceOrSetDecoder(object):
|
||||
def __call__(self, pyObject, asn1Spec, decodeFun=None, **options):
|
||||
asn1Value = asn1Spec.clone()
|
||||
|
||||
componentsTypes = asn1Spec.componentType
|
||||
|
||||
for field in asn1Value:
|
||||
if field in pyObject:
|
||||
asn1Value[field] = decodeFun(pyObject[field], componentsTypes[field].asn1Object, **options)
|
||||
|
||||
return asn1Value
|
||||
|
||||
|
||||
class SequenceOfOrSetOfDecoder(object):
|
||||
def __call__(self, pyObject, asn1Spec, decodeFun=None, **options):
|
||||
asn1Value = asn1Spec.clone()
|
||||
|
||||
for pyValue in pyObject:
|
||||
asn1Value.append(decodeFun(pyValue, asn1Spec.componentType), **options)
|
||||
|
||||
return asn1Value
|
||||
|
||||
|
||||
class ChoiceDecoder(object):
|
||||
def __call__(self, pyObject, asn1Spec, decodeFun=None, **options):
|
||||
asn1Value = asn1Spec.clone()
|
||||
|
||||
componentsTypes = asn1Spec.componentType
|
||||
|
||||
for field in pyObject:
|
||||
if field in componentsTypes:
|
||||
asn1Value[field] = decodeFun(pyObject[field], componentsTypes[field].asn1Object, **options)
|
||||
break
|
||||
|
||||
return asn1Value
|
||||
|
||||
|
||||
tagMap = {
|
||||
univ.Integer.tagSet: AbstractScalarDecoder(),
|
||||
univ.Boolean.tagSet: AbstractScalarDecoder(),
|
||||
univ.BitString.tagSet: BitStringDecoder(),
|
||||
univ.OctetString.tagSet: AbstractScalarDecoder(),
|
||||
univ.Null.tagSet: AbstractScalarDecoder(),
|
||||
univ.ObjectIdentifier.tagSet: AbstractScalarDecoder(),
|
||||
univ.Enumerated.tagSet: AbstractScalarDecoder(),
|
||||
univ.Real.tagSet: AbstractScalarDecoder(),
|
||||
univ.Sequence.tagSet: SequenceOrSetDecoder(), # conflicts with SequenceOf
|
||||
univ.Set.tagSet: SequenceOrSetDecoder(), # conflicts with SetOf
|
||||
univ.Choice.tagSet: ChoiceDecoder(), # conflicts with Any
|
||||
# character string types
|
||||
char.UTF8String.tagSet: AbstractScalarDecoder(),
|
||||
char.NumericString.tagSet: AbstractScalarDecoder(),
|
||||
char.PrintableString.tagSet: AbstractScalarDecoder(),
|
||||
char.TeletexString.tagSet: AbstractScalarDecoder(),
|
||||
char.VideotexString.tagSet: AbstractScalarDecoder(),
|
||||
char.IA5String.tagSet: AbstractScalarDecoder(),
|
||||
char.GraphicString.tagSet: AbstractScalarDecoder(),
|
||||
char.VisibleString.tagSet: AbstractScalarDecoder(),
|
||||
char.GeneralString.tagSet: AbstractScalarDecoder(),
|
||||
char.UniversalString.tagSet: AbstractScalarDecoder(),
|
||||
char.BMPString.tagSet: AbstractScalarDecoder(),
|
||||
# useful types
|
||||
useful.ObjectDescriptor.tagSet: AbstractScalarDecoder(),
|
||||
useful.GeneralizedTime.tagSet: AbstractScalarDecoder(),
|
||||
useful.UTCTime.tagSet: AbstractScalarDecoder()
|
||||
}
|
||||
|
||||
# Put in ambiguous & non-ambiguous types for faster codec lookup
|
||||
typeMap = {
|
||||
univ.Integer.typeId: AbstractScalarDecoder(),
|
||||
univ.Boolean.typeId: AbstractScalarDecoder(),
|
||||
univ.BitString.typeId: BitStringDecoder(),
|
||||
univ.OctetString.typeId: AbstractScalarDecoder(),
|
||||
univ.Null.typeId: AbstractScalarDecoder(),
|
||||
univ.ObjectIdentifier.typeId: AbstractScalarDecoder(),
|
||||
univ.Enumerated.typeId: AbstractScalarDecoder(),
|
||||
univ.Real.typeId: AbstractScalarDecoder(),
|
||||
# ambiguous base types
|
||||
univ.Set.typeId: SequenceOrSetDecoder(),
|
||||
univ.SetOf.typeId: SequenceOfOrSetOfDecoder(),
|
||||
univ.Sequence.typeId: SequenceOrSetDecoder(),
|
||||
univ.SequenceOf.typeId: SequenceOfOrSetOfDecoder(),
|
||||
univ.Choice.typeId: ChoiceDecoder(),
|
||||
univ.Any.typeId: AbstractScalarDecoder(),
|
||||
# character string types
|
||||
char.UTF8String.typeId: AbstractScalarDecoder(),
|
||||
char.NumericString.typeId: AbstractScalarDecoder(),
|
||||
char.PrintableString.typeId: AbstractScalarDecoder(),
|
||||
char.TeletexString.typeId: AbstractScalarDecoder(),
|
||||
char.VideotexString.typeId: AbstractScalarDecoder(),
|
||||
char.IA5String.typeId: AbstractScalarDecoder(),
|
||||
char.GraphicString.typeId: AbstractScalarDecoder(),
|
||||
char.VisibleString.typeId: AbstractScalarDecoder(),
|
||||
char.GeneralString.typeId: AbstractScalarDecoder(),
|
||||
char.UniversalString.typeId: AbstractScalarDecoder(),
|
||||
char.BMPString.typeId: AbstractScalarDecoder(),
|
||||
# useful types
|
||||
useful.ObjectDescriptor.typeId: AbstractScalarDecoder(),
|
||||
useful.GeneralizedTime.typeId: AbstractScalarDecoder(),
|
||||
useful.UTCTime.typeId: AbstractScalarDecoder()
|
||||
}
|
||||
|
||||
|
||||
class Decoder(object):
|
||||
|
||||
# noinspection PyDefaultArgument
|
||||
def __init__(self, tagMap, typeMap):
|
||||
self.__tagMap = tagMap
|
||||
self.__typeMap = typeMap
|
||||
|
||||
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
|
||||
|
||||
|
||||
#: Turns Python objects of built-in types into ASN.1 objects.
|
||||
#:
|
||||
#: Takes Python objects of built-in types and turns them into a tree of
|
||||
#: ASN.1 objects (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which
|
||||
#: may be a scalar or an arbitrary nested structure.
|
||||
#:
|
||||
#: Parameters
|
||||
#: ----------
|
||||
#: pyObject: :py:class:`object`
|
||||
#: A scalar or nested Python objects
|
||||
#:
|
||||
#: Keyword Args
|
||||
#: ------------
|
||||
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
|
||||
#: A pyasn1 type object to act as a template guiding the decoder. It is required
|
||||
#: for successful interpretation of Python objects mapping into their ASN.1
|
||||
#: representations.
|
||||
#:
|
||||
#: Returns
|
||||
#: -------
|
||||
#: : :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
|
||||
#: A scalar or constructed pyasn1 object
|
||||
#:
|
||||
#: Raises
|
||||
#: ------
|
||||
#: ~pyasn1.error.PyAsn1Error
|
||||
#: On decoding errors
|
||||
#:
|
||||
#: Examples
|
||||
#: --------
|
||||
#: Decode native Python object into ASN.1 objects with ASN.1 schema
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> seq = SequenceOf(componentType=Integer())
|
||||
#: >>> s, _ = decode([1, 2, 3], asn1Spec=seq)
|
||||
#: >>> str(s)
|
||||
#: SequenceOf:
|
||||
#: 1 2 3
|
||||
#:
|
||||
decode = Decoder(tagMap, typeMap)
|
256
venv/Lib/site-packages/pyasn1/codec/native/encoder.py
Normal file
256
venv/Lib/site-packages/pyasn1/codec/native/encoder.py
Normal file
|
@ -0,0 +1,256 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
|
||||
except ImportError:
|
||||
OrderedDict = dict
|
||||
|
||||
from pyasn1 import debug
|
||||
from pyasn1 import error
|
||||
from pyasn1.type import base
|
||||
from pyasn1.type import char
|
||||
from pyasn1.type import tag
|
||||
from pyasn1.type import univ
|
||||
from pyasn1.type import useful
|
||||
|
||||
__all__ = ['encode']
|
||||
|
||||
LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_ENCODER)
|
||||
|
||||
|
||||
class AbstractItemEncoder(object):
|
||||
def encode(self, value, encodeFun, **options):
|
||||
raise error.PyAsn1Error('Not implemented')
|
||||
|
||||
|
||||
class BooleanEncoder(AbstractItemEncoder):
|
||||
def encode(self, value, encodeFun, **options):
|
||||
return bool(value)
|
||||
|
||||
|
||||
class IntegerEncoder(AbstractItemEncoder):
|
||||
def encode(self, value, encodeFun, **options):
|
||||
return int(value)
|
||||
|
||||
|
||||
class BitStringEncoder(AbstractItemEncoder):
|
||||
def encode(self, value, encodeFun, **options):
|
||||
return str(value)
|
||||
|
||||
|
||||
class OctetStringEncoder(AbstractItemEncoder):
|
||||
def encode(self, value, encodeFun, **options):
|
||||
return value.asOctets()
|
||||
|
||||
|
||||
class TextStringEncoder(AbstractItemEncoder):
|
||||
def encode(self, value, encodeFun, **options):
|
||||
return str(value)
|
||||
|
||||
|
||||
class NullEncoder(AbstractItemEncoder):
|
||||
def encode(self, value, encodeFun, **options):
|
||||
return None
|
||||
|
||||
|
||||
class ObjectIdentifierEncoder(AbstractItemEncoder):
|
||||
def encode(self, value, encodeFun, **options):
|
||||
return str(value)
|
||||
|
||||
|
||||
class RealEncoder(AbstractItemEncoder):
|
||||
def encode(self, value, encodeFun, **options):
|
||||
return float(value)
|
||||
|
||||
|
||||
class SetEncoder(AbstractItemEncoder):
|
||||
protoDict = dict
|
||||
|
||||
def encode(self, value, encodeFun, **options):
|
||||
inconsistency = value.isInconsistent
|
||||
if inconsistency:
|
||||
raise inconsistency
|
||||
|
||||
namedTypes = value.componentType
|
||||
substrate = self.protoDict()
|
||||
|
||||
for idx, (key, subValue) in enumerate(value.items()):
|
||||
if namedTypes and namedTypes[idx].isOptional and not value[idx].isValue:
|
||||
continue
|
||||
substrate[key] = encodeFun(subValue, **options)
|
||||
return substrate
|
||||
|
||||
|
||||
class SequenceEncoder(SetEncoder):
|
||||
protoDict = OrderedDict
|
||||
|
||||
|
||||
class SequenceOfEncoder(AbstractItemEncoder):
|
||||
def encode(self, value, encodeFun, **options):
|
||||
inconsistency = value.isInconsistent
|
||||
if inconsistency:
|
||||
raise inconsistency
|
||||
return [encodeFun(x, **options) for x in value]
|
||||
|
||||
|
||||
class ChoiceEncoder(SequenceEncoder):
|
||||
pass
|
||||
|
||||
|
||||
class AnyEncoder(AbstractItemEncoder):
|
||||
def encode(self, value, encodeFun, **options):
|
||||
return value.asOctets()
|
||||
|
||||
|
||||
tagMap = {
|
||||
univ.Boolean.tagSet: BooleanEncoder(),
|
||||
univ.Integer.tagSet: IntegerEncoder(),
|
||||
univ.BitString.tagSet: BitStringEncoder(),
|
||||
univ.OctetString.tagSet: OctetStringEncoder(),
|
||||
univ.Null.tagSet: NullEncoder(),
|
||||
univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(),
|
||||
univ.Enumerated.tagSet: IntegerEncoder(),
|
||||
univ.Real.tagSet: RealEncoder(),
|
||||
# Sequence & Set have same tags as SequenceOf & SetOf
|
||||
univ.SequenceOf.tagSet: SequenceOfEncoder(),
|
||||
univ.SetOf.tagSet: SequenceOfEncoder(),
|
||||
univ.Choice.tagSet: ChoiceEncoder(),
|
||||
# character string types
|
||||
char.UTF8String.tagSet: TextStringEncoder(),
|
||||
char.NumericString.tagSet: TextStringEncoder(),
|
||||
char.PrintableString.tagSet: TextStringEncoder(),
|
||||
char.TeletexString.tagSet: TextStringEncoder(),
|
||||
char.VideotexString.tagSet: TextStringEncoder(),
|
||||
char.IA5String.tagSet: TextStringEncoder(),
|
||||
char.GraphicString.tagSet: TextStringEncoder(),
|
||||
char.VisibleString.tagSet: TextStringEncoder(),
|
||||
char.GeneralString.tagSet: TextStringEncoder(),
|
||||
char.UniversalString.tagSet: TextStringEncoder(),
|
||||
char.BMPString.tagSet: TextStringEncoder(),
|
||||
# useful types
|
||||
useful.ObjectDescriptor.tagSet: OctetStringEncoder(),
|
||||
useful.GeneralizedTime.tagSet: OctetStringEncoder(),
|
||||
useful.UTCTime.tagSet: OctetStringEncoder()
|
||||
}
|
||||
|
||||
|
||||
# Put in ambiguous & non-ambiguous types for faster codec lookup
|
||||
typeMap = {
|
||||
univ.Boolean.typeId: BooleanEncoder(),
|
||||
univ.Integer.typeId: IntegerEncoder(),
|
||||
univ.BitString.typeId: BitStringEncoder(),
|
||||
univ.OctetString.typeId: OctetStringEncoder(),
|
||||
univ.Null.typeId: NullEncoder(),
|
||||
univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(),
|
||||
univ.Enumerated.typeId: IntegerEncoder(),
|
||||
univ.Real.typeId: RealEncoder(),
|
||||
# Sequence & Set have same tags as SequenceOf & SetOf
|
||||
univ.Set.typeId: SetEncoder(),
|
||||
univ.SetOf.typeId: SequenceOfEncoder(),
|
||||
univ.Sequence.typeId: SequenceEncoder(),
|
||||
univ.SequenceOf.typeId: SequenceOfEncoder(),
|
||||
univ.Choice.typeId: ChoiceEncoder(),
|
||||
univ.Any.typeId: AnyEncoder(),
|
||||
# character string types
|
||||
char.UTF8String.typeId: OctetStringEncoder(),
|
||||
char.NumericString.typeId: OctetStringEncoder(),
|
||||
char.PrintableString.typeId: OctetStringEncoder(),
|
||||
char.TeletexString.typeId: OctetStringEncoder(),
|
||||
char.VideotexString.typeId: OctetStringEncoder(),
|
||||
char.IA5String.typeId: OctetStringEncoder(),
|
||||
char.GraphicString.typeId: OctetStringEncoder(),
|
||||
char.VisibleString.typeId: OctetStringEncoder(),
|
||||
char.GeneralString.typeId: OctetStringEncoder(),
|
||||
char.UniversalString.typeId: OctetStringEncoder(),
|
||||
char.BMPString.typeId: OctetStringEncoder(),
|
||||
# useful types
|
||||
useful.ObjectDescriptor.typeId: OctetStringEncoder(),
|
||||
useful.GeneralizedTime.typeId: OctetStringEncoder(),
|
||||
useful.UTCTime.typeId: OctetStringEncoder()
|
||||
}
|
||||
|
||||
|
||||
class Encoder(object):
|
||||
|
||||
# noinspection PyDefaultArgument
|
||||
def __init__(self, tagMap, typeMap={}):
|
||||
self.__tagMap = tagMap
|
||||
self.__typeMap = typeMap
|
||||
|
||||
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
|
||||
|
||||
|
||||
#: Turns ASN.1 object into a Python built-in type object(s).
|
||||
#:
|
||||
#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
|
||||
#: walks all its components recursively and produces a Python built-in type or a tree
|
||||
#: of those.
|
||||
#:
|
||||
#: One exception is that instead of :py:class:`dict`, the :py:class:`OrderedDict`
|
||||
#: can be produced (whenever available) to preserve ordering of the components
|
||||
#: in ASN.1 SEQUENCE.
|
||||
#:
|
||||
#: Parameters
|
||||
#: ----------
|
||||
# asn1Value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
|
||||
#: pyasn1 object to encode (or a tree of them)
|
||||
#:
|
||||
#: Returns
|
||||
#: -------
|
||||
#: : :py:class:`object`
|
||||
#: Python built-in type instance (or a tree of them)
|
||||
#:
|
||||
#: Raises
|
||||
#: ------
|
||||
#: ~pyasn1.error.PyAsn1Error
|
||||
#: On encoding errors
|
||||
#:
|
||||
#: Examples
|
||||
#: --------
|
||||
#: Encode ASN.1 value object into native Python types
|
||||
#:
|
||||
#: .. code-block:: pycon
|
||||
#:
|
||||
#: >>> seq = SequenceOf(componentType=Integer())
|
||||
#: >>> seq.extend([1, 2, 3])
|
||||
#: >>> encode(seq)
|
||||
#: [1, 2, 3]
|
||||
#:
|
||||
encode = Encoder(tagMap, typeMap)
|
1
venv/Lib/site-packages/pyasn1/compat/__init__.py
Normal file
1
venv/Lib/site-packages/pyasn1/compat/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
33
venv/Lib/site-packages/pyasn1/compat/binary.py
Normal file
33
venv/Lib/site-packages/pyasn1/compat/binary.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from sys import version_info
|
||||
|
||||
if version_info[0:2] < (2, 6):
|
||||
def bin(value):
|
||||
bitstring = []
|
||||
|
||||
if value > 0:
|
||||
prefix = '0b'
|
||||
elif value < 0:
|
||||
prefix = '-0b'
|
||||
value = abs(value)
|
||||
else:
|
||||
prefix = '0b0'
|
||||
|
||||
while value:
|
||||
if value & 1 == 1:
|
||||
bitstring.append('1')
|
||||
else:
|
||||
bitstring.append('0')
|
||||
|
||||
value >>= 1
|
||||
|
||||
bitstring.reverse()
|
||||
|
||||
return prefix + ''.join(bitstring)
|
||||
else:
|
||||
bin = bin
|
20
venv/Lib/site-packages/pyasn1/compat/calling.py
Normal file
20
venv/Lib/site-packages/pyasn1/compat/calling.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from sys import version_info
|
||||
|
||||
__all__ = ['callable']
|
||||
|
||||
|
||||
if (2, 7) < version_info[:2] < (3, 2):
|
||||
import collections
|
||||
|
||||
def callable(x):
|
||||
return isinstance(x, collections.Callable)
|
||||
|
||||
else:
|
||||
|
||||
callable = callable
|
22
venv/Lib/site-packages/pyasn1/compat/dateandtime.py
Normal file
22
venv/Lib/site-packages/pyasn1/compat/dateandtime.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
import time
|
||||
from datetime import datetime
|
||||
from sys import version_info
|
||||
|
||||
__all__ = ['strptime']
|
||||
|
||||
|
||||
if version_info[:2] <= (2, 4):
|
||||
|
||||
def strptime(text, dateFormat):
|
||||
return datetime(*(time.strptime(text, dateFormat)[0:6]))
|
||||
|
||||
else:
|
||||
|
||||
def strptime(text, dateFormat):
|
||||
return datetime.strptime(text, dateFormat)
|
110
venv/Lib/site-packages/pyasn1/compat/integer.py
Normal file
110
venv/Lib/site-packages/pyasn1/compat/integer.py
Normal file
|
@ -0,0 +1,110 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
import sys
|
||||
|
||||
try:
|
||||
import platform
|
||||
|
||||
implementation = platform.python_implementation()
|
||||
|
||||
except (ImportError, AttributeError):
|
||||
implementation = 'CPython'
|
||||
|
||||
from pyasn1.compat.octets import oct2int, null, ensureString
|
||||
|
||||
if sys.version_info[0:2] < (3, 2) or implementation != 'CPython':
|
||||
from binascii import a2b_hex, b2a_hex
|
||||
|
||||
if sys.version_info[0] > 2:
|
||||
long = int
|
||||
|
||||
def from_bytes(octets, signed=False):
|
||||
if not octets:
|
||||
return 0
|
||||
|
||||
value = long(b2a_hex(ensureString(octets)), 16)
|
||||
|
||||
if signed and oct2int(octets[0]) & 0x80:
|
||||
return value - (1 << len(octets) * 8)
|
||||
|
||||
return value
|
||||
|
||||
def to_bytes(value, signed=False, length=0):
|
||||
if value < 0:
|
||||
if signed:
|
||||
bits = bitLength(value)
|
||||
|
||||
# two's complement form
|
||||
maxValue = 1 << bits
|
||||
valueToEncode = (value + maxValue) % maxValue
|
||||
|
||||
else:
|
||||
raise OverflowError('can\'t convert negative int to unsigned')
|
||||
elif value == 0 and length == 0:
|
||||
return null
|
||||
else:
|
||||
bits = 0
|
||||
valueToEncode = value
|
||||
|
||||
hexValue = hex(valueToEncode)[2:]
|
||||
if hexValue.endswith('L'):
|
||||
hexValue = hexValue[:-1]
|
||||
|
||||
if len(hexValue) & 1:
|
||||
hexValue = '0' + hexValue
|
||||
|
||||
# padding may be needed for two's complement encoding
|
||||
if value != valueToEncode or length:
|
||||
hexLength = len(hexValue) * 4
|
||||
|
||||
padLength = max(length, bits)
|
||||
|
||||
if padLength > hexLength:
|
||||
hexValue = '00' * ((padLength - hexLength - 1) // 8 + 1) + hexValue
|
||||
elif length and hexLength - length > 7:
|
||||
raise OverflowError('int too big to convert')
|
||||
|
||||
firstOctet = int(hexValue[:2], 16)
|
||||
|
||||
if signed:
|
||||
if firstOctet & 0x80:
|
||||
if value >= 0:
|
||||
hexValue = '00' + hexValue
|
||||
elif value < 0:
|
||||
hexValue = 'ff' + hexValue
|
||||
|
||||
octets_value = a2b_hex(hexValue)
|
||||
|
||||
return octets_value
|
||||
|
||||
def bitLength(number):
|
||||
# bits in unsigned number
|
||||
hexValue = hex(abs(number))
|
||||
bits = len(hexValue) - 2
|
||||
if hexValue.endswith('L'):
|
||||
bits -= 1
|
||||
if bits & 1:
|
||||
bits += 1
|
||||
bits *= 4
|
||||
# TODO: strip lhs zeros
|
||||
return bits
|
||||
|
||||
else:
|
||||
|
||||
def from_bytes(octets, signed=False):
|
||||
return int.from_bytes(bytes(octets), 'big', signed=signed)
|
||||
|
||||
def to_bytes(value, signed=False, length=0):
|
||||
length = max(value.bit_length(), length)
|
||||
|
||||
if signed and length % 8 == 0:
|
||||
length += 1
|
||||
|
||||
return value.to_bytes(length // 8 + (length % 8 and 1 or 0), 'big', signed=signed)
|
||||
|
||||
def bitLength(number):
|
||||
return int(number).bit_length()
|
46
venv/Lib/site-packages/pyasn1/compat/octets.py
Normal file
46
venv/Lib/site-packages/pyasn1/compat/octets.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from sys import version_info
|
||||
|
||||
if version_info[0] <= 2:
|
||||
int2oct = chr
|
||||
# noinspection PyPep8
|
||||
ints2octs = lambda s: ''.join([int2oct(x) for x in s])
|
||||
null = ''
|
||||
oct2int = ord
|
||||
# TODO: refactor to return a sequence of ints
|
||||
# noinspection PyPep8
|
||||
octs2ints = lambda s: [oct2int(x) for x in s]
|
||||
# noinspection PyPep8
|
||||
str2octs = lambda x: x
|
||||
# noinspection PyPep8
|
||||
octs2str = lambda x: x
|
||||
# noinspection PyPep8
|
||||
isOctetsType = lambda s: isinstance(s, str)
|
||||
# noinspection PyPep8
|
||||
isStringType = lambda s: isinstance(s, (str, unicode))
|
||||
# noinspection PyPep8
|
||||
ensureString = str
|
||||
else:
|
||||
ints2octs = bytes
|
||||
# noinspection PyPep8
|
||||
int2oct = lambda x: ints2octs((x,))
|
||||
null = ints2octs()
|
||||
# noinspection PyPep8
|
||||
oct2int = lambda x: x
|
||||
# noinspection PyPep8
|
||||
octs2ints = lambda x: x
|
||||
# noinspection PyPep8
|
||||
str2octs = lambda x: x.encode('iso-8859-1')
|
||||
# noinspection PyPep8
|
||||
octs2str = lambda x: x.decode('iso-8859-1')
|
||||
# noinspection PyPep8
|
||||
isOctetsType = lambda s: isinstance(s, bytes)
|
||||
# noinspection PyPep8
|
||||
isStringType = lambda s: isinstance(s, str)
|
||||
# noinspection PyPep8
|
||||
ensureString = bytes
|
26
venv/Lib/site-packages/pyasn1/compat/string.py
Normal file
26
venv/Lib/site-packages/pyasn1/compat/string.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from sys import version_info
|
||||
|
||||
if version_info[:2] <= (2, 5):
|
||||
|
||||
def partition(string, sep):
|
||||
try:
|
||||
a, c = string.split(sep, 1)
|
||||
|
||||
except ValueError:
|
||||
a, b, c = string, '', ''
|
||||
|
||||
else:
|
||||
b = sep
|
||||
|
||||
return a, b, c
|
||||
|
||||
else:
|
||||
|
||||
def partition(string, sep):
|
||||
return string.partition(sep)
|
157
venv/Lib/site-packages/pyasn1/debug.py
Normal file
157
venv/Lib/site-packages/pyasn1/debug.py
Normal file
|
@ -0,0 +1,157 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from pyasn1 import __version__
|
||||
from pyasn1 import error
|
||||
from pyasn1.compat.octets import octs2ints
|
||||
|
||||
__all__ = ['Debug', 'setLogger', 'hexdump']
|
||||
|
||||
DEBUG_NONE = 0x0000
|
||||
DEBUG_ENCODER = 0x0001
|
||||
DEBUG_DECODER = 0x0002
|
||||
DEBUG_ALL = 0xffff
|
||||
|
||||
FLAG_MAP = {
|
||||
'none': DEBUG_NONE,
|
||||
'encoder': DEBUG_ENCODER,
|
||||
'decoder': DEBUG_DECODER,
|
||||
'all': DEBUG_ALL
|
||||
}
|
||||
|
||||
LOGGEE_MAP = {}
|
||||
|
||||
|
||||
class Printer(object):
|
||||
# noinspection PyShadowingNames
|
||||
def __init__(self, logger=None, handler=None, formatter=None):
|
||||
if logger is None:
|
||||
logger = logging.getLogger('pyasn1')
|
||||
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
if handler is None:
|
||||
handler = logging.StreamHandler()
|
||||
|
||||
if formatter is None:
|
||||
formatter = logging.Formatter('%(asctime)s %(name)s: %(message)s')
|
||||
|
||||
handler.setFormatter(formatter)
|
||||
handler.setLevel(logging.DEBUG)
|
||||
logger.addHandler(handler)
|
||||
|
||||
self.__logger = logger
|
||||
|
||||
def __call__(self, msg):
|
||||
self.__logger.debug(msg)
|
||||
|
||||
def __str__(self):
|
||||
return '<python logging>'
|
||||
|
||||
|
||||
if hasattr(logging, 'NullHandler'):
|
||||
NullHandler = logging.NullHandler
|
||||
|
||||
else:
|
||||
# Python 2.6 and older
|
||||
class NullHandler(logging.Handler):
|
||||
def emit(self, record):
|
||||
pass
|
||||
|
||||
|
||||
class Debug(object):
|
||||
defaultPrinter = Printer()
|
||||
|
||||
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 __str__(self):
|
||||
return 'logger %s, flags %x' % (self._printer, self._flags)
|
||||
|
||||
def __call__(self, msg):
|
||||
self._printer(msg)
|
||||
|
||||
def __and__(self, flag):
|
||||
return self._flags & flag
|
||||
|
||||
def __rand__(self, flag):
|
||||
return flag & self._flags
|
||||
|
||||
_LOG = DEBUG_NONE
|
||||
|
||||
|
||||
def setLogger(userLogger):
|
||||
global _LOG
|
||||
|
||||
if userLogger:
|
||||
_LOG = userLogger
|
||||
else:
|
||||
_LOG = DEBUG_NONE
|
||||
|
||||
# Update registered logging clients
|
||||
for module, (name, flags) in LOGGEE_MAP.items():
|
||||
setattr(module, name, _LOG & flags and _LOG or DEBUG_NONE)
|
||||
|
||||
|
||||
def registerLoggee(module, name='LOG', flags=DEBUG_NONE):
|
||||
LOGGEE_MAP[sys.modules[module]] = name, flags
|
||||
setLogger(_LOG)
|
||||
return _LOG
|
||||
|
||||
|
||||
def hexdump(octets):
|
||||
return ' '.join(
|
||||
['%s%.2X' % (n % 16 == 0 and ('\n%.5d: ' % n) or '', x)
|
||||
for n, x in zip(range(len(octets)), octs2ints(octets))]
|
||||
)
|
||||
|
||||
|
||||
class Scope(object):
|
||||
def __init__(self):
|
||||
self._list = []
|
||||
|
||||
def __str__(self): return '.'.join(self._list)
|
||||
|
||||
def push(self, token):
|
||||
self._list.append(token)
|
||||
|
||||
def pop(self):
|
||||
return self._list.pop()
|
||||
|
||||
|
||||
scope = Scope()
|
75
venv/Lib/site-packages/pyasn1/error.py
Normal file
75
venv/Lib/site-packages/pyasn1/error.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
|
||||
|
||||
class PyAsn1Error(Exception):
|
||||
"""Base pyasn1 exception
|
||||
|
||||
`PyAsn1Error` is the base exception class (based on
|
||||
:class:`Exception`) that represents all possible ASN.1 related
|
||||
errors.
|
||||
"""
|
||||
|
||||
|
||||
class ValueConstraintError(PyAsn1Error):
|
||||
"""ASN.1 type constraints violation exception
|
||||
|
||||
The `ValueConstraintError` exception indicates an ASN.1 value
|
||||
constraint violation.
|
||||
|
||||
It might happen on value object instantiation (for scalar types) or on
|
||||
serialization (for constructed types).
|
||||
"""
|
||||
|
||||
|
||||
class SubstrateUnderrunError(PyAsn1Error):
|
||||
"""ASN.1 data structure deserialization error
|
||||
|
||||
The `SubstrateUnderrunError` exception indicates insufficient serialised
|
||||
data on input of a de-serialization codec.
|
||||
"""
|
||||
|
||||
|
||||
class PyAsn1UnicodeError(PyAsn1Error, UnicodeError):
|
||||
"""Unicode text processing error
|
||||
|
||||
The `PyAsn1UnicodeError` exception is a base class for errors relating to
|
||||
unicode text de/serialization.
|
||||
|
||||
Apart from inheriting from :class:`PyAsn1Error`, it also inherits from
|
||||
:class:`UnicodeError` to help the caller catching unicode-related errors.
|
||||
"""
|
||||
def __init__(self, message, unicode_error=None):
|
||||
if isinstance(unicode_error, UnicodeError):
|
||||
UnicodeError.__init__(self, *unicode_error.args)
|
||||
PyAsn1Error.__init__(self, message)
|
||||
|
||||
|
||||
class PyAsn1UnicodeDecodeError(PyAsn1UnicodeError, UnicodeDecodeError):
|
||||
"""Unicode text decoding error
|
||||
|
||||
The `PyAsn1UnicodeDecodeError` exception represents a failure to
|
||||
deserialize unicode text.
|
||||
|
||||
Apart from inheriting from :class:`PyAsn1UnicodeError`, it also inherits
|
||||
from :class:`UnicodeDecodeError` to help the caller catching unicode-related
|
||||
errors.
|
||||
"""
|
||||
|
||||
|
||||
class PyAsn1UnicodeEncodeError(PyAsn1UnicodeError, UnicodeEncodeError):
|
||||
"""Unicode text encoding error
|
||||
|
||||
The `PyAsn1UnicodeEncodeError` exception represents a failure to
|
||||
serialize unicode text.
|
||||
|
||||
Apart from inheriting from :class:`PyAsn1UnicodeError`, it also inherits
|
||||
from :class:`UnicodeEncodeError` to help the caller catching
|
||||
unicode-related errors.
|
||||
"""
|
||||
|
||||
|
1
venv/Lib/site-packages/pyasn1/type/__init__.py
Normal file
1
venv/Lib/site-packages/pyasn1/type/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is necessary to make this directory a package.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
707
venv/Lib/site-packages/pyasn1/type/base.py
Normal file
707
venv/Lib/site-packages/pyasn1/type/base.py
Normal file
|
@ -0,0 +1,707 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
import sys
|
||||
|
||||
from pyasn1 import error
|
||||
from pyasn1.compat import calling
|
||||
from pyasn1.type import constraint
|
||||
from pyasn1.type import tag
|
||||
from pyasn1.type import tagmap
|
||||
|
||||
__all__ = ['Asn1Item', 'Asn1Type', 'SimpleAsn1Type',
|
||||
'ConstructedAsn1Type']
|
||||
|
||||
|
||||
class Asn1Item(object):
|
||||
@classmethod
|
||||
def getTypeId(cls, increment=1):
|
||||
try:
|
||||
Asn1Item._typeCounter += increment
|
||||
except AttributeError:
|
||||
Asn1Item._typeCounter = increment
|
||||
return Asn1Item._typeCounter
|
||||
|
||||
|
||||
class Asn1Type(Asn1Item):
|
||||
"""Base class for all classes representing ASN.1 types.
|
||||
|
||||
In the user code, |ASN.1| class is normally used only for telling
|
||||
ASN.1 objects from others.
|
||||
|
||||
Note
|
||||
----
|
||||
For as long as ASN.1 is concerned, a way to compare ASN.1 types
|
||||
is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
|
||||
"""
|
||||
#: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing
|
||||
#: ASN.1 tag(s) associated with |ASN.1| type.
|
||||
tagSet = tag.TagSet()
|
||||
|
||||
#: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
|
||||
#: object imposing constraints on initialization values.
|
||||
subtypeSpec = constraint.ConstraintsIntersection()
|
||||
|
||||
# Disambiguation ASN.1 types identification
|
||||
typeId = None
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
readOnly = {
|
||||
'tagSet': self.tagSet,
|
||||
'subtypeSpec': self.subtypeSpec
|
||||
}
|
||||
|
||||
readOnly.update(kwargs)
|
||||
|
||||
self.__dict__.update(readOnly)
|
||||
|
||||
self._readOnly = readOnly
|
||||
|
||||
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 __str__(self):
|
||||
return self.prettyPrint()
|
||||
|
||||
@property
|
||||
def readOnly(self):
|
||||
return self._readOnly
|
||||
|
||||
@property
|
||||
def effectiveTagSet(self):
|
||||
"""For |ASN.1| type is equivalent to *tagSet*
|
||||
"""
|
||||
return self.tagSet # used by untagged types
|
||||
|
||||
@property
|
||||
def tagMap(self):
|
||||
"""Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping ASN.1 tags to ASN.1 objects within callee object.
|
||||
"""
|
||||
return tagmap.TagMap({self.tagSet: self})
|
||||
|
||||
def isSameTypeWith(self, other, matchTags=True, matchConstraints=True):
|
||||
"""Examine |ASN.1| type for equality with other ASN.1 type.
|
||||
|
||||
ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
|
||||
(:py:mod:`~pyasn1.type.constraint`) are examined when carrying
|
||||
out ASN.1 types comparison.
|
||||
|
||||
Python class inheritance relationship is NOT considered.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other: a pyasn1 type object
|
||||
Class instance representing ASN.1 type.
|
||||
|
||||
Returns
|
||||
-------
|
||||
: :class:`bool`
|
||||
:obj:`True` if *other* is |ASN.1| type,
|
||||
:obj:`False` otherwise.
|
||||
"""
|
||||
return (self is other or
|
||||
(not matchTags or self.tagSet == other.tagSet) and
|
||||
(not matchConstraints or self.subtypeSpec == other.subtypeSpec))
|
||||
|
||||
def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True):
|
||||
"""Examine |ASN.1| type for subtype relationship with other ASN.1 type.
|
||||
|
||||
ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
|
||||
(:py:mod:`~pyasn1.type.constraint`) are examined when carrying
|
||||
out ASN.1 types comparison.
|
||||
|
||||
Python class inheritance relationship is NOT considered.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other: a pyasn1 type object
|
||||
Class instance representing ASN.1 type.
|
||||
|
||||
Returns
|
||||
-------
|
||||
: :class:`bool`
|
||||
:obj:`True` if *other* is a subtype of |ASN.1| type,
|
||||
:obj:`False` otherwise.
|
||||
"""
|
||||
return (not matchTags or
|
||||
(self.tagSet.isSuperTagSetOf(other.tagSet)) and
|
||||
(not matchConstraints or self.subtypeSpec.isSuperTypeOf(other.subtypeSpec)))
|
||||
|
||||
@staticmethod
|
||||
def isNoValue(*values):
|
||||
for value in values:
|
||||
if value is not noValue:
|
||||
return False
|
||||
return True
|
||||
|
||||
def prettyPrint(self, scope=0):
|
||||
raise NotImplementedError()
|
||||
|
||||
# backward compatibility
|
||||
|
||||
def getTagSet(self):
|
||||
return self.tagSet
|
||||
|
||||
def getEffectiveTagSet(self):
|
||||
return self.effectiveTagSet
|
||||
|
||||
def getTagMap(self):
|
||||
return self.tagMap
|
||||
|
||||
def getSubtypeSpec(self):
|
||||
return self.subtypeSpec
|
||||
|
||||
# backward compatibility
|
||||
def hasValue(self):
|
||||
return self.isValue
|
||||
|
||||
# Backward compatibility
|
||||
Asn1ItemBase = Asn1Type
|
||||
|
||||
|
||||
class NoValue(object):
|
||||
"""Create a singleton instance of NoValue class.
|
||||
|
||||
The *NoValue* sentinel object represents an instance of ASN.1 schema
|
||||
object as opposed to ASN.1 value object.
|
||||
|
||||
Only ASN.1 schema-related operations can be performed on ASN.1
|
||||
schema objects.
|
||||
|
||||
Warning
|
||||
-------
|
||||
Any operation attempted on the *noValue* object will raise the
|
||||
*PyAsn1Error* exception.
|
||||
"""
|
||||
skipMethods = set(
|
||||
('__slots__',
|
||||
# attributes
|
||||
'__getattribute__',
|
||||
'__getattr__',
|
||||
'__setattr__',
|
||||
'__delattr__',
|
||||
# class instance
|
||||
'__class__',
|
||||
'__init__',
|
||||
'__del__',
|
||||
'__new__',
|
||||
'__repr__',
|
||||
'__qualname__',
|
||||
'__objclass__',
|
||||
'im_class',
|
||||
'__sizeof__',
|
||||
# pickle protocol
|
||||
'__reduce__',
|
||||
'__reduce_ex__',
|
||||
'__getnewargs__',
|
||||
'__getinitargs__',
|
||||
'__getstate__',
|
||||
'__setstate__')
|
||||
)
|
||||
|
||||
_instance = None
|
||||
|
||||
def __new__(cls):
|
||||
if cls._instance is None:
|
||||
def getPlug(name):
|
||||
def plug(self, *args, **kw):
|
||||
raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name)
|
||||
return plug
|
||||
|
||||
op_names = [name
|
||||
for typ in (str, int, list, dict)
|
||||
for name in dir(typ)
|
||||
if (name not in cls.skipMethods and
|
||||
name.startswith('__') and
|
||||
name.endswith('__') and
|
||||
calling.callable(getattr(typ, name)))]
|
||||
|
||||
for name in set(op_names):
|
||||
setattr(cls, name, getPlug(name))
|
||||
|
||||
cls._instance = object.__new__(cls)
|
||||
|
||||
return cls._instance
|
||||
|
||||
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 __repr__(self):
|
||||
return '<%s object>' % self.__class__.__name__
|
||||
|
||||
|
||||
noValue = NoValue()
|
||||
|
||||
|
||||
class SimpleAsn1Type(Asn1Type):
|
||||
"""Base class for all simple classes representing ASN.1 types.
|
||||
|
||||
ASN.1 distinguishes types by their ability to hold other objects.
|
||||
Scalar types are known as *simple* in ASN.1.
|
||||
|
||||
In the user code, |ASN.1| class is normally used only for telling
|
||||
ASN.1 objects from others.
|
||||
|
||||
Note
|
||||
----
|
||||
For as long as ASN.1 is concerned, a way to compare ASN.1 types
|
||||
is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
|
||||
"""
|
||||
#: Default payload value
|
||||
defaultValue = noValue
|
||||
|
||||
def __init__(self, value=noValue, **kwargs):
|
||||
Asn1Type.__init__(self, **kwargs)
|
||||
if value is noValue:
|
||||
value = self.defaultValue
|
||||
else:
|
||||
value = self.prettyIn(value)
|
||||
try:
|
||||
self.subtypeSpec(value)
|
||||
|
||||
except error.PyAsn1Error:
|
||||
exType, exValue, exTb = sys.exc_info()
|
||||
raise exType('%s at %s' % (exValue, self.__class__.__name__))
|
||||
|
||||
self._value = value
|
||||
|
||||
def __repr__(self):
|
||||
representation = '%s %s object' % (
|
||||
self.__class__.__name__, self.isValue and 'value' or 'schema')
|
||||
|
||||
for attr, value in self.readOnly.items():
|
||||
if value:
|
||||
representation += ', %s %s' % (attr, value)
|
||||
|
||||
if self.isValue:
|
||||
value = self.prettyPrint()
|
||||
if len(value) > 32:
|
||||
value = value[:16] + '...' + value[-16:]
|
||||
representation += ', payload [%s]' % value
|
||||
|
||||
return '<%s>' % representation
|
||||
|
||||
def __eq__(self, other):
|
||||
return self is other and True or self._value == other
|
||||
|
||||
def __ne__(self, other):
|
||||
return self._value != other
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._value < other
|
||||
|
||||
def __le__(self, other):
|
||||
return self._value <= other
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._value > other
|
||||
|
||||
def __ge__(self, other):
|
||||
return self._value >= other
|
||||
|
||||
if sys.version_info[0] <= 2:
|
||||
def __nonzero__(self):
|
||||
return self._value and True or False
|
||||
else:
|
||||
def __bool__(self):
|
||||
return self._value and True or False
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self._value)
|
||||
|
||||
@property
|
||||
def isValue(self):
|
||||
"""Indicate that |ASN.1| object represents ASN.1 value.
|
||||
|
||||
If *isValue* is :obj:`False` then this object represents just
|
||||
ASN.1 schema.
|
||||
|
||||
If *isValue* is :obj:`True` then, in addition to its ASN.1 schema
|
||||
features, this object can also be used like a Python built-in object
|
||||
(e.g. :class:`int`, :class:`str`, :class:`dict` etc.).
|
||||
|
||||
Returns
|
||||
-------
|
||||
: :class:`bool`
|
||||
:obj:`False` if object represents just ASN.1 schema.
|
||||
:obj:`True` if object represents ASN.1 schema and can be used as a normal value.
|
||||
|
||||
Note
|
||||
----
|
||||
There is an important distinction between PyASN1 schema and value objects.
|
||||
The PyASN1 schema objects can only participate in ASN.1 schema-related
|
||||
operations (e.g. defining or testing the structure of the data). Most
|
||||
obvious uses of ASN.1 schema is to guide serialisation codecs whilst
|
||||
encoding/decoding serialised ASN.1 contents.
|
||||
|
||||
The PyASN1 value objects can **additionally** participate in many operations
|
||||
involving regular Python objects (e.g. arithmetic, comprehension etc).
|
||||
"""
|
||||
return self._value is not noValue
|
||||
|
||||
def clone(self, value=noValue, **kwargs):
|
||||
"""Create a modified version of |ASN.1| schema or value object.
|
||||
|
||||
The `clone()` method accepts the same set arguments as |ASN.1|
|
||||
class takes on instantiation except that all arguments
|
||||
of the `clone()` method are optional.
|
||||
|
||||
Whatever arguments are supplied, they are used to create a copy
|
||||
of `self` taking precedence over the ones used to instantiate `self`.
|
||||
|
||||
Note
|
||||
----
|
||||
Due to the immutable nature of the |ASN.1| object, if no arguments
|
||||
are supplied, no new |ASN.1| object will be created and `self` will
|
||||
be returned instead.
|
||||
"""
|
||||
if value is noValue:
|
||||
if not kwargs:
|
||||
return self
|
||||
|
||||
value = self._value
|
||||
|
||||
initializers = self.readOnly.copy()
|
||||
initializers.update(kwargs)
|
||||
|
||||
return self.__class__(value, **initializers)
|
||||
|
||||
def subtype(self, value=noValue, **kwargs):
|
||||
"""Create a specialization of |ASN.1| schema or value object.
|
||||
|
||||
The subtype relationship between ASN.1 types has no correlation with
|
||||
subtype relationship between Python types. ASN.1 type is mainly identified
|
||||
by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range
|
||||
constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`).
|
||||
These ASN.1 type properties are implemented as |ASN.1| attributes.
|
||||
|
||||
The `subtype()` method accepts the same set arguments as |ASN.1|
|
||||
class takes on instantiation except that all parameters
|
||||
of the `subtype()` method are optional.
|
||||
|
||||
With the exception of the arguments described below, the rest of
|
||||
supplied arguments they are used to create a copy of `self` taking
|
||||
precedence over the ones used to instantiate `self`.
|
||||
|
||||
The following arguments to `subtype()` create a ASN.1 subtype out of
|
||||
|ASN.1| type:
|
||||
|
||||
Other Parameters
|
||||
----------------
|
||||
implicitTag: :py:class:`~pyasn1.type.tag.Tag`
|
||||
Implicitly apply given ASN.1 tag object to `self`'s
|
||||
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
|
||||
new object's ASN.1 tag(s).
|
||||
|
||||
explicitTag: :py:class:`~pyasn1.type.tag.Tag`
|
||||
Explicitly apply given ASN.1 tag object to `self`'s
|
||||
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
|
||||
new object's ASN.1 tag(s).
|
||||
|
||||
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
|
||||
Add ASN.1 constraints object to one of the `self`'s, then
|
||||
use the result as new object's ASN.1 constraints.
|
||||
|
||||
Returns
|
||||
-------
|
||||
:
|
||||
new instance of |ASN.1| schema or value object
|
||||
|
||||
Note
|
||||
----
|
||||
Due to the immutable nature of the |ASN.1| object, if no arguments
|
||||
are supplied, no new |ASN.1| object will be created and `self` will
|
||||
be returned instead.
|
||||
"""
|
||||
if value is noValue:
|
||||
if not kwargs:
|
||||
return self
|
||||
|
||||
value = self._value
|
||||
|
||||
initializers = self.readOnly.copy()
|
||||
|
||||
implicitTag = kwargs.pop('implicitTag', None)
|
||||
if implicitTag is not None:
|
||||
initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
|
||||
|
||||
explicitTag = kwargs.pop('explicitTag', None)
|
||||
if explicitTag is not None:
|
||||
initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
|
||||
|
||||
for arg, option in kwargs.items():
|
||||
initializers[arg] += option
|
||||
|
||||
return self.__class__(value, **initializers)
|
||||
|
||||
def prettyIn(self, value):
|
||||
return value
|
||||
|
||||
def prettyOut(self, value):
|
||||
return str(value)
|
||||
|
||||
def prettyPrint(self, scope=0):
|
||||
return self.prettyOut(self._value)
|
||||
|
||||
def prettyPrintType(self, scope=0):
|
||||
return '%s -> %s' % (self.tagSet, self.__class__.__name__)
|
||||
|
||||
# Backward compatibility
|
||||
AbstractSimpleAsn1Item = SimpleAsn1Type
|
||||
|
||||
#
|
||||
# Constructed types:
|
||||
# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice
|
||||
# * ASN1 types and values are represened by Python class instances
|
||||
# * Value initialization is made for defaulted components only
|
||||
# * Primary method of component addressing is by-position. Data model for base
|
||||
# type is Python sequence. Additional type-specific addressing methods
|
||||
# may be implemented for particular types.
|
||||
# * SequenceOf and SetOf types do not implement any additional methods
|
||||
# * Sequence, Set and Choice types also implement by-identifier addressing
|
||||
# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing
|
||||
# * Sequence and Set types may include optional and defaulted
|
||||
# components
|
||||
# * Constructed types hold a reference to component types used for value
|
||||
# verification and ordering.
|
||||
# * Component type is a scalar type for SequenceOf/SetOf types and a list
|
||||
# of types for Sequence/Set/Choice.
|
||||
#
|
||||
|
||||
|
||||
class ConstructedAsn1Type(Asn1Type):
|
||||
"""Base class for all constructed classes representing ASN.1 types.
|
||||
|
||||
ASN.1 distinguishes types by their ability to hold other objects.
|
||||
Those "nesting" types are known as *constructed* in ASN.1.
|
||||
|
||||
In the user code, |ASN.1| class is normally used only for telling
|
||||
ASN.1 objects from others.
|
||||
|
||||
Note
|
||||
----
|
||||
For as long as ASN.1 is concerned, a way to compare ASN.1 types
|
||||
is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
|
||||
"""
|
||||
|
||||
#: If :obj:`True`, requires exact component type matching,
|
||||
#: otherwise subtype relation is only enforced
|
||||
strictConstraints = False
|
||||
|
||||
componentType = None
|
||||
|
||||
# backward compatibility, unused
|
||||
sizeSpec = constraint.ConstraintsIntersection()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
readOnly = {
|
||||
'componentType': self.componentType,
|
||||
# backward compatibility, unused
|
||||
'sizeSpec': self.sizeSpec
|
||||
}
|
||||
|
||||
# backward compatibility: preserve legacy sizeSpec support
|
||||
kwargs = self._moveSizeSpec(**kwargs)
|
||||
|
||||
readOnly.update(kwargs)
|
||||
|
||||
Asn1Type.__init__(self, **readOnly)
|
||||
|
||||
def _moveSizeSpec(self, **kwargs):
|
||||
# backward compatibility, unused
|
||||
sizeSpec = kwargs.pop('sizeSpec', self.sizeSpec)
|
||||
if sizeSpec:
|
||||
subtypeSpec = kwargs.pop('subtypeSpec', self.subtypeSpec)
|
||||
if subtypeSpec:
|
||||
subtypeSpec = sizeSpec
|
||||
|
||||
else:
|
||||
subtypeSpec += sizeSpec
|
||||
|
||||
kwargs['subtypeSpec'] = subtypeSpec
|
||||
|
||||
return kwargs
|
||||
|
||||
def __repr__(self):
|
||||
representation = '%s %s object' % (
|
||||
self.__class__.__name__, self.isValue and 'value' or 'schema'
|
||||
)
|
||||
|
||||
for attr, value in self.readOnly.items():
|
||||
if value is not noValue:
|
||||
representation += ', %s=%r' % (attr, value)
|
||||
|
||||
if self.isValue and self.components:
|
||||
representation += ', payload [%s]' % ', '.join(
|
||||
[repr(x) for x in self.components])
|
||||
|
||||
return '<%s>' % representation
|
||||
|
||||
def __eq__(self, other):
|
||||
return self is other or self.components == other
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.components != other
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.components < other
|
||||
|
||||
def __le__(self, other):
|
||||
return self.components <= other
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.components > other
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.components >= other
|
||||
|
||||
if sys.version_info[0] <= 2:
|
||||
def __nonzero__(self):
|
||||
return bool(self.components)
|
||||
else:
|
||||
def __bool__(self):
|
||||
return bool(self.components)
|
||||
|
||||
@property
|
||||
def components(self):
|
||||
raise error.PyAsn1Error('Method not implemented')
|
||||
|
||||
def _cloneComponentValues(self, myClone, cloneValueFlag):
|
||||
pass
|
||||
|
||||
def clone(self, **kwargs):
|
||||
"""Create a modified version of |ASN.1| schema object.
|
||||
|
||||
The `clone()` method accepts the same set arguments as |ASN.1|
|
||||
class takes on instantiation except that all arguments
|
||||
of the `clone()` method are optional.
|
||||
|
||||
Whatever arguments are supplied, they are used to create a copy
|
||||
of `self` taking precedence over the ones used to instantiate `self`.
|
||||
|
||||
Possible values of `self` are never copied over thus `clone()` can
|
||||
only create a new schema object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
:
|
||||
new instance of |ASN.1| type/value
|
||||
|
||||
Note
|
||||
----
|
||||
Due to the mutable nature of the |ASN.1| object, even if no arguments
|
||||
are supplied, a new |ASN.1| object will be created and returned.
|
||||
"""
|
||||
cloneValueFlag = kwargs.pop('cloneValueFlag', False)
|
||||
|
||||
initializers = self.readOnly.copy()
|
||||
initializers.update(kwargs)
|
||||
|
||||
clone = self.__class__(**initializers)
|
||||
|
||||
if cloneValueFlag:
|
||||
self._cloneComponentValues(clone, cloneValueFlag)
|
||||
|
||||
return clone
|
||||
|
||||
def subtype(self, **kwargs):
|
||||
"""Create a specialization of |ASN.1| schema object.
|
||||
|
||||
The `subtype()` method accepts the same set arguments as |ASN.1|
|
||||
class takes on instantiation except that all parameters
|
||||
of the `subtype()` method are optional.
|
||||
|
||||
With the exception of the arguments described below, the rest of
|
||||
supplied arguments they are used to create a copy of `self` taking
|
||||
precedence over the ones used to instantiate `self`.
|
||||
|
||||
The following arguments to `subtype()` create a ASN.1 subtype out of
|
||||
|ASN.1| type.
|
||||
|
||||
Other Parameters
|
||||
----------------
|
||||
implicitTag: :py:class:`~pyasn1.type.tag.Tag`
|
||||
Implicitly apply given ASN.1 tag object to `self`'s
|
||||
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
|
||||
new object's ASN.1 tag(s).
|
||||
|
||||
explicitTag: :py:class:`~pyasn1.type.tag.Tag`
|
||||
Explicitly apply given ASN.1 tag object to `self`'s
|
||||
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
|
||||
new object's ASN.1 tag(s).
|
||||
|
||||
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
|
||||
Add ASN.1 constraints object to one of the `self`'s, then
|
||||
use the result as new object's ASN.1 constraints.
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
:
|
||||
new instance of |ASN.1| type/value
|
||||
|
||||
Note
|
||||
----
|
||||
Due to the mutable nature of the |ASN.1| object, even if no arguments
|
||||
are supplied, a new |ASN.1| object will be created and returned.
|
||||
"""
|
||||
|
||||
initializers = self.readOnly.copy()
|
||||
|
||||
cloneValueFlag = kwargs.pop('cloneValueFlag', False)
|
||||
|
||||
implicitTag = kwargs.pop('implicitTag', None)
|
||||
if implicitTag is not None:
|
||||
initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
|
||||
|
||||
explicitTag = kwargs.pop('explicitTag', None)
|
||||
if explicitTag is not None:
|
||||
initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
|
||||
|
||||
for arg, option in kwargs.items():
|
||||
initializers[arg] += option
|
||||
|
||||
clone = self.__class__(**initializers)
|
||||
|
||||
if cloneValueFlag:
|
||||
self._cloneComponentValues(clone, cloneValueFlag)
|
||||
|
||||
return clone
|
||||
|
||||
def getComponentByPosition(self, idx):
|
||||
raise error.PyAsn1Error('Method not implemented')
|
||||
|
||||
def setComponentByPosition(self, idx, value, verifyConstraints=True):
|
||||
raise error.PyAsn1Error('Method not implemented')
|
||||
|
||||
def setComponents(self, *args, **kwargs):
|
||||
for idx, value in enumerate(args):
|
||||
self[idx] = value
|
||||
for k in kwargs:
|
||||
self[k] = kwargs[k]
|
||||
return self
|
||||
|
||||
# backward compatibility
|
||||
|
||||
def setDefaultComponents(self):
|
||||
pass
|
||||
|
||||
def getComponentType(self):
|
||||
return self.componentType
|
||||
|
||||
# backward compatibility, unused
|
||||
def verifySizeSpec(self):
|
||||
self.subtypeSpec(self)
|
||||
|
||||
|
||||
# Backward compatibility
|
||||
AbstractConstructedAsn1Item = ConstructedAsn1Type
|
335
venv/Lib/site-packages/pyasn1/type/char.py
Normal file
335
venv/Lib/site-packages/pyasn1/type/char.py
Normal file
|
@ -0,0 +1,335 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
import sys
|
||||
|
||||
from pyasn1 import error
|
||||
from pyasn1.type import tag
|
||||
from pyasn1.type import univ
|
||||
|
||||
__all__ = ['NumericString', 'PrintableString', 'TeletexString', 'T61String', 'VideotexString',
|
||||
'IA5String', 'GraphicString', 'VisibleString', 'ISO646String',
|
||||
'GeneralString', 'UniversalString', 'BMPString', 'UTF8String']
|
||||
|
||||
NoValue = univ.NoValue
|
||||
noValue = univ.noValue
|
||||
|
||||
|
||||
class AbstractCharacterString(univ.OctetString):
|
||||
"""Creates |ASN.1| schema or value object.
|
||||
|
||||
|ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`,
|
||||
its objects are immutable and duck-type Python 2 :class:`str` or Python 3
|
||||
:class:`bytes`. When used in octet-stream context, |ASN.1| type assumes
|
||||
"|encoding|" encoding.
|
||||
|
||||
Keyword Args
|
||||
------------
|
||||
value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object
|
||||
:class:`unicode` object (Python 2) or :class:`str` (Python 3),
|
||||
alternatively :class:`str` (Python 2) or :class:`bytes` (Python 3)
|
||||
representing octet-stream of serialised unicode string
|
||||
(note `encoding` parameter) or |ASN.1| class instance.
|
||||
If `value` is not given, schema object will be created.
|
||||
|
||||
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
|
||||
Object representing non-default ASN.1 tag(s)
|
||||
|
||||
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
|
||||
Object representing non-default ASN.1 subtype constraint(s). Constraints
|
||||
verification for |ASN.1| type occurs automatically on object
|
||||
instantiation.
|
||||
|
||||
encoding: :py:class:`str`
|
||||
Unicode codec ID to encode/decode :class:`unicode` (Python 2) or
|
||||
:class:`str` (Python 3) the payload when |ASN.1| object is used
|
||||
in octet-stream context.
|
||||
|
||||
Raises
|
||||
------
|
||||
~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
|
||||
On constraint violation or bad initializer.
|
||||
"""
|
||||
|
||||
if sys.version_info[0] <= 2:
|
||||
def __str__(self):
|
||||
try:
|
||||
# `str` is Py2 text representation
|
||||
return self._value.encode(self.encoding)
|
||||
|
||||
except UnicodeEncodeError:
|
||||
exc = sys.exc_info()[1]
|
||||
raise error.PyAsn1UnicodeEncodeError(
|
||||
"Can't encode string '%s' with codec "
|
||||
"%s" % (self._value, self.encoding), exc
|
||||
)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self._value)
|
||||
|
||||
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):
|
||||
exc = sys.exc_info()[1]
|
||||
raise error.PyAsn1UnicodeDecodeError(
|
||||
"Can't decode string '%s' with codec "
|
||||
"%s" % (value, self.encoding), exc
|
||||
)
|
||||
|
||||
def asOctets(self, padding=True):
|
||||
return str(self)
|
||||
|
||||
def asNumbers(self, padding=True):
|
||||
return tuple([ord(x) for x in str(self)])
|
||||
|
||||
else:
|
||||
def __str__(self):
|
||||
# `unicode` is Py3 text representation
|
||||
return str(self._value)
|
||||
|
||||
def __bytes__(self):
|
||||
try:
|
||||
return self._value.encode(self.encoding)
|
||||
except UnicodeEncodeError:
|
||||
exc = sys.exc_info()[1]
|
||||
raise error.PyAsn1UnicodeEncodeError(
|
||||
"Can't encode string '%s' with codec "
|
||||
"%s" % (self._value, self.encoding), exc
|
||||
)
|
||||
|
||||
def prettyIn(self, value):
|
||||
try:
|
||||
if isinstance(value, str):
|
||||
return value
|
||||
elif isinstance(value, bytes):
|
||||
return value.decode(self.encoding)
|
||||
elif isinstance(value, (tuple, list)):
|
||||
return self.prettyIn(bytes(value))
|
||||
elif isinstance(value, univ.OctetString):
|
||||
return value.asOctets().decode(self.encoding)
|
||||
else:
|
||||
return str(value)
|
||||
|
||||
except (UnicodeDecodeError, LookupError):
|
||||
exc = sys.exc_info()[1]
|
||||
raise error.PyAsn1UnicodeDecodeError(
|
||||
"Can't decode string '%s' with codec "
|
||||
"%s" % (value, self.encoding), exc
|
||||
)
|
||||
|
||||
def asOctets(self, padding=True):
|
||||
return bytes(self)
|
||||
|
||||
def asNumbers(self, padding=True):
|
||||
return tuple(bytes(self))
|
||||
|
||||
#
|
||||
# See OctetString.prettyPrint() for the explanation
|
||||
#
|
||||
|
||||
def prettyOut(self, value):
|
||||
return value
|
||||
|
||||
def prettyPrint(self, scope=0):
|
||||
# first see if subclass has its own .prettyOut()
|
||||
value = self.prettyOut(self._value)
|
||||
|
||||
if value is not self._value:
|
||||
return value
|
||||
|
||||
return AbstractCharacterString.__str__(self)
|
||||
|
||||
def __reversed__(self):
|
||||
return reversed(self._value)
|
||||
|
||||
|
||||
class NumericString(AbstractCharacterString):
|
||||
__doc__ = AbstractCharacterString.__doc__
|
||||
|
||||
#: Set (on class, not on instance) or return a
|
||||
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
|
||||
#: associated with |ASN.1| type.
|
||||
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 18)
|
||||
)
|
||||
encoding = 'us-ascii'
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
|
||||
class PrintableString(AbstractCharacterString):
|
||||
__doc__ = AbstractCharacterString.__doc__
|
||||
|
||||
#: Set (on class, not on instance) or return a
|
||||
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
|
||||
#: associated with |ASN.1| type.
|
||||
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 19)
|
||||
)
|
||||
encoding = 'us-ascii'
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
|
||||
class TeletexString(AbstractCharacterString):
|
||||
__doc__ = AbstractCharacterString.__doc__
|
||||
|
||||
#: Set (on class, not on instance) or return a
|
||||
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
|
||||
#: associated with |ASN.1| type.
|
||||
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 20)
|
||||
)
|
||||
encoding = 'iso-8859-1'
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
|
||||
class T61String(TeletexString):
|
||||
__doc__ = TeletexString.__doc__
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
|
||||
class VideotexString(AbstractCharacterString):
|
||||
__doc__ = AbstractCharacterString.__doc__
|
||||
|
||||
#: Set (on class, not on instance) or return a
|
||||
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
|
||||
#: associated with |ASN.1| type.
|
||||
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 21)
|
||||
)
|
||||
encoding = 'iso-8859-1'
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
|
||||
class IA5String(AbstractCharacterString):
|
||||
__doc__ = AbstractCharacterString.__doc__
|
||||
|
||||
#: Set (on class, not on instance) or return a
|
||||
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
|
||||
#: associated with |ASN.1| type.
|
||||
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 22)
|
||||
)
|
||||
encoding = 'us-ascii'
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
|
||||
class GraphicString(AbstractCharacterString):
|
||||
__doc__ = AbstractCharacterString.__doc__
|
||||
|
||||
#: Set (on class, not on instance) or return a
|
||||
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
|
||||
#: associated with |ASN.1| type.
|
||||
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 25)
|
||||
)
|
||||
encoding = 'iso-8859-1'
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
|
||||
class VisibleString(AbstractCharacterString):
|
||||
__doc__ = AbstractCharacterString.__doc__
|
||||
|
||||
#: Set (on class, not on instance) or return a
|
||||
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
|
||||
#: associated with |ASN.1| type.
|
||||
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 26)
|
||||
)
|
||||
encoding = 'us-ascii'
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
|
||||
class ISO646String(VisibleString):
|
||||
__doc__ = VisibleString.__doc__
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
class GeneralString(AbstractCharacterString):
|
||||
__doc__ = AbstractCharacterString.__doc__
|
||||
|
||||
#: Set (on class, not on instance) or return a
|
||||
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
|
||||
#: associated with |ASN.1| type.
|
||||
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 27)
|
||||
)
|
||||
encoding = 'iso-8859-1'
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
|
||||
class UniversalString(AbstractCharacterString):
|
||||
__doc__ = AbstractCharacterString.__doc__
|
||||
|
||||
#: Set (on class, not on instance) or return a
|
||||
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
|
||||
#: associated with |ASN.1| type.
|
||||
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 28)
|
||||
)
|
||||
encoding = "utf-32-be"
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
|
||||
class BMPString(AbstractCharacterString):
|
||||
__doc__ = AbstractCharacterString.__doc__
|
||||
|
||||
#: Set (on class, not on instance) or return a
|
||||
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
|
||||
#: associated with |ASN.1| type.
|
||||
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 30)
|
||||
)
|
||||
encoding = "utf-16-be"
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
||||
|
||||
|
||||
class UTF8String(AbstractCharacterString):
|
||||
__doc__ = AbstractCharacterString.__doc__
|
||||
|
||||
#: Set (on class, not on instance) or return a
|
||||
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
|
||||
#: associated with |ASN.1| type.
|
||||
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12)
|
||||
)
|
||||
encoding = "utf-8"
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = AbstractCharacterString.getTypeId()
|
756
venv/Lib/site-packages/pyasn1/type/constraint.py
Normal file
756
venv/Lib/site-packages/pyasn1/type/constraint.py
Normal file
|
@ -0,0 +1,756 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
# Original concept and code by Mike C. Fletcher.
|
||||
#
|
||||
import sys
|
||||
|
||||
from pyasn1.type import error
|
||||
|
||||
__all__ = ['SingleValueConstraint', 'ContainedSubtypeConstraint',
|
||||
'ValueRangeConstraint', 'ValueSizeConstraint',
|
||||
'PermittedAlphabetConstraint', 'InnerTypeConstraint',
|
||||
'ConstraintsExclusion', 'ConstraintsIntersection',
|
||||
'ConstraintsUnion']
|
||||
|
||||
|
||||
class AbstractConstraint(object):
|
||||
|
||||
def __init__(self, *values):
|
||||
self._valueMap = set()
|
||||
self._setValues(values)
|
||||
self.__hash = hash((self.__class__.__name__, self._values))
|
||||
|
||||
def __call__(self, value, idx=None):
|
||||
if not self._values:
|
||||
return
|
||||
|
||||
try:
|
||||
self._testValue(value, idx)
|
||||
|
||||
except error.ValueConstraintError:
|
||||
raise error.ValueConstraintError(
|
||||
'%s failed at: %r' % (self, sys.exc_info()[1])
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
representation = '%s object' % (self.__class__.__name__)
|
||||
|
||||
if self._values:
|
||||
representation += ', consts %s' % ', '.join(
|
||||
[repr(x) for x in self._values])
|
||||
|
||||
return '<%s>' % representation
|
||||
|
||||
def __eq__(self, other):
|
||||
return self is other and True or self._values == other
|
||||
|
||||
def __ne__(self, other):
|
||||
return self._values != other
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._values < other
|
||||
|
||||
def __le__(self, other):
|
||||
return self._values <= other
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._values > other
|
||||
|
||||
def __ge__(self, other):
|
||||
return self._values >= other
|
||||
|
||||
if sys.version_info[0] <= 2:
|
||||
def __nonzero__(self):
|
||||
return self._values and True or False
|
||||
else:
|
||||
def __bool__(self):
|
||||
return self._values and True or False
|
||||
|
||||
def __hash__(self):
|
||||
return self.__hash
|
||||
|
||||
def _setValues(self, values):
|
||||
self._values = values
|
||||
|
||||
def _testValue(self, value, idx):
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
# Constraints derivation logic
|
||||
def getValueMap(self):
|
||||
return self._valueMap
|
||||
|
||||
def isSuperTypeOf(self, otherConstraint):
|
||||
# TODO: fix possible comparison of set vs scalars here
|
||||
return (otherConstraint is self or
|
||||
not self._values or
|
||||
otherConstraint == self or
|
||||
self in otherConstraint.getValueMap())
|
||||
|
||||
def isSubTypeOf(self, otherConstraint):
|
||||
return (otherConstraint is self or
|
||||
not self or
|
||||
otherConstraint == self or
|
||||
otherConstraint in self._valueMap)
|
||||
|
||||
|
||||
class SingleValueConstraint(AbstractConstraint):
|
||||
"""Create a SingleValueConstraint object.
|
||||
|
||||
The SingleValueConstraint satisfies any value that
|
||||
is present in the set of permitted values.
|
||||
|
||||
Objects of this type are iterable (emitting constraint values) and
|
||||
can act as operands for some arithmetic operations e.g. addition
|
||||
and subtraction. The latter can be used for combining multiple
|
||||
SingleValueConstraint objects into one.
|
||||
|
||||
The SingleValueConstraint object can be applied to
|
||||
any ASN.1 type.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*values: :class:`int`
|
||||
Full set of values permitted by this constraint object.
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code-block:: python
|
||||
|
||||
class DivisorOfSix(Integer):
|
||||
'''
|
||||
ASN.1 specification:
|
||||
|
||||
Divisor-Of-6 ::= INTEGER (1 | 2 | 3 | 6)
|
||||
'''
|
||||
subtypeSpec = SingleValueConstraint(1, 2, 3, 6)
|
||||
|
||||
# this will succeed
|
||||
divisor_of_six = DivisorOfSix(1)
|
||||
|
||||
# this will raise ValueConstraintError
|
||||
divisor_of_six = DivisorOfSix(7)
|
||||
"""
|
||||
def _setValues(self, values):
|
||||
self._values = values
|
||||
self._set = set(values)
|
||||
|
||||
def _testValue(self, value, idx):
|
||||
if value not in self._set:
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
# Constrains can be merged or reduced
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self._set
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._set)
|
||||
|
||||
def __sub__(self, constraint):
|
||||
return self.__class__(*(self._set.difference(constraint)))
|
||||
|
||||
def __add__(self, constraint):
|
||||
return self.__class__(*(self._set.union(constraint)))
|
||||
|
||||
def __sub__(self, constraint):
|
||||
return self.__class__(*(self._set.difference(constraint)))
|
||||
|
||||
|
||||
class ContainedSubtypeConstraint(AbstractConstraint):
|
||||
"""Create a ContainedSubtypeConstraint object.
|
||||
|
||||
The ContainedSubtypeConstraint satisfies any value that
|
||||
is present in the set of permitted values and also
|
||||
satisfies included constraints.
|
||||
|
||||
The ContainedSubtypeConstraint object can be applied to
|
||||
any ASN.1 type.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*values:
|
||||
Full set of values and constraint objects permitted
|
||||
by this constraint object.
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code-block:: python
|
||||
|
||||
class DivisorOfEighteen(Integer):
|
||||
'''
|
||||
ASN.1 specification:
|
||||
|
||||
Divisors-of-18 ::= INTEGER (INCLUDES Divisors-of-6 | 9 | 18)
|
||||
'''
|
||||
subtypeSpec = ContainedSubtypeConstraint(
|
||||
SingleValueConstraint(1, 2, 3, 6), 9, 18
|
||||
)
|
||||
|
||||
# this will succeed
|
||||
divisor_of_eighteen = DivisorOfEighteen(9)
|
||||
|
||||
# this will raise ValueConstraintError
|
||||
divisor_of_eighteen = DivisorOfEighteen(10)
|
||||
"""
|
||||
def _testValue(self, value, idx):
|
||||
for constraint in self._values:
|
||||
if isinstance(constraint, AbstractConstraint):
|
||||
constraint(value, idx)
|
||||
elif value not in self._set:
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
|
||||
class ValueRangeConstraint(AbstractConstraint):
|
||||
"""Create a ValueRangeConstraint object.
|
||||
|
||||
The ValueRangeConstraint satisfies any value that
|
||||
falls in the range of permitted values.
|
||||
|
||||
The ValueRangeConstraint object can only be applied
|
||||
to :class:`~pyasn1.type.univ.Integer` and
|
||||
:class:`~pyasn1.type.univ.Real` types.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
start: :class:`int`
|
||||
Minimum permitted value in the range (inclusive)
|
||||
|
||||
end: :class:`int`
|
||||
Maximum permitted value in the range (inclusive)
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code-block:: python
|
||||
|
||||
class TeenAgeYears(Integer):
|
||||
'''
|
||||
ASN.1 specification:
|
||||
|
||||
TeenAgeYears ::= INTEGER (13 .. 19)
|
||||
'''
|
||||
subtypeSpec = ValueRangeConstraint(13, 19)
|
||||
|
||||
# this will succeed
|
||||
teen_year = TeenAgeYears(18)
|
||||
|
||||
# this will raise ValueConstraintError
|
||||
teen_year = TeenAgeYears(20)
|
||||
"""
|
||||
def _testValue(self, value, idx):
|
||||
if value < self.start or value > self.stop:
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
def _setValues(self, values):
|
||||
if len(values) != 2:
|
||||
raise error.PyAsn1Error(
|
||||
'%s: bad constraint values' % (self.__class__.__name__,)
|
||||
)
|
||||
self.start, self.stop = values
|
||||
if self.start > self.stop:
|
||||
raise error.PyAsn1Error(
|
||||
'%s: screwed constraint values (start > stop): %s > %s' % (
|
||||
self.__class__.__name__,
|
||||
self.start, self.stop
|
||||
)
|
||||
)
|
||||
AbstractConstraint._setValues(self, values)
|
||||
|
||||
|
||||
class ValueSizeConstraint(ValueRangeConstraint):
|
||||
"""Create a ValueSizeConstraint object.
|
||||
|
||||
The ValueSizeConstraint satisfies any value for
|
||||
as long as its size falls within the range of
|
||||
permitted sizes.
|
||||
|
||||
The ValueSizeConstraint object can be applied
|
||||
to :class:`~pyasn1.type.univ.BitString`,
|
||||
:class:`~pyasn1.type.univ.OctetString` (including
|
||||
all :ref:`character ASN.1 types <type.char>`),
|
||||
:class:`~pyasn1.type.univ.SequenceOf`
|
||||
and :class:`~pyasn1.type.univ.SetOf` types.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
minimum: :class:`int`
|
||||
Minimum permitted size of the value (inclusive)
|
||||
|
||||
maximum: :class:`int`
|
||||
Maximum permitted size of the value (inclusive)
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code-block:: python
|
||||
|
||||
class BaseballTeamRoster(SetOf):
|
||||
'''
|
||||
ASN.1 specification:
|
||||
|
||||
BaseballTeamRoster ::= SET SIZE (1..25) OF PlayerNames
|
||||
'''
|
||||
componentType = PlayerNames()
|
||||
subtypeSpec = ValueSizeConstraint(1, 25)
|
||||
|
||||
# this will succeed
|
||||
team = BaseballTeamRoster()
|
||||
team.extend(['Jan', 'Matej'])
|
||||
encode(team)
|
||||
|
||||
# this will raise ValueConstraintError
|
||||
team = BaseballTeamRoster()
|
||||
team.extend(['Jan'] * 26)
|
||||
encode(team)
|
||||
|
||||
Note
|
||||
----
|
||||
Whenever ValueSizeConstraint is applied to mutable types
|
||||
(e.g. :class:`~pyasn1.type.univ.SequenceOf`,
|
||||
:class:`~pyasn1.type.univ.SetOf`), constraint
|
||||
validation only happens at the serialisation phase rather
|
||||
than schema instantiation phase (as it is with immutable
|
||||
types).
|
||||
"""
|
||||
def _testValue(self, value, idx):
|
||||
valueSize = len(value)
|
||||
if valueSize < self.start or valueSize > self.stop:
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
|
||||
class PermittedAlphabetConstraint(SingleValueConstraint):
|
||||
"""Create a PermittedAlphabetConstraint object.
|
||||
|
||||
The PermittedAlphabetConstraint satisfies any character
|
||||
string for as long as all its characters are present in
|
||||
the set of permitted characters.
|
||||
|
||||
Objects of this type are iterable (emitting constraint values) and
|
||||
can act as operands for some arithmetic operations e.g. addition
|
||||
and subtraction.
|
||||
|
||||
The PermittedAlphabetConstraint object can only be applied
|
||||
to the :ref:`character ASN.1 types <type.char>` such as
|
||||
:class:`~pyasn1.type.char.IA5String`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*alphabet: :class:`str`
|
||||
Full set of characters permitted by this constraint object.
|
||||
|
||||
Example
|
||||
-------
|
||||
.. code-block:: python
|
||||
|
||||
class BooleanValue(IA5String):
|
||||
'''
|
||||
ASN.1 specification:
|
||||
|
||||
BooleanValue ::= IA5String (FROM ('T' | 'F'))
|
||||
'''
|
||||
subtypeSpec = PermittedAlphabetConstraint('T', 'F')
|
||||
|
||||
# this will succeed
|
||||
truth = BooleanValue('T')
|
||||
truth = BooleanValue('TF')
|
||||
|
||||
# this will raise ValueConstraintError
|
||||
garbage = BooleanValue('TAF')
|
||||
|
||||
ASN.1 `FROM ... EXCEPT ...` clause can be modelled by combining multiple
|
||||
PermittedAlphabetConstraint objects into one:
|
||||
|
||||
Example
|
||||
-------
|
||||
.. code-block:: python
|
||||
|
||||
class Lipogramme(IA5String):
|
||||
'''
|
||||
ASN.1 specification:
|
||||
|
||||
Lipogramme ::=
|
||||
IA5String (FROM (ALL EXCEPT ("e"|"E")))
|
||||
'''
|
||||
subtypeSpec = (
|
||||
PermittedAlphabetConstraint(*string.printable) -
|
||||
PermittedAlphabetConstraint('e', 'E')
|
||||
)
|
||||
|
||||
# this will succeed
|
||||
lipogramme = Lipogramme('A work of fiction?')
|
||||
|
||||
# this will raise ValueConstraintError
|
||||
lipogramme = Lipogramme('Eel')
|
||||
|
||||
Note
|
||||
----
|
||||
Although `ConstraintsExclusion` object could seemingly be used for this
|
||||
purpose, practically, for it to work, it needs to represent its operand
|
||||
constraints as sets and intersect one with the other. That would require
|
||||
the insight into the constraint values (and their types) that are otherwise
|
||||
hidden inside the constraint object.
|
||||
|
||||
Therefore it's more practical to model `EXCEPT` clause at
|
||||
`PermittedAlphabetConstraint` level instead.
|
||||
"""
|
||||
def _setValues(self, values):
|
||||
self._values = values
|
||||
self._set = set(values)
|
||||
|
||||
def _testValue(self, value, idx):
|
||||
if not self._set.issuperset(value):
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
|
||||
class ComponentPresentConstraint(AbstractConstraint):
|
||||
"""Create a ComponentPresentConstraint object.
|
||||
|
||||
The ComponentPresentConstraint is only satisfied when the value
|
||||
is not `None`.
|
||||
|
||||
The ComponentPresentConstraint object is typically used with
|
||||
`WithComponentsConstraint`.
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code-block:: python
|
||||
|
||||
present = ComponentPresentConstraint()
|
||||
|
||||
# this will succeed
|
||||
present('whatever')
|
||||
|
||||
# this will raise ValueConstraintError
|
||||
present(None)
|
||||
"""
|
||||
def _setValues(self, values):
|
||||
self._values = ('<must be present>',)
|
||||
|
||||
if values:
|
||||
raise error.PyAsn1Error('No arguments expected')
|
||||
|
||||
def _testValue(self, value, idx):
|
||||
if value is None:
|
||||
raise error.ValueConstraintError(
|
||||
'Component is not present:')
|
||||
|
||||
|
||||
class ComponentAbsentConstraint(AbstractConstraint):
|
||||
"""Create a ComponentAbsentConstraint object.
|
||||
|
||||
The ComponentAbsentConstraint is only satisfied when the value
|
||||
is `None`.
|
||||
|
||||
The ComponentAbsentConstraint object is typically used with
|
||||
`WithComponentsConstraint`.
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code-block:: python
|
||||
|
||||
absent = ComponentAbsentConstraint()
|
||||
|
||||
# this will succeed
|
||||
absent(None)
|
||||
|
||||
# this will raise ValueConstraintError
|
||||
absent('whatever')
|
||||
"""
|
||||
def _setValues(self, values):
|
||||
self._values = ('<must be absent>',)
|
||||
|
||||
if values:
|
||||
raise error.PyAsn1Error('No arguments expected')
|
||||
|
||||
def _testValue(self, value, idx):
|
||||
if value is not None:
|
||||
raise error.ValueConstraintError(
|
||||
'Component is not absent: %r' % value)
|
||||
|
||||
|
||||
class WithComponentsConstraint(AbstractConstraint):
|
||||
"""Create a WithComponentsConstraint object.
|
||||
|
||||
The `WithComponentsConstraint` satisfies any mapping object that has
|
||||
constrained fields present or absent, what is indicated by
|
||||
`ComponentPresentConstraint` and `ComponentAbsentConstraint`
|
||||
objects respectively.
|
||||
|
||||
The `WithComponentsConstraint` object is typically applied
|
||||
to :class:`~pyasn1.type.univ.Set` or
|
||||
:class:`~pyasn1.type.univ.Sequence` types.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*fields: :class:`tuple`
|
||||
Zero or more tuples of (`field`, `constraint`) indicating constrained
|
||||
fields.
|
||||
|
||||
Notes
|
||||
-----
|
||||
On top of the primary use of `WithComponentsConstraint` (ensuring presence
|
||||
or absence of particular components of a :class:`~pyasn1.type.univ.Set` or
|
||||
:class:`~pyasn1.type.univ.Sequence`), it is also possible to pass any other
|
||||
constraint objects or their combinations. In case of scalar fields, these
|
||||
constraints will be verified in addition to the constraints belonging to
|
||||
scalar components themselves. However, formally, these additional
|
||||
constraints do not change the type of these ASN.1 objects.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Item(Sequence): # Set is similar
|
||||
'''
|
||||
ASN.1 specification:
|
||||
|
||||
Item ::= SEQUENCE {
|
||||
id INTEGER OPTIONAL,
|
||||
name OCTET STRING OPTIONAL
|
||||
} WITH COMPONENTS id PRESENT, name ABSENT | id ABSENT, name PRESENT
|
||||
'''
|
||||
componentType = NamedTypes(
|
||||
OptionalNamedType('id', Integer()),
|
||||
OptionalNamedType('name', OctetString())
|
||||
)
|
||||
withComponents = ConstraintsUnion(
|
||||
WithComponentsConstraint(
|
||||
('id', ComponentPresentConstraint()),
|
||||
('name', ComponentAbsentConstraint())
|
||||
),
|
||||
WithComponentsConstraint(
|
||||
('id', ComponentAbsentConstraint()),
|
||||
('name', ComponentPresentConstraint())
|
||||
)
|
||||
)
|
||||
|
||||
item = Item()
|
||||
|
||||
# This will succeed
|
||||
item['id'] = 1
|
||||
|
||||
# This will succeed
|
||||
item.reset()
|
||||
item['name'] = 'John'
|
||||
|
||||
# This will fail (on encoding)
|
||||
item.reset()
|
||||
descr['id'] = 1
|
||||
descr['name'] = 'John'
|
||||
"""
|
||||
def _testValue(self, value, idx):
|
||||
for field, constraint in self._values:
|
||||
constraint(value.get(field))
|
||||
|
||||
def _setValues(self, values):
|
||||
AbstractConstraint._setValues(self, values)
|
||||
|
||||
|
||||
# This is a bit kludgy, meaning two op modes within a single constraint
|
||||
class InnerTypeConstraint(AbstractConstraint):
|
||||
"""Value must satisfy the type and presence constraints"""
|
||||
|
||||
def _testValue(self, value, idx):
|
||||
if self.__singleTypeConstraint:
|
||||
self.__singleTypeConstraint(value)
|
||||
elif self.__multipleTypeConstraint:
|
||||
if idx not in self.__multipleTypeConstraint:
|
||||
raise error.ValueConstraintError(value)
|
||||
constraint, status = self.__multipleTypeConstraint[idx]
|
||||
if status == 'ABSENT': # XXX presence is not checked!
|
||||
raise error.ValueConstraintError(value)
|
||||
constraint(value)
|
||||
|
||||
def _setValues(self, values):
|
||||
self.__multipleTypeConstraint = {}
|
||||
self.__singleTypeConstraint = None
|
||||
for v in values:
|
||||
if isinstance(v, tuple):
|
||||
self.__multipleTypeConstraint[v[0]] = v[1], v[2]
|
||||
else:
|
||||
self.__singleTypeConstraint = v
|
||||
AbstractConstraint._setValues(self, values)
|
||||
|
||||
|
||||
# Logic operations on constraints
|
||||
|
||||
class ConstraintsExclusion(AbstractConstraint):
|
||||
"""Create a ConstraintsExclusion logic operator object.
|
||||
|
||||
The ConstraintsExclusion logic operator succeeds when the
|
||||
value does *not* satisfy the operand constraint.
|
||||
|
||||
The ConstraintsExclusion object can be applied to
|
||||
any constraint and logic operator object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*constraints:
|
||||
Constraint or logic operator objects.
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code-block:: python
|
||||
|
||||
class LuckyNumber(Integer):
|
||||
subtypeSpec = ConstraintsExclusion(
|
||||
SingleValueConstraint(13)
|
||||
)
|
||||
|
||||
# this will succeed
|
||||
luckyNumber = LuckyNumber(12)
|
||||
|
||||
# this will raise ValueConstraintError
|
||||
luckyNumber = LuckyNumber(13)
|
||||
|
||||
Note
|
||||
----
|
||||
The `FROM ... EXCEPT ...` ASN.1 clause should be modeled by combining
|
||||
constraint objects into one. See `PermittedAlphabetConstraint` for more
|
||||
information.
|
||||
"""
|
||||
def _testValue(self, value, idx):
|
||||
for constraint in self._values:
|
||||
try:
|
||||
constraint(value, idx)
|
||||
|
||||
except error.ValueConstraintError:
|
||||
continue
|
||||
|
||||
raise error.ValueConstraintError(value)
|
||||
|
||||
def _setValues(self, values):
|
||||
AbstractConstraint._setValues(self, values)
|
||||
|
||||
|
||||
class AbstractConstraintSet(AbstractConstraint):
|
||||
|
||||
def __getitem__(self, idx):
|
||||
return self._values[idx]
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._values)
|
||||
|
||||
def __add__(self, value):
|
||||
return self.__class__(*(self._values + (value,)))
|
||||
|
||||
def __radd__(self, value):
|
||||
return self.__class__(*((value,) + self._values))
|
||||
|
||||
def __len__(self):
|
||||
return len(self._values)
|
||||
|
||||
# Constraints inclusion in sets
|
||||
|
||||
def _setValues(self, values):
|
||||
self._values = values
|
||||
for constraint in values:
|
||||
if constraint:
|
||||
self._valueMap.add(constraint)
|
||||
self._valueMap.update(constraint.getValueMap())
|
||||
|
||||
|
||||
class ConstraintsIntersection(AbstractConstraintSet):
|
||||
"""Create a ConstraintsIntersection logic operator object.
|
||||
|
||||
The ConstraintsIntersection logic operator only succeeds
|
||||
if *all* its operands succeed.
|
||||
|
||||
The ConstraintsIntersection object can be applied to
|
||||
any constraint and logic operator objects.
|
||||
|
||||
The ConstraintsIntersection object duck-types the immutable
|
||||
container object like Python :py:class:`tuple`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*constraints:
|
||||
Constraint or logic operator objects.
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code-block:: python
|
||||
|
||||
class CapitalAndSmall(IA5String):
|
||||
'''
|
||||
ASN.1 specification:
|
||||
|
||||
CapitalAndSmall ::=
|
||||
IA5String (FROM ("A".."Z"|"a".."z"))
|
||||
'''
|
||||
subtypeSpec = ConstraintsIntersection(
|
||||
PermittedAlphabetConstraint('A', 'Z'),
|
||||
PermittedAlphabetConstraint('a', 'z')
|
||||
)
|
||||
|
||||
# this will succeed
|
||||
capital_and_small = CapitalAndSmall('Hello')
|
||||
|
||||
# this will raise ValueConstraintError
|
||||
capital_and_small = CapitalAndSmall('hello')
|
||||
"""
|
||||
def _testValue(self, value, idx):
|
||||
for constraint in self._values:
|
||||
constraint(value, idx)
|
||||
|
||||
|
||||
class ConstraintsUnion(AbstractConstraintSet):
|
||||
"""Create a ConstraintsUnion logic operator object.
|
||||
|
||||
The ConstraintsUnion logic operator succeeds if
|
||||
*at least* a single operand succeeds.
|
||||
|
||||
The ConstraintsUnion object can be applied to
|
||||
any constraint and logic operator objects.
|
||||
|
||||
The ConstraintsUnion object duck-types the immutable
|
||||
container object like Python :py:class:`tuple`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*constraints:
|
||||
Constraint or logic operator objects.
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code-block:: python
|
||||
|
||||
class CapitalOrSmall(IA5String):
|
||||
'''
|
||||
ASN.1 specification:
|
||||
|
||||
CapitalOrSmall ::=
|
||||
IA5String (FROM ("A".."Z") | FROM ("a".."z"))
|
||||
'''
|
||||
subtypeSpec = ConstraintsUnion(
|
||||
PermittedAlphabetConstraint('A', 'Z'),
|
||||
PermittedAlphabetConstraint('a', 'z')
|
||||
)
|
||||
|
||||
# this will succeed
|
||||
capital_or_small = CapitalAndSmall('Hello')
|
||||
|
||||
# this will raise ValueConstraintError
|
||||
capital_or_small = CapitalOrSmall('hello!')
|
||||
"""
|
||||
def _testValue(self, value, idx):
|
||||
for constraint in self._values:
|
||||
try:
|
||||
constraint(value, idx)
|
||||
except error.ValueConstraintError:
|
||||
pass
|
||||
else:
|
||||
return
|
||||
|
||||
raise error.ValueConstraintError(
|
||||
'all of %s failed for "%s"' % (self._values, value)
|
||||
)
|
||||
|
||||
# TODO:
|
||||
# refactor InnerTypeConstraint
|
||||
# add tests for type check
|
||||
# implement other constraint types
|
||||
# make constraint validation easy to skip
|
11
venv/Lib/site-packages/pyasn1/type/error.py
Normal file
11
venv/Lib/site-packages/pyasn1/type/error.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from pyasn1.error import PyAsn1Error
|
||||
|
||||
|
||||
class ValueConstraintError(PyAsn1Error):
|
||||
pass
|
561
venv/Lib/site-packages/pyasn1/type/namedtype.py
Normal file
561
venv/Lib/site-packages/pyasn1/type/namedtype.py
Normal file
|
@ -0,0 +1,561 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
import sys
|
||||
|
||||
from pyasn1 import error
|
||||
from pyasn1.type import tag
|
||||
from pyasn1.type import tagmap
|
||||
|
||||
__all__ = ['NamedType', 'OptionalNamedType', 'DefaultedNamedType',
|
||||
'NamedTypes']
|
||||
|
||||
try:
|
||||
any
|
||||
|
||||
except NameError:
|
||||
any = lambda x: bool(filter(bool, x))
|
||||
|
||||
|
||||
class NamedType(object):
|
||||
"""Create named field object for a constructed ASN.1 type.
|
||||
|
||||
The |NamedType| object represents a single name and ASN.1 type of a constructed ASN.1 type.
|
||||
|
||||
|NamedType| objects are immutable and duck-type Python :class:`tuple` objects
|
||||
holding *name* and *asn1Object* components.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: :py:class:`str`
|
||||
Field name
|
||||
|
||||
asn1Object:
|
||||
ASN.1 type object
|
||||
"""
|
||||
isOptional = False
|
||||
isDefaulted = False
|
||||
|
||||
def __init__(self, name, asn1Object, openType=None):
|
||||
self.__name = name
|
||||
self.__type = asn1Object
|
||||
self.__nameAndType = name, asn1Object
|
||||
self.__openType = openType
|
||||
|
||||
def __repr__(self):
|
||||
representation = '%s=%r' % (self.name, self.asn1Object)
|
||||
|
||||
if self.openType:
|
||||
representation += ', open type %r' % self.openType
|
||||
|
||||
return '<%s object, type %s>' % (
|
||||
self.__class__.__name__, representation)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__nameAndType == other
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.__nameAndType != other
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.__nameAndType < other
|
||||
|
||||
def __le__(self, other):
|
||||
return self.__nameAndType <= other
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.__nameAndType > other
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.__nameAndType >= other
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.__nameAndType)
|
||||
|
||||
def __getitem__(self, idx):
|
||||
return self.__nameAndType[idx]
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.__nameAndType)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.__name
|
||||
|
||||
@property
|
||||
def asn1Object(self):
|
||||
return self.__type
|
||||
|
||||
@property
|
||||
def openType(self):
|
||||
return self.__openType
|
||||
|
||||
# Backward compatibility
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getType(self):
|
||||
return self.asn1Object
|
||||
|
||||
|
||||
class OptionalNamedType(NamedType):
|
||||
__doc__ = NamedType.__doc__
|
||||
|
||||
isOptional = True
|
||||
|
||||
|
||||
class DefaultedNamedType(NamedType):
|
||||
__doc__ = NamedType.__doc__
|
||||
|
||||
isDefaulted = True
|
||||
|
||||
|
||||
class NamedTypes(object):
|
||||
"""Create a collection of named fields for a constructed ASN.1 type.
|
||||
|
||||
The NamedTypes object represents a collection of named fields of a constructed ASN.1 type.
|
||||
|
||||
*NamedTypes* objects are immutable and duck-type Python :class:`dict` objects
|
||||
holding *name* as keys and ASN.1 type object as values.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*namedTypes: :class:`~pyasn1.type.namedtype.NamedType`
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Description(Sequence):
|
||||
'''
|
||||
ASN.1 specification:
|
||||
|
||||
Description ::= SEQUENCE {
|
||||
surname IA5String,
|
||||
first-name IA5String OPTIONAL,
|
||||
age INTEGER DEFAULT 40
|
||||
}
|
||||
'''
|
||||
componentType = NamedTypes(
|
||||
NamedType('surname', IA5String()),
|
||||
OptionalNamedType('first-name', IA5String()),
|
||||
DefaultedNamedType('age', Integer(40))
|
||||
)
|
||||
|
||||
descr = Description()
|
||||
descr['surname'] = 'Smith'
|
||||
descr['first-name'] = 'John'
|
||||
"""
|
||||
def __init__(self, *namedTypes, **kwargs):
|
||||
self.__namedTypes = namedTypes
|
||||
self.__namedTypesLen = len(self.__namedTypes)
|
||||
self.__minTagSet = self.__computeMinTagSet()
|
||||
self.__nameToPosMap = self.__computeNameToPosMap()
|
||||
self.__tagToPosMap = self.__computeTagToPosMap()
|
||||
self.__ambiguousTypes = 'terminal' not in kwargs and self.__computeAmbiguousTypes() or {}
|
||||
self.__uniqueTagMap = self.__computeTagMaps(unique=True)
|
||||
self.__nonUniqueTagMap = self.__computeTagMaps(unique=False)
|
||||
self.__hasOptionalOrDefault = any([True for namedType in self.__namedTypes
|
||||
if namedType.isDefaulted or namedType.isOptional])
|
||||
self.__hasOpenTypes = any([True for namedType in self.__namedTypes
|
||||
if namedType.openType])
|
||||
|
||||
self.__requiredComponents = frozenset(
|
||||
[idx for idx, nt in enumerate(self.__namedTypes) if not nt.isOptional and not nt.isDefaulted]
|
||||
)
|
||||
self.__keys = frozenset([namedType.name for namedType in self.__namedTypes])
|
||||
self.__values = tuple([namedType.asn1Object for namedType in self.__namedTypes])
|
||||
self.__items = tuple([(namedType.name, namedType.asn1Object) for namedType in self.__namedTypes])
|
||||
|
||||
def __repr__(self):
|
||||
representation = ', '.join(['%r' % x for x in self.__namedTypes])
|
||||
return '<%s object, types %s>' % (
|
||||
self.__class__.__name__, representation)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__namedTypes == other
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.__namedTypes != other
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.__namedTypes < other
|
||||
|
||||
def __le__(self, other):
|
||||
return self.__namedTypes <= other
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.__namedTypes > other
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.__namedTypes >= other
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.__namedTypes)
|
||||
|
||||
def __getitem__(self, idx):
|
||||
try:
|
||||
return self.__namedTypes[idx]
|
||||
|
||||
except TypeError:
|
||||
return self.__namedTypes[self.__nameToPosMap[idx]]
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.__nameToPosMap
|
||||
|
||||
def __iter__(self):
|
||||
return (x[0] for x in self.__namedTypes)
|
||||
|
||||
if sys.version_info[0] <= 2:
|
||||
def __nonzero__(self):
|
||||
return self.__namedTypesLen > 0
|
||||
else:
|
||||
def __bool__(self):
|
||||
return self.__namedTypesLen > 0
|
||||
|
||||
def __len__(self):
|
||||
return self.__namedTypesLen
|
||||
|
||||
# Python dict protocol
|
||||
|
||||
def values(self):
|
||||
return self.__values
|
||||
|
||||
def keys(self):
|
||||
return self.__keys
|
||||
|
||||
def items(self):
|
||||
return self.__items
|
||||
|
||||
def clone(self):
|
||||
return self.__class__(*self.__namedTypes)
|
||||
|
||||
class PostponedError(object):
|
||||
def __init__(self, errorMsg):
|
||||
self.__errorMsg = errorMsg
|
||||
|
||||
def __getitem__(self, item):
|
||||
raise error.PyAsn1Error(self.__errorMsg)
|
||||
|
||||
def __computeTagToPosMap(self):
|
||||
tagToPosMap = {}
|
||||
for idx, namedType in enumerate(self.__namedTypes):
|
||||
tagMap = namedType.asn1Object.tagMap
|
||||
if isinstance(tagMap, NamedTypes.PostponedError):
|
||||
return tagMap
|
||||
if not tagMap:
|
||||
continue
|
||||
for _tagSet in tagMap.presentTypes:
|
||||
if _tagSet in tagToPosMap:
|
||||
return NamedTypes.PostponedError('Duplicate component tag %s at %s' % (_tagSet, namedType))
|
||||
tagToPosMap[_tagSet] = idx
|
||||
|
||||
return tagToPosMap
|
||||
|
||||
def __computeNameToPosMap(self):
|
||||
nameToPosMap = {}
|
||||
for idx, namedType in enumerate(self.__namedTypes):
|
||||
if namedType.name in nameToPosMap:
|
||||
return NamedTypes.PostponedError('Duplicate component name %s at %s' % (namedType.name, namedType))
|
||||
nameToPosMap[namedType.name] = idx
|
||||
|
||||
return nameToPosMap
|
||||
|
||||
def __computeAmbiguousTypes(self):
|
||||
ambiguousTypes = {}
|
||||
partialAmbiguousTypes = ()
|
||||
for idx, namedType in reversed(tuple(enumerate(self.__namedTypes))):
|
||||
if namedType.isOptional or namedType.isDefaulted:
|
||||
partialAmbiguousTypes = (namedType,) + partialAmbiguousTypes
|
||||
else:
|
||||
partialAmbiguousTypes = (namedType,)
|
||||
if len(partialAmbiguousTypes) == len(self.__namedTypes):
|
||||
ambiguousTypes[idx] = self
|
||||
else:
|
||||
ambiguousTypes[idx] = NamedTypes(*partialAmbiguousTypes, **dict(terminal=True))
|
||||
return ambiguousTypes
|
||||
|
||||
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 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 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 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 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 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 __computeMinTagSet(self):
|
||||
minTagSet = None
|
||||
for namedType in self.__namedTypes:
|
||||
asn1Object = namedType.asn1Object
|
||||
|
||||
try:
|
||||
tagSet = asn1Object.minTagSet
|
||||
|
||||
except AttributeError:
|
||||
tagSet = asn1Object.tagSet
|
||||
|
||||
if minTagSet is None or tagSet < minTagSet:
|
||||
minTagSet = tagSet
|
||||
|
||||
return minTagSet or tag.TagSet()
|
||||
|
||||
@property
|
||||
def minTagSet(self):
|
||||
"""Return the minimal TagSet among ASN.1 type in callee *NamedTypes*.
|
||||
|
||||
Some ASN.1 types/serialisation protocols require ASN.1 types to be
|
||||
arranged based on their numerical tag value. The *minTagSet* property
|
||||
returns that.
|
||||
|
||||
Returns
|
||||
-------
|
||||
: :class:`~pyasn1.type.tagset.TagSet`
|
||||
Minimal TagSet among ASN.1 types in callee *NamedTypes*
|
||||
"""
|
||||
return self.__minTagSet
|
||||
|
||||
def __computeTagMaps(self, unique):
|
||||
presentTypes = {}
|
||||
skipTypes = {}
|
||||
defaultType = None
|
||||
for namedType in self.__namedTypes:
|
||||
tagMap = namedType.asn1Object.tagMap
|
||||
if isinstance(tagMap, NamedTypes.PostponedError):
|
||||
return tagMap
|
||||
for tagSet in tagMap:
|
||||
if unique and tagSet in presentTypes:
|
||||
return NamedTypes.PostponedError('Non-unique tagSet %s of %s at %s' % (tagSet, namedType, self))
|
||||
presentTypes[tagSet] = namedType.asn1Object
|
||||
skipTypes.update(tagMap.skipTypes)
|
||||
|
||||
if defaultType is None:
|
||||
defaultType = tagMap.defaultType
|
||||
elif tagMap.defaultType is not None:
|
||||
return NamedTypes.PostponedError('Duplicate default ASN.1 type at %s' % (self,))
|
||||
|
||||
return tagmap.TagMap(presentTypes, skipTypes, defaultType)
|
||||
|
||||
@property
|
||||
def tagMap(self):
|
||||
"""Return a *TagMap* object from tags and types recursively.
|
||||
|
||||
Return a :class:`~pyasn1.type.tagmap.TagMap` object by
|
||||
combining tags from *TagMap* objects of children types and
|
||||
associating them with their immediate child type.
|
||||
|
||||
Example
|
||||
-------
|
||||
.. code-block:: python
|
||||
|
||||
OuterType ::= CHOICE {
|
||||
innerType INTEGER
|
||||
}
|
||||
|
||||
Calling *.tagMap* on *OuterType* will yield a map like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Integer.tagSet -> Choice
|
||||
"""
|
||||
return self.__nonUniqueTagMap
|
||||
|
||||
@property
|
||||
def tagMapUnique(self):
|
||||
"""Return a *TagMap* object from unique tags and types recursively.
|
||||
|
||||
Return a :class:`~pyasn1.type.tagmap.TagMap` object by
|
||||
combining tags from *TagMap* objects of children types and
|
||||
associating them with their immediate child type.
|
||||
|
||||
Example
|
||||
-------
|
||||
.. code-block:: python
|
||||
|
||||
OuterType ::= CHOICE {
|
||||
innerType INTEGER
|
||||
}
|
||||
|
||||
Calling *.tagMapUnique* on *OuterType* will yield a map like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Integer.tagSet -> Choice
|
||||
|
||||
Note
|
||||
----
|
||||
|
||||
Duplicate *TagSet* objects found in the tree of children
|
||||
types would cause error.
|
||||
"""
|
||||
return self.__uniqueTagMap
|
||||
|
||||
@property
|
||||
def hasOptionalOrDefault(self):
|
||||
return self.__hasOptionalOrDefault
|
||||
|
||||
@property
|
||||
def hasOpenTypes(self):
|
||||
return self.__hasOpenTypes
|
||||
|
||||
@property
|
||||
def namedTypes(self):
|
||||
return tuple(self.__namedTypes)
|
||||
|
||||
@property
|
||||
def requiredComponents(self):
|
||||
return self.__requiredComponents
|
192
venv/Lib/site-packages/pyasn1/type/namedval.py
Normal file
192
venv/Lib/site-packages/pyasn1/type/namedval.py
Normal file
|
@ -0,0 +1,192 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
# ASN.1 named integers
|
||||
#
|
||||
from pyasn1 import error
|
||||
|
||||
__all__ = ['NamedValues']
|
||||
|
||||
|
||||
class NamedValues(object):
|
||||
"""Create named values object.
|
||||
|
||||
The |NamedValues| object represents a collection of string names
|
||||
associated with numeric IDs. These objects are used for giving
|
||||
names to otherwise numerical values.
|
||||
|
||||
|NamedValues| objects are immutable and duck-type Python
|
||||
:class:`dict` object mapping ID to name and vice-versa.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*args: variable number of two-element :py:class:`tuple`
|
||||
|
||||
name: :py:class:`str`
|
||||
Value label
|
||||
|
||||
value: :py:class:`int`
|
||||
Numeric value
|
||||
|
||||
Keyword Args
|
||||
------------
|
||||
name: :py:class:`str`
|
||||
Value label
|
||||
|
||||
value: :py:class:`int`
|
||||
Numeric value
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> nv = NamedValues('a', 'b', ('c', 0), d=1)
|
||||
>>> nv
|
||||
>>> {'c': 0, 'd': 1, 'a': 2, 'b': 3}
|
||||
>>> nv[0]
|
||||
'c'
|
||||
>>> nv['a']
|
||||
2
|
||||
"""
|
||||
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 __repr__(self):
|
||||
representation = ', '.join(['%s=%d' % x for x in self.items()])
|
||||
|
||||
if len(representation) > 64:
|
||||
representation = representation[:32] + '...' + representation[-32:]
|
||||
|
||||
return '<%s object, enums %s>' % (
|
||||
self.__class__.__name__, representation)
|
||||
|
||||
def __eq__(self, other):
|
||||
return dict(self) == other
|
||||
|
||||
def __ne__(self, other):
|
||||
return dict(self) != other
|
||||
|
||||
def __lt__(self, other):
|
||||
return dict(self) < other
|
||||
|
||||
def __le__(self, other):
|
||||
return dict(self) <= other
|
||||
|
||||
def __gt__(self, other):
|
||||
return dict(self) > other
|
||||
|
||||
def __ge__(self, other):
|
||||
return dict(self) >= other
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.items())
|
||||
|
||||
# Python dict protocol (read-only)
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return self.__numbers[key]
|
||||
|
||||
except KeyError:
|
||||
return self.__names[key]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__names)
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.__names or key in self.__numbers
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.__names)
|
||||
|
||||
def values(self):
|
||||
return iter(self.__numbers)
|
||||
|
||||
def keys(self):
|
||||
return iter(self.__names)
|
||||
|
||||
def items(self):
|
||||
for name in self.__names:
|
||||
yield name, self.__names[name]
|
||||
|
||||
# support merging
|
||||
|
||||
def __add__(self, namedValues):
|
||||
return self.__class__(*tuple(self.items()) + tuple(namedValues.items()))
|
||||
|
||||
# XXX clone/subtype?
|
||||
|
||||
def clone(self, *args, **kwargs):
|
||||
new = self.__class__(*args, **kwargs)
|
||||
return self + new
|
||||
|
||||
# legacy protocol
|
||||
|
||||
def getName(self, value):
|
||||
if value in self.__numbers:
|
||||
return self.__numbers[value]
|
||||
|
||||
def getValue(self, name):
|
||||
if name in self.__names:
|
||||
return self.__names[name]
|
||||
|
||||
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),)
|
||||
)
|
104
venv/Lib/site-packages/pyasn1/type/opentype.py
Normal file
104
venv/Lib/site-packages/pyasn1/type/opentype.py
Normal file
|
@ -0,0 +1,104 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
|
||||
__all__ = ['OpenType']
|
||||
|
||||
|
||||
class OpenType(object):
|
||||
"""Create ASN.1 type map indexed by a value
|
||||
|
||||
The *OpenType* object models an untyped field of a constructed ASN.1
|
||||
type. In ASN.1 syntax it is usually represented by the
|
||||
`ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`,
|
||||
`SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically
|
||||
used together with :class:`~pyasn1.type.univ.Any` object.
|
||||
|
||||
OpenType objects duck-type a read-only Python :class:`dict` objects,
|
||||
however the passed `typeMap` is not copied, but stored by reference.
|
||||
That means the user can manipulate `typeMap` at run time having this
|
||||
reflected on *OpenType* object behavior.
|
||||
|
||||
The |OpenType| class models an untyped field of a constructed ASN.1
|
||||
type. In ASN.1 syntax it is usually represented by the
|
||||
`ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`,
|
||||
`SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically
|
||||
used with :class:`~pyasn1.type.univ.Any` type.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: :py:class:`str`
|
||||
Field name
|
||||
|
||||
typeMap: :py:class:`dict`
|
||||
A map of value->ASN.1 type. It's stored by reference and can be
|
||||
mutated later to register new mappings.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
For untyped scalars:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
openType = OpenType(
|
||||
'id', {1: Integer(),
|
||||
2: OctetString()}
|
||||
)
|
||||
Sequence(
|
||||
componentType=NamedTypes(
|
||||
NamedType('id', Integer()),
|
||||
NamedType('blob', Any(), openType=openType)
|
||||
)
|
||||
)
|
||||
|
||||
For untyped `SET OF` or `SEQUENCE OF` vectors:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
openType = OpenType(
|
||||
'id', {1: Integer(),
|
||||
2: OctetString()}
|
||||
)
|
||||
Sequence(
|
||||
componentType=NamedTypes(
|
||||
NamedType('id', Integer()),
|
||||
NamedType('blob', SetOf(componentType=Any()),
|
||||
openType=openType)
|
||||
)
|
||||
)
|
||||
"""
|
||||
|
||||
def __init__(self, name, typeMap=None):
|
||||
self.__name = name
|
||||
if typeMap is None:
|
||||
self.__typeMap = {}
|
||||
else:
|
||||
self.__typeMap = typeMap
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.__name
|
||||
|
||||
# Python dict protocol
|
||||
|
||||
def values(self):
|
||||
return self.__typeMap.values()
|
||||
|
||||
def keys(self):
|
||||
return self.__typeMap.keys()
|
||||
|
||||
def items(self):
|
||||
return self.__typeMap.items()
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.__typeMap
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.__typeMap[key]
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.__typeMap)
|
335
venv/Lib/site-packages/pyasn1/type/tag.py
Normal file
335
venv/Lib/site-packages/pyasn1/type/tag.py
Normal file
|
@ -0,0 +1,335 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from pyasn1 import error
|
||||
|
||||
__all__ = ['tagClassUniversal', 'tagClassApplication', 'tagClassContext',
|
||||
'tagClassPrivate', 'tagFormatSimple', 'tagFormatConstructed',
|
||||
'tagCategoryImplicit', 'tagCategoryExplicit',
|
||||
'tagCategoryUntagged', 'Tag', 'TagSet']
|
||||
|
||||
#: Identifier for ASN.1 class UNIVERSAL
|
||||
tagClassUniversal = 0x00
|
||||
|
||||
#: Identifier for ASN.1 class APPLICATION
|
||||
tagClassApplication = 0x40
|
||||
|
||||
#: Identifier for ASN.1 class context-specific
|
||||
tagClassContext = 0x80
|
||||
|
||||
#: Identifier for ASN.1 class private
|
||||
tagClassPrivate = 0xC0
|
||||
|
||||
#: Identifier for "simple" ASN.1 structure (e.g. scalar)
|
||||
tagFormatSimple = 0x00
|
||||
|
||||
#: Identifier for "constructed" ASN.1 structure (e.g. may have inner components)
|
||||
tagFormatConstructed = 0x20
|
||||
|
||||
tagCategoryImplicit = 0x01
|
||||
tagCategoryExplicit = 0x02
|
||||
tagCategoryUntagged = 0x04
|
||||
|
||||
|
||||
class Tag(object):
|
||||
"""Create ASN.1 tag
|
||||
|
||||
Represents ASN.1 tag that can be attached to a ASN.1 type to make
|
||||
types distinguishable from each other.
|
||||
|
||||
*Tag* objects are immutable and duck-type Python :class:`tuple` objects
|
||||
holding three integer components of a tag.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
tagClass: :py:class:`int`
|
||||
Tag *class* value
|
||||
|
||||
tagFormat: :py:class:`int`
|
||||
Tag *format* value
|
||||
|
||||
tagId: :py:class:`int`
|
||||
Tag ID value
|
||||
"""
|
||||
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 __repr__(self):
|
||||
representation = '[%s:%s:%s]' % (
|
||||
self.__tagClass, self.__tagFormat, self.__tagId)
|
||||
return '<%s object, tag %s>' % (
|
||||
self.__class__.__name__, representation)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__tagClassId == other
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.__tagClassId != other
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.__tagClassId < other
|
||||
|
||||
def __le__(self, other):
|
||||
return self.__tagClassId <= other
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.__tagClassId > other
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.__tagClassId >= other
|
||||
|
||||
def __hash__(self):
|
||||
return self.__hash
|
||||
|
||||
def __getitem__(self, idx):
|
||||
if idx == 0:
|
||||
return self.__tagClass
|
||||
elif idx == 1:
|
||||
return self.__tagFormat
|
||||
elif idx == 2:
|
||||
return self.__tagId
|
||||
else:
|
||||
raise IndexError()
|
||||
|
||||
def __iter__(self):
|
||||
yield self.__tagClass
|
||||
yield self.__tagFormat
|
||||
yield self.__tagId
|
||||
|
||||
def __and__(self, otherTag):
|
||||
return self.__class__(self.__tagClass & otherTag.tagClass,
|
||||
self.__tagFormat & otherTag.tagFormat,
|
||||
self.__tagId & otherTag.tagId)
|
||||
|
||||
def __or__(self, otherTag):
|
||||
return self.__class__(self.__tagClass | otherTag.tagClass,
|
||||
self.__tagFormat | otherTag.tagFormat,
|
||||
self.__tagId | otherTag.tagId)
|
||||
|
||||
@property
|
||||
def tagClass(self):
|
||||
"""ASN.1 tag class
|
||||
|
||||
Returns
|
||||
-------
|
||||
: :py:class:`int`
|
||||
Tag class
|
||||
"""
|
||||
return self.__tagClass
|
||||
|
||||
@property
|
||||
def tagFormat(self):
|
||||
"""ASN.1 tag format
|
||||
|
||||
Returns
|
||||
-------
|
||||
: :py:class:`int`
|
||||
Tag format
|
||||
"""
|
||||
return self.__tagFormat
|
||||
|
||||
@property
|
||||
def tagId(self):
|
||||
"""ASN.1 tag ID
|
||||
|
||||
Returns
|
||||
-------
|
||||
: :py:class:`int`
|
||||
Tag ID
|
||||
"""
|
||||
return self.__tagId
|
||||
|
||||
|
||||
class TagSet(object):
|
||||
"""Create a collection of ASN.1 tags
|
||||
|
||||
Represents a combination of :class:`~pyasn1.type.tag.Tag` objects
|
||||
that can be attached to a ASN.1 type to make types distinguishable
|
||||
from each other.
|
||||
|
||||
*TagSet* objects are immutable and duck-type Python :class:`tuple` objects
|
||||
holding arbitrary number of :class:`~pyasn1.type.tag.Tag` objects.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
baseTag: :class:`~pyasn1.type.tag.Tag`
|
||||
Base *Tag* object. This tag survives IMPLICIT tagging.
|
||||
|
||||
*superTags: :class:`~pyasn1.type.tag.Tag`
|
||||
Additional *Tag* objects taking part in subtyping.
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code-block:: python
|
||||
|
||||
class OrderNumber(NumericString):
|
||||
'''
|
||||
ASN.1 specification
|
||||
|
||||
Order-number ::=
|
||||
[APPLICATION 5] IMPLICIT NumericString
|
||||
'''
|
||||
tagSet = NumericString.tagSet.tagImplicitly(
|
||||
Tag(tagClassApplication, tagFormatSimple, 5)
|
||||
)
|
||||
|
||||
orderNumber = OrderNumber('1234')
|
||||
"""
|
||||
def __init__(self, baseTag=(), *superTags):
|
||||
self.__baseTag = baseTag
|
||||
self.__superTags = superTags
|
||||
self.__superTagsClassId = tuple(
|
||||
[(superTag.tagClass, superTag.tagId) for superTag in superTags]
|
||||
)
|
||||
self.__lenOfSuperTags = len(superTags)
|
||||
self.__hash = hash(self.__superTagsClassId)
|
||||
|
||||
def __repr__(self):
|
||||
representation = '-'.join(['%s:%s:%s' % (x.tagClass, x.tagFormat, x.tagId)
|
||||
for x in self.__superTags])
|
||||
if representation:
|
||||
representation = 'tags ' + representation
|
||||
else:
|
||||
representation = 'untagged'
|
||||
|
||||
return '<%s object, %s>' % (self.__class__.__name__, representation)
|
||||
|
||||
def __add__(self, superTag):
|
||||
return self.__class__(self.__baseTag, *self.__superTags + (superTag,))
|
||||
|
||||
def __radd__(self, superTag):
|
||||
return self.__class__(self.__baseTag, *(superTag,) + self.__superTags)
|
||||
|
||||
def __getitem__(self, i):
|
||||
if i.__class__ is slice:
|
||||
return self.__class__(self.__baseTag, *self.__superTags[i])
|
||||
else:
|
||||
return self.__superTags[i]
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__superTagsClassId == other
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.__superTagsClassId != other
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.__superTagsClassId < other
|
||||
|
||||
def __le__(self, other):
|
||||
return self.__superTagsClassId <= other
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.__superTagsClassId > other
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.__superTagsClassId >= other
|
||||
|
||||
def __hash__(self):
|
||||
return self.__hash
|
||||
|
||||
def __len__(self):
|
||||
return self.__lenOfSuperTags
|
||||
|
||||
@property
|
||||
def baseTag(self):
|
||||
"""Return base ASN.1 tag
|
||||
|
||||
Returns
|
||||
-------
|
||||
: :class:`~pyasn1.type.tag.Tag`
|
||||
Base tag of this *TagSet*
|
||||
"""
|
||||
return self.__baseTag
|
||||
|
||||
@property
|
||||
def superTags(self):
|
||||
"""Return ASN.1 tags
|
||||
|
||||
Returns
|
||||
-------
|
||||
: :py:class:`tuple`
|
||||
Tuple of :class:`~pyasn1.type.tag.Tag` objects that this *TagSet* contains
|
||||
"""
|
||||
return self.__superTags
|
||||
|
||||
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 tagImplicitly(self, superTag):
|
||||
"""Return implicitly tagged *TagSet*
|
||||
|
||||
Create a new *TagSet* representing callee *TagSet* implicitly tagged
|
||||
with passed tag(s). With implicit tagging mode, new tag(s) replace the
|
||||
last existing tag.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
superTag: :class:`~pyasn1.type.tag.Tag`
|
||||
*Tag* object to tag this *TagSet*
|
||||
|
||||
Returns
|
||||
-------
|
||||
: :class:`~pyasn1.type.tag.TagSet`
|
||||
New *TagSet* object
|
||||
"""
|
||||
if self.__superTags:
|
||||
superTag = Tag(superTag.tagClass, self.__superTags[-1].tagFormat, superTag.tagId)
|
||||
return self[:-1] + superTag
|
||||
|
||||
def isSuperTagSetOf(self, tagSet):
|
||||
"""Test type relationship against given *TagSet*
|
||||
|
||||
The callee is considered to be a supertype of given *TagSet*
|
||||
tag-wise if all tags in *TagSet* are present in the callee and
|
||||
they are in the same order.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
tagSet: :class:`~pyasn1.type.tag.TagSet`
|
||||
*TagSet* object to evaluate against the callee
|
||||
|
||||
Returns
|
||||
-------
|
||||
: :py:class:`bool`
|
||||
:obj:`True` if callee is a supertype of *tagSet*
|
||||
"""
|
||||
if len(tagSet) < self.__lenOfSuperTags:
|
||||
return False
|
||||
return self.__superTags == tagSet[:self.__lenOfSuperTags]
|
||||
|
||||
# Backward compatibility
|
||||
|
||||
def getBaseTag(self):
|
||||
return self.__baseTag
|
||||
|
||||
def initTagSet(tag):
|
||||
return TagSet(tag, tag)
|
96
venv/Lib/site-packages/pyasn1/type/tagmap.py
Normal file
96
venv/Lib/site-packages/pyasn1/type/tagmap.py
Normal file
|
@ -0,0 +1,96 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
from pyasn1 import error
|
||||
|
||||
__all__ = ['TagMap']
|
||||
|
||||
|
||||
class TagMap(object):
|
||||
"""Map *TagSet* objects to ASN.1 types
|
||||
|
||||
Create an object mapping *TagSet* object to ASN.1 type.
|
||||
|
||||
*TagMap* objects are immutable and duck-type read-only Python
|
||||
:class:`dict` objects holding *TagSet* objects as keys and ASN.1
|
||||
type objects as values.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
presentTypes: :py:class:`dict`
|
||||
Map of :class:`~pyasn1.type.tag.TagSet` to ASN.1 objects considered
|
||||
as being unconditionally present in the *TagMap*.
|
||||
|
||||
skipTypes: :py:class:`dict`
|
||||
A collection of :class:`~pyasn1.type.tag.TagSet` objects considered
|
||||
as absent in the *TagMap* even when *defaultType* is present.
|
||||
|
||||
defaultType: ASN.1 type object
|
||||
An ASN.1 type object callee *TagMap* returns for any *TagSet* key not present
|
||||
in *presentTypes* (unless given key is present in *skipTypes*).
|
||||
"""
|
||||
def __init__(self, presentTypes=None, skipTypes=None, defaultType=None):
|
||||
self.__presentTypes = presentTypes or {}
|
||||
self.__skipTypes = skipTypes or {}
|
||||
self.__defaultType = defaultType
|
||||
|
||||
def __contains__(self, tagSet):
|
||||
return (tagSet in self.__presentTypes or
|
||||
self.__defaultType is not None and tagSet not in self.__skipTypes)
|
||||
|
||||
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 __iter__(self):
|
||||
return iter(self.__presentTypes)
|
||||
|
||||
def __repr__(self):
|
||||
representation = '%s object' % self.__class__.__name__
|
||||
|
||||
if self.__presentTypes:
|
||||
representation += ', present %s' % repr(self.__presentTypes)
|
||||
|
||||
if self.__skipTypes:
|
||||
representation += ', skip %s' % repr(self.__skipTypes)
|
||||
|
||||
if self.__defaultType is not None:
|
||||
representation += ', default %s' % repr(self.__defaultType)
|
||||
|
||||
return '<%s>' % representation
|
||||
|
||||
@property
|
||||
def presentTypes(self):
|
||||
"""Return *TagSet* to ASN.1 type map present in callee *TagMap*"""
|
||||
return self.__presentTypes
|
||||
|
||||
@property
|
||||
def skipTypes(self):
|
||||
"""Return *TagSet* collection unconditionally absent in callee *TagMap*"""
|
||||
return self.__skipTypes
|
||||
|
||||
@property
|
||||
def defaultType(self):
|
||||
"""Return default ASN.1 type being returned for any missing *TagSet*"""
|
||||
return self.__defaultType
|
||||
|
||||
# Backward compatibility
|
||||
|
||||
def getPosMap(self):
|
||||
return self.presentTypes
|
||||
|
||||
def getNegMap(self):
|
||||
return self.skipTypes
|
||||
|
||||
def getDef(self):
|
||||
return self.defaultType
|
3321
venv/Lib/site-packages/pyasn1/type/univ.py
Normal file
3321
venv/Lib/site-packages/pyasn1/type/univ.py
Normal file
File diff suppressed because it is too large
Load diff
191
venv/Lib/site-packages/pyasn1/type/useful.py
Normal file
191
venv/Lib/site-packages/pyasn1/type/useful.py
Normal file
|
@ -0,0 +1,191 @@
|
|||
#
|
||||
# This file is part of pyasn1 software.
|
||||
#
|
||||
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
||||
# License: http://snmplabs.com/pyasn1/license.html
|
||||
#
|
||||
import datetime
|
||||
|
||||
from pyasn1 import error
|
||||
from pyasn1.compat import dateandtime
|
||||
from pyasn1.compat import string
|
||||
from pyasn1.type import char
|
||||
from pyasn1.type import tag
|
||||
from pyasn1.type import univ
|
||||
|
||||
__all__ = ['ObjectDescriptor', 'GeneralizedTime', 'UTCTime']
|
||||
|
||||
NoValue = univ.NoValue
|
||||
noValue = univ.noValue
|
||||
|
||||
|
||||
class ObjectDescriptor(char.GraphicString):
|
||||
__doc__ = char.GraphicString.__doc__
|
||||
|
||||
#: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects
|
||||
tagSet = char.GraphicString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 7)
|
||||
)
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = char.GraphicString.getTypeId()
|
||||
|
||||
|
||||
class TimeMixIn(object):
|
||||
|
||||
_yearsDigits = 4
|
||||
_hasSubsecond = False
|
||||
_optionalMinutes = False
|
||||
_shortTZ = False
|
||||
|
||||
class FixedOffset(datetime.tzinfo):
|
||||
"""Fixed offset in minutes east from UTC."""
|
||||
|
||||
# defaulted arguments required
|
||||
# https: // docs.python.org / 2.3 / lib / datetime - tzinfo.html
|
||||
def __init__(self, offset=0, name='UTC'):
|
||||
self.__offset = datetime.timedelta(minutes=offset)
|
||||
self.__name = name
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return self.__offset
|
||||
|
||||
def tzname(self, dt):
|
||||
return self.__name
|
||||
|
||||
def dst(self, dt):
|
||||
return datetime.timedelta(0)
|
||||
|
||||
UTC = FixedOffset()
|
||||
|
||||
@property
|
||||
def asDateTime(self):
|
||||
"""Create :py:class:`datetime.datetime` object from a |ASN.1| object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
:
|
||||
new instance of :py:class:`datetime.datetime` object
|
||||
"""
|
||||
text = str(self)
|
||||
if text.endswith('Z'):
|
||||
tzinfo = TimeMixIn.UTC
|
||||
text = text[:-1]
|
||||
|
||||
elif '-' in text or '+' in text:
|
||||
if '+' in text:
|
||||
text, plusminus, tz = string.partition(text, '+')
|
||||
else:
|
||||
text, plusminus, tz = string.partition(text, '-')
|
||||
|
||||
if self._shortTZ and len(tz) == 2:
|
||||
tz += '00'
|
||||
|
||||
if len(tz) != 4:
|
||||
raise error.PyAsn1Error('malformed time zone offset %s' % tz)
|
||||
|
||||
try:
|
||||
minutes = int(tz[:2]) * 60 + int(tz[2:])
|
||||
if plusminus == '-':
|
||||
minutes *= -1
|
||||
|
||||
except ValueError:
|
||||
raise error.PyAsn1Error('unknown time specification %s' % self)
|
||||
|
||||
tzinfo = TimeMixIn.FixedOffset(minutes, '?')
|
||||
|
||||
else:
|
||||
tzinfo = None
|
||||
|
||||
if '.' in text or ',' in text:
|
||||
if '.' in text:
|
||||
text, _, ms = string.partition(text, '.')
|
||||
else:
|
||||
text, _, ms = string.partition(text, ',')
|
||||
|
||||
try:
|
||||
ms = int(ms) * 1000
|
||||
|
||||
except ValueError:
|
||||
raise error.PyAsn1Error('bad sub-second time specification %s' % self)
|
||||
|
||||
else:
|
||||
ms = 0
|
||||
|
||||
if self._optionalMinutes and len(text) - self._yearsDigits == 6:
|
||||
text += '0000'
|
||||
elif len(text) - self._yearsDigits == 8:
|
||||
text += '00'
|
||||
|
||||
try:
|
||||
dt = dateandtime.strptime(text, self._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S')
|
||||
|
||||
except ValueError:
|
||||
raise error.PyAsn1Error('malformed datetime format %s' % self)
|
||||
|
||||
return dt.replace(microsecond=ms, tzinfo=tzinfo)
|
||||
|
||||
@classmethod
|
||||
def fromDateTime(cls, dt):
|
||||
"""Create |ASN.1| object from a :py:class:`datetime.datetime` object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
dt: :py:class:`datetime.datetime` object
|
||||
The `datetime.datetime` object to initialize the |ASN.1| object
|
||||
from
|
||||
|
||||
Returns
|
||||
-------
|
||||
:
|
||||
new instance of |ASN.1| value
|
||||
"""
|
||||
text = dt.strftime(cls._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S')
|
||||
if cls._hasSubsecond:
|
||||
text += '.%d' % (dt.microsecond // 1000)
|
||||
|
||||
if dt.utcoffset():
|
||||
seconds = dt.utcoffset().seconds
|
||||
if seconds < 0:
|
||||
text += '-'
|
||||
else:
|
||||
text += '+'
|
||||
text += '%.2d%.2d' % (seconds // 3600, seconds % 3600)
|
||||
else:
|
||||
text += 'Z'
|
||||
|
||||
return cls(text)
|
||||
|
||||
|
||||
class GeneralizedTime(char.VisibleString, TimeMixIn):
|
||||
__doc__ = char.VisibleString.__doc__
|
||||
|
||||
#: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects
|
||||
tagSet = char.VisibleString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 24)
|
||||
)
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = char.VideotexString.getTypeId()
|
||||
|
||||
_yearsDigits = 4
|
||||
_hasSubsecond = True
|
||||
_optionalMinutes = True
|
||||
_shortTZ = True
|
||||
|
||||
|
||||
class UTCTime(char.VisibleString, TimeMixIn):
|
||||
__doc__ = char.VisibleString.__doc__
|
||||
|
||||
#: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects
|
||||
tagSet = char.VisibleString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 23)
|
||||
)
|
||||
|
||||
# Optimization for faster codec lookup
|
||||
typeId = char.VideotexString.getTypeId()
|
||||
|
||||
_yearsDigits = 2
|
||||
_hasSubsecond = False
|
||||
_optionalMinutes = False
|
||||
_shortTZ = False
|
Loading…
Add table
Add a link
Reference in a new issue