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 */
"Welcome to our mercurial repository"