blob: e77a65cfb1b47ac8b0bc8fb14d0f06221ab07c5e [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 "diameap_tls.h"
40
41//GCRY_THREAD_OPTION_PTHREAD_IMPL;
42
43int diameap_tls_init(struct tls_config * tls_conf)
44{
45 int ret;
46 ret = gnutls_global_init();
47 if (ret < 0)
48 {
49 gnutls_perror(ret);
50 }
51
52 gnutls_global_set_log_function(diameap_tls_log);
53 //gnutls_global_set_log_level(9);
54
55
56 if(tls_conf->cafile ==NULL){
57 fprintf(stderr,"[DiamEAP extension] [EAP TLS] Missing certification authority (CA) certificates. Please provide CA configuration directive.\n");
58 return EINVAL;
59 }
60 if( !tls_conf->certfile || !tls_conf->keyfile){
61 fprintf(stderr,"[DiamEAP extension] [EAP TLS] Missing private Key. Please provide Cred configuration directive.\n");
62 return EINVAL;
63 }
64
65 ret = gnutls_certificate_allocate_credentials(&tls_conf->cert_cred);
66
67 if (ret < 0)
68 {
69 gnutls_perror(ret);
70 return ret;
71 }
72
73 ret = gnutls_certificate_set_x509_trust_file(tls_conf->cert_cred,
74 tls_conf->cafile, GNUTLS_X509_FMT_PEM);
75 if (ret < 0)
76 {
77 gnutls_perror(ret);
78 return ret;
79 }
80 if (tls_conf->crlfile)
81 {
82 ret = gnutls_certificate_set_x509_crl_file(tls_conf->cert_cred,
83 tls_conf->crlfile, GNUTLS_X509_FMT_PEM);
84 if (ret < 0)
85 {
86 gnutls_perror(ret);
87 return ret;
88 }
89 }
90
91 ret = gnutls_certificate_set_x509_key_file(tls_conf->cert_cred,
92 tls_conf->certfile, tls_conf->keyfile, GNUTLS_X509_FMT_PEM);
93 if (ret < 0)
94 {
95 gnutls_perror(ret);
96 return ret;
97 }
98 return 0;
99}
100
101void diameap_tls_log(int lev, const char * text)
102{
103 u8 * msg;
104 if (text == NULL)
105 return;
106 msg = (u8 *) strdup(text);
107 int i;
108 for (i = 0; (G8(text+i) != '\n') && (G8(text+i) != '\0'); i++)
109 {
110 }
111 P8((msg+i),'\0');
112 fprintf(stderr, "[DiamEAP extension] [EAP TLS] GNUTLS log[%d] : %s\n", lev, msg);
113 free(msg);
114}
115
116int diameap_tls_init_session(struct tls_config * tls_conf,
117 struct tls_data * data)
118{
119 int ret;
120 ret = gnutls_init(&data->session, GNUTLS_SERVER);
121 if (ret < 0)
122 {
123 gnutls_perror(ret);
124 }
125 ret = gnutls_set_default_priority(data->session);
126 if (ret < 0)
127 {
128 gnutls_perror(ret);
129 }
130
131 ret = gnutls_credentials_set(data->session, GNUTLS_CRD_CERTIFICATE,
132 tls_conf->cert_cred);
133 if (ret < 0)
134 {
135 gnutls_perror(ret);
136 }
137
138 /* request client certificate if any.
139 */
140 gnutls_certificate_server_set_request(data->session, GNUTLS_CERT_REQUIRE); //GNUTLS_CERT_REQUEST);
141
142 gnutls_transport_set_pull_function(data->session, diameap_tls_receive);
143 gnutls_transport_set_push_function(data->session, diameap_tls_send);
144 gnutls_transport_set_ptr(data->session, (gnutls_transport_ptr_t) data);
145
146 /* starting version 2.12, this call is not needed */
147 //gnutls_transport_set_lowat(data->session, 0);
148
149 return ret;
150}
151
152ssize_t diameap_tls_receive(gnutls_transport_ptr_t ptr, void *buffer,
153 size_t length)
154{
155 struct tls_data * data = (struct tls_data *) ptr;
156 if (data->p_length == 0)
157 {
158 errno = EWOULDBLOCK;
159 return -1;
160 }
161 if (length > data->p_length)
162 {
163 length = data->p_length;
164 }
165 memcpy(buffer, data->tlsResp.data + (data->tlsResp.datalength
166 - data->p_length), length);
167 data->p_length -= length;
168
169 return length;
170}
171
172ssize_t diameap_tls_send(gnutls_transport_ptr_t ptr, const void *buffer,
173 size_t length)
174{
175 struct tls_data * data = (struct tls_data *) ptr;
176 data->tlsReq.data = realloc(data->tlsReq.data, data->tlsReq.datalength
177 + length);
178 U8COPY(data->tlsReq.data,data->tlsReq.datalength,length,(u8*)buffer);
179 data->tlsReq.datalength += length;
180
181 return length;
182}
183
184int diameap_tls_new(struct tls_msg * tlsmsg)
185{
186 if (!tlsmsg)
187 {
188 return EINVAL;
189 }
190 tlsmsg->flags = 0x00;
191 tlsmsg->length = 0;
192 tlsmsg->data = NULL;
193 tlsmsg->datalength = 0;
194 return 0;
195}
196
197int diameap_tls_get_flags(struct tls_msg tlsmsg, u8 * flags)
198{
199 *flags = tlsmsg.flags;
200 return 0;
201}
202
203int diameap_tls_set_flags(struct tls_msg * tlsmsg, u8 flags)
204{
205 if (!tlsmsg)
206 {
207 return EINVAL;
208 }
209 if ((flags & TLS_FLAG_LENGTH) == TLS_FLAG_LENGTH)
210 {
211 flags = flags ^ TLS_FLAG_LENGTH;
212 }
213 tlsmsg->flags = tlsmsg->flags | flags;
214 return 0;
215}
216
217int diameap_tls_get_message_length(struct tls_msg tlsmsg, u32 * length)
218{
219 if ((tlsmsg.flags & TLS_FLAG_LENGTH) == TLS_FLAG_LENGTH)
220 {
221 *length = tlsmsg.length;
222 }
223 else
224 {
225 *length = 0;
226 }
227 return 0;
228}
229
230int diameap_tls_set_message_length(struct tls_msg * tlsmsg, u32 length)
231{
232 if (!tlsmsg)
233 {
234 return EINVAL;
235 }
236 if (length > 0)
237 {
238 tlsmsg->length = length;
239 tlsmsg->flags = tlsmsg->flags | TLS_FLAG_LENGTH;
240 }
241 else
242 {
243 tlsmsg->length = 0;
244 if ((tlsmsg->flags & TLS_FLAG_LENGTH) == TLS_FLAG_LENGTH)
245 {
246 tlsmsg->flags = tlsmsg->flags ^ TLS_FLAG_LENGTH;
247 }
248 }
249 return 0;
250}
251
252int diameap_tls_get_data(struct tls_msg tlsmsg, u8** tls_data,
253 u32 * data_length)
254{
255 if (tlsmsg.datalength > 0)
256 {
257 *tls_data = malloc(sizeof(u8) * tlsmsg.datalength);
258 U8COPY(*tls_data,0,tlsmsg.datalength,tlsmsg.data);
259 *data_length = tlsmsg.datalength;
260 }
261 else
262 {
263 *tls_data = NULL;
264 *data_length = 0;
265 }
266 return 0;
267}
268
269int diameap_tls_set_data(struct tls_msg * tlsmsg, u8* tls_data, int data_length)
270{
271 if (!tlsmsg)
272 {
273 return EINVAL;
274 }
275 tlsmsg->data = malloc(sizeof(u8) * data_length);
276 U8COPY(tlsmsg->data,0,data_length,tls_data);
277 tlsmsg->datalength = data_length;
278 return 0;
279}
280
281/*
282 * data : returned data
283 * eaptls_data : the TLS_Data field
284 * length : the length of eaptls_data
285 * flags : combination of flags et set
286 */
287int diameap_tls_new_tls_packet(u8** data, int * len, struct tls_msg tlsmsg)
288{
289 int buflen, pos = 0;
290
291 buflen = 1;
292
293 if ((tlsmsg.flags & TLS_FLAG_LENGTH) == TLS_FLAG_LENGTH)
294 {
295 buflen += 4;
296 }
297
298 if (tlsmsg.datalength > 0)
299 {
300 buflen += tlsmsg.datalength;
301 }
302 *data = malloc(sizeof(u8) * buflen);
303 memset(*data, 0, sizeof(u8) * buflen);
304 P8(*data,tlsmsg.flags);
305 pos++;
306
307 if ((tlsmsg.flags & TLS_FLAG_LENGTH) == TLS_FLAG_LENGTH)
308 {
309 P32BIGE(*data+pos,tlsmsg.length);
310 pos += 4;
311 }
312 if (tlsmsg.data)
313 {
314 U8COPY(*data,pos,tlsmsg.datalength,tlsmsg.data);
315 }
316 *len = buflen;
317 return 0;
318}
319
320int diameap_set_tls(struct tls_msg * tlsmsg, u8 flags, u32 length,
321 u8 *tls_data, int data_length)
322{
323 diameap_tls_new(tlsmsg);
324 diameap_tls_set_flags(tlsmsg, flags);
325 diameap_tls_set_message_length(tlsmsg, length);
326 diameap_tls_set_data(tlsmsg, tls_data, data_length);
327 return 0;
328}
329
330int diameap_tls_parse(u8* data, int len, struct tls_msg * tlsmsg)
331{
332
333 if (data == NULL)
334 return EINVAL;
335 int pos = 0;
336 diameap_tls_new(tlsmsg);
337 tlsmsg->flags = G8(data);
338 pos++;
339 if ((tlsmsg->flags & TLS_FLAG_LENGTH) == TLS_FLAG_LENGTH)
340 {
341 tlsmsg->length = G32BIGE(data+1);
342 pos = pos + 4;
343 }
344
345 if (len > pos)
346 {
347 tlsmsg->data = malloc(sizeof(u8) * (len - pos));
348 U8COPY(tlsmsg->data,0,(len-pos),data+pos);
349 tlsmsg->datalength = len - pos;
350 }
351 else
352 {
353 tlsmsg->data = NULL;
354 tlsmsg->datalength = 0;
355 }
356 return 0;
357}
358
359void diameap_tls_dump(struct tls_msg tlsmsg)
360{
361 u8 * data = NULL;
362 u32 len;
363 diameap_tls_get_data(tlsmsg, &data, &len);
364
365 fprintf(stderr, "-------------Dump EAP-TLS msg-------------\n");
366 u8 flags;
367 diameap_tls_get_flags(tlsmsg, &flags);
368 fprintf(stderr, "\t -flags : %02x ", flags);
369 if (flags & TLS_FLAG_LENGTH)
370 fprintf(stderr, " TLS_FLAG_LENGTH ");
371 if (flags & TLS_FLAG_MORE)
372 fprintf(stderr, " TLS_FLAG_MORE ");
373 if (flags & TLS_FLAG_START)
374 fprintf(stderr, " TLS_FLAG_START ");
375 fprintf(stderr, "\n");
376 if ((tlsmsg.flags & TLS_FLAG_LENGTH) == TLS_FLAG_LENGTH)
377 {
378 u32 length;
379 diameap_tls_get_message_length(tlsmsg, &length);
380 fprintf(stderr, "\t -TLS msg length : %u (0x%02x%02x%02x%02x)\n",
381 length, (length >> 24) & 0xffU, (length >> 16) & 0xffU, (length
382 >> 8) & 0xffU, length & 0xffU);
383 }
384 fprintf(stderr, "\t -data length : %d \n", len);
385 /*
386 if (len > 0)
387 {
388 int i;
389 fprintf(stderr, "\t -Data : ");
390 for (i = 0; i < len; i++)
391 {
392 fprintf(stderr, "%02x ", G8(data + i));
393 }
394 fprintf(stderr, "\n");
395 }
396 */
397 fprintf(stderr, "-------------End Dump EAP-TLS msg-------------\n");
398
399 free(data);
400}
401
402int diameap_tls_initialize(struct tls_data * data)
403{
404 if (!data)
405 {
406 return EINVAL;
407 }
408 data->state = START;
409 data->more_tosend_length = 0;
410 data->more_toreceive = FALSE;
411 data->handshake = FALSE;
412 return 0;
413}
414
415int diameap_tls_reassemble(struct tls_msg * to, struct tls_msg from)
416{
417 u8 from_flag;
418 diameap_tls_get_flags(from, &from_flag);
419
420 if (from_flag & TLS_FLAG_LENGTH)
421 {
422 diameap_tls_new(to);
423 u32 length;
424 diameap_tls_get_message_length(from, &length);
425 diameap_tls_set_message_length(to, length);
426 }
427 diameap_tls_set_flags(to, from_flag);
428
429 u8 * tlsRespData;
430 u32 tlsRespDataLength;
431 diameap_tls_get_data(from, &tlsRespData, &tlsRespDataLength);
432 to->data = realloc(to->data, to->datalength + tlsRespDataLength);
433 U8COPY(to->data,to->datalength,tlsRespDataLength,tlsRespData);
434 to->datalength += tlsRespDataLength;
435 free(tlsRespData);
436 return 0;
437}
438
439int diameap_tls_copy(struct tls_msg * to, struct tls_msg from)
440{
441 u8 flag;
442 u32 length;
443 u8 * data;
444 diameap_tls_new(to);
445 diameap_tls_get_flags(from, &flag);
446 diameap_tls_set_flags(to, flag);
447 diameap_tls_get_message_length(from, &length);
448 diameap_tls_set_message_length(to, length);
449 length = 0;
450 diameap_tls_get_data(from, &data, &length);
451 diameap_tls_set_data(to, data, length);
452 return 0;
453}
454
455int diameap_tls_process_receive(struct tls_data * data)
456{
457 int ret;
458
459 data->p_length = data->tlsResp.datalength;
460
461 ret = gnutls_handshake(data->session);
462
463 if (ret < 0)
464 {
465 switch (ret)
466 {
467 case GNUTLS_E_AGAIN:
468 break;
469 case GNUTLS_E_INTERRUPTED:
470 fprintf(stderr, "[DiamEAP extension] [EAP TLS] gnutls handshake : GNUTLS_E_INTERRUPTED");
471 break;
472 case GNUTLS_E_GOT_APPLICATION_DATA:
473 fprintf(stderr,
474 "[DiamEAP extension] [EAP TLS] gnutls handshake : GNUTLS_E_GOT_APPLICATION_DATA");
475 break;
476 case GNUTLS_E_WARNING_ALERT_RECEIVED:
477 fprintf(stderr,
478 "[DiamEAP extension] [EAP TLS] gnutls handshake : GNUTLS_E_WARNING_ALERT_RECEIVED");
479 break;
480 }
481 if (ret != GNUTLS_E_AGAIN)
482 {
483 gnutls_perror(ret);
484 }
485 }
486 if (ret == GNUTLS_E_SUCCESS)
487 {
488 data->handshake = TRUE;
489 }
490 return 0;
491}
492