mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-12 18:34:36 +08: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:
parent
2d9140ed26
commit
e73e67c719
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user