From 0e826d71930a09cb00e1b7ec55aeac92612bcd4f Mon Sep 17 00:00:00 2001 From: Daniel Gustafsson Date: Wed, 19 May 2021 15:04:37 +0200 Subject: [PATCH v2 2/2] Add tests for sslinfo This adds rudimentary coverage of the sslinfo extension into the SSL test harness. The output is validated by comparing with pg_stat_ssl to provide some level of test stability should the underlying certs be slightly altered. --- src/test/ssl/Makefile | 2 + src/test/ssl/t/003_sslinfo.pl | 129 ++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 src/test/ssl/t/003_sslinfo.pl diff --git a/src/test/ssl/Makefile b/src/test/ssl/Makefile index a517756c94..3699b9fc78 100644 --- a/src/test/ssl/Makefile +++ b/src/test/ssl/Makefile @@ -9,6 +9,8 @@ # #------------------------------------------------------------------------- +EXTRA_INSTALL = contrib/sslinfo + subdir = src/test/ssl top_builddir = ../../.. include $(top_builddir)/src/Makefile.global diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl new file mode 100644 index 0000000000..2c0f7d27fa --- /dev/null +++ b/src/test/ssl/t/003_sslinfo.pl @@ -0,0 +1,129 @@ + +# Copyright (c) 2021, PostgreSQL Global Development Group + +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More; + +use File::Copy; + +use FindBin; +use lib $FindBin::RealBin; + +use SSLServer; + +if ($ENV{with_ssl} ne 'openssl') +{ + plan skip_all => 'OpenSSL not supported by this build'; +} +else +{ + plan tests => 11; +} + +#### Some configuration + +# This is the hostname used to connect to the server. This cannot be a +# hostname, because the server certificate is always for the domain +# postgresql-ssl-regression.test. +my $SERVERHOSTADDR = '127.0.0.1'; +# This is the pattern to use in pg_hba.conf to match incoming connections. +my $SERVERHOSTCIDR = '127.0.0.1/32'; + +# Allocation of base connection string shared among multiple tests. +my $common_connstr; + +# The client's private key must not be world-readable, so take a copy +# of the key stored in the code tree and update its permissions. +# +# This changes ssl/client.key to ssl/client_tmp.key etc for the rest +# of the tests. +copy("ssl/client.key", "ssl/client_tmp.key") + or die "couldn't copy ssl/client.key to ssl/client_tmp.key for permissions change: $!"; +chmod 0600, "ssl/client_tmp.key" + or die "failed to change permissions on ssl/client_tmp.key: $!"; + +#### Set up the server. + +note "setting up data directory"; +my $node = get_new_node('primary'); +$node->init; + +# PGHOST is enforced here to set up the node, subsequent connections +# will use a dedicated connection string. +$ENV{PGHOST} = $node->host; +$ENV{PGPORT} = $node->port; +$node->start; + +configure_test_server_for_ssl($node, $SERVERHOSTADDR, $SERVERHOSTCIDR, + 'trust', extensions => [ qw(sslinfo) ]); + +# We aren't using any CRL's in this suite so we can keep using server-revoked +# as server certificate for simple client.crt connection much like how the +# 001 test does. +switch_server_cert($node, 'server-revoked'); + +$common_connstr = + "sslrootcert=ssl/root+server_ca.crt sslmode=require dbname=certdb hostaddr=$SERVERHOSTADDR " . + "user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key"; + +# Make sure we can connect even though previous test suites have established this +$node->connect_ok( + $common_connstr, + "certificate authorization succeeds with correct client cert in PEM format", +); + +my $result; + +$result = $node->safe_psql("certdb", "SELECT ssl_is_used();", + connstr => $common_connstr); +is($result, 't', "ssl_is_used() for TLS connection"); + +$result = $node->safe_psql("certdb", "SELECT ssl_version();", + connstr => $common_connstr . " ssl_min_protocol_version=TLSv1.2 " . + "ssl_max_protocol_version=TLSv1.2"); +is($result, 'TLSv1.2', "ssl_version() correctly returning TLS protocol"); + +$result = $node->safe_psql("certdb", + "SELECT ssl_cipher() = cipher FROM pg_stat_ssl WHERE pid = pg_backend_pid();", + connstr => $common_connstr); +is($result, 't', "ssl_cipher() compared with pg_stat_ssl"); + +$result = $node->safe_psql("certdb", "SELECT ssl_client_cert_present();", + connstr => $common_connstr); +is($result, 't', "ssl_client_cert_present() for connection with cert"); + +$result = $node->safe_psql("trustdb", "SELECT ssl_client_cert_present();", + connstr => "sslrootcert=ssl/root+server_ca.crt sslmode=require " . + "dbname=trustdb hostaddr=$SERVERHOSTADDR user=ssltestuser"); +is($result, 'f', "ssl_client_cert_present() for connection without cert"); + +$result = $node->safe_psql("certdb", + "SELECT ssl_client_serial() = client_serial FROM pg_stat_ssl WHERE pid = pg_backend_pid();", + connstr => $common_connstr); +is($result, 't', "ssl_client_serial() compared with pg_stat_ssl"); + +# Must not use safe_psql since we expect an error here +$result = $node->psql("certdb", "SELECT ssl_client_dn_field('invalid');", + connstr => $common_connstr); +is($result, '3', "ssl_client_dn_field() for an invalid field"); + +$result = $node->safe_psql("trustdb", "SELECT ssl_client_dn_field('commonName');", + connstr => "sslrootcert=ssl/root+server_ca.crt sslmode=require " . + "dbname=trustdb hostaddr=$SERVERHOSTADDR user=ssltestuser"); +is($result, '', "ssl_client_dn_field() for connection without cert"); + +$result = $node->safe_psql("certdb", + "SELECT '/CN=' || ssl_client_dn_field('commonName') = client_dn FROM pg_stat_ssl WHERE pid = pg_backend_pid();", + connstr => $common_connstr); +is($result, 't', "ssl_client_dn_field() for commonName"); + +$result = $node->safe_psql("certdb", + "SELECT ssl_issuer_dn() = issuer_dn FROM pg_stat_ssl WHERE pid = pg_backend_pid();", + connstr => $common_connstr); +is($result, 't', "ssl_issuer_dn() for connection with cert"); + +# Clean up +unlink("ssl/client_tmp.key"); -- 2.30.1 (Apple Git-130)