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