Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/asn1/ber.py: 75%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

383 statements  

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