Add TAP tests for contrib/sslinfo
authorDaniel Gustafsson <dgustafsson@postgresql.org>
Tue, 30 Nov 2021 10:19:59 +0000 (11:19 +0100)
committerDaniel Gustafsson <dgustafsson@postgresql.org>
Tue, 30 Nov 2021 10:19:59 +0000 (11:19 +0100)
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.  A new cert is added to provide an extension to
test against.

Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andrew Dunstan <andrew@dunslane.net>
Reviewed-by: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
Discussion: https://postgr.es/m/E23F9811-0C77-45DA-912F-D809AB140741@yesql.se

src/test/ssl/Makefile
src/test/ssl/README
src/test/ssl/conf/client_ext.config [new file with mode: 0644]
src/test/ssl/ssl/client_ext.crt [new file with mode: 0644]
src/test/ssl/ssl/client_ext.key [new file with mode: 0644]
src/test/ssl/sslfiles.mk
src/test/ssl/t/003_sslinfo.pl [new file with mode: 0644]

index cb24e31c6e265581f191515ca21d57e7930d19e7..b7493833481709bad57b86287644739349b64889 100644 (file)
@@ -9,6 +9,8 @@
 #
 #-------------------------------------------------------------------------
 
+EXTRA_INSTALL = contrib/sslinfo
+
 subdir = src/test/ssl
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
index 9e2cedc0dda57a26a94d0e1c845798fd203a8a11..7e6070065204527b8dccee9dcedf1191e552438a 100644 (file)
@@ -16,6 +16,8 @@ Running the tests
 =================
 
 NOTE: You must have given the --enable-tap-tests argument to configure.
+Also, to use "make installcheck", you must have built and installed
+contrib/sslinfo in addition to the core code.
 
 Run
     make check
