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