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