blob: 6b812dde04fae4df99e30b16836aab08cc841dac [file] [log] [blame]
Brian Waters13d96012017-12-08 16:53:31 -06001/*****************************************************************************************************
2 * Software License Agreement (BSD License)
3 * Author : Souheil Ben Ayed <souheil@tera.ics.keio.ac.jp>
4 *
5 * Copyright (c) 2009-2010, Souheil Ben Ayed, Teraoka Laboratory of Keio University, and the WIDE Project
6 * All rights reserved.
7 *
8 * Redistribution and use of this software in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Souheil Ben Ayed <souheil@tera.ics.keio.ac.jp>.
21 *
22 * 4. Neither the name of Souheil Ben Ayed, Teraoka Laboratory of Keio University or the WIDE Project nor the
23 * names of its contributors may be used to endorse or promote products
24 * derived from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' AND ANY
27 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
30 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *****************************************************************************************************/
37
38
39#include "eap_tls.h"
40
41int eap_tls_configure(char * configfile);
42int eap_tls_init(struct eap_state_machine *smd);
43int eap_tls_initPickUp(struct eap_state_machine *smd);
44int eap_tls_buildReq(struct eap_state_machine *smd, u8 eap_md5,
45 struct eap_packet * eapPacket);
46int eap_tls_getTimeout(struct eap_state_machine *smd, int * timeout);
47boolean eap_tls_check(struct eap_state_machine *smd,
48 struct eap_packet *eapRespData);
49int eap_tls_process(struct eap_state_machine *smd,
50 struct eap_packet *eapRespData);
51boolean eap_tls_isDone(struct eap_state_machine *smd);
52int eap_tls_getKey(struct eap_state_machine *smd, u8** msk, int * msklen, u8** emsk, int * emsklen);
53void eap_tls_unregister(void);
54void eap_tls_free(void * data);
55
56REGISTER_METHOD("eap_tls", "eap_tls_configure", "eap_tls_init", "eap_tls_initPickUp", "eap_tls_buildReq", "eap_tls_getTimeout", "eap_tls_check", "eap_tls_process", "eap_tls_isDone", "eap_tls_getKey", "eap_tls_unregister", "eap_tls_free")
57;
58
59int eap_tls_configure(char * configfile)
60{
61 int ret;
62 extern FILE * eaptlsin;
63
64 if (configfile)
65 {
66 tls_global_conf.conffile = configfile;
67 }
68 tls_global_conf.certfile = NULL;
69 tls_global_conf.keyfile = NULL;
70 tls_global_conf.cafile = NULL;
71 tls_global_conf.crlfile = NULL;
72 tls_global_conf.check_cert_cn_username = FALSE;
73
74 /*Parse EAP TLS configuration file */
75 eaptlsin = fopen(tls_global_conf.conffile, "r");
76 if (!eaptlsin)
77 {
78 TRACE_DEBUG(INFO,"%s[EAP TLS plugin] Unable to open configuration file %s for reading: %s",DIAMEAP_EXTENSION, tls_global_conf.conffile, strerror(errno));
79 return errno;
80 }
81
82 /* call yacc parser */
83 CHECK_FCT(eaptlsparse(&tls_global_conf));
84
85
86 tls_global_conf.max_size = 64*1024 /* As per RFC 5216 recommendation */;
87
88 /* Initializing GnuTLS library */
89 ret = diameap_tls_init(&tls_global_conf);
90
91 return ret;
92}
93
94int eap_tls_init(struct eap_state_machine *smd)
95{
96 int ret;
97 struct tls_data *data = NULL;
98 CHECK_MALLOC(data = malloc(sizeof(struct tls_data)));
99 memset(data, 0, sizeof(struct tls_data));
100 CHECK_FCT(diameap_tls_initialize(data));
101 ret = diameap_tls_init_session(&tls_global_conf, data);
102
103 smd->methodData = (struct tls_data*) data;
104 if (ret < 0)
105 {
106 return ret;
107 }
108 return 0;
109}
110
111int eap_tls_initPickUp(struct eap_state_machine *smd)
112{
113 return 0;
114}
115
116int eap_tls_buildReq(struct eap_state_machine *smd, u8 id,
117 struct eap_packet * eapPacket)
118{
119 struct tls_data * data;
120 data = (struct tls_data *) smd->methodData;
121
122 if (data->more_toreceive == TRUE)
123 {
124 CHECK_FCT(diameap_eap_tls_buildReq_ack(id,eapPacket));
125 return 0;
126 }
127
128 if (data->state == START)
129 {
130 CHECK_FCT(diameap_eap_tls_buildReq_start(id,eapPacket));
131 return 0;
132 }
133
134 if (data->state == CONTINUE)
135 {
136 diameap_eap_tls_buildReq_data(data, id, eapPacket);
137
138 smd->methodData = (struct tls_data*) data;
139 return 0;
140 }
141
142 return 0;
143}
144
145int eap_tls_getTimeout(struct eap_state_machine *smd, int * timeout)
146{
147 return 0;
148}
149
150boolean eap_tls_check(struct eap_state_machine *smd,
151 struct eap_packet *eapRespData)
152{
153 eap_type type;
154 if(diameap_eap_get_type(eapRespData,&type)!=0){
155 goto cf;
156 }
157 if (type == TYPE_EAP_TLS)
158 {
159 return TRUE;
160 }
161cf:
162 TRACE_DEBUG(INFO,"%s[EAP TLS plugin] EAP-TLS check failed: Received EAP packet with different EAP-Type (Type = %d)",DIAMEAP_EXTENSION, type);
163 return FALSE;
164}
165
166int eap_tls_process(struct eap_state_machine *smd,
167 struct eap_packet *eapRespData)
168{
169 struct tls_data * data;
170 data = (struct tls_data *) smd->methodData;
171 struct tls_msg tlsmsg;
172 CHECK_FCT(diameap_eap_tls_parse(&tlsmsg,eapRespData));
173
174 if ((tlsmsg.datalength == 0))
175 {
176 if (data->more_tosend_length > 0)
177 {
178 //ACK and more to send
179 return 0;
180 }
181 else
182 {
183 //Success
184 if (data->handshake == TRUE)
185 {
186 data->state = SUCCESS;
187 smd->user.success = TRUE;
188
189 if(tls_global_conf.check_cert_cn_username == TRUE){
190 unsigned int list_size;
191 const gnutls_datum_t * list = gnutls_certificate_get_peers (data->session, &list_size);
192 if(list_size<1){
193 goto failure;
194 }
195
196 gnutls_x509_crt_t cert;
197
198 CHECK_GNUTLS_DO(gnutls_x509_crt_init(&cert),{
199 TRACE_DEBUG(NONE,"%s[EAP TLS plugin] [GnuTLS] error in initialization crt init",DIAMEAP_EXTENSION);
200 goto failure;});
201
202 CHECK_GNUTLS_DO(gnutls_x509_crt_import(cert, &list[0], GNUTLS_X509_FMT_DER), {
203 TRACE_DEBUG(NONE,"%s[EAP TLS plugin] [GnuTLS] error parsing certificate",DIAMEAP_EXTENSION);
204 goto failure;});
205
206 void * buff;
207 size_t size_buffer;
208 int ret;
209 ret = gnutls_x509_crt_get_dn_by_oid(cert,GNUTLS_OID_X520_COMMON_NAME,0,0,NULL,&size_buffer);
210 if( ret != GNUTLS_E_SHORT_MEMORY_BUFFER){
211 CHECK_GNUTLS_DO(ret,{
212 TRACE_DEBUG(NONE,"%s[EAP TLS plugin] [GnuTLS] error get dn by oid",DIAMEAP_EXTENSION);
213 goto failure;});
214 }
215
216 CHECK_MALLOC_DO(buff=malloc(size_buffer), goto failure);
217
218 CHECK_GNUTLS_DO(gnutls_x509_crt_get_dn_by_oid(cert,GNUTLS_OID_X520_COMMON_NAME,0,0,buff,&size_buffer),{
219 TRACE_DEBUG(NONE,"%s[EAP TLS plugin] [GnuTLS] error get dn by oid",DIAMEAP_EXTENSION);
220 goto failure;});
221
222 if(strncmp((char *)smd->user.userid,buff,smd->user.useridLength)!=0){
223 goto failure;
224 }
225
226 gnutls_x509_crt_deinit(cert);
227 goto next;
228
229 failure:
230 TRACE_DEBUG(NONE,"%s[EAP TLS plugin] Checking failed. certificate's CN does not match User_Name AVP value.",DIAMEAP_EXTENSION);
231 data->state = FAILURE;
232 smd->user.success = FALSE;
233 gnutls_x509_crt_deinit(cert);
234 }
235
236 next:
237 smd->methodData = (struct tls_data*) data;
238 return 0;
239
240 }
241
242 return 0;
243 }
244
245 }
246
247 if (data->more_toreceive == TRUE)
248 {
249 //reassemble received fragment to TLS Response
250 CHECK_FCT(diameap_tls_reassemble(&data->tlsResp,tlsmsg));
251 }
252 else
253 {
254 //receive the first fragment or a complete TLS message
255 CHECK_FCT(diameap_tls_copy(&data->tlsResp,tlsmsg));
256 }
257
258 if (tlsmsg.flags & TLS_FLAG_MORE)
259 {
260 data->more_toreceive = TRUE;
261 smd->methodData = (struct tls_data*) data;
262 return 0;
263 }
264 else
265 {
266 //last fragment received
267 data->more_toreceive = FALSE;
268 }
269 data->state = CONTINUE;
270 diameap_tls_process_receive(data);
271
272 if (data->state == SUCCESS)
273 {
274 smd->user.success = TRUE;
275 }
276 smd->methodData = (struct tls_data*) data;
277 return 0;
278}
279
280boolean eap_tls_isDone(struct eap_state_machine *smd)
281{
282 struct tls_data * data;
283 data = (struct tls_data *) smd->methodData;
284 if (data->state == CONTINUE || data->state == START)
285 {
286 return FALSE;
287 }
288 return TRUE;
289}
290
291int eap_tls_getKey(struct eap_state_machine *smd, u8 ** msk, int *msklen, u8 ** emsk, int *emsklen)
292{
293 struct tls_data * data;
294 int len = emsk ? 128 : 64;
295 data = (struct tls_data *) smd->methodData;
296 *msk = malloc(len);
297 if (gnutls_prf(data->session, strlen("client EAP encryption"),
298 "client EAP encryption", 0, 0, NULL, len, (char *) *msk)
299 != GNUTLS_E_SUCCESS)
300 {
301 free(*msk);
302 *msk = NULL;
303 *msklen = 0;
304 return 1;
305 }
306 else
307 {
308 *msklen = 64;
309 }
310 if (emsk) {
311 *emsk = malloc(64);
312 memcpy(*emsk, (*msk)+64, 64);
313 memset((*msk)+64, 0, 64);
314 *emsklen = 64;
315 }
316
317 return 0;
318}
319
320void eap_tls_unregister(void)
321{
322 //
323}
324
325void eap_tls_free(void * mdata)
326{
327 struct tls_data *data;
328 data = (struct tls_data*) mdata;
329 gnutls_deinit(data->session);
330 if(data->tlsReq.data){
331 free(data->tlsReq.data);
332 data->tlsReq.data=NULL;
333 }
334 if(data->tlsResp.data){
335 free(data->tlsResp.data);
336 data->tlsResp.data=NULL;
337 }
338 free(data);
339 data=NULL;
340}
341
342//send TLS ACK Request (empty TLS msg)
343int diameap_eap_tls_buildReq_ack(u8 id, struct eap_packet * eapPacket)
344{
345 u8* payload;
346 struct tls_msg tlsmsg;
347 int len;
348 CHECK_FCT(diameap_tls_new(&tlsmsg));
349 CHECK_FCT(diameap_tls_new_tls_packet(&payload,&len,tlsmsg));
350 CHECK_FCT(diameap_eap_new(EAP_REQUEST,id,TYPE_EAP_TLS,payload,len,eapPacket));
351 return 0;
352}
353
354// parse EAP TLS msg
355int diameap_eap_tls_parse(struct tls_msg * tlsmsg, struct eap_packet *eapPacket)
356{
357 u8 *datatls;
358 int len;
359
360 //initialize a new empty EAP TLS msg
361 diameap_tls_new(tlsmsg);
362 //retrieve the data field from EAP Packet
363 diameap_eap_get_data(eapPacket, &datatls, &len);
364 //parse EAP TLS msg
365 diameap_tls_parse(datatls, len, tlsmsg);
366 return 0;
367}
368
369int diameap_eap_tls_buildReq_start(u8 id, struct eap_packet * eapPacket)
370{
371 u8* payload;
372 struct tls_msg tlsmsg;
373 int len;
374 CHECK_FCT(diameap_tls_new(&tlsmsg));
375 CHECK_FCT(diameap_tls_set_flags(&tlsmsg,TLS_FLAG_START));
376 CHECK_FCT(diameap_tls_new_tls_packet(&payload,&len,tlsmsg));
377 CHECK_FCT(diameap_eap_new(EAP_REQUEST,id,TYPE_EAP_TLS,payload,len,eapPacket));
378 return 0;
379}
380
381int diameap_eap_tls_buildReq_data(struct tls_data * data, int id,
382 struct eap_packet * eapPacket)
383{
384 struct tls_msg tlsmsg;
385 u8* datatosend;
386 u8 * eaptls_data;
387 int length = 0;
388
389 diameap_tls_new(&tlsmsg);
390
391 if (data->more_tosend_length == 0)
392 {
393 //First fragment of message or the only fragment of message
394 data->more_tosend_length = data->tlsReq.datalength;
395 }
396 if (data->more_tosend_length > tls_global_conf.max_size)
397 {
398 //New fragment of message. Is not the last fragment.
399 length = tls_global_conf.max_size;
400 CHECK_FCT(diameap_tls_set_flags(&tlsmsg,TLS_FLAG_MORE));
401 if (data->more_tosend_length == data->tlsReq.datalength)
402 {
403 //The first fragment of message
404 CHECK_FCT(diameap_tls_set_message_length(&tlsmsg,data->tlsReq.datalength));//set L flag and length value
405 }
406 }
407 else
408 {
409 //The last fragment or the only fragment.
410 length = data->more_tosend_length;
411 }
412
413 datatosend = malloc(sizeof(u8) * length);
414 U8COPY(datatosend,0,length,data->tlsReq.data+(data->tlsReq.datalength-data->more_tosend_length));
415 data->more_tosend_length -= length;
416 CHECK_FCT(diameap_tls_set_data(&tlsmsg,datatosend,length));
417
418 CHECK_FCT(diameap_tls_new_tls_packet(&eaptls_data,&length,tlsmsg));
419 CHECK_FCT(diameap_eap_new(EAP_REQUEST,id,TYPE_EAP_TLS,eaptls_data,length,eapPacket));
420
421 if (data->more_tosend_length == 0)
422 {
423 diameap_tls_new(&data->tlsReq);
424 }
425 return 0;
426}