blob: 2a1a063c9ac9a67f6673cfe3893a368155cebd53 [file] [log] [blame]
Brian Waters13d96012017-12-08 16:53:31 -06001/*********************************************************************************************************
2* Software License Agreement (BSD License) *
3* Author: Sebastien Decugis <sdecugis@freediameter.net> *
4* *
5* Copyright (c) 2015, WIDE Project and NICT *
6* All rights reserved. *
7* *
8* Redistribution and use of this software in source and binary forms, with or without modification, are *
9* permitted provided that the following conditions are met: *
10* *
11* * Redistributions of source code must retain the above *
12* copyright notice, this list of conditions and the *
13* following disclaimer. *
14* *
15* * Redistributions in binary form must reproduce the above *
16* copyright notice, this list of conditions and the *
17* following disclaimer in the documentation and/or other *
18* materials provided with the distribution. *
19* *
20* * Neither the name of the WIDE Project or NICT nor the *
21* names of its contributors may be used to endorse or *
22* promote products derived from this software without *
23* specific prior written permission of WIDE Project and *
24* NICT. *
25* *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34*********************************************************************************************************/
35
36#include "fdcore-internal.h"
37#include <sys/stat.h>
38
39/* Configuration management */
40
41#ifndef GNUTLS_DEFAULT_PRIORITY
42# define GNUTLS_DEFAULT_PRIORITY "NORMAL"
43#endif /* GNUTLS_DEFAULT_PRIORITY */
44#ifndef GNUTLS_DEFAULT_DHBITS
45# define GNUTLS_DEFAULT_DHBITS 1024
46#endif /* GNUTLS_DEFAULT_DHBITS */
47
48/* Initialize the fd_g_config structure to default values -- it should already have been initialized to all-0 */
49int fd_conf_init()
50{
51 TRACE_ENTRY();
52
53 fd_g_config->cnf_eyec = EYEC_CONFIG;
54
55 fd_g_config->cnf_timer_tc = 30;
56 fd_g_config->cnf_timer_tw = 30;
57
58 fd_g_config->cnf_port = DIAMETER_PORT;
59 fd_g_config->cnf_port_tls = DIAMETER_SECURE_PORT;
60 fd_g_config->cnf_sctp_str = 30;
61 fd_g_config->cnf_thr_srv = 5;
62 fd_g_config->cnf_dispthr = 4;
63 fd_list_init(&fd_g_config->cnf_endpoints, NULL);
64 fd_list_init(&fd_g_config->cnf_apps, NULL);
65 #ifdef DISABLE_SCTP
66 fd_g_config->cnf_flags.no_sctp = 1;
67 #endif /* DISABLE_SCTP */
68
69 fd_g_config->cnf_orstateid = (uint32_t) time(NULL);
70
71 CHECK_FCT( fd_dict_init(&fd_g_config->cnf_dict) );
72 CHECK_FCT( fd_fifo_new(&fd_g_config->cnf_main_ev, 0) );
73
74 /* TLS parameters */
75 CHECK_GNUTLS_DO( gnutls_certificate_allocate_credentials (&fd_g_config->cnf_sec_data.credentials), return ENOMEM );
76 CHECK_GNUTLS_DO( gnutls_dh_params_init (&fd_g_config->cnf_sec_data.dh_cache), return ENOMEM );
77#ifdef GNUTLS_VERSION_300
78 CHECK_GNUTLS_DO( gnutls_x509_trust_list_init(&fd_g_config->cnf_sec_data.trustlist, 0), return ENOMEM );
79#endif /* GNUTLS_VERSION_300 */
80
81 return 0;
82}
83
84DECLARE_FD_DUMP_PROTOTYPE(fd_conf_dump)
85{
86 FD_DUMP_HANDLE_OFFSET();
87
88 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "freeDiameter configuration:\n"), return NULL);
89 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Default trace level .... : %+d\n", fd_g_debug_lvl), return NULL);
90 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Configuration file ..... : %s\n", fd_g_config->cnf_file), return NULL);
91 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Diameter Identity ...... : %s (l:%zi)\n", fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len), return NULL);
92 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Diameter Realm ......... : %s (l:%zi)\n", fd_g_config->cnf_diamrlm, fd_g_config->cnf_diamrlm_len), return NULL);
93 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Tc Timer ............... : %u\n", fd_g_config->cnf_timer_tc), return NULL);
94 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Tw Timer ............... : %u\n", fd_g_config->cnf_timer_tw), return NULL);
95 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local port ............. : %hu\n", fd_g_config->cnf_port), return NULL);
96 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local secure port ...... : %hu\n", fd_g_config->cnf_port_tls), return NULL);
97 if (fd_g_config->cnf_port_3436) {
98 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local SCTP TLS port .... : %hu\n", fd_g_config->cnf_port_3436), return NULL);
99 }
100 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Number of SCTP streams . : %hu\n", fd_g_config->cnf_sctp_str), return NULL);
101 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Number of clients thr .. : %d\n", fd_g_config->cnf_thr_srv), return NULL);
102 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Number of app threads .. : %hu\n", fd_g_config->cnf_dispthr), return NULL);
103 if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
104 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local endpoints ........ : Default (use all available)\n"), return NULL);
105 } else {
106 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local endpoints ........ : "), return NULL);
107 CHECK_MALLOC_DO( fd_ep_dump( FD_DUMP_STD_PARAMS, 0, 0, &fd_g_config->cnf_endpoints ), return NULL);
108 }
109 if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_apps)) {
110 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local applications ..... : (none)"), return NULL);
111 } else {
112 struct fd_list * li = fd_g_config->cnf_apps.next;
113 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local applications ..... : "), return NULL);
114 while (li != &fd_g_config->cnf_apps) {
115 struct fd_app * app = (struct fd_app *)li;
116 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "App: %u,%s%s,Vnd:%u\t",
117 app->appid,
118 app->flags.auth ? "Au" : "--",
119 app->flags.acct ? "Ac" : "--",
120 app->vndid), return NULL);
121 li = li->next;
122 }
123 }
124
125 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n Flags : - IP ........... : %s\n", fd_g_config->cnf_flags.no_ip4 ? "DISABLED" : "Enabled"), return NULL);
126 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - IPv6 ......... : %s\n", fd_g_config->cnf_flags.no_ip6 ? "DISABLED" : "Enabled"), return NULL);
127 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - Relay app .... : %s\n", fd_g_config->cnf_flags.no_fwd ? "DISABLED" : "Enabled"), return NULL);
128 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - TCP .......... : %s\n", fd_g_config->cnf_flags.no_tcp ? "DISABLED" : "Enabled"), return NULL);
129 #ifdef DISABLE_SCTP
130 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - SCTP ......... : DISABLED (at compilation)\n"), return NULL);
131 #else /* DISABLE_SCTP */
132 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - SCTP ......... : %s\n", fd_g_config->cnf_flags.no_sctp ? "DISABLED" : "Enabled"), return NULL);
133 #endif /* DISABLE_SCTP */
134 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - Pref. proto .. : %s\n", fd_g_config->cnf_flags.pr_tcp ? "TCP" : "SCTP"), return NULL);
135 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - TLS method ... : %s\n", fd_g_config->cnf_flags.tls_alg ? "INBAND" : "Separate port"), return NULL);
136
137 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " TLS : - Certificate .. : %s\n", fd_g_config->cnf_sec_data.cert_file ?: "(NONE)"), return NULL);
138 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - Private key .. : %s\n", fd_g_config->cnf_sec_data.key_file ?: "(NONE)"), return NULL);
139 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - CA (trust) ... : %s (%d certs)\n", fd_g_config->cnf_sec_data.ca_file ?: "(none)", fd_g_config->cnf_sec_data.ca_file_nr), return NULL);
140 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - CRL .......... : %s\n", fd_g_config->cnf_sec_data.crl_file ?: "(none)"), return NULL);
141 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - Priority ..... : %s\n", fd_g_config->cnf_sec_data.prio_string ?: "(default: '" GNUTLS_DEFAULT_PRIORITY "')"), return NULL);
142 if (fd_g_config->cnf_sec_data.dh_file) {
143 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - DH file ...... : %s\n", fd_g_config->cnf_sec_data.dh_file), return NULL);
144 } else {
145 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - DH bits ...... : %d\n", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS), return NULL);
146 }
147
148 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Origin-State-Id ........ : %u", fd_g_config->cnf_orstateid), return NULL);
149
150 return *buf;
151}
152
153/* read contents of a file opened in "rb" mode and alloc this data into a gnutls_datum_t (must be freed afterwards) */
154int fd_conf_stream_to_gnutls_datum(FILE * pemfile, gnutls_datum_t *out)
155{
156 size_t alloc = 0;
157
158 CHECK_PARAMS( pemfile && out );
159 memset(out, 0, sizeof(gnutls_datum_t));
160
161 do {
162 uint8_t * realloced = NULL;
163 size_t read = 0;
164
165 if (alloc < out->size + BUFSIZ + 1) {
166 alloc += alloc / 2 + BUFSIZ + 1;
167 CHECK_MALLOC_DO( realloced = realloc(out->data, alloc),
168 {
169 free(out->data);
170 return ENOMEM;
171 } )
172 out->data = realloced;
173 }
174
175 read = fread( out->data + out->size, 1, alloc - out->size - 1, pemfile );
176 out->size += read;
177
178 if (ferror(pemfile)) {
179 int err = errno;
180 TRACE_DEBUG(INFO, "An error occurred while reading file: %s", strerror(err));
181 return err;
182 }
183 } while (!feof(pemfile));
184
185 out->data[out->size] = '\0';
186 return 0;
187}
188
189#ifdef GNUTLS_VERSION_300
190/* inspired from GnuTLS manual */
191static int fd_conf_print_details_func (gnutls_x509_crt_t cert,
192 gnutls_x509_crt_t issuer, gnutls_x509_crl_t crl,
193 unsigned int verification_output)
194{
195 char name[512];
196 char issuer_name[512];
197 size_t name_size;
198 size_t issuer_name_size;
199
200 if (!TRACE_BOOL(GNUTLS_DBG_LEVEL))
201 return 0;
202
203 issuer_name_size = sizeof (issuer_name);
204 gnutls_x509_crt_get_issuer_dn (cert, issuer_name, &issuer_name_size);
205
206 name_size = sizeof (name);
207 gnutls_x509_crt_get_dn (cert, name, &name_size);
208
209 fd_log_debug("\tSubject: %s", name);
210 fd_log_debug("\tIssuer: %s", issuer_name);
211
212 if (issuer != NULL)
213 {
214 issuer_name_size = sizeof (issuer_name);
215 gnutls_x509_crt_get_dn (issuer, issuer_name, &issuer_name_size);
216
217 fd_log_debug("\tVerified against: %s", issuer_name);
218 }
219
220 if (crl != NULL)
221 {
222 issuer_name_size = sizeof (issuer_name);
223 gnutls_x509_crl_get_issuer_dn (crl, issuer_name, &issuer_name_size);
224
225 fd_log_debug("\tVerified against CRL of: %s", issuer_name);
226 }
227
228 fd_log_debug("\tVerification output: %x", verification_output);
229
230 return 0;
231}
232#endif /* GNUTLS_VERSION_300 */
233
234#ifndef GNUTLS_VERSION_300
235GCC_DIAG_OFF("-Wdeprecated-declarations")
236#endif /* !GNUTLS_VERSION_300 */
237/* Parse the configuration file (using the yacc parser) */
238int fd_conf_parse()
239{
240 extern FILE * fddin;
241 const char * orig = NULL;
242
243 /* Attempt to find the configuration file */
244 if (!fd_g_config->cnf_file)
245 fd_g_config->cnf_file = FD_DEFAULT_CONF_FILENAME;
246
247 fddin = fopen(fd_g_config->cnf_file, "r");
248 if ((fddin == NULL) && (*fd_g_config->cnf_file != '/')) {
249 char * new_cnf = NULL;
250 /* We got a relative path, attempt to add the default directory prefix */
251 orig = fd_g_config->cnf_file;
252 CHECK_MALLOC( new_cnf = malloc(strlen(orig) + strlen(DEFAULT_CONF_PATH) + 2) ); /* we will not free it, but not important */
253 sprintf( new_cnf, DEFAULT_CONF_PATH "/%s", orig );
254 fd_g_config->cnf_file = new_cnf;
255 fddin = fopen(fd_g_config->cnf_file, "r");
256 }
257 if (fddin == NULL) {
258 int ret = errno;
259 LOG_F("Unable to open configuration file for reading; tried the following locations: %s%s%s; Error: %s",
260 orig ?: "", orig? " and " : "", fd_g_config->cnf_file, strerror(ret));
261 return ret;
262 }
263
264 /* call yacc parser */
265 TRACE_DEBUG (FULL, "Parsing configuration file: %s", fd_g_config->cnf_file);
266 CHECK_FCT( fddparse(fd_g_config) );
267
268 /* close the file */
269 fclose(fddin);
270
271 /* Check that TLS private key was given */
272 if (! fd_g_config->cnf_sec_data.key_file) {
273 /* If TLS is not enabled, we allow empty TLS configuration */
274 if ((fd_g_config->cnf_port_tls == 0) && (fd_g_config->cnf_flags.tls_alg == 0)) {
275 LOG_N("TLS is disabled, this is *NOT* a recommended practice! Diameter protocol conveys highly sensitive information on your users.");
276 fd_g_config->cnf_sec_data.tls_disabled = 1;
277 } else {
278 LOG_F( "Missing private key configuration for TLS. Please provide the TLS_cred configuration directive.");
279 return EINVAL;
280 }
281 }
282
283 /* Resolve hostname if not provided */
284 if (fd_g_config->cnf_diamid == NULL) {
285 char buf[HOST_NAME_MAX + 1];
286 struct addrinfo hints, *info;
287 int ret;
288
289 /* local host name */
290 CHECK_SYS(gethostname(buf, sizeof(buf)));
291
292 /* get FQDN */
293 memset(&hints, 0, sizeof hints);
294 hints.ai_flags = AI_CANONNAME;
295
296 ret = getaddrinfo(buf, NULL, &hints, &info);
297 if (ret != 0) {
298 TRACE_ERROR( "Error resolving local FQDN : '%s' : %s"
299 ". Please provide Identity in configuration file.",
300 buf, gai_strerror(ret));
301 return EINVAL;
302 }
303 fd_g_config->cnf_diamid = info->ai_canonname;
304 CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 1) );
305 freeaddrinfo(info);
306 } else {
307 CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 0) );
308 }
309
310 /* Handle the realm part */
311 if (fd_g_config->cnf_diamrlm == NULL) {
312 char * start = NULL;
313
314 /* Check the diameter identity is a fqdn */
315 start = strchr(fd_g_config->cnf_diamid, '.');
316 if ((start == NULL) || (start[1] == '\0')) {
317 TRACE_ERROR( "Unable to extract realm from the Identity '%s'."
318 " Please fix your Identity setting or provide Realm.",
319 fd_g_config->cnf_diamid);
320 return EINVAL;
321 }
322
323 fd_g_config->cnf_diamrlm = start + 1;
324 CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 1) );
325 } else {
326 CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 0) );
327 }
328
329 /* Validate some flags */
330 if (fd_g_config->cnf_flags.no_ip4 && fd_g_config->cnf_flags.no_ip6) {
331 TRACE_ERROR( "IP and IPv6 cannot be disabled at the same time.");
332 return EINVAL;
333 }
334 if (fd_g_config->cnf_flags.no_tcp && fd_g_config->cnf_flags.no_sctp) {
335 TRACE_ERROR( "TCP and SCTP cannot be disabled at the same time.");
336 return EINVAL;
337 }
338
339 /* Validate local endpoints */
340 if ((!FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) && (fd_g_config->cnf_flags.no_ip4 || fd_g_config->cnf_flags.no_ip6)) {
341 struct fd_list * li;
342 for ( li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) {
343 struct fd_endpoint * ep = (struct fd_endpoint *)li;
344 if ( (fd_g_config->cnf_flags.no_ip4 && (ep->sa.sa_family == AF_INET))
345 ||(fd_g_config->cnf_flags.no_ip6 && (ep->sa.sa_family == AF_INET6)) ) {
346 char sa_buf[sSA_DUMP_STRLEN];;
347 li = li->prev;
348 fd_list_unlink(&ep->chain);
349 fd_sa_sdump_numeric(sa_buf, &ep->sa);
350 LOG_N("Info: Removing local address conflicting with the flags no_IP / no_IP6 : %s", sa_buf);
351 free(ep);
352 }
353 }
354 }
355
356 /* Configure TLS default parameters */
357 if ((!fd_g_config->cnf_sec_data.tls_disabled) && (!fd_g_config->cnf_sec_data.prio_string)) {
358 const char * err_pos = NULL;
359 CHECK_GNUTLS_DO( gnutls_priority_init(
360 &fd_g_config->cnf_sec_data.prio_cache,
361 GNUTLS_DEFAULT_PRIORITY,
362 &err_pos),
363 { TRACE_ERROR("Error in priority string at position : %s", err_pos); return EINVAL; } );
364 }
365
366 /* Verify that our certificate is valid -- otherwise remote peers will reject it */
367 if (!fd_g_config->cnf_sec_data.tls_disabled) {
368 int ret = 0, i;
369
370 gnutls_datum_t certfile;
371
372 gnutls_x509_crt_t * certs = NULL;
373 unsigned int cert_max = 0;
374
375
376 /* Read the certificate file */
377 FILE *stream = fopen (fd_g_config->cnf_sec_data.cert_file, "rb");
378 if (!stream) {
379 int err = errno;
380 TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s", fd_g_config->cnf_sec_data.cert_file, strerror(err));
381 return err;
382 }
383 CHECK_FCT( fd_conf_stream_to_gnutls_datum(stream, &certfile) );
384 fclose(stream);
385
386 /* Import the certificate(s) */
387 GNUTLS_TRACE( ret = gnutls_x509_crt_list_import(NULL, &cert_max, &certfile, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) );
388 if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
389 CHECK_GNUTLS_DO(ret, return EINVAL);
390 }
391
392 CHECK_MALLOC( certs = calloc(cert_max, sizeof(gnutls_x509_crt_t)) );
393 CHECK_GNUTLS_DO( gnutls_x509_crt_list_import(certs, &cert_max, &certfile, GNUTLS_X509_FMT_PEM,
394 #ifdef GNUTLS_VERSION_300
395 GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED
396 #else /* GNUTLS_VERSION_300 */
397 0
398 #endif /* GNUTLS_VERSION_300 */
399 ),
400 {
401 TRACE_ERROR("Failed to import the data from file '%s'", fd_g_config->cnf_sec_data.cert_file);
402 free(certfile.data);
403 return EINVAL;
404 } );
405 free(certfile.data);
406
407 ASSERT(cert_max >= 1);
408
409 /* Now, verify the list against the local CA and CRL */
410
411 #ifdef GNUTLS_VERSION_300
412
413 /* We use the trust list for this purpose */
414 {
415 unsigned int output;
416
417 gnutls_x509_trust_list_verify_named_crt (
418 fd_g_config->cnf_sec_data.trustlist,
419 certs[0],
420 fd_g_config->cnf_diamid,
421 fd_g_config->cnf_diamid_len,
422 0,
423 &output,
424 fd_conf_print_details_func);
425
426 /* if this certificate is not explicitly trusted verify against CAs
427 */
428 if (output != 0)
429 {
430 gnutls_x509_trust_list_verify_crt (
431 fd_g_config->cnf_sec_data.trustlist,
432 certs,
433 cert_max,
434 0,
435 &output,
436 fd_conf_print_details_func);
437 }
438
439 if (output & GNUTLS_CERT_INVALID)
440 {
441 fd_log_debug("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
442 if (output & GNUTLS_CERT_SIGNER_NOT_FOUND)
443 TRACE_ERROR(" - The certificate hasn't got a known issuer. Did you forget to specify TLS_CA ?");
444 if (output & GNUTLS_CERT_SIGNER_NOT_CA)
445 TRACE_ERROR(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.");
446 if (output & GNUTLS_CERT_NOT_ACTIVATED)
447 TRACE_ERROR(" - The certificate is not yet activated.");
448 if (output & GNUTLS_CERT_EXPIRED)
449 TRACE_ERROR(" - The certificate is expired.");
450 return EINVAL;
451 }
452
453 /* Now check the subject matches our hostname */
454 if (!gnutls_x509_crt_check_hostname (certs[0], fd_g_config->cnf_diamid))
455 {
456 TRACE_ERROR("TLS: The certificate owner does not match the hostname '%s'", fd_g_config->cnf_diamid);
457 return EINVAL;
458 }
459
460 }
461
462
463 #else /* GNUTLS_VERSION_300 */
464
465 /* GnuTLS 2.x way of checking certificates */
466 {
467 gnutls_x509_crt_t * CA_list;
468 int CA_list_length;
469
470 gnutls_x509_crl_t * CRL_list;
471 int CRL_list_length;
472
473 unsigned int verify;
474 time_t now;
475 GNUTLS_TRACE( gnutls_certificate_get_x509_cas (fd_g_config->cnf_sec_data.credentials, &CA_list, (unsigned int *) &CA_list_length) );
476 GNUTLS_TRACE( gnutls_certificate_get_x509_crls (fd_g_config->cnf_sec_data.credentials, &CRL_list, (unsigned int *) &CRL_list_length) );
477 CHECK_GNUTLS_DO( gnutls_x509_crt_list_verify(certs, cert_max, CA_list, CA_list_length, CRL_list, CRL_list_length, 0, &verify),
478 {
479 TRACE_ERROR("Failed to verify the local certificate '%s' against local credentials. Please check your certificate is valid.", fd_g_config->cnf_sec_data.cert_file);
480 return EINVAL;
481 } );
482
483 if (verify) {
484 fd_log_debug("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
485 if (verify & GNUTLS_CERT_INVALID)
486 TRACE_ERROR(" - The certificate is not trusted (unknown CA? expired?)");
487 if (verify & GNUTLS_CERT_REVOKED)
488 TRACE_ERROR(" - The certificate has been revoked.");
489 if (verify & GNUTLS_CERT_SIGNER_NOT_FOUND)
490 TRACE_ERROR(" - The certificate hasn't got a known issuer.");
491 if (verify & GNUTLS_CERT_SIGNER_NOT_CA)
492 TRACE_ERROR(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.");
493 if (verify & GNUTLS_CERT_INSECURE_ALGORITHM)
494 TRACE_ERROR(" - The certificate signature uses a weak algorithm.");
495 return EINVAL;
496 }
497
498 /* Check the local Identity is valid with the certificate */
499 if (!gnutls_x509_crt_check_hostname (certs[0], fd_g_config->cnf_diamid)) {
500 TRACE_ERROR("TLS: Local certificate '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
501 TRACE_ERROR(" - The certificate hostname does not match '%s'", fd_g_config->cnf_diamid);
502 return EINVAL;
503 }
504
505 /* Check validity of all the certificates in the chain */
506 now = time(NULL);
507 for (i = 0; i < cert_max; i++)
508 {
509 time_t deadline;
510
511 GNUTLS_TRACE( deadline = gnutls_x509_crt_get_expiration_time(certs[i]) );
512 if ((deadline != (time_t)-1) && (deadline < now)) {
513 TRACE_ERROR("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
514 TRACE_ERROR(" - The certificate %d in the chain is expired", i);
515 return EINVAL;
516 }
517
518 GNUTLS_TRACE( deadline = gnutls_x509_crt_get_activation_time(certs[i]) );
519 if ((deadline != (time_t)-1) && (deadline > now)) {
520 TRACE_ERROR("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
521 TRACE_ERROR(" - The certificate %d in the chain is not yet activated", i);
522 return EINVAL;
523 }
524 }
525 }
526 #endif /* GNUTLS_VERSION_300 */
527
528 /* Everything checked OK, free the certificate list */
529 for (i = 0; i < cert_max; i++)
530 {
531 GNUTLS_TRACE( gnutls_x509_crt_deinit (certs[i]) );
532 }
533 free(certs);
534
535 #ifdef GNUTLS_VERSION_300
536 /* Use certificate verification during the handshake */
537 gnutls_certificate_set_verify_function (fd_g_config->cnf_sec_data.credentials, fd_tls_verify_credentials_2);
538 #endif /* GNUTLS_VERSION_300 */
539
540 }
541
542 /* gnutls_certificate_set_verify_limits -- so far the default values are fine... */
543
544 /* DH */
545 if (!fd_g_config->cnf_sec_data.tls_disabled) {
546 if (fd_g_config->cnf_sec_data.dh_file) {
547 gnutls_datum_t dhparams = { NULL, 0 };
548 size_t alloc = 0;
549 FILE *stream = fopen (fd_g_config->cnf_sec_data.dh_file, "rb");
550 if (!stream) {
551 int err = errno;
552 TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s", fd_g_config->cnf_sec_data.dh_file, strerror(err));
553 return err;
554 }
555 do {
556 uint8_t * realloced = NULL;
557 size_t read = 0;
558
559 if (alloc < dhparams.size + BUFSIZ + 1) {
560 alloc += alloc / 2 + BUFSIZ + 1;
561 CHECK_MALLOC_DO( realloced = realloc(dhparams.data, alloc),
562 {
563 free(dhparams.data);
564 return ENOMEM;
565 } )
566 dhparams.data = realloced;
567 }
568
569 read = fread( dhparams.data + dhparams.size, 1, alloc - dhparams.size - 1, stream );
570 dhparams.size += read;
571
572 if (ferror(stream)) {
573 int err = errno;
574 TRACE_DEBUG(INFO, "An error occurred while reading '%s': %s", fd_g_config->cnf_sec_data.dh_file, strerror(err));
575 return err;
576 }
577 } while (!feof(stream));
578 dhparams.data[dhparams.size] = '\0';
579 fclose(stream);
580 CHECK_GNUTLS_DO( gnutls_dh_params_import_pkcs3(
581 fd_g_config->cnf_sec_data.dh_cache,
582 &dhparams,
583 GNUTLS_X509_FMT_PEM),
584 { TRACE_ERROR("Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
585 free(dhparams.data);
586
587 } else {
588 LOG_D( "Generating fresh Diffie-Hellman parameters of size %d (this takes some time)... ", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS);
589 CHECK_GNUTLS_DO( gnutls_dh_params_generate2(
590 fd_g_config->cnf_sec_data.dh_cache,
591 fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS),
592 { TRACE_ERROR("Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
593 }
594
595 }
596
597 return 0;
598}
599#ifndef GNUTLS_VERSION_300
600GCC_DIAG_ON("-Wdeprecated-declarations")
601#endif /* !GNUTLS_VERSION_300 */
602
603
604/* Destroy contents of fd_g_config structure */
605int fd_conf_deinit()
606{
607 TRACE_ENTRY();
608
609 if (!fd_g_config)
610 return 0;
611
612 /* Free the TLS parameters */
613#ifdef GNUTLS_VERSION_300
614 gnutls_x509_trust_list_deinit(fd_g_config->cnf_sec_data.trustlist, 1);
615#endif /* GNUTLS_VERSION_300 */
616 gnutls_priority_deinit(fd_g_config->cnf_sec_data.prio_cache);
617 gnutls_dh_params_deinit(fd_g_config->cnf_sec_data.dh_cache);
618 gnutls_certificate_free_credentials(fd_g_config->cnf_sec_data.credentials);
619
620 free(fd_g_config->cnf_sec_data.cert_file); fd_g_config->cnf_sec_data.cert_file = NULL;
621 free(fd_g_config->cnf_sec_data.key_file); fd_g_config->cnf_sec_data.key_file = NULL;
622 free(fd_g_config->cnf_sec_data.ca_file); fd_g_config->cnf_sec_data.ca_file = NULL;
623 free(fd_g_config->cnf_sec_data.crl_file); fd_g_config->cnf_sec_data.crl_file = NULL;
624 free(fd_g_config->cnf_sec_data.prio_string); fd_g_config->cnf_sec_data.prio_string = NULL;
625 free(fd_g_config->cnf_sec_data.dh_file); fd_g_config->cnf_sec_data.dh_file = NULL;
626
627 /* Destroy dictionary */
628 CHECK_FCT_DO( fd_dict_fini(&fd_g_config->cnf_dict), );
629
630 /* Destroy the main event queue */
631 CHECK_FCT_DO( fd_fifo_del(&fd_g_config->cnf_main_ev), );
632
633 /* Destroy the local endpoints and applications */
634 CHECK_FCT_DO(fd_ep_filter(&fd_g_config->cnf_endpoints, 0 ), );
635 CHECK_FCT_DO(fd_app_empty(&fd_g_config->cnf_apps ), );
636
637 /* Destroy the local identity */
638 free(fd_g_config->cnf_diamid); fd_g_config->cnf_diamid = NULL;
639 free(fd_g_config->cnf_diamrlm); fd_g_config->cnf_diamrlm = NULL;
640
641 return 0;
642}
643
644