mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Add settings to control SSL/TLS protocol version
For example:
    ssl_min_protocol_version = 'TLSv1.1'
    ssl_max_protocol_version = 'TLSv1.2'
Reviewed-by: Steve Singer <steve@ssinger.info>
Discussion: https://www.postgresql.org/message-id/flat/1822da87-b862-041a-9fc2-d0310c3da173@2ndquadrant.com
			
			
This commit is contained in:
		@@ -1291,6 +1291,50 @@ include_dir 'conf.d'
 | 
				
			|||||||
      </listitem>
 | 
					      </listitem>
 | 
				
			||||||
     </varlistentry>
 | 
					     </varlistentry>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     <varlistentry id="guc-ssl-min-protocol-version" xreflabel="ssl_min_protocol_version">
 | 
				
			||||||
 | 
					      <term><varname>ssl_min_protocol_version</varname> (<type>enum</type>)
 | 
				
			||||||
 | 
					      <indexterm>
 | 
				
			||||||
 | 
					       <primary><varname>ssl_min_protocol_version</varname> configuration parameter</primary>
 | 
				
			||||||
 | 
					      </indexterm>
 | 
				
			||||||
 | 
					      </term>
 | 
				
			||||||
 | 
					      <listitem>
 | 
				
			||||||
 | 
					       <para>
 | 
				
			||||||
 | 
					        Sets the minimum SSL/TLS protocol version to use.  Valid values are
 | 
				
			||||||
 | 
					        currently: <literal>TLSv1</literal>, <literal>TLSv1.1</literal>,
 | 
				
			||||||
 | 
					        <literal>TLSv1.2</literal>, <literal>TLSv1.3</literal>.  Older
 | 
				
			||||||
 | 
					        versions of the <productname>OpenSSL</productname> library do not
 | 
				
			||||||
 | 
					        support all values; an error will be raised if an unsupported setting
 | 
				
			||||||
 | 
					        is chosen.  Protocol versions before TLS 1.0, namely SSL version 2 and
 | 
				
			||||||
 | 
					        3, are always disabled.
 | 
				
			||||||
 | 
					       </para>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       <para>
 | 
				
			||||||
 | 
					        The default is <literal>TLSv1</literal>, mainly to support older
 | 
				
			||||||
 | 
					        versions of the <productname>OpenSSL</productname> library.  You might
 | 
				
			||||||
 | 
					        want to set this to a higher value if all software components can
 | 
				
			||||||
 | 
					        support the newer protocol versions.
 | 
				
			||||||
 | 
					       </para>
 | 
				
			||||||
 | 
					      </listitem>
 | 
				
			||||||
 | 
					     </varlistentry>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     <varlistentry id="guc-ssl-max-protocol-version" xreflabel="ssl_max_protocol_version">
 | 
				
			||||||
 | 
					      <term><varname>ssl_max_protocol_version</varname> (<type>enum</type>)
 | 
				
			||||||
 | 
					      <indexterm>
 | 
				
			||||||
 | 
					       <primary><varname>ssl_max_protocol_version</varname> configuration parameter</primary>
 | 
				
			||||||
 | 
					      </indexterm>
 | 
				
			||||||
 | 
					      </term>
 | 
				
			||||||
 | 
					      <listitem>
 | 
				
			||||||
 | 
					       <para>
 | 
				
			||||||
 | 
					        Sets the maximum SSL/TLS protocol version to use.  Valid values are as
 | 
				
			||||||
 | 
					        for <xref linkend="guc-ssl-min-protocol-version"/>, with addition of
 | 
				
			||||||
 | 
					        an empty string, which allows any protocol version.  The default is to
 | 
				
			||||||
 | 
					        allow any version.  Setting the maximum protocol version is mainly
 | 
				
			||||||
 | 
					        useful for testing or if some component has issues working with a
 | 
				
			||||||
 | 
					        newer protocol.
 | 
				
			||||||
 | 
					       </para>
 | 
				
			||||||
 | 
					      </listitem>
 | 
				
			||||||
 | 
					     </varlistentry>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     <varlistentry id="guc-ssl-dh-params-file" xreflabel="ssl_dh_params_file">
 | 
					     <varlistentry id="guc-ssl-dh-params-file" xreflabel="ssl_dh_params_file">
 | 
				
			||||||
      <term><varname>ssl_dh_params_file</varname> (<type>string</type>)
 | 
					      <term><varname>ssl_dh_params_file</varname> (<type>string</type>)
 | 
				
			||||||
      <indexterm>
 | 
					      <indexterm>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,6 +67,12 @@ static bool SSL_initialized = false;
 | 
				
			|||||||
