blob: c51f111d781f940ff9bacf76e05f102fbb15879f [file] [log] [blame]
A R Karthick05d9b5f2016-06-08 11:53:54 -07001#
Chetan Gaonkercfcce782016-05-10 10:10:42 -07002# Copyright 2016-present Ciena Corporation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
A R Karthick05d9b5f2016-06-08 11:53:54 -07007#
Chetan Gaonkercfcce782016-05-10 10:10:42 -07008# http://www.apache.org/licenses/LICENSE-2.0
A R Karthick05d9b5f2016-06-08 11:53:54 -07009#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070010# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
A R Karthicka2e53d62016-02-19 17:38:30 -080016#### Authentication parameters
Chetan Gaonker35cb16f2016-03-02 03:05:28 -080017from scapy.all import *
A R Karthickaa10a202016-08-15 15:06:21 -070018from scapy_ssl_tls.ssl_tls import *
A R Karthicka2e53d62016-02-19 17:38:30 -080019from socket import *
20from struct import *
A R Karthicka2e53d62016-02-19 17:38:30 -080021import sys
22from nose.tools import assert_equal, assert_not_equal, assert_raises, assert_true
23
24USER = "raduser"
25PASS = "radpass"
26WRONG_USER = "XXXX"
27WRONG_PASS = "XXXX"
28NO_USER = ""
29NO_PASS = ""
30DEV = "tap0"
31ETHERTYPE_PAE = 0x888e
32PAE_GROUP_ADDR = "\xff\xff\xff\xff\xff\xff"
33EAPOL_VERSION = 1
34EAPOL_EAPPACKET = 0
35EAPOL_START = 1
36EAPOL_LOGOFF = 2
37EAPOL_KEY = 3
38EAPOL_ASF = 4
39EAP_REQUEST = 1
40EAP_RESPONSE = 2
41EAP_SUCCESS = 3
42EAP_FAILURE = 4
43EAP_TYPE_ID = 1
44EAP_TYPE_MD5 = 4
45EAP_TYPE_MSCHAP = 26
46EAP_TYPE_TLS = 13
47cCertMsg = '\x0b\x00\x00\x03\x00\x00\x00'
48TLS_LENGTH_INCLUDED = 0x80
A R Karthickaa10a202016-08-15 15:06:21 -070049TLS_MORE_FRAGMENTS = 0x40
A R Karthicka2e53d62016-02-19 17:38:30 -080050
A R Karthicka2e53d62016-02-19 17:38:30 -080051class EapolPacket(object):
A R Karthick05d9b5f2016-06-08 11:53:54 -070052
A R Karthicka2e53d62016-02-19 17:38:30 -080053 def __init__(self, intf = 'veth0'):
54 self.intf = intf
55 self.s = None
A R Karthickaa10a202016-08-15 15:06:21 -070056 self.max_recv_size = 1600
A R Karthicka2e53d62016-02-19 17:38:30 -080057
58 def setup(self):
59 self.s = socket(AF_PACKET, SOCK_RAW, htons(ETHERTYPE_PAE))
60 self.s.bind((self.intf, ETHERTYPE_PAE))
61 self.mymac = self.s.getsockname()[4]
Chetan Gaonker35cb16f2016-03-02 03:05:28 -080062 self.llheader = Ether(dst = PAE_GROUP_ADDR, src = self.mymac, type = ETHERTYPE_PAE)
Chetan Gaonker5b366302016-03-21 16:18:21 -070063 self.recv_sock = L2Socket(iface = self.intf, type = ETHERTYPE_PAE)
A R Karthicka2e53d62016-02-19 17:38:30 -080064
65 def cleanup(self):
66 if self.s is not None:
67 self.s.close()
68 self.s = None
A R Karthick05d9b5f2016-06-08 11:53:54 -070069
A R Karthicka2e53d62016-02-19 17:38:30 -080070 def eapol(self, req_type, payload=""):
Chetan Gaonker35cb16f2016-03-02 03:05:28 -080071 return EAPOL(version = EAPOL_VERSION, type = req_type)/payload
A R Karthicka2e53d62016-02-19 17:38:30 -080072
73 def eap(self, code, pkt_id, req_type=0, data=""):
Chetan Gaonker35cb16f2016-03-02 03:05:28 -080074 return EAP(code = code, id = pkt_id, type = req_type)/data
A R Karthicka2e53d62016-02-19 17:38:30 -080075
A R Karthickaa10a202016-08-15 15:06:21 -070076 def eapFragmentSend(self, code, pkt_id, flags = TLS_LENGTH_INCLUDED, payload = "", fragsize = 1024):
77 req_type = EAP_TYPE_TLS
78 if code in [ EAP_SUCCESS, EAP_FAILURE ]:
79 data = pack("!BBH", code, pkt_id, 4)
80 self.eapol_send(EAPOL_EAPPACKET, data)
81 return True
82
83 if len(payload) <= fragsize:
84 if flags & TLS_LENGTH_INCLUDED:
85 flags_dlen = pack("!BL", flags, len(payload))
86 data = pack("!BBHB", code, pkt_id, 5 + len(flags_dlen) + len(payload), req_type) \
87 + flags_dlen + payload
88 self.eapol_send(EAPOL_EAPPACKET, data)
89 return True
90 flags_str = pack("!B", flags)
91 data = pack("!BBHB", code, pkt_id, 5+len(flags_str)+len(payload), req_type) + flags_str + payload
92 self.eapol_send(EAPOL_EAPPACKET, data)
93 return True
94
95 fragments = []
96 data = payload[:]
97 frag = 0
98 def eapol_frag_cb(pkt):
99 r = str(pkt)
100 tls_data = r[self.TLS_OFFSET:]
101 frag_data = fragments[frag]
102 ##change packet id in response to match request
103 eap_payload = frag_data[:1] + pack("!B", pkt[EAP].id) + frag_data[2:]
104 self.eapol_send(EAPOL_EAPPACKET, eap_payload)
105
106 while len(data) > 0:
107 data_frag = data[:fragsize]
108 data = data[fragsize:]
109 if frag == 0:
110 ##first frag, include the total length
111 flags_dlen = pack("!BL", TLS_LENGTH_INCLUDED | TLS_MORE_FRAGMENTS, len(payload))
112 fragments.append(pack("!BBHB", code, pkt_id, 5 + len(flags_dlen) + len(data_frag), req_type) \
113 + flags_dlen + data_frag)
114 else:
115 if len(data) > 0:
116 flags = TLS_MORE_FRAGMENTS
117 else:
118 flags = 0
119 flags_str = pack("!B", flags)
120 fragments.append(pack("!BBHB", code, pkt_id, 5+len(flags_str)+len(data_frag), req_type) + \
121 flags_str + data_frag)
122 frag += 1
123
124 frag = 0
125 self.eapol_send(EAPOL_EAPPACKET, fragments[frag])
126 for frag in range(len(fragments)-1):
127 frag += 1
128 r = self.eapol_scapy_recv(cb = eapol_frag_cb,
129 lfilter = lambda pkt: EAP in pkt and pkt[EAP].type == EAP_TYPE_TLS and \
130 pkt[EAP].code == EAP.REQUEST)
131
132 return True
133
A R Karthicka2e53d62016-02-19 17:38:30 -0800134 def eapTLS(self, code, pkt_id, flags = TLS_LENGTH_INCLUDED, data=""):
135 req_type = EAP_TYPE_TLS
136 if code in [EAP_SUCCESS, EAP_FAILURE]:
137 return pack("!BBH", code, pkt_id, 4)
138 else:
139 if flags & TLS_LENGTH_INCLUDED:
140 flags_dlen = pack("!BL", flags, len(data))
141 return pack("!BBHB", code, pkt_id, 5+len(flags_dlen)+len(data), req_type) + flags_dlen + data
142 flags_str = pack("!B", flags)
143 return pack("!BBHB", code, pkt_id, 5+len(flags_str)+len(data), req_type) + flags_str + data
144
A R Karthickaa10a202016-08-15 15:06:21 -0700145 def eapTLSFragment(self, code, pkt_id, frag, data="", data_len = 0):
146 req_type = EAP_TYPE_TLS
147 if frag == 0:
148 flags = TLS_LENGTH_INCLUDED | TLS_MORE_FRAGMENTS
149 elif frag > 0:
150 flags = TLS_MORE_FRAGMENTS
151 else:
152 #last fragment
153 flags = 0
154 if data_len == 0:
155 data_len = len(data)
156 if flags & TLS_LENGTH_INCLUDED:
157 flags_dlen = pack("!BL", flags, data_len)
158 return pack("!BBHB", code, pkt_id, 5+len(flags_dlen)+len(data), req_type) + flags_dlen + data
159 flags_str = pack("!B", flags)
160 return pack("!BBHB", code, pkt_id, 5+len(flags_str)+len(data), req_type) + flags_str + data
161
A R Karthicka2e53d62016-02-19 17:38:30 -0800162 def eapol_send(self, eapol_type, eap_payload):
Chetan Gaonker35cb16f2016-03-02 03:05:28 -0800163 return sendp(self.llheader/self.eapol(eapol_type, eap_payload), iface=self.intf)
A R Karthicka2e53d62016-02-19 17:38:30 -0800164
165 def eapol_recv(self):
A R Karthickaa10a202016-08-15 15:06:21 -0700166 p = self.s.recv(self.max_recv_size)[14:]
A R Karthicka2e53d62016-02-19 17:38:30 -0800167 vers,pkt_type,eapollen = unpack("!BBH",p[:4])
168 print "Version %d, type %d, len %d" %(vers, pkt_type, eapollen)
169 assert_equal(pkt_type, EAPOL_EAPPACKET)
170 return p[4:]
171
A R Karthick05d9b5f2016-06-08 11:53:54 -0700172 def eapol_scapy_recv(self, cb = None, lfilter = None, count = 1, timeout = 5):
Chetan Gaonker5b366302016-03-21 16:18:21 -0700173 def eapol_default_cb(pkt): pass
174 if cb is None:
175 cb = eapol_default_cb
A R Karthick05d9b5f2016-06-08 11:53:54 -0700176 return sniff(prn = cb, lfilter = lfilter, count = count, timeout = timeout, opened_socket = self.recv_sock)
Chetan Gaonker5b366302016-03-21 16:18:21 -0700177
A R Karthicka2e53d62016-02-19 17:38:30 -0800178 def eapol_start(self):
179 eap_payload = self.eap(EAPOL_START, 2)
180 return self.eapol_send(EAPOL_START, eap_payload)
181
A R Karthick307483c2016-06-06 17:05:19 -0700182 def eapol_logoff(self):
183 eap_payload = self.eap(EAPOL_LOGOFF, 2)
184 return self.eapol_send(EAPOL_LOGOFF, eap_payload)
185
A R Karthicka2e53d62016-02-19 17:38:30 -0800186 def eapol_id_req(self, pkt_id = 0, user = USER):
187 eap_payload = self.eap(EAP_RESPONSE, pkt_id, EAP_TYPE_ID, user)
188 return self.eapol_send(EAPOL_EAPPACKET, eap_payload)
189
Chetan Gaonker4a25e2b2016-03-04 14:45:15 -0800190 def eap_md5_challenge_recv(self,rad_pwd):
191 PASS = rad_pwd
192 print 'Inside EAP MD5 Challenge Exchange'
A R Karthickaa10a202016-08-15 15:06:21 -0700193 p = self.s.recv(self.max_recv_size)[14:]
Chetan Gaonker4a25e2b2016-03-04 14:45:15 -0800194 vers,pkt_type,eapollen = unpack("!BBH",p[:4])
195 print "EAPOL Version %d, type %d, len %d" %(vers, pkt_type, eapollen)
196 code, pkt_id, eaplen = unpack("!BBH", p[4:8])
197 print "EAP Code %d, id %d, len %d" %(code, pkt_id, eaplen)
198 assert_equal(code, EAP_REQUEST)
199 reqtype = unpack("!B", p[8:9])[0]
200 reqdata = p[9:4+eaplen]
201 print 'Request type is %d' %(reqtype)
202 assert_equal(reqtype, EAP_TYPE_MD5)
203 challenge=pack("!B",pkt_id)+PASS+reqdata[1:]
204 print "Generating md5 challenge for %s" % challenge
205 return (challenge,pkt_id)
206
207 def eap_Status(self):
208 print 'Inside EAP Status'
A R Karthickaa10a202016-08-15 15:06:21 -0700209 p = self.s.recv(self.max_recv_size)[14:]
Chetan Gaonker4a25e2b2016-03-04 14:45:15 -0800210 code, id, eaplen = unpack("!BBH", p[4:8])
211 return code
212