diff --git a/src/test/ssl/conf/client_ext.config b/src/test/ssl/conf/client_ext.config
new file mode 100644 (file)
index 0000000..c2dbfef
--- /dev/null
@@ -0,0 +1,16 @@
+# An OpenSSL format CSR config file for creating a client certificate.
+#
+# The certificate is for user "ssltestuser" and intends to test client
+# certificate with extensions.
+
+[ req ]
+distinguished_name     = req_distinguished_name
+req_extensions         = client_ext
+prompt                 = no
+
+[ req_distinguished_name ]
+CN                     = ssltestuser
+
+[ client_ext ]
+basicConstraints         = critical,CA:false
+extendedKeyUsage         = clientAuth
diff --git a/src/test/ssl/ssl/client_ext.crt b/src/test/ssl/ssl/client_ext.crt
new file mode 100644 (file)
index 0000000..9874ce4
--- /dev/null
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDezCCAmOgAwIBAgIIICEREAQyQQAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IGNs
+aWVudCBjZXJ0czAeFw0yMTExMTAwMzMyNDFaFw00OTAzMjgwMzMyNDFaMBYxFDAS
+BgNVBAMMC3NzbHRlc3R1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEArCHikkEQLFITbn3ZfO8X2RW3fELeaImgy8W4Pkkc4LxdHCWjdCML/vtE/ZVu
+Op74qrQQWT0HKXFVUiZLbjAgV2PONS6VFHhc3sTFxuTaBnVdY+K98hoFnXskINt/
+wgwUhRcRZuKPcZvEHiqF6e3g3lQa99l1nVKPGPLOCvVhSgoV0Gwgxok0t7s25BCV
+ZmpMAwSTxpeviLF0e2MsttuyClQ4nuD92EHZX3BuG0WNPLxiwikV96uMffpMRGsx
+uiAHzD5ykYM7/b3eU0bjfi0J0qcfTSeytqFuRCNEukJpmtUmyYGqsFJ7HN7ejCY7
+ObAlBn8h+4bgwBRaeZDZLTMaYQIDAQABo4GgMIGdMAwGA1UdEwEB/wQCMAAwEwYD
+VR0lBAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFPPv1n7k1Vd9BBC4eoGWPZwVz2Lx
+MFkGA1UdIwRSMFChRKRCMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBmb3IgUG9z
+dGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlggggIQMDFBIHATANBgkq
+hkiG9w0BAQsFAAOCAQEAtqIeTmUhtHyCt5k2yx88F0dKshYq4Z+LQI+agyZ1fRE6
+Ux5p+SBGbzvc+NcUvc7yGG6w2G/nTVnGwSHN9NtQa2T2XbHJysJ/dwCfmRsachKz
+4kCp0zAHEDrEmZua0sy5BLwwVCk5WNBR0lZ35WmIEuRA+5G/2lCywtrb9W4YnbAM
+nH7BtZE8qPbK4OicB40I2NXz6KhG3755oKN03VC1IaX9JFQxf37ac7jVK5bsjfaF
+0xCAeuDN6wDiVHZj6q1GhhmNLzaF5zmU2e/cI1nTI5tfGKnygavlZIz2VvAlcypt
+YZdMDy69VbTWUa57UPCspghgvm5M2/Hjmz50CXGMvw==
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client_ext.key b/src/test/ssl/ssl/client_ext.key
new file mode 100644 (file)
index 0000000..04e5930
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCsIeKSQRAsUhNu
+fdl87xfZFbd8Qt5oiaDLxbg+SRzgvF0cJaN0Iwv++0T9lW46nviqtBBZPQcpcVVS
+JktuMCBXY841LpUUeFzexMXG5NoGdV1j4r3yGgWdeyQg23/CDBSFFxFm4o9xm8Qe
+KoXp7eDeVBr32XWdUo8Y8s4K9WFKChXQbCDGiTS3uzbkEJVmakwDBJPGl6+IsXR7
+Yyy227IKVDie4P3YQdlfcG4bRY08vGLCKRX3q4x9+kxEazG6IAfMPnKRgzv9vd5T
+RuN+LQnSpx9NJ7K2oW5EI0S6Qmma1SbJgaqwUnsc3t6MJjs5sCUGfyH7huDAFFp5
+kNktMxphAgMBAAECggEAQlVWkmUHXgUNHvXZo8chyhMP4A+G1QNAl3Zs73fObJ66
+RPgOOtmsrEjZh92XmnibvHDiofkeMu7NYfiG9gIO3I6GL0Fxyu8tXt22l9SmXnnJ
+EQ6Wg19azZrgS9c6ryVnnPhMSPlDLRVJaRSbAZCdqSABOoUvSX7AzWz4UQnJwbVp
+c9Le7DbXcD4IIhi+D2o6k46oGTm+P8kEAbw73tN7NmxBudwMhvGup3HlDNypbwPJ
+0aWR+nxZbaAVnmYiENX7L68R9rweqDES8AgV030L4YF022C8TAuBLeCjuEQucdp4
++ZcNUzAF2G1NN/VUpjBKK08+Pu0C0vV+fDrKWK+QnwKBgQC74THLylX/+7TJC24U
+LXu/z5BjkejUr4GLHTZG9edGgaoSiKikXdseCI/RiDVXvtQ7kstFYflOZ+XGuc4l
+GVAN52uRqg7uXw0R8F8bKpal08j4Rhe4rXKvH5h9hSeozOlxq7jrQ2xk96Guu3k7
+ujqkkVoPX+dnwUVN6elWrMIUpwKBgQDqiwqaKk7Pmkqc5et4WKvKFLKYuTU/qOO6
+fVEqGlgbLGNf+DVgKcTl5AVyhqtedh1hin0ij/dDHoYOmynmbe/zguSxF7kYUxdJ
+STwWpQt/ccaWMfqgrjxXpWsPc1fRWgmACAaum04GXmBeZ4z0rVT4blwAVddgoLL8
+q4lrSNbRtwKBgQClv4jnyaxPNecLCmtln66xzFMMlJe8ssztRqswtRYA7Ll2ultV
+DnwVpeYDK1AsBe1EVT/BCSshEaXzyM3lisxGR+htTIL5pp9oORAeblcTGqEM7wFU
+aqhneM9VxRf04jn8j0uHOicxeAmKllfg6m1768NxFuGWdjpG/1pcnfJmtwKBgAF8
+Nen6AJvB710E+7O8ZAIYlXTwH00y5ZZFuuDYX9x0MIDoEnZ0bUHDauFpxuYHO3Jl
+rRst7DPpmpG3G9HQumdBWe9hJhPoWsplA1NlYihBcS98S4j+8XTgoEftxA2YU10T
+L++lHh5eNKAEadkWy+Xy1PRPltiOy/NbprgeMvYLAoGAKpt7DHcK8B0JdOnEzTuz
+7mT6xRt2C9IASCiv92Fx1BPiPy4l9ukT4CJza/wpSpH3xyeB37afe0kQyU8lDrCF
+iMU3RNTzTftwqO8GgtgntgW8ZKe9fuqzm9VLMQFyL+zdqEfGG6ROS8ipYLx9pn6x
+FHc3UsmLmK0hfCr9B4Yo+C0=
+-----END PRIVATE KEY-----
index 81c20aac9ef3f0cf0d99cf0edba72f278eb98d78..270f55a58f62c9f9cb87d213eab0d9e3b6ebeec3 100644 (file)
@@ -27,7 +27,7 @@ SERVERS := server-cn-and-alt-names \
    server-multiple-alt-names \
    server-no-names \
    server-revoked
-CLIENTS := client client-dn client-revoked
+CLIENTS := client client-dn client-revoked client_ext
 
 #
 # To add a new non-standard key, add it to SPECIAL_KEYS and then add a recipe
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
new file mode 100644 (file)
index 0000000..cf2e8dd
--- /dev/null
@@ -0,0 +1,134 @@
+
+# Copyright (c) 2021, PostgreSQL Global Development Group
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+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 => 13;
+}
+
+#### 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.
+my $client_tmp_key = "${PostgreSQL::Test::Utils::tmp_check}/client_ext.key";
+copy("ssl/client_ext.key", $client_tmp_key)
+  or die "couldn't copy ssl/client_ext.key to $client_tmp_key for permissions change: $!";
+chmod 0600, $client_tmp_key
+  or die "failed to change permissions on $client_tmp_key: $!";
+
+#### Set up the server.
+
+note "setting up data directory";
+my $node = PostgreSQL::Test::Cluster->new('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_ext.crt sslkey=$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");
+
+$result = $node->safe_psql("certdb",
+  "SELECT '/CN=' || ssl_issuer_field('commonName') = issuer_dn FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
+  connstr => $common_connstr);
+is($result, 't', "ssl_issuer_field() for commonName");
+
+$result = $node->safe_psql("certdb",
+  "SELECT value, critical FROM ssl_extension_info() WHERE name = 'basicConstraints';",
+  connstr => $common_connstr);
+is($result, 'CA:FALSE|t', 'extract extension from cert');