Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e73e67c

Browse files
committed
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
1 parent 2d9140e commit e73e67c

File tree

6 files changed

+214
-2
lines changed

6 files changed

+214
-2
lines changed

doc/src/sgml/config.sgml

+44
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,50 @@ include_dir 'conf.d'
12911291
</listitem>
12921292
</varlistentry>
12931293

1294+
<varlistentry id="guc-ssl-min-protocol-version" xreflabel="ssl_min_protocol_version">
1295+
<term><varname>ssl_min_protocol_version</varname> (<type>enum</type>)
1296+
<indexterm>
1297+
<primary><varname>ssl_min_protocol_version</varname> configuration parameter</primary>
1298+
</indexterm>
1299+
</term>
1300+
<listitem>
1301+
<para>
1302+
Sets the minimum SSL/TLS protocol version to use. Valid values are
1303+
currently: <literal>TLSv1</literal>, <literal>TLSv1.1</literal>,
1304+
<literal>TLSv1.2</literal>, <literal>TLSv1.3</literal>. Older
1305+
versions of the <productname>OpenSSL</productname> library do not
1306+
support all values; an error will be raised if an unsupported setting
1307+
is chosen. Protocol versions before TLS 1.0, namely SSL version 2 and
1308+
3, are always disabled.
1309+
</para>
1310+
1311+
<para>
1312+
The default is <literal>TLSv1</literal>, mainly to support older
1313+
versions of the <productname>OpenSSL</productname> library. You might
1314+
want to set this to a higher value if all software components can
1315+
support the newer protocol versions.
1316+
</para>
1317+
</listitem>
1318+
</varlistentry>
1319+
1320+
<varlistentry id="guc-ssl-max-protocol-version" xreflabel="ssl_max_protocol_version">
1321+
<term><varname>ssl_max_protocol_version</varname> (<type>enum</type>)
1322+
<indexterm>
1323+
<primary><varname>ssl_max_protocol_version</varname> configuration parameter</primary>
1324+
</indexterm>
1325+
</term>
1326+
<listitem>
1327+
<para>
1328+
Sets the maximum SSL/TLS protocol version to use. Valid values are as
1329+
for <xref linkend="guc-ssl-min-protocol-version"/>, with addition of
1330+
an empty string, which allows any protocol version. The default is to
1331+
allow any version. Setting the maximum protocol version is mainly
1332+
useful for testing or if some component has issues working with a
1333+
newer protocol.
1334+
</para>
1335+
</listitem>
1336+
</varlistentry>
1337+
12941338
<varlistentry id="guc-ssl-dh-params-file" xreflabel="ssl_dh_params_file">
12951339
<term><varname>ssl_dh_params_file</varname> (<type>string</type>)
12961340
<indexterm>

src/backend/libpq/be-secure-openssl.c

+121-2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ static bool SSL_initialized = false;
6767
static bool dummy_ssl_passwd_cb_called = false;
6868
static bool ssl_is_server_start;
6969

70+
static int ssl_protocol_version_to_openssl(int v, const char *guc_name);
71+
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
72+
static int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version);
73+
static int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version);
74+
#endif
75+
7076

7177
/* ------------------------------------------------------------ */
7278
/* Public interface */
@@ -183,8 +189,14 @@ be_tls_init(bool isServerStart)
183189
goto error;
184190
}
185191

