You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

257 lines
7.8 KiB

  1. #
  2. # This file is part of pyasn1 software.
  3. #
  4. # Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
  5. # License: http://snmplabs.com/pyasn1/license.html
  6. #
  7. try:
  8. from collections import OrderedDict
  9. except ImportError:
  10. OrderedDict = dict
  11. from pyasn1 import debug
  12. from pyasn1 import error
  13. from pyasn1.type import base
  14. from pyasn1.type import char
  15. from pyasn1.type import tag
  16. from pyasn1.type import univ
  17. from pyasn1.type import useful
  18. __all__ = ['encode']
  19. LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_ENCODER)
  20. class AbstractItemEncoder(object):
  21. def encode(self, value, encodeFun, **options):
  22. raise error.PyAsn1Error('Not implemented')
  23. class BooleanEncoder(AbstractItemEncoder):
  24. def encode(self, value, encodeFun, **options):
  25. return bool(value)
  26. class IntegerEncoder(AbstractItemEncoder):
  27. def encode(self, value, encodeFun, **options):
  28. return int(value)
  29. class BitStringEncoder(AbstractItemEncoder):
  30. def encode(self, value, encodeFun, **options):
  31. return str(value)
  32. class OctetStringEncoder(AbstractItemEncoder):
  33. def encode(self, value, encodeFun, **options):
  34. return value.asOctets()
  35. class TextStringEncoder(AbstractItemEncoder):
  36. def encode(self, value, encodeFun, **options):
  37. return str(value)
  38. class NullEncoder(AbstractItemEncoder):
  39. def encode(self, value, encodeFun, **options):
  40. return None
  41. class ObjectIdentifierEncoder(AbstractItemEncoder):
  42. def encode(self, value, encodeFun, **options):
  43. return str(value)
  44. class RealEncoder(AbstractItemEncoder):
  45. def encode(self, value, encodeFun, **options):
  46. return float(value)
  47. class SetEncoder(AbstractItemEncoder):
  48. protoDict = dict
  49. def encode(self, value, encodeFun, **options):
  50. inconsistency = value.isInconsistent
  51. if inconsistency:
  52. raise inconsistency
  53. namedTypes = value.componentType
  54. substrate = self.protoDict()
  55. for idx, (key, subValue) in enumerate(value.items()):
  56. if namedTypes and namedTypes[idx].isOptional and not value[idx].isValue:
  57. continue
  58. substrate[key] = encodeFun(subValue, **options)
  59. return substrate
  60. class SequenceEncoder(SetEncoder):
  61. protoDict = OrderedDict
  62. class SequenceOfEncoder(AbstractItemEncoder):
  63. def encode(self, value, encodeFun, **options):
  64. inconsistency = value.isInconsistent
  65. if inconsistency:
  66. raise inconsistency
  67. return [encodeFun(x, **options) for x in value]
  68. class ChoiceEncoder(SequenceEncoder):
  69. pass
  70. class AnyEncoder(AbstractItemEncoder):
  71. def encode(self, value, encodeFun, **options):
  72. return value.asOctets()
  73. tagMap = {
  74. univ.Boolean.tagSet: BooleanEncoder(),
  75. univ.Integer.tagSet: IntegerEncoder(),
  76. univ.BitString.tagSet: BitStringEncoder(),
  77. univ.OctetString.tagSet: OctetStringEncoder(),
  78. univ.Null.tagSet: NullEncoder(),
  79. univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(),
  80. univ.Enumerated.tagSet: IntegerEncoder(),
  81. univ.Real.tagSet: RealEncoder(),
  82. # Sequence & Set have same tags as SequenceOf & SetOf
  83. univ.SequenceOf.tagSet: SequenceOfEncoder(),
  84. univ.SetOf.tagSet: SequenceOfEncoder(),
  85. univ.Choice.tagSet: ChoiceEncoder(),
  86. # character string types
  87. char.UTF8String.tagSet: TextStringEncoder(),
  88. char.NumericString.tagSet: TextStringEncoder(),
  89. char.PrintableString.tagSet: TextStringEncoder(),
  90. char.TeletexString.tagSet: TextStringEncoder(),
  91. char.VideotexString.tagSet: TextStringEncoder(),
  92. char.IA5String.tagSet: TextStringEncoder(),
  93. char.GraphicString.tagSet: TextStringEncoder(),
  94. char.VisibleString.tagSet: TextStringEncoder(),
  95. char.GeneralString.tagSet: TextStringEncoder(),
  96. char.UniversalString.tagSet: TextStringEncoder(),
  97. char.BMPString.tagSet: TextStringEncoder(),
  98. # useful types
  99. useful.ObjectDescriptor.tagSet: OctetStringEncoder(),
  100. useful.GeneralizedTime.tagSet: OctetStringEncoder(),
  101. useful.UTCTime.tagSet: OctetStringEncoder()
  102. }
  103. # Put in ambiguous & non-ambiguous types for faster codec lookup
  104. typeMap = {
  105. univ.Boolean.typeId: BooleanEncoder(),
  106. univ.Integer.typeId: IntegerEncoder(),
  107. univ.BitString.typeId: BitStringEncoder(),
  108. univ.OctetString.typeId: OctetStringEncoder(),
  109. univ.Null.typeId: NullEncoder(),
  110. univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(),
  111. univ.Enumerated.typeId: IntegerEncoder(),
  112. univ.Real.typeId: RealEncoder(),
  113. # Sequence & Set have same tags as SequenceOf & SetOf
  114. univ.Set.typeId: SetEncoder(),
  115. univ.SetOf.typeId: SequenceOfEncoder(),
  116. univ.Sequence.typeId: SequenceEncoder(),
  117. univ.SequenceOf.typeId: SequenceOfEncoder(),
  118. univ.Choice.typeId: ChoiceEncoder(),
  119. univ.Any.typeId: AnyEncoder(),
  120. # character string types
  121. char.UTF8String.typeId: OctetStringEncoder(),
  122. char.NumericString.typeId: OctetStringEncoder(),
  123. char.PrintableString.typeId: OctetStringEncoder(),
  124. char.TeletexString.typeId: OctetStringEncoder(),
  125. char.VideotexString.typeId: OctetStringEncoder(),
  126. char.IA5String.typeId: OctetStringEncoder(),
  127. char.GraphicString.typeId: OctetStringEncoder(),
  128. char.VisibleString.typeId: OctetStringEncoder(),
  129. char.GeneralString.typeId: OctetStringEncoder(),
  130. char.UniversalString.typeId: OctetStringEncoder(),
  131. char.BMPString.typeId: OctetStringEncoder(),
  132. # useful types
  133. useful.ObjectDescriptor.typeId: OctetStringEncoder(),
  134. useful.GeneralizedTime.typeId: OctetStringEncoder(),
  135. useful.UTCTime.typeId: OctetStringEncoder()
  136. }
  137. class Encoder(object):
  138. # noinspection PyDefaultArgument
  139. def __init__(self, tagMap, typeMap={}):
  140. self.__tagMap = tagMap
  141. self.__typeMap = typeMap
  142. def __call__(self, value, **options):
  143. if not isinstance(value, base.Asn1Item):
  144. raise error.PyAsn1Error('value is not valid (should be an instance of an ASN.1 Item)')
  145. if LOG:
  146. debug.scope.push(type(value).__name__)
  147. LOG('encoder called for type %s <%s>' % (type(value).__name__, value.prettyPrint()))
  148. tagSet = value.tagSet
  149. try:
  150. concreteEncoder = self.__typeMap[value.typeId]
  151. except KeyError:
  152. # use base type for codec lookup to recover untagged types
  153. baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag)
  154. try:
  155. concreteEncoder = self.__tagMap[baseTagSet]
  156. except KeyError:
  157. raise error.PyAsn1Error('No encoder for %s' % (value,))
  158. if LOG:
  159. LOG('using value codec %s chosen by %s' % (concreteEncoder.__class__.__name__, tagSet))
  160. pyObject = concreteEncoder.encode(value, self, **options)
  161. if LOG:
  162. LOG('encoder %s produced: %s' % (type(concreteEncoder).__name__, repr(pyObject)))
  163. debug.scope.pop()
  164. return pyObject
  165. #: Turns ASN.1 object into a Python built-in type object(s).
  166. #:
  167. #: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
  168. #: walks all its components recursively and produces a Python built-in type or a tree
  169. #: of those.
  170. #:
  171. #: One exception is that instead of :py:class:`dict`, the :py:class:`OrderedDict`
  172. #: can be produced (whenever available) to preserve ordering of the components
  173. #: in ASN.1 SEQUENCE.
  174. #:
  175. #: Parameters
  176. #: ----------
  177. # asn1Value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
  178. #: pyasn1 object to encode (or a tree of them)
  179. #:
  180. #: Returns
  181. #: -------
  182. #: : :py:class:`object`
  183. #: Python built-in type instance (or a tree of them)
  184. #:
  185. #: Raises
  186. #: ------
  187. #: ~pyasn1.error.PyAsn1Error
  188. #: On encoding errors
  189. #:
  190. #: Examples
  191. #: --------
  192. #: Encode ASN.1 value object into native Python types
  193. #:
  194. #: .. code-block:: pycon
  195. #:
  196. #: >>> seq = SequenceOf(componentType=Integer())
  197. #: >>> seq.extend([1, 2, 3])
  198. #: >>> encode(seq)
  199. #: [1, 2, 3]
  200. #:
  201. encode = Encoder(tagMap, typeMap)