Skip to content

Commit ac2dcca

Browse files
committed
Add GUC checks for ssl_min_protocol_version and ssl_max_protocol_version
Mixing incorrect bounds set in the SSL context leads to confusing error messages generated by OpenSSL which are hard to act on. New checks are added within the GUC machinery to improve the user experience as they apply to any SSL implementation, not only OpenSSL, and doing the checks beforehand avoids the creation of a SSL during a reload (or startup) which we know will never be used anyway. Backpatch down to 12, as those parameters have been introduced by e73e67c. Author: Michael Paquier Reviewed-by: Daniel Gustafsson Discussion: https://postgr.es/m/20200114035420.GE1515@paquier.xyz Backpatch-through: 12
1 parent 2e26460 commit ac2dcca

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

src/backend/utils/misc/guc.c

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ static bool check_cluster_name(char **newval, void **extra, GucSource source);
201201
static const char *show_unix_socket_permissions(void);
202202
static const char *show_log_file_mode(void);
203203
static const char *show_data_directory_mode(void);
204+
static bool check_ssl_min_protocol_version(int *newval, void **extra,
205+
GucSource source);
206+
static bool check_ssl_max_protocol_version(int *newval, void **extra,
207+
GucSource source);
204208
static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
205209
static void assign_recovery_target_timeline(const char *newval, void *extra);
206210
static bool check_recovery_target(char **newval, void **extra, GucSource source);
@@ -4522,7 +4526,7 @@ static struct config_enum ConfigureNamesEnum[] =
45224526
&ssl_min_protocol_version,
45234527
PG_TLS1_VERSION,
45244528
ssl_protocol_versions_info + 1, /* don't allow PG_TLS_ANY */
4525-
NULL, NULL, NULL
4529+
check_ssl_min_protocol_version, NULL, NULL
45264530
},
45274531

45284532
{
@@ -4534,7 +4538,7 @@ static struct config_enum ConfigureNamesEnum[] =
45344538
&ssl_max_protocol_version,
45354539
PG_TLS_ANY,
45364540
ssl_protocol_versions_info,
4537-
NULL, NULL, NULL
4541+
check_ssl_max_protocol_version, NULL, NULL
45384542
},
45394543

45404544
/* End-of-list marker */
@@ -11462,6 +11466,49 @@ show_data_directory_mode(void)
1146211466
return buf;
1146311467
}
1146411468

11469+
static bool
11470+
check_ssl_min_protocol_version(int *newval, void **extra, GucSource source)
11471+
{
11472+
int new_ssl_min_protocol_version = *newval;
11473+
11474+
/* PG_TLS_ANY is not supported for the minimum bound */
11475+
Assert(new_ssl_min_protocol_version > PG_TLS_ANY);
11476+
11477+
if (ssl_max_protocol_version &&
11478+
new_ssl_min_protocol_version > ssl_max_protocol_version)
11479+
{
11480+
GUC_check_errhint("\"%s\" cannot be higher than \"%s\".",
11481+
"ssl_min_protocol_version",
11482+
"ssl_max_protocol_version");
11483+
GUC_check_errcode(ERRCODE_INVALID_PARAMETER_VALUE);
11484+
return false;
11485+
}
11486+
11487+
return true;
11488+
}
11489+
11490+
static bool
11491+
check_ssl_max_protocol_version(int *newval, void **extra, GucSource source)
11492+
{
11493+
int new_ssl_max_protocol_version = *newval;
11494+
11495+
/* if PG_TLS_ANY, there is no need to check the bounds */
11496+
if (new_ssl_max_protocol_version == PG_TLS_ANY)
11497+
return true;
11498+
11499+
if (ssl_min_protocol_version &&
11500+
ssl_min_protocol_version > new_ssl_max_protocol_version)
11501+
{
11502+
GUC_check_errhint("\"%s\" cannot be lower than \"%s\".",
11503+
"ssl_max_protocol_version",
11504+
"ssl_min_protocol_version");
11505+
GUC_check_errcode(ERRCODE_INVALID_PARAMETER_VALUE);
11506+
return false;
11507+
}
11508+
11509+
return true;
11510+
}
11511+
1146511512
static bool
1146611513
check_recovery_target_timeline(char **newval, void **extra, GucSource source)
1146711514
{

src/test/ssl/t/001_ssltests.pl

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
if ($ENV{with_openssl} eq 'yes')
1515
{
16-
plan tests => 75;
16+
plan tests => 77;
1717
}
1818
else
1919
{
@@ -87,6 +87,24 @@
8787
'restart succeeds with password-protected key file');
8888
$node->_update_pid(1);
8989

90+
# Test compatibility of SSL protocols.
91+
# TLSv1.1 is lower than TLSv1.2, so it won't work.
92+
$node->append_conf(
93+
'postgresql.conf',
94+
qq{ssl_min_protocol_version='TLSv1.2'
95+
ssl_max_protocol_version='TLSv1.1'});
96+
command_fails(
97+
[ 'pg_ctl', '-D', $node->data_dir, '-l', $node->logfile, 'restart' ],
98+
'restart fails with incorrect SSL protocol bounds');
99+
# Go back to the defaults, this works.
100+
$node->append_conf(
101+
'postgresql.conf',
102+
qq{ssl_min_protocol_version='TLSv1'
103+
ssl_max_protocol_version=''});
104+
command_ok(
105+
[ 'pg_ctl', '-D', $node->data_dir, '-l', $node->logfile, 'restart' ],
106+
'restart succeeds with correct SSL protocol bounds');
107+
90108
### Run client-side tests.
91109
###
92110
### Test that libpq accepts/rejects the connection correctly, depending

src/test/ssl/t/SSLServer.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ sub configure_test_server_for_ssl
128128
print $conf "log_statement=all\n";
129129

130130
# enable SSL and set up server key
131-
print $conf "include 'sslconfig.conf'";
131+
print $conf "include 'sslconfig.conf'\n";
132132

133133
close $conf;
134134

0 commit comments

Comments
 (0)