186-
/* disallow SSL v2/v3 */
187-
SSL_CTX_set_options(context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
192+
if (ssl_min_protocol_version)
193+
SSL_CTX_set_min_proto_version(context,
194+
ssl_protocol_version_to_openssl(ssl_min_protocol_version,
195+
"ssl_min_protocol_version"));
196+
if (ssl_max_protocol_version)
197+
SSL_CTX_set_max_proto_version(context,
198+
ssl_protocol_version_to_openssl(ssl_max_protocol_version,
199+
"ssl_max_protocol_version"));
188200

189201
/* disallow SSL session tickets */
190202
#ifdef SSL_OP_NO_TICKET /* added in OpenSSL 0.9.8f */
@@ -1209,3 +1221,110 @@ X509_NAME_to_cstring(X509_NAME *name)
12091221

12101222
return result;
12111223
}
1224+
1225+
/*
1226+
* Convert TLS protocol version GUC enum to OpenSSL values
1227+
*
1228+
* This is a straightforward one-to-one mapping, but doing it this way makes
1229+
* guc.c independent of OpenSSL availability and version.
1230+
*
1231+
* If a version is passed that is not supported by the current OpenSSL
1232+
* version, then we throw an error, so that subsequent code can assume it's
1233+
* working with a supported version.
1234+
*/
1235+
static int
1236+
ssl_protocol_version_to_openssl(int v, const char *guc_name)
1237+
{
1238+
switch (v)
1239+
{
1240+
case PG_TLS_ANY:
1241+
return 0;
1242+
case PG_TLS1_VERSION:
1243+
return TLS1_VERSION;
1244+
case PG_TLS1_1_VERSION:
1245+
#ifdef TLS1_1_VERSION
1246+
return TLS1_1_VERSION;
1247+
#else
1248+
goto error;
1249+
#endif
1250+
case PG_TLS1_2_VERSION:
1251+
#ifdef TLS1_2_VERSION
1252+
return TLS1_2_VERSION;
1253+
#else
1254+
goto error;
1255+
#endif
1256+
case PG_TLS1_3_VERSION:
1257+
#ifdef TLS1_3_VERSION
1258+
return TLS1_3_VERSION;
1259+
#else
1260+
goto error;
1261+
#endif
1262+
}
1263+
1264+
error:
1265+
pg_attribute_unused();
1266+
ereport(ERROR,
1267+
(errmsg("%s setting %s not supported by this build",
1268+
guc_name,
1269+
GetConfigOption(guc_name, false, false))));
1270+
return -1;
1271+
}
1272+
1273+
/*
1274+
* Replacements for APIs present in newer versions of OpenSSL
1275+
*/
1276+
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
1277+
1278+
/*
1279+
* OpenSSL versions that support TLS 1.3 shouldn't get here because they
1280+
* already have these functions. So we don't have to keep updating the below
1281+
* code for every new TLS version, and eventually it can go away. But let's
1282+
* just check this to make sure ...
1283+
*/
1284+
#ifdef TLS1_3_VERSION
1285+
#error OpenSSL version mismatch
1286+
#endif
1287+
1288+
static int
1289+
SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version)
1290+
{
1291+
int ssl_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
1292+
1293+
if (version > TLS1_VERSION)
1294+
ssl_options |= SSL_OP_NO_TLSv1;
1295+
#ifdef TLS1_1_VERSION
1296+
if (version > TLS1_1_VERSION)
1297+
ssl_options |= SSL_OP_NO_TLSv1_1;
1298+
#endif
1299+
#ifdef TLS1_2_VERSION
1300+
if (version > TLS1_2_VERSION)
1301+
ssl_options |= SSL_OP_NO_TLSv1_2;
1302+
#endif
1303+
1304+
SSL_CTX_set_options(ctx, ssl_options);
1305+
1306+
return 1; /* success */
1307+
}
1308+
1309+
static int
1310+
SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version)
1311+
{
1312+
int ssl_options = 0;
1313+
1314+
AssertArg(version != 0);
1315+
1316+
#ifdef TLS1_1_VERSION
1317+
if (version < TLS1_1_VERSION)
1318+
ssl_options |= SSL_OP_NO_TLSv1_1;
1319+
#endif
1320+
#ifdef TLS1_2_VERSION
1321+
if (version < TLS1_2_VERSION)
1322+
ssl_options |= SSL_OP_NO_TLSv1_2;
1323+
#endif
1324+
1325+
SSL_CTX_set_options(ctx, ssl_options);
1326+
1327+
return 1; /* success */
1328+
}
1329+
1330+
#endif /* OPENSSL_VERSION_NUMBER */

