|
Subject: More updates to IKE transforms Newsgroups: gmane.comp.security.scapy.general Date: 2006-03-08 00:40:35 GMT (3 years, 17 weeks, 1 day, 3 hours and 38 minutes ago) If you recall, in the postscript of my mesg from about a week ago I mentioned that the IKE patch I submitted then was only for proper dissecting of packets with long IKE attribute values(*). Getting proper packet construction with long attribute handling(*) was more difficult than I thought it would be, but I finally got it done. I'm attaching a patch that addresses this issue. There is only one slight incompatible change (beyond the changes I have already covered in my last IKE update email). The return value of ISAKMPTransformSetField.type2num() was changed to be a sequence of integers which later get packed into 2-byte fields, as many as as are necessary to handle the data that is passed in to the method. Previously, the result was a single integer which would get packed into a 4 byte long word. I did *NOT* change the name of this method, although it should probably get changed to more accurately reflect the current behavior (type2list_of_long_ints doesn't quite have the same brevity.) In addition to the patch, I'm again attaching a testcase suite which demonstrates the problem and shows that after the patch a proper timestamp lifetime attribute value can be specified. For the curious, the testcase driver program takes a -w option, which will write the generated packet out to a pcap file that allows you to see the packet generated... useful if you want to compare the before/after behavior of my change. I'm also attaching the ike-proposals.pcap file which is used by the the test suite for determining if IKE attribute parsing is happening properly on dissection). Finally, there are a couple of requests for enhancement which go beyond my current understanding of the deep machinery of scapy. It'd be especially nice if scapy could auto-magically fill in the ISAKMP_payload_Proposal.trans_nb (number of included transforms) attribute on the ISAKMP_payload_Proposal as well as auto-populate the 'num' attribute on the ISAKMP_payload_Transform instance itself. I looked into doing this, but wasn't sure whether it was best to override 'build()', 'do_build()', or 'post_build()'. In general, more docstrings on the common base class methods would certainly help 3rd party contributors. In addition to those build* methods, the meaning of i2m, m2i, i2repr, any2i, i2h and others are fairly nebulous (to me at least). -- William * BTW, the complete specification of long attribute vs basic attribute handling is defined in RFC 2408, section 3.3.
--- scapy.py-1.0.3.14 2006-02-21 17:04:23.017716605 -0600
+++ scapy.py 2006-03-07 17:14:49.282591957 -0600
@@ -1363,7 +1363,7 @@
##################
import socket, sys, getopt, string, struct, random, os, code
-import cPickle, copy, types, gzip, base64, re
+import cPickle, copy, types, gzip, base64, re, itertools
from select import select
from fcntl import ioctl
import fcntl
@@ -3485,24 +3485,82 @@
# x = len(v)+self.shift
# return x
-ISAKMPTransformTypes = { "Encryption": (1, { "DES-CBS" : 1,
- "3DES-CBC" : 5, }),
+# see http://www.iana.org/assignments/ipsec-registry for details
+ISAKMPAttributeTypes= { "Encryption": (1, { "DES-CBS" : 1,
+ "IDEA-CBC" : 2,
+ "Blowfish-CBC" : 3,
+ "RC5-R16-B64-CBC" : 4,
+ "3DES-CBC" : 5,
+ "CAST-CBC" : 6,
+ "AES-CBC" : 7,
+ "CAMELLIA-CBC" : 8, }, 0),
"Hash": (2, { "MD5": 1,
- "SHA": 2, }),
- "Authentication":(3, { "PSK": 1, }),
+ "SHA": 2,
+ "Tiger": 3,
+ "SHA2-256": 4,
+ "SHA2-384": 5,
+ "SHA2-512": 6,}, 0),
+ "Authentication":(3, { "PSK": 1,
+ "DSS": 2,
+ "RSA Sig": 3,
+ "RSA Encryption": 4,
+ "RSA Encryption Revised": 5,
+ "ElGamal Encryption": 6,
+ "ElGamal Encryption Revised": 7,
+ "ECDSA Sig": 8,
+ "HybridInitRSA": 64221,
+ "HybridRespRSA": 64222,
+ "HybridInitDSS": 64223,
+ "HybridRespDSS": 64224,
+ "XAUTHInitPreShared": 65001,
+ "XAUTHRespPreShared": 65002,
+ "XAUTHInitDSS": 65003,
+ "XAUTHRespDSS": 65004,
+ "XAUTHInitRSA": 65005,
+ "XAUTHRespRSA": 65006,
+ "XAUTHInitRSAEncryption": 65007,
+ "XAUTHRespRSAEncryption": 65008,
+ "XAUTHInitRSARevisedEncryption": 65009,
+ "XAUTHRespRSARevisedEncryptio": 65010, }, 0),
"GroupDesc": (4, { "768MODPgr" : 1,
- "1024MODPgr" : 2, }),
- "LifeType": (11,{ "Seconds":1, }),
- "LifeDuration": (12,{}),
+ "1024MODPgr" : 2,
+ "EC2Ngr155" : 3,
+ "EC2Ngr185" : 4,
+ "1536MODPgr" : 5,
+ "2048MODPgr" : 14,
+ "3072MODPgr" : 15,
+ "4096MODPgr" : 16,
+ "6144MODPgr" : 17,
+ "8192MODPgr" : 18, }, 0),
+ "GroupType": (5, {"MODP": 1,
+ "ECP": 2,
+ "EC2N": 3}, 0),
+ "GroupPrime": (6, {}, 1),
+ "GroupGenerator1":(7, {}, 1),
+ "GroupGenerator2":(8, {}, 1),
+ "GroupCurveA": (9, {}, 1),
+ "GroupCurveB": (10, {}, 1),
+ "LifeType": (11, {"Seconds": 1,
+ "Kilobytes": 2, }, 0),
+ "LifeDuration": (12, {}, 1),
+ "PRF": (13, {}, 0),
+ "KeyLength": (14, {}, 0),
+ "FieldSize": (15, {}, 0),
+ "GroupOrder": (16, {}, 1),
}
+# the name 'ISAKMPTransformTypes' is actually a misnomer (since the table
+# holds info for all ISAKMP Attribute types, not just transforms) but we'll
+# keep it for backwards compatibility... for now at least
+ISAKMPTransformTypes = ISAKMPAttributeTypes
+
ISAKMPTransformNum = {}
for n in ISAKMPTransformTypes:
val = ISAKMPTransformTypes[n]
tmp = {}
for e in val[1]:
tmp[val[1][e]] = e
- ISAKMPTransformNum[val[0]] = (n,tmp)
+ ISAKMPTransformNum[val[0]] = (n,tmp, val[2])
del(n)
del(e)
del(tmp)
@@ -3511,38 +3569,64 @@
class ISAKMPTransformSetField(StrLenField):
islist=1
+ # all of this TLV attribute versus "simple attribute" complexity is
+ # specified in RFC 2408, section 3.3
def type2num(self, (typ,enc)):
- if ISAKMPTransformTypes.has_key(typ):
- val = ISAKMPTransformTypes[typ]
- else:
- val = (int(typ),{})
- if val[1].has_key(enc):
- enc = val[1][enc]
- else:
- enc = int(enc)
- return ((val[0] | 0x8000L) << 16) | enc
- def num2type(self, num):
- typ = (num >> 16) & 0x7fff
- enc = num & 0xffff
+ attrnum, attrsubs, can_beTLV = ISAKMPAttributeTypes.get(typ, (typ,{},0))
+ enc = attrsubs.get(enc) or int(enc)
+ if not can_beTLV or enc < 65536:
+ # The attribute is either not allowed to be a TLV, or *is*
+ # allowed to be a TLV but doesn't need to be.
+ # Chop off the attr value at 16 bits so we don't overflow into
+ # the attribute type
+ return [(attrnum | 0x8000L), (enc & ((1<<16)-1))]
+ long_vals = []
+ while enc:
+ # peel off every word of the value into a list, least
+ # significant words first, then reverse the list when we're done
+ long_vals.append(enc & (1<<16)-1)
+ enc >>= 16
+ long_vals.append(2*len(long_vals))
+ long_vals.append(attrnum)
+ long_vals.reverse()
+ return long_vals
+
+ def num2type(self, typ, enc):
val = ISAKMPTransformNum.get(typ,(typ,{}))
enc = val[1].get(enc,enc)
return (val[0],enc)
-
-
def i2m(self, pkt, i):
if i is None:
return ""
- i = map(self.type2num, i)
- return struct.pack("!"+"I"*len(i),*i)
+ i = [x for x in itertools.chain(*map(self.type2num, i))]
+ return struct.pack("!"+"H"*len(i),*i)
def m2i(self, pkt, m):
- lst = struct.unpack("!"+"I"*(len(m)/4),m)
- lst = map(self.num2type, lst)
+ # I try to ensure that we don't read off the end of our packet based
+ # on bad length fields we're provided in the packet. There are still
+ # conditions where struct.unpack() may not get enough packet data, but
+ # worst case that should result in broken attributes (which would
+ # be expected). (wam)
+ lst = []
+ while len(m)>0:
+ trans_type, = struct.unpack("!H", m[:2])
+ is_tlv = not (trans_type >>15)
+ trans_type &= 0x7fff
+ if is_tlv:
+ # We should probably check to make sure the attribute type we
+ # are looking at is allowed to have a TLV format and issue a
+ # warning if we're given an TLV on a basic attribute.
+ value_len, = struct.unpack("!H", m[2:4])
+ value = reduce(lambda x,y: (x<<8)|y, struct.unpack("!%s" % ("B"*value_len,), m[4:4+value_len]))
+ else:
+ value_len=0
+ value, = struct.unpack("!H", m[2:4])
+ m=m[4+value_len:]
+ lst.append(self.num2type(trans_type, value))
return lst
def getfield(self, pkt, s):
l = getattr(pkt, self.fld)
l += pkt.get_field(self.fld).shift
i = self.m2i(pkt, s[:l])
-
return s[l:],i
class StrNullField(StrField):
@@ -6311,7 +6395,6 @@
]
-
class ISAKMP_payload_Proposal(ISAKMP_class):
name = "IKE proposal"
# ISAKMP_payload_type = 0
--------------------------------------------------------------------- Desinscription: envoyez un message a: scapy.ml-unsubscribe <at> secdev.org Pour obtenir de l'aide, ecrivez a: scapy.ml-help <at> secdev.org |
|
|