diff --git a/scapy/layers/l2.py b/scapy/layers/l2.py index 26f7871c75975fb036c18f7571f9fd0ab35cd09b..25eed3dcdbb9aaa65871492b564a2a120cc207a6 100644 --- a/scapy/layers/l2.py +++ b/scapy/layers/l2.py @@ -262,65 +262,265 @@ class STP(Packet): BCDFloatField("fwddelay", 15) ] + +# +# EAPOL +# + +#________________________________________________________________________ +# +# EAPOL protocol version +# IEEE Std 802.1X-2010 - Section 11.3.1 +#________________________________________________________________________ +# + +eapol_versions = { + 0x1: "802.1X-2001", + 0x2: "802.1X-2004", + 0x3: "802.1X-2010", +} + +#________________________________________________________________________ +# +# EAPOL Packet Types +# IEEE Std 802.1X-2010 - Table 11.3 +#________________________________________________________________________ +# + +eapol_types = { + 0x0: "EAP-Packet", # "EAPOL-EAP" in 801.1X-2010 + 0x1: "EAPOL-Start", + 0x2: "EAPOL-Logoff", + 0x3: "EAPOL-Key", + 0x4: "EAPOL-Encapsulated-ASF-Alert", + 0x5: "EAPOL-MKA", + 0x6: "EAPOL-Announcement (Generic)", + 0x7: "EAPOL-Announcement (Specific)", + 0x8: "EAPOL-Announcement-Req" +} + + class EAPOL(Packet): + + """ + EAPOL - IEEE Std 802.1X-2010 + """ + name = "EAPOL" - fields_desc = [ ByteField("version", 1), - ByteEnumField("type", 0, ["EAP_PACKET", "START", "LOGOFF", "KEY", "ASF"]), - LenField("len", None, "H") ] - - EAP_PACKET= 0 + fields_desc = [ + ByteEnumField("version", 1, eapol_versions), + ByteEnumField("type", 0, eapol_types), + LenField("len", None, "H") + ] + + EAP_PACKET = 0 START = 1 LOGOFF = 2 KEY = 3 ASF = 4 + def extract_padding(self, s): l = self.len - return s[:l],s[l:] + return s[:l], s[l:] + def hashret(self): - return chr(self.type)+self.payload.hashret() + return chr(self.type) + self.payload.hashret() + def answers(self, other): - if isinstance(other,EAPOL): - if ( (self.type == self.EAP_PACKET) and - (other.type == self.EAP_PACKET) ): + if isinstance(other, EAPOL): + if ((self.type == self.EAP_PACKET) and + (other.type == self.EAP_PACKET)): return self.payload.answers(other.payload) return 0 + def mysummary(self): return self.sprintf("EAPOL %EAPOL.type%") - + + +# +# EAP +# + + +#________________________________________________________________________ +# +# EAP methods types +# http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-4 +#________________________________________________________________________ +# + +eap_types = { + 0: "Reserved", + 1: "Identity", + 2: "Notification", + 3: "Legacy Nak", + 4: "MD5-Challenge", + 5: "One-Time Password (OTP)", + 6: "Generic Token Card (GTC)", + 7: "Allocated - RFC3748", + 8: "Allocated - RFC3748", + 9: "RSA Public Key Authentication", + 10: "DSS Unilateral", + 11: "KEA", + 12: "KEA-VALIDATE", + 13: "EAP-TLS", + 14: "Defender Token (AXENT)", + 15: "RSA Security SecurID EAP", + 16: "Arcot Systems EAP", + 17: "EAP-Cisco Wireless", + 18: "GSM Subscriber Identity Modules (EAP-SIM)", + 19: "SRP-SHA1", + 20: "Unassigned", + 21: "EAP-TTLS", + 22: "Remote Access Service", + 23: "EAP-AKA Authentication", + 24: "EAP-3Com Wireless", + 25: "PEAP", + 26: "MS-EAP-Authentication", + 27: "Mutual Authentication w/Key Exchange (MAKE)", + 28: "CRYPTOCard", + 29: "EAP-MSCHAP-V2", + 30: "DynamID", + 31: "Rob EAP", + 32: "Protected One-Time Password", + 33: "MS-Authentication-TLV", + 34: "SentriNET", + 35: "EAP-Actiontec Wireless", + 36: "Cogent Systems Biometrics Authentication EAP", + 37: "AirFortress EAP", + 38: "EAP-HTTP Digest", + 39: "SecureSuite EAP", + 40: "DeviceConnect EAP", + 41: "EAP-SPEKE", + 42: "EAP-MOBAC", + 43: "EAP-FAST", + 44: "ZoneLabs EAP (ZLXEAP)", + 45: "EAP-Link", + 46: "EAP-PAX", + 47: "EAP-PSK", + 48: "EAP-SAKE", + 49: "EAP-IKEv2", + 50: "EAP-AKA", + 51: "EAP-GPSK", + 52: "EAP-pwd", + 53: "EAP-EKE Version 1", + 54: "EAP Method Type for PT-EAP", + 55: "TEAP", + 254: "Reserved for the Expanded Type", + 255: "Experimental", +} + + +#________________________________________________________________________ +# +# EAP codes +# http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-1 +#________________________________________________________________________ +# + +eap_codes = { + 1: "Request", + 2: "Response", + 3: "Success", + 4: "Failure", + 5: "Initiate", + 6: "Finish" +} + class EAP(Packet): + + """ + RFC 3748 - Extensible Authentication Protocol (EAP) + """ + name = "EAP" - fields_desc = [ ByteEnumField("code", 4, {1:"REQUEST",2:"RESPONSE",3:"SUCCESS",4:"FAILURE"}), - ByteField("id", 0), - ShortField("len",None), - ConditionalField(ByteEnumField("type",0, {1:"ID",4:"MD5"}), lambda pkt:pkt.code not in [EAP.SUCCESS, EAP.FAILURE]) + fields_desc = [ + ByteEnumField("code", 4, eap_codes), + ByteField("id", 0), + ShortField("len", None), + ConditionalField(ByteEnumField("type", 0, eap_types), + lambda pkt:pkt.code not in [ + EAP.SUCCESS, EAP.FAILURE]), + ConditionalField(ByteEnumField("desired_auth_type", 0, eap_types), + lambda pkt:pkt.code == EAP.RESPONSE and pkt.type == 3), + ConditionalField( + StrLenField("identity", '', length_from=lambda pkt: pkt.len - 5), + lambda pkt: pkt.code == EAP.RESPONSE and hasattr(pkt, 'type') and pkt.type == 1) + ] + + #________________________________________________________________________ + # + # EAP codes + # http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-1 + #________________________________________________________________________ + # - ] - REQUEST = 1 RESPONSE = 2 SUCCESS = 3 FAILURE = 4 - TYPE_ID = 1 - TYPE_MD5 = 4 + INITIATE = 5 + FINISH = 6 + def answers(self, other): - if isinstance(other,EAP): + if isinstance(other, EAP): if self.code == self.REQUEST: return 0 elif self.code == self.RESPONSE: - if ( (other.code == self.REQUEST) and - (other.type == self.type) ): + if ((other.code == self.REQUEST) and + (other.type == self.type)): return 1 elif other.code == self.RESPONSE: return 1 return 0 - + def post_build(self, p, pay): if self.len is None: - l = len(p)+len(pay) - p = p[:2]+chr((l>>8)&0xff)+chr(l&0xff)+p[4:] - return p+pay - + l = len(p) + len(pay) + p = p[:2] + chr((l >> 8) & 0xff) + chr(l & 0xff) + p[4:] + return p + pay + + +class EAP_TLS(Packet): + + """ + RFC 5216 - "The EAP-TLS Authentication Protocol" + """ + + name = "EAP-TLS" + fields_desc = [ + BitField('L', 0, 1), + BitField('M', 0, 1), + BitField('S', 0, 1), + BitField('reserved', 0, 5), + ConditionalField( + IntField('tls_message_len', 0), lambda pkt: pkt.L == 1), + ConditionalField( + StrLenField('tls_data', '', length_from=lambda pkt: pkt.tls_message_len), lambda pkt: pkt.L == 1) + ] + + +class EAP_FAST(Packet): + + """ + RFC 4851 - "The Flexible Authentication via Secure Tunneling + Extensible Authentication Protocol Method (EAP-FAST)" + """ + + name = "EAP-FAST" + fields_desc = [ + BitField('L', 0, 1), + BitField('M', 0, 1), + BitField('S', 0, 1), + BitField('reserved', 0, 2), + BitField('version', 0, 3), + ConditionalField(IntField('message_len', 0), lambda pkt: pkt.L == 1), + ConditionalField( + StrLenField('data', '', length_from=lambda pkt: pkt.message_len), lambda pkt: pkt.L == 1) + ] + + class ARP(Packet): name = "ARP" @@ -416,6 +616,8 @@ bind_layers( GRE, GRErouting, { "routing_present" : 1 } ) bind_layers( GRErouting, conf.raw_layer,{ "address_family" : 0, "SRE_len" : 0 }) bind_layers( GRErouting, GRErouting, { } ) bind_layers( EAPOL, EAP, type=0) +bind_layers(EAP, EAP_TLS, type=13) +bind_layers(EAP, EAP_FAST, type=43) bind_layers( LLC, STP, dsap=66, ssap=66, ctrl=3) bind_layers( LLC, SNAP, dsap=170, ssap=170, ctrl=3) bind_layers( SNAP, Dot1Q, code=33024) diff --git a/test/regression.uts b/test/regression.uts index baee093ae1ad4cff7e4e77a70ba0489d10a44110..05a94c2a0a5d6ac813d1d5b6d6b538c9362c9be7 100644 --- a/test/regression.uts +++ b/test/regression.uts @@ -4850,3 +4850,150 @@ ff02::%lo0/32 ::1 UC - assert(check_mandatory_ipv6_routes(routes)) test_netbsd_7_0() + + +############ +############ + +########### EAPOL Class ###################################### ++ EAPOL class test + += EAPOL - Basic Instantiation +str(EAPOL()) == '\x01\x00\x00\x00' + += EAPOL - Instantiation with specific values +str(EAPOL(version = 3, type = 5)) == '\x03\x05\x00\x00' + += EAPOL - Dissection (1) +s = '\x03\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' +eapol = EAPOL(s) +eapol.version == 3 +eapol.type == 1 +eapol.len = 0 + += EAPOL - Dissection (2) +s = '\x03\x00\x00\x05\x01\x01\x00\x05\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' +eapol = EAPOL(s) +eapol.version == 3 +eapol.type == 0 +eapol.len == 5 + += EAPOL - Dissection (3) +s = '\x03\x00\x00\x0e\x02\x01\x00\x0e\x01anonymous\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' +eapol = EAPOL(s) +eapol.version == 3 +eapol.type == 0 +eapol.len == 14 + += EAPOL - Dissection (4) +req = EAPOL('\x03\x00\x00\x05\x01\x01\x00\x05\x01') +ans = EAPOL('\x03\x00\x00\x0e\x02\x01\x00\x0e\x01anonymous') +ans.answers(req) + += EAPOL - Dissection (5) +s = '\x02\x00\x00\x06\x01\x01\x00\x06\r ' +eapol = EAPOL(s) +eapol.version == 2 +eapol.type == 0 +eapol.len == 6 +eapol.haslayer(EAP_TLS) + += EAPOL - Dissection (6) +s = '\x03\x00\x00<\x02\x9e\x00<+\x01\x16\x03\x01\x001\x01\x00\x00-\x03\x01dr1\x93ZS\x0en\xad\x1f\xbaH\xbb\xfe6\xe6\xd0\xcb\xec\xd7\xc0\xd7\xb9\xa5\xc9\x0c\xfd\x98o\xa7T \x00\x00\x04\x004\x00\x00\x01\x00\x00\x00' +eapol = EAPOL(s) +eapol.version == 3 +eapol.type == 0 +eapol.len == 60 +eapol.haslayer(EAP_FAST) + + + +########## EAP Class ###################################### ++ EAP class test + += EAP - Basic Instantiation +str(EAP()) == '\x04\x00\x00\x04' + += EAP - Instantiation with specific values +str(EAP(code = 1, id = 1, len = 5, type = 1)) == '\x01\x01\x00\x05\x01' + += EAP - Dissection (1) +s = '\x01\x01\x00\x05\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' +eap = EAP(s) +eap.code == 1 +eap.id == 1 +eap.len == 5 +hasattr(eap, "type") +eap.type == 1 + += EAP - Dissection (2) +s = '\x02\x01\x00\x0e\x01anonymous\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' +eap = EAP(s) +eap.code == 2 +eap.id == 1 +eap.len == 14 +eap.type == 1 +hasattr(eap, 'identity') +eap.identity == 'anonymous' + += EAP - Dissection (3) +s = '\x01\x01\x00\x06\r ' +eap = EAP(s) +eap.code == 1 +eap.id == 1 +eap.len == 6 +eap.type == 13 +eap.haslayer(EAP_TLS) +eap[EAP_TLS].L == 0 +eap[EAP_TLS].M == 0 +eap[EAP_TLS].S == 1 + += EAP - Dissection (4) +s = '\x02\x01\x00\xd1\r\x00\x16\x03\x01\x00\xc6\x01\x00\x00\xc2\x03\x01UK\x02\xdf\x1e\xde5\xab\xfa[\x15\xef\xbe\xa2\xe4`\xc6g\xb9\xa8\xaa%vAs\xb2\x1cXt\x1c0\xb7\x00\x00P\xc0\x14\xc0\n\x009\x008\x00\x88\x00\x87\xc0\x0f\xc0\x05\x005\x00\x84\xc0\x12\xc0\x08\x00\x16\x00\x13\xc0\r\xc0\x03\x00\n\xc0\x13\xc0\t\x003\x002\x00\x9a\x00\x99\x00E\x00D\xc0\x0e\xc0\x04\x00/\x00\x96\x00A\xc0\x11\xc0\x07\xc0\x0c\xc0\x02\x00\x05\x00\x04\x00\x15\x00\x12\x00\t\x00\xff\x01\x00\x00I\x00\x0b\x00\x04\x03\x00\x01\x02\x00\n\x004\x002\x00\x0e\x00\r\x00\x19\x00\x0b\x00\x0c\x00\x18\x00\t\x00\n\x00\x16\x00\x17\x00\x08\x00\x06\x00\x07\x00\x14\x00\x15\x00\x04\x00\x05\x00\x12\x00\x13\x00\x01\x00\x02\x00\x03\x00\x0f\x00\x10\x00\x11\x00#\x00\x00\x00\x0f\x00\x01\x01' +eap = EAP(s) +eap.code == 2 +eap.id == 1 +eap.len == 209 +eap.type == 13 +eap.haslayer(EAP_TLS) +eap[EAP_TLS].L == 0 +eap[EAP_TLS].M == 0 +eap[EAP_TLS].S == 0 + += EAP - Dissection (5) +s = '\x02\x9e\x00<+\x01\x16\x03\x01\x001\x01\x00\x00-\x03\x01dr1\x93ZS\x0en\xad\x1f\xbaH\xbb\xfe6\xe6\xd0\xcb\xec\xd7\xc0\xd7\xb9\xa5\xc9\x0c\xfd\x98o\xa7T \x00\x00\x04\x004\x00\x00\x01\x00\x00\x00' +eap = EAP(s) +eap.code == 2 +eap.id == 158 +eap.len == 60 +eap.type == 43 +eap.haslayer(EAP_FAST) +eap[EAP_FAST].L == 0 +eap[EAP_FAST].M == 0 +eap[EAP_FAST].S == 0 +eap[EAP_FAST].version == 1 + += EAP - Dissection (6) +s = '\x02\x9f\x01L+\x01\x16\x03\x01\x01\x06\x10\x00\x01\x02\x01\x00Y\xc9\x8a\tcw\t\xdcbU\xfd\x035\xcd\x1a\t\x10f&[(9\xf6\x88W`\xc6\x0f\xb3\x84\x15\x19\xf5\tk\xbd\x8fp&0\xb0\xa4B\x85\x0c<:s\xf2zT\xc3\xbd\x8a\xe4D{m\xe7\x97\xfe>\xda\x14\xb8T1{\xd7H\x9c\xa6\xcb\xe3,u\xdf\xe0\x82\xe5R\x1e<\xe5\x03}\xeb\x98\xe2\xf7\x8d3\xc6\x83\xac"\x8f\xd7\x12\xe5{:"\x84A\xd9\x14\xc2cZF\xd4\t\xab\xdar\xc7\xe0\x0e\x00o\xce\x05g\xdc?\xcc\xf7\xe83\x83E\xb3>\xe8<3-QB\xfd$C/\x1be\xcf\x03\xd6Q4\xbe\\h\xba)<\x99N\x89\xd9\xb1\xfa!\xd7a\xef\xa3\xd3o\xed8Uz\xb5k\xb0`\xfeC\xbc\xb3aS,d\xe6\xdc\x13\xa4A\x1e\x9b\r{\xd6s \xd0cQ\x95y\xc8\x1d\xc3\xd9\x87\xf2=\x81\x96q~\x99E\xc3\x97\xa8px\xe2\xc7\x92\xeb\xff/v\x84\x1e\xfb\x00\x95#\xba\xfb\xd88h\x90K\xa7\xbd9d\xb4\xf2\xf2\x14\x02vtW\xaa\xadY\x14\x03\x01\x00\x01\x01\x16\x03\x01\x000\x97\xc5l\xd6\xef\xffcM\x81\x90Q\x96\xf6\xfeX1\xf7\xfc\x84\xc6\xa0\xf6Z\xcd\xb6\xe1\xd4\xdb\x88\xf9t%Q!\xe7,~#2G-\xdf\x83\xbf\x86Q\xa2$' +eap = EAP(s) +eap.code == 2 +eap.id == 159 +eap.len == 332 +eap.type == 43 +eap.haslayer(EAP_FAST) +eap[EAP_FAST].L == 0 +eap[EAP_FAST].M == 0 +eap[EAP_FAST].S == 0 +eap[EAP_FAST].version == 1 + += EAP - Dissection (7) +s = '\x02\xf1\x00\x06\x03+' +eap = EAP(s) +eap.code == 2 +eap.id == 241 +eap.len == 6 +eap.type == 3 +hasattr(eap, 'desired_auth_type') +eap.desired_auth_type == 43 + +