decoder.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #
  2. # This file is part of pyasn1 software.
  3. #
  4. # Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
  5. # License: https://pyasn1.readthedocs.io/en/latest/license.html
  6. #
  7. import warnings
  8. from pyasn1 import error
  9. from pyasn1.codec.streaming import readFromStream
  10. from pyasn1.codec.ber import decoder
  11. from pyasn1.type import univ
  12. __all__ = ['decode', 'StreamingDecoder']
  13. SubstrateUnderrunError = error.SubstrateUnderrunError
  14. class BooleanPayloadDecoder(decoder.AbstractSimplePayloadDecoder):
  15. protoComponent = univ.Boolean(0)
  16. def valueDecoder(self, substrate, asn1Spec,
  17. tagSet=None, length=None, state=None,
  18. decodeFun=None, substrateFun=None,
  19. **options):
  20. if length != 1:
  21. raise error.PyAsn1Error('Not single-octet Boolean payload')
  22. for chunk in readFromStream(substrate, length, options):
  23. if isinstance(chunk, SubstrateUnderrunError):
  24. yield chunk
  25. byte = chunk[0]
  26. # CER/DER specifies encoding of TRUE as 0xFF and FALSE as 0x0, while
  27. # BER allows any non-zero value as TRUE; cf. sections 8.2.2. and 11.1
  28. # in https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
  29. if byte == 0xff:
  30. value = 1
  31. elif byte == 0x00:
  32. value = 0
  33. else:
  34. raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte)
  35. yield self._createComponent(asn1Spec, tagSet, value, **options)
  36. # TODO: prohibit non-canonical encoding
  37. BitStringPayloadDecoder = decoder.BitStringPayloadDecoder
  38. OctetStringPayloadDecoder = decoder.OctetStringPayloadDecoder
  39. RealPayloadDecoder = decoder.RealPayloadDecoder
  40. TAG_MAP = decoder.TAG_MAP.copy()
  41. TAG_MAP.update(
  42. {univ.Boolean.tagSet: BooleanPayloadDecoder(),
  43. univ.BitString.tagSet: BitStringPayloadDecoder(),
  44. univ.OctetString.tagSet: OctetStringPayloadDecoder(),
  45. univ.Real.tagSet: RealPayloadDecoder()}
  46. )
  47. TYPE_MAP = decoder.TYPE_MAP.copy()
  48. # Put in non-ambiguous types for faster codec lookup
  49. for typeDecoder in TAG_MAP.values():
  50. if typeDecoder.protoComponent is not None:
  51. typeId = typeDecoder.protoComponent.__class__.typeId
  52. if typeId is not None and typeId not in TYPE_MAP:
  53. TYPE_MAP[typeId] = typeDecoder
  54. class SingleItemDecoder(decoder.SingleItemDecoder):
  55. __doc__ = decoder.SingleItemDecoder.__doc__
  56. TAG_MAP = TAG_MAP
  57. TYPE_MAP = TYPE_MAP
  58. class StreamingDecoder(decoder.StreamingDecoder):
  59. __doc__ = decoder.StreamingDecoder.__doc__
  60. SINGLE_ITEM_DECODER = SingleItemDecoder
  61. class Decoder(decoder.Decoder):
  62. __doc__ = decoder.Decoder.__doc__
  63. STREAMING_DECODER = StreamingDecoder
  64. #: Turns CER octet stream into an ASN.1 object.
  65. #:
  66. #: Takes CER octet-stream and decode it into an ASN.1 object
  67. #: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which
  68. #: may be a scalar or an arbitrary nested structure.
  69. #:
  70. #: Parameters
  71. #: ----------
  72. #: substrate: :py:class:`bytes`
  73. #: CER octet-stream
  74. #:
  75. #: Keyword Args
  76. #: ------------
  77. #: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
  78. #: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure
  79. #: being decoded, *asn1Spec* may or may not be required. Most common reason for
  80. #: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode.
  81. #:
  82. #: Returns
  83. #: -------
  84. #: : :py:class:`tuple`
  85. #: A tuple of pyasn1 object recovered from CER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
  86. #: and the unprocessed trailing portion of the *substrate* (may be empty)
  87. #:
  88. #: Raises
  89. #: ------
  90. #: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError
  91. #: On decoding errors
  92. #:
  93. #: Examples
  94. #: --------
  95. #: Decode CER serialisation without ASN.1 schema
  96. #:
  97. #: .. code-block:: pycon
  98. #:
  99. #: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00')
  100. #: >>> str(s)
  101. #: SequenceOf:
  102. #: 1 2 3
  103. #:
  104. #: Decode CER serialisation with ASN.1 schema
  105. #:
  106. #: .. code-block:: pycon
  107. #:
  108. #: >>> seq = SequenceOf(componentType=Integer())
  109. #: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00', asn1Spec=seq)
  110. #: >>> str(s)
  111. #: SequenceOf:
  112. #: 1 2 3
  113. #:
  114. decode = Decoder()
  115. def __getattr__(attr: str):
  116. if newAttr := {"tagMap": "TAG_MAP", "typeMap": "TYPE_MAP"}.get(attr):
  117. warnings.warn(f"{attr} is deprecated. Please use {newAttr} instead.", DeprecationWarning)
  118. return globals()[newAttr]
  119. raise AttributeError(attr)