static bool dummy_ssl_passwd_cb_called = false;
 | 
					static bool dummy_ssl_passwd_cb_called = false;
 | 
				
			||||||
static bool ssl_is_server_start;
 | 
					static bool ssl_is_server_start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ssl_protocol_version_to_openssl(int v, const char *guc_name);
 | 
				
			||||||
 | 
					#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
 | 
				
			||||||
 | 
					static int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version);
 | 
				
			||||||
 | 
					static int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ------------------------------------------------------------ */
 | 
					/* ------------------------------------------------------------ */
 | 
				
			||||||
/*						 Public interface						*/
 | 
					/*						 Public interface						*/
 | 
				
			||||||
@@ -183,8 +189,14 @@ be_tls_init(bool isServerStart)
 | 
				
			|||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* disallow SSL v2/v3 */
 | 
						if (ssl_min_protocol_version)
 | 
				
			||||||
	SSL_CTX_set_options(context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
 | 
							SSL_CTX_set_min_proto_version(context,
 | 
				
			||||||
 | 
														  ssl_protocol_version_to_openssl(ssl_min_protocol_version,
 | 
				
			||||||
 | 
																						  "ssl_min_protocol_version"));
 | 
				
			||||||
 | 
						if (ssl_max_protocol_version)
 | 
				
			||||||
 | 
							SSL_CTX_set_max_proto_version(context,
 | 
				
			||||||
 | 
														  ssl_protocol_version_to_openssl(ssl_max_protocol_version,
 | 
				
			||||||
 | 
																						  "ssl_max_protocol_version"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* disallow SSL session tickets */
 | 
						/* disallow SSL session tickets */
 | 
				
			||||||
#ifdef SSL_OP_NO_TICKET			/* added in OpenSSL 0.9.8f */
 | 
					#ifdef SSL_OP_NO_TICKET			/* added in OpenSSL 0.9.8f */
 | 
				
			||||||
@@ -1209,3 +1221,110 @@ X509_NAME_to_cstring(X509_NAME *name)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Convert TLS protocol version GUC enum to OpenSSL values
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is a straightforward one-to-one mapping, but doing it this way makes
 | 
				
			||||||
 | 
					 * guc.c independent of OpenSSL availability and version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If a version is passed that is not supported by the current OpenSSL
 | 
				
			||||||
 | 
					 * version, then we throw an error, so that subsequent code can assume it's
 | 
				
			||||||
 | 
					 * working with a supported version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					ssl_protocol_version_to_openssl(int v, const char *guc_name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (v)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							case PG_TLS_ANY:
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							case PG_TLS1_VERSION:
 | 
				
			||||||
 | 
								return TLS1_VERSION;
 | 
				
			||||||
 | 
							case PG_TLS1_1_VERSION:
 | 
				
			||||||
 | 
					#ifdef TLS1_1_VERSION
 | 
				
			||||||
 | 
								return TLS1_1_VERSION;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							case PG_TLS1_2_VERSION:
 | 
				
			||||||
 | 
					#ifdef TLS1_2_VERSION
 | 
				
			||||||
 | 
								return TLS1_2_VERSION;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							case PG_TLS1_3_VERSION:
 | 
				
			||||||
 | 
					#ifdef TLS1_3_VERSION
 | 
				
			||||||
 | 
								return TLS1_3_VERSION;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
						pg_attribute_unused();
 | 
				
			||||||
 | 
						ereport(ERROR,
 | 
				
			||||||
 | 
								(errmsg("%s setting %s not supported by this build",
 | 
				
			||||||
 | 
										guc_name,
 | 
				
			||||||
 | 
										GetConfigOption(guc_name, false, false))));
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Replacements for APIs present in newer versions of OpenSSL
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * OpenSSL versions that support TLS 1.3 shouldn't get here because they
 | 
				
			||||||
 | 
					 * already have these functions.  So we don't have to keep updating the below
 | 
				
			||||||
 | 
					 * code for every new TLS version, and eventually it can go away.  But let's
 | 
				
			||||||
 | 
					 * just check this to make sure ...
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifdef TLS1_3_VERSION
 | 
				
			||||||
 | 
					#error OpenSSL version mismatch
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int			ssl_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (version > TLS1_VERSION)
 | 
				
			||||||
 | 
							ssl_options |= SSL_OP_NO_TLSv1;
 | 
				
			||||||
 | 
					#ifdef TLS1_1_VERSION
 | 
				
			||||||
 | 
						if (version > TLS1_1_VERSION)
 | 
				
			||||||
 | 
							ssl_options |= SSL_OP_NO_TLSv1_1;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef TLS1_2_VERSION
 | 
				
			||||||
 | 
						if (version > TLS1_2_VERSION)
 | 
				
			||||||
 | 
							ssl_options |= SSL_OP_NO_TLSv1_2;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSL_CTX_set_options(ctx, ssl_options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 1;					/* success */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int			ssl_options = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AssertArg(version != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TLS1_1_VERSION
 | 
				
			||||||
 | 
						if (version < TLS1_1_VERSION)
 | 
				
			||||||
 | 
							ssl_options |= SSL_OP_NO_TLSv1_1;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef TLS1_2_VERSION
 | 
				
			||||||
 | 
						if (version < TLS1_2_VERSION)
 | 
				
			||||||
 | 
							ssl_options |= SSL_OP_NO_TLSv1_2;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSL_CTX_set_options(ctx, ssl_options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 1;					/* success */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif							/* OPENSSL_VERSION_NUMBER */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,6 +60,9 @@ char	   *SSLECDHCurve;
 | 
				
			|||||||
/* GUC variable: if false, prefer client ciphers */
 | 
					/* GUC variable: if false, prefer client ciphers */
 | 
				
			||||||
bool		SSLPreferServerCiphers;
 | 
					bool		SSLPreferServerCiphers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int			ssl_min_protocol_version;
 | 
				
			||||||
 | 
					int			ssl_max_protocol_version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ------------------------------------------------------------ */
 | 
					/* ------------------------------------------------------------ */
 | 
				
			||||||
/*			 Procedures common to all secure sessions			*/
 | 
					/*			 Procedures common to all secure sessions			*/
 | 
				
			||||||
/* ------------------------------------------------------------ */
 | 
					/* ------------------------------------------------------------ */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -428,6 +428,15 @@ static const struct config_enum_entry password_encryption_options[] = {
 | 
				
			|||||||
	{NULL, 0, false}
 | 
						{NULL, 0, false}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct config_enum_entry ssl_protocol_versions_info[] = {
 | 
				
			||||||
 | 
						{"", PG_TLS_ANY, false},
 | 
				
			||||||
 | 
						{"TLSv1", PG_TLS1_VERSION, false},
 | 
				
			||||||
 | 
						{"TLSv1.1", PG_TLS1_1_VERSION, false},
 | 
				
			||||||
 | 
						{"TLSv1.2", PG_TLS1_2_VERSION, false},
 | 
				
			||||||
 | 
						{"TLSv1.3", PG_TLS1_3_VERSION, false},
 | 
				
			||||||
 | 
						{NULL, 0, false}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Options for enum values stored in other modules
 | 
					 * Options for enum values stored in other modules
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -4193,6 +4202,30 @@ static struct config_enum ConfigureNamesEnum[] =
 | 
				
			|||||||
		NULL, NULL, NULL
 | 
							NULL, NULL, NULL
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							{"ssl_min_protocol_version", PGC_SIGHUP, CONN_AUTH_SSL,
 | 
				
			||||||
 | 
								gettext_noop("Sets the minimum SSL/TLS protocol version to use."),
 | 
				
			||||||
 | 
								NULL,
 | 
				
			||||||
 | 
								GUC_SUPERUSER_ONLY
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							&ssl_min_protocol_version,
 | 
				
			||||||
 | 
							PG_TLS1_VERSION,
 | 
				
			||||||
 | 
							ssl_protocol_versions_info + 1 /* don't allow PG_TLS_ANY */,
 | 
				
			||||||
 | 
							NULL, NULL, NULL
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							{"ssl_max_protocol_version", PGC_SIGHUP, CONN_AUTH_SSL,
 | 
				
			||||||
 | 
								gettext_noop("Sets the maximum SSL/TLS protocol version to use."),
 | 
				
			||||||
 | 
								NULL,
 | 
				
			||||||
 | 
								GUC_SUPERUSER_ONLY
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							&ssl_max_protocol_version,
 | 
				
			||||||
 | 
							PG_TLS_ANY,
 | 
				
			||||||
 | 
							ssl_protocol_versions_info,
 | 
				
			||||||
 | 
							NULL, NULL, NULL
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* End-of-list marker */
 | 
						/* End-of-list marker */
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		{NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL
 | 
							{NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,6 +103,8 @@
 | 
				
			|||||||
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
 | 
					#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
 | 
				
			||||||
#ssl_prefer_server_ciphers = on
 | 
					#ssl_prefer_server_ciphers = on
 | 
				
			||||||
#ssl_ecdh_curve = 'prime256v1'
 | 
					#ssl_ecdh_curve = 'prime256v1'
 | 
				
			||||||
 | 
					#ssl_min_protocol_version = 'TLSv1'
 | 
				
			||||||
 | 
					#ssl_max_protocol_version = ''
 | 
				
			||||||
#ssl_dh_params_file = ''
 | 
					#ssl_dh_params_file = ''
 | 
				
			||||||
#ssl_passphrase_command = ''
 | 
					#ssl_passphrase_command = ''
 | 
				
			||||||
#ssl_passphrase_command_supports_reload = off
 | 
					#ssl_passphrase_command_supports_reload = off
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -102,6 +102,17 @@ extern WaitEventSet *FeBeWaitSet;
 | 
				
			|||||||
extern char *SSLCipherSuites;
 | 
					extern char *SSLCipherSuites;
 | 
				
			||||||
extern char *SSLECDHCurve;
 | 
					extern char *SSLECDHCurve;
 | 
				
			||||||
extern bool SSLPreferServerCiphers;
 | 
					extern bool SSLPreferServerCiphers;
 | 
				
			||||||
 | 
					extern int	ssl_min_protocol_version;
 | 
				
			||||||
 | 
					extern int	ssl_max_protocol_version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum ssl_protocol_versions
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						PG_TLS_ANY = 0,
 | 
				
			||||||
 | 
						PG_TLS1_VERSION,
 | 
				
			||||||
 | 
						PG_TLS1_1_VERSION,
 | 
				
			||||||
 | 
						PG_TLS1_2_VERSION,
 | 
				
			||||||
 | 
						PG_TLS1_3_VERSION,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * prototypes for functions in be-secure-common.c
 | 
					 * prototypes for functions in be-secure-common.c
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user