1 | /********************************************************************************************************* |
---|
2 | * Software License Agreement (BSD License) * |
---|
3 | * Author: Sebastien Decugis <sdecugis@nict.go.jp> * |
---|
4 | * * |
---|
5 | * Copyright (c) 2011, 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 */ |
---|
49 | int 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 = 3868; |
---|
59 | fd_g_config->cnf_port_tls = 3869; |
---|
60 | fd_g_config->cnf_sctp_str = 30; |
---|
61 | fd_g_config->cnf_dispthr = 4; |
---|
62 | fd_list_init(&fd_g_config->cnf_endpoints, NULL); |
---|
63 | fd_list_init(&fd_g_config->cnf_apps, NULL); |
---|
64 | #ifdef DISABLE_SCTP |
---|
65 | fd_g_config->cnf_flags.no_sctp = 1; |
---|
66 | #endif /* DISABLE_SCTP */ |
---|
67 | |
---|
68 | fd_g_config->cnf_orstateid = (uint32_t) time(NULL); |
---|
69 | |
---|
70 | CHECK_FCT( fd_dict_init(&fd_g_config->cnf_dict) ); |
---|
71 | CHECK_FCT( fd_fifo_new(&fd_g_config->cnf_main_ev) ); |
---|
72 | |
---|
73 | /* TLS parameters */ |
---|
74 | CHECK_GNUTLS_DO( gnutls_certificate_allocate_credentials (&fd_g_config->cnf_sec_data.credentials), return ENOMEM ); |
---|
75 | CHECK_GNUTLS_DO( gnutls_dh_params_init (&fd_g_config->cnf_sec_data.dh_cache), return ENOMEM ); |
---|
76 | |
---|
77 | return 0; |
---|
78 | } |
---|
79 | |
---|
80 | void fd_conf_dump() |
---|
81 | { |
---|
82 | if (!TRACE_BOOL(INFO)) |
---|
83 | return; |
---|
84 | |
---|
85 | fd_log_debug("-- Configuration :\n"); |
---|
86 | fd_log_debug(" Debug trace level ...... : %+d\n", fd_g_debug_lvl); |
---|
87 | fd_log_debug(" Configuration file ..... : %s\n", fd_g_config->cnf_file); |
---|
88 | fd_log_debug(" Diameter Identity ...... : %s (l:%Zi)\n", fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len); |
---|
89 | fd_log_debug(" Diameter Realm ......... : %s (l:%Zi)\n", fd_g_config->cnf_diamrlm, fd_g_config->cnf_diamrlm_len); |
---|
90 | fd_log_debug(" Tc Timer ............... : %u\n", fd_g_config->cnf_timer_tc); |
---|
91 | fd_log_debug(" Tw Timer ............... : %u\n", fd_g_config->cnf_timer_tw); |
---|
92 | fd_log_debug(" Local port ............. : %hu\n", fd_g_config->cnf_port); |
---|
93 | fd_log_debug(" Local secure port ...... : %hu\n", fd_g_config->cnf_port_tls); |
---|
94 | fd_log_debug(" Number of SCTP streams . : %hu\n", fd_g_config->cnf_sctp_str); |
---|
95 | fd_log_debug(" Number of server threads : %hu\n", fd_g_config->cnf_dispthr); |
---|
96 | if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) { |
---|
97 | fd_log_debug(" Local endpoints ........ : Default (use all available)\n"); |
---|
98 | } else { |
---|
99 | fd_log_debug(" Local endpoints ........ : \n"); |
---|
100 | fd_ep_dump( 29, &fd_g_config->cnf_endpoints ); |
---|
101 | } |
---|
102 | if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_apps)) { |
---|
103 | fd_log_debug(" Local applications ..... : (none)\n"); |
---|
104 | } else { |
---|
105 | struct fd_list * li = fd_g_config->cnf_apps.next; |
---|
106 | fd_log_debug(" Local applications ..... : "); |
---|
107 | while (li != &fd_g_config->cnf_apps) { |
---|
108 | struct fd_app * app = (struct fd_app *)li; |
---|
109 | if (li != fd_g_config->cnf_apps.next) fd_log_debug(" "); |
---|
110 | fd_log_debug("App: %u\t%s%s\tVnd: %u\n", |
---|
111 | app->appid, |
---|
112 | app->flags.auth ? "Au" : "--", |
---|
113 | app->flags.acct ? "Ac" : "--", |
---|
114 | app->vndid); |
---|
115 | li = li->next; |
---|
116 | } |
---|
117 | } |
---|
118 | |
---|
119 | fd_log_debug(" Flags : - IP ........... : %s\n", fd_g_config->cnf_flags.no_ip4 ? "DISABLED" : "Enabled"); |
---|
120 | fd_log_debug(" - IPv6 ......... : %s\n", fd_g_config->cnf_flags.no_ip6 ? "DISABLED" : "Enabled"); |
---|
121 | fd_log_debug(" - Relay app .... : %s\n", fd_g_config->cnf_flags.no_fwd ? "DISABLED" : "Enabled"); |
---|
122 | fd_log_debug(" - TCP .......... : %s\n", fd_g_config->cnf_flags.no_tcp ? "DISABLED" : "Enabled"); |
---|
123 | #ifdef DISABLE_SCTP |
---|
124 | fd_log_debug(" - SCTP ......... : DISABLED (at compilation)\n"); |
---|
125 | #else /* DISABLE_SCTP */ |
---|
126 | fd_log_debug(" - SCTP ......... : %s\n", fd_g_config->cnf_flags.no_sctp ? "DISABLED" : "Enabled"); |
---|
127 | #endif /* DISABLE_SCTP */ |
---|
128 | fd_log_debug(" - Pref. proto .. : %s\n", fd_g_config->cnf_flags.pr_tcp ? "TCP" : "SCTP"); |
---|
129 | fd_log_debug(" - TLS method ... : %s\n", fd_g_config->cnf_flags.tls_alg ? "INBAND" : "Separate port"); |
---|
130 | |
---|
131 | fd_log_debug(" TLS : - Certificate .. : %s\n", fd_g_config->cnf_sec_data.cert_file ?: "(NONE)"); |
---|
132 | fd_log_debug(" - Private key .. : %s\n", fd_g_config->cnf_sec_data.key_file ?: "(NONE)"); |
---|
133 | fd_log_debug(" - CA (trust) ... : %s (%d certs)\n", fd_g_config->cnf_sec_data.ca_file ?: "(none)", fd_g_config->cnf_sec_data.ca_file_nr); |
---|
134 | fd_log_debug(" - CRL .......... : %s\n", fd_g_config->cnf_sec_data.crl_file ?: "(none)"); |
---|
135 | fd_log_debug(" - Priority ..... : %s\n", fd_g_config->cnf_sec_data.prio_string ?: "(default: '" GNUTLS_DEFAULT_PRIORITY "')"); |
---|
136 | if (fd_g_config->cnf_sec_data.dh_file) |
---|
137 | fd_log_debug(" - DH file ...... : %s\n", fd_g_config->cnf_sec_data.dh_file); |
---|
138 | else |
---|
139 | fd_log_debug(" - DH bits ...... : %d\n", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); |
---|
140 | |
---|
141 | fd_log_debug(" Origin-State-Id ........ : %u\n", fd_g_config->cnf_orstateid); |
---|
142 | } |
---|
143 | |
---|
144 | /* Parse the configuration file (using the yacc parser) */ |
---|
145 | int fd_conf_parse() |
---|
146 | { |
---|
147 | extern FILE * fddin; |
---|
148 | char * orig = NULL; |
---|
149 | |
---|
150 | /* Attempt to find the configuration file */ |
---|
151 | if (!fd_g_config->cnf_file) |
---|
152 | fd_g_config->cnf_file = FD_DEFAULT_CONF_FILENAME; |
---|
153 | |
---|
154 | fddin = fopen(fd_g_config->cnf_file, "r"); |
---|
155 | if ((fddin == NULL) && (*fd_g_config->cnf_file != '/')) { |
---|
156 | /* We got a relative path, attempt to add the default directory prefix */ |
---|
157 | orig = fd_g_config->cnf_file; |
---|
158 | CHECK_MALLOC( fd_g_config->cnf_file = malloc(strlen(orig) + strlen(DEFAULT_CONF_PATH) + 2) ); /* we will not free it, but not important */ |
---|
159 | sprintf( fd_g_config->cnf_file, DEFAULT_CONF_PATH "/%s", orig ); |
---|
160 | fddin = fopen(fd_g_config->cnf_file, "r"); |
---|
161 | } |
---|
162 | if (fddin == NULL) { |
---|
163 | int ret = errno; |
---|
164 | if (orig) { |
---|
165 | fprintf(stderr, "Unable to open configuration file for reading\n" |
---|
166 | "Tried the following locations:\n" |
---|
167 | " - %s\n" |
---|
168 | " - %s\n" |
---|
169 | "Error: %s\n", orig, fd_g_config->cnf_file, strerror(ret)); |
---|
170 | } else { |
---|
171 | fprintf(stderr, "Unable to open '%s' for reading: %s\n", fd_g_config->cnf_file, strerror(ret)); |
---|
172 | } |
---|
173 | return ret; |
---|
174 | } |
---|
175 | |
---|
176 | /* call yacc parser */ |
---|
177 | TRACE_DEBUG (FULL, "Parsing configuration file: %s", fd_g_config->cnf_file); |
---|
178 | CHECK_FCT( fddparse(fd_g_config) ); |
---|
179 | |
---|
180 | /* close the file */ |
---|
181 | fclose(fddin); |
---|
182 | |
---|
183 | /* Check that TLS private key was given */ |
---|
184 | if (! fd_g_config->cnf_sec_data.key_file) { |
---|
185 | fprintf(stderr, "Missing private key configuration for TLS. Please provide the TLS_cred configuration directive.\n"); |
---|
186 | return EINVAL; |
---|
187 | } |
---|
188 | |
---|
189 | /* If the CA is not provided, let's use the same file (assuming self-signed certificate) */ |
---|
190 | if (! fd_g_config->cnf_sec_data.ca_file) { |
---|
191 | CHECK_MALLOC( fd_g_config->cnf_sec_data.ca_file = strdup(fd_g_config->cnf_sec_data.cert_file) ); |
---|
192 | CHECK_GNUTLS_DO( fd_g_config->cnf_sec_data.ca_file_nr += gnutls_certificate_set_x509_trust_file( |
---|
193 | fd_g_config->cnf_sec_data.credentials, |
---|
194 | fd_g_config->cnf_sec_data.ca_file, |
---|
195 | GNUTLS_X509_FMT_PEM), |
---|
196 | { |
---|
197 | TRACE_DEBUG(INFO, "Unable to use the local certificate as trusted security anchor (CA), please provide a valid TLS_CA='...' directive."); |
---|
198 | return EINVAL; |
---|
199 | } ); |
---|
200 | } |
---|
201 | |
---|
202 | |
---|
203 | /* Resolve hostname if not provided */ |
---|
204 | if (fd_g_config->cnf_diamid == NULL) { |
---|
205 | char buf[HOST_NAME_MAX + 1]; |
---|
206 | struct addrinfo hints, *info; |
---|
207 | int ret; |
---|
208 | |
---|
209 | /* local host name */ |
---|
210 | CHECK_SYS(gethostname(buf, sizeof(buf))); |
---|
211 | |
---|
212 | /* get FQDN */ |
---|
213 | memset(&hints, 0, sizeof hints); |
---|
214 | hints.ai_flags = AI_CANONNAME; |
---|
215 | |
---|
216 | ret = getaddrinfo(buf, NULL, &hints, &info); |
---|
217 | if (ret != 0) { |
---|
218 | fprintf(stderr, "Error resolving local FQDN :\n" |
---|
219 | " '%s' : %s\n" |
---|
220 | "Please provide Identity in configuration file.\n", |
---|
221 | buf, gai_strerror(ret)); |
---|
222 | return EINVAL; |
---|
223 | } |
---|
224 | fd_g_config->cnf_diamid = info->ai_canonname; |
---|
225 | CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 1) ); |
---|
226 | freeaddrinfo(info); |
---|
227 | } else { |
---|
228 | CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 0) ); |
---|
229 | } |
---|
230 | |
---|
231 | /* Handle the realm part */ |
---|
232 | if (fd_g_config->cnf_diamrlm == NULL) { |
---|
233 | char * start = NULL; |
---|
234 | |
---|
235 | /* Check the diameter identity is a fqdn */ |
---|
236 | start = strchr(fd_g_config->cnf_diamid, '.'); |
---|
237 | if ((start == NULL) || (start[1] == '\0')) { |
---|
238 | fprintf(stderr, "Unable to extract realm from the Identity '%s'.\n" |
---|
239 | "Please fix your Identity setting or provide Realm.\n", |
---|
240 | fd_g_config->cnf_diamid); |
---|
241 | return EINVAL; |
---|
242 | } |
---|
243 | |
---|
244 | fd_g_config->cnf_diamrlm = start + 1; |
---|
245 | CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 1) ); |
---|
246 | } else { |
---|
247 | CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 0) ); |
---|
248 | } |
---|
249 | |
---|
250 | /* Validate some flags */ |
---|
251 | if (fd_g_config->cnf_flags.no_ip4 && fd_g_config->cnf_flags.no_ip6) { |
---|
252 | fprintf(stderr, "IP and IPv6 cannot be disabled at the same time.\n"); |
---|
253 | return EINVAL; |
---|
254 | } |
---|
255 | if (fd_g_config->cnf_flags.no_tcp && fd_g_config->cnf_flags.no_sctp) { |
---|
256 | fprintf(stderr, "TCP and SCTP cannot be disabled at the same time.\n"); |
---|
257 | return EINVAL; |
---|
258 | } |
---|
259 | |
---|
260 | /* Validate local endpoints */ |
---|
261 | if ((!FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) && (fd_g_config->cnf_flags.no_ip4 || fd_g_config->cnf_flags.no_ip6)) { |
---|
262 | struct fd_list * li; |
---|
263 | for ( li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) { |
---|
264 | struct fd_endpoint * ep = (struct fd_endpoint *)li; |
---|
265 | if ( (fd_g_config->cnf_flags.no_ip4 && (ep->sa.sa_family == AF_INET)) |
---|
266 | ||(fd_g_config->cnf_flags.no_ip6 && (ep->sa.sa_family == AF_INET6)) ) { |
---|
267 | li = li->prev; |
---|
268 | fd_list_unlink(&ep->chain); |
---|
269 | if (TRACE_BOOL(INFO)) { |
---|
270 | fd_log_debug("Info: Removing local address conflicting with the flags no_IP / no_IP6 : "); |
---|
271 | sSA_DUMP_NODE( &ep->sa, NI_NUMERICHOST ); |
---|
272 | fd_log_debug("\n"); |
---|
273 | } |
---|
274 | free(ep); |
---|
275 | } |
---|
276 | } |
---|
277 | } |
---|
278 | |
---|
279 | /* Configure TLS default parameters */ |
---|
280 | if (! fd_g_config->cnf_sec_data.prio_string) { |
---|
281 | const char * err_pos = NULL; |
---|
282 | CHECK_GNUTLS_DO( gnutls_priority_init( |
---|
283 | &fd_g_config->cnf_sec_data.prio_cache, |
---|
284 | GNUTLS_DEFAULT_PRIORITY, |
---|
285 | &err_pos), |
---|
286 | { TRACE_DEBUG(INFO, "Error in priority string at position : %s", err_pos); return EINVAL; } ); |
---|
287 | } |
---|
288 | |
---|
289 | /* Verify that our certificate is valid -- otherwise remote peers will reject it */ |
---|
290 | { |
---|
291 | int ret = 0, i; |
---|
292 | |
---|
293 | gnutls_datum_t certfile; |
---|
294 | size_t alloc = 0; |
---|
295 | |
---|
296 | gnutls_x509_crt_t * certs = NULL; |
---|
297 | unsigned int cert_max = 0; |
---|
298 | |
---|
299 | gnutls_x509_crt_t * CA_list; |
---|
300 | int CA_list_length; |
---|
301 | |
---|
302 | gnutls_x509_crl_t * CRL_list; |
---|
303 | int CRL_list_length; |
---|
304 | |
---|
305 | unsigned int verify; |
---|
306 | time_t now; |
---|
307 | |
---|
308 | memset(&certfile, 0, sizeof(certfile)); |
---|
309 | |
---|
310 | /* Read the certificate file */ |
---|
311 | FILE *stream = fopen (fd_g_config->cnf_sec_data.cert_file, "rb"); |
---|
312 | if (!stream) { |
---|
313 | int err = errno; |
---|
314 | TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s\n", fd_g_config->cnf_sec_data.cert_file, strerror(err)); |
---|
315 | return err; |
---|
316 | } |
---|
317 | do { |
---|
318 | uint8_t * realloced = NULL; |
---|
319 | size_t read = 0; |
---|
320 | |
---|
321 | if (alloc < certfile.size + BUFSIZ + 1) { |
---|
322 | alloc += alloc / 2 + BUFSIZ + 1; |
---|
323 | CHECK_MALLOC_DO( realloced = realloc(certfile.data, alloc), |
---|
324 | { |
---|
325 | free(certfile.data); |
---|
326 | return ENOMEM; |
---|
327 | } ) |
---|
328 | certfile.data = realloced; |
---|
329 | } |
---|
330 | |
---|
331 | read = fread( certfile.data + certfile.size, 1, alloc - certfile.size - 1, stream ); |
---|
332 | certfile.size += read; |
---|
333 | |
---|
334 | if (ferror(stream)) { |
---|
335 | int err = errno; |
---|
336 | TRACE_DEBUG(INFO, "An error occurred while reading '%s': %s\n", fd_g_config->cnf_sec_data.cert_file, strerror(err)); |
---|
337 | return err; |
---|
338 | } |
---|
339 | } while (!feof(stream)); |
---|
340 | certfile.data[certfile.size] = '\0'; |
---|
341 | fclose(stream); |
---|
342 | |
---|
343 | /* Import the certificate(s) */ |
---|
344 | GNUTLS_TRACE( ret = gnutls_x509_crt_list_import(NULL, &cert_max, &certfile, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) ); |
---|
345 | if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { |
---|
346 | CHECK_GNUTLS_DO(ret, return EINVAL); |
---|
347 | } |
---|
348 | |
---|
349 | CHECK_MALLOC( certs = calloc(cert_max, sizeof(gnutls_x509_crt_t)) ); |
---|
350 | CHECK_GNUTLS_DO( gnutls_x509_crt_list_import(certs, &cert_max, &certfile, GNUTLS_X509_FMT_PEM, 0), |
---|
351 | { |
---|
352 | TRACE_DEBUG(INFO, "Failed to import the data from file '%s'", fd_g_config->cnf_sec_data.cert_file); |
---|
353 | free(certfile.data); |
---|
354 | return EINVAL; |
---|
355 | } ); |
---|
356 | free(certfile.data); |
---|
357 | |
---|
358 | ASSERT(cert_max >= 1); |
---|
359 | |
---|
360 | /* Now, verify the list against the local CA and CRL */ |
---|
361 | GNUTLS_TRACE( gnutls_certificate_get_x509_cas (fd_g_config->cnf_sec_data.credentials, &CA_list, (unsigned int *) &CA_list_length) ); |
---|
362 | GNUTLS_TRACE( gnutls_certificate_get_x509_crls (fd_g_config->cnf_sec_data.credentials, &CRL_list, (unsigned int *) &CRL_list_length) ); |
---|
363 | CHECK_GNUTLS_DO( gnutls_x509_crt_list_verify(certs, cert_max, CA_list, CA_list_length, CRL_list, CRL_list_length, 0, &verify), |
---|
364 | { |
---|
365 | TRACE_DEBUG(INFO, "Failed to verify the local certificate '%s' against local credentials. Please check your certificate is valid.", fd_g_config->cnf_sec_data.cert_file); |
---|
366 | return EINVAL; |
---|
367 | } ); |
---|
368 | if (verify) { |
---|
369 | fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file); |
---|
370 | if (verify & GNUTLS_CERT_INVALID) |
---|
371 | fd_log_debug(" - The certificate is not trusted (unknown CA? expired?)\n"); |
---|
372 | if (verify & GNUTLS_CERT_REVOKED) |
---|
373 | fd_log_debug(" - The certificate has been revoked.\n"); |
---|
374 | if (verify & GNUTLS_CERT_SIGNER_NOT_FOUND) |
---|
375 | fd_log_debug(" - The certificate hasn't got a known issuer.\n"); |
---|
376 | if (verify & GNUTLS_CERT_SIGNER_NOT_CA) |
---|
377 | fd_log_debug(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.\n"); |
---|
378 | if (verify & GNUTLS_CERT_INSECURE_ALGORITHM) |
---|
379 | fd_log_debug(" - The certificate signature uses a weak algorithm.\n"); |
---|
380 | return EINVAL; |
---|
381 | } |
---|
382 | |
---|
383 | /* Check the local Identity is valid with the certificate */ |
---|
384 | if (!gnutls_x509_crt_check_hostname (certs[0], fd_g_config->cnf_diamid)) { |
---|
385 | fd_log_debug("TLS: Local certificate '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file); |
---|
386 | fd_log_debug(" - The certificate hostname does not match '%s'\n", fd_g_config->cnf_diamid); |
---|
387 | return EINVAL; |
---|
388 | } |
---|
389 | |
---|
390 | /* Check validity of all the certificates in the chain */ |
---|
391 | now = time(NULL); |
---|
392 | for (i = 0; i < cert_max; i++) |
---|
393 | { |
---|
394 | time_t deadline; |
---|
395 | |
---|
396 | GNUTLS_TRACE( deadline = gnutls_x509_crt_get_expiration_time(certs[i]) ); |
---|
397 | if ((deadline != (time_t)-1) && (deadline < now)) { |
---|
398 | fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file); |
---|
399 | fd_log_debug(" - The certificate %d in the chain is expired\n", i); |
---|
400 | return EINVAL; |
---|
401 | } |
---|
402 | |
---|
403 | GNUTLS_TRACE( deadline = gnutls_x509_crt_get_activation_time(certs[i]) ); |
---|
404 | if ((deadline != (time_t)-1) && (deadline > now)) { |
---|
405 | fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file); |
---|
406 | fd_log_debug(" - The certificate %d in the chain is not yet activated\n", i); |
---|
407 | return EINVAL; |
---|
408 | } |
---|
409 | } |
---|
410 | |
---|
411 | /* Everything checked OK, free the certificate list */ |
---|
412 | for (i = 0; i < cert_max; i++) |
---|
413 | { |
---|
414 | GNUTLS_TRACE( gnutls_x509_crt_deinit (certs[i]) ); |
---|
415 | } |
---|
416 | free(certs); |
---|
417 | } |
---|
418 | |
---|
419 | |
---|
420 | /* gnutls_certificate_set_verify_limits -- so far the default values are fine... */ |
---|
421 | |
---|
422 | /* DH */ |
---|
423 | if (fd_g_config->cnf_sec_data.dh_file) { |
---|
424 | gnutls_datum_t dhparams = { NULL, 0 }; |
---|
425 | size_t alloc = 0; |
---|
426 | FILE *stream = fopen (fd_g_config->cnf_sec_data.dh_file, "rb"); |
---|
427 | if (!stream) { |
---|
428 | int err = errno; |
---|
429 | TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s\n", fd_g_config->cnf_sec_data.dh_file, strerror(err)); |
---|
430 | return err; |
---|
431 | } |
---|
432 | do { |
---|
433 | uint8_t * realloced = NULL; |
---|
434 | size_t read = 0; |
---|
435 | |
---|
436 | if (alloc < dhparams.size + BUFSIZ + 1) { |
---|
437 | alloc += alloc / 2 + BUFSIZ + 1; |
---|
438 | CHECK_MALLOC_DO( realloced = realloc(dhparams.data, alloc), |
---|
439 | { |
---|
440 | free(dhparams.data); |
---|
441 | return ENOMEM; |
---|
442 | } ) |
---|
443 | dhparams.data = realloced; |
---|
444 | } |
---|
445 | |
---|
446 | read = fread( dhparams.data + dhparams.size, 1, alloc - dhparams.size - 1, stream ); |
---|
447 | dhparams.size += read; |
---|
448 | |
---|
449 | if (ferror(stream)) { |
---|
450 | int err = errno; |
---|
451 | TRACE_DEBUG(INFO, "An error occurred while reading '%s': %s\n", fd_g_config->cnf_sec_data.dh_file, strerror(err)); |
---|
452 | return err; |
---|
453 | } |
---|
454 | } while (!feof(stream)); |
---|
455 | dhparams.data[dhparams.size] = '\0'; |
---|
456 | fclose(stream); |
---|
457 | CHECK_GNUTLS_DO( gnutls_dh_params_import_pkcs3( |
---|
458 | fd_g_config->cnf_sec_data.dh_cache, |
---|
459 | &dhparams, |
---|
460 | GNUTLS_X509_FMT_PEM), |
---|
461 | { TRACE_DEBUG(INFO, "Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } ); |
---|
462 | free(dhparams.data); |
---|
463 | |
---|
464 | } else { |
---|
465 | TRACE_DEBUG(INFO, "Generating fresh Diffie-Hellman parameters of size %d (this takes some time)... ", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); |
---|
466 | CHECK_GNUTLS_DO( gnutls_dh_params_generate2( |
---|
467 | fd_g_config->cnf_sec_data.dh_cache, |
---|
468 | fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS), |
---|
469 | { TRACE_DEBUG(INFO, "Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } ); |
---|
470 | } |
---|
471 | |
---|
472 | return 0; |
---|
473 | } |
---|
474 | |
---|
475 | |
---|
476 | /* Destroy contents of fd_g_config structure */ |
---|
477 | int fd_conf_deinit() |
---|
478 | { |
---|
479 | TRACE_ENTRY(); |
---|
480 | |
---|
481 | if (!fd_g_config) |
---|
482 | return 0; |
---|
483 | |
---|
484 | /* Free the TLS parameters */ |
---|
485 | gnutls_priority_deinit(fd_g_config->cnf_sec_data.prio_cache); |
---|
486 | gnutls_dh_params_deinit(fd_g_config->cnf_sec_data.dh_cache); |
---|
487 | gnutls_certificate_free_credentials(fd_g_config->cnf_sec_data.credentials); |
---|
488 | |
---|
489 | free(fd_g_config->cnf_sec_data.cert_file); fd_g_config->cnf_sec_data.cert_file = NULL; |
---|
490 | free(fd_g_config->cnf_sec_data.key_file); fd_g_config->cnf_sec_data.key_file = NULL; |
---|
491 | free(fd_g_config->cnf_sec_data.ca_file); fd_g_config->cnf_sec_data.ca_file = NULL; |
---|
492 | free(fd_g_config->cnf_sec_data.crl_file); fd_g_config->cnf_sec_data.crl_file = NULL; |
---|
493 | free(fd_g_config->cnf_sec_data.prio_string); fd_g_config->cnf_sec_data.prio_string = NULL; |
---|
494 | free(fd_g_config->cnf_sec_data.dh_file); fd_g_config->cnf_sec_data.dh_file = NULL; |
---|
495 | |
---|
496 | /* Destroy dictionary */ |
---|
497 | CHECK_FCT_DO( fd_dict_fini(&fd_g_config->cnf_dict), ); |
---|
498 | |
---|
499 | /* Destroy the main event queue */ |
---|
500 | CHECK_FCT_DO( fd_fifo_del(&fd_g_config->cnf_main_ev), ); |
---|
501 | |
---|
502 | /* Destroy the local endpoints and applications */ |
---|
503 | CHECK_FCT_DO(fd_ep_filter(&fd_g_config->cnf_endpoints, 0 ), ); |
---|
504 | CHECK_FCT_DO(fd_app_empty(&fd_g_config->cnf_apps ), ); |
---|
505 | |
---|
506 | /* Destroy the local identity */ |
---|
507 | free(fd_g_config->cnf_diamid); fd_g_config->cnf_diamid = NULL; |
---|
508 | free(fd_g_config->cnf_diamrlm); fd_g_config->cnf_diamrlm = NULL; |
---|
509 | |
---|
510 | return 0; |
---|
511 | } |
---|
512 | |
---|
513 | |
---|