Development of an internal social media platform with personalised dashboards for students
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.

encoder.py 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #
  2. # This file is part of pyasn1 software.
  3. #
  4. # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
  5. # License: http://snmplabs.com/pyasn1/license.html
  6. #
  7. from pyasn1 import error
  8. from pyasn1.codec.ber import encoder
  9. from pyasn1.compat.octets import str2octs, null
  10. from pyasn1.type import univ
  11. from pyasn1.type import useful
  12. __all__ = ['encode']
  13. class BooleanEncoder(encoder.IntegerEncoder):
  14. def encodeValue(self, value, asn1Spec, encodeFun, **options):
  15. if value == 0:
  16. substrate = (0,)
  17. else:
  18. substrate = (255,)
  19. return substrate, False, False
  20. class RealEncoder(encoder.RealEncoder):
  21. def _chooseEncBase(self, value):
  22. m, b, e = value
  23. return self._dropFloatingPoint(m, b, e)
  24. # specialized GeneralStringEncoder here
  25. class TimeEncoderMixIn(object):
  26. zchar, = str2octs('Z')
  27. pluschar, = str2octs('+')
  28. minuschar, = str2octs('-')
  29. commachar, = str2octs(',')
  30. minLength = 12
  31. maxLength = 19
  32. def encodeValue(self, value, asn1Spec, encodeFun, **options):
  33. # Encoding constraints:
  34. # - minutes are mandatory, seconds are optional
  35. # - subseconds must NOT be zero
  36. # - no hanging fraction dot
  37. # - time in UTC (Z)
  38. # - only dot is allowed for fractions
  39. if asn1Spec is not None:
  40. value = asn1Spec.clone(value)
  41. octets = value.asOctets()
  42. if not self.minLength < len(octets) < self.maxLength:
  43. raise error.PyAsn1Error('Length constraint violated: %r' % value)
  44. if self.pluschar in octets or self.minuschar in octets:
  45. raise error.PyAsn1Error('Must be UTC time: %r' % octets)
  46. if octets[-1] != self.zchar:
  47. raise error.PyAsn1Error('Missing "Z" time zone specifier: %r' % octets)
  48. if self.commachar in octets:
  49. raise error.PyAsn1Error('Comma in fractions disallowed: %r' % value)
  50. options.update(maxChunkSize=1000)
  51. return encoder.OctetStringEncoder.encodeValue(
  52. self, value, asn1Spec, encodeFun, **options
  53. )
  54. class GeneralizedTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):
  55. minLength = 12
  56. maxLength = 19
  57. class UTCTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):
  58. minLength = 10
  59. maxLength = 14
  60. class SetEncoder(encoder.SequenceEncoder):
  61. @staticmethod
  62. def _componentSortKey(componentAndType):
  63. """Sort SET components by tag
  64. Sort regardless of the Choice value (static sort)
  65. """
  66. component, asn1Spec = componentAndType
  67. if asn1Spec is None:
  68. asn1Spec = component
  69. if asn1Spec.typeId == univ.Choice.typeId and not asn1Spec.tagSet:
  70. if asn1Spec.tagSet:
  71. return asn1Spec.tagSet
  72. else:
  73. return asn1Spec.componentType.minTagSet
  74. else:
  75. return asn1Spec.tagSet
  76. def encodeValue(self, value, asn1Spec, encodeFun, **options):
  77. substrate = null
  78. comps = []
  79. compsMap = {}
  80. if asn1Spec is None:
  81. # instance of ASN.1 schema
  82. value.verifySizeSpec()
  83. namedTypes = value.componentType
  84. for idx, component in enumerate(value.values()):
  85. if namedTypes:
  86. namedType = namedTypes[idx]
  87. if namedType.isOptional and not component.isValue:
  88. continue
  89. if namedType.isDefaulted and component == namedType.asn1Object:
  90. continue
  91. compsMap[id(component)] = namedType
  92. else:
  93. compsMap[id(component)] = None
  94. comps.append((component, asn1Spec))
  95. else:
  96. # bare Python value + ASN.1 schema
  97. for idx, namedType in enumerate(asn1Spec.componentType.namedTypes):
  98. try:
  99. component = value[namedType.name]
  100. except KeyError:
  101. raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value))
  102. if namedType.isOptional and namedType.name not in value:
  103. continue
  104. if namedType.isDefaulted and component == namedType.asn1Object:
  105. continue
  106. compsMap[id(component)] = namedType
  107. comps.append((component, asn1Spec[idx]))
  108. for comp, compType in sorted(comps, key=self._componentSortKey):
  109. namedType = compsMap[id(comp)]
  110. if namedType:
  111. options.update(ifNotEmpty=namedType.isOptional)
  112. chunk = encodeFun(comp, compType, **options)
  113. # wrap open type blob if needed
  114. if namedType and namedType.openType:
  115. wrapType = namedType.asn1Object
  116. if wrapType.tagSet and not wrapType.isSameTypeWith(comp):
  117. chunk = encodeFun(chunk, wrapType, **options)
  118. substrate += chunk
  119. return substrate, True, True
  120. class SetOfEncoder(encoder.SequenceOfEncoder):
  121. def encodeValue(self, value, asn1Spec, encodeFun, **options):
  122. if asn1Spec is None:
  123. value.verifySizeSpec()
  124. else:
  125. asn1Spec = asn1Spec.componentType
  126. components = [encodeFun(x, asn1Spec, **options)
  127. for x in value]
  128. # sort by serialised and padded components
  129. if len(components) > 1:
  130. zero = str2octs('\x00')
  131. maxLen = max(map(len, components))
  132. paddedComponents = [
  133. (x.ljust(maxLen, zero), x) for x in components
  134. ]
  135. paddedComponents.sort(key=lambda x: x[0])
  136. components = [x[1] for x in paddedComponents]
  137. substrate = null.join(components)
  138. return substrate, True, True
  139. class SequenceEncoder(encoder.SequenceEncoder):
  140. omitEmptyOptionals = True
  141. class SequenceOfEncoder(encoder.SequenceOfEncoder):
  142. def encodeValue(self, value, asn1Spec, encodeFun, **options):
  143. if options.get('ifNotEmpty', False) and not len(value):
  144. return null, True, True
  145. if asn1Spec is None:
  146. value.verifySizeSpec()
  147. else:
  148. asn1Spec = asn1Spec.componentType
  149. substrate = null
  150. for idx, component in enumerate(value):
  151. substrate += encodeFun(value[idx], asn1Spec, **options)
  152. return substrate, True, True
  153. tagMap = encoder.tagMap.copy()
  154. tagMap.update({
  155. univ.Boolean.tagSet: BooleanEncoder(),
  156. univ.Real.tagSet: RealEncoder(),
  157. useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(),
  158. useful.UTCTime.tagSet: UTCTimeEncoder(),
  159. # Sequence & Set have same tags as SequenceOf & SetOf
  160. univ.SetOf.tagSet: SetOfEncoder(),
  161. univ.Sequence.typeId: SequenceEncoder()
  162. })
  163. typeMap = encoder.typeMap.copy()
  164. typeMap.update({
  165. univ.Boolean.typeId: BooleanEncoder(),
  166. univ.Real.typeId: RealEncoder(),
  167. useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(),
  168. useful.UTCTime.typeId: UTCTimeEncoder(),
  169. # Sequence & Set have same tags as SequenceOf & SetOf
  170. univ.Set.typeId: SetEncoder(),
  171. univ.SetOf.typeId: SetOfEncoder(),
  172. univ.Sequence.typeId: SequenceEncoder(),
  173. univ.SequenceOf.typeId: SequenceOfEncoder()
  174. })
  175. class Encoder(encoder.Encoder):
  176. fixedDefLengthMode = False
  177. fixedChunkSize = 1000
  178. #: Turns ASN.1 object into CER octet stream.
  179. #:
  180. #: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
  181. #: walks all its components recursively and produces a CER octet stream.
  182. #:
  183. #: Parameters
  184. #: ----------
  185. #: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
  186. #: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
  187. #: parameter is required to guide the encoding process.
  188. #:
  189. #: Keyword Args
  190. #: ------------
  191. #: asn1Spec:
  192. #: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
  193. #:
  194. #: Returns
  195. #: -------
  196. #: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
  197. #: Given ASN.1 object encoded into BER octet-stream
  198. #:
  199. #: Raises
  200. #: ------
  201. #: :py:class:`~pyasn1.error.PyAsn1Error`
  202. #: On encoding errors
  203. #:
  204. #: Examples
  205. #: --------
  206. #: Encode Python value into CER with ASN.1 schema
  207. #:
  208. #: .. code-block:: pycon
  209. #:
  210. #: >>> seq = SequenceOf(componentType=Integer())
  211. #: >>> encode([1, 2, 3], asn1Spec=seq)
  212. #: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'
  213. #:
  214. #: Encode ASN.1 value object into CER
  215. #:
  216. #: .. code-block:: pycon
  217. #:
  218. #: >>> seq = SequenceOf(componentType=Integer())
  219. #: >>> seq.extend([1, 2, 3])
  220. #: >>> encode(seq)
  221. #: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'
  222. #:
  223. encode = Encoder(tagMap, typeMap)
  224. # EncoderFactory queries class instance and builds a map of tags -> encoders