Home | History | Annotate | Download | only in layers
      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 ## This program is published under a GPLv2 license
      5 
      6 """
      7 ISAKMP (Internet Security Association and Key Management Protocol).
      8 """
      9 
     10 from __future__ import absolute_import
     11 import struct
     12 from scapy.config import conf
     13 from scapy.packet import *
     14 from scapy.compat import *
     15 from scapy.fields import *
     16 from scapy.ansmachine import *
     17 from scapy.layers.inet import IP,UDP
     18 from scapy.sendrecv import sr
     19 from scapy.error import warning
     20 from functools import reduce
     21 
     22 
     23 # see http://www.iana.org/assignments/ipsec-registry for details
     24 ISAKMPAttributeTypes= { "Encryption":    (1, { "DES-CBC"  : 1,
     25                                                 "IDEA-CBC" : 2,
     26                                                 "Blowfish-CBC" : 3,
     27                                                 "RC5-R16-B64-CBC" : 4,
     28                                                 "3DES-CBC" : 5, 
     29                                                 "CAST-CBC" : 6, 
     30                                                 "AES-CBC" : 7, 
     31                                                 "CAMELLIA-CBC" : 8, }, 0),
     32                          "Hash":          (2, { "MD5": 1,
     33                                                 "SHA": 2,
     34                                                 "Tiger": 3,
     35                                                 "SHA2-256": 4,
     36                                                 "SHA2-384": 5,
     37                                                 "SHA2-512": 6,}, 0),
     38                          "Authentication":(3, { "PSK": 1, 
     39                                                 "DSS": 2,
     40                                                 "RSA Sig": 3,
     41                                                 "RSA Encryption": 4,
     42                                                 "RSA Encryption Revised": 5,
     43                                                 "ElGamal Encryption": 6,
     44                                                 "ElGamal Encryption Revised": 7,
     45                                                 "ECDSA Sig": 8,
     46                                                 "HybridInitRSA": 64221,
     47                                                 "HybridRespRSA": 64222,
     48                                                 "HybridInitDSS": 64223,
     49                                                 "HybridRespDSS": 64224,
     50                                                 "XAUTHInitPreShared": 65001,
     51                                                 "XAUTHRespPreShared": 65002,
     52                                                 "XAUTHInitDSS": 65003,
     53                                                 "XAUTHRespDSS": 65004,
     54                                                 "XAUTHInitRSA": 65005,
     55                                                 "XAUTHRespRSA": 65006,
     56                                                 "XAUTHInitRSAEncryption": 65007,
     57                                                 "XAUTHRespRSAEncryption": 65008,
     58                                                 "XAUTHInitRSARevisedEncryption": 65009,
     59                                                 "XAUTHRespRSARevisedEncryptio": 65010, }, 0),
     60                          "GroupDesc":     (4, { "768MODPgr"  : 1,
     61                                                 "1024MODPgr" : 2, 
     62                                                 "EC2Ngr155"  : 3,
     63                                                 "EC2Ngr185"  : 4,
     64                                                 "1536MODPgr" : 5, 
     65                                                 "2048MODPgr" : 14, 
     66                                                 "3072MODPgr" : 15, 
     67                                                 "4096MODPgr" : 16, 
     68                                                 "6144MODPgr" : 17, 
     69                                                 "8192MODPgr" : 18, }, 0),
     70                          "GroupType":      (5,  {"MODP":       1,
     71                                                  "ECP":        2,
     72                                                  "EC2N":       3}, 0),
     73                          "GroupPrime":     (6,  {}, 1),
     74                          "GroupGenerator1":(7,  {}, 1),
     75                          "GroupGenerator2":(8,  {}, 1),
     76                          "GroupCurveA":    (9,  {}, 1),
     77                          "GroupCurveB":    (10, {}, 1),
     78                          "LifeType":       (11, {"Seconds":     1,
     79                                                  "Kilobytes":   2,  }, 0),
     80                          "LifeDuration":   (12, {}, 1),
     81                          "PRF":            (13, {}, 0),
     82                          "KeyLength":      (14, {}, 0),
     83                          "FieldSize":      (15, {}, 0),
     84                          "GroupOrder":     (16, {}, 1),
     85                          }
     86 
     87 # the name 'ISAKMPTransformTypes' is actually a misnomer (since the table 
     88 # holds info for all ISAKMP Attribute types, not just transforms, but we'll 
     89 # keep it for backwards compatibility... for now at least
     90 ISAKMPTransformTypes = ISAKMPAttributeTypes
     91 
     92 ISAKMPTransformNum = {}
     93 for n in ISAKMPTransformTypes:
     94     val = ISAKMPTransformTypes[n]
     95     tmp = {}
     96     for e in val[1]:
     97         tmp[val[1][e]] = e
     98     ISAKMPTransformNum[val[0]] = (n,tmp, val[2])
     99 del(n)
    100 del(e)
    101 del(tmp)
    102 del(val)
    103 
    104 
    105 class ISAKMPTransformSetField(StrLenField):
    106     islist=1
    107     def type2num(self, type_val_tuple):
    108         typ, val = type_val_tuple
    109         type_val,enc_dict,tlv = ISAKMPTransformTypes.get(typ, (typ,{},0))
    110         val = enc_dict.get(val, val)
    111         s = b""
    112         if (val & ~0xffff):
    113             if not tlv:
    114                 warning("%r should not be TLV but is too big => using TLV encoding" % typ)
    115             n = 0
    116             while val:
    117                 s = chb(val&0xff)+s
    118                 val >>= 8
    119                 n += 1
    120             val = n
    121         else:
    122             type_val |= 0x8000
    123         return struct.pack("!HH",type_val, val)+s
    124     def num2type(self, typ, enc):
    125         val = ISAKMPTransformNum.get(typ,(typ,{}))
    126         enc = val[1].get(enc,enc)
    127         return (val[0],enc)
    128     def i2m(self, pkt, i):
    129         if i is None:
    130             return b""
    131         i = [self.type2num(e) for e in i]
    132         return b"".join(i)
    133     def m2i(self, pkt, m):
    134         # I try to ensure that we don't read off the end of our packet based
    135         # on bad length fields we're provided in the packet. There are still
    136         # conditions where struct.unpack() may not get enough packet data, but
    137         # worst case that should result in broken attributes (which would
    138         # be expected). (wam)
    139         lst = []
    140         while len(m) >= 4:
    141             trans_type, = struct.unpack("!H", m[:2])
    142             is_tlv = not (trans_type & 0x8000)
    143             if is_tlv:
    144                 # We should probably check to make sure the attribute type we
    145                 # are looking at is allowed to have a TLV format and issue a 
    146                 # warning if we're given an TLV on a basic attribute.
    147                 value_len, = struct.unpack("!H", m[2:4])
    148                 if value_len+4 > len(m):
    149                     warning("Bad length for ISAKMP tranform type=%#6x" % trans_type)
    150                 value = m[4:4+value_len]
    151                 value = reduce(lambda x,y: (x<<8)|y, struct.unpack("!%s" % ("B"*len(value),), value),0)
    152             else:
    153                 trans_type &= 0x7fff
    154                 value_len=0
    155                 value, = struct.unpack("!H", m[2:4])
    156             m=m[4+value_len:]
    157             lst.append(self.num2type(trans_type, value))
    158         if len(m) > 0:
    159             warning("Extra bytes after ISAKMP transform dissection [%r]" % m)
    160         return lst
    161 
    162 
    163 ISAKMP_payload_type = ["None","SA","Proposal","Transform","KE","ID","CERT","CR","Hash",
    164                        "SIG","Nonce","Notification","Delete","VendorID"]
    165 
    166 ISAKMP_exchange_type = ["None","base","identity prot.",
    167                         "auth only", "aggressive", "info"]
    168 
    169 
    170 class ISAKMP_class(Packet):
    171     def guess_payload_class(self, payload):
    172         np = self.next_payload
    173         if np == 0:
    174             return conf.raw_layer
    175         elif np < len(ISAKMP_payload_type):
    176             pt = ISAKMP_payload_type[np]
    177             return globals().get("ISAKMP_payload_%s" % pt, ISAKMP_payload)
    178         else:
    179             return ISAKMP_payload
    180 
    181 
    182 class ISAKMP(ISAKMP_class): # rfc2408
    183     name = "ISAKMP"
    184     fields_desc = [
    185         StrFixedLenField("init_cookie","",8),
    186         StrFixedLenField("resp_cookie","",8),
    187         ByteEnumField("next_payload",0,ISAKMP_payload_type),
    188         XByteField("version",0x10),
    189         ByteEnumField("exch_type",0,ISAKMP_exchange_type),
    190         FlagsField("flags",0, 8, ["encryption","commit","auth_only","res3","res4","res5","res6","res7"]), # XXX use a Flag field
    191         IntField("id",0),
    192         IntField("length",None)
    193         ]
    194 
    195     def guess_payload_class(self, payload):
    196         if self.flags & 1:
    197             return conf.raw_layer
    198         return ISAKMP_class.guess_payload_class(self, payload)
    199 
    200     def answers(self, other):
    201         if isinstance(other, ISAKMP):
    202             if other.init_cookie == self.init_cookie:
    203                 return 1
    204         return 0
    205     def post_build(self, p, pay):
    206         p += pay
    207         if self.length is None:
    208             p = p[:24]+struct.pack("!I",len(p))+p[28:]
    209         return p
    210        
    211 
    212 
    213 
    214 class ISAKMP_payload_Transform(ISAKMP_class):
    215     name = "IKE Transform"
    216     fields_desc = [
    217         ByteEnumField("next_payload",None,ISAKMP_payload_type),
    218         ByteField("res",0),
    219 #        ShortField("len",None),
    220         ShortField("length",None),
    221         ByteField("num",None),
    222         ByteEnumField("id",1,{1:"KEY_IKE"}),
    223         ShortField("res2",0),
    224         ISAKMPTransformSetField("transforms",None,length_from=lambda x:x.length-8)
    225 #        XIntField("enc",0x80010005L),
    226 #        XIntField("hash",0x80020002L),
    227 #        XIntField("auth",0x80030001L),
    228 #        XIntField("group",0x80040002L),
    229 #        XIntField("life_type",0x800b0001L),
    230 #        XIntField("durationh",0x000c0004L),
    231 #        XIntField("durationl",0x00007080L),
    232         ]
    233     def post_build(self, p, pay):
    234         if self.length is None:
    235             l = len(p)
    236             p = p[:2]+chb((l>>8)&0xff)+chb(l&0xff)+p[4:]
    237         p += pay
    238         return p
    239             
    240 
    241 
    242         
    243 class ISAKMP_payload_Proposal(ISAKMP_class):
    244     name = "IKE proposal"
    245 #    ISAKMP_payload_type = 0
    246     fields_desc = [
    247         ByteEnumField("next_payload",None,ISAKMP_payload_type),
    248         ByteField("res",0),
    249         FieldLenField("length",None,"trans","H", adjust=lambda pkt,x:x+8),
    250         ByteField("proposal",1),
    251         ByteEnumField("proto",1,{1:"ISAKMP"}),
    252         FieldLenField("SPIsize",None,"SPI","B"),
    253         ByteField("trans_nb",None),
    254         StrLenField("SPI","",length_from=lambda x:x.SPIsize),
    255         PacketLenField("trans",conf.raw_layer(),ISAKMP_payload_Transform,length_from=lambda x:x.length-8),
    256         ]
    257 
    258 
    259 class ISAKMP_payload(ISAKMP_class):
    260     name = "ISAKMP payload"
    261     fields_desc = [
    262         ByteEnumField("next_payload",None,ISAKMP_payload_type),
    263         ByteField("res",0),
    264         FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4),
    265         StrLenField("load","",length_from=lambda x:x.length-4),
    266         ]
    267 
    268 
    269 class ISAKMP_payload_VendorID(ISAKMP_class):
    270     name = "ISAKMP Vendor ID"
    271     overload_fields = { ISAKMP: { "next_payload":13 }}
    272     fields_desc = [
    273         ByteEnumField("next_payload",None,ISAKMP_payload_type),
    274         ByteField("res",0),
    275         FieldLenField("length",None,"vendorID","H", adjust=lambda pkt,x:x+4),
    276         StrLenField("vendorID","",length_from=lambda x:x.length-4),
    277         ]
    278 
    279 class ISAKMP_payload_SA(ISAKMP_class):
    280     name = "ISAKMP SA"
    281     overload_fields = { ISAKMP: { "next_payload":1 }}
    282     fields_desc = [
    283         ByteEnumField("next_payload",None,ISAKMP_payload_type),
    284         ByteField("res",0),
    285         FieldLenField("length",None,"prop","H", adjust=lambda pkt,x:x+12),
    286         IntEnumField("DOI",1,{1:"IPSEC"}),
    287         IntEnumField("situation",1,{1:"identity"}),
    288         PacketLenField("prop",conf.raw_layer(),ISAKMP_payload_Proposal,length_from=lambda x:x.length-12),
    289         ]
    290 
    291 class ISAKMP_payload_Nonce(ISAKMP_class):
    292     name = "ISAKMP Nonce"
    293     overload_fields = { ISAKMP: { "next_payload":10 }}
    294     fields_desc = [
    295         ByteEnumField("next_payload",None,ISAKMP_payload_type),
    296         ByteField("res",0),
    297         FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4),
    298         StrLenField("load","",length_from=lambda x:x.length-4),
    299         ]
    300 
    301 class ISAKMP_payload_KE(ISAKMP_class):
    302     name = "ISAKMP Key Exchange"
    303     overload_fields = { ISAKMP: { "next_payload":4 }}
    304     fields_desc = [
    305         ByteEnumField("next_payload",None,ISAKMP_payload_type),
    306         ByteField("res",0),
    307         FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4),
    308         StrLenField("load","",length_from=lambda x:x.length-4),
    309         ]
    310 
    311 class ISAKMP_payload_ID(ISAKMP_class):
    312     name = "ISAKMP Identification"
    313     overload_fields = { ISAKMP: { "next_payload":5 }}
    314     fields_desc = [
    315         ByteEnumField("next_payload",None,ISAKMP_payload_type),
    316         ByteField("res",0),
    317         FieldLenField("length",None,"load","H",adjust=lambda pkt,x:x+8),
    318         ByteEnumField("IDtype",1,{1:"IPv4_addr", 11:"Key"}),
    319         ByteEnumField("ProtoID",0,{0:"Unused"}),
    320         ShortEnumField("Port",0,{0:"Unused"}),
    321 #        IPField("IdentData","127.0.0.1"),
    322         StrLenField("load","",length_from=lambda x:x.length-8),
    323         ]
    324 
    325 
    326 
    327 class ISAKMP_payload_Hash(ISAKMP_class):
    328     name = "ISAKMP Hash"
    329     overload_fields = { ISAKMP: { "next_payload":8 }}
    330     fields_desc = [
    331         ByteEnumField("next_payload",None,ISAKMP_payload_type),
    332         ByteField("res",0),
    333         FieldLenField("length",None,"load","H",adjust=lambda pkt,x:x+4),
    334         StrLenField("load","",length_from=lambda x:x.length-4),
    335         ]
    336 
    337 
    338 
    339 ISAKMP_payload_type_overload = {}
    340 for i, payloadname in enumerate(ISAKMP_payload_type):
    341     name = "ISAKMP_payload_%s" % payloadname
    342     if name in globals():
    343         ISAKMP_payload_type_overload[globals()[name]] = {"next_payload": i}
    344 
    345 del i, payloadname, name
    346 ISAKMP_class._overload_fields = ISAKMP_payload_type_overload.copy()
    347 
    348 
    349 bind_layers( UDP,           ISAKMP,        dport=500, sport=500)
    350 def ikescan(ip):
    351     return sr(IP(dst=ip)/UDP()/ISAKMP(init_cookie=RandString(8),
    352                                       exch_type=2)/ISAKMP_payload_SA(prop=ISAKMP_payload_Proposal()))
    353 
    354