encoder.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #
  2. # This file is part of pyasn1 software.
  3. #
  4. # Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
  5. # License: http://pyasn1.sf.net/license.html
  6. #
  7. from pyasn1.type import univ
  8. from pyasn1.type import useful
  9. from pyasn1.codec.ber import encoder
  10. from pyasn1.compat.octets import int2oct, str2octs, null
  11. from pyasn1 import error
  12. __all__ = ['encode']
  13. class BooleanEncoder(encoder.IntegerEncoder):
  14. def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
  15. if client == 0:
  16. substrate = int2oct(0)
  17. else:
  18. substrate = int2oct(255)
  19. return substrate, 0
  20. class BitStringEncoder(encoder.BitStringEncoder):
  21. def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
  22. return encoder.BitStringEncoder.encodeValue(
  23. self, encodeFun, client, defMode, 1000
  24. )
  25. class OctetStringEncoder(encoder.OctetStringEncoder):
  26. def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
  27. return encoder.OctetStringEncoder.encodeValue(
  28. self, encodeFun, client, defMode, 1000
  29. )
  30. class RealEncoder(encoder.RealEncoder):
  31. def _chooseEncBase(self, value):
  32. m, b, e = value
  33. return self._dropFloatingPoint(m, b, e)
  34. # specialized GeneralStringEncoder here
  35. class GeneralizedTimeEncoder(OctetStringEncoder):
  36. zchar = str2octs('Z')
  37. pluschar = str2octs('+')
  38. minuschar = str2octs('-')
  39. zero = str2octs('0')
  40. def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
  41. octets = client.asOctets()
  42. # This breaks too many existing data items
  43. # if '.' not in octets:
  44. # raise error.PyAsn1Error('Format must include fraction of second: %r' % octets)
  45. if len(octets) < 15:
  46. raise error.PyAsn1Error('Bad UTC time length: %r' % octets)
  47. if self.pluschar in octets or self.minuschar in octets:
  48. raise error.PyAsn1Error('Must be UTC time: %r' % octets)
  49. if octets[-1] != self.zchar[0]:
  50. raise error.PyAsn1Error('Missing timezone specifier: %r' % octets)
  51. return encoder.OctetStringEncoder.encodeValue(
  52. self, encodeFun, client, defMode, 1000
  53. )
  54. class UTCTimeEncoder(encoder.OctetStringEncoder):
  55. zchar = str2octs('Z')
  56. pluschar = str2octs('+')
  57. minuschar = str2octs('-')
  58. def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
  59. octets = client.asOctets()
  60. if self.pluschar in octets or self.minuschar in octets:
  61. raise error.PyAsn1Error('Must be UTC time: %r' % octets)
  62. if octets and octets[-1] != self.zchar[0]:
  63. client = client.clone(octets + self.zchar)
  64. if len(client) != 13:
  65. raise error.PyAsn1Error('Bad UTC time length: %r' % client)
  66. return encoder.OctetStringEncoder.encodeValue(
  67. self, encodeFun, client, defMode, 1000
  68. )
  69. class SetOfEncoder(encoder.SequenceOfEncoder):
  70. def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
  71. if isinstance(client, univ.SequenceAndSetBase):
  72. client.setDefaultComponents()
  73. client.verifySizeSpec()
  74. substrate = null
  75. idx = len(client)
  76. # This is certainly a hack but how else do I distinguish SetOf
  77. # from Set if they have the same tags&constraints?
  78. if isinstance(client, univ.SequenceAndSetBase):
  79. # Set
  80. comps = []
  81. while idx > 0:
  82. idx -= 1
  83. if client[idx] is None: # Optional component
  84. continue
  85. if client.getDefaultComponentByPosition(idx) == client[idx]:
  86. continue
  87. comps.append(client[idx])
  88. comps.sort(key=lambda x: isinstance(x, univ.Choice) and x.getMinTagSet() or x.getTagSet())
  89. for c in comps:
  90. substrate += encodeFun(c, defMode, maxChunkSize)
  91. else:
  92. # SetOf
  93. compSubs = []
  94. while idx > 0:
  95. idx -= 1
  96. compSubs.append(
  97. encodeFun(client[idx], defMode, maxChunkSize)
  98. )
  99. compSubs.sort() # perhaps padding's not needed
  100. substrate = null
  101. for compSub in compSubs:
  102. substrate += compSub
  103. return substrate, 1
  104. tagMap = encoder.tagMap.copy()
  105. tagMap.update({
  106. univ.Boolean.tagSet: BooleanEncoder(),
  107. univ.BitString.tagSet: BitStringEncoder(),
  108. univ.OctetString.tagSet: OctetStringEncoder(),
  109. univ.Real.tagSet: RealEncoder(),
  110. useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(),
  111. useful.UTCTime.tagSet: UTCTimeEncoder(),
  112. univ.SetOf().tagSet: SetOfEncoder() # conflcts with Set
  113. })
  114. typeMap = encoder.typeMap.copy()
  115. typeMap.update({
  116. univ.Set.typeId: SetOfEncoder(),
  117. univ.SetOf.typeId: SetOfEncoder()
  118. })
  119. class Encoder(encoder.Encoder):
  120. def __call__(self, client, defMode=False, maxChunkSize=0):
  121. return encoder.Encoder.__call__(self, client, defMode, maxChunkSize)
  122. #: Turns ASN.1 object into CER octet stream.
  123. #:
  124. #: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
  125. #: walks all its components recursively and produces a CER octet stream.
  126. #:
  127. #: Parameters
  128. #: ----------
  129. # value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
  130. #: A pyasn1 object to encode
  131. #:
  132. #: defMode: :py:class:`bool`
  133. #: If `False`, produces indefinite length encoding
  134. #:
  135. #: maxChunkSize: :py:class:`int`
  136. #: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size)
  137. #:
  138. #: Returns
  139. #: -------
  140. #: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
  141. #: Given ASN.1 object encoded into BER octetstream
  142. #:
  143. #: Raises
  144. #: ------
  145. #: : :py:class:`pyasn1.error.PyAsn1Error`
  146. #: On encoding errors
  147. encode = Encoder(tagMap, typeMap)
  148. # EncoderFactory queries class instance and builds a map of tags -> encoders