Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/asn1fields.py: 72%
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
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
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>
7"""
8Classes that implement ASN.1 data structures.
9"""
11import copy
13from functools import reduce
15from scapy.asn1.asn1 import (
16 ASN1_BIT_STRING,
17 ASN1_BOOLEAN,
18 ASN1_Class,
19 ASN1_Class_UNIVERSAL,
20 ASN1_Error,
21 ASN1_INTEGER,
22 ASN1_NULL,
23 ASN1_OID,
24 ASN1_Object,
25 ASN1_STRING,
26)
27from scapy.asn1.ber import (
28 BER_Decoding_Error,
29 BER_id_dec,
30 BER_tagging_dec,
31 BER_tagging_enc,
32)
33from scapy.base_classes import BasePacket
34from scapy.volatile import (
35 GeneralizedTime,
36 RandChoice,
37 RandInt,
38 RandNum,
39 RandOID,
40 RandString,
41 RandField,
42)
44from scapy import packet
46from typing import (
47 Any,
48 AnyStr,
49 Callable,
50 Dict,
51 Generic,
52 List,
53 Optional,
54 Tuple,
55 Type,
56 TypeVar,
57 Union,
58 cast,
59 TYPE_CHECKING,
60)
62if TYPE_CHECKING:
63 from scapy.asn1packet import ASN1_Packet
66class ASN1F_badsequence(Exception):
67 pass
70class ASN1F_element(object):
71 pass
74##########################
75# Basic ASN1 Field #
76##########################
78_I = TypeVar('_I') # Internal storage
79_A = TypeVar('_A') # ASN.1 object
82class ASN1F_field(ASN1F_element, Generic[_I, _A]):
83 holds_packets = 0
84 islist = 0
85 ASN1_tag = ASN1_Class_UNIVERSAL.ANY
86 context = ASN1_Class_UNIVERSAL # type: Type[ASN1_Class]
88 def __init__(self,
89 name, # type: str
90 default, # type: Optional[_A]
91 context=None, # type: Optional[Type[ASN1_Class]]
92 implicit_tag=None, # type: Optional[int]
93 explicit_tag=None, # type: Optional[int]
94 flexible_tag=False, # type: Optional[bool]
95 size_len=None, # type: Optional[int]
96 ):
97 # type: (...) -> None
98 if context is not None:
99 self.context = context
100 self.name = name
101 if default is None:
102 self.default = default # type: Optional[_A]
103 elif isinstance(default, ASN1_NULL):
104 self.default = default # type: ignore
105 else:
106 self.default = self.ASN1_tag.asn1_object(default) # type: ignore
107 self.size_len = size_len
108 self.flexible_tag = flexible_tag
109 if (implicit_tag is not None) and (explicit_tag is not None):
110 err_msg = "field cannot be both implicitly and explicitly tagged"
111 raise ASN1_Error(err_msg)
112 self.implicit_tag = implicit_tag and int(implicit_tag)
113 self.explicit_tag = explicit_tag and int(explicit_tag)
114 # network_tag gets useful for ASN1F_CHOICE
115 self.network_tag = int(implicit_tag or explicit_tag or self.ASN1_tag)
116 self.owners = [] # type: List[Type[ASN1_Packet]]
118 def register_owner(self, cls):
119 # type: (Type[ASN1_Packet]) -> None
120 self.owners.append(cls)
122 def i2repr(self, pkt, x):
123 # type: (ASN1_Packet, _I) -> str
124 return repr(x)
126 def i2h(self, pkt, x):
127 # type: (ASN1_Packet, _I) -> Any
128 return x
130 def m2i(self, pkt, s):
131 # type: (ASN1_Packet, bytes) -> Tuple[_A, bytes]
132 """
133 The good thing about safedec is that it may still decode ASN1
134 even if there is a mismatch between the expected tag (self.ASN1_tag)
135 and the actual tag; the decoded ASN1 object will simply be put
136 into an ASN1_BADTAG object. However, safedec prevents the raising of
137 exceptions needed for ASN1F_optional processing.
138 Thus we use 'flexible_tag', which should be False with ASN1F_optional.
140 Regarding other fields, we might need to know whether encoding went
141 as expected or not. Noticeably, input methods from cert.py expect
142 certain exceptions to be raised. Hence default flexible_tag is False.
143 """
144 diff_tag, s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
145 implicit_tag=self.implicit_tag,
146 explicit_tag=self.explicit_tag,
147 safe=self.flexible_tag,
148 _fname=self.name)
149 if diff_tag is not None:
150 # this implies that flexible_tag was True
151 if self.implicit_tag is not None:
152 self.implicit_tag = diff_tag
153 elif self.explicit_tag is not None:
154 self.explicit_tag = diff_tag
155 codec = self.ASN1_tag.get_codec(pkt.ASN1_codec)
156 if self.flexible_tag:
157 return codec.safedec(s, context=self.context) # type: ignore
158 else:
159 return codec.dec(s, context=self.context) # type: ignore
161 def i2m(self, pkt, x):
162 # type: (ASN1_Packet, Union[bytes, _I, _A]) -> bytes
163 if x is None:
164 return b""
165 if isinstance(x, ASN1_Object):
166 if (self.ASN1_tag == ASN1_Class_UNIVERSAL.ANY or
167 x.tag == ASN1_Class_UNIVERSAL.RAW or
168 x.tag == ASN1_Class_UNIVERSAL.ERROR or
169 self.ASN1_tag == x.tag):
170 s = x.enc(pkt.ASN1_codec)
171 else:
172 raise ASN1_Error("Encoding Error: got %r instead of an %r for field [%s]" % (x, self.ASN1_tag, self.name)) # noqa: E501
173 else:
174 s = self.ASN1_tag.get_codec(pkt.ASN1_codec).enc(x, size_len=self.size_len)
175 return BER_tagging_enc(s,
176 implicit_tag=self.implicit_tag,
177 explicit_tag=self.explicit_tag)
179 def any2i(self, pkt, x):
180 # type: (ASN1_Packet, Any) -> _I
181 return cast(_I, x)
183 def extract_packet(self,
184 cls, # type: Type[ASN1_Packet]
185 s, # type: bytes
186 _underlayer=None # type: Optional[ASN1_Packet]
187 ):
188 # type: (...) -> Tuple[ASN1_Packet, bytes]
189 try:
190 c = cls(s, _underlayer=_underlayer)
191 except ASN1F_badsequence:
192 c = packet.Raw(s, _underlayer=_underlayer) # type: ignore
193 cpad = c.getlayer(packet.Raw)
194 s = b""
195 if cpad is not None:
196 s = cpad.load
197 if cpad.underlayer:
198 del cpad.underlayer.payload
199 return c, s
201 def build(self, pkt):
202 # type: (ASN1_Packet) -> bytes
203 return self.i2m(pkt, getattr(pkt, self.name))
205 def dissect(self, pkt, s):
206 # type: (ASN1_Packet, bytes) -> bytes
207 v, s = self.m2i(pkt, s)
208 self.set_val(pkt, v)
209 return s
211 def do_copy(self, x):
212 # type: (Any) -> Any
213 if isinstance(x, list):
214 x = x[:]
215 for i in range(len(x)):
216 if isinstance(x[i], BasePacket):
217 x[i] = x[i].copy()
218 return x
219 if hasattr(x, "copy"):
220 return x.copy()
221 return x
223 def set_val(self, pkt, val):
224 # type: (ASN1_Packet, Any) -> None
225 setattr(pkt, self.name, val)
227 def is_empty(self, pkt):
228 # type: (ASN1_Packet) -> bool
229 return getattr(pkt, self.name) is None
231 def get_fields_list(self):
232 # type: () -> List[ASN1F_field[Any, Any]]
233 return [self]
235 def __str__(self):
236 # type: () -> str
237 return repr(self)
239 def randval(self):
240 # type: () -> RandField[_I]
241 return cast(RandField[_I], RandInt())
243 def copy(self):
244 # type: () -> ASN1F_field[_I, _A]
245 return copy.copy(self)
248############################
249# Simple ASN1 Fields #
250############################
252class ASN1F_BOOLEAN(ASN1F_field[bool, ASN1_BOOLEAN]):
253 ASN1_tag = ASN1_Class_UNIVERSAL.BOOLEAN
255 def randval(self):
256 # type: () -> RandChoice
257 return RandChoice(True, False)
260class ASN1F_INTEGER(ASN1F_field[int, ASN1_INTEGER]):
261 ASN1_tag = ASN1_Class_UNIVERSAL.INTEGER
263 def randval(self):
264 # type: () -> RandNum
265 return RandNum(-2**64, 2**64 - 1)
268class ASN1F_enum_INTEGER(ASN1F_INTEGER):
269 def __init__(self,
270 name, # type: str
271 default, # type: ASN1_INTEGER
272 enum, # type: Dict[int, str]
273 context=None, # type: Optional[Any]
274 implicit_tag=None, # type: Optional[Any]
275 explicit_tag=None, # type: Optional[Any]
276 ):
277 # type: (...) -> None
278 super(ASN1F_enum_INTEGER, self).__init__(
279 name, default, context=context,
280 implicit_tag=implicit_tag,
281 explicit_tag=explicit_tag
282 )
283 i2s = self.i2s = {} # type: Dict[int, str]
284 s2i = self.s2i = {} # type: Dict[str, int]
285 if isinstance(enum, list):
286 keys = range(len(enum))
287 else:
288 keys = list(enum)
289 if any(isinstance(x, str) for x in keys):
290 i2s, s2i = s2i, i2s # type: ignore
291 for k in keys:
292 i2s[k] = enum[k]
293 s2i[enum[k]] = k
295 def i2m(self,
296 pkt, # type: ASN1_Packet
297 s, # type: Union[bytes, str, int, ASN1_INTEGER]
298 ):
299 # type: (...) -> bytes
300 if not isinstance(s, str):
301 vs = s
302 else:
303 vs = self.s2i[s]
304 return super(ASN1F_enum_INTEGER, self).i2m(pkt, vs)
306 def i2repr(self,
307 pkt, # type: ASN1_Packet
308 x, # type: Union[str, int]
309 ):
310 # type: (...) -> str
311 if x is not None and isinstance(x, ASN1_INTEGER):
312 r = self.i2s.get(x.val)
313 if r:
314 return "'%s' %s" % (r, repr(x))
315 return repr(x)
318class ASN1F_BIT_STRING(ASN1F_field[str, ASN1_BIT_STRING]):
319 ASN1_tag = ASN1_Class_UNIVERSAL.BIT_STRING
321 def __init__(self,
322 name, # type: str
323 default, # type: Optional[Union[ASN1_BIT_STRING, AnyStr]]
324 default_readable=True, # type: bool
325 context=None, # type: Optional[Any]
326 implicit_tag=None, # type: Optional[int]
327 explicit_tag=None, # type: Optional[int]
328 ):
329 # type: (...) -> None
330 super(ASN1F_BIT_STRING, self).__init__(
331 name, None, context=context,
332 implicit_tag=implicit_tag,
333 explicit_tag=explicit_tag
334 )
335 if isinstance(default, (bytes, str)):
336 self.default = ASN1_BIT_STRING(default,
337 readable=default_readable)
338 else:
339 self.default = default
341 def randval(self):
342 # type: () -> RandString
343 return RandString(RandNum(0, 1000))
346class ASN1F_STRING(ASN1F_field[str, ASN1_STRING]):
347 ASN1_tag = ASN1_Class_UNIVERSAL.STRING
349 def randval(self):
350 # type: () -> RandString
351 return RandString(RandNum(0, 1000))
354class ASN1F_NULL(ASN1F_INTEGER):
355 ASN1_tag = ASN1_Class_UNIVERSAL.NULL
358class ASN1F_OID(ASN1F_field[str, ASN1_OID]):
359 ASN1_tag = ASN1_Class_UNIVERSAL.OID
361 def randval(self):
362 # type: () -> RandOID
363 return RandOID()
366class ASN1F_ENUMERATED(ASN1F_enum_INTEGER):
367 ASN1_tag = ASN1_Class_UNIVERSAL.ENUMERATED
370class ASN1F_UTF8_STRING(ASN1F_STRING):
371 ASN1_tag = ASN1_Class_UNIVERSAL.UTF8_STRING
374class ASN1F_NUMERIC_STRING(ASN1F_STRING):
375 ASN1_tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING
378class ASN1F_PRINTABLE_STRING(ASN1F_STRING):
379 ASN1_tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING
382class ASN1F_T61_STRING(ASN1F_STRING):
383 ASN1_tag = ASN1_Class_UNIVERSAL.T61_STRING
386class ASN1F_VIDEOTEX_STRING(ASN1F_STRING):
387 ASN1_tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING
390class ASN1F_IA5_STRING(ASN1F_STRING):
391 ASN1_tag = ASN1_Class_UNIVERSAL.IA5_STRING
394class ASN1F_GENERAL_STRING(ASN1F_STRING):
395 ASN1_tag = ASN1_Class_UNIVERSAL.GENERAL_STRING
398class ASN1F_UTC_TIME(ASN1F_STRING):
399 ASN1_tag = ASN1_Class_UNIVERSAL.UTC_TIME
401 def randval(self): # type: ignore
402 # type: () -> GeneralizedTime
403 return GeneralizedTime()
406class ASN1F_GENERALIZED_TIME(ASN1F_STRING):
407 ASN1_tag = ASN1_Class_UNIVERSAL.GENERALIZED_TIME
409 def randval(self): # type: ignore
410 # type: () -> GeneralizedTime
411 return GeneralizedTime()
414class ASN1F_ISO646_STRING(ASN1F_STRING):
415 ASN1_tag = ASN1_Class_UNIVERSAL.ISO646_STRING
418class ASN1F_UNIVERSAL_STRING(ASN1F_STRING):
419 ASN1_tag = ASN1_Class_UNIVERSAL.UNIVERSAL_STRING
422class ASN1F_BMP_STRING(ASN1F_STRING):
423 ASN1_tag = ASN1_Class_UNIVERSAL.BMP_STRING
426class ASN1F_SEQUENCE(ASN1F_field[List[Any], List[Any]]):
427 # Here is how you could decode a SEQUENCE
428 # with an unknown, private high-tag prefix :
429 # class PrivSeq(ASN1_Packet):
430 # ASN1_codec = ASN1_Codecs.BER
431 # ASN1_root = ASN1F_SEQUENCE(
432 # <asn1 field #0>,
433 # ...
434 # <asn1 field #N>,
435 # explicit_tag=0,
436 # flexible_tag=True)
437 # Because we use flexible_tag, the value of the explicit_tag does not matter. # noqa: E501
438 ASN1_tag = ASN1_Class_UNIVERSAL.SEQUENCE
439 holds_packets = 1
441 def __init__(self, *seq, **kwargs):
442 # type: (*Any, **Any) -> None
443 name = "dummy_seq_name"
444 default = [field.default for field in seq]
445 super(ASN1F_SEQUENCE, self).__init__(
446 name, default, **kwargs
447 )
448 self.seq = seq
449 self.islist = len(seq) > 1
451 def __repr__(self):
452 # type: () -> str
453 return "<%s%r>" % (self.__class__.__name__, self.seq)
455 def is_empty(self, pkt):
456 # type: (ASN1_Packet) -> bool
457 return all(f.is_empty(pkt) for f in self.seq)
459 def get_fields_list(self):
460 # type: () -> List[ASN1F_field[Any, Any]]
461 return reduce(lambda x, y: x + y.get_fields_list(),
462 self.seq, [])
464 def m2i(self, pkt, s):
465 # type: (Any, bytes) -> Tuple[Any, bytes]
466 """
467 ASN1F_SEQUENCE behaves transparently, with nested ASN1_objects being
468 dissected one by one. Because we use obj.dissect (see loop below)
469 instead of obj.m2i (as we trust dissect to do the appropriate set_vals)
470 we do not directly retrieve the list of nested objects.
471 Thus m2i returns an empty list (along with the proper remainder).
472 It is discarded by dissect() and should not be missed elsewhere.
473 """
474 diff_tag, s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
475 implicit_tag=self.implicit_tag,
476 explicit_tag=self.explicit_tag,
477 safe=self.flexible_tag,
478 _fname=pkt.name)
479 if diff_tag is not None:
480 if self.implicit_tag is not None:
481 self.implicit_tag = diff_tag
482 elif self.explicit_tag is not None:
483 self.explicit_tag = diff_tag
484 codec = self.ASN1_tag.get_codec(pkt.ASN1_codec)
485 i, s, remain = codec.check_type_check_len(s)
486 if len(s) == 0:
487 for obj in self.seq:
488 obj.set_val(pkt, None)
489 else:
490 for obj in self.seq:
491 try:
492 s = obj.dissect(pkt, s)
493 except ASN1F_badsequence:
494 break
495 if len(s) > 0:
496 raise BER_Decoding_Error(
497 "unexpected remainder in %s" % pkt.name,
498 remaining=s,
499 )
500 return [], remain
502 def dissect(self, pkt, s):
503 # type: (Any, bytes) -> bytes
504 _, x = self.m2i(pkt, s)
505 return x
507 def build(self, pkt):
508 # type: (ASN1_Packet) -> bytes
509 s = reduce(lambda x, y: x + y.build(pkt),
510 self.seq, b"")
511 return super(ASN1F_SEQUENCE, self).i2m(pkt, s)
514class ASN1F_SET(ASN1F_SEQUENCE):
515 ASN1_tag = ASN1_Class_UNIVERSAL.SET
518_SEQ_T = Union[
519 'ASN1_Packet',
520 Type[ASN1F_field[Any, Any]],
521 'ASN1F_PACKET',
522 ASN1F_field[Any, Any],
523]
526class ASN1F_SEQUENCE_OF(ASN1F_field[List[_SEQ_T],
527 List[ASN1_Object[Any]]]):
528 """
529 Two types are allowed as cls: ASN1_Packet, ASN1F_field
530 """
531 ASN1_tag = ASN1_Class_UNIVERSAL.SEQUENCE
532 islist = 1
534 def __init__(self,
535 name, # type: str
536 default, # type: Any
537 cls, # type: _SEQ_T
538 context=None, # type: Optional[Any]
539 implicit_tag=None, # type: Optional[Any]
540 explicit_tag=None, # type: Optional[Any]
541 ):
542 # type: (...) -> None
543 if isinstance(cls, type) and issubclass(cls, ASN1F_field) or \
544 isinstance(cls, ASN1F_field):
545 if isinstance(cls, type):
546 self.fld = cls(name, b"")
547 else:
548 self.fld = cls
549 self._extract_packet = lambda s, pkt: self.fld.m2i(pkt, s)
550 self.holds_packets = 0
551 elif hasattr(cls, "ASN1_root") or callable(cls):
552 self.cls = cast("Type[ASN1_Packet]", cls)
553 self._extract_packet = lambda s, pkt: self.extract_packet(
554 self.cls, s, _underlayer=pkt)
555 self.holds_packets = 1
556 else:
557 raise ValueError("cls should be an ASN1_Packet or ASN1_field")
558 super(ASN1F_SEQUENCE_OF, self).__init__(
559 name, None, context=context,
560 implicit_tag=implicit_tag, explicit_tag=explicit_tag
561 )
562 self.default = default
564 def is_empty(self,
565 pkt, # type: ASN1_Packet
566 ):
567 # type: (...) -> bool
568 return ASN1F_field.is_empty(self, pkt)
570 def m2i(self,
571 pkt, # type: ASN1_Packet
572 s, # type: bytes
573 ):
574 # type: (...) -> Tuple[List[Any], bytes]
575 diff_tag, s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
576 implicit_tag=self.implicit_tag,
577 explicit_tag=self.explicit_tag,
578 safe=self.flexible_tag)
579 if diff_tag is not None:
580 if self.implicit_tag is not None:
581 self.implicit_tag = diff_tag
582 elif self.explicit_tag is not None:
583 self.explicit_tag = diff_tag
584 codec = self.ASN1_tag.get_codec(pkt.ASN1_codec)
585 i, s, remain = codec.check_type_check_len(s)
586 lst = []
587 while s:
588 c, s = self._extract_packet(s, pkt) # type: ignore
589 if c:
590 lst.append(c)
591 if len(s) > 0:
592 raise BER_Decoding_Error(
593 "unexpected remainder in %s" % pkt.name,
594 remaining=s,
595 )
596 return lst, remain
598 def build(self, pkt):
599 # type: (ASN1_Packet) -> bytes
600 val = getattr(pkt, self.name)
601 if isinstance(val, ASN1_Object) and \
602 val.tag == ASN1_Class_UNIVERSAL.RAW:
603 s = cast(Union[List[_SEQ_T], bytes], val)
604 elif val is None:
605 s = b""
606 else:
607 s = b"".join(bytes(i) for i in val)
608 return self.i2m(pkt, s)
610 def i2repr(self, pkt, x):
611 # type: (ASN1_Packet, _I) -> str
612 if self.holds_packets:
613 return super(ASN1F_SEQUENCE_OF, self).i2repr(pkt, x) # type: ignore
614 elif x is None:
615 return "[]"
616 else:
617 return "[%s]" % ", ".join(
618 self.fld.i2repr(pkt, x) for x in x # type: ignore
619 )
621 def randval(self):
622 # type: () -> Any
623 if self.holds_packets:
624 return packet.fuzz(self.cls())
625 else:
626 return self.fld.randval()
628 def __repr__(self):
629 # type: () -> str
630 return "<%s %s>" % (self.__class__.__name__, self.name)
633class ASN1F_SET_OF(ASN1F_SEQUENCE_OF):
634 ASN1_tag = ASN1_Class_UNIVERSAL.SET
637class ASN1F_IPADDRESS(ASN1F_STRING):
638 ASN1_tag = ASN1_Class_UNIVERSAL.IPADDRESS
641class ASN1F_TIME_TICKS(ASN1F_INTEGER):
642 ASN1_tag = ASN1_Class_UNIVERSAL.TIME_TICKS
645#############################
646# Complex ASN1 Fields #
647#############################
649class ASN1F_optional(ASN1F_element):
650 """
651 ASN.1 field that is optional.
652 """
653 def __init__(self, field):
654 # type: (ASN1F_field[Any, Any]) -> None
655 field.flexible_tag = False
656 self._field = field
658 def __getattr__(self, attr):
659 # type: (str) -> Optional[Any]
660 return getattr(self._field, attr)
662 def m2i(self, pkt, s):
663 # type: (ASN1_Packet, bytes) -> Tuple[Any, bytes]
664 try:
665 return self._field.m2i(pkt, s)
666 except (ASN1_Error, ASN1F_badsequence, BER_Decoding_Error):
667 # ASN1_Error may be raised by ASN1F_CHOICE
668 return None, s
670 def dissect(self, pkt, s):
671 # type: (ASN1_Packet, bytes) -> bytes
672 try:
673 return self._field.dissect(pkt, s)
674 except (ASN1_Error, ASN1F_badsequence, BER_Decoding_Error):
675 self._field.set_val(pkt, None)
676 return s
678 def build(self, pkt):
679 # type: (ASN1_Packet) -> bytes
680 if self._field.is_empty(pkt):
681 return b""
682 return self._field.build(pkt)
684 def any2i(self, pkt, x):
685 # type: (ASN1_Packet, Any) -> Any
686 return self._field.any2i(pkt, x)
688 def i2repr(self, pkt, x):
689 # type: (ASN1_Packet, Any) -> str
690 return self._field.i2repr(pkt, x)
693class ASN1F_omit(ASN1F_field[None, None]):
694 """
695 ASN.1 field that is not specified. This is simply omitted on the network.
696 This is different from ASN1F_NULL which has a network representation.
697 """
698 def m2i(self, pkt, s):
699 # type: (ASN1_Packet, bytes) -> Tuple[None, bytes]
700 return None, s
702 def i2m(self, pkt, x):
703 # type: (ASN1_Packet, Optional[bytes]) -> bytes
704 return b""
707_CHOICE_T = Union['ASN1_Packet', Type[ASN1F_field[Any, Any]], 'ASN1F_PACKET']
710class ASN1F_CHOICE(ASN1F_field[_CHOICE_T, ASN1_Object[Any]]):
711 """
712 Multiple types are allowed: ASN1_Packet, ASN1F_field and ASN1F_PACKET(),
713 See layers/x509.py for examples.
714 Other ASN1F_field instances than ASN1F_PACKET instances must not be used.
715 """
716 holds_packets = 1
717 ASN1_tag = ASN1_Class_UNIVERSAL.ANY
719 def __init__(self, name, default, *args, **kwargs):
720 # type: (str, Any, *_CHOICE_T, **Any) -> None
721 if "implicit_tag" in kwargs:
722 err_msg = "ASN1F_CHOICE has been called with an implicit_tag"
723 raise ASN1_Error(err_msg)
724 self.implicit_tag = None
725 for kwarg in ["context", "explicit_tag"]:
726 setattr(self, kwarg, kwargs.get(kwarg))
727 super(ASN1F_CHOICE, self).__init__(
728 name, None, context=self.context,
729 explicit_tag=self.explicit_tag
730 )
731 self.default = default
732 self.current_choice = None
733 self.choices = {} # type: Dict[int, _CHOICE_T]
734 self.pktchoices = {}
735 for p in args:
736 if hasattr(p, "ASN1_root"):
737 p = cast('ASN1_Packet', p)
738 # should be ASN1_Packet
739 if hasattr(p.ASN1_root, "choices"):
740 root = cast(ASN1F_CHOICE, p.ASN1_root)
741 for k, v in root.choices.items():
742 # ASN1F_CHOICE recursion
743 self.choices[k] = v
744 else:
745 self.choices[p.ASN1_root.network_tag] = p
746 elif hasattr(p, "ASN1_tag"):
747 if isinstance(p, type):
748 # should be ASN1F_field class
749 self.choices[int(p.ASN1_tag)] = p
750 else:
751 # should be ASN1F_field instance
752 self.choices[p.network_tag] = p
753 self.pktchoices[hash(p.cls)] = (p.implicit_tag, p.explicit_tag) # noqa: E501
754 else:
755 raise ASN1_Error("ASN1F_CHOICE: no tag found for one field")
757 def m2i(self, pkt, s):
758 # type: (ASN1_Packet, bytes) -> Tuple[ASN1_Object[Any], bytes]
759 """
760 First we have to retrieve the appropriate choice.
761 Then we extract the field/packet, according to this choice.
762 """
763 if len(s) == 0:
764 raise ASN1_Error("ASN1F_CHOICE: got empty string")
765 _, s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
766 explicit_tag=self.explicit_tag)
767 tag, _ = BER_id_dec(s)
768 if tag in self.choices:
769 choice = self.choices[tag]
770 else:
771 if self.flexible_tag:
772 choice = ASN1F_field
773 else:
774 raise ASN1_Error(
775 "ASN1F_CHOICE: unexpected field in '%s' "
776 "(tag %s not in possible tags %s)" % (
777 self.name, tag, list(self.choices.keys())
778 )
779 )
780 if hasattr(choice, "ASN1_root"):
781 # we don't want to import ASN1_Packet in this module...
782 return self.extract_packet(choice, s, _underlayer=pkt) # type: ignore
783 elif isinstance(choice, type):
784 return choice(self.name, b"").m2i(pkt, s)
785 else:
786 # XXX check properly if this is an ASN1F_PACKET
787 return choice.m2i(pkt, s)
789 def i2m(self, pkt, x):
790 # type: (ASN1_Packet, Any) -> bytes
791 if x is None:
792 s = b""
793 else:
794 s = bytes(x)
795 if hash(type(x)) in self.pktchoices:
796 imp, exp = self.pktchoices[hash(type(x))]
797 s = BER_tagging_enc(s,
798 implicit_tag=imp,
799 explicit_tag=exp)
800 return BER_tagging_enc(s, explicit_tag=self.explicit_tag)
802 def randval(self):
803 # type: () -> RandChoice
804 randchoices = []
805 for p in self.choices.values():
806 if hasattr(p, "ASN1_root"):
807 # should be ASN1_Packet class
808 randchoices.append(packet.fuzz(p())) # type: ignore
809 elif hasattr(p, "ASN1_tag"):
810 if isinstance(p, type):
811 # should be (basic) ASN1F_field class
812 randchoices.append(p("dummy", None).randval())
813 else:
814 # should be ASN1F_PACKET instance
815 randchoices.append(p.randval())
816 return RandChoice(*randchoices)
819class ASN1F_PACKET(ASN1F_field['ASN1_Packet', Optional['ASN1_Packet']]):
820 holds_packets = 1
822 def __init__(self,
823 name, # type: str
824 default, # type: Optional[ASN1_Packet]
825 cls, # type: Type[ASN1_Packet]
826 context=None, # type: Optional[Any]
827 implicit_tag=None, # type: Optional[int]
828 explicit_tag=None, # type: Optional[int]
829 next_cls_cb=None, # type: Optional[Callable[[ASN1_Packet], Type[ASN1_Packet]]] # noqa: E501
830 ):
831 # type: (...) -> None
832 self.cls = cls
833 self.next_cls_cb = next_cls_cb
834 super(ASN1F_PACKET, self).__init__(
835 name, None, context=context,
836 implicit_tag=implicit_tag, explicit_tag=explicit_tag
837 )
838 if implicit_tag is None and explicit_tag is None and cls is not None:
839 if cls.ASN1_root.ASN1_tag == ASN1_Class_UNIVERSAL.SEQUENCE:
840 self.network_tag = 16 | 0x20 # 16 + CONSTRUCTED
841 self.default = default
843 def m2i(self, pkt, s):
844 # type: (ASN1_Packet, bytes) -> Tuple[Any, bytes]
845 if self.next_cls_cb:
846 cls = self.next_cls_cb(pkt) or self.cls
847 else:
848 cls = self.cls
849 if not hasattr(cls, "ASN1_root"):
850 # A normal Packet (!= ASN1)
851 return self.extract_packet(cls, s, _underlayer=pkt)
852 diff_tag, s = BER_tagging_dec(s, hidden_tag=cls.ASN1_root.ASN1_tag, # noqa: E501
853 implicit_tag=self.implicit_tag,
854 explicit_tag=self.explicit_tag,
855 safe=self.flexible_tag,
856 _fname=self.name)
857 if diff_tag is not None:
858 if self.implicit_tag is not None:
859 self.implicit_tag = diff_tag
860 elif self.explicit_tag is not None:
861 self.explicit_tag = diff_tag
862 if not s:
863 return None, s
864 return self.extract_packet(cls, s, _underlayer=pkt)
866 def i2m(self,
867 pkt, # type: ASN1_Packet
868 x # type: Union[bytes, ASN1_Packet, None, ASN1_Object[Optional[ASN1_Packet]]] # noqa: E501
869 ):
870 # type: (...) -> bytes
871 if x is None:
872 s = b""
873 elif isinstance(x, bytes):
874 s = x
875 elif isinstance(x, ASN1_Object):
876 if x.val:
877 s = bytes(x.val)
878 else:
879 s = b""
880 else:
881 s = bytes(x)
882 if not hasattr(x, "ASN1_root"):
883 # A normal Packet (!= ASN1)
884 return s
885 return BER_tagging_enc(s,
886 implicit_tag=self.implicit_tag,
887 explicit_tag=self.explicit_tag)
889 def any2i(self,
890 pkt, # type: ASN1_Packet
891 x # type: Union[bytes, ASN1_Packet, None, ASN1_Object[Optional[ASN1_Packet]]] # noqa: E501
892 ):
893 # type: (...) -> 'ASN1_Packet'
894 if hasattr(x, "add_underlayer"):
895 x.add_underlayer(pkt) # type: ignore
896 return super(ASN1F_PACKET, self).any2i(pkt, x)
898 def randval(self): # type: ignore
899 # type: () -> ASN1_Packet
900 return packet.fuzz(self.cls())
903class ASN1F_BIT_STRING_ENCAPS(ASN1F_BIT_STRING):
904 """
905 We may emulate simple string encapsulation with explicit_tag=0x04,
906 but we need a specific class for bit strings because of unused bits, etc.
907 """
908 ASN1_tag = ASN1_Class_UNIVERSAL.BIT_STRING
910 def __init__(self,
911 name, # type: str
912 default, # type: Optional[ASN1_Packet]
913 cls, # type: Type[ASN1_Packet]
914 context=None, # type: Optional[Any]
915 implicit_tag=None, # type: Optional[int]
916 explicit_tag=None, # type: Optional[int]
917 ):
918 # type: (...) -> None
919 self.cls = cls
920 super(ASN1F_BIT_STRING_ENCAPS, self).__init__( # type: ignore
921 name,
922 default and bytes(default),
923 context=context,
924 implicit_tag=implicit_tag,
925 explicit_tag=explicit_tag
926 )
928 def m2i(self, pkt, s): # type: ignore
929 # type: (ASN1_Packet, bytes) -> Tuple[Optional[ASN1_Packet], bytes]
930 bit_string, remain = super(ASN1F_BIT_STRING_ENCAPS, self).m2i(pkt, s)
931 if len(bit_string.val) % 8 != 0:
932 raise BER_Decoding_Error("wrong bit string", remaining=s)
933 if bit_string.val_readable:
934 p, s = self.extract_packet(self.cls, bit_string.val_readable,
935 _underlayer=pkt)
936 else:
937 return None, bit_string.val_readable
938 if len(s) > 0:
939 raise BER_Decoding_Error(
940 "unexpected remainder in %s" % pkt.name,
941 remaining=s,
942 )
943 return p, remain
945 def i2m(self, pkt, x): # type: ignore
946 # type: (ASN1_Packet, Optional[ASN1_BIT_STRING]) -> bytes
947 if not isinstance(x, ASN1_BIT_STRING):
948 x = ASN1_BIT_STRING(
949 b"" if x is None else bytes(x), # type: ignore
950 readable=True,
951 )
952 return super(ASN1F_BIT_STRING_ENCAPS, self).i2m(pkt, x)
955class ASN1F_FLAGS(ASN1F_BIT_STRING):
956 def __init__(self,
957 name, # type: str
958 default, # type: Optional[str]
959 mapping, # type: List[str]
960 context=None, # type: Optional[Any]
961 implicit_tag=None, # type: Optional[int]
962 explicit_tag=None, # type: Optional[Any]
963 ):
964 # type: (...) -> None
965 self.mapping = mapping
966 super(ASN1F_FLAGS, self).__init__(
967 name, default,
968 default_readable=False,
969 context=context,
970 implicit_tag=implicit_tag,
971 explicit_tag=explicit_tag
972 )
974 def any2i(self, pkt, x):
975 # type: (ASN1_Packet, Any) -> str
976 if isinstance(x, str):
977 if any(y not in ["0", "1"] for y in x):
978 # resolve the flags
979 value = ["0"] * len(self.mapping)
980 for i in x.split("+"):
981 value[self.mapping.index(i)] = "1"
982 x = "".join(value)
983 x = ASN1_BIT_STRING(x)
984 return super(ASN1F_FLAGS, self).any2i(pkt, x)
986 def get_flags(self, pkt):
987 # type: (ASN1_Packet) -> List[str]
988 fbytes = getattr(pkt, self.name).val
989 return [self.mapping[i] for i, positional in enumerate(fbytes)
990 if positional == '1' and i < len(self.mapping)]
992 def i2repr(self, pkt, x):
993 # type: (ASN1_Packet, Any) -> str
994 if x is not None:
995 pretty_s = ", ".join(self.get_flags(pkt))
996 return pretty_s + " " + repr(x)
997 return repr(x)
1000class ASN1F_STRING_PacketField(ASN1F_STRING):
1001 """
1002 ASN1F_STRING that holds packets.
1003 """
1004 holds_packets = 1
1006 def i2m(self, pkt, val):
1007 # type: (ASN1_Packet, Any) -> bytes
1008 if hasattr(val, "ASN1_root"):
1009 val = ASN1_STRING(bytes(val))
1010 return super(ASN1F_STRING_PacketField, self).i2m(pkt, val)
1012 def any2i(self, pkt, x):
1013 # type: (ASN1_Packet, Any) -> Any
1014 if hasattr(x, "add_underlayer"):
1015 x.add_underlayer(pkt)
1016 return super(ASN1F_STRING_PacketField, self).any2i(pkt, x)
1019class ASN1F_STRING_ENCAPS(ASN1F_STRING_PacketField):
1020 """
1021 ASN1F_STRING that encapsulates a single ASN1 packet.
1022 """
1024 def __init__(self,
1025 name, # type: str
1026 default, # type: Optional[ASN1_Packet]
1027 cls, # type: Type[ASN1_Packet]
1028 context=None, # type: Optional[Any]
1029 implicit_tag=None, # type: Optional[int]
1030 explicit_tag=None, # type: Optional[int]
1031 ):
1032 # type: (...) -> None
1033 self.cls = cls
1034 super(ASN1F_STRING_ENCAPS, self).__init__(
1035 name,
1036 default and bytes(default), # type: ignore
1037 context=context,
1038 implicit_tag=implicit_tag,
1039 explicit_tag=explicit_tag
1040 )
1042 def m2i(self, pkt, s): # type: ignore
1043 # type: (ASN1_Packet, bytes) -> Tuple[ASN1_Packet, bytes]
1044 val = super(ASN1F_STRING_ENCAPS, self).m2i(pkt, s)
1045 return self.cls(val[0].val, _underlayer=pkt), val[1]