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.cer import encoder
11from pyasn1.type import univ
12
13__all__ = ['Encoder', 'encode']
14
15
16class SetEncoder(encoder.SetEncoder):
17 @staticmethod
18 def _componentSortKey(componentAndType):
19 """Sort SET components by tag
20
21 Sort depending on the actual Choice value (dynamic sort)
22 """
23 component, asn1Spec = componentAndType
24
25 if asn1Spec is None:
26 compType = component
27 else:
28 compType = asn1Spec
29
30 if compType.typeId == univ.Choice.typeId and not compType.tagSet:
31 if asn1Spec is None:
32 return component.getComponent().tagSet
33 else:
34 # TODO: move out of sorting key function
35 names = [namedType.name for namedType in asn1Spec.componentType.namedTypes
36 if namedType.name in component]
37 if len(names) != 1:
38 raise error.PyAsn1Error(
39 '%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', component))
40
41 # TODO: support nested CHOICE ordering
42 return asn1Spec[names[0]].tagSet
43
44 else:
45 return compType.tagSet
46
47
48TAG_MAP = encoder.TAG_MAP.copy()
49
50TAG_MAP.update({
51 # Set & SetOf have same tags
52 univ.Set.tagSet: SetEncoder()
53})
54
55TYPE_MAP = encoder.TYPE_MAP.copy()
56
57TYPE_MAP.update({
58 # Set & SetOf have same tags
59 univ.Set.typeId: SetEncoder()
60})
61
62
63class SingleItemEncoder(encoder.SingleItemEncoder):
64 fixedDefLengthMode = True
65 fixedChunkSize = 0
66
67 TAG_MAP = TAG_MAP
68 TYPE_MAP = TYPE_MAP
69
70
71class Encoder(encoder.Encoder):
72 SINGLE_ITEM_ENCODER = SingleItemEncoder
73
74
75#: Turns ASN.1 object into DER octet stream.
76#:
77#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
78#: walks all its components recursively and produces a DER octet stream.
79#:
80#: Parameters
81#: ----------
82#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
83#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
84#: parameter is required to guide the encoding process.
85#:
86#: Keyword Args
87#: ------------
88#: asn1Spec:
89#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
90#:
91#: Returns
92#: -------
93#: : :py:class:`bytes`
94#: Given ASN.1 object encoded into BER octet-stream
95#:
96#: Raises
97#: ------
98#: ~pyasn1.error.PyAsn1Error
99#: On encoding errors
100#:
101#: Examples
102#: --------
103#: Encode Python value into DER with ASN.1 schema
104#:
105#: .. code-block:: pycon
106#:
107#: >>> seq = SequenceOf(componentType=Integer())
108#: >>> encode([1, 2, 3], asn1Spec=seq)
109#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
110#:
111#: Encode ASN.1 value object into DER
112#:
113#: .. code-block:: pycon
114#:
115#: >>> seq = SequenceOf(componentType=Integer())
116#: >>> seq.extend([1, 2, 3])
117#: >>> encode(seq)
118#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
119#:
120encode = Encoder()
121
122def __getattr__(attr: str):
123 if newAttr := {"tagMap": "TAG_MAP", "typeMap": "TYPE_MAP"}.get(attr):
124 warnings.warn(f"{attr} is deprecated. Please use {newAttr} instead.", DeprecationWarning)
125 return globals()[newAttr]
126 raise AttributeError(attr)