Home | History | Annotate | Download | only in asn1
      1 ## This file is part of Scapy
      2 ## See http://www.secdev.org/projects/scapy for more informations
      3 ## Copyright (C) Philippe Biondi <phil (at] secdev.org>
      4 ## Modified by Maxence Tury <maxence.tury (at] ssi.gouv.fr>
      5 ## This program is published under a GPLv2 license
      6 
      7 """
      8 ASN.1 (Abstract Syntax Notation One)
      9 """
     10 
     11 from __future__ import absolute_import
     12 from __future__ import print_function
     13 import random
     14 from datetime import datetime
     15 from scapy.config import conf
     16 from scapy.error import Scapy_Exception, warning
     17 from scapy.volatile import RandField, RandIP, GeneralizedTime
     18 from scapy.utils import Enum_metaclass, EnumElement, binrepr
     19 from scapy.compat import plain_str, chb, raw, orb
     20 import scapy.modules.six as six
     21 from scapy.modules.six.moves import range
     22 
     23 class RandASN1Object(RandField):
     24     def __init__(self, objlist=None):
     25         self.objlist = [
     26             x._asn1_obj
     27             for x in six.itervalues(ASN1_Class_UNIVERSAL.__rdict__)
     28             if hasattr(x, "_asn1_obj")
     29         ] if objlist is None else objlist
     30         self.chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
     31     def _fix(self, n=0):
     32         o = random.choice(self.objlist)
     33         if issubclass(o, ASN1_INTEGER):
     34             return o(int(random.gauss(0,1000)))
     35         elif issubclass(o, ASN1_IPADDRESS):
     36             z = RandIP()._fix()
     37             return o(z)
     38         elif issubclass(o, ASN1_GENERALIZED_TIME) or issubclass(o, ASN1_UTC_TIME):
     39             z = GeneralizedTime()._fix()
     40             return o(z)
     41         elif issubclass(o, ASN1_STRING):
     42             z = int(random.expovariate(0.05)+1)
     43             return o("".join(random.choice(self.chars) for _ in range(z)))
     44         elif issubclass(o, ASN1_SEQUENCE) and (n < 10):
     45             z = int(random.expovariate(0.08)+1)
     46             return o([self.__class__(objlist=self.objlist)._fix(n + 1)
     47                       for _ in range(z)])
     48         return ASN1_INTEGER(int(random.gauss(0,1000)))
     49 
     50 
     51 ##############
     52 #### ASN1 ####
     53 ##############
     54 
     55 class ASN1_Error(Scapy_Exception):
     56     pass
     57 
     58 class ASN1_Encoding_Error(ASN1_Error):
     59     pass
     60 
     61 class ASN1_Decoding_Error(ASN1_Error):
     62     pass
     63 
     64 class ASN1_BadTag_Decoding_Error(ASN1_Decoding_Error):
     65     pass
     66 
     67 
     68 
     69 class ASN1Codec(EnumElement):
     70     def register_stem(cls, stem):
     71         cls._stem = stem
     72     def dec(cls, s, context=None):
     73         return cls._stem.dec(s, context=context)
     74     def safedec(cls, s, context=None):
     75         return cls._stem.safedec(s, context=context)
     76     def get_stem(cls):
     77         return cls.stem
     78     
     79 
     80 class ASN1_Codecs_metaclass(Enum_metaclass):
     81     element_class = ASN1Codec
     82 
     83 class ASN1_Codecs(six.with_metaclass(ASN1_Codecs_metaclass)):
     84     BER = 1
     85     DER = 2
     86     PER = 3
     87     CER = 4
     88     LWER = 5
     89     BACnet = 6
     90     OER = 7
     91     SER = 8
     92     XER = 9
     93 
     94 class ASN1Tag(EnumElement):
     95     def __init__(self, key, value, context=None, codec=None):
     96         EnumElement.__init__(self, key, value)
     97         self._context = context
     98         if codec == None:
     99             codec = {}
    100         self._codec = codec
    101     def clone(self): # /!\ not a real deep copy. self.codec is shared
    102         return self.__class__(self._key, self._value, self._context, self._codec)
    103     def register_asn1_object(self, asn1obj):
    104         self._asn1_obj = asn1obj
    105     def asn1_object(self, val):
    106         if hasattr(self,"_asn1_obj"):
    107             return self._asn1_obj(val)
    108         raise ASN1_Error("%r does not have any assigned ASN1 object" % self)
    109     def register(self, codecnum, codec):
    110         self._codec[codecnum] = codec
    111     def get_codec(self, codec):
    112         try:
    113             c = self._codec[codec]
    114         except KeyError as msg:
    115             raise ASN1_Error("Codec %r not found for tag %r" % (codec, self))
    116         return c
    117 
    118 class ASN1_Class_metaclass(Enum_metaclass):
    119     element_class = ASN1Tag
    120     def __new__(cls, name, bases, dct): # XXX factorise a bit with Enum_metaclass.__new__()
    121         for b in bases:
    122             for k,v in six.iteritems(b.__dict__):
    123                 if k not in dct and isinstance(v,ASN1Tag):
    124                     dct[k] = v.clone()
    125 
    126         rdict = {}
    127         for k,v in six.iteritems(dct):
    128             if isinstance(v, int):
    129                 v = ASN1Tag(k,v) 
    130                 dct[k] = v
    131                 rdict[v] = v
    132             elif isinstance(v, ASN1Tag):
    133                 rdict[v] = v
    134         dct["__rdict__"] = rdict
    135 
    136         cls = type.__new__(cls, name, bases, dct)
    137         for v in cls.__dict__.values():
    138             if isinstance(v, ASN1Tag): 
    139                 v.context = cls # overwrite ASN1Tag contexts, even cloned ones
    140         return cls
    141             
    142 
    143 class ASN1_Class(six.with_metaclass(ASN1_Class_metaclass)):
    144     pass
    145 
    146 class ASN1_Class_UNIVERSAL(ASN1_Class):
    147     name = "UNIVERSAL"
    148     ERROR = -3
    149     RAW = -2
    150     NONE = -1
    151     ANY = 0
    152     BOOLEAN = 1
    153     INTEGER = 2
    154     BIT_STRING = 3
    155     STRING = 4
    156     NULL = 5
    157     OID = 6
    158     OBJECT_DESCRIPTOR = 7
    159     EXTERNAL = 8
    160     REAL = 9
    161     ENUMERATED = 10
    162     EMBEDDED_PDF = 11
    163     UTF8_STRING = 12
    164     RELATIVE_OID = 13
    165     SEQUENCE = 16|0x20          # constructed encoding
    166     SET = 17|0x20               # constructed encoding
    167     NUMERIC_STRING = 18
    168     PRINTABLE_STRING = 19
    169     T61_STRING = 20             # aka TELETEX_STRING
    170     VIDEOTEX_STRING = 21
    171     IA5_STRING = 22
    172     UTC_TIME = 23
    173     GENERALIZED_TIME = 24
    174     GRAPHIC_STRING = 25
    175     ISO646_STRING = 26          # aka VISIBLE_STRING
    176     GENERAL_STRING = 27
    177     UNIVERSAL_STRING = 28
    178     CHAR_STRING = 29
    179     BMP_STRING = 30
    180     IPADDRESS = 0|0x40          # application-specific encoding
    181     COUNTER32 = 1|0x40          # application-specific encoding
    182     GAUGE32 = 2|0x40            # application-specific encoding
    183     TIME_TICKS = 3|0x40         # application-specific encoding
    184 
    185 
    186 class ASN1_Object_metaclass(type):
    187     def __new__(cls, name, bases, dct):
    188         c = super(ASN1_Object_metaclass, cls).__new__(cls, name, bases, dct)
    189         try:
    190             c.tag.register_asn1_object(c)
    191         except:
    192             warning("Error registering %r for %r" % (c.tag, c.codec))
    193         return c
    194 
    195 class ASN1_Object(six.with_metaclass(ASN1_Object_metaclass)):
    196     tag = ASN1_Class_UNIVERSAL.ANY
    197     def __init__(self, val):
    198         self.val = val
    199     def enc(self, codec):
    200         return self.tag.get_codec(codec).enc(self.val)
    201     def __repr__(self):
    202         return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), self.val)
    203     def __str__(self):
    204         return self.enc(conf.ASN1_default_codec)
    205     def __bytes__(self):
    206         return self.enc(conf.ASN1_default_codec)
    207     def strshow(self, lvl=0):
    208         return ("  "*lvl)+repr(self)+"\n"
    209     def show(self, lvl=0):
    210         print(self.strshow(lvl))
    211     def __eq__(self, other):
    212         return self.val == other
    213     def __lt__(self, other):
    214         return self.val < other
    215     def __le__(self, other):
    216         return self.val <= other
    217     def __gt__(self, other):
    218         return self.val > other
    219     def __ge__(self, other):
    220         return self.val >= other
    221     def __ne__(self, other):
    222         return self.val != other
    223 
    224 
    225 #######################
    226 ####  ASN1 objects ####
    227 #######################
    228 
    229 # on the whole, we order the classes by ASN1_Class_UNIVERSAL tag value
    230 
    231 class ASN1_DECODING_ERROR(ASN1_Object):
    232     tag = ASN1_Class_UNIVERSAL.ERROR
    233     def __init__(self, val, exc=None):
    234         ASN1_Object.__init__(self, val)
    235         self.exc = exc
    236     def __repr__(self):
    237         return "<%s[%r]{{%r}}>" % (self.__dict__.get("name", self.__class__.__name__),
    238                                    self.val, self.exc.args[0])
    239     def enc(self, codec):
    240         if isinstance(self.val, ASN1_Object):
    241             return self.val.enc(codec)
    242         return self.val
    243 
    244 class ASN1_force(ASN1_Object):
    245     tag = ASN1_Class_UNIVERSAL.RAW
    246     def enc(self, codec):
    247         if isinstance(self.val, ASN1_Object):
    248             return self.val.enc(codec)
    249         return self.val
    250 
    251 class ASN1_BADTAG(ASN1_force):
    252     pass
    253 
    254 class ASN1_INTEGER(ASN1_Object):
    255     tag = ASN1_Class_UNIVERSAL.INTEGER
    256     def __repr__(self):
    257         h = hex(self.val)
    258         if h[-1] == "L":
    259             h = h[:-1]
    260         # cut at 22 because with leading '0x', x509 serials should be < 23
    261         if len(h) > 22:
    262             h = h[:12] + "..." + h[-10:]
    263         r = repr(self.val)
    264         if len(r) > 20:
    265             r = r[:10] + "..." + r[-10:]
    266         return h + " <%s[%s]>" % (self.__dict__.get("name", self.__class__.__name__), r)
    267 
    268 
    269 class ASN1_BOOLEAN(ASN1_INTEGER):
    270     tag = ASN1_Class_UNIVERSAL.BOOLEAN
    271     # BER: 0 means False, anything else means True
    272     def __repr__(self):
    273         return '%s %s' % (not (self.val==0), ASN1_Object.__repr__(self))
    274 
    275 
    276 class ASN1_BIT_STRING(ASN1_Object):
    277     """
    278     /!\ ASN1_BIT_STRING values are bit strings like "011101".
    279     /!\ A zero-bit padded readable string is provided nonetheless,
    280     /!\ which is also output when __str__ is called.
    281     """
    282     tag = ASN1_Class_UNIVERSAL.BIT_STRING
    283     def __init__(self, val, readable=False):
    284         if not readable:
    285             self.val = val
    286         else:
    287             self.val_readable = val
    288     def __setattr__(self, name, value):
    289         str_value = None
    290         if isinstance(value, str):
    291             str_value = value
    292             value = raw(value)
    293         if name == "val_readable":
    294             if isinstance(value, bytes):
    295                 val = b"".join(binrepr(orb(x)).zfill(8).encode("utf8") for x in value)
    296             else:
    297                 val = "<invalid val_readable>"
    298             super(ASN1_Object, self).__setattr__("val", val)
    299             super(ASN1_Object, self).__setattr__(name, value)
    300             super(ASN1_Object, self).__setattr__("unused_bits", 0)
    301         elif name == "val":
    302             if not str_value:
    303                 str_value = plain_str(value)
    304             if isinstance(value, bytes):
    305                 if any(c for c in str_value if c not in ["0", "1"]):
    306                     print("Invalid operation: 'val' is not a valid bit string.")
    307                     return
    308                 else:
    309                     if len(value) % 8 == 0:
    310                         unused_bits = 0
    311                     else:
    312                         unused_bits = 8 - (len(value) % 8)
    313                     padded_value = str_value + ("0" * unused_bits)
    314                     bytes_arr = zip(*[iter(padded_value)]*8)
    315                     val_readable = b"".join(chb(int("".join(x),2)) for x in bytes_arr)
    316             else:
    317                 val_readable = "<invalid val>"
    318                 unused_bits = 0
    319             super(ASN1_Object, self).__setattr__("val_readable", val_readable)
    320             super(ASN1_Object, self).__setattr__(name, value)
    321             super(ASN1_Object, self).__setattr__("unused_bits", unused_bits)
    322         elif name == "unused_bits":
    323             print("Invalid operation: unused_bits rewriting is not supported.")
    324         else:
    325             super(ASN1_Object, self).__setattr__(name, value)
    326     def __repr__(self):
    327         if len(self.val) <= 16:
    328             v = plain_str(self.val)
    329             return "<%s[%s] (%d unused bit%s)>" % (self.__dict__.get("name", self.__class__.__name__), v, self.unused_bits, "s" if self.unused_bits>1 else "")
    330         else:
    331             s = self.val_readable
    332             if len(s) > 20:
    333                 s = s[:10] + b"..." + s[-10:]
    334             v = plain_str(self.val)
    335             return "<%s[%s] (%d unused bit%s)>" % (self.__dict__.get("name", self.__class__.__name__), v, self.unused_bits, "s" if self.unused_bits>1 else "")
    336     def __str__(self):
    337         return self.val_readable
    338     def __bytes__(self):
    339         return self.val_readable
    340 
    341 class ASN1_STRING(ASN1_Object):
    342     tag = ASN1_Class_UNIVERSAL.STRING
    343 
    344 class ASN1_NULL(ASN1_Object):
    345     tag = ASN1_Class_UNIVERSAL.NULL
    346     def __repr__(self):
    347         return ASN1_Object.__repr__(self)
    348 
    349 class ASN1_OID(ASN1_Object):
    350     tag = ASN1_Class_UNIVERSAL.OID
    351     def __init__(self, val):
    352         val = conf.mib._oid(plain_str(val))
    353         ASN1_Object.__init__(self, val)
    354         self.oidname = conf.mib._oidname(val)
    355     def __repr__(self):
    356         return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), self.oidname)
    357 
    358 class ASN1_ENUMERATED(ASN1_INTEGER):
    359     tag = ASN1_Class_UNIVERSAL.ENUMERATED
    360 
    361 class ASN1_UTF8_STRING(ASN1_STRING):
    362     tag = ASN1_Class_UNIVERSAL.UTF8_STRING
    363 
    364 class ASN1_NUMERIC_STRING(ASN1_STRING):
    365     tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING
    366 
    367 class ASN1_PRINTABLE_STRING(ASN1_STRING):
    368     tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING
    369 
    370 class ASN1_T61_STRING(ASN1_STRING):
    371     tag = ASN1_Class_UNIVERSAL.T61_STRING
    372 
    373 class ASN1_VIDEOTEX_STRING(ASN1_STRING):
    374     tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING
    375 
    376 class ASN1_IA5_STRING(ASN1_STRING):
    377     tag = ASN1_Class_UNIVERSAL.IA5_STRING
    378 
    379 class ASN1_UTC_TIME(ASN1_STRING):
    380     tag = ASN1_Class_UNIVERSAL.UTC_TIME
    381     def __init__(self, val):
    382         super(ASN1_UTC_TIME, self).__init__(val)
    383     def __setattr__(self, name, value):
    384         if isinstance(value, bytes):
    385             value = plain_str(value)
    386         if name == "val":
    387             pretty_time = None
    388             if (isinstance(value, str) and
    389                 len(value) == 13 and value[-1] == "Z"):
    390                 dt = datetime.strptime(value[:-1], "%y%m%d%H%M%S")
    391                 pretty_time = dt.strftime("%b %d %H:%M:%S %Y GMT")
    392             else:
    393                 pretty_time = "%s [invalid utc_time]" % value
    394             super(ASN1_UTC_TIME, self).__setattr__("pretty_time", pretty_time)
    395             super(ASN1_UTC_TIME, self).__setattr__(name, value)
    396         elif name == "pretty_time":
    397             print("Invalid operation: pretty_time rewriting is not supported.")
    398         else:
    399             super(ASN1_UTC_TIME, self).__setattr__(name, value)
    400     def __repr__(self):
    401         return "%s %s" % (self.pretty_time, ASN1_STRING.__repr__(self))
    402 
    403 class ASN1_GENERALIZED_TIME(ASN1_STRING):
    404     tag = ASN1_Class_UNIVERSAL.GENERALIZED_TIME
    405     def __init__(self, val):
    406         super(ASN1_GENERALIZED_TIME, self).__init__(val)
    407     def __setattr__(self, name, value):
    408         if isinstance(value, bytes):
    409             value = plain_str(value)
    410         if name == "val":
    411             pretty_time = None
    412             if (isinstance(value, str) and
    413                 len(value) == 15 and value[-1] == "Z"):
    414                 dt = datetime.strptime(value[:-1], "%Y%m%d%H%M%S")
    415                 pretty_time = dt.strftime("%b %d %H:%M:%S %Y GMT")
    416             else:
    417                 pretty_time = "%s [invalid generalized_time]" % value
    418             super(ASN1_GENERALIZED_TIME, self).__setattr__("pretty_time", pretty_time)
    419             super(ASN1_GENERALIZED_TIME, self).__setattr__(name, value)
    420         elif name == "pretty_time":
    421             print("Invalid operation: pretty_time rewriting is not supported.")
    422         else:
    423             super(ASN1_GENERALIZED_TIME, self).__setattr__(name, value)
    424     def __repr__(self):
    425         return "%s %s" % (self.pretty_time, ASN1_STRING.__repr__(self))
    426 
    427 class ASN1_ISO646_STRING(ASN1_STRING):
    428     tag = ASN1_Class_UNIVERSAL.ISO646_STRING
    429 
    430 class ASN1_UNIVERSAL_STRING(ASN1_STRING):
    431     tag = ASN1_Class_UNIVERSAL.UNIVERSAL_STRING
    432 
    433 class ASN1_BMP_STRING(ASN1_STRING):
    434     tag = ASN1_Class_UNIVERSAL.BMP_STRING
    435 
    436 class ASN1_SEQUENCE(ASN1_Object):
    437     tag = ASN1_Class_UNIVERSAL.SEQUENCE
    438     def strshow(self, lvl=0):
    439         s = ("  "*lvl)+("# %s:" % self.__class__.__name__)+"\n"
    440         for o in self.val:
    441             s += o.strshow(lvl=lvl+1)
    442         return s
    443     
    444 class ASN1_SET(ASN1_SEQUENCE):
    445     tag = ASN1_Class_UNIVERSAL.SET
    446 
    447 class ASN1_IPADDRESS(ASN1_STRING):
    448     tag = ASN1_Class_UNIVERSAL.IPADDRESS
    449 
    450 class ASN1_COUNTER32(ASN1_INTEGER):
    451     tag = ASN1_Class_UNIVERSAL.COUNTER32
    452 
    453 class ASN1_GAUGE32(ASN1_INTEGER):
    454     tag = ASN1_Class_UNIVERSAL.GAUGE32
    455 
    456 class ASN1_TIME_TICKS(ASN1_INTEGER):
    457     tag = ASN1_Class_UNIVERSAL.TIME_TICKS
    458    
    459 
    460 conf.ASN1_default_codec = ASN1_Codecs.BER
    461