1## This file is part of Scapy
2## See http://www.secdev.org/projects/scapy for more informations
3## Copyright (C) Philippe Biondi <phil@secdev.org>
4## This program is published under a GPLv2 license
5
6"""
7ASN.1 (Abstract Syntax Notation One)
8"""
9
10import random
11from scapy.config import conf
12from scapy.error import Scapy_Exception,warning
13from scapy.volatile import RandField
14from scapy.utils import Enum_metaclass, EnumElement
15
16class RandASN1Object(RandField):
17    def __init__(self, objlist=None):
18        if objlist is None:
19            objlist = [ x._asn1_obj for x in
20                          [ x for x in ASN1_Class_UNIVERSAL.__rdict__.values() if hasattr(x,"_asn1_obj") ]]
21#            objlist = map(lambda x:x._asn1_obj,
22#                          [ x for x in ASN1_Class_UNIVERSAL.__rdict__.values() if hasattr(x,"_asn1_obj") ])
23        self.objlist = objlist
24        self.chars = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
25    def _fix(self, n=0):
26        o = random.choice(self.objlist)
27        if issubclass(o, ASN1_INTEGER):
28            return o(int(random.gauss(0,1000)))
29        elif issubclass(o, ASN1_IPADDRESS):
30            z = RandIP()._fix()
31            return o(z)
32        elif issubclass(o, ASN1_STRING):
33            z = int(random.expovariate(0.05)+1)
34            return o(bytes([random.choice(self.chars) for i in range(z)]))
35        elif issubclass(o, ASN1_SEQUENCE) and (n < 10):
36            z = int(random.expovariate(0.08)+1)
37#            return o(map(lambda x:x._fix(n+1), [self.__class__(objlist=self.objlist)]*z))
38            return o([ x._fix(n+1) for x in [self.__class__(objlist=self.objlist)]*z])
39        return ASN1_INTEGER(int(random.gauss(0,1000)))
40
41
42##############
43#### ASN1 ####
44##############
45
46class ASN1_Error(Scapy_Exception):
47    pass
48
49class ASN1_Encoding_Error(ASN1_Error):
50    pass
51
52class ASN1_Decoding_Error(ASN1_Error):
53    pass
54
55class ASN1_BadTag_Decoding_Error(ASN1_Decoding_Error):
56    pass
57
58
59
60class ASN1Codec(EnumElement):
61    def register_stem(cls, stem):
62        cls._stem = stem
63    def dec(cls, s, context=None):
64        return cls._stem.dec(s, context=context)
65    def safedec(cls, s, context=None):
66        return cls._stem.safedec(s, context=context)
67    def get_stem(cls):
68        return cls.stem
69
70
71class ASN1_Codecs_metaclass(Enum_metaclass):
72    element_class = ASN1Codec
73
74class ASN1_Codecs(metaclass = ASN1_Codecs_metaclass):
75    #__metaclass__ = ASN1_Codecs_metaclass
76    BER = 1
77    DER = 2
78    PER = 3
79    CER = 4
80    LWER = 5
81    BACnet = 6
82    OER = 7
83    SER = 8
84    XER = 9
85
86class ASN1Tag(EnumElement):
87    def __init__(self, key, value, context=None, codec=None):
88        EnumElement.__init__(self, key, value)
89        self._context = context
90        if codec == None:
91            codec = {}
92        self._codec = codec
93    def clone(self): # /!\ not a real deep copy. self.codec is shared
94        return self.__class__(self._key, self._value, self._context, self._codec)
95    def register_asn1_object(self, asn1obj):
96        self._asn1_obj = asn1obj
97    def asn1_object(self, val):
98        if hasattr(self,"_asn1_obj"):
99            return self._asn1_obj(val)
100        raise ASN1_Error("%r does not have any assigned ASN1 object" % self)
101    def register(self, codecnum, codec):
102        self._codec[codecnum] = codec
103    def get_codec(self, codec):
104        try:
105            c = self._codec[codec]
106        except KeyError as msg:
107            raise ASN1_Error("Codec %r not found for tag %r" % (codec, self))
108        return c
109
110class ASN1_Class_metaclass(Enum_metaclass):
111    element_class = ASN1Tag
112    def __new__(cls, name, bases, dct): # XXX factorise a bit with Enum_metaclass.__new__()
113        for b in bases:
114            for k,v in b.__dict__.items():
115                if k not in dct and isinstance(v,ASN1Tag):
116                    dct[k] = v.clone()
117
118        rdict = {}
119        for k,v in dct.items():
120            if type(v) is int:
121                v = ASN1Tag(k,v)
122                dct[k] = v
123                rdict[v] = v
124            elif isinstance(v, ASN1Tag):
125                rdict[v] = v
126        dct["__rdict__"] = rdict
127
128        cls = type.__new__(cls, name, bases, dct)
129        for v in cls.__dict__.values():
130            if isinstance(v, ASN1Tag):
131                v.context = cls # overwrite ASN1Tag contexts, even cloned ones
132        return cls
133
134
135class ASN1_Class(metaclass = ASN1_Class_metaclass):
136    pass
137
138class ASN1_Class_UNIVERSAL(ASN1_Class):
139    name = "UNIVERSAL"
140    ERROR = -3
141    RAW = -2
142    NONE = -1
143    ANY = 0
144    BOOLEAN = 1
145    INTEGER = 2
146    BIT_STRING = 3
147    STRING = 4
148    NULL = 5
149    OID = 6
150    OBJECT_DESCRIPTOR = 7
151    EXTERNAL = 8
152    REAL = 9
153    ENUMERATED = 10
154    EMBEDDED_PDF = 11
155    UTF8_STRING = 12
156    RELATIVE_OID = 13
157    SEQUENCE = 0x30#XXX 16 ??
158    SET = 0x31 #XXX 17 ??
159    NUMERIC_STRING = 18
160    PRINTABLE_STRING = 19
161    T61_STRING = 20
162    VIDEOTEX_STRING = 21
163    IA5_STRING = 22
164    UTC_TIME = 23
165    GENERALIZED_TIME = 24
166    GRAPHIC_STRING = 25
167    ISO646_STRING = 26
168    GENERAL_STRING = 27
169    UNIVERSAL_STRING = 28
170    CHAR_STRING = 29
171    BMP_STRING = 30
172    IPADDRESS = 0x40
173    COUNTER32 = 0x41
174    GAUGE32 = 0x42
175    TIME_TICKS = 0x43
176    SEP = 0x80
177
178class ASN1_Object_metaclass(type):
179    def __new__(cls, name, bases, dct):
180        c = super(ASN1_Object_metaclass, cls).__new__(cls, name, bases, dct)
181        try:
182            c.tag.register_asn1_object(c)
183        except:
184            warning("Error registering %r for %r" % (c.tag, c.codec))
185        return c
186
187
188class ASN1_Object(metaclass = ASN1_Object_metaclass):
189    tag = ASN1_Class_UNIVERSAL.ANY
190    def __init__(self, val):
191        self.val = val
192    def enc(self, codec):
193        return self.tag.get_codec(codec).enc(self.val)
194    def __repr__(self):
195        return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), self.val)
196    def __str__(self):
197        raise Exception("Should not get here")
198        #return self.enc(conf.ASN1_default_codec)
199    def __bytes__(self):
200        return self.enc(conf.ASN1_default_codec)
201    def strshow(self, lvl=0):
202        return ("  "*lvl)+repr(self)+"\n"
203    def show(self, lvl=0):
204        print(self.strshow(lvl))
205    def __eq__(self, other):
206        return self.val == other
207    def __hash__(self):
208        return self.val
209    def __cmp__(self, other):
210        return cmp(self.val, other)
211
212class ASN1_DECODING_ERROR(ASN1_Object):
213    tag = ASN1_Class_UNIVERSAL.ERROR
214    def __init__(self, val, exc=None):
215        ASN1_Object.__init__(self, val)
216        self.exc = exc
217    def __repr__(self):
218        return "<%s[%r]{{%s}}>" % (self.__dict__.get("name", self.__class__.__name__),
219                                   self.val, self.exc.args[0])
220    def enc(self, codec):
221        if isinstance(self.val, ASN1_Object):
222            return self.val.enc(codec)
223        return self.val
224
225class ASN1_force(ASN1_Object):
226    tag = ASN1_Class_UNIVERSAL.RAW
227    def enc(self, codec):
228        if isinstance(self.val, ASN1_Object):
229            return self.val.enc(codec)
230        return self.val
231
232class ASN1_BADTAG(ASN1_force):
233    pass
234
235class ASN1_INTEGER(ASN1_Object):
236    tag = ASN1_Class_UNIVERSAL.INTEGER
237
238class ASN1_STRING(ASN1_Object):
239    tag = ASN1_Class_UNIVERSAL.STRING
240    def __init__(self, val):
241      if type(val) is str:
242        self.val = val.encode('ascii')
243      elif type(val) is bytes:
244        self.val = val
245      else:
246        raise Exception("Unknown value type for ASN1_STRING")
247
248class ASN1_BIT_STRING(ASN1_STRING):
249    tag = ASN1_Class_UNIVERSAL.BIT_STRING
250
251class ASN1_PRINTABLE_STRING(ASN1_STRING):
252    tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING
253
254class ASN1_T61_STRING(ASN1_STRING):
255    tag = ASN1_Class_UNIVERSAL.T61_STRING
256
257class ASN1_IA5_STRING(ASN1_STRING):
258    tag = ASN1_Class_UNIVERSAL.IA5_STRING
259
260class ASN1_NUMERIC_STRING(ASN1_STRING):
261    tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING
262
263class ASN1_VIDEOTEX_STRING(ASN1_STRING):
264    tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING
265
266class ASN1_IPADDRESS(ASN1_STRING):
267    tag = ASN1_Class_UNIVERSAL.IPADDRESS
268
269class ASN1_UTC_TIME(ASN1_STRING):
270    tag = ASN1_Class_UNIVERSAL.UTC_TIME
271
272class ASN1_GENERALIZED_TIME(ASN1_STRING):
273    tag = ASN1_Class_UNIVERSAL.GENERALIZED_TIME
274
275class ASN1_TIME_TICKS(ASN1_INTEGER):
276    tag = ASN1_Class_UNIVERSAL.TIME_TICKS
277
278class ASN1_BOOLEAN(ASN1_INTEGER):
279    tag = ASN1_Class_UNIVERSAL.BOOLEAN
280
281class ASN1_ENUMERATED(ASN1_INTEGER):
282    tag = ASN1_Class_UNIVERSAL.ENUMERATED
283
284class ASN1_NULL(ASN1_INTEGER):
285    tag = ASN1_Class_UNIVERSAL.NULL
286
287class ASN1_SEP(ASN1_NULL):
288    tag = ASN1_Class_UNIVERSAL.SEP
289
290class ASN1_GAUGE32(ASN1_INTEGER):
291    tag = ASN1_Class_UNIVERSAL.GAUGE32
292
293class ASN1_COUNTER32(ASN1_INTEGER):
294    tag = ASN1_Class_UNIVERSAL.COUNTER32
295
296class ASN1_SEQUENCE(ASN1_Object):
297    tag = ASN1_Class_UNIVERSAL.SEQUENCE
298    def strshow(self, lvl=0):
299        s = ("  "*lvl)+("# %s:" % self.__class__.__name__)+"\n"
300        for o in self.val:
301            s += o.strshow(lvl=lvl+1)
302        return s
303
304class ASN1_SET(ASN1_SEQUENCE):
305    tag = ASN1_Class_UNIVERSAL.SET
306
307class ASN1_OID(ASN1_Object):
308    tag = ASN1_Class_UNIVERSAL.OID
309    def __init__(self, val):
310        if type(val) is str:
311          val = val.encode('ascii')
312        val = conf.mib._oid(val)
313        ASN1_Object.__init__(self, val)
314    def __repr__(self):
315        return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), conf.mib._oidname(self.val))
316    def __oidname__(self):
317        return '%s'%conf.mib._oidname(self.val)
318
319
320
321conf.ASN1_default_codec = ASN1_Codecs.BER
322