• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Philippe Biondi <phil@secdev.org>
5# Acknowledgment: Maxence Tury <maxence.tury@ssi.gouv.fr>
6# Acknowledgment: Ralph Broenink
7
8"""
9Basic Encoding Rules (BER) for ASN.1
10"""
11
12# Good read: https://luca.ntop.org/Teaching/Appunti/asn1.html
13
14from scapy.error import warning
15from scapy.compat import chb, orb, bytes_encode
16from scapy.utils import binrepr, inet_aton, inet_ntoa
17from scapy.asn1.asn1 import (
18    ASN1Tag,
19    ASN1_BADTAG,
20    ASN1_BadTag_Decoding_Error,
21    ASN1_Class,
22    ASN1_Class_UNIVERSAL,
23    ASN1_Codecs,
24    ASN1_DECODING_ERROR,
25    ASN1_Decoding_Error,
26    ASN1_Encoding_Error,
27    ASN1_Error,
28    ASN1_Object,
29    _ASN1_ERROR,
30)
31
32from typing import (
33    Any,
34    AnyStr,
35    Dict,
36    Generic,
37    List,
38    Optional,
39    Tuple,
40    Type,
41    TypeVar,
42    Union,
43    cast,
44)
45
46##################
47#  BER encoding  #
48##################
49
50
51#    [ BER tools ]    #
52
53
54class BER_Exception(Exception):
55    pass
56
57
58class BER_Encoding_Error(ASN1_Encoding_Error):
59    def __init__(self,
60                 msg,  # type: str
61                 encoded=None,  # type: Optional[Union[BERcodec_Object[Any], str]]  # noqa: E501
62                 remaining=b""  # type: bytes
63                 ):
64        # type: (...) -> None
65        Exception.__init__(self, msg)
66        self.remaining = remaining
67        self.encoded = encoded
68
69    def __str__(self):
70        # type: () -> str
71        s = Exception.__str__(self)
72        if isinstance(self.encoded, ASN1_Object):
73            s += "\n### Already encoded ###\n%s" % self.encoded.strshow()
74        else:
75            s += "\n### Already encoded ###\n%r" % self.encoded
76        s += "\n### Remaining ###\n%r" % self.remaining
77        return s
78
79
80class BER_Decoding_Error(ASN1_Decoding_Error):
81    def __init__(self,
82                 msg,  # type: str
83                 decoded=None,  # type: Optional[Any]
84                 remaining=b""  # type: bytes
85                 ):
86        # type: (...) -> None
87        Exception.__init__(self, msg)
88        self.remaining = remaining
89        self.decoded = decoded
90
91    def __str__(self):
92        # type: () -> str
93        s = Exception.__str__(self)
94        if isinstance(self.decoded, ASN1_Object):
95            s += "\n### Already decoded ###\n%s" % self.decoded.strshow()
96        else:
97            s += "\n### Already decoded ###\n%r" % self.decoded
98        s += "\n### Remaining ###\n%r" % self.remaining
99        return s
100
101
102class BER_BadTag_Decoding_Error(BER_Decoding_Error,
103                                ASN1_BadTag_Decoding_Error):
104    pass
105
106
107def BER_len_enc(ll, size=0):
108    # type: (int, Optional[int]) -> bytes
109    from scapy.config import conf
110    if size is None:
111        size = conf.ASN1_default_long_size
112    if ll <= 127 and size == 0:
113        return chb(ll)
114    s = b""
115    while ll or size > 0:
116        s = chb(ll & 0xff) + s
117        ll >>= 8
118        size -= 1
119    if len(s) > 127:
120        raise BER_Exception(
121            "BER_len_enc: Length too long (%i) to be encoded [%r]" %
122            (len(s), s)
123        )
124    return chb(len(s) | 0x80) + s
125
126
127def BER_len_dec(s):
128    # type: (bytes) -> Tuple[int, bytes]
129    tmp_len = orb(s[0])
130    if not tmp_len & 0x80:
131        return tmp_len, s[1:]
132    tmp_len &= 0x7f
133    if len(s) <= tmp_len:
134        raise BER_Decoding_Error(
135            "BER_len_dec: Got %i bytes while expecting %i" %
136            (len(s) - 1, tmp_len),
137            remaining=s
138        )
139    ll = 0
140    for c in s[1:tmp_len + 1]:
141        ll <<= 8
142        ll |= orb(c)
143    return ll, s[tmp_len + 1:]
144
145
146def BER_num_enc(ll, size=1):
147    # type: (int, int) -> bytes
148    x = []  # type: List[int]
149    while ll or size > 0:
150        x.insert(0, ll & 0x7f)
151        if len(x) > 1:
152            x[0] |= 0x80
153        ll >>= 7
154        size -= 1
155    return b"".join(chb(k) for k in x)
156
157
158def BER_num_dec(s, cls_id=0):
159    # type: (bytes, int) -> Tuple[int, bytes]
160    if len(s) == 0:
161        raise BER_Decoding_Error("BER_num_dec: got empty string", remaining=s)
162    x = cls_id
163    for i, c in enumerate(s):
164        c = orb(c)
165        x <<= 7
166        x |= c & 0x7f
167        if not c & 0x80:
168            break
169    if c & 0x80:
170        raise BER_Decoding_Error("BER_num_dec: unfinished number description",
171                                 remaining=s)
172    return x, s[i + 1:]
173
174
175def BER_id_dec(s):
176    # type: (bytes) -> Tuple[int, bytes]
177    # This returns the tag ALONG WITH THE PADDED CLASS+CONSTRUCTIVE INFO.
178    # Let's recall that bits 8-7 from the first byte of the tag encode
179    # the class information, while bit 6 means primitive or constructive.
180    #
181    # For instance, with low-tag-number b'\x81', class would be 0b10
182    # ('context-specific') and tag 0x01, but we return 0x81 as a whole.
183    # For b'\xff\x22', class would be 0b11 ('private'), constructed, then
184    # padding, then tag 0x22, but we return (0xff>>5)*128^1 + 0x22*128^0.
185    # Why the 5-bit-shifting? Because it provides an unequivocal encoding
186    # on base 128 (note that 0xff would equal 1*128^1 + 127*128^0...),
187    # as we know that bits 5 to 1 are fixed to 1 anyway.
188    #
189    # As long as there is no class differentiation, we have to keep this info
190    # encoded in scapy's tag in order to reuse it for packet building.
191    # Note that tags thus may have to be hard-coded with their extended
192    # information, e.g. a SEQUENCE from asn1.py has a direct tag 0x20|16.
193    x = orb(s[0])
194    if x & 0x1f != 0x1f:
195        # low-tag-number
196        return x, s[1:]
197    else:
198        # high-tag-number
199        return BER_num_dec(s[1:], cls_id=x >> 5)
200
201
202def BER_id_enc(n):
203    # type: (int) -> bytes
204    if n < 256:
205        # low-tag-number
206        return chb(n)
207    else:
208        # high-tag-number
209        s = BER_num_enc(n)
210        tag = orb(s[0])             # first byte, as an int
211        tag &= 0x07                 # reset every bit from 8 to 4
212        tag <<= 5                   # move back the info bits on top
213        tag |= 0x1f                 # pad with 1s every bit from 5 to 1
214        return chb(tag) + s[1:]
215
216# The functions below provide implicit and explicit tagging support.
217
218
219def BER_tagging_dec(s,  # type: bytes
220                    hidden_tag=None,  # type: Optional[int | ASN1Tag]
221                    implicit_tag=None,  # type: Optional[int]
222                    explicit_tag=None,  # type: Optional[int]
223                    safe=False,  # type: Optional[bool]
224                    _fname="",  # type: str
225                    ):
226    # type: (...) -> Tuple[Optional[int], bytes]
227    # We output the 'real_tag' if it is different from the (im|ex)plicit_tag.
228    # 'hidden_tag' is the type tag that is implicited when 'implicit_tag' is used.
229    real_tag = None
230    if len(s) > 0:
231        err_msg = (
232            "BER_tagging_dec: observed tag 0x%.02x does not "
233            "match expected tag 0x%.02x (%s)"
234        )
235        if implicit_tag is not None:
236            ber_id, s = BER_id_dec(s)
237            if ber_id != implicit_tag:
238                if not safe and ber_id != implicit_tag:
239                    raise BER_Decoding_Error(err_msg % (
240                        ber_id, implicit_tag, _fname),
241                        remaining=s)
242                else:
243                    real_tag = ber_id
244            s = chb(int(hidden_tag)) + s  # type: ignore
245        elif explicit_tag is not None:
246            ber_id, s = BER_id_dec(s)
247            if ber_id != explicit_tag:
248                if not safe:
249                    raise BER_Decoding_Error(
250                        err_msg % (ber_id, explicit_tag, _fname),
251                        remaining=s)
252                else:
253                    real_tag = ber_id
254            l, s = BER_len_dec(s)
255    return real_tag, s
256
257
258def BER_tagging_enc(s, implicit_tag=None, explicit_tag=None):
259    # type: (bytes, Optional[int], Optional[int]) -> bytes
260    if len(s) > 0:
261        if implicit_tag is not None:
262            s = BER_id_enc(implicit_tag) + s[1:]
263        elif explicit_tag is not None:
264            s = BER_id_enc(explicit_tag) + BER_len_enc(len(s)) + s
265    return s
266
267#    [ BER classes ]    #
268
269
270class BERcodec_metaclass(type):
271    def __new__(cls,
272                name,  # type: str
273                bases,  # type: Tuple[type, ...]
274                dct  # type: Dict[str, Any]
275                ):
276        # type: (...) -> Type[BERcodec_Object[Any]]
277        c = cast('Type[BERcodec_Object[Any]]',
278                 super(BERcodec_metaclass, cls).__new__(cls, name, bases, dct))
279        try:
280            c.tag.register(c.codec, c)
281        except Exception:
282            warning("Error registering %r for %r" % (c.tag, c.codec))
283        return c
284
285
286_K = TypeVar('_K')
287
288
289class BERcodec_Object(Generic[_K], metaclass=BERcodec_metaclass):
290    codec = ASN1_Codecs.BER
291    tag = ASN1_Class_UNIVERSAL.ANY
292
293    @classmethod
294    def asn1_object(cls, val):
295        # type: (_K) -> ASN1_Object[_K]
296        return cls.tag.asn1_object(val)
297
298    @classmethod
299    def check_string(cls, s):
300        # type: (bytes) -> None
301        if not s:
302            raise BER_Decoding_Error(
303                "%s: Got empty object while expecting tag %r" %
304                (cls.__name__, cls.tag), remaining=s
305            )
306
307    @classmethod
308    def check_type(cls, s):
309        # type: (bytes) -> bytes
310        cls.check_string(s)
311        tag, remainder = BER_id_dec(s)
312        if not isinstance(tag, int) or cls.tag != tag:
313            raise BER_BadTag_Decoding_Error(
314                "%s: Got tag [%i/%#x] while expecting %r" %
315                (cls.__name__, tag, tag, cls.tag), remaining=s
316            )
317        return remainder
318
319    @classmethod
320    def check_type_get_len(cls, s):
321        # type: (bytes) -> Tuple[int, bytes]
322        s2 = cls.check_type(s)
323        if not s2:
324            raise BER_Decoding_Error("%s: No bytes while expecting a length" %
325                                     cls.__name__, remaining=s)
326        return BER_len_dec(s2)
327
328    @classmethod
329    def check_type_check_len(cls, s):
330        # type: (bytes) -> Tuple[int, bytes, bytes]
331        l, s3 = cls.check_type_get_len(s)
332        if len(s3) < l:
333            raise BER_Decoding_Error("%s: Got %i bytes while expecting %i" %
334                                     (cls.__name__, len(s3), l), remaining=s)
335        return l, s3[:l], s3[l:]
336
337    @classmethod
338    def do_dec(cls,
339               s,  # type: bytes
340               context=None,  # type: Optional[Type[ASN1_Class]]
341               safe=False  # type: bool
342               ):
343        # type: (...) -> Tuple[ASN1_Object[Any], bytes]
344        if context is not None:
345            _context = context
346        else:
347            _context = cls.tag.context
348        cls.check_string(s)
349        p, remainder = BER_id_dec(s)
350        if p not in _context:
351            t = s
352            if len(t) > 18:
353                t = t[:15] + b"..."
354            raise BER_Decoding_Error("Unknown prefix [%02x] for [%r]" %
355                                     (p, t), remaining=s)
356        tag = _context[p]
357        codec = cast('Type[BERcodec_Object[_K]]',
358                     tag.get_codec(ASN1_Codecs.BER))
359        if codec == BERcodec_Object:
360            # Value type defined as Unknown
361            l, s = BER_num_dec(remainder)
362            return ASN1_BADTAG(s[:l]), s[l:]
363        return codec.dec(s, _context, safe)
364
365    @classmethod
366    def dec(cls,
367            s,  # type: bytes
368            context=None,  # type: Optional[Type[ASN1_Class]]
369            safe=False,  # type: bool
370            ):
371        # type: (...) -> Tuple[Union[_ASN1_ERROR, ASN1_Object[_K]], bytes]
372        if not safe:
373            return cls.do_dec(s, context, safe)
374        try:
375            return cls.do_dec(s, context, safe)
376        except BER_BadTag_Decoding_Error as e:
377            o, remain = BERcodec_Object.dec(
378                e.remaining, context, safe
379            )  # type: Tuple[ASN1_Object[Any], bytes]
380            return ASN1_BADTAG(o), remain
381        except BER_Decoding_Error as e:
382            return ASN1_DECODING_ERROR(s, exc=e), b""
383        except ASN1_Error as e:
384            return ASN1_DECODING_ERROR(s, exc=e), b""
385
386    @classmethod
387    def safedec(cls,
388                s,  # type: bytes
389                context=None,  # type: Optional[Type[ASN1_Class]]
390                ):
391        # type: (...) -> Tuple[Union[_ASN1_ERROR, ASN1_Object[_K]], bytes]
392        return cls.dec(s, context, safe=True)
393
394    @classmethod
395    def enc(cls, s, size_len=0):
396        # type: (_K, Optional[int]) -> bytes
397        if isinstance(s, (str, bytes)):
398            return BERcodec_STRING.enc(s, size_len=size_len)
399        else:
400            try:
401                return BERcodec_INTEGER.enc(int(s), size_len=size_len)  # type: ignore
402            except TypeError:
403                raise TypeError("Trying to encode an invalid value !")
404
405
406ASN1_Codecs.BER.register_stem(BERcodec_Object)
407
408
409##########################
410#    BERcodec objects    #
411##########################
412
413class BERcodec_INTEGER(BERcodec_Object[int]):
414    tag = ASN1_Class_UNIVERSAL.INTEGER
415
416    @classmethod
417    def enc(cls, i, size_len=0):
418        # type: (int, Optional[int]) -> bytes
419        ls = []
420        while True:
421            ls.append(i & 0xff)
422            if -127 <= i < 0:
423                break
424            if 128 <= i <= 255:
425                ls.append(0)
426            i >>= 8
427            if not i:
428                break
429        s = [chb(int(c)) for c in ls]
430        s.append(BER_len_enc(len(s), size=size_len))
431        s.append(chb(int(cls.tag)))
432        s.reverse()
433        return b"".join(s)
434
435    @classmethod
436    def do_dec(cls,
437               s,  # type: bytes
438               context=None,  # type: Optional[Type[ASN1_Class]]
439               safe=False,  # type: bool
440               ):
441        # type: (...) -> Tuple[ASN1_Object[int], bytes]
442        l, s, t = cls.check_type_check_len(s)
443        x = 0
444        if s:
445            if orb(s[0]) & 0x80:  # negative int
446                x = -1
447            for c in s:
448                x <<= 8
449                x |= orb(c)
450        return cls.asn1_object(x), t
451
452
453class BERcodec_BOOLEAN(BERcodec_INTEGER):
454    tag = ASN1_Class_UNIVERSAL.BOOLEAN
455
456
457class BERcodec_BIT_STRING(BERcodec_Object[str]):
458    tag = ASN1_Class_UNIVERSAL.BIT_STRING
459
460    @classmethod
461    def do_dec(cls,
462               s,  # type: bytes
463               context=None,  # type: Optional[Type[ASN1_Class]]
464               safe=False  # type: bool
465               ):
466        # type: (...) -> Tuple[ASN1_Object[str], bytes]
467        # /!\ the unused_bits information is lost after this decoding
468        l, s, t = cls.check_type_check_len(s)
469        if len(s) > 0:
470            unused_bits = orb(s[0])
471            if safe and unused_bits > 7:
472                raise BER_Decoding_Error(
473                    "BERcodec_BIT_STRING: too many unused_bits advertised",
474                    remaining=s
475                )
476            fs = "".join(binrepr(orb(x)).zfill(8) for x in s[1:])
477            if unused_bits > 0:
478                fs = fs[:-unused_bits]
479            return cls.tag.asn1_object(fs), t
480        else:
481            raise BER_Decoding_Error(
482                "BERcodec_BIT_STRING found no content "
483                "(not even unused_bits byte)",
484                remaining=s
485            )
486
487    @classmethod
488    def enc(cls, _s, size_len=0):
489        # type: (AnyStr, Optional[int]) -> bytes
490        # /!\ this is DER encoding (bit strings are only zero-bit padded)
491        s = bytes_encode(_s)
492        if len(s) % 8 == 0:
493            unused_bits = 0
494        else:
495            unused_bits = 8 - len(s) % 8
496            s += b"0" * unused_bits
497        s = b"".join(chb(int(b"".join(chb(y) for y in x), 2))
498                     for x in zip(*[iter(s)] * 8))
499        s = chb(unused_bits) + s
500        return chb(int(cls.tag)) + BER_len_enc(len(s), size=size_len) + s
501
502
503class BERcodec_STRING(BERcodec_Object[str]):
504    tag = ASN1_Class_UNIVERSAL.STRING
505
506    @classmethod
507    def enc(cls, _s, size_len=0):
508        # type: (Union[str, bytes], Optional[int]) -> bytes
509        s = bytes_encode(_s)
510        # Be sure we are encoding bytes
511        return chb(int(cls.tag)) + BER_len_enc(len(s), size=size_len) + s
512
513    @classmethod
514    def do_dec(cls,
515               s,  # type: bytes
516               context=None,  # type: Optional[Type[ASN1_Class]]
517               safe=False,  # type: bool
518               ):
519        # type: (...) -> Tuple[ASN1_Object[Any], bytes]
520        l, s, t = cls.check_type_check_len(s)
521        return cls.tag.asn1_object(s), t
522
523
524class BERcodec_NULL(BERcodec_INTEGER):
525    tag = ASN1_Class_UNIVERSAL.NULL
526
527    @classmethod
528    def enc(cls, i, size_len=0):
529        # type: (int, Optional[int]) -> bytes
530        if i == 0:
531            return chb(int(cls.tag)) + b"\0"
532        else:
533            return super(cls, cls).enc(i, size_len=size_len)
534
535
536class BERcodec_OID(BERcodec_Object[bytes]):
537    tag = ASN1_Class_UNIVERSAL.OID
538
539    @classmethod
540    def enc(cls, _oid, size_len=0):
541        # type: (AnyStr, Optional[int]) -> bytes
542        oid = bytes_encode(_oid)
543        if oid:
544            lst = [int(x) for x in oid.strip(b".").split(b".")]
545        else:
546            lst = list()
547        if len(lst) >= 2:
548            lst[1] += 40 * lst[0]
549            del lst[0]
550        s = b"".join(BER_num_enc(k) for k in lst)
551        return chb(int(cls.tag)) + BER_len_enc(len(s), size=size_len) + s
552
553    @classmethod
554    def do_dec(cls,
555               s,  # type: bytes
556               context=None,  # type: Optional[Type[ASN1_Class]]
557               safe=False,  # type: bool
558               ):
559        # type: (...) -> Tuple[ASN1_Object[bytes], bytes]
560        l, s, t = cls.check_type_check_len(s)
561        lst = []
562        while s:
563            l, s = BER_num_dec(s)
564            lst.append(l)
565        if (len(lst) > 0):
566            lst.insert(0, lst[0] // 40)
567            lst[1] %= 40
568        return (
569            cls.asn1_object(b".".join(str(k).encode('ascii') for k in lst)),
570            t,
571        )
572
573
574class BERcodec_ENUMERATED(BERcodec_INTEGER):
575    tag = ASN1_Class_UNIVERSAL.ENUMERATED
576
577
578class BERcodec_UTF8_STRING(BERcodec_STRING):
579    tag = ASN1_Class_UNIVERSAL.UTF8_STRING
580
581
582class BERcodec_NUMERIC_STRING(BERcodec_STRING):
583    tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING
584
585
586class BERcodec_PRINTABLE_STRING(BERcodec_STRING):
587    tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING
588
589
590class BERcodec_T61_STRING(BERcodec_STRING):
591    tag = ASN1_Class_UNIVERSAL.T61_STRING
592
593
594class BERcodec_VIDEOTEX_STRING(BERcodec_STRING):
595    tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING
596
597
598class BERcodec_IA5_STRING(BERcodec_STRING):
599    tag = ASN1_Class_UNIVERSAL.IA5_STRING
600
601
602class BERcodec_GENERAL_STRING(BERcodec_STRING):
603    tag = ASN1_Class_UNIVERSAL.GENERAL_STRING
604
605
606class BERcodec_UTC_TIME(BERcodec_STRING):
607    tag = ASN1_Class_UNIVERSAL.UTC_TIME
608
609
610class BERcodec_GENERALIZED_TIME(BERcodec_STRING):
611    tag = ASN1_Class_UNIVERSAL.GENERALIZED_TIME
612
613
614class BERcodec_ISO646_STRING(BERcodec_STRING):
615    tag = ASN1_Class_UNIVERSAL.ISO646_STRING
616
617
618class BERcodec_UNIVERSAL_STRING(BERcodec_STRING):
619    tag = ASN1_Class_UNIVERSAL.UNIVERSAL_STRING
620
621
622class BERcodec_BMP_STRING(BERcodec_STRING):
623    tag = ASN1_Class_UNIVERSAL.BMP_STRING
624
625
626class BERcodec_SEQUENCE(BERcodec_Object[Union[bytes, List[BERcodec_Object[Any]]]]):  # noqa: E501
627    tag = ASN1_Class_UNIVERSAL.SEQUENCE
628
629    @classmethod
630    def enc(cls, _ll, size_len=0):
631        # type: (Union[bytes, List[BERcodec_Object[Any]]], Optional[int]) -> bytes
632        if isinstance(_ll, bytes):
633            ll = _ll
634        else:
635            ll = b"".join(x.enc(cls.codec) for x in _ll)
636        return chb(int(cls.tag)) + BER_len_enc(len(ll), size=size_len) + ll
637
638    @classmethod
639    def do_dec(cls,
640               s,  # type: bytes
641               context=None,  # type: Optional[Type[ASN1_Class]]
642               safe=False  # type: bool
643               ):
644        # type: (...) -> Tuple[ASN1_Object[Union[bytes, List[Any]]], bytes]
645        if context is None:
646            context = cls.tag.context
647        ll, st = cls.check_type_get_len(s)  # we may have len(s) < ll
648        s, t = st[:ll], st[ll:]
649        obj = []
650        while s:
651            try:
652                o, remain = BERcodec_Object.dec(
653                    s, context, safe
654                )  # type: Tuple[ASN1_Object[Any], bytes]
655                s = remain
656            except BER_Decoding_Error as err:
657                err.remaining += t
658                if err.decoded is not None:
659                    obj.append(err.decoded)
660                err.decoded = obj
661                raise
662            obj.append(o)
663        if len(st) < ll:
664            raise BER_Decoding_Error("Not enough bytes to decode sequence",
665                                     decoded=obj)
666        return cls.asn1_object(obj), t
667
668
669class BERcodec_SET(BERcodec_SEQUENCE):
670    tag = ASN1_Class_UNIVERSAL.SET
671
672
673class BERcodec_IPADDRESS(BERcodec_STRING):
674    tag = ASN1_Class_UNIVERSAL.IPADDRESS
675
676    @classmethod
677    def enc(cls, ipaddr_ascii, size_len=0):  # type: ignore
678        # type: (str, Optional[int]) -> bytes
679        try:
680            s = inet_aton(ipaddr_ascii)
681        except Exception:
682            raise BER_Encoding_Error("IPv4 address could not be encoded")
683        return chb(int(cls.tag)) + BER_len_enc(len(s), size=size_len) + s
684
685    @classmethod
686    def do_dec(cls, s, context=None, safe=False):
687        # type: (bytes, Optional[Any], bool) -> Tuple[ASN1_Object[str], bytes]
688        l, s, t = cls.check_type_check_len(s)
689        try:
690            ipaddr_ascii = inet_ntoa(s)
691        except Exception:
692            raise BER_Decoding_Error("IP address could not be decoded",
693                                     remaining=s)
694        return cls.asn1_object(ipaddr_ascii), t
695
696
697class BERcodec_COUNTER32(BERcodec_INTEGER):
698    tag = ASN1_Class_UNIVERSAL.COUNTER32
699
700
701class BERcodec_COUNTER64(BERcodec_INTEGER):
702    tag = ASN1_Class_UNIVERSAL.COUNTER64
703
704
705class BERcodec_GAUGE32(BERcodec_INTEGER):
706    tag = ASN1_Class_UNIVERSAL.GAUGE32
707
708
709class BERcodec_TIME_TICKS(BERcodec_INTEGER):
710    tag = ASN1_Class_UNIVERSAL.TIME_TICKS
711