Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
encoder.py332 linesDownload Raw Back to cer
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.html6#7import warnings8 9from pyasn1 import error10from pyasn1.codec.ber import encoder11from pyasn1.type import univ12from pyasn1.type import useful13 14__all__ = ['Encoder', 'encode']15 16 17class BooleanEncoder(encoder.IntegerEncoder):18    def encodeValue(self, value, asn1Spec, encodeFun, **options):19        if value == 0:20            substrate = (0,)21        else:22            substrate = (255,)23        return substrate, False, False24 25 26class RealEncoder(encoder.RealEncoder):27    def _chooseEncBase(self, value):28        m, b, e = value29        return self._dropFloatingPoint(m, b, e)30 31 32# specialized GeneralStringEncoder here33 34class TimeEncoderMixIn(object):35    Z_CHAR = ord('Z')36    PLUS_CHAR = ord('+')37    MINUS_CHAR = ord('-')38    COMMA_CHAR = ord(',')39    DOT_CHAR = ord('.')40    ZERO_CHAR = ord('0')41 42    MIN_LENGTH = 1243    MAX_LENGTH = 1944 45    def encodeValue(self, value, asn1Spec, encodeFun, **options):46        # CER encoding constraints:47        # - minutes are mandatory, seconds are optional48        # - sub-seconds must NOT be zero / no meaningless zeros49        # - no hanging fraction dot50        # - time in UTC (Z)51        # - only dot is allowed for fractions52 53        if asn1Spec is not None:54            value = asn1Spec.clone(value)55 56        numbers = value.asNumbers()57 58        if self.PLUS_CHAR in numbers or self.MINUS_CHAR in numbers:59            raise error.PyAsn1Error('Must be UTC time: %r' % value)60 61        if numbers[-1] != self.Z_CHAR:62            raise error.PyAsn1Error('Missing "Z" time zone specifier: %r' % value)63 64        if self.COMMA_CHAR in numbers:65            raise error.PyAsn1Error('Comma in fractions disallowed: %r' % value)66 67        if self.DOT_CHAR in numbers:68 69            isModified = False70 71            numbers = list(numbers)72 73            searchIndex = min(numbers.index(self.DOT_CHAR) + 4, len(numbers) - 1)74 75            while numbers[searchIndex] != self.DOT_CHAR:76                if numbers[searchIndex] == self.ZERO_CHAR:77                    del numbers[searchIndex]78                    isModified = True79 80                searchIndex -= 181 82            searchIndex += 183 84            if searchIndex < len(numbers):85                if numbers[searchIndex] == self.Z_CHAR:86                    # drop hanging comma87                    del numbers[searchIndex - 1]88                    isModified = True89 90            if isModified:91                value = value.clone(numbers)92 93        if not self.MIN_LENGTH < len(numbers) < self.MAX_LENGTH:94            raise error.PyAsn1Error('Length constraint violated: %r' % value)95 96        options.update(maxChunkSize=1000)97 98        return encoder.OctetStringEncoder.encodeValue(99            self, value, asn1Spec, encodeFun, **options100        )101 102 103class GeneralizedTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):104    MIN_LENGTH = 12105    MAX_LENGTH = 20106 107 108class UTCTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):109    MIN_LENGTH = 10110    MAX_LENGTH = 14111 112 113class SetOfEncoder(encoder.SequenceOfEncoder):114    def encodeValue(self, value, asn1Spec, encodeFun, **options):115        chunks = self._encodeComponents(116            value, asn1Spec, encodeFun, **options)117 118        # sort by serialised and padded components119        if len(chunks) > 1:120            zero = b'\x00'121            maxLen = max(map(len, chunks))122            paddedChunks = [123                (x.ljust(maxLen, zero), x) for x in chunks124            ]125            paddedChunks.sort(key=lambda x: x[0])126 127            chunks = [x[1] for x in paddedChunks]128 129        return b''.join(chunks), True, True130 131 132class SequenceOfEncoder(encoder.SequenceOfEncoder):133    def encodeValue(self, value, asn1Spec, encodeFun, **options):134 135        if options.get('ifNotEmpty', False) and not len(value):136            return b'', True, True137 138        chunks = self._encodeComponents(139            value, asn1Spec, encodeFun, **options)140 141        return b''.join(chunks), True, True142 143 144class SetEncoder(encoder.SequenceEncoder):145    @staticmethod146    def _componentSortKey(componentAndType):147        """Sort SET components by tag148 149        Sort regardless of the Choice value (static sort)150        """151        component, asn1Spec = componentAndType152 153        if asn1Spec is None:154            asn1Spec = component155 156        if asn1Spec.typeId == univ.Choice.typeId and not asn1Spec.tagSet:157            if asn1Spec.tagSet:158                return asn1Spec.tagSet159            else:160                return asn1Spec.componentType.minTagSet161        else:162            return asn1Spec.tagSet163 164    def encodeValue(self, value, asn1Spec, encodeFun, **options):165 166        substrate = b''167 168        comps = []169        compsMap = {}170 171        if asn1Spec is None:172            # instance of ASN.1 schema173            inconsistency = value.isInconsistent174            if inconsistency:175                raise error.PyAsn1Error(176                    f"ASN.1 object {value.__class__.__name__} is inconsistent")177 178            namedTypes = value.componentType179 180            for idx, component in enumerate(value.values()):181                if namedTypes:182                    namedType = namedTypes[idx]183 184                    if namedType.isOptional and not component.isValue:185                            continue186 187                    if namedType.isDefaulted and component == namedType.asn1Object:188                            continue189 190                    compsMap[id(component)] = namedType191 192                else:193                    compsMap[id(component)] = None194 195                comps.append((component, asn1Spec))196 197        else:198            # bare Python value + ASN.1 schema199            for idx, namedType in enumerate(asn1Spec.componentType.namedTypes):200 201                try:202                    component = value[namedType.name]203 204                except KeyError:205                    raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value))206 207                if namedType.isOptional and namedType.name not in value:208                    continue209 210                if namedType.isDefaulted and component == namedType.asn1Object:211                    continue212 213                compsMap[id(component)] = namedType214                comps.append((component, asn1Spec[idx]))215 216        for comp, compType in sorted(comps, key=self._componentSortKey):217            namedType = compsMap[id(comp)]218 219            if namedType:220                options.update(ifNotEmpty=namedType.isOptional)221 222            chunk = encodeFun(comp, compType, **options)223 224            # wrap open type blob if needed225            if namedType and namedType.openType:226                wrapType = namedType.asn1Object227                if wrapType.tagSet and not wrapType.isSameTypeWith(comp):228                    chunk = encodeFun(chunk, wrapType, **options)229 230            substrate += chunk231 232        return substrate, True, True233 234 235class SequenceEncoder(encoder.SequenceEncoder):236    omitEmptyOptionals = True237 238 239TAG_MAP = encoder.TAG_MAP.copy()240 241TAG_MAP.update({242    univ.Boolean.tagSet: BooleanEncoder(),243    univ.Real.tagSet: RealEncoder(),244    useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(),245    useful.UTCTime.tagSet: UTCTimeEncoder(),246    # Sequence & Set have same tags as SequenceOf & SetOf247    univ.SetOf.tagSet: SetOfEncoder(),248    univ.Sequence.typeId: SequenceEncoder()249})250 251TYPE_MAP = encoder.TYPE_MAP.copy()252 253TYPE_MAP.update({254    univ.Boolean.typeId: BooleanEncoder(),255    univ.Real.typeId: RealEncoder(),256    useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(),257    useful.UTCTime.typeId: UTCTimeEncoder(),258    # Sequence & Set have same tags as SequenceOf & SetOf259    univ.Set.typeId: SetEncoder(),260    univ.SetOf.typeId: SetOfEncoder(),261    univ.Sequence.typeId: SequenceEncoder(),262    univ.SequenceOf.typeId: SequenceOfEncoder()263})264 265 266class SingleItemEncoder(encoder.SingleItemEncoder):267    fixedDefLengthMode = False268    fixedChunkSize = 1000269 270    TAG_MAP = TAG_MAP271    TYPE_MAP = TYPE_MAP272 273 274class Encoder(encoder.Encoder):275    SINGLE_ITEM_ENCODER = SingleItemEncoder276 277 278#: Turns ASN.1 object into CER octet stream.279#:280#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)281#: walks all its components recursively and produces a CER octet stream.282#:283#: Parameters284#: ----------285#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)286#:     A Python or pyasn1 object to encode. If Python object is given, `asnSpec`287#:     parameter is required to guide the encoding process.288#:289#: Keyword Args290#: ------------291#: asn1Spec:292#:     Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative293#:294#: Returns295#: -------296#: : :py:class:`bytes`297#:     Given ASN.1 object encoded into BER octet-stream298#:299#: Raises300#: ------301#: ~pyasn1.error.PyAsn1Error302#:     On encoding errors303#:304#: Examples305#: --------306#: Encode Python value into CER with ASN.1 schema307#:308#: .. code-block:: pycon309#:310#:    >>> seq = SequenceOf(componentType=Integer())311#:    >>> encode([1, 2, 3], asn1Spec=seq)312#:    b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'313#:314#: Encode ASN.1 value object into CER315#:316#: .. code-block:: pycon317#:318#:    >>> seq = SequenceOf(componentType=Integer())319#:    >>> seq.extend([1, 2, 3])320#:    >>> encode(seq)321#:    b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'322#:323encode = Encoder()324 325# EncoderFactory queries class instance and builds a map of tags -> encoders326 327def __getattr__(attr: str):328    if newAttr := {"tagMap": "TAG_MAP", "typeMap": "TYPE_MAP"}.get(attr):329        warnings.warn(f"{attr} is deprecated. Please use {newAttr} instead.", DeprecationWarning, stacklevel=2)330        return globals()[newAttr]331    raise AttributeError(attr)332 
codekingpro/portable-devtools · Team Ai