changeset 1155:d00b5914351e

Allow running freeDiameter without TLS credentials if the following conditions are verified: - The Secure Diameter port is disabled (SecPort = 0;) - The old TLS mechanism is not used (TLS_old_method; not defined) Note that in this context only connections to peers explicitely authorized for 'No_TLS' are permitted.
author Sebastien Decugis <sdecugis@freediameter.net>
date Tue, 28 May 2013 12:11:27 +0800
parents 0b95a3afbfc3
children 7ab58e6d987d
files include/freeDiameter/libfdcore.h libfdcore/config.c libfdcore/p_ce.c libfdcore/p_cnx.c
diffstat 4 files changed, 93 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/include/freeDiameter/libfdcore.h	Mon May 27 17:22:40 2013 +0800
+++ b/include/freeDiameter/libfdcore.h	Tue May 28 12:11:27 2013 +0800
@@ -150,6 +150,8 @@
 	} 		 cnf_flags;
 	
 	struct {
+		int				 tls_disabled;
+		
 		/* Credentials parameters (backup) */
 		char *  			 cert_file;
 		char *				 key_file;
--- a/libfdcore/config.c	Mon May 27 17:22:40 2013 +0800
+++ b/libfdcore/config.c	Tue May 28 12:11:27 2013 +0800
@@ -251,7 +251,7 @@
 	}
 	if (fddin == NULL) {
 		int ret = errno;
-		TRACE_ERROR("Unable to open configuration file for reading; tried the following locations: %s%s%s; Error: %s",
+		LOG_F("Unable to open configuration file for reading; tried the following locations: %s%s%s; Error: %s",
 				  orig ?: "", orig? " and " : "", fd_g_config->cnf_file, strerror(ret));
 		return ret;
 	}
@@ -265,12 +265,18 @@
 	
 	/* Check that TLS private key was given */
 	if (! fd_g_config->cnf_sec_data.key_file) {
-		TRACE_ERROR( "Missing private key configuration for TLS. Please provide the TLS_cred configuration directive.");
-		return EINVAL;
+		/* If TLS is not enabled, we allow empty TLS configuration */
+		if ((fd_g_config->cnf_port_tls == 0) && (fd_g_config->cnf_flags.tls_alg == 0)) {
+			LOG_N("TLS is disabled, this is *NOT* a recommended practice! Diameter protocol conveys highly sensitive information on your users.");
+			fd_g_config->cnf_sec_data.tls_disabled = 1;
+		} else {
+			LOG_F( "Missing private key configuration for TLS. Please provide the TLS_cred configuration directive.");
+			return EINVAL;
+		}
 	}
 	
 	/* If the CA is not provided, let's use the same file (assuming self-signed certificate) */
-	if (! fd_g_config->cnf_sec_data.ca_file) {
+	if ((!fd_g_config->cnf_sec_data.tls_disabled) && (!fd_g_config->cnf_sec_data.ca_file)) {
 		CHECK_MALLOC( fd_g_config->cnf_sec_data.ca_file = strdup(fd_g_config->cnf_sec_data.cert_file) );
 		CHECK_GNUTLS_DO( fd_g_config->cnf_sec_data.ca_file_nr += gnutls_certificate_set_x509_trust_file( 
 					fd_g_config->cnf_sec_data.credentials,
@@ -357,7 +363,7 @@
 	}
 	
 	/* Configure TLS default parameters */
-	if (! fd_g_config->cnf_sec_data.prio_string) {
+	if ((!fd_g_config->cnf_sec_data.tls_disabled) && (!fd_g_config->cnf_sec_data.prio_string)) {
 		const char * err_pos = NULL;
 		CHECK_GNUTLS_DO( gnutls_priority_init( 
 					&fd_g_config->cnf_sec_data.prio_cache,
@@ -367,7 +373,7 @@
 	}
 	
 	/* Verify that our certificate is valid -- otherwise remote peers will reject it */
-	{
+	if (!fd_g_config->cnf_sec_data.tls_disabled) {
 		int ret = 0, i;
 		
 		gnutls_datum_t certfile;
@@ -534,65 +540,68 @@
 			GNUTLS_TRACE( gnutls_x509_crt_deinit (certs[i]) );
 		}
 		free(certs);
+	
+		#ifdef GNUTLS_VERSION_300
+		/* Use certificate verification during the handshake */
+		gnutls_certificate_set_verify_function (fd_g_config->cnf_sec_data.credentials, fd_tls_verify_credentials_2);
+		#endif /* GNUTLS_VERSION_300 */
+
 	}
 	
-	
 	/* gnutls_certificate_set_verify_limits -- so far the default values are fine... */
 	
-	#ifdef GNUTLS_VERSION_300
-	/* Use certificate verification during the handshake */
-	gnutls_certificate_set_verify_function (fd_g_config->cnf_sec_data.credentials, fd_tls_verify_credentials_2);
-	#endif /* GNUTLS_VERSION_300 */
-	
 	/* DH */
-	if (fd_g_config->cnf_sec_data.dh_file) {
-		gnutls_datum_t dhparams = { NULL, 0 };
-		size_t alloc = 0;
-		FILE *stream = fopen (fd_g_config->cnf_sec_data.dh_file, "rb");
-		if (!stream) {
-			int err = errno;
-			TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s", fd_g_config->cnf_sec_data.dh_file, strerror(err));
-			return err; 
-		}
-		do {
-			uint8_t * realloced = NULL;
-			size_t read = 0;
-			
-			if (alloc < dhparams.size + BUFSIZ + 1) {
-				alloc += alloc / 2 + BUFSIZ + 1;
-				CHECK_MALLOC_DO( realloced = realloc(dhparams.data, alloc),
-					{
-						free(dhparams.data);
-						return ENOMEM;
-					} )
-				dhparams.data = realloced;
-			}
-			
-			read = fread( dhparams.data + dhparams.size, 1, alloc - dhparams.size - 1, stream );
-			dhparams.size += read;
-			
-			if (ferror(stream)) {
+	if (!fd_g_config->cnf_sec_data.tls_disabled) {
+		if (fd_g_config->cnf_sec_data.dh_file) {
+			gnutls_datum_t dhparams = { NULL, 0 };
+			size_t alloc = 0;
+			FILE *stream = fopen (fd_g_config->cnf_sec_data.dh_file, "rb");
+			if (!stream) {
 				int err = errno;
-				TRACE_DEBUG(INFO, "An error occurred while reading '%s': %s", fd_g_config->cnf_sec_data.dh_file, strerror(err));
+				TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s", fd_g_config->cnf_sec_data.dh_file, strerror(err));
 				return err; 
 			}
-		} while (!feof(stream));
-		dhparams.data[dhparams.size] = '\0';
-		fclose(stream);
-		CHECK_GNUTLS_DO( gnutls_dh_params_import_pkcs3( 
-					fd_g_config->cnf_sec_data.dh_cache,
-					&dhparams,
-					GNUTLS_X509_FMT_PEM),
-					 { TRACE_ERROR("Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
-		free(dhparams.data);
-		
-	} else {
-		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);
-		CHECK_GNUTLS_DO( gnutls_dh_params_generate2( 
-					fd_g_config->cnf_sec_data.dh_cache,
-					fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS),
-					 { TRACE_ERROR("Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
-	}			
+			do {
+				uint8_t * realloced = NULL;
+				size_t read = 0;
+
+				if (alloc < dhparams.size + BUFSIZ + 1) {
+					alloc += alloc / 2 + BUFSIZ + 1;
+					CHECK_MALLOC_DO( realloced = realloc(dhparams.data, alloc),
+						{
+							free(dhparams.data);
+							return ENOMEM;
+						} )
+					dhparams.data = realloced;
+				}
+
+				read = fread( dhparams.data + dhparams.size, 1, alloc - dhparams.size - 1, stream );
+				dhparams.size += read;
+
+				if (ferror(stream)) {
+					int err = errno;
+					TRACE_DEBUG(INFO, "An error occurred while reading '%s': %s", fd_g_config->cnf_sec_data.dh_file, strerror(err));
+					return err; 
+				}
+			} while (!feof(stream));
+			dhparams.data[dhparams.size] = '\0';
+			fclose(stream);
+			CHECK_GNUTLS_DO( gnutls_dh_params_import_pkcs3( 
+						fd_g_config->cnf_sec_data.dh_cache,
+						&dhparams,
+						GNUTLS_X509_FMT_PEM),
+						 { TRACE_ERROR("Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
+			free(dhparams.data);
+
+		} else {
+			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);
+			CHECK_GNUTLS_DO( gnutls_dh_params_generate2( 
+						fd_g_config->cnf_sec_data.dh_cache,
+						fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS),
+						 { TRACE_ERROR("Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
+		}			
+	
+	}
 	
 	return 0;
 }
--- a/libfdcore/p_ce.c	Mon May 27 17:22:40 2013 +0800
+++ b/libfdcore/p_ce.c	Tue May 28 12:11:27 2013 +0800
@@ -595,7 +595,14 @@
 	/* Do we need Inband-Security-Id AVPs ? If we're already using TLS, we don't... */
 	if (!fd_cnx_getTLS(cnx)) {
 		isi_none = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE; /* we add it even if the peer does not use the old mechanism, it is impossible to distinguish */
-		isi_tls  = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD;
+
+		if (peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD) {
+			if (fd_g_config->cnf_sec_data.tls_disabled) {
+				LOG_N("TLS disabled locally, so Inband-Security-Id (TLS) not included for peer %s", peer->p_hdr.info.pi_diamid);
+			} else {
+				isi_tls  = 1;
+			}
+		}
 	}
 	
 	/* Add the information about the local peer */
@@ -770,8 +777,13 @@
 			/* Ok for clear connection */
 			TRACE_DEBUG(INFO, "No TLS protection negotiated with peer '%s'.", peer->p_hdr.info.pi_diamid);
 			CHECK_FCT( fd_cnx_start_clear(peer->p_cnxctx, 1) );
+			
+		} else if (fd_g_config->cnf_sec_data.tls_disabled) {
+			LOG_E("Clear connection with remote peer '%s' is not (explicitly) allowed, and TLS is disabled. Giving up...", peer->p_hdr.info.pi_diamid);
+			fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "TLS is disabled and peer is not configured for IPsec", NULL);
+			goto cleanup;
+			
 		} else {
-			
 			fd_psm_change_state(peer, STATE_OPEN_HANDSHAKE);
 			CHECK_FCT_DO( fd_cnx_handshake(peer->p_cnxctx, GNUTLS_CLIENT, peer->p_hdr.info.config.pic_priority, NULL),
 				{
@@ -899,6 +911,9 @@
 				if ((peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE) && (peer->p_hdr.info.runtime.pir_isi & PI_SEC_NONE)) {
 					/* We have allowed IPsec */
 					isi = PI_SEC_NONE;
+				} else if (fd_g_config->cnf_sec_data.tls_disabled) {
+					/* We can agree on TLS */
+					TRACE_DEBUG(INFO, "Remote peer is not allowed for IPsec and TLS is disabled.");;
 				} else if (peer->p_hdr.info.runtime.pir_isi & PI_SEC_TLS_OLD) {
 					/* We can agree on TLS */
 					isi = PI_SEC_TLS_OLD;
--- a/libfdcore/p_cnx.c	Mon May 27 17:22:40 2013 +0800
+++ b/libfdcore/p_cnx.c	Tue May 28 12:11:27 2013 +0800
@@ -128,6 +128,14 @@
 		return 0;
 	}
 	
+	/* Check if we are able to communicate with this peer */
+	if (fd_g_config->cnf_sec_data.tls_disabled && ( peer->p_hdr.info.config.pic_flags.sec != PI_SEC_NONE)) {
+		LOG_E("Peer '%s' not configured for No_TLS and TLS is locally disabled; giving up connection attempts", 
+					peer->p_hdr.info.pi_diamid);
+		fd_psm_terminate( peer, NULL );
+		return 0;
+	}
+	
 	/* Cleanup any previous list */
 	empty_connection_list(peer);
 	
"Welcome to our mercurial repository"