Mercurial > hg > freeDiameter
comparison freeDiameter/config.c @ 542:0b6cee362f5d
Enforce validation of local certificate upon daemon start.
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Mon, 13 Sep 2010 18:39:22 +0900 |
parents | 097bae83b07a |
children | 7c9a00bfd115 |
comparison
equal
deleted
inserted
replaced
541:fac6907479ad | 542:0b6cee362f5d |
---|---|
266 fd_g_config->cnf_sec_data.dh_cache, | 266 fd_g_config->cnf_sec_data.dh_cache, |
267 GNUTLS_DEFAULT_DHBITS), | 267 GNUTLS_DEFAULT_DHBITS), |
268 { TRACE_DEBUG(INFO, "Error in DH bits value : %d", GNUTLS_DEFAULT_DHBITS); return EINVAL; } ); | 268 { TRACE_DEBUG(INFO, "Error in DH bits value : %d", GNUTLS_DEFAULT_DHBITS); return EINVAL; } ); |
269 } | 269 } |
270 | 270 |
271 | |
272 /* Verify that our certificate is valid -- otherwise remote peers will reject it */ | |
273 { | |
274 int ret = 0, i; | |
275 | |
276 gnutls_datum_t certfile; | |
277 size_t alloc = 0; | |
278 | |
279 gnutls_x509_crt_t * certs = NULL; | |
280 unsigned int cert_max = 0; | |
281 | |
282 gnutls_x509_crt_t * CA_list; | |
283 int CA_list_length; | |
284 | |
285 gnutls_x509_crl_t * CRL_list; | |
286 int CRL_list_length; | |
287 | |
288 unsigned int verify; | |
289 time_t now; | |
290 | |
291 memset(&certfile, 0, sizeof(certfile)); | |
292 | |
293 /* Read the certificate file */ | |
294 FILE *stream = fopen (fd_g_config->cnf_sec_data.cert_file, "rb"); | |
295 if (!stream) { | |
296 int err = errno; | |
297 TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s\n", fd_g_config->cnf_sec_data.cert_file, strerror(err)); | |
298 return err; | |
299 } | |
300 do { | |
301 uint8_t * realloced = NULL; | |
302 size_t read = 0; | |
303 | |
304 if (alloc < certfile.size + BUFSIZ + 1) { | |
305 alloc += alloc / 2 + BUFSIZ + 1; | |
306 CHECK_MALLOC_DO( realloced = realloc(certfile.data, alloc), | |
307 { | |
308 free(certfile.data); | |
309 return ENOMEM; | |
310 } ) | |
311 certfile.data = realloced; | |
312 } | |
313 | |
314 read = fread( certfile.data + certfile.size, 1, alloc - certfile.size - 1, stream ); | |
315 certfile.size += read; | |
316 | |
317 if (ferror(stream)) { | |
318 int err = errno; | |
319 TRACE_DEBUG(INFO, "An error occurred while reading '%s': %s\n", fd_g_config->cnf_sec_data.cert_file, strerror(err)); | |
320 return err; | |
321 } | |
322 } while (!feof(stream)); | |
323 certfile.data[certfile.size] = '\0'; | |
324 fclose(stream); | |
325 | |
326 /* Import the certificate(s) */ | |
327 GNUTLS_TRACE( ret = gnutls_x509_crt_list_import(NULL, &cert_max, &certfile, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) ); | |
328 if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { | |
329 CHECK_GNUTLS_DO(ret, return EINVAL); | |
330 } | |
331 | |
332 CHECK_MALLOC( certs = calloc(cert_max, sizeof(gnutls_x509_crt_t)) ); | |
333 CHECK_GNUTLS_DO( gnutls_x509_crt_list_import(certs, &cert_max, &certfile, GNUTLS_X509_FMT_PEM, 0), | |
334 { | |
335 TRACE_DEBUG(INFO, "Failed to import the data from file '%s'", fd_g_config->cnf_sec_data.cert_file); | |
336 free(certfile.data); | |
337 return EINVAL; | |
338 } ); | |
339 free(certfile.data); | |
340 | |
341 ASSERT(cert_max >= 1); | |
342 | |
343 /* Now, verify the list against the local CA and CRL */ | |
344 GNUTLS_TRACE( gnutls_certificate_get_x509_cas (fd_g_config->cnf_sec_data.credentials, &CA_list, (unsigned int *) &CA_list_length) ); | |
345 GNUTLS_TRACE( gnutls_certificate_get_x509_crls (fd_g_config->cnf_sec_data.credentials, &CRL_list, (unsigned int *) &CRL_list_length) ); | |
346 CHECK_GNUTLS_DO( gnutls_x509_crt_list_verify(certs, cert_max, CA_list, CA_list_length, CRL_list, CRL_list_length, 0, &verify), | |
347 { | |
348 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); | |
349 return EINVAL; | |
350 } ); | |
351 if (verify) { | |
352 fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file); | |
353 if (verify & GNUTLS_CERT_INVALID) | |
354 fd_log_debug(" - The certificate is not trusted (unknown CA? expired?)\n"); | |
355 if (verify & GNUTLS_CERT_REVOKED) | |
356 fd_log_debug(" - The certificate has been revoked.\n"); | |
357 if (verify & GNUTLS_CERT_SIGNER_NOT_FOUND) | |
358 fd_log_debug(" - The certificate hasn't got a known issuer.\n"); | |
359 if (verify & GNUTLS_CERT_SIGNER_NOT_CA) | |
360 fd_log_debug(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.\n"); | |
361 if (verify & GNUTLS_CERT_INSECURE_ALGORITHM) | |
362 fd_log_debug(" - The certificate signature uses a weak algorithm.\n"); | |
363 return EINVAL; | |
364 } | |
365 | |
366 /* Check the local Identity is valid with the certificate */ | |
367 if (!gnutls_x509_crt_check_hostname (certs[0], fd_g_config->cnf_diamid)) { | |
368 fd_log_debug("TLS: Local certificate '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file); | |
369 fd_log_debug(" - The certificate hostname does not match '%s'\n", fd_g_config->cnf_diamid); | |
370 return EINVAL; | |
371 } | |
372 | |
373 /* Check validity of all the certificates in the chain */ | |
374 now = time(NULL); | |
375 for (i = 0; i < cert_max; i++) | |
376 { | |
377 time_t deadline; | |
378 | |
379 GNUTLS_TRACE( deadline = gnutls_x509_crt_get_expiration_time(certs[i]) ); | |
380 if ((deadline != (time_t)-1) && (deadline < now)) { | |
381 fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file); | |
382 fd_log_debug(" - The certificate %d in the chain is expired\n", i); | |
383 return EINVAL; | |
384 } | |
385 | |
386 GNUTLS_TRACE( deadline = gnutls_x509_crt_get_activation_time(certs[i]) ); | |
387 if ((deadline != (time_t)-1) && (deadline > now)) { | |
388 fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file); | |
389 fd_log_debug(" - The certificate %d in the chain is not yet activated\n", i); | |
390 return EINVAL; | |
391 } | |
392 } | |
393 | |
394 /* Everything checked OK, free the certificate list */ | |
395 for (i = 0; i < cert_max; i++) | |
396 { | |
397 GNUTLS_TRACE( gnutls_x509_crt_deinit (certs[i]) ); | |
398 } | |
399 free(certs); | |
400 } | |
401 | |
402 | |
403 /* gnutls_certificate_set_verify_limits -- so far the default values are fine... */ | |
404 | |
271 return 0; | 405 return 0; |
272 } | 406 } |
273 | 407 |
274 | 408 |
275 /* Destroy contents of fd_g_config structure */ | 409 /* Destroy contents of fd_g_config structure */ |