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