src/backend/libpq/be-secure.c

+3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ char *SSLECDHCurve;
6060
/* GUC variable: if false, prefer client ciphers */
6161
bool SSLPreferServerCiphers;
6262

63+
int ssl_min_protocol_version;
64+
int ssl_max_protocol_version;
65+
6366
/* ------------------------------------------------------------ */
6467
/* Procedures common to all secure sessions */
6568
/* ------------------------------------------------------------ */

src/backend/utils/misc/guc.c

+33
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,15 @@ static const struct config_enum_entry password_encryption_options[] = {
428428
{NULL, 0, false}
429429
};
430430

431+
const struct config_enum_entry ssl_protocol_versions_info[] = {
432+
{"", PG_TLS_ANY, false},
433+
{"TLSv1", PG_TLS1_VERSION, false},
434+
{"TLSv1.1", PG_TLS1_1_VERSION, false},
435+
{"TLSv1.2", PG_TLS1_2_VERSION, false},
436+
{"TLSv1.3", PG_TLS1_3_VERSION, false},
437+
{NULL, 0, false}
438+
};
439+
431440
/*
432441
* Options for enum values stored in other modules
433442
*/
@@ -4193,6 +4202,30 @@ static struct config_enum ConfigureNamesEnum[] =
41934202
NULL, NULL, NULL
41944203
},
41954204

4205+
{
4206+
{"ssl_min_protocol_version", PGC_SIGHUP, CONN_AUTH_SSL,
4207+
gettext_noop("Sets the minimum SSL/TLS protocol version to use."),
4208+
NULL,
4209+
GUC_SUPERUSER_ONLY
4210+
},
4211+
&ssl_min_protocol_version,
4212+
PG_TLS1_VERSION,
4213+
ssl_protocol_versions_info + 1 /* don't allow PG_TLS_ANY */,
4214+
NULL, NULL, NULL
4215+
},
4216+
4217+
{
4218+
{"ssl_max_protocol_version", PGC_SIGHUP, CONN_AUTH_SSL,
4219+
gettext_noop("Sets the maximum SSL/TLS protocol version to use."),
4220+
NULL,
4221+
GUC_SUPERUSER_ONLY
4222+
},
4223+
&ssl_max_protocol_version,
4224+
PG_TLS_ANY,
4225+
ssl_protocol_versions_info,
4226+
NULL, NULL, NULL
4227+
},
4228+
41964229
/* End-of-list marker */
41974230
{
41984231
{NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL

src/backend/utils/misc/postgresql.conf.sample

+2
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@
103103
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
104104
#ssl_prefer_server_ciphers = on
105105
#ssl_ecdh_curve = 'prime256v1'
106+
#ssl_min_protocol_version = 'TLSv1'
107+
#ssl_max_protocol_version = ''
106108
#ssl_dh_params_file = ''
107109
#ssl_passphrase_command = ''
108110
#ssl_passphrase_command_supports_reload = off

src/include/libpq/libpq.h

+11
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,17 @@ extern WaitEventSet *FeBeWaitSet;
102102
extern char *SSLCipherSuites;
103103
extern char *SSLECDHCurve;
104104
extern bool SSLPreferServerCiphers;
105+
extern int ssl_min_protocol_version;
106+
extern int ssl_max_protocol_version;
107+
108+
enum ssl_protocol_versions
109+
{
110+
PG_TLS_ANY = 0,
111+
PG_TLS1_VERSION,
112+
PG_TLS1_1_VERSION,
113+
PG_TLS1_2_VERSION,
114+
PG_TLS1_3_VERSION,
115+
};
105116

106117
/*
107118
* prototypes for functions in be-secure-common.c

0 commit comments

Comments
 (0)